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 size_t buff_len
= sizeof (tmp_buff
);
237 #ifndef STRERROR_R_CHAR_P
239 while ((r
= strerror_r (errnum
, buff
, buff_len
- 1))) {
241 buff
= g_strdup_printf ("Invalid Error code '%d'", errnum
);
244 if (buff
== tmp_buff
)
245 buff
= g_malloc (buff_len
* 2);
247 buff
= g_realloc (buff
, buff_len
* 2);
249 //Spec is not clean on whether size argument includes space for null terminator or not
251 if (!error_messages
[errnum
])
252 error_messages
[errnum
] = g_strdup (buff
);
253 if (buff
!= tmp_buff
)
255 #else /* STRERROR_R_CHAR_P */
256 buff
= strerror_r (errnum
, buff
, buff_len
);
257 if (!error_messages
[errnum
])
258 error_messages
[errnum
] = g_strdup (buff
);
259 #endif /* STRERROR_R_CHAR_P */
261 #else /* HAVE_STRERROR_R */
262 if (!error_messages
[errnum
])
263 error_messages
[errnum
] = g_strdup_printf ("Error code '%d'", errnum
);
264 #endif /* HAVE_STRERROR_R */
268 pthread_mutex_unlock (&strerror_lock
);
272 return error_messages
[errnum
];
276 g_strconcat (const gchar
*first
, ...)
281 g_return_val_if_fail (first
!= NULL
, NULL
);
283 total
+= strlen (first
);
284 va_start (args
, first
);
285 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg(args
, char *)){
290 ret
= g_malloc (total
+ 1);
296 va_start (args
, first
);
297 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg(args
, char *)){
306 add_to_vector (gchar
***vector
, int size
, gchar
*token
)
308 *vector
= *vector
== NULL
?
309 (gchar
**)g_malloc(2 * sizeof(*vector
)) :
310 (gchar
**)g_realloc(*vector
, (size
+ 1) * sizeof(*vector
));
312 (*vector
)[size
- 1] = token
;
316 g_strsplit (const gchar
*string
, const gchar
*delimiter
, gint max_tokens
)
319 gchar
*token
, **vector
;
322 g_return_val_if_fail (string
!= NULL
, NULL
);
323 g_return_val_if_fail (delimiter
!= NULL
, NULL
);
324 g_return_val_if_fail (delimiter
[0] != 0, NULL
);
326 if (strncmp (string
, delimiter
, strlen (delimiter
)) == 0) {
327 vector
= (gchar
**)g_malloc (2 * sizeof(vector
));
328 vector
[0] = g_strdup ("");
330 string
+= strlen (delimiter
);
335 while (*string
&& !(max_tokens
> 0 && size
>= max_tokens
)) {
337 if (strncmp (string
, delimiter
, strlen (delimiter
)) == 0) {
338 token
= g_strdup ("");
339 string
+= strlen (delimiter
);
341 while (*string
&& strncmp (string
, delimiter
, strlen (delimiter
)) != 0) {
346 gsize toklen
= (string
- c
);
347 token
= g_strndup (c
, toklen
);
349 /* Need to leave a trailing empty
350 * token if the delimiter is the last
353 if (strcmp (string
, delimiter
) != 0) {
354 string
+= strlen (delimiter
);
357 token
= g_strdup (c
);
361 add_to_vector (&vector
, size
, token
);
366 if (strcmp (string
, delimiter
) == 0)
367 add_to_vector (&vector
, size
, g_strdup (""));
369 /* Add the rest of the string as the last element */
370 add_to_vector (&vector
, size
, g_strdup (string
));
375 if (vector
== NULL
) {
376 vector
= (gchar
**) g_malloc (2 * sizeof (vector
));
378 } else if (size
> 0) {
379 vector
[size
- 1] = NULL
;
386 charcmp (gchar testchar
, const gchar
*compare
)
389 if (*compare
== testchar
) {
399 g_strsplit_set (const gchar
*string
, const gchar
*delimiter
, gint max_tokens
)
402 gchar
*token
, **vector
;
405 g_return_val_if_fail (string
!= NULL
, NULL
);
406 g_return_val_if_fail (delimiter
!= NULL
, NULL
);
407 g_return_val_if_fail (delimiter
[0] != 0, NULL
);
409 if (charcmp (*string
, delimiter
)) {
410 vector
= (gchar
**)g_malloc (2 * sizeof(vector
));
411 vector
[0] = g_strdup ("");
419 while (*string
&& !(max_tokens
> 0 && size
>= max_tokens
)) {
420 if (charcmp (*string
, delimiter
)) {
421 gsize toklen
= (string
- c
);
423 token
= g_strdup ("");
425 token
= g_strndup (c
, toklen
);
430 add_to_vector (&vector
, size
, token
);
437 if (max_tokens
> 0 && size
>= max_tokens
) {
439 /* Add the rest of the string as the last element */
440 add_to_vector (&vector
, size
, g_strdup (string
));
445 /* Fill in the trailing last token */
446 add_to_vector (&vector
, size
, g_strdup (c
));
449 /* Need to leave a trailing empty token if the
450 * delimiter is the last part of the string
452 add_to_vector (&vector
, size
, g_strdup (""));
457 if (vector
== NULL
) {
458 vector
= (gchar
**) g_malloc (2 * sizeof (vector
));
460 } else if (size
> 0) {
461 vector
[size
- 1] = NULL
;
468 g_strreverse (gchar
*str
)
479 for (i
= 0, j
= strlen (str
) - 1; i
< j
; i
++, j
--) {
489 g_strjoin (const gchar
*separator
, ...)
495 if (separator
!= NULL
)
496 slen
= strlen (separator
);
501 va_start (args
, separator
);
502 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg (args
, char *)){
509 return g_strdup ("");
511 /* Remove the last separator */
512 if (slen
> 0 && len
> 0)
515 res
= g_malloc (len
+ 1);
516 va_start (args
, separator
);
517 s
= va_arg (args
, char *);
518 r
= g_stpcpy (res
, s
);
519 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg (args
, char *)){
520 if (separator
!= NULL
)
521 r
= g_stpcpy (r
, separator
);
530 g_strjoinv (const gchar
*separator
, gchar
**str_array
)
535 if (separator
!= NULL
)
536 slen
= strlen (separator
);
541 for (i
= 0; str_array
[i
] != NULL
; i
++){
542 len
+= strlen (str_array
[i
]);
547 return g_strdup ("");
549 if (slen
> 0 && len
> 0)
552 res
= g_malloc (len
+ 1);
553 r
= g_stpcpy (res
, str_array
[0]);
554 for (i
= 1; str_array
[i
] != NULL
; i
++){
555 if (separator
!= NULL
)
556 r
= g_stpcpy (r
, separator
);
557 r
= g_stpcpy (r
, str_array
[i
]);
564 g_strchug (gchar
*str
)
573 while (*tmp
&& isspace (*tmp
)) tmp
++;
575 len
= strlen (str
) - (tmp
- str
- 1);
576 memmove (str
, tmp
, len
);
582 g_strchomp (gchar
*str
)
589 tmp
= str
+ strlen (str
) - 1;
590 while (*tmp
&& isspace (*tmp
)) tmp
--;
596 g_printf(gchar
const *format
, ...)
601 va_start(args
, format
);
602 ret
= vprintf(format
, args
);
609 g_fprintf(FILE *file
, gchar
const *format
, ...)
614 va_start(args
, format
);
615 ret
= vfprintf(file
, format
, args
);
622 g_sprintf(gchar
*string
, gchar
const *format
, ...)
627 va_start(args
, format
);
628 ret
= vsprintf(string
, format
, args
);
635 g_snprintf(gchar
*string
, gulong n
, gchar
const *format
, ...)
640 va_start(args
, format
);
641 ret
= vsnprintf(string
, n
, format
, args
);
647 static const char hx
[] = { '0', '1', '2', '3', '4', '5', '6', '7',
648 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
651 char_needs_encoding (char c
)
653 if (((unsigned char)c
) >= 0x80)
656 if ((c
>= '@' && c
<= 'Z') ||
657 (c
>= 'a' && c
<= 'z') ||
658 (c
>= '&' && c
< 0x3b) ||
659 (c
== '!') || (c
== '$') || (c
== '_') || (c
== '=') || (c
== '~'))
665 g_filename_to_uri (const gchar
*filename
, const gchar
*hostname
, GError
**gerror
)
671 const char *uriPrefix
= "file:///";
673 const char *uriPrefix
= "file://";
676 g_return_val_if_fail (filename
!= NULL
, NULL
);
678 if (hostname
!= NULL
)
679 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
681 if (!g_path_is_absolute (filename
)){
683 *gerror
= g_error_new (NULL
, 2, "Not an absolute filename");
688 n
= strlen (uriPrefix
) + 1;
689 for (p
= filename
; *p
; p
++){
696 if (char_needs_encoding (*p
))
702 strcpy (ret
, uriPrefix
);
703 for (p
= filename
, rp
= ret
+ strlen (ret
); *p
; p
++){
710 if (char_needs_encoding (*p
)){
712 *rp
++ = hx
[((unsigned char)(*p
)) >> 4];
713 *rp
++ = hx
[((unsigned char)(*p
)) & 0xf];
724 if (p
>= '0' && p
<= '9')
726 if (p
>= 'A' && p
<= 'F')
728 if (p
>= 'a' && p
<= 'f')
730 g_assert_not_reached ();
735 g_filename_from_uri (const gchar
*uri
, gchar
**hostname
, GError
**gerror
)
741 g_return_val_if_fail (uri
!= NULL
, NULL
);
743 if (hostname
!= NULL
)
744 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
746 if (strncmp (uri
, "file:///", 8) != 0){
748 *gerror
= g_error_new (NULL
, 2, "URI does not start with the file: scheme");
752 for (p
= uri
+ 8; *p
; p
++){
754 if (p
[1] && p
[2] && isxdigit (p
[1]) && isxdigit (p
[2])){
758 *gerror
= g_error_new (NULL
, 2, "URI contains an invalid escape sequence");
768 result
= g_malloc (flen
+ 1);
778 for (p
= uri
+ 8; *p
; p
++){
780 *r
++ = (char)((decode (p
[1]) << 4) | decode (p
[2]));
790 g_strdown (gchar
*string
)
792 g_return_if_fail (string
!= NULL
);
795 *string
= (gchar
)tolower (*string
);
801 g_ascii_tolower (gchar c
)
803 return c
>= 'A' && c
<= 'Z' ? c
+ ('a' - 'A') : c
;
807 g_ascii_strdown (const gchar
*str
, gssize len
)
812 g_return_val_if_fail (str
!= NULL
, NULL
);
817 ret
= g_malloc (len
+ 1);
818 for (i
= 0; i
< len
; i
++)
819 ret
[i
] = (guchar
) g_ascii_tolower (str
[i
]);
826 g_ascii_toupper (gchar c
)
828 return c
>= 'a' && c
<= 'z' ? c
+ ('A' - 'a') : c
;
832 g_ascii_strup (const gchar
*str
, gssize len
)
837 g_return_val_if_fail (str
!= NULL
, NULL
);
842 ret
= g_malloc (len
+ 1);
843 for (i
= 0; i
< len
; i
++)
844 ret
[i
] = (guchar
) g_ascii_toupper (str
[i
]);
851 g_ascii_strncasecmp (const gchar
*s1
, const gchar
*s2
, gsize n
)
855 g_return_val_if_fail (s1
!= NULL
, 0);
856 g_return_val_if_fail (s2
!= NULL
, 0);
858 for (i
= 0; i
< n
; i
++) {
859 gchar c1
= g_ascii_tolower (*s1
++);
860 gchar c2
= g_ascii_tolower (*s2
++);
870 g_ascii_strcasecmp (const gchar
*s1
, const gchar
*s2
)
872 const char *sp1
= s1
;
873 const char *sp2
= s2
;
875 g_return_val_if_fail (s1
!= NULL
, 0);
876 g_return_val_if_fail (s2
!= NULL
, 0);
878 while (*sp1
!= '\0') {
879 char c1
= g_ascii_tolower (*sp1
++);
880 char c2
= g_ascii_tolower (*sp2
++);
886 return (*sp1
) - (*sp2
);
890 g_utf16_ascii_equal (const gunichar2
*utf16
, size_t ulen
, const char *ascii
, size_t alen
)
895 for (i
= 0; i
< ulen
; ++i
) {
896 if (utf16
[i
] != ascii
[i
])
903 g_utf16_asciiz_equal (const gunichar2
*utf16
, const char *ascii
)
904 // z for zero means null terminated
909 gunichar2 u
= *utf16
++;
918 g_strdelimit (gchar
*string
, const gchar
*delimiters
, gchar new_delimiter
)
922 g_return_val_if_fail (string
!= NULL
, NULL
);
924 if (delimiters
== NULL
)
925 delimiters
= G_STR_DELIMITERS
;
927 for (ptr
= string
; *ptr
; ptr
++) {
928 if (strchr (delimiters
, *ptr
))
929 *ptr
= new_delimiter
;
936 g_strlcpy (gchar
*dest
, const gchar
*src
, gsize dest_size
)
939 return strlcpy (dest
, src
, dest_size
);
946 g_return_val_if_fail (src
!= NULL
, 0);
947 g_return_val_if_fail (dest
!= NULL
, 0);
959 return (dest_size
- len
- 1);
962 /* len is 0 i we get here */
964 /* we need to return the length of src here */
965 while (*s
++) ; /* instead of a plain strlen, we use 's' */
971 g_stpcpy (gchar
*dest
, const char *src
)
973 g_return_val_if_fail (dest
!= NULL
, dest
);
974 g_return_val_if_fail (src
!= NULL
, dest
);
977 return stpcpy (dest
, src
);
988 static const gchar escaped_dflt
[256] = {
989 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
990 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
991 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
992 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
993 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
994 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
995 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
996 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
997 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
998 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
999 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1000 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1001 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1002 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1003 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1004 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1008 g_strescape (const gchar
*source
, const gchar
*exceptions
)
1010 gchar escaped
[256];
1017 g_return_val_if_fail (source
!= NULL
, NULL
);
1019 memcpy (escaped
, escaped_dflt
, 256);
1020 if (exceptions
!= NULL
) {
1021 for (ptr
= exceptions
; *ptr
; ptr
++)
1022 escaped
[(int) *ptr
] = 0;
1024 result
= g_malloc (strlen (source
) * 4 + 1); /* Worst case: everything octal. */
1026 for (ptr
= source
; *ptr
; ptr
++) {
1028 op
= escaped
[(int) c
];
1036 *res_ptr
++ = '0' + ((c
>> 6) & 3);
1037 *res_ptr
++ = '0' + ((c
>> 3) & 7);
1038 *res_ptr
++ = '0' + (c
& 7);
1047 g_ascii_xdigit_value (gchar c
)
1049 return ((isxdigit (c
) == 0) ? -1 :
1050 ((c
>= '0' && c
<= '9') ? (c
- '0') :
1051 ((c
>= 'a' && c
<= 'f') ? (c
- 'a' + 10) :
1056 g_strnfill (gsize length
, gchar fill_char
)
1058 gchar
*ret
= g_new (gchar
, length
+ 1);
1060 memset (ret
, fill_char
, length
);