Fix undeclared variables in exceptions-amd64.c on win64.
[mono-project.git] / eglib / src / gstr.c
blob335ccff9365ba7ae6c3e6cec0a8d7f18083bd151
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 if (strcmp (string, delimiter) == 0)
255 add_to_vector (&vector, size, g_strdup (""));
256 else {
257 /* Add the rest of the string as the last element */
258 add_to_vector (&vector, size, g_strdup (string));
260 size++;
263 if (vector == NULL) {
264 vector = (gchar **) g_malloc (2 * sizeof (vector));
265 vector [0] = NULL;
266 } else if (size > 0) {
267 vector[size - 1] = NULL;
270 return vector;
273 static gboolean
274 charcmp (gchar testchar, const gchar *compare)
276 while(*compare) {
277 if (*compare == testchar) {
278 return TRUE;
280 compare++;
283 return FALSE;
286 gchar **
287 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
289 const gchar *c;
290 gchar *token, **vector;
291 gint size = 1;
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 ("");
300 size++;
301 string++;
302 } else {
303 vector = NULL;
306 c = string;
307 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
308 if (charcmp (*string, delimiter)) {
309 gsize toklen = (string - c);
310 if (toklen == 0) {
311 token = g_strdup ("");
312 } else {
313 token = g_strndup (c, toklen);
316 c = string + 1;
318 add_to_vector (&vector, size, token);
319 size++;
322 string++;
325 if (max_tokens > 0 && size >= max_tokens) {
326 if (*string) {
327 /* Add the rest of the string as the last element */
328 add_to_vector (&vector, size, g_strdup (string));
329 size++;
331 } else {
332 if (*c) {
333 /* Fill in the trailing last token */
334 add_to_vector (&vector, size, g_strdup (c));
335 size++;
336 } else {
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 (""));
341 size++;
345 if (vector == NULL) {
346 vector = (gchar **) g_malloc (2 * sizeof (vector));
347 vector [0] = NULL;
348 } else if (size > 0) {
349 vector[size - 1] = NULL;
352 return vector;
355 gchar *
356 g_strreverse (gchar *str)
358 size_t i, j;
359 gchar c;
361 if (str == NULL)
362 return NULL;
364 if (*str == 0)
365 return str;
367 for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
368 c = str [i];
369 str [i] = str [j];
370 str [j] = c;
373 return str;
376 gchar *
377 g_strjoin (const gchar *separator, ...)
379 va_list args;
380 char *res, *s, *r;
381 size_t len, slen;
383 if (separator != NULL)
384 slen = strlen (separator);
385 else
386 slen = 0;
388 len = 0;
389 va_start (args, separator);
390 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
391 len += strlen (s);
392 len += slen;
394 va_end (args);
396 if (len == 0)
397 return g_strdup ("");
399 /* Remove the last separator */
400 if (slen > 0 && len > 0)
401 len -= slen;
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);
410 r = g_stpcpy (r, s);
412 va_end (args);
414 return res;
417 gchar *
418 g_strjoinv (const gchar *separator, gchar **str_array)
420 char *res, *r;
421 size_t slen, len, i;
423 if (separator != NULL)
424 slen = strlen (separator);
425 else
426 slen = 0;
428 len = 0;
429 for (i = 0; str_array [i] != NULL; i++){
430 len += strlen (str_array [i]);
431 len += slen;
434 if (len == 0)
435 return g_strdup ("");
437 if (slen > 0 && len > 0)
438 len -= slen;
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]);
448 return res;
451 gchar *
452 g_strchug (gchar *str)
454 size_t len;
455 gchar *tmp;
457 if (str == NULL)
458 return NULL;
460 tmp = str;
461 while (*tmp && isspace (*tmp)) tmp++;
462 if (str != tmp) {
463 len = strlen (str) - (tmp - str - 1);
464 memmove (str, tmp, len);
466 return str;
469 gchar *
470 g_strchomp (gchar *str)
472 gchar *tmp;
474 if (str == NULL)
475 return NULL;
477 tmp = str + strlen (str) - 1;
478 while (*tmp && isspace (*tmp)) tmp--;
479 *(tmp + 1) = '\0';
480 return str;
483 gint
484 g_printf(gchar const *format, ...)
486 va_list args;
487 gint ret;
489 va_start(args, format);
490 ret = vprintf(format, args);
491 va_end(args);
493 return ret;
496 gint
497 g_fprintf(FILE *file, gchar const *format, ...)
499 va_list args;
500 gint ret;
502 va_start(args, format);
503 ret = vfprintf(file, format, args);
504 va_end(args);
506 return ret;
509 gint
510 g_sprintf(gchar *string, gchar const *format, ...)
512 va_list args;
513 gint ret;
515 va_start(args, format);
516 ret = vsprintf(string, format, args);
517 va_end(args);
519 return ret;
522 gint
523 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
525 va_list args;
526 gint ret;
528 va_start(args, format);
529 ret = vsnprintf(string, n, format, args);
530 va_end(args);
532 return ret;
535 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
536 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
538 static gboolean
539 char_needs_encoding (char c)
541 if (((unsigned char)c) >= 0x80)
542 return TRUE;
544 if ((c >= '@' && c <= 'Z') ||
545 (c >= 'a' && c <= 'z') ||
546 (c >= '&' && c < 0x3b) ||
547 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
548 return FALSE;
549 return TRUE;
552 gchar *
553 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
555 size_t n;
556 char *ret, *rp;
557 const char *p;
558 #ifdef G_OS_WIN32
559 const char *uriPrefix = "file:///";
560 #else
561 const char *uriPrefix = "file://";
562 #endif
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)){
570 if (error != NULL)
571 *error = g_error_new (NULL, 2, "Not an absolute filename");
573 return NULL;
576 n = strlen (uriPrefix) + 1;
577 for (p = filename; *p; p++){
578 #ifdef G_OS_WIN32
579 if (*p == '\\') {
580 n++;
581 continue;
583 #endif
584 if (char_needs_encoding (*p))
585 n += 3;
586 else
587 n++;
589 ret = g_malloc (n);
590 strcpy (ret, uriPrefix);
591 for (p = filename, rp = ret + strlen (ret); *p; p++){
592 #ifdef G_OS_WIN32
593 if (*p == '\\') {
594 *rp++ = '/';
595 continue;
597 #endif
598 if (char_needs_encoding (*p)){
599 *rp++ = '%';
600 *rp++ = hx [((unsigned char)(*p)) >> 4];
601 *rp++ = hx [((unsigned char)(*p)) & 0xf];
602 } else
603 *rp++ = *p;
605 *rp = 0;
606 return ret;
609 static int
610 decode (char p)
612 if (p >= '0' && p <= '9')
613 return p - '0';
614 if (p >= 'A' && p <= 'F')
615 return p - 'A';
616 if (p >= 'a' && p <= 'f')
617 return p - 'a';
618 g_assert_not_reached ();
619 return 0;
622 gchar *
623 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
625 const char *p;
626 char *r, *result;
627 int flen = 0;
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){
635 if (error != NULL)
636 *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
637 return NULL;
640 for (p = uri + 8; *p; p++){
641 if (*p == '%'){
642 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
643 p += 2;
644 } else {
645 if (error != NULL)
646 *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
647 return NULL;
650 flen++;
652 #ifndef G_OS_WIN32
653 flen++;
654 #endif
656 result = g_malloc (flen + 1);
657 result [flen] = 0;
659 #ifndef G_OS_WIN32
660 *result = '/';
661 r = result + 1;
662 #else
663 r = result;
664 #endif
666 for (p = uri + 8; *p; p++){
667 if (*p == '%'){
668 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
669 p += 2;
670 } else
671 *r++ = *p;
672 flen++;
674 return result;
677 void
678 g_strdown (gchar *string)
680 g_return_if_fail (string != NULL);
682 while (*string){
683 *string = (gchar)tolower (*string);
684 string++;
688 gchar
689 g_ascii_tolower (gchar c)
691 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
694 gchar *
695 g_ascii_strdown (const gchar *str, gssize len)
697 char *ret;
698 int i;
700 g_return_val_if_fail (str != NULL, NULL);
702 if (len == -1)
703 len = strlen (str);
705 ret = g_malloc (len + 1);
706 for (i = 0; i < len; i++)
707 ret [i] = (guchar) g_ascii_tolower (str [i]);
708 ret [i] = 0;
710 return ret;
713 gchar
714 g_ascii_toupper (gchar c)
716 return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
719 gchar *
720 g_ascii_strup (const gchar *str, gssize len)
722 char *ret;
723 int i;
725 g_return_val_if_fail (str != NULL, NULL);
727 if (len == -1)
728 len = strlen (str);
730 ret = g_malloc (len + 1);
731 for (i = 0; i < len; i++)
732 ret [i] = (guchar) g_ascii_toupper (str [i]);
733 ret [i] = 0;
735 return ret;
738 gint
739 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
741 gsize i;
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++);
750 if (c1 != c2)
751 return c1 - c2;
754 return 0;
757 gint
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++);
770 if (c1 != c2)
771 return c1 - c2;
774 return (*sp1) - (*sp2);
777 gchar *
778 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
780 gchar *ptr;
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;
792 return string;
795 gsize
796 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
798 #ifdef HAVE_STRLCPY
799 return strlcpy (dest, src, dest_size);
800 #else
801 gchar *d;
802 const gchar *s;
803 gchar c;
804 gsize len;
806 g_return_val_if_fail (src != NULL, 0);
807 g_return_val_if_fail (dest != NULL, 0);
809 len = dest_size;
810 if (len == 0)
811 return 0;
813 s = src;
814 d = dest;
815 while (--len) {
816 c = *s++;
817 *d++ = c;
818 if (c == '\0')
819 return (dest_size - len - 1);
822 /* len is 0 i we get here */
823 *d = '\0';
824 /* we need to return the length of src here */
825 while (*s++) ; /* instead of a plain strlen, we use 's' */
826 return s - src - 1;
827 #endif
830 gchar *
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);
836 #if HAVE_STPCPY
837 return stpcpy (dest, src);
838 #else
839 while (*src)
840 *dest++ = *src++;
842 *dest = '\0';
844 return dest;
845 #endif
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
867 gchar *
868 g_strescape (const gchar *source, const gchar *exceptions)
870 gchar escaped [256];
871 const gchar *ptr;
872 gchar c;
873 gchar op;
874 gchar *result;
875 gchar *res_ptr;
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. */
885 res_ptr = result;
886 for (ptr = source; *ptr; ptr++) {
887 c = *ptr;
888 op = escaped [(int) c];
889 if (op == 0) {
890 *res_ptr++ = c;
891 } else {
892 *res_ptr++ = '\\';
893 if (op != 1) {
894 *res_ptr++ = op;
895 } else {
896 *res_ptr++ = '0' + ((c >> 6) & 3);
897 *res_ptr++ = '0' + ((c >> 3) & 7);
898 *res_ptr++ = '0' + (c & 7);
902 *res_ptr = '\0';
903 return result;
906 gint
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) :
912 (c - 'A' + 10))));
915 gchar *
916 g_strnfill (gsize length, gchar fill_char)
918 gchar *ret = g_new (gchar, length + 1);
920 memset (ret, fill_char, length);
921 ret [length] = 0;
922 return ret;