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