[mono-api-html] Allow `-r` to ignore class removals
[mono.git] / eglib / src / 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                 int buff_len = sizeof (tmp_buff);
235                 int r;
236                 buff [0] = 0;
237
238                 while ((r = strerror_r (errnum, buff, buff_len - 1))) {
239                         if (r != ERANGE) {
240                                 buff = g_strdup_printf ("Invalid Error code '%d'", errnum);
241                                 break;
242                         }
243                         if (buff == tmp_buff)
244                                 buff = g_malloc (buff_len * 2);
245                         else
246                                 buff = g_realloc (buff, buff_len * 2);
247                         buff_len *= 2;
248                  //Spec is not clean on whether size argument includes space for null terminator or not 
249                 }
250                 if (!error_messages [errnum])
251                         error_messages [errnum] = g_strdup (buff);
252                 if (buff != tmp_buff)
253                         g_free (buff);
254 #else
255                 if (!error_messages [errnum])
256                         error_messages [errnum] = g_strdup_printf ("Error code '%d'", errnum);
257 #endif
258
259
260 #ifndef G_OS_WIN32
261                 pthread_mutex_unlock (&strerror_lock);
262 #endif
263
264         }
265         return error_messages [errnum];
266 }
267
268 gchar *
269 g_strconcat (const gchar *first, ...)
270 {
271         va_list args;
272         size_t total = 0;
273         char *s, *ret;
274         g_return_val_if_fail (first != NULL, NULL);
275
276         total += strlen (first);
277         va_start (args, first);
278         for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
279                 total += strlen (s);
280         }
281         va_end (args);
282         
283         ret = g_malloc (total + 1);
284         if (ret == NULL)
285                 return NULL;
286
287         ret [total] = 0;
288         strcpy (ret, first);
289         va_start (args, first);
290         for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
291                 strcat (ret, s);
292         }
293         va_end (args);
294
295         return ret;
296 }
297
298 static void
299 add_to_vector (gchar ***vector, int size, gchar *token)
300 {
301         *vector = *vector == NULL ? 
302                 (gchar **)g_malloc(2 * sizeof(*vector)) :
303                 (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
304                 
305         (*vector)[size - 1] = token;
306 }
307
308 gchar ** 
309 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
310 {
311         const gchar *c;
312         gchar *token, **vector;
313         gint size = 1;
314         
315         g_return_val_if_fail (string != NULL, NULL);
316         g_return_val_if_fail (delimiter != NULL, NULL);
317         g_return_val_if_fail (delimiter[0] != 0, NULL);
318         
319         if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
320                 vector = (gchar **)g_malloc (2 * sizeof(vector));
321                 vector[0] = g_strdup ("");
322                 size++;
323                 string += strlen (delimiter);
324         } else {
325                 vector = NULL;
326         }
327
328         while (*string && !(max_tokens > 0 && size >= max_tokens)) {
329                 c = string;
330                 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
331                         token = g_strdup ("");
332                         string += strlen (delimiter);
333                 } else {
334                         while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
335                                 string++;
336                         }
337
338                         if (*string) {
339                                 gsize toklen = (string - c);
340                                 token = g_strndup (c, toklen);
341
342                                 /* Need to leave a trailing empty
343                                  * token if the delimiter is the last
344                                  * part of the string
345                                  */
346                                 if (strcmp (string, delimiter) != 0) {
347                                         string += strlen (delimiter);
348                                 }
349                         } else {
350                                 token = g_strdup (c);
351                         }
352                 }
353                         
354                 add_to_vector (&vector, size, token);
355                 size++;
356         }
357
358         if (*string) {
359                 if (strcmp (string, delimiter) == 0)
360                         add_to_vector (&vector, size, g_strdup (""));
361                 else {
362                         /* Add the rest of the string as the last element */
363                         add_to_vector (&vector, size, g_strdup (string));
364                 }
365                 size++;
366         }
367         
368         if (vector == NULL) {
369                 vector = (gchar **) g_malloc (2 * sizeof (vector));
370                 vector [0] = NULL;
371         } else if (size > 0) {
372                 vector[size - 1] = NULL;
373         }
374         
375         return vector;
376 }
377
378 static gboolean
379 charcmp (gchar testchar, const gchar *compare)
380 {
381         while(*compare) {
382                 if (*compare == testchar) {
383                         return TRUE;
384                 }
385                 compare++;
386         }
387         
388         return FALSE;
389 }
390
391 gchar ** 
392 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
393 {
394         const gchar *c;
395         gchar *token, **vector;
396         gint size = 1;
397         
398         g_return_val_if_fail (string != NULL, NULL);
399         g_return_val_if_fail (delimiter != NULL, NULL);
400         g_return_val_if_fail (delimiter[0] != 0, NULL);
401         
402         if (charcmp (*string, delimiter)) {
403                 vector = (gchar **)g_malloc (2 * sizeof(vector));
404                 vector[0] = g_strdup ("");
405                 size++;
406                 string++;
407         } else {
408                 vector = NULL;
409         }
410
411         c = string;
412         while (*string && !(max_tokens > 0 && size >= max_tokens)) {
413                 if (charcmp (*string, delimiter)) {
414                         gsize toklen = (string - c);
415                         if (toklen == 0) {
416                                 token = g_strdup ("");
417                         } else {
418                                 token = g_strndup (c, toklen);
419                         }
420                         
421                         c = string + 1;
422                         
423                         add_to_vector (&vector, size, token);
424                         size++;
425                 }
426
427                 string++;
428         }
429         
430         if (max_tokens > 0 && size >= max_tokens) {
431                 if (*string) {
432                         /* Add the rest of the string as the last element */
433                         add_to_vector (&vector, size, g_strdup (string));
434                         size++;
435                 }
436         } else {
437                 if (*c) {
438                         /* Fill in the trailing last token */
439                         add_to_vector (&vector, size, g_strdup (c));
440                         size++;
441                 } else {
442                         /* Need to leave a trailing empty token if the
443                          * delimiter is the last part of the string
444                          */
445                         add_to_vector (&vector, size, g_strdup (""));
446                         size++;
447                 }
448         }
449         
450         if (vector == NULL) {
451                 vector = (gchar **) g_malloc (2 * sizeof (vector));
452                 vector [0] = NULL;
453         } else if (size > 0) {
454                 vector[size - 1] = NULL;
455         }
456         
457         return vector;
458 }
459
460 gchar *
461 g_strreverse (gchar *str)
462 {
463         size_t i, j;
464         gchar c;
465
466         if (str == NULL)
467                 return NULL;
468
469         if (*str == 0)
470                 return str;
471
472         for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
473                 c = str [i];
474                 str [i] = str [j];
475                 str [j] = c;
476         }
477
478         return str;
479 }
480
481 gchar *
482 g_strjoin (const gchar *separator, ...)
483 {
484         va_list args;
485         char *res, *s, *r;
486         size_t len, slen;
487
488         if (separator != NULL)
489                 slen = strlen (separator);
490         else
491                 slen = 0;
492         
493         len = 0;
494         va_start (args, separator);
495         for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
496                 len += strlen (s);
497                 len += slen;
498         }
499         va_end (args);
500
501         if (len == 0)
502                 return g_strdup ("");
503         
504         /* Remove the last separator */
505         if (slen > 0 && len > 0)
506                 len -= slen;
507
508         res = g_malloc (len + 1);
509         va_start (args, separator);
510         s = va_arg (args, char *);
511         r = g_stpcpy (res, s);
512         for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
513                 if (separator != NULL)
514                         r = g_stpcpy (r, separator);
515                 r = g_stpcpy (r, s);
516         }
517         va_end (args);
518
519         return res;
520 }
521
522 gchar *
523 g_strjoinv (const gchar *separator, gchar **str_array)
524 {
525         char *res, *r;
526         size_t slen, len, i;
527         
528         if (separator != NULL)
529                 slen = strlen (separator);
530         else
531                 slen = 0;
532         
533         len = 0;
534         for (i = 0; str_array [i] != NULL; i++){
535                 len += strlen (str_array [i]);
536                 len += slen;
537         }
538
539         if (len == 0)
540                 return g_strdup ("");
541
542         if (slen > 0 && len > 0)
543                 len -= slen;
544
545         res = g_malloc (len + 1);
546         r = g_stpcpy (res, str_array [0]);
547         for (i = 1; str_array [i] != NULL; i++){
548                 if (separator != NULL)
549                         r = g_stpcpy (r, separator);
550                 r = g_stpcpy (r, str_array [i]);
551         }
552
553         return res;
554 }
555
556 gchar *
557 g_strchug (gchar *str)
558 {
559         size_t len;
560         gchar *tmp;
561
562         if (str == NULL)
563                 return NULL;
564
565         tmp = str;
566         while (*tmp && isspace (*tmp)) tmp++;
567         if (str != tmp) {
568                 len = strlen (str) - (tmp - str - 1);
569                 memmove (str, tmp, len);
570         }
571         return str;
572 }
573
574 gchar *
575 g_strchomp (gchar *str)
576 {
577         gchar *tmp;
578
579         if (str == NULL)
580                 return NULL;
581
582         tmp = str + strlen (str) - 1;
583         while (*tmp && isspace (*tmp)) tmp--;
584         *(tmp + 1) = '\0';
585         return str;
586 }
587
588 gint
589 g_printf(gchar const *format, ...)
590 {
591         va_list args;
592         gint ret;
593
594         va_start(args, format);
595         ret = vprintf(format, args);
596         va_end(args);
597
598         return ret;
599 }
600
601 gint
602 g_fprintf(FILE *file, gchar const *format, ...)
603 {
604         va_list args;
605         gint ret;
606
607         va_start(args, format);
608         ret = vfprintf(file, format, args);
609         va_end(args);
610
611         return ret;
612 }
613
614 gint
615 g_sprintf(gchar *string, gchar const *format, ...)
616 {
617         va_list args;
618         gint ret;
619
620         va_start(args, format);
621         ret = vsprintf(string, format, args);
622         va_end(args);
623
624         return ret;
625 }
626
627 gint
628 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
629 {
630         va_list args;
631         gint ret;
632         
633         va_start(args, format);
634         ret = vsnprintf(string, n, format, args);
635         va_end(args);
636
637         return ret;
638 }
639
640 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
641                                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
642
643 static gboolean
644 char_needs_encoding (char c)
645 {
646         if (((unsigned char)c) >= 0x80)
647                 return TRUE;
648         
649         if ((c >= '@' && c <= 'Z') ||
650             (c >= 'a' && c <= 'z') ||
651             (c >= '&' && c < 0x3b) ||
652             (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
653                 return FALSE;
654         return TRUE;
655 }
656
657 gchar *
658 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
659 {
660         size_t n;
661         char *ret, *rp;
662         const char *p;
663 #ifdef G_OS_WIN32
664         const char *uriPrefix = "file:///";
665 #else
666         const char *uriPrefix = "file://";
667 #endif
668         
669         g_return_val_if_fail (filename != NULL, NULL);
670
671         if (hostname != NULL)
672                 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
673
674         if (!g_path_is_absolute (filename)){
675                 if (error != NULL)
676                         *error = g_error_new (NULL, 2, "Not an absolute filename");
677                 
678                 return NULL;
679         }
680         
681         n = strlen (uriPrefix) + 1;
682         for (p = filename; *p; p++){
683 #ifdef G_OS_WIN32
684                 if (*p == '\\') {
685                         n++;
686                         continue;
687                 }
688 #endif
689                 if (char_needs_encoding (*p))
690                         n += 3;
691                 else
692                         n++;
693         }
694         ret = g_malloc (n);
695         strcpy (ret, uriPrefix);
696         for (p = filename, rp = ret + strlen (ret); *p; p++){
697 #ifdef G_OS_WIN32
698                 if (*p == '\\') {
699                         *rp++ = '/';
700                         continue;
701                 }
702 #endif
703                 if (char_needs_encoding (*p)){
704                         *rp++ = '%';
705                         *rp++ = hx [((unsigned char)(*p)) >> 4];
706                         *rp++ = hx [((unsigned char)(*p)) & 0xf];
707                 } else
708                         *rp++ = *p;
709         }
710         *rp = 0;
711         return ret;
712 }
713
714 static int
715 decode (char p)
716 {
717         if (p >= '0' && p <= '9')
718                 return p - '0';
719         if (p >= 'A' && p <= 'F')
720                 return p - 'A';
721         if (p >= 'a' && p <= 'f')
722                 return p - 'a';
723         g_assert_not_reached ();
724         return 0;
725 }
726
727 gchar *
728 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
729 {
730         const char *p;
731         char *r, *result;
732         int flen = 0;
733         
734         g_return_val_if_fail (uri != NULL, NULL);
735
736         if (hostname != NULL)
737                 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
738
739         if (strncmp (uri, "file:///", 8) != 0){
740                 if (error != NULL)
741                         *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
742                 return NULL;
743         }
744
745         for (p = uri + 8; *p; p++){
746                 if (*p == '%'){
747                         if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
748                                 p += 2;
749                         } else {
750                                 if (error != NULL)
751                                         *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
752                                 return NULL;
753                         }
754                 } 
755                 flen++;
756         }
757 #ifndef G_OS_WIN32
758         flen++;
759 #endif
760
761         result = g_malloc (flen + 1);
762         result [flen] = 0;
763
764 #ifndef G_OS_WIN32
765         *result = '/';
766         r = result + 1;
767 #else
768         r = result;
769 #endif
770
771         for (p = uri + 8; *p; p++){
772                 if (*p == '%'){
773                         *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
774                         p += 2;
775                 } else
776                         *r++ = *p;
777                 flen++;
778         }
779         return result;
780 }
781
782 void
783 g_strdown (gchar *string)
784 {
785         g_return_if_fail (string != NULL);
786
787         while (*string){
788                 *string = (gchar)tolower (*string);
789                 string++;
790         }
791 }
792
793 gchar
794 g_ascii_tolower (gchar c)
795 {
796         return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
797 }
798
799 gchar *
800 g_ascii_strdown (const gchar *str, gssize len)
801 {
802         char *ret;
803         int i;
804         
805         g_return_val_if_fail  (str != NULL, NULL);
806
807         if (len == -1)
808                 len = strlen (str);
809         
810         ret = g_malloc (len + 1);
811         for (i = 0; i < len; i++)
812                 ret [i] = (guchar) g_ascii_tolower (str [i]);
813         ret [i] = 0;
814         
815         return ret;
816 }
817
818 gchar
819 g_ascii_toupper (gchar c)
820 {
821         return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
822 }
823
824 gchar *
825 g_ascii_strup (const gchar *str, gssize len)
826 {
827         char *ret;
828         int i;
829         
830         g_return_val_if_fail  (str != NULL, NULL);
831
832         if (len == -1)
833                 len = strlen (str);
834         
835         ret = g_malloc (len + 1);
836         for (i = 0; i < len; i++)
837                 ret [i] = (guchar) g_ascii_toupper (str [i]);
838         ret [i] = 0;
839         
840         return ret;
841 }
842
843 gint
844 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
845 {
846         gsize i;
847         
848         g_return_val_if_fail (s1 != NULL, 0);
849         g_return_val_if_fail (s2 != NULL, 0);
850
851         for (i = 0; i < n; i++) {
852                 gchar c1 = g_ascii_tolower (*s1++);
853                 gchar c2 = g_ascii_tolower (*s2++);
854                 
855                 if (c1 != c2)
856                         return c1 - c2;
857         }
858         
859         return 0;
860 }
861
862 gint
863 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
864 {
865         const char *sp1 = s1;
866         const char *sp2 = s2;
867         
868         g_return_val_if_fail (s1 != NULL, 0);
869         g_return_val_if_fail (s2 != NULL, 0);
870         
871         while (*sp1 != '\0') {
872                 char c1 = g_ascii_tolower (*sp1++);
873                 char c2 = g_ascii_tolower (*sp2++);
874                 
875                 if (c1 != c2)
876                         return c1 - c2;
877         }
878         
879         return (*sp1) - (*sp2);
880 }
881
882 gchar *
883 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
884 {
885         gchar *ptr;
886
887         g_return_val_if_fail (string != NULL, NULL);
888
889         if (delimiters == NULL)
890                 delimiters = G_STR_DELIMITERS;
891
892         for (ptr = string; *ptr; ptr++) {
893                 if (strchr (delimiters, *ptr))
894                         *ptr = new_delimiter;
895         }
896         
897         return string;
898 }
899
900 gsize 
901 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
902 {
903 #ifdef HAVE_STRLCPY
904         return strlcpy (dest, src, dest_size);
905 #else
906         gchar *d;
907         const gchar *s;
908         gchar c;
909         gsize len;
910         
911         g_return_val_if_fail (src != NULL, 0);
912         g_return_val_if_fail (dest != NULL, 0);
913
914         len = dest_size;
915         if (len == 0)
916                 return 0;
917
918         s = src;
919         d = dest;
920         while (--len) {
921                 c = *s++;
922                 *d++ = c;
923                 if (c == '\0')
924                         return (dest_size - len - 1);
925         }
926
927         /* len is 0 i we get here */
928         *d = '\0';
929         /* we need to return the length of src here */
930         while (*s++) ; /* instead of a plain strlen, we use 's' */
931         return s - src - 1;
932 #endif
933 }
934
935 gchar *
936 g_stpcpy (gchar *dest, const char *src)
937 {
938         g_return_val_if_fail (dest != NULL, dest);
939         g_return_val_if_fail (src != NULL, dest);
940
941 #if HAVE_STPCPY
942         return stpcpy (dest, src);
943 #else
944         while (*src)
945                 *dest++ = *src++;
946         
947         *dest = '\0';
948         
949         return dest;
950 #endif
951 }
952
953 static const gchar escaped_dflt [256] = {
954         1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
955         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
956         0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
957         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
958         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
959         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
960         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
961         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
962         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
963         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
964         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
965         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
966         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
967         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
968         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
969         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
970 };
971
972 gchar *
973 g_strescape (const gchar *source, const gchar *exceptions)
974 {
975         gchar escaped [256];
976         const gchar *ptr;
977         gchar c;
978         gchar op;
979         gchar *result;
980         gchar *res_ptr;
981
982         g_return_val_if_fail (source != NULL, NULL);
983
984         memcpy (escaped, escaped_dflt, 256);
985         if (exceptions != NULL) {
986                 for (ptr = exceptions; *ptr; ptr++)
987                         escaped [(int) *ptr] = 0;
988         }
989         result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
990         res_ptr = result;
991         for (ptr = source; *ptr; ptr++) {
992                 c = *ptr;
993                 op = escaped [(int) c];
994                 if (op == 0) {
995                         *res_ptr++ = c;
996                 } else {
997                         *res_ptr++ = '\\';
998                         if (op != 1) {
999                                 *res_ptr++ = op;
1000                         } else {
1001                                 *res_ptr++ = '0' + ((c >> 6) & 3);
1002                                 *res_ptr++ = '0' + ((c >> 3) & 7);
1003                                 *res_ptr++ = '0' + (c & 7);
1004                         }
1005                 }
1006         }
1007         *res_ptr = '\0';
1008         return result;
1009 }
1010
1011 gint
1012 g_ascii_xdigit_value (gchar c)
1013 {
1014         return ((isxdigit (c) == 0) ? -1 :
1015                 ((c >= '0' && c <= '9') ? (c - '0') :
1016                  ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
1017                   (c - 'A' + 10))));
1018 }
1019
1020 gchar *
1021 g_strnfill (gsize length, gchar fill_char)
1022 {
1023         gchar *ret = g_new (gchar, length + 1);
1024
1025         memset (ret, fill_char, length);
1026         ret [length] = 0;
1027         return ret;
1028 }