6a6a39d89c3969135dd5ef1fa4060609567ec3a2
[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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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  * MT safe
22  */
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include "glib.h"
30
31
32 typedef struct _GRealStringChunk GRealStringChunk;
33 typedef struct _GRealString      GRealString;
34
35 struct _GRealStringChunk
36 {
37   GHashTable *const_table;
38   GSList     *storage_list;
39   gint        storage_next;
40   gint        this_size;
41   gint        default_size;
42 };
43
44 struct _GRealString
45 {
46   gchar *str;
47   gint   len;
48   gint   alloc;
49 };
50
51 G_LOCK_DEFINE_STATIC (string_mem_chunk);
52 static GMemChunk *string_mem_chunk = NULL;
53
54 /* Hash Functions.
55  */
56
57 gint
58 g_str_equal (gconstpointer v, gconstpointer v2)
59 {
60   return strcmp ((const gchar*) v, (const gchar*)v2) == 0;
61 }
62
63 /* a char* hash function from ASU */
64 guint
65 g_str_hash (gconstpointer v)
66 {
67   const char *s = (char*)v;
68   const char *p;
69   guint h=0, g;
70
71   for(p = s; *p != '\0'; p += 1) {
72     h = ( h << 4 ) + *p;
73     if ( ( g = h & 0xf0000000 ) ) {
74       h = h ^ (g >> 24);
75       h = h ^ g;
76     }
77   }
78
79   return h /* % M */;
80 }
81
82
83 /* String Chunks.
84  */
85
86 GStringChunk*
87 g_string_chunk_new (gint default_size)
88 {
89   GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1);
90   gint size = 1;
91
92   while (size < default_size)
93     size <<= 1;
94
95   new_chunk->const_table       = NULL;
96   new_chunk->storage_list      = NULL;
97   new_chunk->storage_next      = size;
98   new_chunk->default_size      = size;
99   new_chunk->this_size         = size;
100
101   return (GStringChunk*) new_chunk;
102 }
103
104 void
105 g_string_chunk_free (GStringChunk *fchunk)
106 {
107   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
108   GSList *tmp_list;
109
110   g_return_if_fail (chunk != NULL);
111
112   if (chunk->storage_list)
113     {
114       for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
115         g_free (tmp_list->data);
116
117       g_slist_free (chunk->storage_list);
118     }
119
120   if (chunk->const_table)
121     g_hash_table_destroy (chunk->const_table);
122
123   g_free (chunk);
124 }
125
126 gchar*
127 g_string_chunk_insert (GStringChunk *fchunk,
128                        const gchar  *string)
129 {
130   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
131   gint len = strlen (string);
132   char* pos;
133
134   g_return_val_if_fail (chunk != NULL, NULL);
135
136   if ((chunk->storage_next + len + 1) > chunk->this_size)
137     {
138       gint new_size = chunk->default_size;
139
140       while (new_size < len+1)
141         new_size <<= 1;
142
143       chunk->storage_list = g_slist_prepend (chunk->storage_list,
144                                              g_new (char, new_size));
145
146       chunk->this_size = new_size;
147       chunk->storage_next = 0;
148     }
149
150   pos = ((char*)chunk->storage_list->data) + chunk->storage_next;
151
152   strcpy (pos, string);
153
154   chunk->storage_next += len + 1;
155
156   return pos;
157 }
158
159 gchar*
160 g_string_chunk_insert_const (GStringChunk *fchunk,
161                              const gchar  *string)
162 {
163   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
164   char* lookup;
165
166   g_return_val_if_fail (chunk != NULL, NULL);
167
168   if (!chunk->const_table)
169     chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
170
171   lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
172
173   if (!lookup)
174     {
175       lookup = g_string_chunk_insert (fchunk, string);
176       g_hash_table_insert (chunk->const_table, lookup, lookup);
177     }
178
179   return lookup;
180 }
181
182 /* Strings.
183  */
184 static gint
185 nearest_pow (gint num)
186 {
187   gint n = 1;
188
189   while (n < num)
190     n <<= 1;
191
192   return n;
193 }
194
195 static void
196 g_string_maybe_expand (GRealString* string, gint len)
197 {
198   if (string->len + len >= string->alloc)
199     {
200       string->alloc = nearest_pow (string->len + len + 1);
201       string->str = g_realloc (string->str, string->alloc);
202     }
203 }
204
205 GString*
206 g_string_sized_new (guint dfl_size)
207 {
208   GRealString *string;
209
210   G_LOCK (string_mem_chunk);
211   if (!string_mem_chunk)
212     string_mem_chunk = g_mem_chunk_new ("string mem chunk",
213                                         sizeof (GRealString),
214                                         1024, G_ALLOC_AND_FREE);
215
216   string = g_chunk_new (GRealString, string_mem_chunk);
217   G_UNLOCK (string_mem_chunk);
218
219   string->alloc = 0;
220   string->len   = 0;
221   string->str   = NULL;
222
223   g_string_maybe_expand (string, MAX (dfl_size, 2));
224   string->str[0] = 0;
225
226   return (GString*) string;
227 }
228
229 GString*
230 g_string_new (const gchar *init)
231 {
232   GString *string;
233
234   string = g_string_sized_new (2);
235
236   if (init)
237     g_string_append (string, init);
238
239   return string;
240 }
241
242 void
243 g_string_free (GString *string,
244                gint free_segment)
245 {
246   g_return_if_fail (string != NULL);
247
248   if (free_segment)
249     g_free (string->str);
250
251   G_LOCK (string_mem_chunk);
252   g_mem_chunk_free (string_mem_chunk, string);
253   G_UNLOCK (string_mem_chunk);
254 }
255
256 GString*
257 g_string_assign (GString *lval,
258                  const gchar *rval)
259 {
260   g_string_truncate (lval, 0);
261   g_string_append (lval, rval);
262
263   return lval;
264 }
265
266 GString*
267 g_string_truncate (GString* fstring,
268                    gint len)
269 {
270   GRealString *string = (GRealString*)fstring;
271
272   g_return_val_if_fail (string != NULL, NULL);
273
274   string->len = len;
275
276   string->str[len] = 0;
277
278   return fstring;
279 }
280
281 GString*
282 g_string_append (GString *fstring,
283                  const gchar *val)
284 {
285   GRealString *string = (GRealString*)fstring;
286   int len;
287
288   g_return_val_if_fail (string != NULL, NULL);
289   g_return_val_if_fail (val != NULL, fstring);
290   
291   len = strlen (val);
292   g_string_maybe_expand (string, len);
293
294   strcpy (string->str + string->len, val);
295
296   string->len += len;
297
298   return fstring;
299 }
300
301 GString*
302 g_string_append_c (GString *fstring,
303                    gchar c)
304 {
305   GRealString *string = (GRealString*)fstring;
306
307   g_return_val_if_fail (string != NULL, NULL);
308   g_string_maybe_expand (string, 1);
309
310   string->str[string->len++] = c;
311   string->str[string->len] = 0;
312
313   return fstring;
314 }
315
316 GString*
317 g_string_prepend (GString *fstring,
318                   const gchar *val)
319 {
320   GRealString *string = (GRealString*)fstring;
321   gint len;
322
323   g_return_val_if_fail (string != NULL, NULL);
324   g_return_val_if_fail (val != NULL, fstring);
325
326   len = strlen (val);
327   g_string_maybe_expand (string, len);
328
329   g_memmove (string->str + len, string->str, string->len);
330
331   strncpy (string->str, val, len);
332
333   string->len += len;
334
335   string->str[string->len] = 0;
336
337   return fstring;
338 }
339
340 GString*
341 g_string_prepend_c (GString *fstring,
342                     gchar    c)
343 {
344   GRealString *string = (GRealString*)fstring;
345
346   g_return_val_if_fail (string != NULL, NULL);
347   g_string_maybe_expand (string, 1);
348
349   g_memmove (string->str + 1, string->str, string->len);
350
351   string->str[0] = c;
352
353   string->len += 1;
354
355   string->str[string->len] = 0;
356
357   return fstring;
358 }
359
360 GString*
361 g_string_insert (GString     *fstring,
362                  gint         pos,
363                  const gchar *val)
364 {
365   GRealString *string = (GRealString*)fstring;
366   gint len;
367
368   g_return_val_if_fail (string != NULL, NULL);
369   g_return_val_if_fail (val != NULL, fstring);
370   g_return_val_if_fail (pos >= 0, fstring);
371   g_return_val_if_fail (pos <= string->len, fstring);
372
373   len = strlen (val);
374   g_string_maybe_expand (string, len);
375
376   g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
377
378   strncpy (string->str + pos, val, len);
379
380   string->len += len;
381
382   string->str[string->len] = 0;
383
384   return fstring;
385 }
386
387 GString *
388 g_string_insert_c (GString *fstring,
389                    gint     pos,
390                    gchar    c)
391 {
392   GRealString *string = (GRealString*)fstring;
393
394   g_return_val_if_fail (string != NULL, NULL);
395   g_return_val_if_fail (pos <= string->len, fstring);
396
397   g_string_maybe_expand (string, 1);
398
399   g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
400
401   string->str[pos] = c;
402
403   string->len += 1;
404
405   string->str[string->len] = 0;
406
407   return fstring;
408 }
409
410 GString*
411 g_string_erase (GString *fstring,
412                 gint pos,
413                 gint len)
414 {
415   GRealString *string = (GRealString*)fstring;
416
417   g_return_val_if_fail (string != NULL, NULL);
418   g_return_val_if_fail (len >= 0, fstring);
419   g_return_val_if_fail (pos >= 0, fstring);
420   g_return_val_if_fail (pos <= string->len, fstring);
421   g_return_val_if_fail (pos + len <= string->len, fstring);
422
423   if (pos + len < string->len)
424     g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
425
426   string->len -= len;
427   
428   string->str[string->len] = 0;
429
430   return fstring;
431 }
432
433 GString*
434 g_string_down (GString *fstring)
435 {
436   GRealString *string = (GRealString*)fstring;
437   gchar *s;
438
439   g_return_val_if_fail (string != NULL, NULL);
440
441   s = string->str;
442
443   while (*s)
444     {
445       *s = tolower (*s);
446       s++;
447     }
448
449   return fstring;
450 }
451
452 GString*
453 g_string_up (GString *fstring)
454 {
455   GRealString *string = (GRealString*)fstring;
456   gchar *s;
457
458   g_return_val_if_fail (string != NULL, NULL);
459
460   s = string->str;
461
462   while (*s)
463     {
464       *s = toupper (*s);
465       s++;
466     }
467
468   return fstring;
469 }
470
471 static void
472 g_string_sprintfa_int (GString     *string,
473                        const gchar *fmt,
474                        va_list      args)
475 {
476   gchar *buffer;
477
478   buffer = g_strdup_vprintf (fmt, args);
479   g_string_append (string, buffer);
480   g_free (buffer);
481 }
482
483 void
484 g_string_sprintf (GString *string,
485                   const gchar *fmt,
486                   ...)
487 {
488   va_list args;
489
490   g_string_truncate (string, 0);
491
492   va_start (args, fmt);
493   g_string_sprintfa_int (string, fmt, args);
494   va_end (args);
495 }
496
497 void
498 g_string_sprintfa (GString *string,
499                    const gchar *fmt,
500                    ...)
501 {
502   va_list args;
503
504   va_start (args, fmt);
505   g_string_sprintfa_int (string, fmt, args);
506   va_end (args);
507 }