fix build regarding ContentType.
[mono-project.git] / eglib / src / gstr.c
blobfccf2651db26b05678dea8a5e4b1472f6d5a0753
1 /*
2 * gstr.c: String Utility Functions.
4 * Author:
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.
29 #include <config.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <glib.h>
35 /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
36 gchar *
37 g_strndup (const gchar *str, gsize n)
39 #ifdef HAVE_STRNDUP
40 return strndup (str, n);
41 #else
42 if (str) {
43 char *retval = g_malloc(n+1);
44 if (retval) {
45 strncpy(retval, str, n)[n] = 0;
47 return retval;
49 return NULL;
50 #endif
53 void
54 g_strfreev (gchar **str_array)
56 gchar **orig = str_array;
57 if (str_array == NULL)
58 return;
59 while (*str_array != NULL){
60 g_free (*str_array);
61 str_array++;
63 g_free (orig);
66 gchar **
67 g_strdupv (gchar **str_array)
69 guint length;
70 gchar **ret;
71 guint i;
73 if (!str_array)
74 return NULL;
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]);
81 ret[length] = NULL;
82 return ret;
85 guint
86 g_strv_length(gchar **str_array)
88 gint length = 0;
89 g_return_val_if_fail(str_array != NULL, 0);
90 for(length = 0; str_array[length] != NULL; length++);
91 return length;
94 gboolean
95 g_str_has_suffix(const gchar *str, const gchar *suffix)
97 size_t str_length;
98 size_t suffix_length;
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 :
108 FALSE;
111 gboolean
112 g_str_has_prefix(const gchar *str, const gchar *prefix)
114 size_t str_length;
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 :
125 FALSE;
128 gchar *
129 g_strdup_vprintf (const gchar *format, va_list args)
131 int n;
132 char *ret;
134 n = vasprintf (&ret, format, args);
135 if (n == -1)
136 return NULL;
138 return ret;
141 gchar *
142 g_strdup_printf (const gchar *format, ...)
144 gchar *ret;
145 va_list args;
146 int n;
148 va_start (args, format);
149 n = vasprintf (&ret, format, args);
150 va_end (args);
151 if (n == -1)
152 return NULL;
154 return ret;
157 const gchar *
158 g_strerror (gint errnum)
160 return strerror (errnum);
163 gchar *
164 g_strconcat (const gchar *first, ...)
166 va_list args;
167 size_t total = 0;
168 char *s, *ret;
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 *)){
174 total += strlen (s);
176 va_end (args);
178 ret = g_malloc (total + 1);
179 if (ret == NULL)
180 return NULL;
182 ret [total] = 0;
183 strcpy (ret, first);
184 va_start (args, first);
185 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
186 strcat (ret, s);
188 va_end (args);
190 return ret;
193 static void
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;
203 gchar **
204 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
206 const gchar *c;
207 gchar *token, **vector;
208 gint size = 1;
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 ("");
217 size++;
218 string += strlen (delimiter);
219 } else {
220 vector = NULL;
223 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
224 c = string;
225 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
226 token = g_strdup ("");
227 string += strlen (delimiter);
228 } else {
229 while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
230 string++;
233 if (*string) {
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
239 * part of the string
241 if (strcmp (string, delimiter) != 0) {
242 string += strlen (delimiter);
244 } else {
245 token = g_strdup (c);
249 add_to_vector (&vector, size, token);
250 size++;
253 if (*string) {
254 /* Add the rest of the string as the last element */
255 add_to_vector (&vector, size, g_strdup (string));
256 size++;
259 if (vector == NULL) {
260 vector = (gchar **) g_malloc (2 * sizeof (vector));
261 vector [0] = NULL;
262 } else if (size > 0) {
263 vector[size - 1] = NULL;
266 return vector;
269 static gboolean
270 charcmp (gchar testchar, const gchar *compare)
272 while(*compare) {
273 if (*compare == testchar) {
274 return TRUE;
276 compare++;
279 return FALSE;
282 gchar **
283 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
285 const gchar *c;
286 gchar *token, **vector;
287 gint size = 1;
289 g_return_val_if_fail (string != NULL, NULL);
290 g_return_val_if_fail (delimiter != NULL, NULL);
291 g_return_val_if_fail (delimiter[0] != 0, NULL);
293 if (charcmp (*string, delimiter)) {
294 vector = (gchar **)g_malloc (2 * sizeof(vector));
295 vector[0] = g_strdup ("");
296 size++;
297 string++;
298 } else {
299 vector = NULL;
302 c = string;
303 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
304 if (charcmp (*string, delimiter)) {
305 gsize toklen = (string - c);
306 if (toklen == 0) {
307 token = g_strdup ("");
308 } else {
309 token = g_strndup (c, toklen);
312 c = string + 1;
314 add_to_vector (&vector, size, token);
315 size++;
318 string++;
321 if (max_tokens > 0 && size >= max_tokens) {
322 if (*string) {
323 /* Add the rest of the string as the last element */
324 add_to_vector (&vector, size, g_strdup (string));
325 size++;
327 } else {
328 if (*c) {
329 /* Fill in the trailing last token */
330 add_to_vector (&vector, size, g_strdup (c));
331 size++;
332 } else {
333 /* Need to leave a trailing empty token if the
334 * delimiter is the last part of the string
336 add_to_vector (&vector, size, g_strdup (""));
337 size++;
341 if (vector == NULL) {
342 vector = (gchar **) g_malloc (2 * sizeof (vector));
343 vector [0] = NULL;
344 } else if (size > 0) {
345 vector[size - 1] = NULL;
348 return vector;
351 gchar *
352 g_strreverse (gchar *str)
354 size_t i, j;
355 gchar c;
357 if (str == NULL)
358 return NULL;
360 for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
361 c = str [i];
362 str [i] = str [j];
363 str [j] = c;
366 return str;
369 gchar *
370 g_strjoin (const gchar *separator, ...)
372 va_list args;
373 char *res, *s, *r;
374 size_t len, slen;
376 if (separator != NULL)
377 slen = strlen (separator);
378 else
379 slen = 0;
381 len = 0;
382 va_start (args, separator);
383 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
384 len += strlen (s);
385 len += slen;
387 va_end (args);
389 if (len == 0)
390 return g_strdup ("");
392 /* Remove the last separator */
393 if (slen > 0 && len > 0)
394 len -= slen;
396 res = g_malloc (len + 1);
397 va_start (args, separator);
398 s = va_arg (args, char *);
399 r = g_stpcpy (res, s);
400 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
401 if (separator != NULL)
402 r = g_stpcpy (r, separator);
403 r = g_stpcpy (r, s);
405 va_end (args);
407 return res;
410 gchar *
411 g_strjoinv (const gchar *separator, gchar **str_array)
413 char *res, *r;
414 size_t slen, len, i;
416 if (separator != NULL)
417 slen = strlen (separator);
418 else
419 slen = 0;
421 len = 0;
422 for (i = 0; str_array [i] != NULL; i++){
423 len += strlen (str_array [i]);
424 len += slen;
427 if (len == 0)
428 return g_strdup ("");
430 if (slen > 0 && len > 0)
431 len -= slen;
433 res = g_malloc (len + 1);
434 r = g_stpcpy (res, str_array [0]);
435 for (i = 1; str_array [i] != NULL; i++){
436 if (separator != NULL)
437 r = g_stpcpy (r, separator);
438 r = g_stpcpy (r, str_array [i]);
441 return res;
444 gchar *
445 g_strchug (gchar *str)
447 size_t len;
448 gchar *tmp;
450 if (str == NULL)
451 return NULL;
453 tmp = str;
454 while (*tmp && isspace (*tmp)) tmp++;
455 if (str != tmp) {
456 len = strlen (str) - (tmp - str - 1);
457 memmove (str, tmp, len);
459 return str;
462 gchar *
463 g_strchomp (gchar *str)
465 gchar *tmp;
467 if (str == NULL)
468 return NULL;
470 tmp = str + strlen (str) - 1;
471 while (*tmp && isspace (*tmp)) tmp--;
472 *(tmp + 1) = '\0';
473 return str;
476 gint
477 g_printf(gchar const *format, ...)
479 va_list args;
480 gint ret;
482 va_start(args, format);
483 ret = vprintf(format, args);
484 va_end(args);
486 return ret;
489 gint
490 g_fprintf(FILE *file, gchar const *format, ...)
492 va_list args;
493 gint ret;
495 va_start(args, format);
496 ret = vfprintf(file, format, args);
497 va_end(args);
499 return ret;
502 gint
503 g_sprintf(gchar *string, gchar const *format, ...)
505 va_list args;
506 gint ret;
508 va_start(args, format);
509 ret = vsprintf(string, format, args);
510 va_end(args);
512 return ret;
515 gint
516 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
518 va_list args;
519 gint ret;
521 va_start(args, format);
522 ret = vsnprintf(string, n, format, args);
523 va_end(args);
525 return ret;
528 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
529 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
531 static gboolean
532 char_needs_encoding (char c)
534 if (((unsigned char)c) >= 0x80)
535 return TRUE;
537 if ((c >= '@' && c <= 'Z') ||
538 (c >= 'a' && c <= 'z') ||
539 (c >= '&' && c < 0x3b) ||
540 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
541 return FALSE;
542 return TRUE;
545 gchar *
546 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
548 size_t n;
549 char *ret, *rp;
550 const char *p;
551 #ifdef G_OS_WIN32
552 const char *uriPrefix = "file:///";
553 #else
554 const char *uriPrefix = "file://";
555 #endif
557 g_return_val_if_fail (filename != NULL, NULL);
559 if (hostname != NULL)
560 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
562 if (!g_path_is_absolute (filename)){
563 if (error != NULL)
564 *error = g_error_new (NULL, 2, "Not an absolute filename");
566 return NULL;
569 n = strlen (uriPrefix) + 1;
570 for (p = filename; *p; p++){
571 #ifdef G_OS_WIN32
572 if (*p == '\\') {
573 n++;
574 continue;
576 #endif
577 if (char_needs_encoding (*p))
578 n += 3;
579 else
580 n++;
582 ret = g_malloc (n);
583 strcpy (ret, uriPrefix);
584 for (p = filename, rp = ret + strlen (ret); *p; p++){
585 #ifdef G_OS_WIN32
586 if (*p == '\\') {
587 *rp++ = '/';
588 continue;
590 #endif
591 if (char_needs_encoding (*p)){
592 *rp++ = '%';
593 *rp++ = hx [((unsigned char)(*p)) >> 4];
594 *rp++ = hx [((unsigned char)(*p)) & 0xf];
595 } else
596 *rp++ = *p;
598 *rp = 0;
599 return ret;
602 static int
603 decode (char p)
605 if (p >= '0' && p <= '9')
606 return p - '0';
607 if (p >= 'A' && p <= 'F')
608 return p - 'A';
609 if (p >= 'a' && p <= 'f')
610 return p - 'a';
611 g_assert_not_reached ();
612 return 0;
615 gchar *
616 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
618 const char *p;
619 char *r, *result;
620 int flen = 0;
622 g_return_val_if_fail (uri != NULL, NULL);
624 if (hostname != NULL)
625 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
627 if (strncmp (uri, "file:///", 8) != 0){
628 if (error != NULL)
629 *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
630 return NULL;
633 for (p = uri + 8; *p; p++){
634 if (*p == '%'){
635 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
636 p += 2;
637 } else {
638 if (error != NULL)
639 *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
640 return NULL;
643 flen++;
645 #ifndef G_OS_WIN32
646 flen++;
647 #endif
649 result = g_malloc (flen + 1);
650 result [flen] = 0;
652 #ifndef G_OS_WIN32
653 *result = '/';
654 r = result + 1;
655 #else
656 r = result;
657 #endif
659 for (p = uri + 8; *p; p++){
660 if (*p == '%'){
661 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
662 p += 2;
663 } else
664 *r++ = *p;
665 flen++;
667 return result;
670 void
671 g_strdown (gchar *string)
673 g_return_if_fail (string != NULL);
675 while (*string){
676 *string = (gchar)tolower (*string);
677 string++;
681 gchar
682 g_ascii_tolower (gchar c)
684 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
687 gchar *
688 g_ascii_strdown (const gchar *str, gssize len)
690 char *ret;
691 int i;
693 g_return_val_if_fail (str != NULL, NULL);
695 if (len == -1)
696 len = strlen (str);
698 ret = g_malloc (len + 1);
699 for (i = 0; i < len; i++)
700 ret [i] = (guchar) g_ascii_tolower (str [i]);
701 ret [i] = 0;
703 return ret;
706 gchar
707 g_ascii_toupper (gchar c)
709 return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
712 gchar *
713 g_ascii_strup (const gchar *str, gssize len)
715 char *ret;
716 int i;
718 g_return_val_if_fail (str != NULL, NULL);
720 if (len == -1)
721 len = strlen (str);
723 ret = g_malloc (len + 1);
724 for (i = 0; i < len; i++)
725 ret [i] = (guchar) g_ascii_toupper (str [i]);
726 ret [i] = 0;
728 return ret;
731 gint
732 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
734 gsize i;
736 g_return_val_if_fail (s1 != NULL, 0);
737 g_return_val_if_fail (s2 != NULL, 0);
739 for (i = 0; i < n; i++) {
740 gchar c1 = g_ascii_tolower (*s1++);
741 gchar c2 = g_ascii_tolower (*s2++);
743 if (c1 != c2)
744 return c1 - c2;
747 return 0;
750 gint
751 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
753 const char *sp1 = s1;
754 const char *sp2 = s2;
756 g_return_val_if_fail (s1 != NULL, 0);
757 g_return_val_if_fail (s2 != NULL, 0);
759 while (*sp1 != '\0') {
760 char c1 = g_ascii_tolower (*sp1++);
761 char c2 = g_ascii_tolower (*sp2++);
763 if (c1 != c2)
764 return c1 - c2;
767 return (*sp1) - (*sp2);
770 gchar *
771 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
773 gchar *ptr;
775 g_return_val_if_fail (string != NULL, NULL);
777 if (delimiters == NULL)
778 delimiters = G_STR_DELIMITERS;
780 for (ptr = string; *ptr; ptr++) {
781 if (strchr (delimiters, *ptr))
782 *ptr = new_delimiter;
785 return string;
788 gsize
789 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
791 #ifdef HAVE_STRLCPY
792 return strlcpy (dest, src, dest_size);
793 #else
794 gchar *d;
795 const gchar *s;
796 gchar c;
797 gsize len;
799 g_return_val_if_fail (src != NULL, 0);
800 g_return_val_if_fail (dest != NULL, 0);
802 len = dest_size;
803 if (len == 0)
804 return 0;
806 s = src;
807 d = dest;
808 while (--len) {
809 c = *s++;
810 *d++ = c;
811 if (c == '\0')
812 return (dest_size - len - 1);
815 /* len is 0 i we get here */
816 *d = '\0';
817 /* we need to return the length of src here */
818 while (*s++) ; /* instead of a plain strlen, we use 's' */
819 return s - src - 1;
820 #endif
823 gchar *
824 g_stpcpy (gchar *dest, const char *src)
826 g_return_val_if_fail (dest != NULL, dest);
827 g_return_val_if_fail (src != NULL, dest);
829 #if HAVE_STPCPY
830 return stpcpy (dest, src);
831 #else
832 while (*src)
833 *dest++ = *src++;
835 *dest = '\0';
837 return dest;
838 #endif
841 static const gchar escaped_dflt [256] = {
842 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
843 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
844 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
845 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
846 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
847 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
848 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
849 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
850 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
851 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
852 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
853 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
854 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
855 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
856 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
857 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
860 gchar *
861 g_strescape (const gchar *source, const gchar *exceptions)
863 gchar escaped [256];
864 const gchar *ptr;
865 gchar c;
866 gchar op;
867 gchar *result;
868 gchar *res_ptr;
870 g_return_val_if_fail (source != NULL, NULL);
872 memcpy (escaped, escaped_dflt, 256);
873 if (exceptions != NULL) {
874 for (ptr = exceptions; *ptr; ptr++)
875 escaped [(int) *ptr] = 0;
877 result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
878 res_ptr = result;
879 for (ptr = source; *ptr; ptr++) {
880 c = *ptr;
881 op = escaped [(int) c];
882 if (op == 0) {
883 *res_ptr++ = c;
884 } else {
885 *res_ptr++ = '\\';
886 if (op != 1) {
887 *res_ptr++ = op;
888 } else {
889 *res_ptr++ = '0' + ((c >> 6) & 3);
890 *res_ptr++ = '0' + ((c >> 3) & 7);
891 *res_ptr++ = '0' + (c & 7);
895 *res_ptr = '\0';
896 return result;
899 gint
900 g_ascii_xdigit_value (gchar c)
902 return ((isxdigit (c) == 0) ? -1 :
903 ((c >= '0' && c <= '9') ? (c - '0') :
904 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
905 (c - 'A' + 10))));
908 gchar *
909 g_strnfill (gsize length, gchar fill_char)
911 gchar *ret = g_new (gchar, length + 1);
913 memset (ret, fill_char, length);
914 ret [length] = 0;
915 return ret;