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