41ee60753b61608867877543d2b8d209545614b1
[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         for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
361                 c = str [i];
362                 str [i] = str [j];
363                 str [j] = c;
364         }
365
366         return str;
367 }
368
369 gchar *
370 g_strjoin (const gchar *separator, ...)
371 {
372         va_list args;
373         char *res, *s, *r;
374         size_t len, slen;
375
376         if (separator != NULL)
377                 slen = strlen (separator);
378         else
379                 slen = 0;
380         
381         len = 0;
382         va_start (args, separator);
383         for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
384                 len += strlen (s);
385                 len += slen;
386         }
387         va_end (args);
388
389         if (len == 0)
390                 return g_strdup ("");
391         
392         /* Remove the last separator */
393         if (slen > 0 && len > 0)
394                 len -= slen;
395
396         r = res = g_malloc (len + 1);
397         va_start (args, separator);
398         for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
399                 if (separator != NULL)
400                         r = g_stpcpy (r, separator);
401                 r = g_stpcpy (r, s);
402         }
403         va_end (args);
404
405         return res;
406 }
407
408 gchar *
409 g_strjoinv (const gchar *separator, gchar **str_array)
410 {
411         char *res, *r;
412         size_t slen, len, i;
413         
414         if (separator != NULL)
415                 slen = strlen (separator);
416         else
417                 slen = 0;
418         
419         len = 0;
420         for (i = 0; str_array [i] != NULL; i++){
421                 len += strlen (str_array [i]);
422                 len += slen;
423         }
424
425         if (len == 0)
426                 return g_strdup ("");
427
428         if (slen > 0 && len > 0)
429                 len -= slen;
430
431         r = res = g_malloc (len + 1);
432         for (i = 0; str_array [i] != NULL; i++){
433                 if (separator != NULL)
434                         r = g_stpcpy (r, separator);
435                 r = g_stpcpy (r, str_array [i]);
436         }
437
438         return res;
439 }
440
441 gchar *
442 g_strchug (gchar *str)
443 {
444         size_t len;
445         gchar *tmp;
446
447         if (str == NULL)
448                 return NULL;
449
450         tmp = str;
451         while (*tmp && isspace (*tmp)) tmp++;
452         if (str != tmp) {
453                 len = strlen (str) - (tmp - str - 1);
454                 memmove (str, tmp, len);
455         }
456         return str;
457 }
458
459 gchar *
460 g_strchomp (gchar *str)
461 {
462         gchar *tmp;
463
464         if (str == NULL)
465                 return NULL;
466
467         tmp = str + strlen (str) - 1;
468         while (*tmp && isspace (*tmp)) tmp--;
469         *(tmp + 1) = '\0';
470         return str;
471 }
472
473 gint
474 g_printf(gchar const *format, ...)
475 {
476         va_list args;
477         gint ret;
478
479         va_start(args, format);
480         ret = vprintf(format, args);
481         va_end(args);
482
483         return ret;
484 }
485
486 gint
487 g_fprintf(FILE *file, gchar const *format, ...)
488 {
489         va_list args;
490         gint ret;
491
492         va_start(args, format);
493         ret = vfprintf(file, format, args);
494         va_end(args);
495
496         return ret;
497 }
498
499 gint
500 g_sprintf(gchar *string, gchar const *format, ...)
501 {
502         va_list args;
503         gint ret;
504
505         va_start(args, format);
506         ret = vsprintf(string, format, args);
507         va_end(args);
508
509         return ret;
510 }
511
512 gint
513 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
514 {
515         va_list args;
516         gint ret;
517         
518         va_start(args, format);
519         ret = vsnprintf(string, n, format, args);
520         va_end(args);
521
522         return ret;
523 }
524
525 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
526                                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
527
528 static gboolean
529 char_needs_encoding (char c)
530 {
531         if (((unsigned char)c) >= 0x80)
532                 return TRUE;
533         
534         if ((c >= '@' && c <= 'Z') ||
535             (c >= 'a' && c <= 'z') ||
536             (c >= '&' && c < 0x3b) ||
537             (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
538                 return FALSE;
539         return TRUE;
540 }
541
542 gchar *
543 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **error)
544 {
545         size_t n;
546         char *ret, *rp;
547         const char *p;
548 #ifdef G_OS_WIN32
549         const char *uriPrefix = "file:///";
550 #else
551         const char *uriPrefix = "file://";
552 #endif
553         
554         g_return_val_if_fail (filename != NULL, NULL);
555
556         if (hostname != NULL)
557                 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
558
559         if (!g_path_is_absolute (filename)){
560                 if (error != NULL)
561                         *error = g_error_new (NULL, 2, "Not an absolute filename");
562                 
563                 return NULL;
564         }
565         
566         n = strlen (uriPrefix) + 1;
567         for (p = filename; *p; p++){
568 #ifdef G_OS_WIN32
569                 if (*p == '\\') {
570                         n++;
571                         continue;
572                 }
573 #endif
574                 if (char_needs_encoding (*p))
575                         n += 3;
576                 else
577                         n++;
578         }
579         ret = g_malloc (n);
580         strcpy (ret, uriPrefix);
581         for (p = filename, rp = ret + strlen (ret); *p; p++){
582 #ifdef G_OS_WIN32
583                 if (*p == '\\') {
584                         *rp++ = '/';
585                         continue;
586                 }
587 #endif
588                 if (char_needs_encoding (*p)){
589                         *rp++ = '%';
590                         *rp++ = hx [((unsigned char)(*p)) >> 4];
591                         *rp++ = hx [((unsigned char)(*p)) & 0xf];
592                 } else
593                         *rp++ = *p;
594         }
595         *rp = 0;
596         return ret;
597 }
598
599 static int
600 decode (char p)
601 {
602         if (p >= '0' && p <= '9')
603                 return p - '0';
604         if (p >= 'A' && p <= 'F')
605                 return p - 'A';
606         if (p >= 'a' && p <= 'f')
607                 return p - 'a';
608         g_assert_not_reached ();
609         return 0;
610 }
611
612 gchar *
613 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **error)
614 {
615         const char *p;
616         char *r, *result;
617         int flen = 0;
618         
619         g_return_val_if_fail (uri != NULL, NULL);
620
621         if (hostname != NULL)
622                 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
623
624         if (strncmp (uri, "file:///", 8) != 0){
625                 if (error != NULL)
626                         *error = g_error_new (NULL, 2, "URI does not start with the file: scheme");
627                 return NULL;
628         }
629
630         for (p = uri + 8; *p; p++){
631                 if (*p == '%'){
632                         if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
633                                 p += 2;
634                         } else {
635                                 if (error != NULL)
636                                         *error = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
637                                 return NULL;
638                         }
639                 } 
640                 flen++;
641         }
642 #ifndef G_OS_WIN32
643         flen++;
644 #endif
645
646         result = g_malloc (flen + 1);
647         result [flen] = 0;
648
649 #ifndef G_OS_WIN32
650         *result = '/';
651         r = result + 1;
652 #else
653         r = result;
654 #endif
655
656         for (p = uri + 8; *p; p++){
657                 if (*p == '%'){
658                         *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
659                         p += 2;
660                 } else
661                         *r++ = *p;
662                 flen++;
663         }
664         return result;
665 }
666
667 void
668 g_strdown (gchar *string)
669 {
670         g_return_if_fail (string != NULL);
671
672         while (*string){
673                 *string = (gchar)tolower (*string);
674                 string++;
675         }
676 }
677
678 gchar
679 g_ascii_tolower (gchar c)
680 {
681         return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
682 }
683
684 gchar *
685 g_ascii_strdown (const gchar *str, gssize len)
686 {
687         char *ret;
688         int i;
689         
690         g_return_val_if_fail  (str != NULL, NULL);
691
692         if (len == -1)
693                 len = strlen (str);
694         
695         ret = g_malloc (len + 1);
696         for (i = 0; i < len; i++)
697                 ret [i] = (guchar) g_ascii_tolower (str [i]);
698         ret [i] = 0;
699         
700         return ret;
701 }
702
703 gint
704 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
705 {
706         gsize i;
707         
708         g_return_val_if_fail (s1 != NULL, 0);
709         g_return_val_if_fail (s2 != NULL, 0);
710
711         for (i = 0; i < n; i++){
712                 gchar c1 = g_ascii_tolower (*s1++);
713                 gchar c2 = g_ascii_tolower (*s2++);
714                 
715                 if (c1 == c2)
716                         continue;
717                 
718                 if (c1 == 0)
719                         return -1;
720                 if (c2 == 0)
721                         return 1;
722                 return c1-c2;
723         }
724         return 0;
725 }
726
727 gchar *
728 g_strdelimit (gchar *string, const gchar *delimiters, gchar new_delimiter)
729 {
730         gchar *ptr;
731
732         g_return_val_if_fail (string != NULL, NULL);
733
734         if (delimiters == NULL)
735                 delimiters = G_STR_DELIMITERS;
736
737         for (ptr = string; *ptr; ptr++) {
738                 if (strchr (delimiters, *ptr))
739                         *ptr = new_delimiter;
740         }
741         
742         return string;
743 }
744
745 gsize 
746 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
747 {
748 #ifdef HAVE_STRLCPY
749         return strlcpy (dest, src, dest_size);
750 #else
751         gchar *d;
752         const gchar *s;
753         gchar c;
754         gsize len;
755         
756         g_return_val_if_fail (src != NULL, 0);
757         g_return_val_if_fail (dest != NULL, 0);
758
759         len = dest_size;
760         if (len == 0)
761                 return 0;
762
763         s = src;
764         d = dest;
765         while (--len) {
766                 c = *s++;
767                 *d++ = c;
768                 if (c == '\0')
769                         return (dest_size - len - 1);
770         }
771
772         /* len is 0 i we get here */
773         *d = '\0';
774         /* we need to return the length of src here */
775         while (*s++) ; /* instead of a plain strlen, we use 's' */
776         return s - src - 1;
777 #endif
778 }
779
780 gchar *
781 g_stpcpy (gchar *dest, const char *src)
782 {
783         g_return_val_if_fail (dest != NULL, dest);
784         g_return_val_if_fail (src != NULL, dest);
785
786 #if HAVE_STPCPY
787         return stpcpy (dest, src);
788 #else
789         strcpy (dest, src);
790         return dest + strlen (src);
791 #endif
792 }
793
794 static const gchar escaped_dflt [256] = {
795         1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
796         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
797         0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
798         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
799         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
800         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
801         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
802         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
803         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
804         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
805         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
806         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
807         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
808         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
809         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
810         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
811 };
812
813 gchar *
814 g_strescape (const gchar *source, const gchar *exceptions)
815 {
816         gchar escaped [256];
817         const gchar *ptr;
818         gchar c;
819         gchar op;
820         gchar *result;
821         gchar *res_ptr;
822
823         g_return_val_if_fail (source != NULL, NULL);
824
825         memcpy (escaped, escaped_dflt, 256);
826         if (exceptions != NULL) {
827                 for (ptr = exceptions; *ptr; ptr++)
828                         escaped [(int) *ptr] = 0;
829         }
830         result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
831         res_ptr = result;
832         for (ptr = source; *ptr; ptr++) {
833                 c = *ptr;
834                 op = escaped [(int) c];
835                 if (op == 0) {
836                         *res_ptr++ = c;
837                 } else {
838                         *res_ptr++ = '\\';
839                         if (op != 1) {
840                                 *res_ptr++ = op;
841                         } else {
842                                 *res_ptr++ = '0' + ((c >> 6) & 3);
843                                 *res_ptr++ = '0' + ((c >> 3) & 7);
844                                 *res_ptr++ = '0' + (c & 7);
845                         }
846                 }
847         }
848         *res_ptr = '\0';
849         return result;
850 }
851
852 gint
853 g_ascii_xdigit_value (gchar c)
854 {
855         return ((isxdigit (c) == 0) ? -1 :
856                 ((c >= '0' && c <= '9') ? (c - '0') :
857                  ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
858                   (c - 'A' + 10))));
859 }
860
861 gchar *
862 g_strnfill (gsize length, gchar fill_char)
863 {
864         gchar *ret = g_new (gchar, length + 1);
865
866         memset (ret, fill_char, length);
867         ret [length] = 0;
868         return ret;
869 }