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 */
267 r = strerror_r (errnum, buff, buff_len);
268 if (!error_messages [errnum])
269 error_messages [errnum] = g_strdup (buff);
270 #endif /* USE_STRERROR_R_XSI */
272 #else /* HAVE_STRERROR_R */
273 if (!error_messages [errnum])
274 error_messages [errnum] = g_strdup_printf ("Error code '%d'", errnum);
275 #endif /* HAVE_STRERROR_R */
279 pthread_mutex_unlock (&strerror_lock);
283 return error_messages [errnum];
287 g_strconcat (const gchar *first, ...)
292 g_return_val_if_fail (first != NULL, NULL);
294 total += strlen (first);
295 va_start (args, first);
296 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
301 ret = g_malloc (total + 1);
307 va_start (args, first);
308 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
317 add_to_vector (gchar ***vector, int size, gchar *token)
319 *vector = *vector == NULL ?
320 (gchar **)g_malloc(2 * sizeof(*vector)) :
321 (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
323 (*vector)[size - 1] = token;
327 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
330 gchar *token, **vector;
333 g_return_val_if_fail (string != NULL, NULL);
334 g_return_val_if_fail (delimiter != NULL, NULL);
335 g_return_val_if_fail (delimiter[0] != 0, NULL);
337 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
338 vector = (gchar **)g_malloc (2 * sizeof(vector));
339 vector[0] = g_strdup ("");
341 string += strlen (delimiter);
346 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
348 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
349 token = g_strdup ("");
350 string += strlen (delimiter);
352 while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
357 gsize toklen = (string - c);
358 token = g_strndup (c, toklen);
360 /* Need to leave a trailing empty
361 * token if the delimiter is the last
364 if (strcmp (string, delimiter) != 0) {
365 string += strlen (delimiter);
368 token = g_strdup (c);
372 add_to_vector (&vector, size, token);
377 if (strcmp (string, delimiter) == 0)
378 add_to_vector (&vector, size, g_strdup (""));
380 /* Add the rest of the string as the last element */
381 add_to_vector (&vector, size, g_strdup (string));
386 if (vector == NULL) {
387 vector = (gchar **) g_malloc (2 * sizeof (vector));
389 } else if (size > 0) {
390 vector[size - 1] = NULL;
397 charcmp (gchar testchar, const gchar *compare)
400 if (*compare == testchar) {
410 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
413 gchar *token, **vector;
416 g_return_val_if_fail (string != NULL, NULL);
417 g_return_val_if_fail (delimiter != NULL, NULL);
418 g_return_val_if_fail (delimiter[0] != 0, NULL);
420 if (charcmp (*string, delimiter)) {
421 vector = (gchar **)g_malloc (2 * sizeof(vector));
422 vector[0] = g_strdup ("");
430 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
431 if (charcmp (*string, delimiter)) {
432 gsize toklen = (string - c);
434 token = g_strdup ("");
436 token = g_strndup (c, toklen);
441 add_to_vector (&vector, size, token);
448 if (max_tokens > 0 && size >= max_tokens) {
450 /* Add the rest of the string as the last element */
451 add_to_vector (&vector, size, g_strdup (string));
456 /* Fill in the trailing last token */
457 add_to_vector (&vector, size, g_strdup (c));
460 /* Need to leave a trailing empty token if the
461 * delimiter is the last part of the string
463 add_to_vector (&vector, size, g_strdup (""));
468 if (vector == NULL) {
469 vector = (gchar **) g_malloc (2 * sizeof (vector));
471 } else if (size > 0) {
472 vector[size - 1] = NULL;
479 g_strreverse (gchar *str)
490 for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
500 g_strjoin (const gchar *separator, ...)
506 if (separator != NULL)
507 slen = strlen (separator);
512 va_start (args, separator);
513 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
520 return g_strdup ("");
522 /* Remove the last separator */
523 if (slen > 0 && len > 0)
526 res = g_malloc (len + 1);
527 va_start (args, separator);
528 s = va_arg (args, char *);
529 r = g_stpcpy (res, s);
530 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
531 if (separator != NULL)
532 r = g_stpcpy (r, separator);
541 g_strjoinv (const gchar *separator, gchar **str_array)
546 if (separator != NULL)
547 slen = strlen (separator);
552 for (i = 0; str_array [i] != NULL; i++){
553 len += strlen (str_array [i]);
558 return g_strdup ("");
560 if (slen > 0 && len > 0)
563 res = g_malloc (len + 1);
564 r = g_stpcpy (res, str_array [0]);
565 for (i = 1; str_array [i] != NULL; i++){
566 if (separator != NULL)
567 r = g_stpcpy (r, separator);
568 r = g_stpcpy (r, str_array [i]);
575 g_strchug (gchar *str)
584 while (*tmp && isspace (*tmp)) tmp++;
586 len = strlen (str) - (tmp - str - 1);
587 memmove (str, tmp, len);
593 g_strchomp (gchar *str)
600 tmp = str + strlen (str) - 1;
601 while (*tmp && isspace (*tmp)) tmp--;
607 g_printf(gchar const *format, ...)
612 va_start(args, format);
613 ret = vprintf(format, args);
620 g_fprintf(FILE *file, gchar const *format, ...)
625 va_start(args, format);
626 ret = vfprintf(file, format, args);
633 g_sprintf(gchar *string, gchar const *format, ...)
638 va_start(args, format);
639 ret = vsprintf(string, format, args);
646 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
651 va_start(args, format);
652 ret = vsnprintf(string, n, format, args);
658 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
659 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
662 char_needs_encoding (char c)
664 if (((unsigned char)c) >= 0x80)
667 if ((c >= '@' && c <= 'Z') ||
668 (c >= 'a' && c <= 'z') ||
669 (c >= '&' && c < 0x3b) ||
670 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
676 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
682 const char *uriPrefix = "file:///";
684 const char *uriPrefix = "file://";
687 g_return_val_if_fail (filename != NULL, NULL);
689 if (hostname != NULL)
690 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
692 if (!g_path_is_absolute (filename)){
694 *error = g_error_new (NULL, 2, "Not an absolute filename");
699 n = strlen (uriPrefix) + 1;
700 for (p = filename; *p; p++){
707 if (char_needs_encoding (*p))
713 strcpy (ret, uriPrefix);
714 for (p = filename, rp = ret + strlen (ret); *p; p++){
721 if (char_needs_encoding (*p)){
723 *rp++ = hx [((unsigned char)(*p)) >> 4];
724 *rp++ = hx [((unsigned char)(*p)) & 0xf];
735 if (p >= '0' && p <= '9')
737 if (p >= 'A' && p <= 'F')
739 if (p >= 'a' && p <= 'f')
741 g_assert_not_reached ();
746 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
752 g_return_val_if_fail (uri != NULL, NULL);
754 if (hostname != NULL)
755 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
757 if (strncmp (uri, "file:///", 8) != 0){
759 *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
763 for (p = uri + 8; *p; p++){
765 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
769 *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
779 result = g_malloc (flen + 1);
789 for (p = uri + 8; *p; p++){
791 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
801 g_strdown (gchar *string)
803 g_return_if_fail (string != NULL);
806 *string = (gchar)tolower (*string);
812 g_ascii_tolower (gchar c)
814 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
818 g_ascii_strdown (const gchar *str, gssize len)
823 g_return_val_if_fail (str != NULL, NULL);
828 ret = g_malloc (len + 1);
829 for (i = 0; i < len; i++)
830 ret [i] = (guchar) g_ascii_tolower (str [i]);
837 g_ascii_toupper (gchar c)
839 return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
843 g_ascii_strup (const gchar *str, gssize len)
848 g_return_val_if_fail (str != NULL, NULL);
853 ret = g_malloc (len + 1);
854 for (i = 0; i < len; i++)
855 ret [i] = (guchar) g_ascii_toupper (str [i]);
862 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
866 g_return_val_if_fail (s1 != NULL, 0);
867 g_return_val_if_fail (s2 != NULL, 0);
869 for (i = 0; i < n; i++) {
870 gchar c1 = g_ascii_tolower (*s1++);
871 gchar c2 = g_ascii_tolower (*s2++);
881 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
883 const char *sp1 = s1;
884 const char *sp2 = s2;
886 g_return_val_if_fail (s1 != NULL, 0);
887 g_return_val_if_fail (s2 != NULL, 0);
889 while (*sp1 != '\0') {
890 char c1 = g_ascii_tolower (*sp1++);
891 char c2 = g_ascii_tolower (*sp2++);
897 return (*sp1) - (*sp2);
901 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
905 g_return_val_if_fail (string != NULL, NULL);
907 if (delimiters == NULL)
908 delimiters = G_STR_DELIMITERS;
910 for (ptr = string; *ptr; ptr++) {
911 if (strchr (delimiters, *ptr))
912 *ptr = new_delimiter;
919 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
922 return strlcpy (dest, src, dest_size);
929 g_return_val_if_fail (src != NULL, 0);
930 g_return_val_if_fail (dest != NULL, 0);
942 return (dest_size - len - 1);
945 /* len is 0 i we get here */
947 /* we need to return the length of src here */
948 while (*s++) ; /* instead of a plain strlen, we use 's' */
954 g_stpcpy (gchar *dest, const char *src)
956 g_return_val_if_fail (dest != NULL, dest);
957 g_return_val_if_fail (src != NULL, dest);
960 return stpcpy (dest, src);
971 static const gchar escaped_dflt [256] = {
972 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
973 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
974 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, 0,
977 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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,
987 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
991 g_strescape (const gchar *source, const gchar *exceptions)
1000 g_return_val_if_fail (source != NULL, NULL);
1002 memcpy (escaped, escaped_dflt, 256);
1003 if (exceptions != NULL) {
1004 for (ptr = exceptions; *ptr; ptr++)
1005 escaped [(int) *ptr] = 0;
1007 result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
1009 for (ptr = source; *ptr; ptr++) {
1011 op = escaped [(int) c];
1019 *res_ptr++ = '0' + ((c >> 6) & 3);
1020 *res_ptr++ = '0' + ((c >> 3) & 7);
1021 *res_ptr++ = '0' + (c & 7);
1030 g_ascii_xdigit_value (gchar c)
1032 return ((isxdigit (c) == 0) ? -1 :
1033 ((c >= '0' && c <= '9') ? (c - '0') :
1034 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
1039 g_strnfill (gsize length, gchar fill_char)
1041 gchar *ret = g_new (gchar, length + 1);
1043 memset (ret, fill_char, length);