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