• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 2006-2019 Free Software Foundation, Inc.
3  *
4  * This file is not part of the GNU gettext program, but is used with
5  * GNU gettext.
6  *
7  * The original copyright notice is as follows:
8  */
9 
10 /* GLIB - Library of useful routines for C programming
11  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the
25  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26  * Boston, MA 02111-1307, USA.
27  */
28 
29 /*
30  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
31  * file for a list of people on the GLib Team.  See the ChangeLog
32  * files for a list of changes.  These files are distributed with
33  * GLib at ftp://ftp.gtk.org/pub/gtk/.
34  */
35 
36 /*
37  * Modified by Bruno Haible for use as a gnulib module.
38  */
39 
40 /*
41  * MT safe
42  */
43 
44 #include "config.h"
45 
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #include <stdarg.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <ctype.h>
54 
55 #include "glib.h"
56 #if 0
57 #include "gprintf.h"
58 
59 #include "galias.h"
60 
61 struct _GStringChunk
62 {
63   GHashTable *const_table;
64   GSList     *storage_list;
65   gsize       storage_next;
66   gsize       this_size;
67   gsize       default_size;
68 };
69 #endif
70 
71 /* Hash Functions.
72  */
73 
74 /**
75  * g_str_equal:
76  * @v1: a key.
77  * @v2: a key to compare with @v1.
78  *
79  * Compares two strings and returns %TRUE if they are equal.
80  * It can be passed to g_hash_table_new() as the @key_equal_func
81  * parameter, when using strings as keys in a #GHashTable.
82  *
83  * Returns: %TRUE if the two keys match.
84  */
85 gboolean
g_str_equal(gconstpointer v1,gconstpointer v2)86 g_str_equal (gconstpointer v1,
87 	     gconstpointer v2)
88 {
89   const gchar *string1 = v1;
90   const gchar *string2 = v2;
91 
92   return strcmp (string1, string2) == 0;
93 }
94 
95 /**
96  * g_str_hash:
97  * @v: a string key.
98  *
99  * Converts a string to a hash value.
100  * It can be passed to g_hash_table_new() as the @hash_func parameter,
101  * when using strings as keys in a #GHashTable.
102  *
103  * Returns: a hash value corresponding to the key.
104  */
105 guint
g_str_hash(gconstpointer v)106 g_str_hash (gconstpointer v)
107 {
108   /* 31 bit hash function */
109   const signed char *p = v;
110   guint32 h = *p;
111 
112   if (h)
113     for (p += 1; *p != '\0'; p++)
114       h = (h << 5) - h + *p;
115 
116   return h;
117 }
118 
119 #define MY_MAXSIZE ((gsize)-1)
120 
121 static inline gsize
nearest_power(gsize base,gsize num)122 nearest_power (gsize base, gsize num)
123 {
124   if (num > MY_MAXSIZE / 2)
125     {
126       return MY_MAXSIZE;
127     }
128   else
129     {
130       gsize n = base;
131 
132       while (n < num)
133 	n <<= 1;
134 
135       return n;
136     }
137 }
138 
139 #if 0
140 
141 /* String Chunks.
142  */
143 
144 GStringChunk*
145 g_string_chunk_new (gsize default_size)
146 {
147   GStringChunk *new_chunk = g_new (GStringChunk, 1);
148   gsize size = 1;
149 
150   size = nearest_power (1, default_size);
151 
152   new_chunk->const_table       = NULL;
153   new_chunk->storage_list      = NULL;
154   new_chunk->storage_next      = size;
155   new_chunk->default_size      = size;
156   new_chunk->this_size         = size;
157 
158   return new_chunk;
159 }
160 
161 void
162 g_string_chunk_free (GStringChunk *chunk)
163 {
164   GSList *tmp_list;
165 
166   g_return_if_fail (chunk != NULL);
167 
168   if (chunk->storage_list)
169     {
170       for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
171 	g_free (tmp_list->data);
172 
173       g_slist_free (chunk->storage_list);
174     }
175 
176   if (chunk->const_table)
177     g_hash_table_destroy (chunk->const_table);
178 
179   g_free (chunk);
180 }
181 
182 gchar*
183 g_string_chunk_insert (GStringChunk *chunk,
184 		       const gchar  *string)
185 {
186   g_return_val_if_fail (chunk != NULL, NULL);
187 
188   return g_string_chunk_insert_len (chunk, string, -1);
189 }
190 
191 gchar*
192 g_string_chunk_insert_const (GStringChunk *chunk,
193 			     const gchar  *string)
194 {
195   char* lookup;
196 
197   g_return_val_if_fail (chunk != NULL, NULL);
198 
199   if (!chunk->const_table)
200     chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
201 
202   lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
203 
204   if (!lookup)
205     {
206       lookup = g_string_chunk_insert (chunk, string);
207       g_hash_table_insert (chunk->const_table, lookup, lookup);
208     }
209 
210   return lookup;
211 }
212 
213 /**
214  * g_string_chunk_insert_len:
215  * @chunk: a #GStringChunk
216  * @string: bytes to insert
217  * @len: number of bytes of @string to insert, or -1 to insert a
218  *     nul-terminated string.
219  *
220  * Adds a copy of the first @len bytes of @string to the #GStringChunk. The
221  * copy is nul-terminated.
222  *
223  * The characters in the string can be changed, if necessary, though you
224  * should not change anything after the end of the string.
225  *
226  * Return value: a pointer to the copy of @string within the #GStringChunk
227  *
228  * Since: 2.4
229  **/
230 gchar*
231 g_string_chunk_insert_len (GStringChunk *chunk,
232 			   const gchar  *string,
233 			   gssize        len)
234 {
235   gssize size;
236   gchar* pos;
237 
238   g_return_val_if_fail (chunk != NULL, NULL);
239 
240   if (len < 0)
241     size = strlen (string);
242   else
243     size = len;
244 
245   if ((chunk->storage_next + size + 1) > chunk->this_size)
246     {
247       gsize new_size = nearest_power (chunk->default_size, size + 1);
248 
249       chunk->storage_list = g_slist_prepend (chunk->storage_list,
250 					     g_new (gchar, new_size));
251 
252       chunk->this_size = new_size;
253       chunk->storage_next = 0;
254     }
255 
256   pos = ((gchar *) chunk->storage_list->data) + chunk->storage_next;
257 
258   *(pos + size) = '\0';
259 
260   strncpy (pos, string, size);
261   if (len > 0)
262     size = strlen (pos);
263 
264   chunk->storage_next += size + 1;
265 
266   return pos;
267 }
268 
269 #endif
270 
271 /* Strings.
272  */
273 static void
g_string_maybe_expand(GString * string,gsize len)274 g_string_maybe_expand (GString* string,
275 		       gsize    len)
276 {
277   if (string->len + len >= string->allocated_len)
278     {
279       string->allocated_len = nearest_power (1, string->len + len + 1);
280       string->str = g_realloc (string->str, string->allocated_len);
281     }
282 }
283 
284 GString*
g_string_sized_new(gsize dfl_size)285 g_string_sized_new (gsize dfl_size)
286 {
287   GString *string = g_slice_new (GString);
288 
289   string->allocated_len = 0;
290   string->len   = 0;
291   string->str   = NULL;
292 
293   g_string_maybe_expand (string, MAX (dfl_size, 2));
294   string->str[0] = 0;
295 
296   return string;
297 }
298 
299 GString*
g_string_new(const gchar * init)300 g_string_new (const gchar *init)
301 {
302   GString *string;
303 
304   if (init == NULL || *init == '\0')
305     string = g_string_sized_new (2);
306   else
307     {
308       gint len;
309 
310       len = strlen (init);
311       string = g_string_sized_new (len + 2);
312 
313       g_string_append_len (string, init, len);
314     }
315 
316   return string;
317 }
318 
319 GString*
g_string_new_len(const gchar * init,gssize len)320 g_string_new_len (const gchar *init,
321                   gssize       len)
322 {
323   GString *string;
324 
325   if (len < 0)
326     return g_string_new (init);
327   else
328     {
329       string = g_string_sized_new (len);
330 
331       if (init)
332         g_string_append_len (string, init, len);
333 
334       return string;
335     }
336 }
337 
338 gchar*
g_string_free(GString * string,gboolean free_segment)339 g_string_free (GString *string,
340 	       gboolean free_segment)
341 {
342   gchar *segment;
343 
344   g_return_val_if_fail (string != NULL, NULL);
345 
346   if (free_segment)
347     {
348       g_free (string->str);
349       segment = NULL;
350     }
351   else
352     segment = string->str;
353 
354   g_slice_free (GString, string);
355 
356   return segment;
357 }
358 
359 #if 0
360 
361 gboolean
362 g_string_equal (const GString *v,
363                 const GString *v2)
364 {
365   gchar *p, *q;
366   GString *string1 = (GString *) v;
367   GString *string2 = (GString *) v2;
368   gsize i = string1->len;
369 
370   if (i != string2->len)
371     return FALSE;
372 
373   p = string1->str;
374   q = string2->str;
375   while (i)
376     {
377       if (*p != *q)
378 	return FALSE;
379       p++;
380       q++;
381       i--;
382     }
383   return TRUE;
384 }
385 
386 /* 31 bit hash function */
387 guint
388 g_string_hash (const GString *str)
389 {
390   const gchar *p = str->str;
391   gsize n = str->len;
392   guint h = 0;
393 
394   while (n--)
395     {
396       h = (h << 5) - h + *p;
397       p++;
398     }
399 
400   return h;
401 }
402 
403 GString*
404 g_string_assign (GString     *string,
405 		 const gchar *rval)
406 {
407   g_return_val_if_fail (string != NULL, NULL);
408   g_return_val_if_fail (rval != NULL, string);
409 
410   /* Make sure assigning to itself doesn't corrupt the string.  */
411   if (string->str != rval)
412     {
413       /* Assigning from substring should be ok since g_string_truncate
414 	 does not realloc.  */
415       g_string_truncate (string, 0);
416       g_string_append (string, rval);
417     }
418 
419   return string;
420 }
421 
422 GString*
423 g_string_truncate (GString *string,
424 		   gsize    len)
425 {
426   g_return_val_if_fail (string != NULL, NULL);
427 
428   string->len = MIN (len, string->len);
429   string->str[string->len] = 0;
430 
431   return string;
432 }
433 
434 /**
435  * g_string_set_size:
436  * @string: a #GString
437  * @len: the new length
438  *
439  * Sets the length of a #GString. If the length is less than
440  * the current length, the string will be truncated. If the
441  * length is greater than the current length, the contents
442  * of the newly added area are undefined. (However, as
443  * always, string->str[string->len] will be a nul byte.)
444  *
445  * Return value: @string
446  **/
447 GString*
448 g_string_set_size (GString *string,
449 		   gsize    len)
450 {
451   g_return_val_if_fail (string != NULL, NULL);
452 
453   if (len >= string->allocated_len)
454     g_string_maybe_expand (string, len - string->len);
455 
456   string->len = len;
457   string->str[len] = 0;
458 
459   return string;
460 }
461 
462 #endif
463 
464 GString*
g_string_insert_len(GString * string,gssize pos,const gchar * val,gssize len)465 g_string_insert_len (GString     *string,
466 		     gssize       pos,
467 		     const gchar *val,
468 		     gssize       len)
469 {
470   g_return_val_if_fail (string != NULL, NULL);
471   g_return_val_if_fail (val != NULL, string);
472 
473   if (len < 0)
474     len = strlen (val);
475 
476   if (pos < 0)
477     pos = string->len;
478   else
479     g_return_val_if_fail (pos <= string->len, string);
480 
481   /* Check whether val represents a substring of string.  This test
482      probably violates chapter and verse of the C standards, since
483      ">=" and "<=" are only valid when val really is a substring.
484      In practice, it will work on modern archs.  */
485   if (val >= string->str && val <= string->str + string->len)
486     {
487       gsize offset = val - string->str;
488       gsize precount = 0;
489 
490       g_string_maybe_expand (string, len);
491       val = string->str + offset;
492       /* At this point, val is valid again.  */
493 
494       /* Open up space where we are going to insert.  */
495       if (pos < string->len)
496 	g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
497 
498       /* Move the source part before the gap, if any.  */
499       if (offset < pos)
500 	{
501 	  precount = MIN (len, pos - offset);
502 	  memcpy (string->str + pos, val, precount);
503 	}
504 
505       /* Move the source part after the gap, if any.  */
506       if (len > precount)
507 	memcpy (string->str + pos + precount,
508 		val + /* Already moved: */ precount + /* Space opened up: */ len,
509 		len - precount);
510     }
511   else
512     {
513       g_string_maybe_expand (string, len);
514 
515       /* If we aren't appending at the end, move a hunk
516        * of the old string to the end, opening up space
517        */
518       if (pos < string->len)
519 	g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
520 
521       /* insert the new string */
522       if (len == 1)
523         string->str[pos] = *val;
524       else
525         memcpy (string->str + pos, val, len);
526     }
527 
528   string->len += len;
529 
530   string->str[string->len] = 0;
531 
532   return string;
533 }
534 
535 GString*
g_string_append(GString * string,const gchar * val)536 g_string_append (GString     *string,
537 		 const gchar *val)
538 {
539   g_return_val_if_fail (string != NULL, NULL);
540   g_return_val_if_fail (val != NULL, string);
541 
542   return g_string_insert_len (string, -1, val, -1);
543 }
544 
545 GString*
g_string_append_len(GString * string,const gchar * val,gssize len)546 g_string_append_len (GString	 *string,
547                      const gchar *val,
548                      gssize       len)
549 {
550   g_return_val_if_fail (string != NULL, NULL);
551   g_return_val_if_fail (val != NULL, string);
552 
553   return g_string_insert_len (string, -1, val, len);
554 }
555 
556 #if !defined IN_LIBTEXTSTYLE
557 #undef g_string_append_c
558 #endif
559 GString*
g_string_append_c(GString * string,gchar c)560 g_string_append_c (GString *string,
561 		   gchar    c)
562 {
563   g_return_val_if_fail (string != NULL, NULL);
564 
565   return g_string_insert_c (string, -1, c);
566 }
567 
568 /**
569  * g_string_append_unichar:
570  * @string: a #GString
571  * @wc: a Unicode character
572  *
573  * Converts a Unicode character into UTF-8, and appends it
574  * to the string.
575  *
576  * Return value: @string
577  **/
578 GString*
g_string_append_unichar(GString * string,gunichar wc)579 g_string_append_unichar (GString  *string,
580 			 gunichar  wc)
581 {
582   g_return_val_if_fail (string != NULL, NULL);
583 
584   return g_string_insert_unichar (string, -1, wc);
585 }
586 
587 #if 0
588 
589 GString*
590 g_string_prepend (GString     *string,
591 		  const gchar *val)
592 {
593   g_return_val_if_fail (string != NULL, NULL);
594   g_return_val_if_fail (val != NULL, string);
595 
596   return g_string_insert_len (string, 0, val, -1);
597 }
598 
599 GString*
600 g_string_prepend_len (GString	  *string,
601                       const gchar *val,
602                       gssize       len)
603 {
604   g_return_val_if_fail (string != NULL, NULL);
605   g_return_val_if_fail (val != NULL, string);
606 
607   return g_string_insert_len (string, 0, val, len);
608 }
609 
610 GString*
611 g_string_prepend_c (GString *string,
612 		    gchar    c)
613 {
614   g_return_val_if_fail (string != NULL, NULL);
615 
616   return g_string_insert_c (string, 0, c);
617 }
618 
619 /**
620  * g_string_prepend_unichar:
621  * @string: a #GString.
622  * @wc: a Unicode character.
623  *
624  * Converts a Unicode character into UTF-8, and prepends it
625  * to the string.
626  *
627  * Return value: @string.
628  **/
629 GString*
630 g_string_prepend_unichar (GString  *string,
631 			  gunichar  wc)
632 {
633   g_return_val_if_fail (string != NULL, NULL);
634 
635   return g_string_insert_unichar (string, 0, wc);
636 }
637 
638 GString*
639 g_string_insert (GString     *string,
640 		 gssize       pos,
641 		 const gchar *val)
642 {
643   g_return_val_if_fail (string != NULL, NULL);
644   g_return_val_if_fail (val != NULL, string);
645   if (pos >= 0)
646     g_return_val_if_fail (pos <= string->len, string);
647 
648   return g_string_insert_len (string, pos, val, -1);
649 }
650 
651 #endif
652 
653 GString*
g_string_insert_c(GString * string,gssize pos,gchar c)654 g_string_insert_c (GString *string,
655 		   gssize   pos,
656 		   gchar    c)
657 {
658   g_return_val_if_fail (string != NULL, NULL);
659 
660   g_string_maybe_expand (string, 1);
661 
662   if (pos < 0)
663     pos = string->len;
664   else
665     g_return_val_if_fail (pos <= string->len, string);
666 
667   /* If not just an append, move the old stuff */
668   if (pos < string->len)
669     g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
670 
671   string->str[pos] = c;
672 
673   string->len += 1;
674 
675   string->str[string->len] = 0;
676 
677   return string;
678 }
679 
680 /**
681  * g_string_insert_unichar:
682  * @string: a #GString
683  * @pos: the position at which to insert character, or -1 to
684  *       append at the end of the string.
685  * @wc: a Unicode character
686  *
687  * Converts a Unicode character into UTF-8, and insert it
688  * into the string at the given position.
689  *
690  * Return value: @string
691  **/
692 GString*
g_string_insert_unichar(GString * string,gssize pos,gunichar wc)693 g_string_insert_unichar (GString *string,
694 			 gssize   pos,
695 			 gunichar wc)
696 {
697   gint charlen, first, i;
698   gchar *dest;
699 
700   g_return_val_if_fail (string != NULL, NULL);
701 
702   /* Code copied from g_unichar_to_utf() */
703   if (wc < 0x80)
704     {
705       first = 0;
706       charlen = 1;
707     }
708   else if (wc < 0x800)
709     {
710       first = 0xc0;
711       charlen = 2;
712     }
713   else if (wc < 0x10000)
714     {
715       first = 0xe0;
716       charlen = 3;
717     }
718    else if (wc < 0x200000)
719     {
720       first = 0xf0;
721       charlen = 4;
722     }
723   else if (wc < 0x4000000)
724     {
725       first = 0xf8;
726       charlen = 5;
727     }
728   else
729     {
730       first = 0xfc;
731       charlen = 6;
732     }
733   /* End of copied code */
734 
735   g_string_maybe_expand (string, charlen);
736 
737   if (pos < 0)
738     pos = string->len;
739   else
740     g_return_val_if_fail (pos <= string->len, string);
741 
742   /* If not just an append, move the old stuff */
743   if (pos < string->len)
744     g_memmove (string->str + pos + charlen, string->str + pos, string->len - pos);
745 
746   dest = string->str + pos;
747   /* Code copied from g_unichar_to_utf() */
748   for (i = charlen - 1; i > 0; --i)
749     {
750       dest[i] = (wc & 0x3f) | 0x80;
751       wc >>= 6;
752     }
753   dest[0] = wc | first;
754   /* End of copied code */
755 
756   string->len += charlen;
757 
758   string->str[string->len] = 0;
759 
760   return string;
761 }
762 
763 #if 0
764 
765 GString*
766 g_string_erase (GString *string,
767 		gssize   pos,
768 		gssize   len)
769 {
770   g_return_val_if_fail (string != NULL, NULL);
771   g_return_val_if_fail (pos >= 0, string);
772   g_return_val_if_fail (pos <= string->len, string);
773 
774   if (len < 0)
775     len = string->len - pos;
776   else
777     {
778       g_return_val_if_fail (pos + len <= string->len, string);
779 
780       if (pos + len < string->len)
781 	g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
782     }
783 
784   string->len -= len;
785 
786   string->str[string->len] = 0;
787 
788   return string;
789 }
790 
791 /**
792  * g_string_ascii_down:
793  * @string: a GString
794  *
795  * Converts all upper case ASCII letters to lower case ASCII letters.
796  *
797  * Return value: passed-in @string pointer, with all the upper case
798  *               characters converted to lower case in place, with
799  *               semantics that exactly match g_ascii_tolower.
800  **/
801 GString*
802 g_string_ascii_down (GString *string)
803 {
804   gchar *s;
805   gint n;
806 
807   g_return_val_if_fail (string != NULL, NULL);
808 
809   n = string->len;
810   s = string->str;
811 
812   while (n)
813     {
814       *s = g_ascii_tolower (*s);
815       s++;
816       n--;
817     }
818 
819   return string;
820 }
821 
822 /**
823  * g_string_ascii_up:
824  * @string: a GString
825  *
826  * Converts all lower case ASCII letters to upper case ASCII letters.
827  *
828  * Return value: passed-in @string pointer, with all the lower case
829  *               characters converted to upper case in place, with
830  *               semantics that exactly match g_ascii_toupper.
831  **/
832 GString*
833 g_string_ascii_up (GString *string)
834 {
835   gchar *s;
836   gint n;
837 
838   g_return_val_if_fail (string != NULL, NULL);
839 
840   n = string->len;
841   s = string->str;
842 
843   while (n)
844     {
845       *s = g_ascii_toupper (*s);
846       s++;
847       n--;
848     }
849 
850   return string;
851 }
852 
853 /**
854  * g_string_down:
855  * @string: a #GString
856  *
857  * Converts a #GString to lowercase.
858  *
859  * Returns: the #GString.
860  *
861  * Deprecated:2.2: This function uses the locale-specific tolower() function,
862  * which is almost never the right thing. Use g_string_ascii_down() or
863  * g_utf8_strdown() instead.
864  */
865 GString*
866 g_string_down (GString *string)
867 {
868   guchar *s;
869   glong n;
870 
871   g_return_val_if_fail (string != NULL, NULL);
872 
873   n = string->len;
874   s = (guchar *) string->str;
875 
876   while (n)
877     {
878       if (isupper (*s))
879 	*s = tolower (*s);
880       s++;
881       n--;
882     }
883 
884   return string;
885 }
886 
887 /**
888  * g_string_up:
889  * @string: a #GString
890  *
891  * Converts a #GString to uppercase.
892  *
893  * Return value: the #GString
894  *
895  * Deprecated:2.2: This function uses the locale-specific toupper() function,
896  * which is almost never the right thing. Use g_string_ascii_up() or
897  * g_utf8_strup() instead.
898  **/
899 GString*
900 g_string_up (GString *string)
901 {
902   guchar *s;
903   glong n;
904 
905   g_return_val_if_fail (string != NULL, NULL);
906 
907   n = string->len;
908   s = (guchar *) string->str;
909 
910   while (n)
911     {
912       if (islower (*s))
913 	*s = toupper (*s);
914       s++;
915       n--;
916     }
917 
918   return string;
919 }
920 
921 #endif
922 
923 static void
g_string_append_printf_internal(GString * string,const gchar * fmt,va_list args)924 g_string_append_printf_internal (GString     *string,
925 				 const gchar *fmt,
926 				 va_list      args)
927 {
928   gchar *buffer;
929   gint length;
930 
931   length = g_vasprintf (&buffer, fmt, args);
932   g_string_append_len (string, buffer, length);
933   g_free (buffer);
934 }
935 
936 #if 0
937 
938 void
939 g_string_printf (GString *string,
940 		 const gchar *fmt,
941 		 ...)
942 {
943   va_list args;
944 
945   g_string_truncate (string, 0);
946 
947   va_start (args, fmt);
948   g_string_append_printf_internal (string, fmt, args);
949   va_end (args);
950 }
951 
952 #endif
953 
954 void
g_string_append_printf(GString * string,const gchar * fmt,...)955 g_string_append_printf (GString *string,
956 			const gchar *fmt,
957 			...)
958 {
959   va_list args;
960 
961   va_start (args, fmt);
962   g_string_append_printf_internal (string, fmt, args);
963   va_end (args);
964 }
965 
966 #if 0
967 #define __G_STRING_C__
968 #include "galiasdef.c"
969 #endif
970