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