Enable monitor enter/exit wrappers under sgen.
[mono-project/dkf.git] / eglib / src / gstr.c
blob015f798faecb10a1c1729cb455f3fe5013f4ab5a
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 len, half;
355 size_t i;
356 gchar c;
358 if (str == NULL)
359 return NULL;
361 len = strlen (str);
362 half = len / 2;
363 len--;
364 for (i = 0; i < half; i++, len--) {
365 c = str [i];
366 str [i] = str [len];
367 str [len] = c;
369 return str;
372 gchar *
373 g_strjoin (const gchar *separator, ...)
375 va_list args;
376 char *res, *s;
377 size_t len, slen;
379 if (separator != NULL)
380 slen = strlen (separator);
381 else
382 slen = 0;
383 len = 0;
384 va_start (args, separator);
385 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
386 len += strlen (s);
387 len += slen;
389 va_end (args);
390 if (len == 0)
391 return g_strdup ("");
393 /* Remove the last separator */
394 if (slen > 0 && len > 0)
395 len -= slen;
396 len++;
397 res = g_malloc (len);
398 va_start (args, separator);
399 s = va_arg (args, char *);
400 strcpy (res, s);
401 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
402 if (separator != NULL)
403 strcat (res, separator);
404 strcat (res, s);
406 va_end (args);
408 return res;
411 gchar *
412 g_strjoinv (const gchar *separator, gchar **str_array)
414 char *res;
415 size_t slen, len, i;
417 if (separator != NULL)
418 slen = strlen (separator);
419 else
420 slen = 0;
422 len = 0;
423 for (i = 0; str_array [i] != NULL; i++){
424 len += strlen (str_array [i]);
425 len += slen;
427 if (len == 0)
428 return g_strdup ("");
429 if (slen > 0 && len > 0)
430 len -= slen;
431 len++;
432 res = g_malloc (len);
433 strcpy (res, str_array [0]);
434 for (i = 1; str_array [i] != NULL; i++){
435 if (separator != NULL)
436 strcat (res, separator);
437 strcat (res, str_array [i]);
439 return res;
442 gchar *
443 g_strchug (gchar *str)
445 size_t len;
446 gchar *tmp;
448 if (str == NULL)
449 return NULL;
451 tmp = str;
452 while (*tmp && isspace (*tmp)) tmp++;
453 if (str != tmp) {
454 len = strlen (str) - (tmp - str - 1);
455 memmove (str, tmp, len);
457 return str;
460 gchar *
461 g_strchomp (gchar *str)
463 gchar *tmp;
465 if (str == NULL)
466 return NULL;
468 tmp = str + strlen (str) - 1;
469 while (*tmp && isspace (*tmp)) tmp--;
470 *(tmp + 1) = '\0';
471 return str;
474 gint
475 g_printf(gchar const *format, ...)
477 va_list args;
478 gint ret;
480 va_start(args, format);
481 ret = vprintf(format, args);
482 va_end(args);
484 return ret;
487 gint
488 g_fprintf(FILE *file, gchar const *format, ...)
490 va_list args;
491 gint ret;
493 va_start(args, format);
494 ret = vfprintf(file, format, args);
495 va_end(args);
497 return ret;
500 gint
501 g_sprintf(gchar *string, gchar const *format, ...)
503 va_list args;
504 gint ret;
506 va_start(args, format);
507 ret = vsprintf(string, format, args);
508 va_end(args);
510 return ret;
513 gint
514 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
516 va_list args;
517 gint ret;
519 va_start(args, format);
520 ret = vsnprintf(string, n, format, args);
521 va_end(args);
523 return ret;
526 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
527 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
529 static gboolean
530 char_needs_encoding (char c)
532 if (((unsigned char)c) >= 0x80)
533 return TRUE;
535 if ((c >= '@' && c <= 'Z') ||
536 (c >= 'a' && c <= 'z') ||
537 (c >= '&' && c < 0x3b) ||
538 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
539 return FALSE;
540 return TRUE;
543 gchar *
544 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
546 size_t n;
547 char *ret, *rp;
548 const char *p;
549 #ifdef G_OS_WIN32
550 const char *uriPrefix = "file:///";
551 #else
552 const char *uriPrefix = "file://";
553 #endif
555 g_return_val_if_fail (filename != NULL, NULL);
557 if (hostname != NULL)
558 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
560 if (!g_path_is_absolute (filename)){
561 if (error != NULL)
562 *error = g_error_new (NULL, 2, "Not an absolute filename");
564 return NULL;
567 n = strlen (uriPrefix) + 1;
568 for (p = filename; *p; p++){
569 #ifdef G_OS_WIN32
570 if (*p == '\\') {
571 n++;
572 continue;
574 #endif
575 if (char_needs_encoding (*p))
576 n += 3;
577 else
578 n++;
580 ret = g_malloc (n);
581 strcpy (ret, uriPrefix);
582 for (p = filename, rp = ret + strlen (ret); *p; p++){
583 #ifdef G_OS_WIN32
584 if (*p == '\\') {
585 *rp++ = '/';
586 continue;
588 #endif
589 if (char_needs_encoding (*p)){
590 *rp++ = '%';
591 *rp++ = hx [((unsigned char)(*p)) >> 4];
592 *rp++ = hx [((unsigned char)(*p)) & 0xf];
593 } else
594 *rp++ = *p;
596 *rp = 0;
597 return ret;
600 static int
601 decode (char p)
603 if (p >= '0' && p <= '9')
604 return p - '0';
605 if (p >= 'A' && p <= 'F')
606 return p - 'A';
607 if (p >= 'a' && p <= 'f')
608 return p - 'a';
609 g_assert_not_reached ();
610 return 0;
613 gchar *
614 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
616 const char *p;
617 char *r, *result;
618 int flen = 0;
620 g_return_val_if_fail (uri != NULL, NULL);
622 if (hostname != NULL)
623 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
625 if (strncmp (uri, "file:///", 8) != 0){
626 if (error != NULL)
627 *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
628 return NULL;
631 for (p = uri + 8; *p; p++){
632 if (*p == '%'){
633 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
634 p += 2;
635 } else {
636 if (error != NULL)
637 *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
638 return NULL;
641 flen++;
643 #ifndef G_OS_WIN32
644 flen++;
645 #endif
647 result = g_malloc (flen + 1);
648 result [flen] = 0;
650 #ifndef G_OS_WIN32
651 *result = '/';
652 r = result + 1;
653 #else
654 r = result;
655 #endif
657 for (p = uri + 8; *p; p++){
658 if (*p == '%'){
659 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
660 p += 2;
661 } else
662 *r++ = *p;
663 flen++;
665 return result;
668 void
669 g_strdown (gchar *string)
671 g_return_if_fail (string != NULL);
673 while (*string){
674 *string = (gchar)tolower (*string);
675 string++;
679 gchar
680 g_ascii_tolower (gchar c)
682 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
685 gchar *
686 g_ascii_strdown (const gchar *str, gssize len)
688 char *ret;
689 int i;
691 g_return_val_if_fail (str != NULL, NULL);
693 if (len == -1)
694 len = strlen (str);
696 ret = g_malloc (len + 1);
697 for (i = 0; i < len; i++)
698 ret [i] = (guchar) g_ascii_tolower (str [i]);
699 ret [i] = 0;
701 return ret;
704 gint
705 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
707 gsize i;
709 g_return_val_if_fail (s1 != NULL, 0);
710 g_return_val_if_fail (s2 != NULL, 0);
712 for (i = 0; i < n; i++){
713 gchar c1 = g_ascii_tolower (*s1++);
714 gchar c2 = g_ascii_tolower (*s2++);
716 if (c1 == c2)
717 continue;
719 if (c1 == 0)
720 return -1;
721 if (c2 == 0)
722 return 1;
723 return c1-c2;
725 return 0;
728 gchar *
729 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
731 gchar *ptr;
733 g_return_val_if_fail (string != NULL, NULL);
735 if (delimiters == NULL)
736 delimiters = G_STR_DELIMITERS;
738 for (ptr = string; *ptr; ptr++) {
739 if (strchr (delimiters, *ptr))
740 *ptr = new_delimiter;
743 return string;
746 gsize
747 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
749 #ifdef HAVE_STRLCPY
750 return strlcpy (dest, src, dest_size);
751 #else
752 gchar *d;
753 const gchar *s;
754 gchar c;
755 gsize len;
757 g_return_val_if_fail (src != NULL, 0);
758 g_return_val_if_fail (dest != NULL, 0);
760 len = dest_size;
761 if (len == 0)
762 return 0;
764 s = src;
765 d = dest;
766 while (--len) {
767 c = *s++;
768 *d++ = c;
769 if (c == '\0')
770 return (dest_size - len - 1);
773 /* len is 0 i we get here */
774 *d = '\0';
775 /* we need to return the length of src here */
776 while (*s++) ; /* instead of a plain strlen, we use 's' */
777 return s - src - 1;
778 #endif
781 static const gchar escaped_dflt [256] = {
782 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
783 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
784 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
787 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
788 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
789 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
790 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
791 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
792 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
793 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
794 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
795 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
796 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
797 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
800 gchar *
801 g_strescape (const gchar *source, const gchar *exceptions)
803 gchar escaped [256];
804 const gchar *ptr;
805 gchar c;
806 gchar op;
807 gchar *result;
808 gchar *res_ptr;
810 g_return_val_if_fail (source != NULL, NULL);
812 memcpy (escaped, escaped_dflt, 256);
813 if (exceptions != NULL) {
814 for (ptr = exceptions; *ptr; ptr++)
815 escaped [(int) *ptr] = 0;
817 result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
818 res_ptr = result;
819 for (ptr = source; *ptr; ptr++) {
820 c = *ptr;
821 op = escaped [(int) c];
822 if (op == 0) {
823 *res_ptr++ = c;
824 } else {
825 *res_ptr++ = '\\';
826 if (op != 1) {
827 *res_ptr++ = op;
828 } else {
829 *res_ptr++ = '0' + ((c >> 6) & 3);
830 *res_ptr++ = '0' + ((c >> 3) & 7);
831 *res_ptr++ = '0' + (c & 7);
835 *res_ptr = '\0';
836 return result;
839 gint
840 g_ascii_xdigit_value (gchar c)
842 return ((isxdigit (c) == 0) ? -1 :
843 ((c >= '0' && c <= '9') ? (c - '0') :
844 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
845 (c - 'A' + 10))));
848 gchar *
849 g_strnfill (gsize length, gchar fill_char)
851 gchar *ret = g_new (gchar, length + 1);
853 memset (ret, fill_char, length);
854 ret [length] = 0;
855 return ret;