Implement the same PLT reduction technique used in GTK+:
[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 #include "config.h"
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 #include "galias.h"
43 #include "glib.h"
44 #include "gprintf.h"
45
46
47 struct _GStringChunk
48 {
49   GHashTable *const_table;
50   GSList     *storage_list;
51   gsize       storage_next;    
52   gsize       this_size;       
53   gsize       default_size;    
54 };
55
56 G_LOCK_DEFINE_STATIC (string_mem_chunk);
57 static GMemChunk *string_mem_chunk = NULL;
58
59 /* Hash Functions.
60  */
61
62 gboolean
63 g_str_equal (gconstpointer v1,
64              gconstpointer v2)
65 {
66   const gchar *string1 = v1;
67   const gchar *string2 = v2;
68   
69   return strcmp (string1, string2) == 0;
70 }
71
72 /* 31 bit hash function */
73 guint
74 g_str_hash (gconstpointer key)
75 {
76   const char *p = key;
77   guint h = *p;
78
79   if (h)
80     for (p += 1; *p != '\0'; p++)
81       h = (h << 5) - h + *p;
82
83   return h;
84 }
85
86 #define MY_MAXSIZE ((gsize)-1)
87
88 static inline gsize
89 nearest_power (gsize base, gsize num)    
90 {
91   if (num > MY_MAXSIZE / 2)
92     {
93       return MY_MAXSIZE;
94     }
95   else
96     {
97       gsize n = base;
98
99       while (n < num)
100         n <<= 1;
101       
102       return n;
103     }
104 }
105
106 /* String Chunks.
107  */
108
109 GStringChunk*
110 g_string_chunk_new (gsize default_size)    
111 {
112   GStringChunk *new_chunk = g_new (GStringChunk, 1);
113   gsize size = 1;    
114
115   size = nearest_power (1, default_size);
116
117   new_chunk->const_table       = NULL;
118   new_chunk->storage_list      = NULL;
119   new_chunk->storage_next      = size;
120   new_chunk->default_size      = size;
121   new_chunk->this_size         = size;
122
123   return new_chunk;
124 }
125
126 void
127 g_string_chunk_free (GStringChunk *chunk)
128 {
129   GSList *tmp_list;
130
131   g_return_if_fail (chunk != NULL);
132
133   if (chunk->storage_list)
134     {
135       for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
136         g_free (tmp_list->data);
137
138       g_slist_free (chunk->storage_list);
139     }
140
141   if (chunk->const_table)
142     g_hash_table_destroy (chunk->const_table);
143
144   g_free (chunk);
145 }
146
147 gchar*
148 g_string_chunk_insert (GStringChunk *chunk,
149                        const gchar  *string)
150 {
151   g_return_val_if_fail (chunk != NULL, NULL);
152
153   return g_string_chunk_insert_len (chunk, string, -1);
154 }
155
156 gchar*
157 g_string_chunk_insert_const (GStringChunk *chunk,
158                              const gchar  *string)
159 {
160   char* lookup;
161
162   g_return_val_if_fail (chunk != NULL, NULL);
163
164   if (!chunk->const_table)
165     chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
166
167   lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
168
169   if (!lookup)
170     {
171       lookup = g_string_chunk_insert (chunk, string);
172       g_hash_table_insert (chunk->const_table, lookup, lookup);
173     }
174
175   return lookup;
176 }
177
178 /**
179  * g_string_chunk_insert_len:
180  * @chunk: a #GStringChunk
181  * @string: bytes to insert
182  * @len: number of bytes of @string to insert, or -1 to insert a 
183  *     nul-terminated string. 
184  * 
185  * Adds a copy of the first @len bytes of @string to the #GStringChunk. The
186  * copy is nul-terminated.
187  * 
188  * The characters in the string can be changed, if necessary, though you
189  * should not change anything after the end of the string.
190  * 
191  * Return value: a pointer to the copy of @string within the #GStringChunk
192  * 
193  * Since: 2.4
194  **/
195 gchar*
196 g_string_chunk_insert_len (GStringChunk *chunk,
197                            const gchar  *string, 
198                            gssize        len)
199 {
200   gchar* pos;
201
202   g_return_val_if_fail (chunk != NULL, NULL);
203
204   if (len < 0)
205     len = strlen (string);
206   
207   if ((chunk->storage_next + len + 1) > chunk->this_size)
208     {
209       gsize new_size = nearest_power (chunk->default_size, len + 1);
210
211       chunk->storage_list = g_slist_prepend (chunk->storage_list,
212                                              g_new (gchar, new_size));
213
214       chunk->this_size = new_size;
215       chunk->storage_next = 0;
216     }
217
218   pos = ((gchar *) chunk->storage_list->data) + chunk->storage_next;
219
220   *(pos + len) = '\0';
221
222   strncpy (pos, string, len);
223   len = strlen (pos);
224
225   chunk->storage_next += len + 1;
226
227   return pos;
228 }
229
230 /* Strings.
231  */
232 static void
233 g_string_maybe_expand (GString* string,
234                        gsize    len) 
235 {
236   if (string->len + len >= string->allocated_len)
237     {
238       string->allocated_len = nearest_power (1, string->len + len + 1);
239       string->str = g_realloc (string->str, string->allocated_len);
240     }
241 }
242
243 GString*
244 g_string_sized_new (gsize dfl_size)    
245 {
246   GString *string;
247
248   G_LOCK (string_mem_chunk);
249   if (!string_mem_chunk)
250     string_mem_chunk = g_mem_chunk_new ("string mem chunk",
251                                         sizeof (GString),
252                                         1024, G_ALLOC_AND_FREE);
253
254   string = g_chunk_new (GString, string_mem_chunk);
255   G_UNLOCK (string_mem_chunk);
256
257   string->allocated_len = 0;
258   string->len   = 0;
259   string->str   = NULL;
260
261   g_string_maybe_expand (string, MAX (dfl_size, 2));
262   string->str[0] = 0;
263
264   return string;
265 }
266
267 GString*
268 g_string_new (const gchar *init)
269 {
270   GString *string;
271
272   if (init == NULL || *init == '\0')
273     string = g_string_sized_new (2);
274   else 
275     {
276       gint len;
277
278       len = strlen (init);
279       string = g_string_sized_new (len + 2);
280
281       g_string_append_len (string, init, len);
282     }
283
284   return string;
285 }
286
287 GString*
288 g_string_new_len (const gchar *init,
289                   gssize       len)    
290 {
291   GString *string;
292
293   if (len < 0)
294     return g_string_new (init);
295   else
296     {
297       string = g_string_sized_new (len);
298       
299       if (init)
300         g_string_append_len (string, init, len);
301       
302       return string;
303     }
304 }
305
306 gchar*
307 g_string_free (GString *string,
308                gboolean free_segment)
309 {
310   gchar *segment;
311
312   g_return_val_if_fail (string != NULL, NULL);
313
314   if (free_segment)
315     {
316       g_free (string->str);
317       segment = NULL;
318     }
319   else
320     segment = string->str;
321
322   G_LOCK (string_mem_chunk);
323   g_mem_chunk_free (string_mem_chunk, string);
324   G_UNLOCK (string_mem_chunk);
325
326   return segment;
327 }
328
329 gboolean
330 g_string_equal (const GString *v,
331                 const GString *v2)
332 {
333   gchar *p, *q;
334   GString *string1 = (GString *) v;
335   GString *string2 = (GString *) v2;
336   gsize i = string1->len;    
337
338   if (i != string2->len)
339     return FALSE;
340
341   p = string1->str;
342   q = string2->str;
343   while (i)
344     {
345       if (*p != *q)
346         return FALSE;
347       p++;
348       q++;
349       i--;
350     }
351   return TRUE;
352 }
353
354 /* 31 bit hash function */
355 guint
356 g_string_hash (const GString *str)
357 {
358   const gchar *p = str->str;
359   gsize n = str->len;    
360   guint h = 0;
361
362   while (n--)
363     {
364       h = (h << 5) - h + *p;
365       p++;
366     }
367
368   return h;
369 }
370
371 GString*
372 g_string_assign (GString     *string,
373                  const gchar *rval)
374 {
375   g_return_val_if_fail (string != NULL, NULL);
376   g_return_val_if_fail (rval != NULL, string);
377
378   /* Make sure assigning to itself doesn't corrupt the string.  */
379   if (string->str != rval)
380     {
381       /* Assigning from substring should be ok since g_string_truncate
382          does not realloc.  */
383       g_string_truncate (string, 0);
384       g_string_append (string, rval);
385     }
386
387   return string;
388 }
389
390 GString*
391 g_string_truncate (GString *string,
392                    gsize    len)    
393 {
394   g_return_val_if_fail (string != NULL, NULL);
395
396   string->len = MIN (len, string->len);
397   string->str[string->len] = 0;
398
399   return string;
400 }
401
402 /**
403  * g_string_set_size:
404  * @string: a #GString
405  * @len: the new length
406  * 
407  * Sets the length of a #GString. If the length is less than
408  * the current length, the string will be truncated. If the
409  * length is greater than the current length, the contents
410  * of the newly added area are undefined. (However, as
411  * always, string->str[string->len] will be a nul byte.) 
412  * 
413  * Return value: @string
414  **/
415 GString*
416 g_string_set_size (GString *string,
417                    gsize    len)    
418 {
419   g_return_val_if_fail (string != NULL, NULL);
420
421   if (len >= string->allocated_len)
422     g_string_maybe_expand (string, len - string->len);
423   
424   string->len = len;
425   string->str[len] = 0;
426
427   return string;
428 }
429
430 GString*
431 g_string_insert_len (GString     *string,
432                      gssize       pos,    
433                      const gchar *val,
434                      gssize       len)    
435 {
436   g_return_val_if_fail (string != NULL, NULL);
437   g_return_val_if_fail (val != NULL, string);
438
439   if (len < 0)
440     len = strlen (val);
441
442   if (pos < 0)
443     pos = string->len;
444   else
445     g_return_val_if_fail (pos <= string->len, string);
446
447   /* Check whether val represents a substring of string.  This test
448      probably violates chapter and verse of the C standards, since
449      ">=" and "<=" are only valid when val really is a substring.
450      In practice, it will work on modern archs.  */
451   if (val >= string->str && val <= string->str + string->len)
452     {
453       gsize offset = val - string->str;
454       gsize precount = 0;
455
456       g_string_maybe_expand (string, len);
457       val = string->str + offset;
458       /* At this point, val is valid again.  */
459
460       /* Open up space where we are going to insert.  */
461       if (pos < string->len)
462         g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
463
464       /* Move the source part before the gap, if any.  */
465       if (offset < pos)
466         {
467           precount = MIN (len, pos - offset);
468           memcpy (string->str + pos, val, precount);
469         }
470
471       /* Move the source part after the gap, if any.  */
472       if (len > precount)
473         memcpy (string->str + pos + precount,
474                 val + /* Already moved: */ precount + /* Space opened up: */ len,
475                 len - precount);
476     }
477   else
478     {
479       g_string_maybe_expand (string, len);
480
481       /* If we aren't appending at the end, move a hunk
482        * of the old string to the end, opening up space
483        */
484       if (pos < string->len)
485         g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
486
487       /* insert the new string */
488       memcpy (string->str + pos, val, len);
489     }
490
491   string->len += len;
492
493   string->str[string->len] = 0;
494
495   return string;
496 }
497
498 GString*
499 g_string_append (GString     *string,
500                  const gchar *val)
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, -1, val, -1);
506 }
507
508 GString*
509 g_string_append_len (GString     *string,
510                      const gchar *val,
511                      gssize       len)    
512 {
513   g_return_val_if_fail (string != NULL, NULL);
514   g_return_val_if_fail (val != NULL, string);
515
516   return g_string_insert_len (string, -1, val, len);
517 }
518
519 #undef g_string_append_c
520 GString*
521 g_string_append_c (GString *string,
522                    gchar    c)
523 {
524   g_return_val_if_fail (string != NULL, NULL);
525
526   return g_string_insert_c (string, -1, c);
527 }
528
529 /**
530  * g_string_append_unichar:
531  * @string: a #GString
532  * @wc: a Unicode character
533  * 
534  * Converts a Unicode character into UTF-8, and appends it
535  * to the string.
536  * 
537  * Return value: @string
538  **/
539 GString*
540 g_string_append_unichar (GString  *string,
541                          gunichar  wc)
542 {  
543   g_return_val_if_fail (string != NULL, NULL);
544   
545   return g_string_insert_unichar (string, -1, wc);
546 }
547
548 GString*
549 g_string_prepend (GString     *string,
550                   const gchar *val)
551 {
552   g_return_val_if_fail (string != NULL, NULL);
553   g_return_val_if_fail (val != NULL, string);
554   
555   return g_string_insert_len (string, 0, val, -1);
556 }
557
558 GString*
559 g_string_prepend_len (GString     *string,
560                       const gchar *val,
561                       gssize       len)    
562 {
563   g_return_val_if_fail (string != NULL, NULL);
564   g_return_val_if_fail (val != NULL, string);
565
566   return g_string_insert_len (string, 0, val, len);
567 }
568
569 GString*
570 g_string_prepend_c (GString *string,
571                     gchar    c)
572 {  
573   g_return_val_if_fail (string != NULL, NULL);
574   
575   return g_string_insert_c (string, 0, c);
576 }
577
578 /**
579  * g_string_prepend_unichar:
580  * @string: a #GString.
581  * @wc: a Unicode character.
582  * 
583  * Converts a Unicode character into UTF-8, and prepends it
584  * to the string.
585  * 
586  * Return value: @string.
587  **/
588 GString*
589 g_string_prepend_unichar (GString  *string,
590                           gunichar  wc)
591 {  
592   g_return_val_if_fail (string != NULL, NULL);
593   
594   return g_string_insert_unichar (string, 0, wc);
595 }
596
597 GString*
598 g_string_insert (GString     *string,
599                  gssize       pos,    
600                  const gchar *val)
601 {
602   g_return_val_if_fail (string != NULL, NULL);
603   g_return_val_if_fail (val != NULL, string);
604   if (pos >= 0)
605     g_return_val_if_fail (pos <= string->len, string);
606   
607   return g_string_insert_len (string, pos, val, -1);
608 }
609
610 GString*
611 g_string_insert_c (GString *string,
612                    gssize   pos,    
613                    gchar    c)
614 {
615   g_return_val_if_fail (string != NULL, NULL);
616
617   g_string_maybe_expand (string, 1);
618
619   if (pos < 0)
620     pos = string->len;
621   else
622     g_return_val_if_fail (pos <= string->len, string);
623   
624   /* If not just an append, move the old stuff */
625   if (pos < string->len)
626     g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
627
628   string->str[pos] = c;
629
630   string->len += 1;
631
632   string->str[string->len] = 0;
633
634   return string;
635 }
636
637 /**
638  * g_string_insert_unichar:
639  * @string: a #GString
640  * @pos: the position at which to insert character, or -1 to
641  *       append at the end of the string.
642  * @wc: a Unicode character
643  * 
644  * Converts a Unicode character into UTF-8, and insert it
645  * into the string at the given position.
646  * 
647  * Return value: @string
648  **/
649 GString*
650 g_string_insert_unichar (GString *string,
651                          gssize   pos,    
652                          gunichar wc)
653 {  
654   gchar buf[6];
655   gint charlen;
656
657   /* We could be somewhat more efficient here by computing
658    * the length, adding the space, then converting into that
659    * space, by cut-and-pasting the internals of g_unichar_to_utf8.
660    */
661   g_return_val_if_fail (string != NULL, NULL);
662
663   charlen = g_unichar_to_utf8 (wc, buf);
664   return g_string_insert_len (string, pos, buf, charlen);
665 }
666
667 GString*
668 g_string_erase (GString *string,
669                 gssize   pos,
670                 gssize   len)
671 {
672   g_return_val_if_fail (string != NULL, NULL);
673   g_return_val_if_fail (pos >= 0, string);
674   g_return_val_if_fail (pos <= string->len, string);
675
676   if (len < 0)
677     len = string->len - pos;
678   else
679     {
680       g_return_val_if_fail (pos + len <= string->len, string);
681
682       if (pos + len < string->len)
683         g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
684     }
685
686   string->len -= len;
687   
688   string->str[string->len] = 0;
689
690   return string;
691 }
692
693 /**
694  * g_string_ascii_down:
695  * @string: a GString
696  * 
697  * Converts all upper case ASCII letters to lower case ASCII letters.
698  * 
699  * Return value: passed-in @string pointer, with all the upper case
700  *               characters converted to lower case in place, with
701  *               semantics that exactly match g_ascii_tolower.
702  **/
703 GString*
704 g_string_ascii_down (GString *string)
705 {
706   gchar *s;
707   gint n;
708
709   g_return_val_if_fail (string != NULL, NULL);
710
711   n = string->len;
712   s = string->str;
713
714   while (n)
715     {
716       *s = g_ascii_tolower (*s);
717       s++;
718       n--;
719     }
720
721   return string;
722 }
723
724 /**
725  * g_string_ascii_up:
726  * @string: a GString
727  * 
728  * Converts all lower case ASCII letters to upper case ASCII letters.
729  * 
730  * Return value: passed-in @string pointer, with all the lower case
731  *               characters converted to upper case in place, with
732  *               semantics that exactly match g_ascii_toupper.
733  **/
734 GString*
735 g_string_ascii_up (GString *string)
736 {
737   gchar *s;
738   gint n;
739
740   g_return_val_if_fail (string != NULL, NULL);
741
742   n = string->len;
743   s = string->str;
744
745   while (n)
746     {
747       *s = g_ascii_toupper (*s);
748       s++;
749       n--;
750     }
751
752   return string;
753 }
754
755 /**
756  * g_string_down:
757  * @string: a #GString
758  *  
759  * Converts a #GString to lowercase.
760  *
761  * Returns: the #GString.
762  *
763  * Deprecated: This function uses the locale-specific tolower() function, 
764  * which is almost never the right thing. Use g_string_ascii_down() or 
765  * g_utf8_strdown() instead.
766  */
767 GString*
768 g_string_down (GString *string)
769 {
770   guchar *s;
771   glong n;
772
773   g_return_val_if_fail (string != NULL, NULL);
774
775   n = string->len;    
776   s = (guchar *) string->str;
777
778   while (n)
779     {
780       if (isupper (*s))
781         *s = tolower (*s);
782       s++;
783       n--;
784     }
785
786   return string;
787 }
788
789 /**
790  * g_string_up:
791  * @string: a #GString 
792  * 
793  * Converts a #GString to uppercase.
794  * 
795  * Return value: the #GString
796  *
797  * Deprecated: This function uses the locale-specific toupper() function, 
798  * which is almost never the right thing. Use g_string_ascii_up() or 
799  * g_utf8_strup() instead.
800  **/
801 GString*
802 g_string_up (GString *string)
803 {
804   guchar *s;
805   glong n;
806
807   g_return_val_if_fail (string != NULL, NULL);
808
809   n = string->len;
810   s = (guchar *) string->str;
811
812   while (n)
813     {
814       if (islower (*s))
815         *s = toupper (*s);
816       s++;
817       n--;
818     }
819
820   return string;
821 }
822
823 static void
824 g_string_append_printf_internal (GString     *string,
825                                  const gchar *fmt,
826                                  va_list      args)
827 {
828   gchar *buffer;
829   gint length;
830   
831   length = g_vasprintf (&buffer, fmt, args);
832   g_string_append_len (string, buffer, length);
833   g_free (buffer);
834 }
835
836 void
837 g_string_printf (GString *string,
838                  const gchar *fmt,
839                  ...)
840 {
841   va_list args;
842
843   g_string_truncate (string, 0);
844
845   va_start (args, fmt);
846   g_string_append_printf_internal (string, fmt, args);
847   va_end (args);
848 }
849
850 void
851 g_string_append_printf (GString *string,
852                         const gchar *fmt,
853                         ...)
854 {
855   va_list args;
856
857   va_start (args, fmt);
858   g_string_append_printf_internal (string, fmt, args);
859   va_end (args);
860 }