cd5f13be9bfb9eef415a8642866cb9c3d59616fe
[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   gint        storage_next;
53   gint        this_size;
54   gint        default_size;
55 };
56
57 struct _GRealString
58 {
59   gchar *str;
60   gint   len;
61   gint   alloc;
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
95 /* String Chunks.
96  */
97
98 GStringChunk*
99 g_string_chunk_new (gint default_size)
100 {
101   GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1);
102   gint size = 1;
103
104   while (size < default_size)
105     size <<= 1;
106
107   new_chunk->const_table       = NULL;
108   new_chunk->storage_list      = NULL;
109   new_chunk->storage_next      = size;
110   new_chunk->default_size      = size;
111   new_chunk->this_size         = size;
112
113   return (GStringChunk*) new_chunk;
114 }
115
116 void
117 g_string_chunk_free (GStringChunk *fchunk)
118 {
119   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
120   GSList *tmp_list;
121
122   g_return_if_fail (chunk != NULL);
123
124   if (chunk->storage_list)
125     {
126       for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
127         g_free (tmp_list->data);
128
129       g_slist_free (chunk->storage_list);
130     }
131
132   if (chunk->const_table)
133     g_hash_table_destroy (chunk->const_table);
134
135   g_free (chunk);
136 }
137
138 gchar*
139 g_string_chunk_insert (GStringChunk *fchunk,
140                        const gchar  *string)
141 {
142   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
143   gint len = strlen (string);
144   char* pos;
145
146   g_return_val_if_fail (chunk != NULL, NULL);
147
148   if ((chunk->storage_next + len + 1) > chunk->this_size)
149     {
150       gint new_size = chunk->default_size;
151
152       while (new_size < len+1)
153         new_size <<= 1;
154
155       chunk->storage_list = g_slist_prepend (chunk->storage_list,
156                                              g_new (char, new_size));
157
158       chunk->this_size = new_size;
159       chunk->storage_next = 0;
160     }
161
162   pos = ((char *) chunk->storage_list->data) + chunk->storage_next;
163
164   strcpy (pos, string);
165
166   chunk->storage_next += len + 1;
167
168   return pos;
169 }
170
171 gchar*
172 g_string_chunk_insert_const (GStringChunk *fchunk,
173                              const gchar  *string)
174 {
175   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
176   char* lookup;
177
178   g_return_val_if_fail (chunk != NULL, NULL);
179
180   if (!chunk->const_table)
181     chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
182
183   lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
184
185   if (!lookup)
186     {
187       lookup = g_string_chunk_insert (fchunk, string);
188       g_hash_table_insert (chunk->const_table, lookup, lookup);
189     }
190
191   return lookup;
192 }
193
194 /* Strings.
195  */
196 static inline gint
197 nearest_power (gint num)
198 {
199   gint n = 1;
200
201   while (n < num)
202     n <<= 1;
203
204   return n;
205 }
206
207 static void
208 g_string_maybe_expand (GRealString* string, gint len)
209 {
210   if (string->len + len >= string->alloc)
211     {
212       string->alloc = nearest_power (string->len + len + 1);
213       string->str = g_realloc (string->str, string->alloc);
214     }
215 }
216
217 GString*
218 g_string_sized_new (guint dfl_size)
219 {
220   GRealString *string;
221
222   G_LOCK (string_mem_chunk);
223   if (!string_mem_chunk)
224     string_mem_chunk = g_mem_chunk_new ("string mem chunk",
225                                         sizeof (GRealString),
226                                         1024, G_ALLOC_AND_FREE);
227
228   string = g_chunk_new (GRealString, string_mem_chunk);
229   G_UNLOCK (string_mem_chunk);
230
231   string->alloc = 0;
232   string->len   = 0;
233   string->str   = NULL;
234
235   g_string_maybe_expand (string, MAX (dfl_size, 2));
236   string->str[0] = 0;
237
238   return (GString*) string;
239 }
240
241 GString*
242 g_string_new (const gchar *init)
243 {
244   GString *string;
245
246   string = g_string_sized_new (2);
247
248   if (init)
249     g_string_append (string, init);
250
251   return string;
252 }
253
254 gchar*
255 g_string_free (GString *string,
256                gboolean free_segment)
257 {
258   gchar *segment;
259
260   g_return_val_if_fail (string != NULL, NULL);
261
262   if (free_segment)
263     {
264       g_free (string->str);
265       segment = NULL;
266     }
267   else
268     segment = string->str;
269
270   G_LOCK (string_mem_chunk);
271   g_mem_chunk_free (string_mem_chunk, string);
272   G_UNLOCK (string_mem_chunk);
273
274   return segment;
275 }
276
277 gboolean
278 g_string_equal (const GString *v,
279                 const GString *v2)
280 {
281   gchar *p, *q;
282   GRealString *string1 = (GRealString *) v;
283   GRealString *string2 = (GRealString *) v2;
284   gint i = string1->len;
285
286   if (i != string2->len)
287     return FALSE;
288
289   p = string1->str;
290   q = string2->str;
291   while (i)
292     {
293       if (*p != *q)
294         return FALSE;
295       p++;
296       q++;
297       i--;
298     }
299   return TRUE;
300 }
301
302 /* 31 bit hash function */
303 guint
304 g_string_hash (const GString *str)
305 {
306   const gchar *p = str->str;
307   gint n = str->len;
308   guint h = 0;
309
310   while (n--)
311     {
312       h = (h << 5) - h + *p;
313       p++;
314     }
315
316   return h;
317 }
318
319 GString*
320 g_string_assign (GString     *string,
321                  const gchar *rval)
322 {
323   g_return_val_if_fail (string != NULL, NULL);
324   g_return_val_if_fail (rval != NULL, string);
325   
326   g_string_truncate (string, 0);
327   g_string_append (string, rval);
328
329   return string;
330 }
331
332 GString*
333 g_string_truncate (GString *fstring,
334                    guint    len)
335 {
336   GRealString *string = (GRealString *) fstring;
337
338   g_return_val_if_fail (string != NULL, NULL);
339
340   string->len = MIN (len, string->len);
341
342   string->str[string->len] = 0;
343
344   return fstring;
345 }
346
347 GString*
348 g_string_insert_len (GString     *fstring,
349                      gint         pos,
350                      const gchar *val,
351                      gint         len)
352 {
353   GRealString *string = (GRealString *) fstring;
354
355   g_return_val_if_fail (string != NULL, NULL);
356   g_return_val_if_fail (val != NULL, fstring);
357   g_return_val_if_fail (pos <= string->len, fstring);
358
359   if (len < 0)
360     len = strlen (val);
361
362   if (pos < 0)
363     pos = string->len;
364   
365   g_string_maybe_expand (string, len);
366
367   /* If we aren't appending at the end, move a hunk
368    * of the old string to the end, opening up space
369    */
370   if (pos < string->len)
371     g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
372   
373   /* insert the new string */
374   g_memmove (string->str + pos, val, len);
375
376   string->len += len;
377
378   string->str[string->len] = 0;
379
380   return fstring;
381 }
382
383 GString*
384 g_string_append (GString     *fstring,
385                  const gchar *val)
386 {  
387   g_return_val_if_fail (fstring != NULL, NULL);
388   g_return_val_if_fail (val != NULL, fstring);
389
390   return g_string_insert_len (fstring, -1, val, -1);
391 }
392
393 GString*
394 g_string_append_len (GString     *string,
395                      const gchar *val,
396                      gint         len)
397 {
398   g_return_val_if_fail (string != NULL, NULL);
399   g_return_val_if_fail (val != NULL, string);
400
401   return g_string_insert_len (string, -1, val, len);
402 }
403
404 GString*
405 g_string_append_c (GString *fstring,
406                    gchar    c)
407 {
408   g_return_val_if_fail (fstring != NULL, NULL);
409
410   return g_string_insert_c (fstring, -1, c);
411 }
412
413 GString*
414 g_string_prepend (GString     *fstring,
415                   const gchar *val)
416 {
417   g_return_val_if_fail (fstring != NULL, NULL);
418   g_return_val_if_fail (val != NULL, fstring);
419   
420   return g_string_insert_len (fstring, 0, val, -1);
421 }
422
423 GString*
424 g_string_prepend_len (GString     *string,
425                       const gchar *val,
426                       gint         len)
427 {
428   g_return_val_if_fail (string != NULL, NULL);
429   g_return_val_if_fail (val != NULL, string);
430
431   return g_string_insert_len (string, 0, val, len);
432 }
433
434 GString*
435 g_string_prepend_c (GString *fstring,
436                     gchar    c)
437 {  
438   g_return_val_if_fail (fstring != NULL, NULL);
439   
440   return g_string_insert_c (fstring, 0, c);
441 }
442
443 GString*
444 g_string_insert (GString     *fstring,
445                  gint         pos,
446                  const gchar *val)
447 {
448   g_return_val_if_fail (fstring != NULL, NULL);
449   g_return_val_if_fail (val != NULL, fstring);
450   g_return_val_if_fail (pos <= fstring->len, fstring);
451   
452   return g_string_insert_len (fstring, pos, val, -1);
453 }
454
455 GString*
456 g_string_insert_c (GString *fstring,
457                    gint     pos,
458                    gchar    c)
459 {
460   GRealString *string = (GRealString *) fstring;
461
462   g_return_val_if_fail (string != NULL, NULL);
463   g_return_val_if_fail (pos <= string->len, fstring);
464
465   g_string_maybe_expand (string, 1);
466
467   if (pos < 0)
468     pos = string->len;
469   
470   /* If not just an append, move the old stuff */
471   if (pos < string->len)
472     g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
473
474   string->str[pos] = c;
475
476   string->len += 1;
477
478   string->str[string->len] = 0;
479
480   return fstring;
481 }
482
483 GString*
484 g_string_erase (GString *fstring,
485                 gint     pos,
486                 gint     len)
487 {
488   GRealString *string = (GRealString*)fstring;
489
490   g_return_val_if_fail (string != NULL, NULL);
491   g_return_val_if_fail (len >= 0, fstring);
492   g_return_val_if_fail (pos >= 0, fstring);
493   g_return_val_if_fail (pos <= string->len, fstring);
494   g_return_val_if_fail (pos + len <= string->len, fstring);
495
496   if (pos + len < string->len)
497     g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
498
499   string->len -= len;
500   
501   string->str[string->len] = 0;
502
503   return fstring;
504 }
505
506 GString*
507 g_string_down (GString *fstring)
508 {
509   GRealString *string = (GRealString *) fstring;
510   guchar *s;
511   gint n = string->len;
512
513   g_return_val_if_fail (string != NULL, NULL);
514
515   s = (guchar *) string->str;
516
517   while (n)
518     {
519       *s = tolower (*s);
520       s++;
521       n--;
522     }
523
524   return fstring;
525 }
526
527 GString*
528 g_string_up (GString *fstring)
529 {
530   GRealString *string = (GRealString *) fstring;
531   guchar *s;
532   gint n = string->len;
533
534   g_return_val_if_fail (string != NULL, NULL);
535
536   s = (guchar *) string->str;
537
538   while (n)
539     {
540       *s = toupper (*s);
541       s++;
542       n--;
543     }
544
545   return fstring;
546 }
547
548 static void
549 g_string_sprintfa_int (GString     *string,
550                        const gchar *fmt,
551                        va_list      args)
552 {
553   gchar *buffer;
554
555   buffer = g_strdup_vprintf (fmt, args);
556   g_string_append (string, buffer);
557   g_free (buffer);
558 }
559
560 void
561 g_string_sprintf (GString *string,
562                   const gchar *fmt,
563                   ...)
564 {
565   va_list args;
566
567   g_string_truncate (string, 0);
568
569   va_start (args, fmt);
570   g_string_sprintfa_int (string, fmt, args);
571   va_end (args);
572 }
573
574 void
575 g_string_sprintfa (GString *string,
576                    const gchar *fmt,
577                    ...)
578 {
579   va_list args;
580
581   va_start (args, fmt);
582   g_string_sprintfa_int (string, fmt, args);
583   va_end (args);
584 }