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 * g_strndup and g_vasprintf need to allocate memory with g_malloc if
43 * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free
47 /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
49 g_strndup (const gchar *str, gsize n)
51 #if defined (HAVE_STRNDUP) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
52 return strndup (str, n);
55 char *retval = g_malloc(n+1);
57 strncpy(retval, str, n)[n] = 0;
65 gint g_vasprintf (gchar **ret, const gchar *fmt, va_list ap)
67 #if defined (HAVE_VASPRINTF) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
68 return vasprintf (ret, fmt, ap);
75 #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
77 len = _vscprintf(fmt, ap2); // NOTE MS specific extension ( :-( )
80 len = vsnprintf(NULL, 0, fmt, ap2);
83 if (len >= 0 && (buf = g_malloc ((buflen = (size_t) (len + 1)))) != NULL) {
84 len = vsnprintf(buf, buflen, fmt, ap);
97 g_strfreev (gchar **str_array)
99 gchar **orig = str_array;
100 if (str_array == NULL)
102 while (*str_array != NULL){
110 g_strdupv (gchar **str_array)
119 length = g_strv_length(str_array);
120 ret = g_new0(gchar *, length + 1);
121 for (i = 0; str_array[i]; i++) {
122 ret[i] = g_strdup(str_array[i]);
129 g_strv_length(gchar **str_array)
132 g_return_val_if_fail(str_array != NULL, 0);
133 for(length = 0; str_array[length] != NULL; length++);
138 g_str_has_suffix(const gchar *str, const gchar *suffix)
141 size_t suffix_length;
143 g_return_val_if_fail(str != NULL, FALSE);
144 g_return_val_if_fail(suffix != NULL, FALSE);
146 str_length = strlen(str);
147 suffix_length = strlen(suffix);
149 return suffix_length <= str_length ?
150 strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0 :
155 g_str_has_prefix(const gchar *str, const gchar *prefix)
158 size_t prefix_length;
160 g_return_val_if_fail(str != NULL, FALSE);
161 g_return_val_if_fail(prefix != NULL, FALSE);
163 str_length = strlen(str);
164 prefix_length = strlen(prefix);
166 return prefix_length <= str_length ?
167 strncmp(str, prefix, prefix_length) == 0 :
172 g_strdup_vprintf (const gchar *format, va_list args)
177 n = g_vasprintf (&ret, format, args);
185 g_strdup_printf (const gchar *format, ...)
191 va_start (args, format);
192 n = g_vasprintf (&ret, format, args);
202 Max error number we support. It's empirically found by looking at our target OS.
204 Last this was checked was June-2017.
209 #define MONO_ERRNO_MAX 200
213 static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
216 static char *error_messages [MONO_ERRNO_MAX];
219 g_strerror (gint errnum)
223 if (errnum >= MONO_ERRNO_MAX)
224 return ("Error number higher than " str (MONO_ERRNO_MAX));
226 if (!error_messages [errnum]) {
228 pthread_mutex_lock (&strerror_lock);
231 #ifdef HAVE_STRERROR_R
232 char tmp_buff [128]; //Quite arbitrary, should be large enough
233 char *buff = tmp_buff;
234 int buff_len = sizeof (tmp_buff);
238 while ((r = strerror_r (errnum, buff, buff_len - 1))) {
240 buff = g_strdup_printf ("Invalid Error code '%d'", errnum);
243 if (buff == tmp_buff)
244 buff = g_malloc (buff_len * 2);
246 buff = g_realloc (buff, buff_len * 2);
248 //Spec is not clean on whether size argument includes space for null terminator or not
250 if (!error_messages [errnum])
251 error_messages [errnum] = g_strdup (buff);
252 if (buff != tmp_buff)
255 if (!error_messages [errnum])
256 error_messages [errnum] = g_strdup_printf ("Error code '%d'", errnum);
261 pthread_mutex_unlock (&strerror_lock);
265 return error_messages [errnum];
269 g_strconcat (const gchar *first, ...)
274 g_return_val_if_fail (first != NULL, NULL);
276 total += strlen (first);
277 va_start (args, first);
278 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
283 ret = g_malloc (total + 1);
289 va_start (args, first);
290 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
299 add_to_vector (gchar ***vector, int size, gchar *token)
301 *vector = *vector == NULL ?
302 (gchar **)g_malloc(2 * sizeof(*vector)) :
303 (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
305 (*vector)[size - 1] = token;
309 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
312 gchar *token, **vector;
315 g_return_val_if_fail (string != NULL, NULL);
316 g_return_val_if_fail (delimiter != NULL, NULL);
317 g_return_val_if_fail (delimiter[0] != 0, NULL);
319 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
320 vector = (gchar **)g_malloc (2 * sizeof(vector));
321 vector[0] = g_strdup ("");
323 string += strlen (delimiter);
328 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
330 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
331 token = g_strdup ("");
332 string += strlen (delimiter);
334 while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
339 gsize toklen = (string - c);
340 token = g_strndup (c, toklen);
342 /* Need to leave a trailing empty
343 * token if the delimiter is the last
346 if (strcmp (string, delimiter) != 0) {
347 string += strlen (delimiter);
350 token = g_strdup (c);
354 add_to_vector (&vector, size, token);
359 if (strcmp (string, delimiter) == 0)
360 add_to_vector (&vector, size, g_strdup (""));
362 /* Add the rest of the string as the last element */
363 add_to_vector (&vector, size, g_strdup (string));
368 if (vector == NULL) {
369 vector = (gchar **) g_malloc (2 * sizeof (vector));
371 } else if (size > 0) {
372 vector[size - 1] = NULL;
379 charcmp (gchar testchar, const gchar *compare)
382 if (*compare == testchar) {
392 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
395 gchar *token, **vector;
398 g_return_val_if_fail (string != NULL, NULL);
399 g_return_val_if_fail (delimiter != NULL, NULL);
400 g_return_val_if_fail (delimiter[0] != 0, NULL);
402 if (charcmp (*string, delimiter)) {
403 vector = (gchar **)g_malloc (2 * sizeof(vector));
404 vector[0] = g_strdup ("");
412 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
413 if (charcmp (*string, delimiter)) {
414 gsize toklen = (string - c);
416 token = g_strdup ("");
418 token = g_strndup (c, toklen);
423 add_to_vector (&vector, size, token);
430 if (max_tokens > 0 && size >= max_tokens) {
432 /* Add the rest of the string as the last element */
433 add_to_vector (&vector, size, g_strdup (string));
438 /* Fill in the trailing last token */
439 add_to_vector (&vector, size, g_strdup (c));
442 /* Need to leave a trailing empty token if the
443 * delimiter is the last part of the string
445 add_to_vector (&vector, size, g_strdup (""));
450 if (vector == NULL) {
451 vector = (gchar **) g_malloc (2 * sizeof (vector));
453 } else if (size > 0) {
454 vector[size - 1] = NULL;
461 g_strreverse (gchar *str)
472 for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
482 g_strjoin (const gchar *separator, ...)
488 if (separator != NULL)
489 slen = strlen (separator);
494 va_start (args, separator);
495 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
502 return g_strdup ("");
504 /* Remove the last separator */
505 if (slen > 0 && len > 0)
508 res = g_malloc (len + 1);
509 va_start (args, separator);
510 s = va_arg (args, char *);
511 r = g_stpcpy (res, s);
512 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
513 if (separator != NULL)
514 r = g_stpcpy (r, separator);
523 g_strjoinv (const gchar *separator, gchar **str_array)
528 if (separator != NULL)
529 slen = strlen (separator);
534 for (i = 0; str_array [i] != NULL; i++){
535 len += strlen (str_array [i]);
540 return g_strdup ("");
542 if (slen > 0 && len > 0)
545 res = g_malloc (len + 1);
546 r = g_stpcpy (res, str_array [0]);
547 for (i = 1; str_array [i] != NULL; i++){
548 if (separator != NULL)
549 r = g_stpcpy (r, separator);
550 r = g_stpcpy (r, str_array [i]);
557 g_strchug (gchar *str)
566 while (*tmp && isspace (*tmp)) tmp++;
568 len = strlen (str) - (tmp - str - 1);
569 memmove (str, tmp, len);
575 g_strchomp (gchar *str)
582 tmp = str + strlen (str) - 1;
583 while (*tmp && isspace (*tmp)) tmp--;
589 g_printf(gchar const *format, ...)
594 va_start(args, format);
595 ret = vprintf(format, args);
602 g_fprintf(FILE *file, gchar const *format, ...)
607 va_start(args, format);
608 ret = vfprintf(file, format, args);
615 g_sprintf(gchar *string, gchar const *format, ...)
620 va_start(args, format);
621 ret = vsprintf(string, format, args);
628 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
633 va_start(args, format);
634 ret = vsnprintf(string, n, format, args);
640 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
641 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
644 char_needs_encoding (char c)
646 if (((unsigned char)c) >= 0x80)
649 if ((c >= '@' && c <= 'Z') ||
650 (c >= 'a' && c <= 'z') ||
651 (c >= '&' && c < 0x3b) ||
652 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
658 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
664 const char *uriPrefix = "file:///";
666 const char *uriPrefix = "file://";
669 g_return_val_if_fail (filename != NULL, NULL);
671 if (hostname != NULL)
672 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
674 if (!g_path_is_absolute (filename)){
676 *error = g_error_new (NULL, 2, "Not an absolute filename");
681 n = strlen (uriPrefix) + 1;
682 for (p = filename; *p; p++){
689 if (char_needs_encoding (*p))
695 strcpy (ret, uriPrefix);
696 for (p = filename, rp = ret + strlen (ret); *p; p++){
703 if (char_needs_encoding (*p)){
705 *rp++ = hx [((unsigned char)(*p)) >> 4];
706 *rp++ = hx [((unsigned char)(*p)) & 0xf];
717 if (p >= '0' && p <= '9')
719 if (p >= 'A' && p <= 'F')
721 if (p >= 'a' && p <= 'f')
723 g_assert_not_reached ();
728 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
734 g_return_val_if_fail (uri != NULL, NULL);
736 if (hostname != NULL)
737 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
739 if (strncmp (uri, "file:///", 8) != 0){
741 *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
745 for (p = uri + 8; *p; p++){
747 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
751 *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
761 result = g_malloc (flen + 1);
771 for (p = uri + 8; *p; p++){
773 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
783 g_strdown (gchar *string)
785 g_return_if_fail (string != NULL);
788 *string = (gchar)tolower (*string);
794 g_ascii_tolower (gchar c)
796 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
800 g_ascii_strdown (const gchar *str, gssize len)
805 g_return_val_if_fail (str != NULL, NULL);
810 ret = g_malloc (len + 1);
811 for (i = 0; i < len; i++)
812 ret [i] = (guchar) g_ascii_tolower (str [i]);
819 g_ascii_toupper (gchar c)
821 return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
825 g_ascii_strup (const gchar *str, gssize len)
830 g_return_val_if_fail (str != NULL, NULL);
835 ret = g_malloc (len + 1);
836 for (i = 0; i < len; i++)
837 ret [i] = (guchar) g_ascii_toupper (str [i]);
844 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
848 g_return_val_if_fail (s1 != NULL, 0);
849 g_return_val_if_fail (s2 != NULL, 0);
851 for (i = 0; i < n; i++) {
852 gchar c1 = g_ascii_tolower (*s1++);
853 gchar c2 = g_ascii_tolower (*s2++);
863 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
865 const char *sp1 = s1;
866 const char *sp2 = s2;
868 g_return_val_if_fail (s1 != NULL, 0);
869 g_return_val_if_fail (s2 != NULL, 0);
871 while (*sp1 != '\0') {
872 char c1 = g_ascii_tolower (*sp1++);
873 char c2 = g_ascii_tolower (*sp2++);
879 return (*sp1) - (*sp2);
883 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
887 g_return_val_if_fail (string != NULL, NULL);
889 if (delimiters == NULL)
890 delimiters = G_STR_DELIMITERS;
892 for (ptr = string; *ptr; ptr++) {
893 if (strchr (delimiters, *ptr))
894 *ptr = new_delimiter;
901 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
904 return strlcpy (dest, src, dest_size);
911 g_return_val_if_fail (src != NULL, 0);
912 g_return_val_if_fail (dest != NULL, 0);
924 return (dest_size - len - 1);
927 /* len is 0 i we get here */
929 /* we need to return the length of src here */
930 while (*s++) ; /* instead of a plain strlen, we use 's' */
936 g_stpcpy (gchar *dest, const char *src)
938 g_return_val_if_fail (dest != NULL, dest);
939 g_return_val_if_fail (src != NULL, dest);
942 return stpcpy (dest, src);
953 static const gchar escaped_dflt [256] = {
954 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
955 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
956 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
957 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
958 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
959 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
960 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
961 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
962 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
963 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
964 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
965 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
966 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
967 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
968 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
969 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
973 g_strescape (const gchar *source, const gchar *exceptions)
982 g_return_val_if_fail (source != NULL, NULL);
984 memcpy (escaped, escaped_dflt, 256);
985 if (exceptions != NULL) {
986 for (ptr = exceptions; *ptr; ptr++)
987 escaped [(int) *ptr] = 0;
989 result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
991 for (ptr = source; *ptr; ptr++) {
993 op = escaped [(int) c];
1001 *res_ptr++ = '0' + ((c >> 6) & 3);
1002 *res_ptr++ = '0' + ((c >> 3) & 7);
1003 *res_ptr++ = '0' + (c & 7);
1012 g_ascii_xdigit_value (gchar c)
1014 return ((isxdigit (c) == 0) ? -1 :
1015 ((c >= '0' && c <= '9') ? (c - '0') :
1016 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
1021 g_strnfill (gsize length, gchar fill_char)
1023 gchar *ret = g_new (gchar, length + 1);
1025 memset (ret, fill_char, length);