Changes for 64-bit cleanliness, loosely based on patch from Mark Murnane.
[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 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 #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->alloc)
216     {
217       string->alloc = nearest_power (1, string->len + len + 1);
218       string->str = g_realloc (string->str, string->alloc);
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->alloc = 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 GString*
372 g_string_insert_len (GString     *fstring,
373                      gssize       pos,    
374                      const gchar *val,
375                      gssize       len)    
376 {
377   GRealString *string = (GRealString *) fstring;
378
379   g_return_val_if_fail (string != NULL, NULL);
380   g_return_val_if_fail (val != NULL, fstring);
381
382   if (len < 0)
383     len = strlen (val);
384
385   if (pos < 0)
386     pos = string->len;
387   else
388     g_return_val_if_fail (pos <= string->len, fstring);
389   
390   g_string_maybe_expand (string, len);
391
392   /* If we aren't appending at the end, move a hunk
393    * of the old string to the end, opening up space
394    */
395   if (pos < string->len)
396     g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
397   
398   /* insert the new string */
399   g_memmove (string->str + pos, val, len);
400
401   string->len += len;
402
403   string->str[string->len] = 0;
404
405   return fstring;
406 }
407
408 GString*
409 g_string_append (GString     *fstring,
410                  const gchar *val)
411 {  
412   g_return_val_if_fail (fstring != NULL, NULL);
413   g_return_val_if_fail (val != NULL, fstring);
414
415   return g_string_insert_len (fstring, -1, val, -1);
416 }
417
418 GString*
419 g_string_append_len (GString     *string,
420                      const gchar *val,
421                      gssize       len)    
422 {
423   g_return_val_if_fail (string != NULL, NULL);
424   g_return_val_if_fail (val != NULL, string);
425
426   return g_string_insert_len (string, -1, val, len);
427 }
428
429 GString*
430 g_string_append_c (GString *fstring,
431                    gchar    c)
432 {
433   g_return_val_if_fail (fstring != NULL, NULL);
434
435   return g_string_insert_c (fstring, -1, c);
436 }
437
438 GString*
439 g_string_prepend (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, 0, val, -1);
446 }
447
448 GString*
449 g_string_prepend_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, 0, val, len);
457 }
458
459 GString*
460 g_string_prepend_c (GString *fstring,
461                     gchar    c)
462 {  
463   g_return_val_if_fail (fstring != NULL, NULL);
464   
465   return g_string_insert_c (fstring, 0, c);
466 }
467
468 GString*
469 g_string_insert (GString     *fstring,
470                  gssize       pos,    
471                  const gchar *val)
472 {
473   g_return_val_if_fail (fstring != NULL, NULL);
474   g_return_val_if_fail (val != NULL, fstring);
475   if (pos >= 0)
476     g_return_val_if_fail (pos <= fstring->len, fstring);
477   
478   return g_string_insert_len (fstring, pos, val, -1);
479 }
480
481 GString*
482 g_string_insert_c (GString *fstring,
483                    gssize   pos,    
484                    gchar    c)
485 {
486   GRealString *string = (GRealString *) fstring;
487
488   g_return_val_if_fail (string != NULL, NULL);
489
490   g_string_maybe_expand (string, 1);
491
492   if (pos < 0)
493     pos = string->len;
494   else
495     g_return_val_if_fail (pos <= string->len, fstring);
496   
497   /* If not just an append, move the old stuff */
498   if (pos < string->len)
499     g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
500
501   string->str[pos] = c;
502
503   string->len += 1;
504
505   string->str[string->len] = 0;
506
507   return fstring;
508 }
509
510 GString*
511 g_string_erase (GString *fstring,
512                 gsize    pos,    
513                 gsize    len)    
514 {
515   GRealString *string = (GRealString*)fstring;
516
517   g_return_val_if_fail (string != NULL, NULL);
518   g_return_val_if_fail (pos >= 0, fstring);
519   g_return_val_if_fail (pos <= string->len, fstring);
520
521   if (len < 0)
522     len = string->len - pos;
523   else
524     {
525       g_return_val_if_fail (pos + len <= string->len, fstring);
526
527       if (pos + len < string->len)
528         g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
529     }
530
531   string->len -= len;
532   
533   string->str[string->len] = 0;
534
535   return fstring;
536 }
537
538 GString*
539 g_string_down (GString *fstring)
540 {
541   GRealString *string = (GRealString *) fstring;
542   guchar *s;
543   glong n = string->len;    
544
545   g_return_val_if_fail (string != NULL, NULL);
546
547   s = (guchar *) string->str;
548
549   while (n)
550     {
551       *s = tolower (*s);
552       s++;
553       n--;
554     }
555
556   return fstring;
557 }
558
559 GString*
560 g_string_up (GString *fstring)
561 {
562   GRealString *string = (GRealString *) fstring;
563   guchar *s;
564   glong n = string->len;
565
566   g_return_val_if_fail (string != NULL, NULL);
567
568   s = (guchar *) string->str;
569
570   while (n)
571     {
572       *s = toupper (*s);
573       s++;
574       n--;
575     }
576
577   return fstring;
578 }
579
580 static void
581 g_string_printfa_internal (GString     *string,
582                            const gchar *fmt,
583                            va_list      args)
584 {
585   gchar *buffer;
586
587   buffer = g_strdup_vprintf (fmt, args);
588   g_string_append (string, buffer);
589   g_free (buffer);
590 }
591
592 void
593 g_string_printf (GString *string,
594                  const gchar *fmt,
595                  ...)
596 {
597   va_list args;
598
599   g_string_truncate (string, 0);
600
601   va_start (args, fmt);
602   g_string_printfa_internal (string, fmt, args);
603   va_end (args);
604 }
605
606 void
607 g_string_printfa (GString *string,
608                   const gchar *fmt,
609                   ...)
610 {
611   va_list args;
612
613   va_start (args, fmt);
614   g_string_printfa_internal (string, fmt, args);
615   va_end (args);
616 }