2010-03-30 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / eglib / src / gstr.c
blob305f9480e26867fb19f6bcbcef8b34cb25e15df9
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 guint
67 g_strv_length(gchar **str_array)
69 gint length = 0;
70 g_return_val_if_fail(str_array != NULL, 0);
71 for(length = 0; str_array[length] != NULL; length++);
72 return length;
75 gboolean
76 g_str_has_suffix(const gchar *str, const gchar *suffix)
78 size_t str_length;
79 size_t suffix_length;
81 g_return_val_if_fail(str != NULL, FALSE);
82 g_return_val_if_fail(suffix != NULL, FALSE);
84 str_length = strlen(str);
85 suffix_length = strlen(suffix);
87 return suffix_length <= str_length ?
88 strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0 :
89 FALSE;
92 gboolean
93 g_str_has_prefix(const gchar *str, const gchar *prefix)
95 size_t str_length;
96 size_t prefix_length;
98 g_return_val_if_fail(str != NULL, FALSE);
99 g_return_val_if_fail(prefix != NULL, FALSE);
101 str_length = strlen(str);
102 prefix_length = strlen(prefix);
104 return prefix_length <= str_length ?
105 strncmp(str, prefix, prefix_length) == 0 :
106 FALSE;
109 gchar *
110 g_strdup_vprintf (const gchar *format, va_list args)
112 int n;
113 char *ret;
115 n = vasprintf (&ret, format, args);
116 if (n == -1)
117 return NULL;
119 return ret;
122 gchar *
123 g_strdup_printf (const gchar *format, ...)
125 gchar *ret;
126 va_list args;
127 int n;
129 va_start (args, format);
130 n = vasprintf (&ret, format, args);
131 va_end (args);
132 if (n == -1)
133 return NULL;
135 return ret;
138 const gchar *
139 g_strerror (gint errnum)
141 return strerror (errnum);
144 gchar *
145 g_strconcat (const gchar *first, ...)
147 va_list args;
148 size_t total = 0;
149 char *s, *ret;
150 g_return_val_if_fail (first != NULL, NULL);
152 total += strlen (first);
153 va_start (args, first);
154 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
155 total += strlen (s);
157 va_end (args);
159 ret = g_malloc (total + 1);
160 if (ret == NULL)
161 return NULL;
163 ret [total] = 0;
164 strcpy (ret, first);
165 va_start (args, first);
166 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
167 strcat (ret, s);
169 va_end (args);
171 return ret;
174 static void
175 add_to_vector (gchar ***vector, int size, gchar *token)
177 *vector = *vector == NULL ?
178 (gchar **)g_malloc(2 * sizeof(*vector)) :
179 (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
181 (*vector)[size - 1] = token;
184 gchar **
185 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
187 const gchar *c;
188 gchar *token, **vector;
189 gint size = 1;
191 g_return_val_if_fail (string != NULL, NULL);
192 g_return_val_if_fail (delimiter != NULL, NULL);
193 g_return_val_if_fail (delimiter[0] != 0, NULL);
195 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
196 vector = (gchar **)g_malloc (2 * sizeof(vector));
197 vector[0] = g_strdup ("");
198 size++;
199 string += strlen (delimiter);
200 } else {
201 vector = NULL;
204 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
205 c = string;
206 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
207 token = g_strdup ("");
208 string += strlen (delimiter);
209 } else {
210 while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
211 string++;
214 if (*string) {
215 gsize toklen = (string - c);
216 token = g_strndup (c, toklen);
218 /* Need to leave a trailing empty
219 * token if the delimiter is the last
220 * part of the string
222 if (strcmp (string, delimiter) != 0) {
223 string += strlen (delimiter);
225 } else {
226 token = g_strdup (c);
230 add_to_vector (&vector, size, token);
231 size++;
234 if (*string) {
235 /* Add the rest of the string as the last element */
236 add_to_vector (&vector, size, g_strdup (string));
237 size++;
240 if (vector == NULL) {
241 vector = (gchar **) g_malloc (2 * sizeof (vector));
242 vector [0] = NULL;
243 } else if (size > 0) {
244 vector[size - 1] = NULL;
247 return vector;
250 static gboolean
251 charcmp (gchar testchar, const gchar *compare)
253 while(*compare) {
254 if (*compare == testchar) {
255 return TRUE;
257 compare++;
260 return FALSE;
263 gchar **
264 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
266 const gchar *c;
267 gchar *token, **vector;
268 gint size = 1;
270 g_return_val_if_fail (string != NULL, NULL);
271 g_return_val_if_fail (delimiter != NULL, NULL);
272 g_return_val_if_fail (delimiter[0] != 0, NULL);
274 if (charcmp (*string, delimiter)) {
275 vector = (gchar **)g_malloc (2 * sizeof(vector));
276 vector[0] = g_strdup ("");
277 size++;
278 string++;
279 } else {
280 vector = NULL;
283 c = string;
284 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
285 if (charcmp (*string, delimiter)) {
286 gsize toklen = (string - c);
287 if (toklen == 0) {
288 token = g_strdup ("");
289 } else {
290 token = g_strndup (c, toklen);
293 c = string + 1;
295 add_to_vector (&vector, size, token);
296 size++;
299 string++;
302 if (max_tokens > 0 && size >= max_tokens) {
303 if (*string) {
304 /* Add the rest of the string as the last element */
305 add_to_vector (&vector, size, g_strdup (string));
306 size++;
308 } else {
309 if (*c) {
310 /* Fill in the trailing last token */
311 add_to_vector (&vector, size, g_strdup (c));
312 size++;
313 } else {
314 /* Need to leave a trailing empty token if the
315 * delimiter is the last part of the string
317 add_to_vector (&vector, size, g_strdup (""));
318 size++;
322 if (vector == NULL) {
323 vector = (gchar **) g_malloc (2 * sizeof (vector));
324 vector [0] = NULL;
325 } else if (size > 0) {
326 vector[size - 1] = NULL;
329 return vector;
332 gchar *
333 g_strreverse (gchar *str)
335 size_t len, half;
336 size_t i;
337 gchar c;
339 if (str == NULL)
340 return NULL;
342 len = strlen (str);
343 half = len / 2;
344 len--;
345 for (i = 0; i < half; i++, len--) {
346 c = str [i];
347 str [i] = str [len];
348 str [len] = c;
350 return str;
353 gchar *
354 g_strjoin (const gchar *separator, ...)
356 va_list args;
357 char *res, *s;
358 size_t len, slen;
360 if (separator != NULL)
361 slen = strlen (separator);
362 else
363 slen = 0;
364 len = 0;
365 va_start (args, separator);
366 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
367 len += strlen (s);
368 len += slen;
370 va_end (args);
371 if (len == 0)
372 return g_strdup ("");
374 /* Remove the last separator */
375 if (slen > 0 && len > 0)
376 len -= slen;
377 len++;
378 res = g_malloc (len);
379 va_start (args, separator);
380 s = va_arg (args, char *);
381 strcpy (res, s);
382 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
383 if (separator != NULL)
384 strcat (res, separator);
385 strcat (res, s);
387 va_end (args);
389 return res;
392 gchar *
393 g_strjoinv (const gchar *separator, gchar **str_array)
395 char *res;
396 size_t slen, len, i;
398 if (separator != NULL)
399 slen = strlen (separator);
400 else
401 slen = 0;
403 len = 0;
404 for (i = 0; str_array [i] != NULL; i++){
405 len += strlen (str_array [i]);
406 len += slen;
408 if (len == 0)
409 return g_strdup ("");
410 if (slen > 0 && len > 0)
411 len -= slen;
412 len++;
413 res = g_malloc (len);
414 strcpy (res, str_array [0]);
415 for (i = 1; str_array [i] != NULL; i++){
416 if (separator != NULL)
417 strcat (res, separator);
418 strcat (res, str_array [i]);
420 return res;
423 gchar *
424 g_strchug (gchar *str)
426 size_t len;
427 gchar *tmp;
429 if (str == NULL)
430 return NULL;
432 tmp = str;
433 while (*tmp && isspace (*tmp)) tmp++;
434 if (str != tmp) {
435 len = strlen (str) - (tmp - str - 1);
436 memmove (str, tmp, len);
438 return str;
441 gchar *
442 g_strchomp (gchar *str)
444 gchar *tmp;
446 if (str == NULL)
447 return NULL;
449 tmp = str + strlen (str) - 1;
450 while (*tmp && isspace (*tmp)) tmp--;
451 *(tmp + 1) = '\0';
452 return str;
455 gint
456 g_printf(gchar const *format, ...)
458 va_list args;
459 gint ret;
461 va_start(args, format);
462 ret = vprintf(format, args);
463 va_end(args);
465 return ret;
468 gint
469 g_fprintf(FILE *file, gchar const *format, ...)
471 va_list args;
472 gint ret;
474 va_start(args, format);
475 ret = vfprintf(file, format, args);
476 va_end(args);
478 return ret;
481 gint
482 g_sprintf(gchar *string, gchar const *format, ...)
484 va_list args;
485 gint ret;
487 va_start(args, format);
488 ret = vsprintf(string, format, args);
489 va_end(args);
491 return ret;
494 gint
495 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
497 va_list args;
498 gint ret;
500 va_start(args, format);
501 ret = vsnprintf(string, n, format, args);
502 va_end(args);
504 return ret;
507 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
508 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
510 static gboolean
511 char_needs_encoding (char c)
513 if (((unsigned char)c) >= 0x80)
514 return TRUE;
516 if ((c >= '@' && c <= 'Z') ||
517 (c >= 'a' && c <= 'z') ||
518 (c >= '&' && c < 0x3b) ||
519 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
520 return FALSE;
521 return TRUE;
524 gchar *
525 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
527 size_t n;
528 char *ret, *rp;
529 const char *p;
530 #ifdef G_OS_WIN32
531 const char *uriPrefix = "file:///";
532 #else
533 const char *uriPrefix = "file://";
534 #endif
536 g_return_val_if_fail (filename != NULL, NULL);
538 if (hostname != NULL)
539 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
541 if (!g_path_is_absolute (filename)){
542 if (error != NULL)
543 *error = g_error_new (NULL, 2, "Not an absolute filename");
545 return NULL;
548 n = strlen (uriPrefix) + 1;
549 for (p = filename; *p; p++){
550 #ifdef G_OS_WIN32
551 if (*p == '\\') {
552 n++;
553 continue;
555 #endif
556 if (char_needs_encoding (*p))
557 n += 3;
558 else
559 n++;
561 ret = g_malloc (n);
562 strcpy (ret, uriPrefix);
563 for (p = filename, rp = ret + strlen (ret); *p; p++){
564 #ifdef G_OS_WIN32
565 if (*p == '\\') {
566 *rp++ = '/';
567 continue;
569 #endif
570 if (char_needs_encoding (*p)){
571 *rp++ = '%';
572 *rp++ = hx [((unsigned char)(*p)) >> 4];
573 *rp++ = hx [((unsigned char)(*p)) & 0xf];
574 } else
575 *rp++ = *p;
577 *rp = 0;
578 return ret;
581 static int
582 decode (char p)
584 if (p >= '0' && p <= '9')
585 return p - '0';
586 if (p >= 'A' && p <= 'F')
587 return p - 'A';
588 if (p >= 'a' && p <= 'f')
589 return p - 'a';
590 g_assert_not_reached ();
591 return 0;
594 gchar *
595 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
597 const char *p;
598 char *r, *result;
599 int flen = 0;
601 g_return_val_if_fail (uri != NULL, NULL);
603 if (hostname != NULL)
604 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
606 if (strncmp (uri, "file:///", 8) != 0){
607 if (error != NULL)
608 *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
609 return NULL;
612 for (p = uri + 8; *p; p++){
613 if (*p == '%'){
614 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
615 p += 2;
616 } else {
617 if (error != NULL)
618 *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
619 return NULL;
622 flen++;
624 #ifndef G_OS_WIN32
625 flen++;
626 #endif
628 result = g_malloc (flen + 1);
629 result [flen] = 0;
631 #ifndef G_OS_WIN32
632 *result = '/';
633 r = result + 1;
634 #else
635 r = result;
636 #endif
638 for (p = uri + 8; *p; p++){
639 if (*p == '%'){
640 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
641 p += 2;
642 } else
643 *r++ = *p;
644 flen++;
646 return result;
649 void
650 g_strdown (gchar *string)
652 g_return_if_fail (string != NULL);
654 while (*string){
655 *string = (gchar)tolower (*string);
656 string++;
660 gchar
661 g_ascii_tolower (gchar c)
663 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
666 gchar *
667 g_ascii_strdown (const gchar *str, gssize len)
669 char *ret;
670 int i;
672 g_return_val_if_fail (str != NULL, NULL);
674 if (len == -1)
675 len = strlen (str);
677 ret = g_malloc (len + 1);
678 for (i = 0; i < len; i++)
679 ret [i] = (guchar) g_ascii_tolower (str [i]);
680 ret [i] = 0;
682 return ret;
685 gint
686 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
688 gsize i;
690 g_return_val_if_fail (s1 != NULL, 0);
691 g_return_val_if_fail (s2 != NULL, 0);
693 for (i = 0; i < n; i++){
694 gchar c1 = g_ascii_tolower (*s1++);
695 gchar c2 = g_ascii_tolower (*s2++);
697 if (c1 == c2)
698 continue;
700 if (c1 == 0)
701 return -1;
702 if (c2 == 0)
703 return 1;
704 return c1-c2;
706 return 0;
709 gchar *
710 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
712 gchar *ptr;
714 g_return_val_if_fail (string != NULL, NULL);
716 if (delimiters == NULL)
717 delimiters = G_STR_DELIMITERS;
719 for (ptr = string; *ptr; ptr++) {
720 if (strchr (delimiters, *ptr))
721 *ptr = new_delimiter;
724 return string;
727 gsize
728 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
730 #ifdef HAVE_STRLCPY
731 return strlcpy (dest, src, dest_size);
732 #else
733 gchar *d;
734 const gchar *s;
735 gchar c;
736 gsize len;
738 g_return_val_if_fail (src != NULL, 0);
739 g_return_val_if_fail (dest != NULL, 0);
741 len = dest_size;
742 if (len == 0)
743 return 0;
745 s = src;
746 d = dest;
747 while (--len) {
748 c = *s++;
749 *d++ = c;
750 if (c == '\0')
751 return (dest_size - len - 1);
754 /* len is 0 i we get here */
755 *d = '\0';
756 /* we need to return the length of src here */
757 while (*s++) ; /* instead of a plain strlen, we use 's' */
758 return s - src - 1;
759 #endif
762 static const gchar escaped_dflt [256] = {
763 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
764 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
765 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
766 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
767 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
768 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
769 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
770 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
771 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
772 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
773 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
774 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
775 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
776 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
777 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
778 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
781 gchar *
782 g_strescape (const gchar *source, const gchar *exceptions)
784 gchar escaped [256];
785 const gchar *ptr;
786 gchar c;
787 gchar op;
788 gchar *result;
789 gchar *res_ptr;
791 g_return_val_if_fail (source != NULL, NULL);
793 memcpy (escaped, escaped_dflt, 256);
794 if (exceptions != NULL) {
795 for (ptr = exceptions; *ptr; ptr++)
796 escaped [(int) *ptr] = 0;
798 result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
799 res_ptr = result;
800 for (ptr = source; *ptr; ptr++) {
801 c = *ptr;
802 op = escaped [(int) c];
803 if (op == 0) {
804 *res_ptr++ = c;
805 } else {
806 *res_ptr++ = '\\';
807 if (op != 1) {
808 *res_ptr++ = op;
809 } else {
810 *res_ptr++ = '0' + ((c >> 6) & 3);
811 *res_ptr++ = '0' + ((c >> 3) & 7);
812 *res_ptr++ = '0' + (c & 7);
816 *res_ptr = '\0';
817 return result;
820 gint
821 g_ascii_xdigit_value (gchar c)
823 return ((isxdigit (c) == 0) ? -1 :
824 ((c >= '0' && c <= '9') ? (c - '0') :
825 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
826 (c - 'A' + 10))));
829 gchar *
830 g_strnfill (gsize length, gchar fill_char)
832 gchar *ret = g_new (gchar, length + 1);
834 memset (ret, fill_char, length);
835 ret [length] = 0;
836 return ret;