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.
36 * g_strndup and g_vasprintf need to allocate memory with g_malloc if
37 * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free
41 /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
43 g_strndup (const gchar *str, gsize n)
45 #if defined (HAVE_STRNDUP) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
46 return strndup (str, n);
49 char *retval = g_malloc(n+1);
51 strncpy(retval, str, n)[n] = 0;
59 gint g_vasprintf (gchar **ret, const gchar *fmt, va_list ap)
61 #if defined (HAVE_VASPRINTF) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
62 return vasprintf (ret, fmt, ap);
69 #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
71 len = _vscprintf(fmt, ap2); // NOTE MS specific extension ( :-( )
74 len = vsnprintf(NULL, 0, fmt, ap2);
77 if (len >= 0 && (buf = g_malloc ((buflen = (size_t) (len + 1)))) != NULL) {
78 len = vsnprintf(buf, buflen, fmt, ap);
91 g_strfreev (gchar **str_array)
93 gchar **orig = str_array;
94 if (str_array == NULL)
96 while (*str_array != NULL){
104 g_strdupv (gchar **str_array)
113 length = g_strv_length(str_array);
114 ret = g_new0(gchar *, length + 1);
115 for (i = 0; str_array[i]; i++) {
116 ret[i] = g_strdup(str_array[i]);
123 g_strv_length(gchar **str_array)
126 g_return_val_if_fail(str_array != NULL, 0);
127 for(length = 0; str_array[length] != NULL; length++);
132 g_str_has_suffix(const gchar *str, const gchar *suffix)
135 size_t suffix_length;
137 g_return_val_if_fail(str != NULL, FALSE);
138 g_return_val_if_fail(suffix != NULL, FALSE);
140 str_length = strlen(str);
141 suffix_length = strlen(suffix);
143 return suffix_length <= str_length ?
144 strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0 :
149 g_str_has_prefix(const gchar *str, const gchar *prefix)
152 size_t prefix_length;
154 g_return_val_if_fail(str != NULL, FALSE);
155 g_return_val_if_fail(prefix != NULL, FALSE);
157 str_length = strlen(str);
158 prefix_length = strlen(prefix);
160 return prefix_length <= str_length ?
161 strncmp(str, prefix, prefix_length) == 0 :
166 g_strdup_vprintf (const gchar *format, va_list args)
171 n = g_vasprintf (&ret, format, args);
179 g_strdup_printf (const gchar *format, ...)
185 va_start (args, format);
186 n = g_vasprintf (&ret, format, args);
195 g_strerror (gint errnum)
197 return strerror (errnum);
201 g_strconcat (const gchar *first, ...)
206 g_return_val_if_fail (first != NULL, NULL);
208 total += strlen (first);
209 va_start (args, first);
210 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
215 ret = g_malloc (total + 1);
221 va_start (args, first);
222 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
231 add_to_vector (gchar ***vector, int size, gchar *token)
233 *vector = *vector == NULL ?
234 (gchar **)g_malloc(2 * sizeof(*vector)) :
235 (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
237 (*vector)[size - 1] = token;
241 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
244 gchar *token, **vector;
247 g_return_val_if_fail (string != NULL, NULL);
248 g_return_val_if_fail (delimiter != NULL, NULL);
249 g_return_val_if_fail (delimiter[0] != 0, NULL);
251 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
252 vector = (gchar **)g_malloc (2 * sizeof(vector));
253 vector[0] = g_strdup ("");
255 string += strlen (delimiter);
260 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
262 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
263 token = g_strdup ("");
264 string += strlen (delimiter);
266 while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
271 gsize toklen = (string - c);
272 token = g_strndup (c, toklen);
274 /* Need to leave a trailing empty
275 * token if the delimiter is the last
278 if (strcmp (string, delimiter) != 0) {
279 string += strlen (delimiter);
282 token = g_strdup (c);
286 add_to_vector (&vector, size, token);
291 if (strcmp (string, delimiter) == 0)
292 add_to_vector (&vector, size, g_strdup (""));
294 /* Add the rest of the string as the last element */
295 add_to_vector (&vector, size, g_strdup (string));
300 if (vector == NULL) {
301 vector = (gchar **) g_malloc (2 * sizeof (vector));
303 } else if (size > 0) {
304 vector[size - 1] = NULL;
311 charcmp (gchar testchar, const gchar *compare)
314 if (*compare == testchar) {
324 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
327 gchar *token, **vector;
330 g_return_val_if_fail (string != NULL, NULL);
331 g_return_val_if_fail (delimiter != NULL, NULL);
332 g_return_val_if_fail (delimiter[0] != 0, NULL);
334 if (charcmp (*string, delimiter)) {
335 vector = (gchar **)g_malloc (2 * sizeof(vector));
336 vector[0] = g_strdup ("");
344 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
345 if (charcmp (*string, delimiter)) {
346 gsize toklen = (string - c);
348 token = g_strdup ("");
350 token = g_strndup (c, toklen);
355 add_to_vector (&vector, size, token);
362 if (max_tokens > 0 && size >= max_tokens) {
364 /* Add the rest of the string as the last element */
365 add_to_vector (&vector, size, g_strdup (string));
370 /* Fill in the trailing last token */
371 add_to_vector (&vector, size, g_strdup (c));
374 /* Need to leave a trailing empty token if the
375 * delimiter is the last part of the string
377 add_to_vector (&vector, size, g_strdup (""));
382 if (vector == NULL) {
383 vector = (gchar **) g_malloc (2 * sizeof (vector));
385 } else if (size > 0) {
386 vector[size - 1] = NULL;
393 g_strreverse (gchar *str)
404 for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
414 g_strjoin (const gchar *separator, ...)
420 if (separator != NULL)
421 slen = strlen (separator);
426 va_start (args, separator);
427 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
434 return g_strdup ("");
436 /* Remove the last separator */
437 if (slen > 0 && len > 0)
440 res = g_malloc (len + 1);
441 va_start (args, separator);
442 s = va_arg (args, char *);
443 r = g_stpcpy (res, s);
444 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
445 if (separator != NULL)
446 r = g_stpcpy (r, separator);
455 g_strjoinv (const gchar *separator, gchar **str_array)
460 if (separator != NULL)
461 slen = strlen (separator);
466 for (i = 0; str_array [i] != NULL; i++){
467 len += strlen (str_array [i]);
472 return g_strdup ("");
474 if (slen > 0 && len > 0)
477 res = g_malloc (len + 1);
478 r = g_stpcpy (res, str_array [0]);
479 for (i = 1; str_array [i] != NULL; i++){
480 if (separator != NULL)
481 r = g_stpcpy (r, separator);
482 r = g_stpcpy (r, str_array [i]);
489 g_strchug (gchar *str)
498 while (*tmp && isspace (*tmp)) tmp++;
500 len = strlen (str) - (tmp - str - 1);
501 memmove (str, tmp, len);
507 g_strchomp (gchar *str)
514 tmp = str + strlen (str) - 1;
515 while (*tmp && isspace (*tmp)) tmp--;
521 g_printf(gchar const *format, ...)
526 va_start(args, format);
527 ret = vprintf(format, args);
534 g_fprintf(FILE *file, gchar const *format, ...)
539 va_start(args, format);
540 ret = vfprintf(file, format, args);
547 g_sprintf(gchar *string, gchar const *format, ...)
552 va_start(args, format);
553 ret = vsprintf(string, format, args);
560 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
565 va_start(args, format);
566 ret = vsnprintf(string, n, format, args);
572 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
573 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
576 char_needs_encoding (char c)
578 if (((unsigned char)c) >= 0x80)
581 if ((c >= '@' && c <= 'Z') ||
582 (c >= 'a' && c <= 'z') ||
583 (c >= '&' && c < 0x3b) ||
584 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
590 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
596 const char *uriPrefix = "file:///";
598 const char *uriPrefix = "file://";
601 g_return_val_if_fail (filename != NULL, NULL);
603 if (hostname != NULL)
604 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
606 if (!g_path_is_absolute (filename)){
608 *error = g_error_new (NULL, 2, "Not an absolute filename");
613 n = strlen (uriPrefix) + 1;
614 for (p = filename; *p; p++){
621 if (char_needs_encoding (*p))
627 strcpy (ret, uriPrefix);
628 for (p = filename, rp = ret + strlen (ret); *p; p++){
635 if (char_needs_encoding (*p)){
637 *rp++ = hx [((unsigned char)(*p)) >> 4];
638 *rp++ = hx [((unsigned char)(*p)) & 0xf];
649 if (p >= '0' && p <= '9')
651 if (p >= 'A' && p <= 'F')
653 if (p >= 'a' && p <= 'f')
655 g_assert_not_reached ();
660 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
666 g_return_val_if_fail (uri != NULL, NULL);
668 if (hostname != NULL)
669 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
671 if (strncmp (uri, "file:///", 8) != 0){
673 *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
677 for (p = uri + 8; *p; p++){
679 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
683 *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
693 result = g_malloc (flen + 1);
703 for (p = uri + 8; *p; p++){
705 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
715 g_strdown (gchar *string)
717 g_return_if_fail (string != NULL);
720 *string = (gchar)tolower (*string);
726 g_ascii_tolower (gchar c)
728 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
732 g_ascii_strdown (const gchar *str, gssize len)
737 g_return_val_if_fail (str != NULL, NULL);
742 ret = g_malloc (len + 1);
743 for (i = 0; i < len; i++)
744 ret [i] = (guchar) g_ascii_tolower (str [i]);
751 g_ascii_toupper (gchar c)
753 return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
757 g_ascii_strup (const gchar *str, gssize len)
762 g_return_val_if_fail (str != NULL, NULL);
767 ret = g_malloc (len + 1);
768 for (i = 0; i < len; i++)
769 ret [i] = (guchar) g_ascii_toupper (str [i]);
776 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
780 g_return_val_if_fail (s1 != NULL, 0);
781 g_return_val_if_fail (s2 != NULL, 0);
783 for (i = 0; i < n; i++) {
784 gchar c1 = g_ascii_tolower (*s1++);
785 gchar c2 = g_ascii_tolower (*s2++);
795 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
797 const char *sp1 = s1;
798 const char *sp2 = s2;
800 g_return_val_if_fail (s1 != NULL, 0);
801 g_return_val_if_fail (s2 != NULL, 0);
803 while (*sp1 != '\0') {
804 char c1 = g_ascii_tolower (*sp1++);
805 char c2 = g_ascii_tolower (*sp2++);
811 return (*sp1) - (*sp2);
815 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
819 g_return_val_if_fail (string != NULL, NULL);
821 if (delimiters == NULL)
822 delimiters = G_STR_DELIMITERS;
824 for (ptr = string; *ptr; ptr++) {
825 if (strchr (delimiters, *ptr))
826 *ptr = new_delimiter;
833 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
836 return strlcpy (dest, src, dest_size);
843 g_return_val_if_fail (src != NULL, 0);
844 g_return_val_if_fail (dest != NULL, 0);
856 return (dest_size - len - 1);
859 /* len is 0 i we get here */
861 /* we need to return the length of src here */
862 while (*s++) ; /* instead of a plain strlen, we use 's' */
868 g_stpcpy (gchar *dest, const char *src)
870 g_return_val_if_fail (dest != NULL, dest);
871 g_return_val_if_fail (src != NULL, dest);
874 return stpcpy (dest, src);
885 static const gchar escaped_dflt [256] = {
886 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
887 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
888 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
889 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
890 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
891 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
892 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
893 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
894 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
895 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
896 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
897 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
898 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
899 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
900 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
901 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
905 g_strescape (const gchar *source, const gchar *exceptions)
914 g_return_val_if_fail (source != NULL, NULL);
916 memcpy (escaped, escaped_dflt, 256);
917 if (exceptions != NULL) {
918 for (ptr = exceptions; *ptr; ptr++)
919 escaped [(int) *ptr] = 0;
921 result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
923 for (ptr = source; *ptr; ptr++) {
925 op = escaped [(int) c];
933 *res_ptr++ = '0' + ((c >> 6) & 3);
934 *res_ptr++ = '0' + ((c >> 3) & 7);
935 *res_ptr++ = '0' + (c & 7);
944 g_ascii_xdigit_value (gchar c)
946 return ((isxdigit (c) == 0) ? -1 :
947 ((c >= '0' && c <= '9') ? (c - '0') :
948 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
953 g_strnfill (gsize length, gchar fill_char)
955 gchar *ret = g_new (gchar, length + 1);
957 memset (ret, fill_char, length);