1From 6caf952e48dbed40b5dcff01a94f57ba079b526c Mon Sep 17 00:00:00 2001 2From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net> 3Date: Tue, 20 Sep 2022 18:06:35 +0200 4Subject: [PATCH] gregex: Use pcre2 error messages if we don't provide a 5 specific one 6 7In case we got a compilation or match error we should try to provide 8some useful error message, if possible, before returning a quite obscure 9"internal error" or "unknown error" string. 10 11So rely on PCRE2 strings even if they're not translated they can provide 12better information than the ones we're currently giving. 13 14Related to: https://gitlab.gnome.org/GNOME/glib/-/issues/2691 15Related to: https://gitlab.gnome.org/GNOME/glib/-/issues/2760 16 17Conflict:NA 18Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/6caf952e48dbed40b5dcff01a94f57ba079b526c 19 20--- 21 glib/gregex.c | 64 ++++++++++++++++++++++++++++++++++++++++------ 22 glib/tests/regex.c | 2 ++ 23 2 files changed, 58 insertions(+), 8 deletions(-) 24 25diff --git a/glib/gregex.c b/glib/gregex.c 26index 220a1a11ac..fcc28d62f4 100644 27--- a/glib/gregex.c 28+++ b/glib/gregex.c 29@@ -456,8 +456,25 @@ get_pcre2_bsr_match_options (GRegexMatchFlags match_flags) 30 return 0; 31 } 32 33+static char * 34+get_pcre2_error_string (int errcode) 35+{ 36+ PCRE2_UCHAR8 error_msg[2048]; 37+ int err_length; 38+ 39+ err_length = pcre2_get_error_message (errcode, error_msg, 40+ G_N_ELEMENTS (error_msg)); 41+ 42+ if (err_length <= 0) 43+ return NULL; 44+ 45+ /* The array is always filled with a trailing zero */ 46+ g_assert ((size_t) err_length < G_N_ELEMENTS (error_msg)); 47+ return g_memdup2 (error_msg, err_length + 1); 48+} 49+ 50 static const gchar * 51-match_error (gint errcode) 52+translate_match_error (gint errcode) 53 { 54 switch (errcode) 55 { 56@@ -511,7 +528,24 @@ match_error (gint errcode) 57 default: 58 break; 59 } 60- return _("unknown error"); 61+ return NULL; 62+} 63+ 64+static char * 65+get_match_error_message (int errcode) 66+{ 67+ const char *msg = translate_match_error (errcode); 68+ char *error_string; 69+ 70+ if (msg) 71+ return g_strdup (msg); 72+ 73+ error_string = get_pcre2_error_string (errcode); 74+ 75+ if (error_string) 76+ return error_string; 77+ 78+ return g_strdup (_("unknown error")); 79 } 80 81 static void 82@@ -743,7 +777,6 @@ translate_compile_error (gint *errcode, const gchar **errmsg) 83 case PCRE2_ERROR_INTERNAL_BAD_CODE: 84 case PCRE2_ERROR_INTERNAL_BAD_CODE_IN_SKIP: 85 *errcode = G_REGEX_ERROR_INTERNAL; 86- *errmsg = _("internal error"); 87 break; 88 case PCRE2_ERROR_INVALID_SUBPATTERN_NAME: 89 case PCRE2_ERROR_CLASS_INVALID_RANGE: 90@@ -772,12 +805,10 @@ translate_compile_error (gint *errcode, const gchar **errmsg) 91 case PCRE2_ERROR_BAD_LITERAL_OPTIONS: 92 default: 93 *errcode = G_REGEX_ERROR_COMPILE; 94- *errmsg = _("internal error"); 95 break; 96 } 97 98 g_assert (*errcode != -1); 99- g_assert (*errmsg != NULL); 100 } 101 102 /* GMatchInfo */ 103@@ -1096,9 +1127,12 @@ g_match_info_next (GMatchInfo *match_info, 104 105 if (IS_PCRE2_ERROR (match_info->matches)) 106 { 107+ gchar *error_msg = get_match_error_message (match_info->matches); 108+ 109 g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_MATCH, 110 _("Error while matching regular expression %s: %s"), 111- match_info->regex->pattern, match_error (match_info->matches)); 112+ match_info->regex->pattern, error_msg); 113+ g_clear_pointer (&error_msg, g_free); 114 return FALSE; 115 } 116 else if (match_info->matches == 0) 117@@ -1800,11 +1834,20 @@ regex_compile (const gchar *pattern, 118 { 119 GError *tmp_error; 120 gchar *offset_str; 121+ gchar *pcre2_errmsg = NULL; 122+ int original_errcode; 123 124 /* Translate the PCRE error code to GRegexError and use a translated 125 * error message if possible */ 126+ original_errcode = errcode; 127 translate_compile_error (&errcode, &errmsg); 128 129+ if (!errmsg) 130+ { 131+ errmsg = _("unknown error"); 132+ pcre2_errmsg = get_pcre2_error_string (original_errcode); 133+ } 134+ 135 /* PCRE uses byte offsets but we want to show character offsets */ 136 erroffset = g_utf8_pointer_to_offset (pattern, &pattern[erroffset]); 137 138@@ -1812,9 +1855,11 @@ regex_compile (const gchar *pattern, 139 tmp_error = g_error_new (G_REGEX_ERROR, errcode, 140 _("Error while compiling regular expression ‘%s’ " 141 "at char %s: %s"), 142- pattern, offset_str, errmsg); 143+ pattern, offset_str, 144+ pcre2_errmsg ? pcre2_errmsg : errmsg); 145 g_propagate_error (error, tmp_error); 146 g_free (offset_str); 147+ g_clear_pointer (&pcre2_errmsg, g_free); 148 149 return NULL; 150 } 151@@ -2402,9 +2447,12 @@ g_regex_match_all_full (const GRegex *regex, 152 } 153 else if (IS_PCRE2_ERROR (info->matches)) 154 { 155+ gchar *error_msg = get_match_error_message (info->matches); 156+ 157 g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_MATCH, 158 _("Error while matching regular expression %s: %s"), 159- regex->pattern, match_error (info->matches)); 160+ regex->pattern, error_msg); 161+ g_clear_pointer (&error_msg, g_free); 162 } 163 else if (info->matches != PCRE2_ERROR_NOMATCH) 164 { 165diff --git a/glib/tests/regex.c b/glib/tests/regex.c 166index 9803d49659..52af212f29 100644 167--- a/glib/tests/regex.c 168+++ b/glib/tests/regex.c 169@@ -2560,6 +2560,7 @@ main (int argc, char *argv[]) 170 TEST_NEW_FAIL ("[a-z", 0, G_REGEX_ERROR_UNTERMINATED_CHARACTER_CLASS); 171 TEST_NEW_FAIL ("[\\B]", 0, G_REGEX_ERROR_INVALID_ESCAPE_IN_CHARACTER_CLASS); 172 TEST_NEW_FAIL ("[z-a]", 0, G_REGEX_ERROR_RANGE_OUT_OF_ORDER); 173+ TEST_NEW_FAIL ("^[[:alnum:]-_.]+$", 0, G_REGEX_ERROR_COMPILE); 174 TEST_NEW_FAIL ("{2,4}", 0, G_REGEX_ERROR_NOTHING_TO_REPEAT); 175 TEST_NEW_FAIL ("a(?u)", 0, G_REGEX_ERROR_UNRECOGNIZED_CHARACTER); 176 TEST_NEW_FAIL ("a(?<$foo)bar", 0, G_REGEX_ERROR_MISSING_SUBPATTERN_NAME); 177@@ -2636,6 +2637,7 @@ main (int argc, char *argv[]) 178 TEST_MATCH_SIMPLE("a", "a", G_REGEX_CASELESS, 0, TRUE); 179 TEST_MATCH_SIMPLE("a", "A", G_REGEX_CASELESS, 0, TRUE); 180 TEST_MATCH_SIMPLE("\\C\\C", "ab", G_REGEX_OPTIMIZE | G_REGEX_RAW, 0, TRUE); 181+ TEST_MATCH_SIMPLE("^[[:alnum:]\\-_.]+$", "admin-foo", 0, 0, TRUE); 182 /* These are needed to test extended properties. */ 183 TEST_MATCH_SIMPLE(AGRAVE, AGRAVE, G_REGEX_CASELESS, 0, TRUE); 184 TEST_MATCH_SIMPLE(AGRAVE, AGRAVE_UPPER, G_REGEX_CASELESS, 0, TRUE); 185-- 186GitLab 187 188