2 * gstr.c: String Utility Functions.
5 * Miguel de Icaza (miguel@novell.com)
6 * Aaron Bockover (abockover@novell.com)
8 * (C) 2006 Novell, Inc.
10 * Permission is hereby granted, free of charge, to any person obtaining
11 * a copy of this software and associated documentation files (the
12 * "Software"), to deal in the Software without restriction, including
13 * without limitation the rights to use, copy, modify, merge, publish,
14 * distribute, sublicense, and/or sell copies of the Software, and to
15 * permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 * Linux knows two different versions of strerror_r () that can only be distinguished
43 * by using feature test macros. Please check the man pages for more details.
45 #if defined (_POSIX_C_SOURCE) && defined (_GNU_SOURCE)
46 #if (_POSIX_C_SOURCE >= 200112L) && !_GNU_SOURCE
47 #define USE_STRERROR_R_XSI
52 * g_strndup and g_vasprintf need to allocate memory with g_malloc if
53 * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free
57 /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
59 g_strndup (const gchar *str, gsize n)
61 #if defined (HAVE_STRNDUP) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
62 return strndup (str, n);
65 char *retval = g_malloc(n+1);
67 strncpy(retval, str, n)[n] = 0;
75 gint g_vasprintf (gchar **ret, const gchar *fmt, va_list ap)
77 #if defined (HAVE_VASPRINTF) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
78 return vasprintf (ret, fmt, ap);
85 #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
87 len = _vscprintf(fmt, ap2); // NOTE MS specific extension ( :-( )
90 len = vsnprintf(NULL, 0, fmt, ap2);
93 if (len >= 0 && (buf = g_malloc ((buflen = (size_t) (len + 1)))) != NULL) {
94 len = vsnprintf(buf, buflen, fmt, ap);
107 g_strfreev (gchar **str_array)
109 gchar **orig = str_array;
110 if (str_array == NULL)
112 while (*str_array != NULL){
120 g_strdupv (gchar **str_array)
129 length = g_strv_length(str_array);
130 ret = g_new0(gchar *, length + 1);
131 for (i = 0; str_array[i]; i++) {
132 ret[i] = g_strdup(str_array[i]);
139 g_strv_length(gchar **str_array)
142 g_return_val_if_fail(str_array != NULL, 0);
143 for(length = 0; str_array[length] != NULL; length++);
148 g_str_has_suffix(const gchar *str, const gchar *suffix)
151 size_t suffix_length;
153 g_return_val_if_fail(str != NULL, FALSE);
154 g_return_val_if_fail(suffix != NULL, FALSE);
156 str_length = strlen(str);
157 suffix_length = strlen(suffix);
159 return suffix_length <= str_length ?
160 strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0 :
165 g_str_has_prefix(const gchar *str, const gchar *prefix)
168 size_t prefix_length;
170 g_return_val_if_fail(str != NULL, FALSE);
171 g_return_val_if_fail(prefix != NULL, FALSE);
173 str_length = strlen(str);
174 prefix_length = strlen(prefix);
176 return prefix_length <= str_length ?
177 strncmp(str, prefix, prefix_length) == 0 :
182 g_strdup_vprintf (const gchar *format, va_list args)
187 n = g_vasprintf (&ret, format, args);
195 g_strdup_printf (const gchar *format, ...)
201 va_start (args, format);
202 n = g_vasprintf (&ret, format, args);
212 Max error number we support. It's empirically found by looking at our target OS.
214 Last this was checked was June-2017.
219 #define MONO_ERRNO_MAX 200
223 static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
226 static char *error_messages [MONO_ERRNO_MAX];
229 g_strerror (gint errnum)
233 if (errnum >= MONO_ERRNO_MAX)
234 return ("Error number higher than " str (MONO_ERRNO_MAX));
236 if (!error_messages [errnum]) {
238 pthread_mutex_lock (&strerror_lock);
241 #ifdef HAVE_STRERROR_R
242 char tmp_buff [128]; //Quite arbitrary, should be large enough
243 char *buff = tmp_buff;
244 size_t buff_len = sizeof (tmp_buff);
247 #ifdef USE_STRERROR_R_XSI
249 while ((r = strerror_r (errnum, buff, buff_len - 1))) {
251 buff = g_strdup_printf ("Invalid Error code '%d'", errnum);
254 if (buff == tmp_buff)
255 buff = g_malloc (buff_len * 2);
257 buff = g_realloc (buff, buff_len * 2);
259 //Spec is not clean on whether size argument includes space for null terminator or not
261 if (!error_messages [errnum])
262 error_messages [errnum] = g_strdup (buff);
263 if (buff != tmp_buff)
265 #else /* USE_STRERROR_R_XSI */
266 buff = strerror_r (errnum, buff, buff_len);
267 if (!error_messages [errnum])
268 error_messages [errnum] = g_strdup (buff);
269 #endif /* USE_STRERROR_R_XSI */
271 #else /* HAVE_STRERROR_R */
272 if (!error_messages [errnum])
273 error_messages [errnum] = g_strdup_printf ("Error code '%d'", errnum);
274 #endif /* HAVE_STRERROR_R */
278 pthread_mutex_unlock (&strerror_lock);
282 return error_messages [errnum];
286 g_strconcat (const gchar *first, ...)
291 g_return_val_if_fail (first != NULL, NULL);
293 total += strlen (first);
294 va_start (args, first);
295 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
300 ret = g_malloc (total + 1);
306 va_start (args, first);
307 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
316 add_to_vector (gchar ***vector, int size, gchar *token)
318 *vector = *vector == NULL ?
319 (gchar **)g_malloc(2 * sizeof(*vector)) :
320 (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
322 (*vector)[size - 1] = token;
326 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
329 gchar *token, **vector;
332 g_return_val_if_fail (string != NULL, NULL);
333 g_return_val_if_fail (delimiter != NULL, NULL);
334 g_return_val_if_fail (delimiter[0] != 0, NULL);
336 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
337 vector = (gchar **)g_malloc (2 * sizeof(vector));
338 vector[0] = g_strdup ("");
340 string += strlen (delimiter);
345 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
347 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
348 token = g_strdup ("");
349 string += strlen (delimiter);
351 while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
356 gsize toklen = (string - c);
357 token = g_strndup (c, toklen);
359 /* Need to leave a trailing empty
360 * token if the delimiter is the last
363 if (strcmp (string, delimiter) != 0) {
364 string += strlen (delimiter);
367 token = g_strdup (c);
371 add_to_vector (&vector, size, token);
376 if (strcmp (string, delimiter) == 0)
377 add_to_vector (&vector, size, g_strdup (""));
379 /* Add the rest of the string as the last element */
380 add_to_vector (&vector, size, g_strdup (string));
385 if (vector == NULL) {
386 vector = (gchar **) g_malloc (2 * sizeof (vector));
388 } else if (size > 0) {
389 vector[size - 1] = NULL;
396 charcmp (gchar testchar, const gchar *compare)
399 if (*compare == testchar) {
409 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
412 gchar *token, **vector;
415 g_return_val_if_fail (string != NULL, NULL);
416 g_return_val_if_fail (delimiter != NULL, NULL);
417 g_return_val_if_fail (delimiter[0] != 0, NULL);
419 if (charcmp (*string, delimiter)) {
420 vector = (gchar **)g_malloc (2 * sizeof(vector));
421 vector[0] = g_strdup ("");
429 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
430 if (charcmp (*string, delimiter)) {
431 gsize toklen = (string - c);
433 token = g_strdup ("");
435 token = g_strndup (c, toklen);
440 add_to_vector (&vector, size, token);
447 if (max_tokens > 0 && size >= max_tokens) {
449 /* Add the rest of the string as the last element */
450 add_to_vector (&vector, size, g_strdup (string));
455 /* Fill in the trailing last token */
456 add_to_vector (&vector, size, g_strdup (c));
459 /* Need to leave a trailing empty token if the
460 * delimiter is the last part of the string
462 add_to_vector (&vector, size, g_strdup (""));
467 if (vector == NULL) {
468 vector = (gchar **) g_malloc (2 * sizeof (vector));
470 } else if (size > 0) {
471 vector[size - 1] = NULL;
478 g_strreverse (gchar *str)
489 for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
499 g_strjoin (const gchar *separator, ...)
505 if (separator != NULL)
506 slen = strlen (separator);
511 va_start (args, separator);
512 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
519 return g_strdup ("");
521 /* Remove the last separator */
522 if (slen > 0 && len > 0)
525 res = g_malloc (len + 1);
526 va_start (args, separator);
527 s = va_arg (args, char *);
528 r = g_stpcpy (res, s);
529 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
530 if (separator != NULL)
531 r = g_stpcpy (r, separator);
540 g_strjoinv (const gchar *separator, gchar **str_array)
545 if (separator != NULL)
546 slen = strlen (separator);
551 for (i = 0; str_array [i] != NULL; i++){
552 len += strlen (str_array [i]);
557 return g_strdup ("");
559 if (slen > 0 && len > 0)
562 res = g_malloc (len + 1);
563 r = g_stpcpy (res, str_array [0]);
564 for (i = 1; str_array [i] != NULL; i++){
565 if (separator != NULL)
566 r = g_stpcpy (r, separator);
567 r = g_stpcpy (r, str_array [i]);
574 g_strchug (gchar *str)
583 while (*tmp && isspace (*tmp)) tmp++;
585 len = strlen (str) - (tmp - str - 1);
586 memmove (str, tmp, len);
592 g_strchomp (gchar *str)
599 tmp = str + strlen (str) - 1;
600 while (*tmp && isspace (*tmp)) tmp--;
606 g_printf(gchar const *format, ...)
611 va_start(args, format);
612 ret = vprintf(format, args);
619 g_fprintf(FILE *file, gchar const *format, ...)
624 va_start(args, format);
625 ret = vfprintf(file, format, args);
632 g_sprintf(gchar *string, gchar const *format, ...)
637 va_start(args, format);
638 ret = vsprintf(string, format, args);
645 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
650 va_start(args, format);
651 ret = vsnprintf(string, n, format, args);
657 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
658 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
661 char_needs_encoding (char c)
663 if (((unsigned char)c) >= 0x80)
666 if ((c >= '@' && c <= 'Z') ||
667 (c >= 'a' && c <= 'z') ||
668 (c >= '&' && c < 0x3b) ||
669 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
675 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
681 const char *uriPrefix = "file:///";
683 const char *uriPrefix = "file://";
686 g_return_val_if_fail (filename != NULL, NULL);
688 if (hostname != NULL)
689 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
691 if (!g_path_is_absolute (filename)){
693 *error = g_error_new (NULL, 2, "Not an absolute filename");
698 n = strlen (uriPrefix) + 1;
699 for (p = filename; *p; p++){
706 if (char_needs_encoding (*p))
712 strcpy (ret, uriPrefix);
713 for (p = filename, rp = ret + strlen (ret); *p; p++){
720 if (char_needs_encoding (*p)){
722 *rp++ = hx [((unsigned char)(*p)) >> 4];
723 *rp++ = hx [((unsigned char)(*p)) & 0xf];
734 if (p >= '0' && p <= '9')
736 if (p >= 'A' && p <= 'F')
738 if (p >= 'a' && p <= 'f')
740 g_assert_not_reached ();
745 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
751 g_return_val_if_fail (uri != NULL, NULL);
753 if (hostname != NULL)
754 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
756 if (strncmp (uri, "file:///", 8) != 0){
758 *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
762 for (p = uri + 8; *p; p++){
764 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
768 *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
778 result = g_malloc (flen + 1);
788 for (p = uri + 8; *p; p++){
790 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
800 g_strdown (gchar *string)
802 g_return_if_fail (string != NULL);
805 *string = (gchar)tolower (*string);
811 g_ascii_tolower (gchar c)
813 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
817 g_ascii_strdown (const gchar *str, gssize len)
822 g_return_val_if_fail (str != NULL, NULL);
827 ret = g_malloc (len + 1);
828 for (i = 0; i < len; i++)
829 ret [i] = (guchar) g_ascii_tolower (str [i]);
836 g_ascii_toupper (gchar c)
838 return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
842 g_ascii_strup (const gchar *str, gssize len)
847 g_return_val_if_fail (str != NULL, NULL);
852 ret = g_malloc (len + 1);
853 for (i = 0; i < len; i++)
854 ret [i] = (guchar) g_ascii_toupper (str [i]);
861 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
865 g_return_val_if_fail (s1 != NULL, 0);
866 g_return_val_if_fail (s2 != NULL, 0);
868 for (i = 0; i < n; i++) {
869 gchar c1 = g_ascii_tolower (*s1++);
870 gchar c2 = g_ascii_tolower (*s2++);
880 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
882 const char *sp1 = s1;
883 const char *sp2 = s2;
885 g_return_val_if_fail (s1 != NULL, 0);
886 g_return_val_if_fail (s2 != NULL, 0);
888 while (*sp1 != '\0') {
889 char c1 = g_ascii_tolower (*sp1++);
890 char c2 = g_ascii_tolower (*sp2++);
896 return (*sp1) - (*sp2);
900 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
904 g_return_val_if_fail (string != NULL, NULL);
906 if (delimiters == NULL)
907 delimiters = G_STR_DELIMITERS;
909 for (ptr = string; *ptr; ptr++) {
910 if (strchr (delimiters, *ptr))
911 *ptr = new_delimiter;
918 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
921 return strlcpy (dest, src, dest_size);
928 g_return_val_if_fail (src != NULL, 0);
929 g_return_val_if_fail (dest != NULL, 0);
941 return (dest_size - len - 1);
944 /* len is 0 i we get here */
946 /* we need to return the length of src here */
947 while (*s++) ; /* instead of a plain strlen, we use 's' */
953 g_stpcpy (gchar *dest, const char *src)
955 g_return_val_if_fail (dest != NULL, dest);
956 g_return_val_if_fail (src != NULL, dest);
959 return stpcpy (dest, src);
970 static const gchar escaped_dflt [256] = {
971 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
972 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
973 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
974 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
975 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
976 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
977 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
978 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
979 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
980 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
981 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
982 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
983 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
984 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
985 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
986 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
990 g_strescape (const gchar *source, const gchar *exceptions)
999 g_return_val_if_fail (source != NULL, NULL);
1001 memcpy (escaped, escaped_dflt, 256);
1002 if (exceptions != NULL) {
1003 for (ptr = exceptions; *ptr; ptr++)
1004 escaped [(int) *ptr] = 0;
1006 result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
1008 for (ptr = source; *ptr; ptr++) {
1010 op = escaped [(int) c];
1018 *res_ptr++ = '0' + ((c >> 6) & 3);
1019 *res_ptr++ = '0' + ((c >> 3) & 7);
1020 *res_ptr++ = '0' + (c & 7);
1029 g_ascii_xdigit_value (gchar c)
1031 return ((isxdigit (c) == 0) ? -1 :
1032 ((c >= '0' && c <= '9') ? (c - '0') :
1033 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
1038 g_strnfill (gsize length, gchar fill_char)
1040 gchar *ret = g_new (gchar, length + 1);
1042 memset (ret, fill_char, length);