applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[platform/upstream/glib.git] / 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 void
255 g_string_free (GString *string,
256                gboolean free_segment)
257 {
258   g_return_if_fail (string != NULL);
259
260   if (free_segment)
261     g_free (string->str);
262
263   G_LOCK (string_mem_chunk);
264   g_mem_chunk_free (string_mem_chunk, string);
265   G_UNLOCK (string_mem_chunk);
266 }
267
268 gboolean
269 g_string_equal (const GString *v,
270                 const GString *v2)
271 {
272   gchar *p, *q;
273   GRealString *string1 = (GRealString *) v;
274   GRealString *string2 = (GRealString *) v2;
275   gint i = string1->len;
276
277   if (i != string2->len)
278     return FALSE;
279
280   p = string1->str;
281   q = string2->str;
282   while (i)
283     {
284       if (*p != *q)
285         return FALSE;
286       p++;
287       q++;
288       i--;
289     }
290   return TRUE;
291 }
292
293 /* 31 bit hash function */
294 guint
295 g_string_hash (const GString *str)
296 {
297   const gchar *p = str->str;
298   gint n = str->len;
299   guint h = 0;
300
301   while (n--)
302     {
303       h = (h << 5) - h + *p;
304       p++;
305     }
306
307   return h;
308 }
309
310 GString*
311 g_string_assign (GString     *string,
312                  const gchar *rval)
313 {
314   g_return_val_if_fail (string != NULL, NULL);
315   g_return_val_if_fail (rval != NULL, string);
316   
317   g_string_truncate (string, 0);
318   g_string_append (string, rval);
319
320   return string;
321 }
322
323 GString*
324 g_string_truncate (GString *fstring,
325                    guint    len)
326 {
327   GRealString *string = (GRealString *) fstring;
328
329   g_return_val_if_fail (string != NULL, NULL);
330
331   string->len = MIN (len, string->len);
332
333   string->str[string->len] = 0;
334
335   return fstring;
336 }
337
338 GString*
339 g_string_insert_len (GString     *fstring,
340                      gint         pos,
341                      const gchar *val,
342                      gint         len)
343 {
344   GRealString *string = (GRealString *) fstring;
345
346   g_return_val_if_fail (string != NULL, NULL);
347   g_return_val_if_fail (val != NULL, fstring);
348   g_return_val_if_fail (pos <= string->len, fstring);
349
350   if (len < 0)
351     len = strlen (val);
352
353   if (pos < 0)
354     pos = string->len;
355   
356   g_string_maybe_expand (string, len);
357
358   /* If we aren't appending at the end, move a hunk
359    * of the old string to the end, opening up space
360    */
361   if (pos < string->len)
362     g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
363   
364   /* insert the new string */
365   g_memmove (string->str + pos, val, len);
366
367   string->len += len;
368
369   string->str[string->len] = 0;
370
371   return fstring;
372 }
373
374 GString*
375 g_string_append (GString     *fstring,
376                  const gchar *val)
377 {  
378   g_return_val_if_fail (fstring != NULL, NULL);
379   g_return_val_if_fail (val != NULL, fstring);
380
381   return g_string_insert_len (fstring, -1, val, -1);
382 }
383
384 GString*
385 g_string_append_len (GString     *string,
386                      const gchar *val,
387                      gint         len)
388 {
389   g_return_val_if_fail (string != NULL, NULL);
390   g_return_val_if_fail (val != NULL, string);
391
392   return g_string_insert_len (string, -1, val, len);
393 }
394
395 GString*
396 g_string_append_c (GString *fstring,
397                    gchar    c)
398 {
399   g_return_val_if_fail (fstring != NULL, NULL);
400
401   return g_string_insert_c (fstring, -1, c);
402 }
403
404 GString*
405 g_string_prepend (GString     *fstring,
406                   const gchar *val)
407 {
408   g_return_val_if_fail (fstring != NULL, NULL);
409   g_return_val_if_fail (val != NULL, fstring);
410   
411   return g_string_insert_len (fstring, 0, val, -1);
412 }
413
414 GString*
415 g_string_prepend_len (GString     *string,
416                       const gchar *val,
417                       gint         len)
418 {
419   g_return_val_if_fail (string != NULL, NULL);
420   g_return_val_if_fail (val != NULL, string);
421
422   return g_string_insert_len (string, 0, val, len);
423 }
424
425 GString*
426 g_string_prepend_c (GString *fstring,
427                     gchar    c)
428 {  
429   g_return_val_if_fail (fstring != NULL, NULL);
430   
431   return g_string_insert_c (fstring, 0, c);
432 }
433
434 GString*
435 g_string_insert (GString     *fstring,
436                  gint         pos,
437                  const gchar *val)
438 {
439   g_return_val_if_fail (fstring != NULL, NULL);
440   g_return_val_if_fail (val != NULL, fstring);
441   g_return_val_if_fail (pos <= fstring->len, fstring);
442   
443   return g_string_insert_len (fstring, pos, val, -1);
444 }
445
446 GString*
447 g_string_insert_c (GString *fstring,
448                    gint     pos,
449                    gchar    c)
450 {
451   GRealString *string = (GRealString *) fstring;
452
453   g_return_val_if_fail (string != NULL, NULL);
454   g_return_val_if_fail (pos <= string->len, fstring);
455
456   g_string_maybe_expand (string, 1);
457
458   if (pos < 0)
459     pos = string->len;
460   
461   /* If not just an append, move the old stuff */
462   if (pos < string->len)
463     g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
464
465   string->str[pos] = c;
466
467   string->len += 1;
468
469   string->str[string->len] = 0;
470
471   return fstring;
472 }
473
474 GString*
475 g_string_erase (GString *fstring,
476                 gint     pos,
477                 gint     len)
478 {
479   GRealString *string = (GRealString*)fstring;
480
481   g_return_val_if_fail (string != NULL, NULL);
482   g_return_val_if_fail (len >= 0, fstring);
483   g_return_val_if_fail (pos >= 0, fstring);
484   g_return_val_if_fail (pos <= string->len, fstring);
485   g_return_val_if_fail (pos + len <= string->len, fstring);
486
487   if (pos + len < string->len)
488     g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
489
490   string->len -= len;
491   
492   string->str[string->len] = 0;
493
494   return fstring;
495 }
496
497 GString*
498 g_string_down (GString *fstring)
499 {
500   GRealString *string = (GRealString *) fstring;
501   guchar *s;
502   gint n = string->len;
503
504   g_return_val_if_fail (string != NULL, NULL);
505
506   s = string->str;
507
508   while (n)
509     {
510       *s = tolower (*s);
511       s++;
512       n--;
513     }
514
515   return fstring;
516 }
517
518 GString*
519 g_string_up (GString *fstring)
520 {
521   GRealString *string = (GRealString *) fstring;
522   guchar *s;
523   gint n = string->len;
524
525   g_return_val_if_fail (string != NULL, NULL);
526
527   s = string->str;
528
529   while (n)
530     {
531       *s = toupper (*s);
532       s++;
533       n--;
534     }
535
536   return fstring;
537 }
538
539 static void
540 g_string_sprintfa_int (GString     *string,
541                        const gchar *fmt,
542                        va_list      args)
543 {
544   gchar *buffer;
545
546   buffer = g_strdup_vprintf (fmt, args);
547   g_string_append (string, buffer);
548   g_free (buffer);
549 }
550
551 void
552 g_string_sprintf (GString *string,
553                   const gchar *fmt,
554                   ...)
555 {
556   va_list args;
557
558   g_string_truncate (string, 0);
559
560   va_start (args, fmt);
561   g_string_sprintfa_int (string, fmt, args);
562   va_end (args);
563 }
564
565 void
566 g_string_sprintfa (GString *string,
567                    const gchar *fmt,
568                    ...)
569 {
570   va_list args;
571
572   va_start (args, fmt);
573   g_string_sprintfa_int (string, fmt, args);
574   va_end (args);
575 }