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