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