Add functions to insert a unichar as UTF-8, since this is reasonably
[platform/upstream/glib.git] / glib / gstring.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GLib Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 /* 
28  * MT safe
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include "glib.h"
44
45 typedef struct _GRealStringChunk GRealStringChunk;
46 typedef struct _GRealString      GRealString;
47
48 struct _GRealStringChunk
49 {
50   GHashTable *const_table;
51   GSList     *storage_list;
52   gsize       storage_next;    
53   gsize       this_size;       
54   gsize       default_size;    
55 };
56
57 struct _GRealString
58 {
59   gchar *str;
60   gsize len;    
61   gsize allocated_len;  
62 };
63
64 G_LOCK_DEFINE_STATIC (string_mem_chunk);
65 static GMemChunk *string_mem_chunk = NULL;
66
67 /* Hash Functions.
68  */
69
70 gboolean
71 g_str_equal (gconstpointer v1,
72              gconstpointer v2)
73 {
74   const gchar *string1 = v1;
75   const gchar *string2 = v2;
76   
77   return strcmp (string1, string2) == 0;
78 }
79
80 /* 31 bit hash function */
81 guint
82 g_str_hash (gconstpointer key)
83 {
84   const char *p = key;
85   guint h = *p;
86
87   if (h)
88     for (p += 1; *p != '\0'; p++)
89       h = (h << 5) - h + *p;
90
91   return h;
92 }
93
94 #define MY_MAXSIZE ((gsize)-1)
95
96 static inline gsize
97 nearest_power (gsize base, gsize num)    
98 {
99   if (num > MY_MAXSIZE / 2)
100     {
101       return MY_MAXSIZE;
102     }
103   else
104     {
105       gsize n = base;
106
107       while (n < num)
108         n <<= 1;
109       
110       return n;
111     }
112 }
113
114 /* String Chunks.
115  */
116
117 GStringChunk*
118 g_string_chunk_new (gsize default_size)    
119 {
120   GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1);
121   gsize size = 1;    
122
123   size = nearest_power (1, default_size);
124
125   new_chunk->const_table       = NULL;
126   new_chunk->storage_list      = NULL;
127   new_chunk->storage_next      = size;
128   new_chunk->default_size      = size;
129   new_chunk->this_size         = size;
130
131   return (GStringChunk*) new_chunk;
132 }
133
134 void
135 g_string_chunk_free (GStringChunk *fchunk)
136 {
137   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
138   GSList *tmp_list;
139
140   g_return_if_fail (chunk != NULL);
141
142   if (chunk->storage_list)
143     {
144       for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
145         g_free (tmp_list->data);
146
147       g_slist_free (chunk->storage_list);
148     }
149
150   if (chunk->const_table)
151     g_hash_table_destroy (chunk->const_table);
152
153   g_free (chunk);
154 }
155
156 gchar*
157 g_string_chunk_insert (GStringChunk *fchunk,
158                        const gchar  *string)
159 {
160   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
161   gsize len = strlen (string);
162   char* pos;
163
164   g_return_val_if_fail (chunk != NULL, NULL);
165
166   if ((chunk->storage_next + len + 1) > chunk->this_size)
167     {
168       gsize new_size = nearest_power (chunk->default_size, len + 1);
169
170       chunk->storage_list = g_slist_prepend (chunk->storage_list,
171                                              g_new (char, new_size));
172
173       chunk->this_size = new_size;
174       chunk->storage_next = 0;
175     }
176
177   pos = ((char *) chunk->storage_list->data) + chunk->storage_next;
178
179   strcpy (pos, string);
180
181   chunk->storage_next += len + 1;
182
183   return pos;
184 }
185
186 gchar*
187 g_string_chunk_insert_const (GStringChunk *fchunk,
188                              const gchar  *string)
189 {
190   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
191   char* lookup;
192
193   g_return_val_if_fail (chunk != NULL, NULL);
194
195   if (!chunk->const_table)
196     chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
197
198   lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
199
200   if (!lookup)
201     {
202       lookup = g_string_chunk_insert (fchunk, string);
203       g_hash_table_insert (chunk->const_table, lookup, lookup);
204     }
205
206   return lookup;
207 }
208
209 /* Strings.
210  */
211 static void
212 g_string_maybe_expand (GRealString* string,
213                        gsize        len) 
214 {
215   if (string->len + len >= string->allocated_len)
216     {
217       string->allocated_len = nearest_power (1, string->len + len + 1);
218       string->str = g_realloc (string->str, string->allocated_len);
219     }
220 }
221
222 GString*
223 g_string_sized_new (gsize dfl_size)    
224 {
225   GRealString *string;
226
227   G_LOCK (string_mem_chunk);
228   if (!string_mem_chunk)
229     string_mem_chunk = g_mem_chunk_new ("string mem chunk",
230                                         sizeof (GRealString),
231                                         1024, G_ALLOC_AND_FREE);
232
233   string = g_chunk_new (GRealString, string_mem_chunk);
234   G_UNLOCK (string_mem_chunk);
235
236   string->allocated_len = 0;
237   string->len   = 0;
238   string->str   = NULL;
239
240   g_string_maybe_expand (string, MAX (dfl_size, 2));
241   string->str[0] = 0;
242
243   return (GString*) string;
244 }
245
246 GString*
247 g_string_new (const gchar *init)
248 {
249   GString *string;
250
251   string = g_string_sized_new (init ? strlen (init) + 2 : 2);
252
253   if (init)
254     g_string_append (string, init);
255
256   return string;
257 }
258
259 GString*
260 g_string_new_len (const gchar *init,
261                   gssize       len)    
262 {
263   GString *string;
264
265   if (len < 0)
266     return g_string_new (init);
267   else
268     {
269       string = g_string_sized_new (len);
270       
271       if (init)
272         g_string_append_len (string, init, len);
273       
274       return string;
275     }
276 }
277
278 gchar*
279 g_string_free (GString *string,
280                gboolean free_segment)
281 {
282   gchar *segment;
283
284   g_return_val_if_fail (string != NULL, NULL);
285
286   if (free_segment)
287     {
288       g_free (string->str);
289       segment = NULL;
290     }
291   else
292     segment = string->str;
293
294   G_LOCK (string_mem_chunk);
295   g_mem_chunk_free (string_mem_chunk, string);
296   G_UNLOCK (string_mem_chunk);
297
298   return segment;
299 }
300
301 gboolean
302 g_string_equal (const GString *v,
303                 const GString *v2)
304 {
305   gchar *p, *q;
306   GRealString *string1 = (GRealString *) v;
307   GRealString *string2 = (GRealString *) v2;
308   gsize i = string1->len;    
309
310   if (i != string2->len)
311     return FALSE;
312
313   p = string1->str;
314   q = string2->str;
315   while (i)
316     {
317       if (*p != *q)
318         return FALSE;
319       p++;
320       q++;
321       i--;
322     }
323   return TRUE;
324 }
325
326 /* 31 bit hash function */
327 guint
328 g_string_hash (const GString *str)
329 {
330   const gchar *p = str->str;
331   gsize n = str->len;    
332   guint h = 0;
333
334   while (n--)
335     {
336       h = (h << 5) - h + *p;
337       p++;
338     }
339
340   return h;
341 }
342
343 GString*
344 g_string_assign (GString     *string,
345                  const gchar *rval)
346 {
347   g_return_val_if_fail (string != NULL, NULL);
348   g_return_val_if_fail (rval != NULL, string);
349   
350   g_string_truncate (string, 0);
351   g_string_append (string, rval);
352
353   return string;
354 }
355
356 GString*
357 g_string_truncate (GString *fstring,
358                    gsize    len)    
359 {
360   GRealString *string = (GRealString *) fstring;
361
362   g_return_val_if_fail (string != NULL, NULL);
363
364   string->len = MIN (len, string->len);
365
366   string->str[string->len] = 0;
367
368   return fstring;
369 }
370
371 /**
372  * g_string_set_size:
373  * @fstring: a #GString
374  * @len: the new length
375  * 
376  * Sets the length of a #GString. If the length is less than
377  * the current length, the string will be truncated. If the
378  * length is greater than the current length, the contents
379  * of the newly added area are undefined. (However, as
380  * always, string->str[string->len] will be a nul byte.) 
381  * 
382  * Return value: @fstring
383  **/
384 GString*
385 g_string_set_size (GString *fstring,
386                    gsize    len)    
387 {
388   GRealString *string = (GRealString *) fstring;
389
390   g_return_val_if_fail (string != NULL, NULL);
391
392   if (len >= string->allocated_len)
393     g_string_maybe_expand (string, len - fstring->len);
394   
395   string->len = len;
396   string->str[len] = 0;
397
398   return fstring;
399 }
400
401 GString*
402 g_string_insert_len (GString     *fstring,
403                      gssize       pos,    
404                      const gchar *val,
405                      gssize       len)    
406 {
407   GRealString *string = (GRealString *) fstring;
408
409   g_return_val_if_fail (string != NULL, NULL);
410   g_return_val_if_fail (val != NULL, fstring);
411
412   if (len < 0)
413     len = strlen (val);
414
415   if (pos < 0)
416     pos = string->len;
417   else
418     g_return_val_if_fail (pos <= string->len, fstring);
419   
420   g_string_maybe_expand (string, len);
421
422   /* If we aren't appending at the end, move a hunk
423    * of the old string to the end, opening up space
424    */
425   if (pos < string->len)
426     g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
427   
428   /* insert the new string */
429   g_memmove (string->str + pos, val, len);
430
431   string->len += len;
432
433   string->str[string->len] = 0;
434
435   return fstring;
436 }
437
438 GString*
439 g_string_append (GString     *fstring,
440                  const gchar *val)
441 {  
442   g_return_val_if_fail (fstring != NULL, NULL);
443   g_return_val_if_fail (val != NULL, fstring);
444
445   return g_string_insert_len (fstring, -1, val, -1);
446 }
447
448 GString*
449 g_string_append_len (GString     *string,
450                      const gchar *val,
451                      gssize       len)    
452 {
453   g_return_val_if_fail (string != NULL, NULL);
454   g_return_val_if_fail (val != NULL, string);
455
456   return g_string_insert_len (string, -1, val, len);
457 }
458
459 GString*
460 g_string_append_c (GString *fstring,
461                    gchar    c)
462 {
463   g_return_val_if_fail (fstring != NULL, NULL);
464
465   return g_string_insert_c (fstring, -1, c);
466 }
467
468 /**
469  * g_string_append_unichar:
470  * @string: a #GString
471  * @wc: a Unicode character
472  * 
473  * Converts a Unicode character into UTF-8, and appends it
474  * to the string.
475  * 
476  * Return value: @string
477  **/
478 GString*
479 g_string_append_unichar (GString  *string,
480                          gunichar  wc)
481 {  
482   g_return_val_if_fail (string != NULL, NULL);
483   
484   return g_string_insert_unichar (string, -1, wc);
485 }
486
487 GString*
488 g_string_prepend (GString     *fstring,
489                   const gchar *val)
490 {
491   g_return_val_if_fail (fstring != NULL, NULL);
492   g_return_val_if_fail (val != NULL, fstring);
493   
494   return g_string_insert_len (fstring, 0, val, -1);
495 }
496
497 GString*
498 g_string_prepend_len (GString     *string,
499                       const gchar *val,
500                       gssize       len)    
501 {
502   g_return_val_if_fail (string != NULL, NULL);
503   g_return_val_if_fail (val != NULL, string);
504
505   return g_string_insert_len (string, 0, val, len);
506 }
507
508 GString*
509 g_string_prepend_c (GString *fstring,
510                     gchar    c)
511 {  
512   g_return_val_if_fail (fstring != NULL, NULL);
513   
514   return g_string_insert_c (fstring, 0, c);
515 }
516
517 /**
518  * g_string_append_unichar:
519  * @string: a #GString
520  * @wc: a Unicode character
521  * 
522  * Converts a Unicode character into UTF-8, and prepends it
523  * to the string.
524  * 
525  * Return value: @string
526  **/
527 GString*
528 g_string_prepend_unichar (GString  *string,
529                           gunichar  wc)
530 {  
531   g_return_val_if_fail (string != NULL, NULL);
532   
533   return g_string_insert_unichar (string, 0, wc);
534 }
535
536 GString*
537 g_string_insert (GString     *fstring,
538                  gssize       pos,    
539                  const gchar *val)
540 {
541   g_return_val_if_fail (fstring != NULL, NULL);
542   g_return_val_if_fail (val != NULL, fstring);
543   if (pos >= 0)
544     g_return_val_if_fail (pos <= fstring->len, fstring);
545   
546   return g_string_insert_len (fstring, pos, val, -1);
547 }
548
549 GString*
550 g_string_insert_c (GString *fstring,
551                    gssize   pos,    
552                    gchar    c)
553 {
554   GRealString *string = (GRealString *) fstring;
555
556   g_return_val_if_fail (string != NULL, NULL);
557
558   g_string_maybe_expand (string, 1);
559
560   if (pos < 0)
561     pos = string->len;
562   else
563     g_return_val_if_fail (pos <= string->len, fstring);
564   
565   /* If not just an append, move the old stuff */
566   if (pos < string->len)
567     g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
568
569   string->str[pos] = c;
570
571   string->len += 1;
572
573   string->str[string->len] = 0;
574
575   return fstring;
576 }
577
578 /**
579  * g_string_insert_unichar:
580  * @string: a #Gstring
581  * @pos: the position at which to insert character, or -1 to
582  *       append at the end of the string.
583  * @wc: a Unicode character
584  * 
585  * Converts a Unicode character into UTF-8, and insert it
586  * into the string at the given position.
587  * 
588  * Return value: @string
589  **/
590 GString*
591 g_string_insert_unichar (GString *string,
592                          gssize   pos,    
593                          gunichar wc)
594 {  
595   gchar buf[6];
596   gint charlen;
597
598   /* We could be somewhat more efficient here by computing
599    * the length, adding the space, then converting into that
600    * space, by cut-and-pasting the internals of g_unichar_to_utf8.
601    */
602   g_return_val_if_fail (string != NULL, NULL);
603
604   charlen = g_unichar_to_utf8 (wc, buf);
605   return g_string_insert_len (string, pos, buf, charlen);
606 }
607
608 GString*
609 g_string_erase (GString *fstring,
610                 gsize    pos,    
611                 gsize    len)    
612 {
613   GRealString *string = (GRealString*)fstring;
614
615   g_return_val_if_fail (string != NULL, NULL);
616   g_return_val_if_fail (pos >= 0, fstring);
617   g_return_val_if_fail (pos <= string->len, fstring);
618
619   if (len < 0)
620     len = string->len - pos;
621   else
622     {
623       g_return_val_if_fail (pos + len <= string->len, fstring);
624
625       if (pos + len < string->len)
626         g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
627     }
628
629   string->len -= len;
630   
631   string->str[string->len] = 0;
632
633   return fstring;
634 }
635
636 /**
637  * g_string_ascii_down:
638  * @string: a GString
639  * 
640  * Converts all upper case ASCII letters to lower case ASCII letters.
641  * 
642  * Return value: passed-in @string pointer, with all the upper case
643  *               characters converted to lower case in place, with
644  *               semantics that exactly match g_ascii_tolower.
645  **/
646 GString*
647 g_string_ascii_down (GString *string)
648 {
649   gchar *s;
650   gint n = string->len;
651
652   g_return_val_if_fail (string != NULL, NULL);
653
654   s = string->str;
655
656   while (n)
657     {
658       *s = g_ascii_tolower (*s);
659       s++;
660       n--;
661     }
662
663   return string;
664 }
665
666 /**
667  * g_string_ascii_up:
668  * @string: a GString
669  * 
670  * Converts all lower case ASCII letters to upper case ASCII letters.
671  * 
672  * Return value: passed-in @string pointer, with all the lower case
673  *               characters converted to upper case in place, with
674  *               semantics that exactly match g_ascii_toupper.
675  **/
676 GString*
677 g_string_ascii_up (GString *string)
678 {
679   gchar *s;
680   gint n = string->len;
681
682   g_return_val_if_fail (string != NULL, NULL);
683
684   s = string->str;
685
686   while (n)
687     {
688       *s = g_ascii_toupper (*s);
689       s++;
690       n--;
691     }
692
693   return string;
694 }
695
696 GString*
697 g_string_down (GString *fstring)
698 {
699   GRealString *string = (GRealString *) fstring;
700   guchar *s;
701   glong n = string->len;    
702
703   g_return_val_if_fail (string != NULL, NULL);
704
705   s = (guchar *) string->str;
706
707   while (n)
708     {
709       if (isupper (*s))
710         *s = tolower (*s);
711       s++;
712       n--;
713     }
714
715   return fstring;
716 }
717
718 GString*
719 g_string_up (GString *fstring)
720 {
721   GRealString *string = (GRealString *) fstring;
722   guchar *s;
723   glong n = string->len;
724
725   g_return_val_if_fail (string != NULL, NULL);
726
727   s = (guchar *) string->str;
728
729   while (n)
730     {
731       if (islower (*s))
732         *s = toupper (*s);
733       s++;
734       n--;
735     }
736
737   return fstring;
738 }
739
740 static void
741 g_string_printfa_internal (GString     *string,
742                            const gchar *fmt,
743                            va_list      args)
744 {
745   gchar *buffer;
746
747   buffer = g_strdup_vprintf (fmt, args);
748   g_string_append (string, buffer);
749   g_free (buffer);
750 }
751
752 void
753 g_string_printf (GString *string,
754                  const gchar *fmt,
755                  ...)
756 {
757   va_list args;
758
759   g_string_truncate (string, 0);
760
761   va_start (args, fmt);
762   g_string_printfa_internal (string, fmt, args);
763   va_end (args);
764 }
765
766 void
767 g_string_printfa (GString *string,
768                   const gchar *fmt,
769                   ...)
770 {
771   va_list args;
772
773   va_start (args, fmt);
774   g_string_printfa_internal (string, fmt, args);
775   va_end (args);
776 }