Patch from Darin Adler (#54166)
[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 GString*
469 g_string_prepend (GString     *fstring,
470                   const gchar *val)
471 {
472   g_return_val_if_fail (fstring != NULL, NULL);
473   g_return_val_if_fail (val != NULL, fstring);
474   
475   return g_string_insert_len (fstring, 0, val, -1);
476 }
477
478 GString*
479 g_string_prepend_len (GString     *string,
480                       const gchar *val,
481                       gssize       len)    
482 {
483   g_return_val_if_fail (string != NULL, NULL);
484   g_return_val_if_fail (val != NULL, string);
485
486   return g_string_insert_len (string, 0, val, len);
487 }
488
489 GString*
490 g_string_prepend_c (GString *fstring,
491                     gchar    c)
492 {  
493   g_return_val_if_fail (fstring != NULL, NULL);
494   
495   return g_string_insert_c (fstring, 0, c);
496 }
497
498 GString*
499 g_string_insert (GString     *fstring,
500                  gssize       pos,    
501                  const gchar *val)
502 {
503   g_return_val_if_fail (fstring != NULL, NULL);
504   g_return_val_if_fail (val != NULL, fstring);
505   if (pos >= 0)
506     g_return_val_if_fail (pos <= fstring->len, fstring);
507   
508   return g_string_insert_len (fstring, pos, val, -1);
509 }
510
511 GString*
512 g_string_insert_c (GString *fstring,
513                    gssize   pos,    
514                    gchar    c)
515 {
516   GRealString *string = (GRealString *) fstring;
517
518   g_return_val_if_fail (string != NULL, NULL);
519
520   g_string_maybe_expand (string, 1);
521
522   if (pos < 0)
523     pos = string->len;
524   else
525     g_return_val_if_fail (pos <= string->len, fstring);
526   
527   /* If not just an append, move the old stuff */
528   if (pos < string->len)
529     g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
530
531   string->str[pos] = c;
532
533   string->len += 1;
534
535   string->str[string->len] = 0;
536
537   return fstring;
538 }
539
540 GString*
541 g_string_erase (GString *fstring,
542                 gsize    pos,    
543                 gsize    len)    
544 {
545   GRealString *string = (GRealString*)fstring;
546
547   g_return_val_if_fail (string != NULL, NULL);
548   g_return_val_if_fail (pos >= 0, fstring);
549   g_return_val_if_fail (pos <= string->len, fstring);
550
551   if (len < 0)
552     len = string->len - pos;
553   else
554     {
555       g_return_val_if_fail (pos + len <= string->len, fstring);
556
557       if (pos + len < string->len)
558         g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
559     }
560
561   string->len -= len;
562   
563   string->str[string->len] = 0;
564
565   return fstring;
566 }
567
568 /**
569  * g_string_ascii_down:
570  * @string: a GString
571  * 
572  * Converts all upper case ASCII letters to lower case ASCII letters.
573  * 
574  * Return value: passed-in @string pointer, with all the upper case
575  *               characters converted to lower case in place, with
576  *               semantics that exactly match g_ascii_tolower.
577  **/
578 GString*
579 g_string_ascii_down (GString *string)
580 {
581   gchar *s;
582   gint n = string->len;
583
584   g_return_val_if_fail (string != NULL, NULL);
585
586   s = string->str;
587
588   while (n)
589     {
590       *s = g_ascii_tolower (*s);
591       s++;
592       n--;
593     }
594
595   return string;
596 }
597
598 /**
599  * g_string_ascii_up:
600  * @string: a GString
601  * 
602  * Converts all lower case ASCII letters to upper case ASCII letters.
603  * 
604  * Return value: passed-in @string pointer, with all the lower case
605  *               characters converted to upper case in place, with
606  *               semantics that exactly match g_ascii_toupper.
607  **/
608 GString*
609 g_string_ascii_up (GString *string)
610 {
611   gchar *s;
612   gint n = string->len;
613
614   g_return_val_if_fail (string != NULL, NULL);
615
616   s = string->str;
617
618   while (n)
619     {
620       *s = g_ascii_toupper (*s);
621       s++;
622       n--;
623     }
624
625   return string;
626 }
627
628 GString*
629 g_string_down (GString *fstring)
630 {
631   GRealString *string = (GRealString *) fstring;
632   guchar *s;
633   glong n = string->len;    
634
635   g_return_val_if_fail (string != NULL, NULL);
636
637   s = (guchar *) string->str;
638
639   while (n)
640     {
641       if (isupper (*s))
642         *s = tolower (*s);
643       s++;
644       n--;
645     }
646
647   return fstring;
648 }
649
650 GString*
651 g_string_up (GString *fstring)
652 {
653   GRealString *string = (GRealString *) fstring;
654   guchar *s;
655   glong n = string->len;
656
657   g_return_val_if_fail (string != NULL, NULL);
658
659   s = (guchar *) string->str;
660
661   while (n)
662     {
663       if (islower (*s))
664         *s = toupper (*s);
665       s++;
666       n--;
667     }
668
669   return fstring;
670 }
671
672 static void
673 g_string_printfa_internal (GString     *string,
674                            const gchar *fmt,
675                            va_list      args)
676 {
677   gchar *buffer;
678
679   buffer = g_strdup_vprintf (fmt, args);
680   g_string_append (string, buffer);
681   g_free (buffer);
682 }
683
684 void
685 g_string_printf (GString *string,
686                  const gchar *fmt,
687                  ...)
688 {
689   va_list args;
690
691   g_string_truncate (string, 0);
692
693   va_start (args, fmt);
694   g_string_printfa_internal (string, fmt, args);
695   va_end (args);
696 }
697
698 void
699 g_string_printfa (GString *string,
700                   const gchar *fmt,
701                   ...)
702 {
703   va_list args;
704
705   va_start (args, fmt);
706   g_string_printfa_internal (string, fmt, args);
707   va_end (args);
708 }