[gthumb] utils: added more powerful functions to deal with templates
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] utils: added more powerful functions to deal with templates
- Date: Sat, 19 Jun 2021 18:10:34 +0000 (UTC)
commit b22029edc6c50c004b6fac1a2546ca70b7c0a360
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun May 16 12:36:45 2021 +0200
utils: added more powerful functions to deal with templates
gthumb/str-utils.c | 607 ++++++++++++++++++++++++++++++++++++++++-------
gthumb/str-utils.h | 44 +++-
gthumb/test-glib-utils.c | 301 ++++++++++++++++++++++-
3 files changed, 848 insertions(+), 104 deletions(-)
---
diff --git a/gthumb/str-utils.c b/gthumb/str-utils.c
index 828f6202..9b00107f 100644
--- a/gthumb/str-utils.c
+++ b/gthumb/str-utils.c
@@ -407,96 +407,6 @@ _g_utf8_split (const char *str,
}
-/* -- _g_utf8_split_template -- */
-
-
-typedef enum {
- SPLIT_TMPL_STATE_START,
- SPLIT_TMPL_STATE_READING_SHARPS,
- SPLIT_TMPL_STATE_READING_LITERAL
-} SplitTmplState;
-
-
-/**
- * example 1 : "xxx##yy#" --> [0] = xxx
- * [1] = ##
- * [2] = yy
- * [3] = #
- * [4] = NULL
- *
- * example 2 : "" --> [0] = NULL
- **/
-char **
-_g_utf8_split_template (const char *tmpl)
-{
- SplitTmplState state;
- GList *chunk_list;
- int chunk_n;
- const char *p;
- const char *chunk_start;
- const char *chunk_end;
- char **chunk_v;
-
- state = SPLIT_TMPL_STATE_START;
- chunk_list = NULL;
- chunk_n = 0;
- p = tmpl;
- while (p != NULL) {
- gunichar ch = g_utf8_get_char (p);
- gboolean save_chunk = FALSE;
-
- switch (state) {
- case SPLIT_TMPL_STATE_START:
- chunk_start = chunk_end = p;
- if (ch == '#')
- state = SPLIT_TMPL_STATE_READING_SHARPS;
- else
- state = SPLIT_TMPL_STATE_READING_LITERAL;
- break;
-
- case SPLIT_TMPL_STATE_READING_SHARPS:
- if (ch != '#') {
- state = SPLIT_TMPL_STATE_READING_LITERAL;
- save_chunk = TRUE;
- }
- else
- chunk_end = p;
- break;
-
- case SPLIT_TMPL_STATE_READING_LITERAL:
- if ((ch == '#') || (ch == 0)) {
- state = SPLIT_TMPL_STATE_READING_SHARPS;
- save_chunk = TRUE;
- }
- else
- chunk_end = p;
- break;
- }
-
- if (save_chunk) {
- glong chunk_size;
- char *chunk;
-
- chunk_size = chunk_end - chunk_start + 1;
- chunk = _g_utf8_strndup (chunk_start, chunk_size);
- chunk_list = g_list_prepend (chunk_list, chunk);
- chunk_n++;
- chunk_start = chunk_end = p;
- }
-
- if (ch == 0)
- break;
-
- p = g_utf8_next_char (p);
- }
-
- chunk_v = _g_strv_take_from_str_list (chunk_list, chunk_n);
- g_list_free (chunk_list);
-
- return chunk_v;
-}
-
-
char *
_g_utf8_replace_str (const char *str,
const char *old_str,
@@ -1015,3 +925,520 @@ _g_utf8_remove_string_properties (const char *str)
return (after_properties != NULL) ? g_strdup (after_properties) : NULL;
}
+
+
+/* -- Template utils -- */
+
+
+#undef DEBUG_TOKENIZER
+
+
+typedef enum {
+ TOKENIZER_STATE_START,
+ TOKENIZER_STATE_ENUMERATOR,
+ TOKENIZER_STATE_CODE,
+ TOKENIZER_STATE_ARG,
+ TOKENIZER_STATE_TEXT
+} TokenizerState;
+
+
+#if DEBUG_TOKENIZER
+static char *TokenizerStateName[] = {
+ "TOKENIZER_STATE_START",
+ "TOKENIZER_STATE_ENUMERATOR",
+ "TOKENIZER_STATE_CODE",
+ "TOKENIZER_STATE_ARG",
+ "TOKENIZER_STATE_TEXT"
+};
+#endif
+
+
+static gboolean
+valid_char_after_code_prefix (gunichar ch)
+{
+ return (ch != '%') && (ch != '{') && ! g_unichar_isspace (ch) && (ch != 0);
+}
+
+
+char **
+_g_template_tokenize (const char *template,
+ TemplateFlags flags)
+{
+ gboolean split_enumerator;
+ TokenizerState state;
+ GList *token_list;
+ int token_n;
+ const char *p;
+ const char *token_start;
+ glong token_size;
+ int n_open_brackets;
+ char **token_v;
+
+#if DEBUG_TOKENIZER
+ g_print ("\n> _g_template_tokenize: '%s'\n", template);
+#endif
+
+ split_enumerator = (flags & TEMPLATE_FLAGS_NO_ENUMERATOR) == 0;
+
+ state = TOKENIZER_STATE_START;
+ token_list = NULL;
+ token_n = 0;
+ token_start = NULL;
+ token_size = 0;
+ n_open_brackets = 0;
+ p = template;
+ while (p != NULL) {
+ gboolean add_to_token;
+ gboolean save_token;
+ gunichar ch;
+ const char *next_p;
+ gunichar next_ch;
+ gboolean code_prefix;
+ gboolean enumerator_prefix;
+
+ add_to_token = FALSE;
+ save_token = FALSE;
+ ch = (p != NULL) ? g_utf8_get_char (p) : 0;
+ next_p = (p != NULL) ? g_utf8_next_char (p) : NULL;
+ next_ch = (next_p != NULL) ? g_utf8_get_char (next_p) : 0;
+ code_prefix = (ch == '%') && valid_char_after_code_prefix (next_ch);
+ enumerator_prefix = split_enumerator && (ch == '#');
+
+#if DEBUG_TOKENIZER
+ {
+ char str[7] = { 0, 0, 0, 0, 0, 0, 0 };
+ g_unichar_to_utf8 (ch, str);
+ g_print ("> ch: '%s'\n", str);
+ }
+#endif
+
+ switch (state) {
+ case TOKENIZER_STATE_START:
+ token_start = p;
+ token_size = 0;
+ add_to_token = TRUE;
+ if (enumerator_prefix)
+ state = TOKENIZER_STATE_ENUMERATOR;
+ else if (code_prefix)
+ state = TOKENIZER_STATE_CODE;
+ else
+ state = TOKENIZER_STATE_TEXT;
+ break;
+
+ case TOKENIZER_STATE_ENUMERATOR:
+ if (ch != '#') {
+ add_to_token = FALSE;
+ save_token = TRUE;
+ state = TOKENIZER_STATE_START;
+ }
+ else
+ add_to_token = TRUE;
+ break;
+
+ case TOKENIZER_STATE_CODE:
+ if (next_ch == '{') {
+ add_to_token = TRUE;
+ state = TOKENIZER_STATE_ARG;
+ n_open_brackets = 0;
+ }
+ else {
+ add_to_token = TRUE;
+ save_token = TRUE;
+ state = TOKENIZER_STATE_START;
+ }
+ break;
+
+ case TOKENIZER_STATE_ARG:
+ if (ch == '{')
+ n_open_brackets++;
+ else if (ch == '}')
+ n_open_brackets--;
+ if ((n_open_brackets == 0) && (ch == '}') && (next_ch != '{')) {
+ add_to_token = TRUE;
+ save_token = TRUE;
+ state = TOKENIZER_STATE_START;
+ }
+ else
+ add_to_token = TRUE;
+ break;
+
+ case TOKENIZER_STATE_TEXT:
+ if ((ch == 0) || enumerator_prefix || code_prefix) {
+ add_to_token = FALSE;
+ save_token = TRUE;
+ state = TOKENIZER_STATE_START;
+ }
+ else
+ add_to_token = TRUE;
+ break;
+ }
+
+#if DEBUG_TOKENIZER
+ g_print (" new state: %s\n", TokenizerStateName[state]);
+ g_print (" save_token: %d\n", save_token);
+ g_print (" add_to_token: %d\n", add_to_token);
+ g_print (" token_size: %ld\n", token_size);
+ g_print (" n_open_brackets: %d\n", n_open_brackets);
+#endif
+
+ if (add_to_token) {
+ token_size++;
+ p = next_p;
+ }
+
+ if (save_token) {
+ token_list = g_list_prepend (token_list, _g_utf8_strndup (token_start, token_size));
+ token_n++;
+ }
+
+ if (ch == 0)
+ break;
+ }
+
+ token_v = _g_strv_take_from_str_list (token_list, token_n);
+ g_list_free (token_list);
+
+ return token_v;
+}
+
+
+gunichar
+_g_template_get_token_code (const char *token)
+{
+ gunichar ch;
+
+ if (token == NULL)
+ return 0;
+
+ ch = g_utf8_get_char (token);
+ if (ch != '%')
+ return 0;
+
+ token = g_utf8_next_char (token);
+ if (token == NULL)
+ return 0;
+
+ ch = g_utf8_get_char (token);
+
+ return valid_char_after_code_prefix (ch) ? ch : 0;
+}
+
+
+char **
+_g_template_get_token_args (const char *token)
+{
+ TokenizerState state;
+ GList *token_list;
+ int token_n;
+ const char *p;
+ const char *token_start;
+ glong token_size;
+ int n_open_brackets;
+ char **token_v;
+
+#if DEBUG_TOKENIZER
+ g_print ("\n> _g_template_get_token_args: '%s'\n", token);
+#endif
+
+ state = TOKENIZER_STATE_START;
+ token_list = NULL;
+ token_n = 0;
+ token_start = NULL;
+ token_size = 0;
+ n_open_brackets = 0;
+ p = token;
+ while (p != NULL) {
+ gboolean save_token = FALSE;
+ gunichar ch;
+ const char *next_p;
+ gunichar next_ch;
+
+ ch = (p != NULL) ? g_utf8_get_char (p) : 0;
+ next_p = (p != NULL) ? g_utf8_next_char (p) : NULL;
+ next_ch = (next_p != NULL) ? g_utf8_get_char (next_p) : 0;
+
+#if DEBUG_TOKENIZER
+ {
+ char str[7] = { 0, 0, 0, 0, 0, 0, 0 };
+ g_unichar_to_utf8 (ch, str);
+ g_print ("> ch: '%s'\n", str);
+ }
+#endif
+
+ switch (state) {
+ case TOKENIZER_STATE_START:
+ if ((ch == '%') && valid_char_after_code_prefix (next_ch)) {
+ /* Skip the code. */
+ p = next_p;
+ next_p = (p != NULL) ? g_utf8_next_char (p) : NULL;
+ state = TOKENIZER_STATE_CODE;
+ }
+ else
+ ch = 0; /* Not a special code. */
+ break;
+
+ case TOKENIZER_STATE_CODE:
+ if (ch == '{') {
+ n_open_brackets = 1;
+ token_start = next_p;
+ token_size = 0;
+ state = TOKENIZER_STATE_ARG;
+ }
+ else
+ ch = 0; /* No arguments for this code. */
+ break;
+
+ case TOKENIZER_STATE_ARG:
+ if (ch == '}') {
+ n_open_brackets--;
+ if (n_open_brackets == 0) {
+ save_token = TRUE;
+ state = TOKENIZER_STATE_CODE;
+ }
+ else
+ token_size++;
+ }
+ else {
+ token_size++;
+ if (ch == '{')
+ n_open_brackets++;
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+#if DEBUG_TOKENIZER
+ g_print (" new state: %s\n", TokenizerStateName[state]);
+ g_print (" save_token: %d\n", save_token);
+ g_print (" token_size: %ld\n", token_size);
+ g_print (" n_open_brackets: %d\n", n_open_brackets);
+#endif
+
+ if (save_token) {
+ char *token;
+
+ token = _g_utf8_strndup (token_start, token_size);
+ token_list = g_list_prepend (token_list, _g_utf8_strip (token));
+ token_n++;
+
+ g_free (token);
+ }
+
+ if (ch == 0)
+ break;
+
+ p = next_p;
+ }
+
+ token_v = _g_strv_take_from_str_list (token_list, token_n);
+ g_list_free (token_list);
+
+ return token_v;
+}
+
+
+gboolean
+_g_template_token_is (const char *token,
+ gunichar code)
+{
+ return _g_template_get_token_code (token) == code;
+}
+
+
+/* -- _g_template_for_each_token -- */
+
+
+static void
+_for_each_token (const char *tmpl,
+ TemplateFlags flags,
+ gunichar parent_node,
+ TemplateForEachFunc for_each,
+ gpointer user_data)
+{
+ char **tokenv;
+ int i;
+ gboolean with_enumerator;
+ gboolean stop;
+
+ if ((tmpl == NULL) || (for_each == NULL))
+ return;
+
+ with_enumerator = (flags & TEMPLATE_FLAGS_NO_ENUMERATOR) == 0;
+ stop = FALSE;
+ tokenv = _g_template_tokenize (tmpl, flags);
+ for (i = 0; ! stop && (tokenv[i] != NULL); i++) {
+ char *token = tokenv[i];
+ gunichar code;
+
+ code = _g_template_get_token_code (token);
+ if (code != 0) {
+ char **args;
+ int j;
+
+ args = _g_template_get_token_args (token);
+ for (j = 0; args[j] != NULL; j++)
+ _for_each_token (args[j], flags, code, for_each, user_data);
+
+ stop = for_each (parent_node, code, args, user_data);
+
+ g_strfreev (args);
+ }
+ else if (with_enumerator && (token[0] == '#')) {
+ char *args[] = { token, NULL };
+ stop = for_each (parent_node, '#', args, user_data);
+ }
+ else {
+ char *args[] = { token, NULL };
+ stop = for_each (parent_node, code, args, user_data);
+ }
+ }
+
+ g_strfreev (tokenv);
+}
+
+
+void
+_g_template_for_each_token (const char *tmpl,
+ TemplateFlags flags,
+ TemplateForEachFunc for_each,
+ gpointer user_data)
+{
+ _for_each_token (tmpl, flags, 0, for_each, user_data);
+}
+
+
+/* -- _g_template_eval -- */
+
+
+static gchar *
+_eval_template (const char *tmpl,
+ TemplateFlags flags,
+ gunichar parent_code,
+ TemplateEvalFunc eval,
+ gpointer user_data)
+{
+ GString *result;
+ char **tokenv;
+ int i;
+ gboolean with_enumerator;
+ gboolean stop;
+
+ if (tmpl == NULL)
+ return NULL;
+
+ result = g_string_new ("");
+ with_enumerator = (flags & TEMPLATE_FLAGS_NO_ENUMERATOR) == 0;
+ stop = FALSE;
+ tokenv = _g_template_tokenize (tmpl, flags);
+ for (i = 0; ! stop && (tokenv[i] != NULL); i++) {
+ char *token = tokenv[i];
+ gunichar code;
+
+ code = _g_template_get_token_code (token);
+ if (code != 0) {
+ char **args;
+ int j;
+
+ if (eval == NULL)
+ continue;
+
+ args = _g_template_get_token_args (token);
+ for (j = 0; args[j] != NULL; j++)
+ args[j] = _eval_template (args[j], flags, code, eval, user_data);
+
+ stop = eval (flags, parent_code, code, args, result, user_data);
+
+ g_strfreev (args);
+ }
+ else if (with_enumerator && (token[0] == '#')) {
+ char *args[] = { token, NULL };
+
+ if (eval == NULL)
+ continue;
+
+ stop = eval (flags, parent_code, '#', args, result, user_data);
+ }
+ else { /* Literal string. */
+ if (flags & TEMPLATE_FLAGS_PREVIEW)
+ _g_string_append_markup_escaped (result, "%s", token);
+ else
+ g_string_append (result, token);
+ }
+ }
+
+ g_strfreev (tokenv);
+
+ return g_string_free (result, FALSE);
+}
+
+
+char *
+_g_template_eval (const char *tmpl,
+ TemplateFlags flags,
+ TemplateEvalFunc eval,
+ gpointer user_data)
+{
+ return _eval_template (tmpl,
+ flags,
+ 0,
+ eval,
+ user_data);
+}
+
+
+void
+_g_string_append_template_code (GString *str,
+ gunichar code,
+ char **args)
+{
+ if (code == 0) {
+ /* Literal string, not a special code. */
+ if (args[0] != NULL)
+ g_string_append (str, args[0]);
+ }
+ else {
+ g_string_append_c (str, '%');
+ g_string_append_unichar (str, code);
+
+ if (args != NULL) {
+ int i;
+
+ for (i = 0; args[i] != NULL; i++)
+ g_string_append_printf (str, "{ %s }", args[i]);
+ }
+ }
+}
+
+
+char *
+_g_template_replace_enumerator (const char *token,
+ int n)
+{
+ long length;
+ char *format;
+ char *result;
+
+ length = 0;
+ while (token != NULL) {
+ gunichar ch = g_utf8_get_char (token);
+ if (ch == 0)
+ break;
+ if (ch != '#')
+ return NULL; /* Syntax error. */
+ length++;
+ token = g_utf8_next_char (token);
+ }
+
+ if (length == 0)
+ return NULL;
+
+ format = g_strdup_printf ("%%0" "%ld" "d", length);
+ result = g_strdup_printf (format, n);
+
+ g_free (format);
+
+ return result;
+}
diff --git a/gthumb/str-utils.h b/gthumb/str-utils.h
index cbd32656..950ad36d 100644
--- a/gthumb/str-utils.h
+++ b/gthumb/str-utils.h
@@ -67,7 +67,6 @@ const char * _g_utf8_find_str (const char *haystack,
char ** _g_utf8_split (const char *str,
const char *separator,
int max_tokens);
-char ** _g_utf8_split_template (const char *tmpl);
char * _g_utf8_replace_str (const char *str,
const char *old_str,
const char *new_str);
@@ -99,6 +98,49 @@ char * _g_utf8_text_escape_xml (const char *str);
char * _g_utf8_remove_string_properties
(const char *str);
+/* Template utils */
+
+typedef enum {
+ TEMPLATE_FLAGS_DEFAULT = 0,
+ TEMPLATE_FLAGS_NO_ENUMERATOR = (1 << 0),
+ TEMPLATE_FLAGS_PREVIEW = (1 << 1),
+ TEMPLATE_FLAGS_PARTIAL = (1 << 2),
+} TemplateFlags;
+
+typedef gboolean (*TemplateForEachFunc) (gunichar parent_code,
+ gunichar code,
+ char **args,
+ gpointer user_data);
+typedef gboolean (*TemplateEvalFunc) (gunichar root_code,
+ gunichar parent_code,
+ gunichar code,
+ char **args,
+ GString *result,
+ gpointer user_data);
+typedef char * (*TemplatePreviewFunc) (const char *tmpl,
+ TemplateFlags flags,
+ gpointer user_data);
+
+char ** _g_template_tokenize (const char *tmpl,
+ TemplateFlags flags);
+gunichar _g_template_get_token_code (const char *token);
+char ** _g_template_get_token_args (const char *token);
+gboolean _g_template_token_is (const char *token,
+ gunichar code);
+void _g_template_for_each_token (const char *tmpl,
+ TemplateFlags flags,
+ TemplateForEachFunc for_each,
+ gpointer user_data);
+char * _g_template_eval (const char *tmpl,
+ TemplateFlags flags,
+ TemplateEvalFunc eval,
+ gpointer user_data);
+void _g_string_append_template_code (GString *str,
+ gunichar code,
+ char **args);
+char * _g_template_replace_enumerator (const char *token,
+ int n);
+
G_END_DECLS
#endif /* _STR_UTILS_H */
diff --git a/gthumb/test-glib-utils.c b/gthumb/test-glib-utils.c
index cf92f40c..f300ed04 100644
--- a/gthumb/test-glib-utils.c
+++ b/gthumb/test-glib-utils.c
@@ -525,53 +525,323 @@ test_g_utf8_split_all (void)
static void
-test_g_utf8_split_template_all (void)
+test_g_template_tokenize_all (void)
{
char **strv;
- strv = _g_utf8_split_template ("");
+ strv = _g_template_tokenize ("", 0);
_g_assert_strv_equal (strv, NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("xxx##yy#");
+ strv = _g_template_tokenize ("xxx##yy#", 0);
_g_assert_strv_equal (strv, "xxx", "##", "yy", "#", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("日");
+ strv = _g_template_tokenize ("日", 0);
_g_assert_strv_equal (strv, "日", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("日本");
+ strv = _g_template_tokenize ("日本", 0);
_g_assert_strv_equal (strv, "日本", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("#");
+ strv = _g_template_tokenize ("#", 0);
_g_assert_strv_equal (strv, "#", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("##");
+ strv = _g_template_tokenize ("##", 0);
_g_assert_strv_equal (strv, "##", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("#日");
+ strv = _g_template_tokenize ("#日", 0);
_g_assert_strv_equal (strv, "#", "日", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("日#");
+ strv = _g_template_tokenize ("日#", 0);
_g_assert_strv_equal (strv, "日", "#", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("日#本");
+ strv = _g_template_tokenize ("日#本", 0);
_g_assert_strv_equal (strv, "日", "#", "本", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("日#本#");
+ strv = _g_template_tokenize ("日#本#", 0);
_g_assert_strv_equal (strv, "日", "#", "本", "#", NULL);
g_strfreev (strv);
- strv = _g_utf8_split_template ("日#本#語");
+ strv = _g_template_tokenize ("日#本#語", 0);
_g_assert_strv_equal (strv, "日", "#", "本", "#", "語", NULL);
g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日", 0);
+ _g_assert_strv_equal (strv, "%日", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日%本", 0);
+ _g_assert_strv_equal (strv, "%日", "%本", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日-%本", 0);
+ _g_assert_strv_equal (strv, "%日", "-", "%本", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日-%本-", 0);
+ _g_assert_strv_equal (strv, "%日", "-", "%本", "-", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("-%日-%本", 0);
+ _g_assert_strv_equal (strv, "-", "%日", "-", "%本", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日{ 本語 }", 0);
+ _g_assert_strv_equal (strv, "%日{ 本語 }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日{ 本語 }日本語", 0);
+ _g_assert_strv_equal (strv, "%日{ 本語 }", "日本語", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日{ 本語 }%本", 0);
+ _g_assert_strv_equal (strv, "%日{ 本語 }", "%本", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日{ 本語 }%正{ 體字 }", 0);
+ _g_assert_strv_equal (strv, "%日{ 本語 }", "%正{ 體字 }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日{ 本語 }%正{ 體字 }{ 本語 }", 0);
+ _g_assert_strv_equal (strv, "%日{ 本語 }", "%正{ 體字 }{ 本語 }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日{ 本語 }-%正{ 體字 }{ 本語 }", 0);
+ _g_assert_strv_equal (strv, "%日{ 本語 }", "-", "%正{ 體字 }{ 本語 }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%日{ 本語 }-%日{ 本 }{ 語 }-", 0);
+ _g_assert_strv_equal (strv, "%日{ 本語 }", "-", "%日{ 本 }{ 語 }", "-", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%Q{ %A{ Prompt: } }", 0);
+ _g_assert_strv_equal (strv, "%Q{ %A{ Prompt: } }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%Q{ { %A } }", 0);
+ _g_assert_strv_equal (strv, "%Q{ { %A } }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%Q{ {} }", 0);
+ _g_assert_strv_equal (strv, "%Q{ {} }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%Q{ { }", 0);
+ _g_assert_strv_equal (strv, NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%Q{ %A{} }", 0);
+ _g_assert_strv_equal (strv, "%Q{ %A{} }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%Q{ %A{}{} }", 0);
+ _g_assert_strv_equal (strv, "%Q{ %A{}{} }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%Q{ %A{ Prompt: }{ 12 } }", 0);
+ _g_assert_strv_equal (strv, "%Q{ %A{ Prompt: }{ 12 } }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%a{ %x }%b{ %y }", 0);
+ _g_assert_strv_equal (strv, "%a{ %x }", "%b{ %y }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%a{ %x }%b{ %y }%c{ %z }", 0);
+ _g_assert_strv_equal (strv, "%a{ %x }", "%b{ %y }", "%c{ %z }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%a{%x}%b{%y}%c{%z}", 0);
+ _g_assert_strv_equal (strv, "%a{%x}", "%b{%y}", "%c{%z}", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_tokenize ("%a{%x} %b{%y} %c{%z}", 0);
+ _g_assert_strv_equal (strv, "%a{%x}", " ", "%b{%y}", " ", "%c{%z}", NULL);
+ g_strfreev (strv);
+}
+
+
+static void
+test_g_template_get_token_code_all (void)
+{
+ g_assert_true (_g_template_get_token_code (NULL) == 0);
+ g_assert_true (_g_template_get_token_code ("") == 0);
+ g_assert_true (_g_template_get_token_code ("a") == 0);
+ g_assert_true (_g_template_get_token_code ("日") == 0);
+ g_assert_true (_g_template_get_token_code ("%a") == 'a');
+ g_assert_true (_g_template_get_token_code ("% a") == 0);
+ g_assert_true (_g_template_get_token_code ("%日") == g_utf8_get_char ("日"));
+ g_assert_true (_g_template_get_token_code ("%日 %字") == g_utf8_get_char ("日"));
+ g_assert_true (_g_template_get_token_code ("% 日") == 0);
+ g_assert_true (_g_template_get_token_code (" %日") == 0);
+ g_assert_true (_g_template_get_token_code (" % 日") == 0);
+ g_assert_true (_g_template_get_token_code ("%{}") == 0);
+ g_assert_true (_g_template_get_token_code ("%{ text }") == 0);
+ g_assert_true (_g_template_get_token_code ("%{ %字 }") == 0);
+ g_assert_true (_g_template_get_token_code ("%日{}") == g_utf8_get_char ("日"));
+ g_assert_true (_g_template_get_token_code ("%日{%字}") == g_utf8_get_char ("日"));
+ g_assert_true (_g_template_get_token_code ("%日{ }") == g_utf8_get_char ("日"));
+ g_assert_true (_g_template_get_token_code ("%日{ %字 }") == g_utf8_get_char ("日"));
+}
+
+
+static void
+test_g_template_get_token_args_all (void)
+{
+ char **strv;
+
+ strv = _g_template_get_token_args ("");
+ _g_assert_strv_equal (strv, NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%F");
+ _g_assert_strv_equal (strv, NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("{ xxx }{ yyy }");
+ _g_assert_strv_equal (strv, NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%A%F{ xxx }{ yyy }");
+ _g_assert_strv_equal (strv, NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%F{ xxx }{ yyy }");
+ _g_assert_strv_equal (strv, "xxx", "yyy", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%日{ 本語 }");
+ _g_assert_strv_equal (strv, "本語", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%日{ 本語 }{ 體字 }");
+ _g_assert_strv_equal (strv, "本語", "體字", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%Q{ %A }");
+ _g_assert_strv_equal (strv, "%A", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%Q{ %A{ Prompt: } }");
+ _g_assert_strv_equal (strv, "%A{ Prompt: }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%Q{ %A{ Prompt: }{ 10 } }");
+ _g_assert_strv_equal (strv, "%A{ Prompt: }{ 10 }", NULL);
+ g_strfreev (strv);
+
+ strv = _g_template_get_token_args ("%Q{ %A{ Prompt: }{ 10 } %A{ Prompt2: }{ 20 } }");
+ _g_assert_strv_equal (strv, "%A{ Prompt: }{ 10 } %A{ Prompt2: }{ 20 }", NULL);
+ g_strfreev (strv);
+}
+
+
+static void
+test_g_template_token_is_all (void)
+{
+ g_assert_true (_g_template_token_is (NULL, 0));
+ g_assert_true (_g_template_token_is ("", 0));
+
+ g_assert_true (_g_template_token_is ("a", 0));
+ g_assert_true (! _g_template_token_is ("a", 'a'));
+ g_assert_true (! _g_template_token_is ("a", 'b'));
+
+ g_assert_true (! _g_template_token_is ("%a", 0));
+ g_assert_true (_g_template_token_is ("%a", 'a'));
+ g_assert_true (_g_template_token_is ("%abc", 'a'));
+ g_assert_true (_g_template_token_is ("%a{}", 'a'));
+ g_assert_true (_g_template_token_is ("%a{ xyz }", 'a'));
+
+ g_assert_true (_g_template_token_is ("%日", g_utf8_get_char ("日")));
+ g_assert_true (_g_template_token_is ("%日{}", g_utf8_get_char ("日")));
+ g_assert_true (_g_template_token_is ("%日{ 日本語 }", g_utf8_get_char ("日")));
+}
+
+
+static gboolean
+eval_template_cb (gunichar root_code,
+ gunichar parent_code,
+ gunichar code,
+ char **args,
+ GString *result,
+ gpointer user_data)
+{
+ int i;
+
+ switch (code) {
+ case 'A':
+ g_string_append (result, "a");
+ break;
+ case 'B':
+ for (i = 0; args[i] != NULL; i++)
+ g_string_append (result, args[i]);
+ break;
+ case 'C':
+ break;
+ case '#':
+ g_string_append (result, _g_template_replace_enumerator (args[0], 1));
+ break;
+ default:
+ g_string_append_unichar (result, code);
+ break;
+ }
+ return FALSE;
+}
+
+
+static void
+test_g_template_eval_all (void)
+{
+ g_assert_cmpstr (_g_template_eval (NULL, 0, eval_template_cb, NULL), ==, NULL);
+ g_assert_cmpstr (_g_template_eval ("", 0, eval_template_cb, NULL), ==, "");
+ g_assert_cmpstr (_g_template_eval ("日本語", 0, eval_template_cb, NULL), ==, "日本語");
+ g_assert_cmpstr (_g_template_eval ("%A", 0, eval_template_cb, NULL), ==, "a");
+ g_assert_cmpstr (_g_template_eval ("%A{}", 0, eval_template_cb, NULL), ==, "a");
+ g_assert_cmpstr (_g_template_eval ("%A{ xyz }", 0, eval_template_cb, NULL), ==, "a");
+ g_assert_cmpstr (_g_template_eval ("%A{ %B }", 0, eval_template_cb, NULL), ==, "a");
+ g_assert_cmpstr (_g_template_eval ("%A{ %A }", 0, eval_template_cb, NULL), ==, "a");
+ g_assert_cmpstr (_g_template_eval ("%B{x}", 0, eval_template_cb, NULL), ==, "x");
+ g_assert_cmpstr (_g_template_eval ("%B{%B{x}}", 0, eval_template_cb, NULL), ==, "x");
+ g_assert_cmpstr (_g_template_eval ("%B{%B{x}y}z", 0, eval_template_cb, NULL), ==, "xyz");
+ g_assert_cmpstr (_g_template_eval ("%B{%B{x}%B{y}}", 0, eval_template_cb, NULL), ==, "xy");
+ g_assert_cmpstr (_g_template_eval ("%A%B%C", 0, eval_template_cb, NULL), ==, "a");
+ g_assert_cmpstr (_g_template_eval ("%A{}%B{ x }%C{ xyz }", 0, eval_template_cb, NULL), ==, "ax");
+ g_assert_cmpstr (_g_template_eval ("%A%B%C日本語", 0, eval_template_cb, NULL), ==, "a日本語");
+ g_assert_cmpstr (_g_template_eval ("日本語%A%B{日}%C", 0, eval_template_cb, NULL), ==, "日本語a日");
+
+ g_assert_cmpstr (_g_template_eval ("#", 0, eval_template_cb, NULL), ==, "1");
+ g_assert_cmpstr (_g_template_eval ("##", 0, eval_template_cb, NULL), ==, "01");
+ g_assert_cmpstr (_g_template_eval ("日##", 0, eval_template_cb, NULL), ==, "日01");
+ g_assert_cmpstr (_g_template_eval ("日#本##語###", 0, eval_template_cb, NULL), ==, "日1本01語001");
+ g_assert_cmpstr (_g_template_eval ("#日##本###語", 0, eval_template_cb, NULL), ==, "1日01本001語");
+ g_assert_cmpstr (_g_template_eval ("%A#%B#%C##", 0, eval_template_cb, NULL), ==, "a1101");
+ g_assert_cmpstr (_g_template_eval ("日本語%A%B{日}%C###", 0, eval_template_cb, NULL), ==, "日本語a日001");
+
+ g_assert_cmpstr (_g_template_eval ("#", TEMPLATE_FLAGS_NO_ENUMERATOR, eval_template_cb, NULL), ==,
"#");
+ g_assert_cmpstr (_g_template_eval ("%A#%B{#}%C##", TEMPLATE_FLAGS_NO_ENUMERATOR, eval_template_cb,
NULL), ==, "a####");
+}
+
+
+static void
+test_g_template_replace_enumerator_all (void)
+{
+ g_assert_cmpstr (_g_template_replace_enumerator (NULL, 1), ==, NULL);
+ g_assert_cmpstr (_g_template_replace_enumerator ("", 1), ==, NULL);
+ g_assert_cmpstr (_g_template_replace_enumerator ("X", 1), ==, NULL);
+ g_assert_cmpstr (_g_template_replace_enumerator ("日", 1), ==, NULL);
+ g_assert_cmpstr (_g_template_replace_enumerator ("日#", 1), ==, NULL);
+ g_assert_cmpstr (_g_template_replace_enumerator ("#日", 1), ==, NULL);
+ g_assert_cmpstr (_g_template_replace_enumerator ("#", 1), ==, "1");
+ g_assert_cmpstr (_g_template_replace_enumerator ("##", 1), ==, "01");
+ g_assert_cmpstr (_g_template_replace_enumerator ("###", 1), ==, "001");
+ g_assert_cmpstr (_g_template_replace_enumerator ("###", 10), ==, "010");
+ g_assert_cmpstr (_g_template_replace_enumerator ("###", 1000), ==, "1000");
}
@@ -931,7 +1201,12 @@ main (int argc,
g_test_add_func ("/glib-utils/_g_utf8_replace_str", test_g_utf8_replace_str_all);
g_test_add_func ("/glib-utils/_g_utf8_rstrip", test_g_utf8_rstrip_all);
g_test_add_func ("/glib-utils/_g_utf8_split", test_g_utf8_split_all);
- g_test_add_func ("/glib-utils/_g_utf8_split_template", test_g_utf8_split_template_all);
+ g_test_add_func ("/glib-utils/_g_template_tokenize", test_g_template_tokenize_all);
+ g_test_add_func ("/glib-utils/_g_template_get_token_code", test_g_template_get_token_code_all);
+ g_test_add_func ("/glib-utils/_g_template_get_token_args", test_g_template_get_token_args_all);
+ g_test_add_func ("/glib-utils/_g_template_token_is", test_g_template_token_is_all);
+ g_test_add_func ("/glib-utils/_g_template_eval", test_g_template_eval_all);
+ g_test_add_func ("/glib-utils/_g_template_replace_enumerator",
test_g_template_replace_enumerator_all);
g_test_add_func ("/glib-utils/_g_utf8_strip", test_g_utf8_strip_all);
g_test_add_func ("/glib-utils/_g_utf8_translate", test_g_utf8_translate_all);
g_test_add_func ("/glib-utils/_g_utf8_remove_string_properties",
test_g_utf8_remove_string_properties);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]