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 Haiku starts numbering at 0x8000_7000 (like HRESULT on Win32) for POSIX errno,
210 but errors from BeAPI or custom user libraries could be lower or higher.
211 (Technically, this is C and old POSIX compliant, but not new POSIX compliant.)
212 The big problem with this is that it effectively means errors start at a
213 negative offset. As such, disable the whole strerror caching mechanism.
216 #define MONO_ERRNO_MAX 200
220 static pthread_mutex_t strerror_lock
= PTHREAD_MUTEX_INITIALIZER
;
223 #if defined(__HAIKU__)
225 g_strerror (gint errnum
)
227 /* returns a const char* on Haiku */
228 return strerror(errnum
);
231 static char *error_messages
[MONO_ERRNO_MAX
];
234 g_strerror (gint errnum
)
238 if (errnum
>= MONO_ERRNO_MAX
)
239 return ("Error number higher than " str (MONO_ERRNO_MAX
));
241 if (!error_messages
[errnum
]) {
243 pthread_mutex_lock (&strerror_lock
);
246 #ifdef HAVE_STRERROR_R
247 char tmp_buff
[128]; //Quite arbitrary, should be large enough
248 char *buff
= tmp_buff
;
249 size_t buff_len
= sizeof (tmp_buff
);
252 #ifndef STRERROR_R_CHAR_P
254 while ((r
= strerror_r (errnum
, buff
, buff_len
- 1))) {
256 buff
= g_strdup_printf ("Invalid Error code '%d'", errnum
);
259 if (buff
== tmp_buff
)
260 buff
= g_malloc (buff_len
* 2);
262 buff
= g_realloc (buff
, buff_len
* 2);
264 //Spec is not clean on whether size argument includes space for null terminator or not
266 if (!error_messages
[errnum
])
267 error_messages
[errnum
] = g_strdup (buff
);
268 if (buff
!= tmp_buff
)
270 #else /* STRERROR_R_CHAR_P */
271 buff
= strerror_r (errnum
, buff
, buff_len
);
272 if (!error_messages
[errnum
])
273 error_messages
[errnum
] = g_strdup (buff
);
274 #endif /* STRERROR_R_CHAR_P */
276 #else /* HAVE_STRERROR_R */
277 if (!error_messages
[errnum
])
278 error_messages
[errnum
] = g_strdup_printf ("Error code '%d'", errnum
);
279 #endif /* HAVE_STRERROR_R */
283 pthread_mutex_unlock (&strerror_lock
);
287 return error_messages
[errnum
];
292 g_strconcat (const gchar
*first
, ...)
296 g_return_val_if_fail (first
!= NULL
, NULL
);
298 size_t len
= strlen (first
);
299 va_start (args
, first
);
300 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg(args
, char *)){
305 ret
= (char*)g_malloc (len
+ 1);
310 len
= strlen (first
);
311 memcpy (ret
, first
, len
);
312 va_start (args
, first
);
313 first
= ret
; // repurpose first as cursor
314 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg(args
, char *)){
316 memcpy ((char*)first
, s
, len
= strlen (s
));
324 add_to_vector (gchar
***vector
, int size
, gchar
*token
)
326 *vector
= *vector
== NULL
?
327 (gchar
**)g_malloc(2 * sizeof(*vector
)) :
328 (gchar
**)g_realloc(*vector
, (size
+ 1) * sizeof(*vector
));
330 (*vector
)[size
- 1] = token
;
334 g_strsplit (const gchar
*string
, const gchar
*delimiter
, gint max_tokens
)
337 gchar
*token
, **vector
;
340 g_return_val_if_fail (string
!= NULL
, NULL
);
341 g_return_val_if_fail (delimiter
!= NULL
, NULL
);
342 g_return_val_if_fail (delimiter
[0] != 0, NULL
);
344 if (strncmp (string
, delimiter
, strlen (delimiter
)) == 0) {
345 vector
= (gchar
**)g_malloc (2 * sizeof(vector
));
346 vector
[0] = g_strdup ("");
348 string
+= strlen (delimiter
);
353 while (*string
&& !(max_tokens
> 0 && size
>= max_tokens
)) {
355 if (strncmp (string
, delimiter
, strlen (delimiter
)) == 0) {
356 token
= g_strdup ("");
357 string
+= strlen (delimiter
);
359 while (*string
&& strncmp (string
, delimiter
, strlen (delimiter
)) != 0) {
364 gsize toklen
= (string
- c
);
365 token
= g_strndup (c
, toklen
);
367 /* Need to leave a trailing empty
368 * token if the delimiter is the last
371 if (strcmp (string
, delimiter
) != 0) {
372 string
+= strlen (delimiter
);
375 token
= g_strdup (c
);
379 add_to_vector (&vector
, size
, token
);
384 if (strcmp (string
, delimiter
) == 0)
385 add_to_vector (&vector
, size
, g_strdup (""));
387 /* Add the rest of the string as the last element */
388 add_to_vector (&vector
, size
, g_strdup (string
));
393 if (vector
== NULL
) {
394 vector
= (gchar
**) g_malloc (2 * sizeof (vector
));
396 } else if (size
> 0) {
397 vector
[size
- 1] = NULL
;
404 charcmp (gchar testchar
, const gchar
*compare
)
407 if (*compare
== testchar
) {
417 g_strsplit_set (const gchar
*string
, const gchar
*delimiter
, gint max_tokens
)
420 gchar
*token
, **vector
;
423 g_return_val_if_fail (string
!= NULL
, NULL
);
424 g_return_val_if_fail (delimiter
!= NULL
, NULL
);
425 g_return_val_if_fail (delimiter
[0] != 0, NULL
);
427 if (charcmp (*string
, delimiter
)) {
428 vector
= (gchar
**)g_malloc (2 * sizeof(vector
));
429 vector
[0] = g_strdup ("");
437 while (*string
&& !(max_tokens
> 0 && size
>= max_tokens
)) {
438 if (charcmp (*string
, delimiter
)) {
439 gsize toklen
= (string
- c
);
441 token
= g_strdup ("");
443 token
= g_strndup (c
, toklen
);
448 add_to_vector (&vector
, size
, token
);
455 if (max_tokens
> 0 && size
>= max_tokens
) {
457 /* Add the rest of the string as the last element */
458 add_to_vector (&vector
, size
, g_strdup (string
));
463 /* Fill in the trailing last token */
464 add_to_vector (&vector
, size
, g_strdup (c
));
467 /* Need to leave a trailing empty token if the
468 * delimiter is the last part of the string
470 add_to_vector (&vector
, size
, g_strdup (""));
475 if (vector
== NULL
) {
476 vector
= (gchar
**) g_malloc (2 * sizeof (vector
));
478 } else if (size
> 0) {
479 vector
[size
- 1] = NULL
;
486 g_strreverse (gchar
*str
)
497 for (i
= 0, j
= strlen (str
) - 1; i
< j
; i
++, j
--) {
507 g_strjoin (const gchar
*separator
, ...)
513 if (separator
!= NULL
)
514 slen
= strlen (separator
);
519 va_start (args
, separator
);
520 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg (args
, char *)){
527 return g_strdup ("");
529 /* Remove the last separator */
530 if (slen
> 0 && len
> 0)
533 res
= (char*)g_malloc (len
+ 1);
534 va_start (args
, separator
);
535 s
= va_arg (args
, char *);
536 r
= g_stpcpy (res
, s
);
537 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg (args
, char *)){
538 if (separator
!= NULL
)
539 r
= g_stpcpy (r
, separator
);
548 g_strjoinv (const gchar
*separator
, gchar
**str_array
)
553 if (separator
!= NULL
)
554 slen
= strlen (separator
);
559 for (i
= 0; str_array
[i
] != NULL
; i
++){
560 len
+= strlen (str_array
[i
]);
565 return g_strdup ("");
567 if (slen
> 0 && len
> 0)
570 res
= g_malloc (len
+ 1);
571 r
= g_stpcpy (res
, str_array
[0]);
572 for (i
= 1; str_array
[i
] != NULL
; i
++){
573 if (separator
!= NULL
)
574 r
= g_stpcpy (r
, separator
);
575 r
= g_stpcpy (r
, str_array
[i
]);
582 g_strchug (gchar
*str
)
591 while (*tmp
&& isspace (*tmp
)) tmp
++;
593 len
= strlen (str
) - (tmp
- str
- 1);
594 memmove (str
, tmp
, len
);
600 g_strchomp (gchar
*str
)
607 tmp
= str
+ strlen (str
) - 1;
608 while (*tmp
&& isspace (*tmp
)) tmp
--;
614 g_fprintf(FILE *file
, gchar
const *format
, ...)
619 va_start(args
, format
);
620 ret
= vfprintf(file
, format
, args
);
627 g_sprintf(gchar
*string
, gchar
const *format
, ...)
632 va_start(args
, format
);
633 ret
= vsprintf(string
, format
, args
);
640 g_snprintf(gchar
*string
, gulong n
, gchar
const *format
, ...)
645 va_start(args
, format
);
646 ret
= vsnprintf(string
, n
, format
, args
);
652 static const char hx
[] = { '0', '1', '2', '3', '4', '5', '6', '7',
653 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
656 char_needs_encoding (char c
)
658 if (((unsigned char)c
) >= 0x80)
661 if ((c
>= '@' && c
<= 'Z') ||
662 (c
>= 'a' && c
<= 'z') ||
663 (c
>= '&' && c
< 0x3b) ||
664 (c
== '!') || (c
== '$') || (c
== '_') || (c
== '=') || (c
== '~'))
670 g_filename_to_uri (const gchar
*filename
, const gchar
*hostname
, GError
**gerror
)
676 const char *uriPrefix
= "file:///";
678 const char *uriPrefix
= "file://";
681 g_return_val_if_fail (filename
!= NULL
, NULL
);
683 if (hostname
!= NULL
)
684 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
686 if (!g_path_is_absolute (filename
)){
688 *gerror
= g_error_new (NULL
, 2, "Not an absolute filename");
693 n
= strlen (uriPrefix
) + 1;
694 for (p
= filename
; *p
; p
++){
701 if (char_needs_encoding (*p
))
707 strcpy (ret
, uriPrefix
);
708 for (p
= filename
, rp
= ret
+ strlen (ret
); *p
; p
++){
715 if (char_needs_encoding (*p
)){
717 *rp
++ = hx
[((unsigned char)(*p
)) >> 4];
718 *rp
++ = hx
[((unsigned char)(*p
)) & 0xf];
729 if (p
>= '0' && p
<= '9')
731 if (p
>= 'A' && p
<= 'F')
732 return (p
- 'A') + 10;
733 if (p
>= 'a' && p
<= 'f')
734 return (p
- 'a') + 10;
735 g_assert_not_reached ();
740 g_filename_from_uri (const gchar
*uri
, gchar
**hostname
, GError
**gerror
)
746 g_return_val_if_fail (uri
!= NULL
, NULL
);
748 if (hostname
!= NULL
)
749 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
751 if (strncmp (uri
, "file:///", 8) != 0){
753 *gerror
= g_error_new (NULL
, 2, "URI does not start with the file: scheme");
757 for (p
= uri
+ 8; *p
; p
++){
759 if (p
[1] && p
[2] && isxdigit (p
[1]) && isxdigit (p
[2])){
763 *gerror
= g_error_new (NULL
, 2, "URI contains an invalid escape sequence");
773 result
= g_malloc (flen
+ 1);
783 for (p
= uri
+ 8; *p
; p
++){
785 *r
++ = (char)((decode (p
[1]) << 4) | decode (p
[2]));
795 g_strdown (gchar
*string
)
797 g_return_if_fail (string
!= NULL
);
800 *string
= (gchar
)tolower (*string
);
806 g_ascii_tolower (gchar c
)
808 return c
>= 'A' && c
<= 'Z' ? c
+ ('a' - 'A') : c
;
812 g_ascii_strdown_no_alloc (char* dst
, const char* src
, gsize len
)
814 // dst can equal src. no_alloc means this function does no
815 // allocation; caller may very well.
817 for (gsize i
= 0; i
< len
; ++i
)
818 dst
[i
] = g_ascii_tolower (src
[i
]);
822 g_ascii_strdown (const gchar
*str
, gssize len
)
826 g_return_val_if_fail (str
!= NULL
, NULL
);
831 ret
= g_malloc (len
+ 1);
832 g_ascii_strdown_no_alloc (ret
, str
, len
);
839 g_ascii_toupper (gchar c
)
841 return c
>= 'a' && c
<= 'z' ? c
+ ('A' - 'a') : c
;
845 g_ascii_strup (const gchar
*str
, gssize len
)
850 g_return_val_if_fail (str
!= NULL
, NULL
);
855 ret
= g_malloc (len
+ 1);
856 for (i
= 0; i
< len
; i
++)
857 ret
[i
] = g_ascii_toupper (str
[i
]);
865 g_ascii_charcmp (char c1
, char c2
)
867 // Do not subtract, to avoid overflow.
868 // Use unsigned to mimic strcmp, and so
869 // shorter strings compare as less.
871 const guchar u1
= (guchar
)c1
;
872 const guchar u2
= (guchar
)c2
;
873 return (u1
< u2
) ? -1 : (u1
> u2
) ? 1 : 0;
878 g_ascii_charcasecmp (char c1
, char c2
)
880 return g_ascii_charcmp (g_ascii_tolower (c1
), g_ascii_tolower (c2
));
884 g_ascii_strncasecmp (const gchar
*s1
, const gchar
*s2
, gsize n
)
886 // Unlike strncmp etc. this function does not stop at nul,
887 // unless there is a mismatch.
894 g_return_val_if_fail (s1
!= NULL
, 0);
895 g_return_val_if_fail (s2
!= NULL
, 0);
897 for (i
= 0; i
< n
; i
++) {
898 const int j
= g_ascii_charcasecmp (*s1
++, *s2
++);
907 g_ascii_strcasecmp (const gchar
*s1
, const gchar
*s2
)
912 g_return_val_if_fail (s1
!= NULL
, 0);
913 g_return_val_if_fail (s2
!= NULL
, 0);
919 const int j
= g_ascii_charcasecmp (c1
, *s2
++);
924 return g_ascii_charcmp (0, *s2
);
928 g_utf16_ascii_equal (const gunichar2
*utf16
, size_t ulen
, const char *ascii
, size_t alen
)
933 for (i
= 0; i
< ulen
; ++i
) {
934 if (utf16
[i
] != ascii
[i
])
941 g_utf16_asciiz_equal (const gunichar2
*utf16
, const char *ascii
)
942 // z for zero means null terminated
947 gunichar2 u
= *utf16
++;
956 g_strdelimit (gchar
*string
, gchar delimiter
, gchar new_delimiter
)
960 g_return_if_fail (string
!= NULL
);
962 for (ptr
= string
; *ptr
; ptr
++) {
963 if (delimiter
== *ptr
)
964 *ptr
= new_delimiter
;
969 g_strlcpy (gchar
*dest
, const gchar
*src
, gsize dest_size
)
975 return strlcpy (dest
, src
, dest_size
);
992 return (dest_size
- len
- 1);
995 /* len is 0 i we get here */
997 /* we need to return the length of src here */
998 while (*s
++) ; /* instead of a plain strlen, we use 's' */
1004 g_stpcpy (gchar
*dest
, const char *src
)
1006 g_return_val_if_fail (dest
!= NULL
, dest
);
1007 g_return_val_if_fail (src
!= NULL
, dest
);
1010 return stpcpy (dest
, src
);
1021 static const gchar escaped_dflt
[256] = {
1022 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
1023 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1024 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1025 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1026 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1027 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
1028 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1029 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1030 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1031 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1032 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1033 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1034 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1035 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1036 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1037 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1041 g_strescape (const gchar
*source
, const gchar
*exceptions
)
1043 gchar escaped
[256];
1050 g_return_val_if_fail (source
!= NULL
, NULL
);
1052 memcpy (escaped
, escaped_dflt
, 256);
1053 if (exceptions
!= NULL
) {
1054 for (ptr
= exceptions
; *ptr
; ptr
++)
1055 escaped
[(int) *ptr
] = 0;
1057 result
= g_malloc (strlen (source
) * 4 + 1); /* Worst case: everything octal. */
1059 for (ptr
= source
; *ptr
; ptr
++) {
1061 op
= escaped
[(int) c
];
1069 *res_ptr
++ = '0' + ((c
>> 6) & 3);
1070 *res_ptr
++ = '0' + ((c
>> 3) & 7);
1071 *res_ptr
++ = '0' + (c
& 7);
1080 g_ascii_xdigit_value (gchar c
)
1082 return ((isxdigit (c
) == 0) ? -1 :
1083 ((c
>= '0' && c
<= '9') ? (c
- '0') :
1084 ((c
>= 'a' && c
<= 'f') ? (c
- 'a' + 10) :
1089 g_strnfill (gsize length
, gchar fill_char
)
1091 gchar
*ret
= g_new (gchar
, length
+ 1);
1093 memset (ret
, fill_char
, length
);
1099 g_utf16_len (const gunichar2
*a
)
1112 g_strnlen (const char* s
, gsize n
)
1115 for (i
= 0; i
< n
&& s
[i
]; ++i
) ;
1120 * Loads a chunk of data from the file pointed to by the
1121 * @fd starting at the file offset @offset for @size bytes
1122 * and returns an allocated version of that string, or NULL
1126 g_str_from_file_region (int fd
, guint64 offset
, gsize size
)
1133 loc
= lseek (fd
, offset
, SEEK_SET
);
1134 } while (loc
== -1 && errno
== EINTR
);
1137 buffer
= (char *)g_malloc (size
+ 1);
1142 status
= read (fd
, buffer
, size
);
1143 } while (status
== -1 && errno
== EINTR
);