Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / eglib / gstr.c
1 /*
2  * gstr.c: String Utility Functions.
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@novell.com)
6  *   Aaron Bockover (abockover@novell.com)
7  *
8  * (C) 2006 Novell, Inc.
9  *
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:
17  *
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  *
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.
28  */
29 #include <config.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <glib.h>
34
35 #ifndef G_OS_WIN32
36 #include <pthread.h>
37 #endif
38
39 #include <errno.h>
40
41 /* 
42  * g_strndup and g_vasprintf need to allocate memory with g_malloc if 
43  * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free 
44  * rather than free.
45  */
46
47 /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
48 gchar *
49 g_strndup (const gchar *str, gsize n)
50 {
51 #if defined (HAVE_STRNDUP) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
52         return strndup (str, n);
53 #else
54         if (str) {
55                 char *retval = g_malloc(n+1);
56                 if (retval) {
57                         strncpy(retval, str, n)[n] = 0;
58                 }
59                 return retval;
60         }
61         return NULL;
62 #endif
63 }
64
65 gint g_vasprintf (gchar **ret, const gchar *fmt, va_list ap)
66 {
67 #if defined (HAVE_VASPRINTF) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
68   return vasprintf (ret, fmt, ap);
69 #else
70         char *buf;
71         int len;
72         size_t buflen;
73         va_list ap2;
74         
75 #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
76         ap2 = ap;
77         len = _vscprintf(fmt, ap2); // NOTE MS specific extension ( :-( )
78 #else
79         va_copy(ap2, ap);
80         len = vsnprintf(NULL, 0, fmt, ap2);
81 #endif
82
83         if (len >= 0 && (buf = g_malloc ((buflen = (size_t) (len + 1)))) != NULL) {
84                 len = vsnprintf(buf, buflen, fmt, ap);
85                 *ret = buf;
86         } else {
87                 *ret = NULL;
88                 len = -1;
89         }
90
91         va_end(ap2);
92         return len;
93 #endif
94 }
95
96 void
97 g_strfreev (gchar **str_array)
98 {
99         gchar **orig = str_array;
100         if (str_array == NULL)
101                 return;
102         while (*str_array != NULL){
103                 g_free (*str_array);
104                 str_array++;
105         }
106         g_free (orig);
107 }
108
109 gchar **
110 g_strdupv (gchar **str_array)
111 {
112         guint length;
113         gchar **ret;
114         guint i;
115
116         if (!str_array)
117                 return NULL;
118
119         length = g_strv_length(str_array);
120         ret = g_new0(gchar *, length + 1);
121         for (i = 0; str_array[i]; i++) {
122                 ret[i] = g_strdup(str_array[i]);
123         }
124         ret[length] = NULL;
125         return ret;
126 }
127
128 guint
129 g_strv_length(gchar **str_array)
130 {
131         gint length = 0;
132         g_return_val_if_fail(str_array != NULL, 0);
133         for(length = 0; str_array[length] != NULL; length++);
134         return length;
135 }
136
137 gboolean
138 g_str_has_suffix(const gchar *str, const gchar *suffix)
139 {
140         size_t str_length;
141         size_t suffix_length;
142         
143         g_return_val_if_fail(str != NULL, FALSE);
144         g_return_val_if_fail(suffix != NULL, FALSE);
145
146         str_length = strlen(str);
147         suffix_length = strlen(suffix);
148
149         return suffix_length <= str_length ?
150                 strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0 :
151                 FALSE;
152 }
153
154 gboolean
155 g_str_has_prefix(const gchar *str, const gchar *prefix)
156 {
157         size_t str_length;
158         size_t prefix_length;
159         
160         g_return_val_if_fail(str != NULL, FALSE);
161         g_return_val_if_fail(prefix != NULL, FALSE);
162
163         str_length = strlen(str);
164         prefix_length = strlen(prefix);
165
166         return prefix_length <= str_length ?
167                 strncmp(str, prefix, prefix_length) == 0 :
168                 FALSE;
169 }
170
171 gchar *
172 g_strdup_vprintf (const gchar *format, va_list args)
173 {
174         int n;
175         char *ret;
176         
177         n = g_vasprintf (&ret, format, args);
178         if (n == -1)
179                 return NULL;
180
181         return ret;
182 }
183
184 gchar *
185 g_strdup_printf (const gchar *format, ...)
186 {
187         gchar *ret;
188         va_list args;
189         int n;
190
191         va_start (args, format);
192         n = g_vasprintf (&ret, format, args);
193         va_end (args);
194         if (n == -1)
195                 return NULL;
196
197         return ret;
198 }
199
200
201 /*
202 Max error number we support. It's empirically found by looking at our target OS.
203
204 Last this was checked was June-2017.
205
206 Apple is at 106.
207 Android is at 133.
208 */
209 #define MONO_ERRNO_MAX 200
210 #define str(s) #s
211
212 #ifndef G_OS_WIN32
213 static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
214 #endif
215
216 static char *error_messages [MONO_ERRNO_MAX];
217
218 const gchar *
219 g_strerror (gint errnum)
220 {
221         if (errnum < 0)
222                 errnum = -errnum;
223         if (errnum >= MONO_ERRNO_MAX)
224                 return ("Error number higher than " str (MONO_ERRNO_MAX));
225
226         if (!error_messages [errnum]) {
227 #ifndef G_OS_WIN32
228                 pthread_mutex_lock (&strerror_lock);
229 #endif
230
231 #ifdef HAVE_STRERROR_R
232                 char tmp_buff [128]; //Quite arbitrary, should be large enough
233                 char *buff = tmp_buff;
234                 size_t buff_len = sizeof (tmp_buff);
235                 buff [0] = 0;
236
237 #ifndef STRERROR_R_CHAR_P
238                 int r;
239                 while ((r = strerror_r (errnum, buff, buff_len - 1))) {
240                         if (r != ERANGE) {
241                                 buff = g_strdup_printf ("Invalid Error code '%d'", errnum);
242                                 break;
243                         }
244                         if (buff == tmp_buff)
245                                 buff = g_malloc (buff_len * 2);
246                         else
247                                 buff = g_realloc (buff, buff_len * 2);
248                         buff_len *= 2;
249                  //Spec is not clean on whether size argument includes space for null terminator or not 
250                 }
251                 if (!error_messages [errnum])
252                         error_messages [errnum] = g_strdup (buff);
253                 if (buff != tmp_buff)
254                         g_free (buff);
255 #else /* STRERROR_R_CHAR_P */
256                 buff = strerror_r (errnum, buff, buff_len);
257                 if (!error_messages [errnum])
258                         error_messages [errnum] = g_strdup (buff);
259 #endif /* STRERROR_R_CHAR_P */
260
261 #else /* HAVE_STRERROR_R */
262                 if (!error_messages [errnum])
263                         error_messages [errnum] = g_strdup_printf ("Error code '%d'", errnum);
264 #endif /* HAVE_STRERROR_R */
265
266
267 #ifndef G_OS_WIN32
268                 pthread_mutex_unlock (&strerror_lock);
269 #endif
270
271         }
272         return error_messages [errnum];
273 }
274
275 gchar *
276 g_strconcat (const gchar *first, ...)
277 {
278         va_list args;
279         size_t total = 0;
280         char *s, *ret;
281         g_return_val_if_fail (first != NULL, NULL);
282
283         total += strlen (first);
284         va_start (args, first);
285         for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
286                 total += strlen (s);
287         }
288         va_end (args);
289         
290         ret = g_malloc (total + 1);
291         if (ret == NULL)
292                 return NULL;
293
294         ret [total] = 0;
295         strcpy (ret, first);
296         va_start (args, first);
297         for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
298                 strcat (ret, s);
299         }
300         va_end (args);
301
302         return ret;
303 }
304
305 static void
306 add_to_vector (gchar ***vector, int size, gchar *token)
307 {
308         *vector = *vector == NULL ? 
309                 (gchar **)g_malloc(2 * sizeof(*vector)) :
310                 (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
311                 
312         (*vector)[size - 1] = token;
313 }
314
315 gchar ** 
316 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
317 {
318         const gchar *c;
319         gchar *token, **vector;
320         gint size = 1;
321         
322         g_return_val_if_fail (string != NULL, NULL);
323         g_return_val_if_fail (delimiter != NULL, NULL);
324         g_return_val_if_fail (delimiter[0] != 0, NULL);
325         
326         if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
327                 vector = (gchar **)g_malloc (2 * sizeof(vector));
328                 vector[0] = g_strdup ("");
329                 size++;
330                 string += strlen (delimiter);
331         } else {
332                 vector = NULL;
333         }
334
335         while (*string && !(max_tokens > 0 && size >= max_tokens)) {
336                 c = string;
337                 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
338                         token = g_strdup ("");
339                         string += strlen (delimiter);
340                 } else {
341                         while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
342                                 string++;
343                         }
344
345                         if (*string) {
346                                 gsize toklen = (string - c);
347                                 token = g_strndup (c, toklen);
348
349                                 /* Need to leave a trailing empty
350                                  * token if the delimiter is the last
351                                  * part of the string
352                                  */
353                                 if (strcmp (string, delimiter) != 0) {
354                                         string += strlen (delimiter);
355                                 }
356                         } else {
357                                 token = g_strdup (c);
358                         }
359                 }
360                         
361                 add_to_vector (&vector, size, token);
362                 size++;
363         }
364
365         if (*string) {
366                 if (strcmp (string, delimiter) == 0)
367                         add_to_vector (&vector, size, g_strdup (""));
368                 else {
369                         /* Add the rest of the string as the last element */
370                         add_to_vector (&vector, size, g_strdup (string));
371                 }
372                 size++;
373         }
374         
375         if (vector == NULL) {
376                 vector = (gchar **) g_malloc (2 * sizeof (vector));
377                 vector [0] = NULL;
378         } else if (size > 0) {
379                 vector[size - 1] = NULL;
380         }
381         
382         return vector;
383 }
384
385 static gboolean
386 charcmp (gchar testchar, const gchar *compare)
387 {
388         while(*compare) {
389                 if (*compare == testchar) {
390                         return TRUE;
391                 }
392                 compare++;
393         }
394         
395         return FALSE;
396 }
397
398 gchar ** 
399 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
400 {
401         const gchar *c;
402         gchar *token, **vector;
403         gint size = 1;
404         
405         g_return_val_if_fail (string != NULL, NULL);
406         g_return_val_if_fail (delimiter != NULL, NULL);
407         g_return_val_if_fail (delimiter[0] != 0, NULL);
408         
409         if (charcmp (*string, delimiter)) {
410                 vector = (gchar **)g_malloc (2 * sizeof(vector));
411                 vector[0] = g_strdup ("");
412                 size++;
413                 string++;
414         } else {
415                 vector = NULL;
416         }
417
418         c = string;
419         while (*string && !(max_tokens > 0 && size >= max_tokens)) {
420                 if (charcmp (*string, delimiter)) {
421                         gsize toklen = (string - c);
422                         if (toklen == 0) {
423                                 token = g_strdup ("");
424                         } else {
425                                 token = g_strndup (c, toklen);
426                         }
427                         
428                         c = string + 1;
429                         
430                         add_to_vector (&vector, size, token);
431                         size++;
432                 }
433
434                 string++;
435         }
436         
437         if (max_tokens > 0 && size >= max_tokens) {
438                 if (*string) {
439                         /* Add the rest of the string as the last element */
440                         add_to_vector (&vector, size, g_strdup (string));
441                         size++;
442                 }
443         } else {
444                 if (*c) {
445                         /* Fill in the trailing last token */
446                         add_to_vector (&vector, size, g_strdup (c));
447                         size++;
448                 } else {
449                         /* Need to leave a trailing empty token if the
450                          * delimiter is the last part of the string
451                          */
452                         add_to_vector (&vector, size, g_strdup (""));
453                         size++;
454                 }
455         }
456         
457         if (vector == NULL) {
458                 vector = (gchar **) g_malloc (2 * sizeof (vector));
459                 vector [0] = NULL;
460         } else if (size > 0) {
461                 vector[size - 1] = NULL;
462         }
463         
464         return vector;
465 }
466
467 gchar *
468 g_strreverse (gchar *str)
469 {
470         size_t i, j;
471         gchar c;
472
473         if (str == NULL)
474                 return NULL;
475
476         if (*str == 0)
477                 return str;
478
479         for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
480                 c = str [i];
481                 str [i] = str [j];
482                 str [j] = c;
483         }
484
485         return str;
486 }
487
488 gchar *
489 g_strjoin (const gchar *separator, ...)
490 {
491         va_list args;
492         char *res, *s, *r;
493         size_t len, slen;
494
495         if (separator != NULL)
496                 slen = strlen (separator);
497         else
498                 slen = 0;
499         
500         len = 0;
501         va_start (args, separator);
502         for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
503                 len += strlen (s);
504                 len += slen;
505         }
506         va_end (args);
507
508         if (len == 0)
509                 return g_strdup ("");
510         
511         /* Remove the last separator */
512         if (slen > 0 && len > 0)
513                 len -= slen;
514
515         res = g_malloc (len + 1);
516         va_start (args, separator);
517         s = va_arg (args, char *);
518         r = g_stpcpy (res, s);
519         for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
520                 if (separator != NULL)
521                         r = g_stpcpy (r, separator);
522                 r = g_stpcpy (r, s);
523         }
524         va_end (args);
525
526         return res;
527 }
528
529 gchar *
530 g_strjoinv (const gchar *separator, gchar **str_array)
531 {
532         char *res, *r;
533         size_t slen, len, i;
534         
535         if (separator != NULL)
536                 slen = strlen (separator);
537         else
538                 slen = 0;
539         
540         len = 0;
541         for (i = 0; str_array [i] != NULL; i++){
542                 len += strlen (str_array [i]);
543                 len += slen;
544         }
545
546         if (len == 0)
547                 return g_strdup ("");
548
549         if (slen > 0 && len > 0)
550                 len -= slen;
551
552         res = g_malloc (len + 1);
553         r = g_stpcpy (res, str_array [0]);
554         for (i = 1; str_array [i] != NULL; i++){
555                 if (separator != NULL)
556                         r = g_stpcpy (r, separator);
557                 r = g_stpcpy (r, str_array [i]);
558         }
559
560         return res;
561 }
562
563 gchar *
564 g_strchug (gchar *str)
565 {
566         size_t len;
567         gchar *tmp;
568
569         if (str == NULL)
570                 return NULL;
571
572         tmp = str;
573         while (*tmp && isspace (*tmp)) tmp++;
574         if (str != tmp) {
575                 len = strlen (str) - (tmp - str - 1);
576                 memmove (str, tmp, len);
577         }
578         return str;
579 }
580
581 gchar *
582 g_strchomp (gchar *str)
583 {
584         gchar *tmp;
585
586         if (str == NULL)
587                 return NULL;
588
589         tmp = str + strlen (str) - 1;
590         while (*tmp && isspace (*tmp)) tmp--;
591         *(tmp + 1) = '\0';
592         return str;
593 }
594
595 gint
596 g_printf(gchar const *format, ...)
597 {
598         va_list args;
599         gint ret;
600
601         va_start(args, format);
602         ret = vprintf(format, args);
603         va_end(args);
604
605         return ret;
606 }
607
608 gint
609 g_fprintf(FILE *file, gchar const *format, ...)
610 {
611         va_list args;
612         gint ret;
613
614         va_start(args, format);
615         ret = vfprintf(file, format, args);
616         va_end(args);
617
618         return ret;
619 }
620
621 gint
622 g_sprintf(gchar *string, gchar const *format, ...)
623 {
624         va_list args;
625         gint ret;
626
627         va_start(args, format);
628         ret = vsprintf(string, format, args);
629         va_end(args);
630
631         return ret;
632 }
633
634 gint
635 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
636 {
637         va_list args;
638         gint ret;
639         
640         va_start(args, format);
641         ret = vsnprintf(string, n, format, args);
642         va_end(args);
643
644         return ret;
645 }
646
647 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
648                                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
649
650 static gboolean
651 char_needs_encoding (char c)
652 {
653         if (((unsigned char)c) >= 0x80)
654                 return TRUE;
655         
656         if ((c >= '@' && c <= 'Z') ||
657             (c >= 'a' && c <= 'z') ||
658             (c >= '&' && c < 0x3b) ||
659             (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
660                 return FALSE;
661         return TRUE;
662 }
663
664 gchar *
665 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
666 {
667         size_t n;
668         char *ret, *rp;
669         const char *p;
670 #ifdef G_OS_WIN32
671         const char *uriPrefix = "file:///";
672 #else
673         const char *uriPrefix = "file://";
674 #endif
675         
676         g_return_val_if_fail (filename != NULL, NULL);
677
678         if (hostname != NULL)
679                 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
680
681         if (!g_path_is_absolute (filename)){
682                 if (error != NULL)
683                         *error = g_error_new (NULL, 2, "Not an absolute filename");
684                 
685                 return NULL;
686         }
687         
688         n = strlen (uriPrefix) + 1;
689         for (p = filename; *p; p++){
690 #ifdef G_OS_WIN32
691                 if (*p == '\\') {
692                         n++;
693                         continue;
694                 }
695 #endif
696                 if (char_needs_encoding (*p))
697                         n += 3;
698                 else
699                         n++;
700         }
701         ret = g_malloc (n);
702         strcpy (ret, uriPrefix);
703         for (p = filename, rp = ret + strlen (ret); *p; p++){
704 #ifdef G_OS_WIN32
705                 if (*p == '\\') {
706                         *rp++ = '/';
707                         continue;
708                 }
709 #endif
710                 if (char_needs_encoding (*p)){
711                         *rp++ = '%';
712                         *rp++ = hx [((unsigned char)(*p)) >> 4];
713                         *rp++ = hx [((unsigned char)(*p)) & 0xf];
714                 } else
715                         *rp++ = *p;
716         }
717         *rp = 0;
718         return ret;
719 }
720
721 static int
722 decode (char p)
723 {
724         if (p >= '0' && p <= '9')
725                 return p - '0';
726         if (p >= 'A' && p <= 'F')
727                 return p - 'A';
728         if (p >= 'a' && p <= 'f')
729                 return p - 'a';
730         g_assert_not_reached ();
731         return 0;
732 }
733
734 gchar *
735 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
736 {
737         const char *p;
738         char *r, *result;
739         int flen = 0;
740         
741         g_return_val_if_fail (uri != NULL, NULL);
742
743         if (hostname != NULL)
744                 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
745
746         if (strncmp (uri, "file:///", 8) != 0){
747                 if (error != NULL)
748                         *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
749                 return NULL;
750         }
751
752         for (p = uri + 8; *p; p++){
753                 if (*p == '%'){
754                         if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
755                                 p += 2;
756                         } else {
757                                 if (error != NULL)
758                                         *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
759                                 return NULL;
760                         }
761                 } 
762                 flen++;
763         }
764 #ifndef G_OS_WIN32
765         flen++;
766 #endif
767
768         result = g_malloc (flen + 1);
769         result [flen] = 0;
770
771 #ifndef G_OS_WIN32
772         *result = '/';
773         r = result + 1;
774 #else
775         r = result;
776 #endif
777
778         for (p = uri + 8; *p; p++){
779                 if (*p == '%'){
780                         *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
781                         p += 2;
782                 } else
783                         *r++ = *p;
784                 flen++;
785         }
786         return result;
787 }
788
789 void
790 g_strdown (gchar *string)
791 {
792         g_return_if_fail (string != NULL);
793
794         while (*string){
795                 *string = (gchar)tolower (*string);
796                 string++;
797         }
798 }
799
800 gchar
801 g_ascii_tolower (gchar c)
802 {
803         return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
804 }
805
806 gchar *
807 g_ascii_strdown (const gchar *str, gssize len)
808 {
809         char *ret;
810         int i;
811         
812         g_return_val_if_fail  (str != NULL, NULL);
813
814         if (len == -1)
815                 len = strlen (str);
816         
817         ret = g_malloc (len + 1);
818         for (i = 0; i < len; i++)
819                 ret [i] = (guchar) g_ascii_tolower (str [i]);
820         ret [i] = 0;
821         
822         return ret;
823 }
824
825 gchar
826 g_ascii_toupper (gchar c)
827 {
828         return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
829 }
830
831 gchar *
832 g_ascii_strup (const gchar *str, gssize len)
833 {
834         char *ret;
835         int i;
836         
837         g_return_val_if_fail  (str != NULL, NULL);
838
839         if (len == -1)
840                 len = strlen (str);
841         
842         ret = g_malloc (len + 1);
843         for (i = 0; i < len; i++)
844                 ret [i] = (guchar) g_ascii_toupper (str [i]);
845         ret [i] = 0;
846         
847         return ret;
848 }
849
850 gint
851 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
852 {
853         gsize i;
854         
855         g_return_val_if_fail (s1 != NULL, 0);
856         g_return_val_if_fail (s2 != NULL, 0);
857
858         for (i = 0; i < n; i++) {
859                 gchar c1 = g_ascii_tolower (*s1++);
860                 gchar c2 = g_ascii_tolower (*s2++);
861                 
862                 if (c1 != c2)
863                         return c1 - c2;
864         }
865         
866         return 0;
867 }
868
869 gint
870 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
871 {
872         const char *sp1 = s1;
873         const char *sp2 = s2;
874         
875         g_return_val_if_fail (s1 != NULL, 0);
876         g_return_val_if_fail (s2 != NULL, 0);
877         
878         while (*sp1 != '\0') {
879                 char c1 = g_ascii_tolower (*sp1++);
880                 char c2 = g_ascii_tolower (*sp2++);
881                 
882                 if (c1 != c2)
883                         return c1 - c2;
884         }
885         
886         return (*sp1) - (*sp2);
887 }
888
889 gchar *
890 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
891 {
892         gchar *ptr;
893
894         g_return_val_if_fail (string != NULL, NULL);
895
896         if (delimiters == NULL)
897                 delimiters = G_STR_DELIMITERS;
898
899         for (ptr = string; *ptr; ptr++) {
900                 if (strchr (delimiters, *ptr))
901                         *ptr = new_delimiter;
902         }
903         
904         return string;
905 }
906
907 gsize 
908 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
909 {
910 #ifdef HAVE_STRLCPY
911         return strlcpy (dest, src, dest_size);
912 #else
913         gchar *d;
914         const gchar *s;
915         gchar c;
916         gsize len;
917         
918         g_return_val_if_fail (src != NULL, 0);
919         g_return_val_if_fail (dest != NULL, 0);
920
921         len = dest_size;
922         if (len == 0)
923                 return 0;
924
925         s = src;
926         d = dest;
927         while (--len) {
928                 c = *s++;
929                 *d++ = c;
930                 if (c == '\0')
931                         return (dest_size - len - 1);
932         }
933
934         /* len is 0 i we get here */
935         *d = '\0';
936         /* we need to return the length of src here */
937         while (*s++) ; /* instead of a plain strlen, we use 's' */
938         return s - src - 1;
939 #endif
940 }
941
942 gchar *
943 g_stpcpy (gchar *dest, const char *src)
944 {
945         g_return_val_if_fail (dest != NULL, dest);
946         g_return_val_if_fail (src != NULL, dest);
947
948 #if HAVE_STPCPY
949         return stpcpy (dest, src);
950 #else
951         while (*src)
952                 *dest++ = *src++;
953         
954         *dest = '\0';
955         
956         return dest;
957 #endif
958 }
959
960 static const gchar escaped_dflt [256] = {
961         1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
962         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
963         0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
964         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
965         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
966         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
967         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
968         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
969         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
970         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
971         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
972         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
973         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
974         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
975         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
976         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
977 };
978
979 gchar *
980 g_strescape (const gchar *source, const gchar *exceptions)
981 {
982         gchar escaped [256];
983         const gchar *ptr;
984         gchar c;
985         gchar op;
986         gchar *result;
987         gchar *res_ptr;
988
989         g_return_val_if_fail (source != NULL, NULL);
990
991         memcpy (escaped, escaped_dflt, 256);
992         if (exceptions != NULL) {
993                 for (ptr = exceptions; *ptr; ptr++)
994                         escaped [(int) *ptr] = 0;
995         }
996         result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
997         res_ptr = result;
998         for (ptr = source; *ptr; ptr++) {
999                 c = *ptr;
1000                 op = escaped [(int) c];
1001                 if (op == 0) {
1002                         *res_ptr++ = c;
1003                 } else {
1004                         *res_ptr++ = '\\';
1005                         if (op != 1) {
1006                                 *res_ptr++ = op;
1007                         } else {
1008                                 *res_ptr++ = '0' + ((c >> 6) & 3);
1009                                 *res_ptr++ = '0' + ((c >> 3) & 7);
1010                                 *res_ptr++ = '0' + (c & 7);
1011                         }
1012                 }
1013         }
1014         *res_ptr = '\0';
1015         return result;
1016 }
1017
1018 gint
1019 g_ascii_xdigit_value (gchar c)
1020 {
1021         return ((isxdigit (c) == 0) ? -1 :
1022                 ((c >= '0' && c <= '9') ? (c - '0') :
1023                  ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
1024                   (c - 'A' + 10))));
1025 }
1026
1027 gchar *
1028 g_strnfill (gsize length, gchar fill_char)
1029 {
1030         gchar *ret = g_new (gchar, length + 1);
1031
1032         memset (ret, fill_char, length);
1033         ret [length] = 0;
1034         return ret;
1035 }