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.
35 /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
37 g_strndup (const gchar
*str
, gsize n
)
40 return strndup (str
, n
);
43 char *retval
= g_malloc(n
+1);
45 strncpy(retval
, str
, n
)[n
] = 0;
54 g_strfreev (gchar
**str_array
)
56 gchar
**orig
= str_array
;
57 if (str_array
== NULL
)
59 while (*str_array
!= NULL
){
67 g_strdupv (gchar
**str_array
)
76 length
= g_strv_length(str_array
);
77 ret
= g_new0(gchar
*, length
+ 1);
78 for (i
= 0; str_array
[i
]; i
++) {
79 ret
[i
] = g_strdup(str_array
[i
]);
86 g_strv_length(gchar
**str_array
)
89 g_return_val_if_fail(str_array
!= NULL
, 0);
90 for(length
= 0; str_array
[length
] != NULL
; length
++);
95 g_str_has_suffix(const gchar
*str
, const gchar
*suffix
)
100 g_return_val_if_fail(str
!= NULL
, FALSE
);
101 g_return_val_if_fail(suffix
!= NULL
, FALSE
);
103 str_length
= strlen(str
);
104 suffix_length
= strlen(suffix
);
106 return suffix_length
<= str_length
?
107 strncmp(str
+ str_length
- suffix_length
, suffix
, suffix_length
) == 0 :
112 g_str_has_prefix(const gchar
*str
, const gchar
*prefix
)
115 size_t prefix_length
;
117 g_return_val_if_fail(str
!= NULL
, FALSE
);
118 g_return_val_if_fail(prefix
!= NULL
, FALSE
);
120 str_length
= strlen(str
);
121 prefix_length
= strlen(prefix
);
123 return prefix_length
<= str_length
?
124 strncmp(str
, prefix
, prefix_length
) == 0 :
129 g_strdup_vprintf (const gchar
*format
, va_list args
)
134 n
= vasprintf (&ret
, format
, args
);
142 g_strdup_printf (const gchar
*format
, ...)
148 va_start (args
, format
);
149 n
= vasprintf (&ret
, format
, args
);
158 g_strerror (gint errnum
)
160 return strerror (errnum
);
164 g_strconcat (const gchar
*first
, ...)
169 g_return_val_if_fail (first
!= NULL
, NULL
);
171 total
+= strlen (first
);
172 va_start (args
, first
);
173 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg(args
, char *)){
178 ret
= g_malloc (total
+ 1);
184 va_start (args
, first
);
185 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg(args
, char *)){
194 add_to_vector (gchar
***vector
, int size
, gchar
*token
)
196 *vector
= *vector
== NULL
?
197 (gchar
**)g_malloc(2 * sizeof(*vector
)) :
198 (gchar
**)g_realloc(*vector
, (size
+ 1) * sizeof(*vector
));
200 (*vector
)[size
- 1] = token
;
204 g_strsplit (const gchar
*string
, const gchar
*delimiter
, gint max_tokens
)
207 gchar
*token
, **vector
;
210 g_return_val_if_fail (string
!= NULL
, NULL
);
211 g_return_val_if_fail (delimiter
!= NULL
, NULL
);
212 g_return_val_if_fail (delimiter
[0] != 0, NULL
);
214 if (strncmp (string
, delimiter
, strlen (delimiter
)) == 0) {
215 vector
= (gchar
**)g_malloc (2 * sizeof(vector
));
216 vector
[0] = g_strdup ("");
218 string
+= strlen (delimiter
);
223 while (*string
&& !(max_tokens
> 0 && size
>= max_tokens
)) {
225 if (strncmp (string
, delimiter
, strlen (delimiter
)) == 0) {
226 token
= g_strdup ("");
227 string
+= strlen (delimiter
);
229 while (*string
&& strncmp (string
, delimiter
, strlen (delimiter
)) != 0) {
234 gsize toklen
= (string
- c
);
235 token
= g_strndup (c
, toklen
);
237 /* Need to leave a trailing empty
238 * token if the delimiter is the last
241 if (strcmp (string
, delimiter
) != 0) {
242 string
+= strlen (delimiter
);
245 token
= g_strdup (c
);
249 add_to_vector (&vector
, size
, token
);
254 if (strcmp (string
, delimiter
) == 0)
255 add_to_vector (&vector
, size
, g_strdup (""));
257 /* Add the rest of the string as the last element */
258 add_to_vector (&vector
, size
, g_strdup (string
));
263 if (vector
== NULL
) {
264 vector
= (gchar
**) g_malloc (2 * sizeof (vector
));
266 } else if (size
> 0) {
267 vector
[size
- 1] = NULL
;
274 charcmp (gchar testchar
, const gchar
*compare
)
277 if (*compare
== testchar
) {
287 g_strsplit_set (const gchar
*string
, const gchar
*delimiter
, gint max_tokens
)
290 gchar
*token
, **vector
;
293 g_return_val_if_fail (string
!= NULL
, NULL
);
294 g_return_val_if_fail (delimiter
!= NULL
, NULL
);
295 g_return_val_if_fail (delimiter
[0] != 0, NULL
);
297 if (charcmp (*string
, delimiter
)) {
298 vector
= (gchar
**)g_malloc (2 * sizeof(vector
));
299 vector
[0] = g_strdup ("");
307 while (*string
&& !(max_tokens
> 0 && size
>= max_tokens
)) {
308 if (charcmp (*string
, delimiter
)) {
309 gsize toklen
= (string
- c
);
311 token
= g_strdup ("");
313 token
= g_strndup (c
, toklen
);
318 add_to_vector (&vector
, size
, token
);
325 if (max_tokens
> 0 && size
>= max_tokens
) {
327 /* Add the rest of the string as the last element */
328 add_to_vector (&vector
, size
, g_strdup (string
));
333 /* Fill in the trailing last token */
334 add_to_vector (&vector
, size
, g_strdup (c
));
337 /* Need to leave a trailing empty token if the
338 * delimiter is the last part of the string
340 add_to_vector (&vector
, size
, g_strdup (""));
345 if (vector
== NULL
) {
346 vector
= (gchar
**) g_malloc (2 * sizeof (vector
));
348 } else if (size
> 0) {
349 vector
[size
- 1] = NULL
;
356 g_strreverse (gchar
*str
)
367 for (i
= 0, j
= strlen (str
) - 1; i
< j
; i
++, j
--) {
377 g_strjoin (const gchar
*separator
, ...)
383 if (separator
!= NULL
)
384 slen
= strlen (separator
);
389 va_start (args
, separator
);
390 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg (args
, char *)){
397 return g_strdup ("");
399 /* Remove the last separator */
400 if (slen
> 0 && len
> 0)
403 res
= g_malloc (len
+ 1);
404 va_start (args
, separator
);
405 s
= va_arg (args
, char *);
406 r
= g_stpcpy (res
, s
);
407 for (s
= va_arg (args
, char *); s
!= NULL
; s
= va_arg (args
, char *)){
408 if (separator
!= NULL
)
409 r
= g_stpcpy (r
, separator
);
418 g_strjoinv (const gchar
*separator
, gchar
**str_array
)
423 if (separator
!= NULL
)
424 slen
= strlen (separator
);
429 for (i
= 0; str_array
[i
] != NULL
; i
++){
430 len
+= strlen (str_array
[i
]);
435 return g_strdup ("");
437 if (slen
> 0 && len
> 0)
440 res
= g_malloc (len
+ 1);
441 r
= g_stpcpy (res
, str_array
[0]);
442 for (i
= 1; str_array
[i
] != NULL
; i
++){
443 if (separator
!= NULL
)
444 r
= g_stpcpy (r
, separator
);
445 r
= g_stpcpy (r
, str_array
[i
]);
452 g_strchug (gchar
*str
)
461 while (*tmp
&& isspace (*tmp
)) tmp
++;
463 len
= strlen (str
) - (tmp
- str
- 1);
464 memmove (str
, tmp
, len
);
470 g_strchomp (gchar
*str
)
477 tmp
= str
+ strlen (str
) - 1;
478 while (*tmp
&& isspace (*tmp
)) tmp
--;
484 g_printf(gchar
const *format
, ...)
489 va_start(args
, format
);
490 ret
= vprintf(format
, args
);
497 g_fprintf(FILE *file
, gchar
const *format
, ...)
502 va_start(args
, format
);
503 ret
= vfprintf(file
, format
, args
);
510 g_sprintf(gchar
*string
, gchar
const *format
, ...)
515 va_start(args
, format
);
516 ret
= vsprintf(string
, format
, args
);
523 g_snprintf(gchar
*string
, gulong n
, gchar
const *format
, ...)
528 va_start(args
, format
);
529 ret
= vsnprintf(string
, n
, format
, args
);
535 static const char hx
[] = { '0', '1', '2', '3', '4', '5', '6', '7',
536 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
539 char_needs_encoding (char c
)
541 if (((unsigned char)c
) >= 0x80)
544 if ((c
>= '@' && c
<= 'Z') ||
545 (c
>= 'a' && c
<= 'z') ||
546 (c
>= '&' && c
< 0x3b) ||
547 (c
== '!') || (c
== '$') || (c
== '_') || (c
== '=') || (c
== '~'))
553 g_filename_to_uri (const gchar
*filename
, const gchar
*hostname
, GError
**error
)
559 const char *uriPrefix
= "file:///";
561 const char *uriPrefix
= "file://";
564 g_return_val_if_fail (filename
!= NULL
, NULL
);
566 if (hostname
!= NULL
)
567 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
569 if (!g_path_is_absolute (filename
)){
571 *error
= g_error_new (NULL
, 2, "Not an absolute filename");
576 n
= strlen (uriPrefix
) + 1;
577 for (p
= filename
; *p
; p
++){
584 if (char_needs_encoding (*p
))
590 strcpy (ret
, uriPrefix
);
591 for (p
= filename
, rp
= ret
+ strlen (ret
); *p
; p
++){
598 if (char_needs_encoding (*p
)){
600 *rp
++ = hx
[((unsigned char)(*p
)) >> 4];
601 *rp
++ = hx
[((unsigned char)(*p
)) & 0xf];
612 if (p
>= '0' && p
<= '9')
614 if (p
>= 'A' && p
<= 'F')
616 if (p
>= 'a' && p
<= 'f')
618 g_assert_not_reached ();
623 g_filename_from_uri (const gchar
*uri
, gchar
**hostname
, GError
**error
)
629 g_return_val_if_fail (uri
!= NULL
, NULL
);
631 if (hostname
!= NULL
)
632 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
634 if (strncmp (uri
, "file:///", 8) != 0){
636 *error
= g_error_new (NULL
, 2, "URI does not start with the file: scheme");
640 for (p
= uri
+ 8; *p
; p
++){
642 if (p
[1] && p
[2] && isxdigit (p
[1]) && isxdigit (p
[2])){
646 *error
= g_error_new (NULL
, 2, "URI contains an invalid escape sequence");
656 result
= g_malloc (flen
+ 1);
666 for (p
= uri
+ 8; *p
; p
++){
668 *r
++ = (char)((decode (p
[1]) << 4) | decode (p
[2]));
678 g_strdown (gchar
*string
)
680 g_return_if_fail (string
!= NULL
);
683 *string
= (gchar
)tolower (*string
);
689 g_ascii_tolower (gchar c
)
691 return c
>= 'A' && c
<= 'Z' ? c
+ ('a' - 'A') : c
;
695 g_ascii_strdown (const gchar
*str
, gssize len
)
700 g_return_val_if_fail (str
!= NULL
, NULL
);
705 ret
= g_malloc (len
+ 1);
706 for (i
= 0; i
< len
; i
++)
707 ret
[i
] = (guchar
) g_ascii_tolower (str
[i
]);
714 g_ascii_toupper (gchar c
)
716 return c
>= 'a' && c
<= 'z' ? c
+ ('A' - 'a') : c
;
720 g_ascii_strup (const gchar
*str
, gssize len
)
725 g_return_val_if_fail (str
!= NULL
, NULL
);
730 ret
= g_malloc (len
+ 1);
731 for (i
= 0; i
< len
; i
++)
732 ret
[i
] = (guchar
) g_ascii_toupper (str
[i
]);
739 g_ascii_strncasecmp (const gchar
*s1
, const gchar
*s2
, gsize n
)
743 g_return_val_if_fail (s1
!= NULL
, 0);
744 g_return_val_if_fail (s2
!= NULL
, 0);
746 for (i
= 0; i
< n
; i
++) {
747 gchar c1
= g_ascii_tolower (*s1
++);
748 gchar c2
= g_ascii_tolower (*s2
++);
758 g_ascii_strcasecmp (const gchar
*s1
, const gchar
*s2
)
760 const char *sp1
= s1
;
761 const char *sp2
= s2
;
763 g_return_val_if_fail (s1
!= NULL
, 0);
764 g_return_val_if_fail (s2
!= NULL
, 0);
766 while (*sp1
!= '\0') {
767 char c1
= g_ascii_tolower (*sp1
++);
768 char c2
= g_ascii_tolower (*sp2
++);
774 return (*sp1
) - (*sp2
);
778 g_strdelimit (gchar
*string
, const gchar
*delimiters
, gchar new_delimiter
)
782 g_return_val_if_fail (string
!= NULL
, NULL
);
784 if (delimiters
== NULL
)
785 delimiters
= G_STR_DELIMITERS
;
787 for (ptr
= string
; *ptr
; ptr
++) {
788 if (strchr (delimiters
, *ptr
))
789 *ptr
= new_delimiter
;
796 g_strlcpy (gchar
*dest
, const gchar
*src
, gsize dest_size
)
799 return strlcpy (dest
, src
, dest_size
);
806 g_return_val_if_fail (src
!= NULL
, 0);
807 g_return_val_if_fail (dest
!= NULL
, 0);
819 return (dest_size
- len
- 1);
822 /* len is 0 i we get here */
824 /* we need to return the length of src here */
825 while (*s
++) ; /* instead of a plain strlen, we use 's' */
831 g_stpcpy (gchar
*dest
, const char *src
)
833 g_return_val_if_fail (dest
!= NULL
, dest
);
834 g_return_val_if_fail (src
!= NULL
, dest
);
837 return stpcpy (dest
, src
);
848 static const gchar escaped_dflt
[256] = {
849 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
850 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
851 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
852 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
853 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
854 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
855 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
856 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
857 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
858 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
859 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
860 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
861 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
862 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
863 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
864 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
868 g_strescape (const gchar
*source
, const gchar
*exceptions
)
877 g_return_val_if_fail (source
!= NULL
, NULL
);
879 memcpy (escaped
, escaped_dflt
, 256);
880 if (exceptions
!= NULL
) {
881 for (ptr
= exceptions
; *ptr
; ptr
++)
882 escaped
[(int) *ptr
] = 0;
884 result
= g_malloc (strlen (source
) * 4 + 1); /* Worst case: everything octal. */
886 for (ptr
= source
; *ptr
; ptr
++) {
888 op
= escaped
[(int) c
];
896 *res_ptr
++ = '0' + ((c
>> 6) & 3);
897 *res_ptr
++ = '0' + ((c
>> 3) & 7);
898 *res_ptr
++ = '0' + (c
& 7);
907 g_ascii_xdigit_value (gchar c
)
909 return ((isxdigit (c
) == 0) ? -1 :
910 ((c
>= '0' && c
<= '9') ? (c
- '0') :
911 ((c
>= 'a' && c
<= 'f') ? (c
- 'a' + 10) :
916 g_strnfill (gsize length
, gchar fill_char
)
918 gchar
*ret
= g_new (gchar
, length
+ 1);
920 memset (ret
, fill_char
, length
);