source: trunk/third/glib2/glib/gstring.c @ 20721

Revision 20721, 17.6 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20720, which included commits to RCS files with non-trunk default branches.
Line 
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#include "config.h"
32
33#ifdef HAVE_UNISTD_H
34#include <unistd.h>
35#endif
36#include <stdarg.h>
37#include <stdlib.h>
38#include <stdio.h>
39#include <string.h>
40#include <ctype.h>
41
42#include "glib.h"
43#include "gprintf.h"
44
45
46struct _GStringChunk
47{
48  GHashTable *const_table;
49  GSList     *storage_list;
50  gsize       storage_next;   
51  gsize       this_size;       
52  gsize       default_size;   
53};
54
55G_LOCK_DEFINE_STATIC (string_mem_chunk);
56static GMemChunk *string_mem_chunk = NULL;
57
58/* Hash Functions.
59 */
60
61gboolean
62g_str_equal (gconstpointer v1,
63             gconstpointer v2)
64{
65  const gchar *string1 = v1;
66  const gchar *string2 = v2;
67 
68  return strcmp (string1, string2) == 0;
69}
70
71/* 31 bit hash function */
72guint
73g_str_hash (gconstpointer key)
74{
75  const char *p = key;
76  guint h = *p;
77
78  if (h)
79    for (p += 1; *p != '\0'; p++)
80      h = (h << 5) - h + *p;
81
82  return h;
83}
84
85#define MY_MAXSIZE ((gsize)-1)
86
87static inline gsize
88nearest_power (gsize base, gsize num)   
89{
90  if (num > MY_MAXSIZE / 2)
91    {
92      return MY_MAXSIZE;
93    }
94  else
95    {
96      gsize n = base;
97
98      while (n < num)
99        n <<= 1;
100     
101      return n;
102    }
103}
104
105/* String Chunks.
106 */
107
108GStringChunk*
109g_string_chunk_new (gsize default_size)   
110{
111  GStringChunk *new_chunk = g_new (GStringChunk, 1);
112  gsize size = 1;   
113
114  size = nearest_power (1, default_size);
115
116  new_chunk->const_table       = NULL;
117  new_chunk->storage_list      = NULL;
118  new_chunk->storage_next      = size;
119  new_chunk->default_size      = size;
120  new_chunk->this_size         = size;
121
122  return new_chunk;
123}
124
125void
126g_string_chunk_free (GStringChunk *chunk)
127{
128  GSList *tmp_list;
129
130  g_return_if_fail (chunk != NULL);
131
132  if (chunk->storage_list)
133    {
134      for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
135        g_free (tmp_list->data);
136
137      g_slist_free (chunk->storage_list);
138    }
139
140  if (chunk->const_table)
141    g_hash_table_destroy (chunk->const_table);
142
143  g_free (chunk);
144}
145
146gchar*
147g_string_chunk_insert (GStringChunk *chunk,
148                       const gchar  *string)
149{
150  g_return_val_if_fail (chunk != NULL, NULL);
151
152  return g_string_chunk_insert_len (chunk, string, -1);
153}
154
155gchar*
156g_string_chunk_insert_const (GStringChunk *chunk,
157                             const gchar  *string)
158{
159  char* lookup;
160
161  g_return_val_if_fail (chunk != NULL, NULL);
162
163  if (!chunk->const_table)
164    chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
165
166  lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
167
168  if (!lookup)
169    {
170      lookup = g_string_chunk_insert (chunk, string);
171      g_hash_table_insert (chunk->const_table, lookup, lookup);
172    }
173
174  return lookup;
175}
176
177/**
178 * g_string_chunk_insert_len:
179 * @chunk: a #GStringChunk
180 * @string: bytes to insert
181 * @len: number of bytes of @string to insert, or -1 to insert a
182 *     nul-terminated string.
183 *
184 * Adds a copy of the first @len bytes of @string to the #GStringChunk. The
185 * copy is nul-terminated.
186 *
187 * The characters in the string can be changed, if necessary, though you
188 * should not change anything after the end of the string.
189 *
190 * Return value: a pointer to the copy of @string within the #GStringChunk
191 *
192 * Since: 2.4
193 **/
194gchar*
195g_string_chunk_insert_len (GStringChunk *chunk,
196                           const gchar  *string,
197                           gssize        len)
198{
199  gchar* pos;
200
201  g_return_val_if_fail (chunk != NULL, NULL);
202
203  if (len < 0)
204    len = strlen (string);
205 
206  if ((chunk->storage_next + len + 1) > chunk->this_size)
207    {
208      gsize new_size = nearest_power (chunk->default_size, len + 1);
209
210      chunk->storage_list = g_slist_prepend (chunk->storage_list,
211                                             g_new (gchar, new_size));
212
213      chunk->this_size = new_size;
214      chunk->storage_next = 0;
215    }
216
217  pos = ((gchar *) chunk->storage_list->data) + chunk->storage_next;
218
219  *(pos + len) = '\0';
220
221  strncpy (pos, string, len);
222  len = strlen (pos);
223
224  chunk->storage_next += len + 1;
225
226  return pos;
227}
228
229/* Strings.
230 */
231static void
232g_string_maybe_expand (GString* string,
233                       gsize    len)
234{
235  if (string->len + len >= string->allocated_len)
236    {
237      string->allocated_len = nearest_power (1, string->len + len + 1);
238      string->str = g_realloc (string->str, string->allocated_len);
239    }
240}
241
242GString*
243g_string_sized_new (gsize dfl_size)   
244{
245  GString *string;
246
247  G_LOCK (string_mem_chunk);
248  if (!string_mem_chunk)
249    string_mem_chunk = g_mem_chunk_new ("string mem chunk",
250                                        sizeof (GString),
251                                        1024, G_ALLOC_AND_FREE);
252
253  string = g_chunk_new (GString, string_mem_chunk);
254  G_UNLOCK (string_mem_chunk);
255
256  string->allocated_len = 0;
257  string->len   = 0;
258  string->str   = NULL;
259
260  g_string_maybe_expand (string, MAX (dfl_size, 2));
261  string->str[0] = 0;
262
263  return string;
264}
265
266GString*
267g_string_new (const gchar *init)
268{
269  GString *string;
270
271  if (init == NULL || *init == '\0')
272    string = g_string_sized_new (2);
273  else
274    {
275      gint len;
276
277      len = strlen (init);
278      string = g_string_sized_new (len + 2);
279
280      g_string_append_len (string, init, len);
281    }
282
283  return string;
284}
285
286GString*
287g_string_new_len (const gchar *init,
288                  gssize       len)   
289{
290  GString *string;
291
292  if (len < 0)
293    return g_string_new (init);
294  else
295    {
296      string = g_string_sized_new (len);
297     
298      if (init)
299        g_string_append_len (string, init, len);
300     
301      return string;
302    }
303}
304
305gchar*
306g_string_free (GString *string,
307               gboolean free_segment)
308{
309  gchar *segment;
310
311  g_return_val_if_fail (string != NULL, NULL);
312
313  if (free_segment)
314    {
315      g_free (string->str);
316      segment = NULL;
317    }
318  else
319    segment = string->str;
320
321  G_LOCK (string_mem_chunk);
322  g_mem_chunk_free (string_mem_chunk, string);
323  G_UNLOCK (string_mem_chunk);
324
325  return segment;
326}
327
328gboolean
329g_string_equal (const GString *v,
330                const GString *v2)
331{
332  gchar *p, *q;
333  GString *string1 = (GString *) v;
334  GString *string2 = (GString *) v2;
335  gsize i = string1->len;   
336
337  if (i != string2->len)
338    return FALSE;
339
340  p = string1->str;
341  q = string2->str;
342  while (i)
343    {
344      if (*p != *q)
345        return FALSE;
346      p++;
347      q++;
348      i--;
349    }
350  return TRUE;
351}
352
353/* 31 bit hash function */
354guint
355g_string_hash (const GString *str)
356{
357  const gchar *p = str->str;
358  gsize n = str->len;   
359  guint h = 0;
360
361  while (n--)
362    {
363      h = (h << 5) - h + *p;
364      p++;
365    }
366
367  return h;
368}
369
370GString*
371g_string_assign (GString     *string,
372                 const gchar *rval)
373{
374  g_return_val_if_fail (string != NULL, NULL);
375  g_return_val_if_fail (rval != NULL, string);
376
377  /* Make sure assigning to itself doesn't corrupt the string.  */
378  if (string->str != rval)
379    {
380      /* Assigning from substring should be ok since g_string_truncate
381         does not realloc.  */
382      g_string_truncate (string, 0);
383      g_string_append (string, rval);
384    }
385
386  return string;
387}
388
389GString*
390g_string_truncate (GString *string,
391                   gsize    len)   
392{
393  g_return_val_if_fail (string != NULL, NULL);
394
395  string->len = MIN (len, string->len);
396  string->str[string->len] = 0;
397
398  return string;
399}
400
401/**
402 * g_string_set_size:
403 * @string: a #GString
404 * @len: the new length
405 *
406 * Sets the length of a #GString. If the length is less than
407 * the current length, the string will be truncated. If the
408 * length is greater than the current length, the contents
409 * of the newly added area are undefined. (However, as
410 * always, string->str[string->len] will be a nul byte.)
411 *
412 * Return value: @string
413 **/
414GString*
415g_string_set_size (GString *string,
416                   gsize    len)   
417{
418  g_return_val_if_fail (string != NULL, NULL);
419
420  if (len >= string->allocated_len)
421    g_string_maybe_expand (string, len - string->len);
422 
423  string->len = len;
424  string->str[len] = 0;
425
426  return string;
427}
428
429GString*
430g_string_insert_len (GString     *string,
431                     gssize       pos,   
432                     const gchar *val,
433                     gssize       len)   
434{
435  g_return_val_if_fail (string != NULL, NULL);
436  g_return_val_if_fail (val != NULL, string);
437
438  if (len < 0)
439    len = strlen (val);
440
441  if (pos < 0)
442    pos = string->len;
443  else
444    g_return_val_if_fail (pos <= string->len, string);
445
446  /* Check whether val represents a substring of string.  This test
447     probably violates chapter and verse of the C standards, since
448     ">=" and "<=" are only valid when val really is a substring.
449     In practice, it will work on modern archs.  */
450  if (val >= string->str && val <= string->str + string->len)
451    {
452      gsize offset = val - string->str;
453      gsize precount = 0;
454
455      g_string_maybe_expand (string, len);
456      val = string->str + offset;
457      /* At this point, val is valid again.  */
458
459      /* Open up space where we are going to insert.  */
460      if (pos < string->len)
461        g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
462
463      /* Move the source part before the gap, if any.  */
464      if (offset < pos)
465        {
466          precount = MIN (len, pos - offset);
467          memcpy (string->str + pos, val, precount);
468        }
469
470      /* Move the source part after the gap, if any.  */
471      if (len > precount)
472        memcpy (string->str + pos + precount,
473                val + /* Already moved: */ precount + /* Space opened up: */ len,
474                len - precount);
475    }
476  else
477    {
478      g_string_maybe_expand (string, len);
479
480      /* If we aren't appending at the end, move a hunk
481       * of the old string to the end, opening up space
482       */
483      if (pos < string->len)
484        g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
485
486      /* insert the new string */
487      memcpy (string->str + pos, val, len);
488    }
489
490  string->len += len;
491
492  string->str[string->len] = 0;
493
494  return string;
495}
496
497GString*
498g_string_append (GString     *string,
499                 const gchar *val)
500
501  g_return_val_if_fail (string != NULL, NULL);
502  g_return_val_if_fail (val != NULL, string);
503
504  return g_string_insert_len (string, -1, val, -1);
505}
506
507GString*
508g_string_append_len (GString     *string,
509                     const gchar *val,
510                     gssize       len)   
511{
512  g_return_val_if_fail (string != NULL, NULL);
513  g_return_val_if_fail (val != NULL, string);
514
515  return g_string_insert_len (string, -1, val, len);
516}
517
518#undef g_string_append_c
519GString*
520g_string_append_c (GString *string,
521                   gchar    c)
522{
523  g_return_val_if_fail (string != NULL, NULL);
524
525  return g_string_insert_c (string, -1, c);
526}
527
528/**
529 * g_string_append_unichar:
530 * @string: a #GString
531 * @wc: a Unicode character
532 *
533 * Converts a Unicode character into UTF-8, and appends it
534 * to the string.
535 *
536 * Return value: @string
537 **/
538GString*
539g_string_append_unichar (GString  *string,
540                         gunichar  wc)
541
542  g_return_val_if_fail (string != NULL, NULL);
543 
544  return g_string_insert_unichar (string, -1, wc);
545}
546
547GString*
548g_string_prepend (GString     *string,
549                  const gchar *val)
550{
551  g_return_val_if_fail (string != NULL, NULL);
552  g_return_val_if_fail (val != NULL, string);
553 
554  return g_string_insert_len (string, 0, val, -1);
555}
556
557GString*
558g_string_prepend_len (GString     *string,
559                      const gchar *val,
560                      gssize       len)   
561{
562  g_return_val_if_fail (string != NULL, NULL);
563  g_return_val_if_fail (val != NULL, string);
564
565  return g_string_insert_len (string, 0, val, len);
566}
567
568GString*
569g_string_prepend_c (GString *string,
570                    gchar    c)
571
572  g_return_val_if_fail (string != NULL, NULL);
573 
574  return g_string_insert_c (string, 0, c);
575}
576
577/**
578 * g_string_prepend_unichar:
579 * @string: a #GString.
580 * @wc: a Unicode character.
581 *
582 * Converts a Unicode character into UTF-8, and prepends it
583 * to the string.
584 *
585 * Return value: @string.
586 **/
587GString*
588g_string_prepend_unichar (GString  *string,
589                          gunichar  wc)
590
591  g_return_val_if_fail (string != NULL, NULL);
592 
593  return g_string_insert_unichar (string, 0, wc);
594}
595
596GString*
597g_string_insert (GString     *string,
598                 gssize       pos,   
599                 const gchar *val)
600{
601  g_return_val_if_fail (string != NULL, NULL);
602  g_return_val_if_fail (val != NULL, string);
603  if (pos >= 0)
604    g_return_val_if_fail (pos <= string->len, string);
605 
606  return g_string_insert_len (string, pos, val, -1);
607}
608
609GString*
610g_string_insert_c (GString *string,
611                   gssize   pos,   
612                   gchar    c)
613{
614  g_return_val_if_fail (string != NULL, NULL);
615
616  g_string_maybe_expand (string, 1);
617
618  if (pos < 0)
619    pos = string->len;
620  else
621    g_return_val_if_fail (pos <= string->len, string);
622 
623  /* If not just an append, move the old stuff */
624  if (pos < string->len)
625    g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
626
627  string->str[pos] = c;
628
629  string->len += 1;
630
631  string->str[string->len] = 0;
632
633  return string;
634}
635
636/**
637 * g_string_insert_unichar:
638 * @string: a #GString
639 * @pos: the position at which to insert character, or -1 to
640 *       append at the end of the string.
641 * @wc: a Unicode character
642 *
643 * Converts a Unicode character into UTF-8, and insert it
644 * into the string at the given position.
645 *
646 * Return value: @string
647 **/
648GString*
649g_string_insert_unichar (GString *string,
650                         gssize   pos,   
651                         gunichar wc)
652
653  gchar buf[6];
654  gint charlen;
655
656  /* We could be somewhat more efficient here by computing
657   * the length, adding the space, then converting into that
658   * space, by cut-and-pasting the internals of g_unichar_to_utf8.
659   */
660  g_return_val_if_fail (string != NULL, NULL);
661
662  charlen = g_unichar_to_utf8 (wc, buf);
663  return g_string_insert_len (string, pos, buf, charlen);
664}
665
666GString*
667g_string_erase (GString *string,
668                gssize   pos,
669                gssize   len)
670{
671  g_return_val_if_fail (string != NULL, NULL);
672  g_return_val_if_fail (pos >= 0, string);
673  g_return_val_if_fail (pos <= string->len, string);
674
675  if (len < 0)
676    len = string->len - pos;
677  else
678    {
679      g_return_val_if_fail (pos + len <= string->len, string);
680
681      if (pos + len < string->len)
682        g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
683    }
684
685  string->len -= len;
686 
687  string->str[string->len] = 0;
688
689  return string;
690}
691
692/**
693 * g_string_ascii_down:
694 * @string: a GString
695 *
696 * Converts all upper case ASCII letters to lower case ASCII letters.
697 *
698 * Return value: passed-in @string pointer, with all the upper case
699 *               characters converted to lower case in place, with
700 *               semantics that exactly match g_ascii_tolower.
701 **/
702GString*
703g_string_ascii_down (GString *string)
704{
705  gchar *s;
706  gint n;
707
708  g_return_val_if_fail (string != NULL, NULL);
709
710  n = string->len;
711  s = string->str;
712
713  while (n)
714    {
715      *s = g_ascii_tolower (*s);
716      s++;
717      n--;
718    }
719
720  return string;
721}
722
723/**
724 * g_string_ascii_up:
725 * @string: a GString
726 *
727 * Converts all lower case ASCII letters to upper case ASCII letters.
728 *
729 * Return value: passed-in @string pointer, with all the lower case
730 *               characters converted to upper case in place, with
731 *               semantics that exactly match g_ascii_toupper.
732 **/
733GString*
734g_string_ascii_up (GString *string)
735{
736  gchar *s;
737  gint n;
738
739  g_return_val_if_fail (string != NULL, NULL);
740
741  n = string->len;
742  s = string->str;
743
744  while (n)
745    {
746      *s = g_ascii_toupper (*s);
747      s++;
748      n--;
749    }
750
751  return string;
752}
753
754/**
755 * g_string_down:
756 * @string: a #GString
757 * 
758 * Converts a #GString to lowercase.
759 *
760 * Returns: the #GString.
761 *
762 * Deprecated: This function uses the locale-specific tolower() function,
763 * which is almost never the right thing. Use g_string_ascii_down() or
764 * g_utf8_strdown() instead.
765 */
766GString*
767g_string_down (GString *string)
768{
769  guchar *s;
770  glong n;
771
772  g_return_val_if_fail (string != NULL, NULL);
773
774  n = string->len;   
775  s = (guchar *) string->str;
776
777  while (n)
778    {
779      if (isupper (*s))
780        *s = tolower (*s);
781      s++;
782      n--;
783    }
784
785  return string;
786}
787
788/**
789 * g_string_up:
790 * @string: a #GString
791 *
792 * Converts a #GString to uppercase.
793 *
794 * Return value: the #GString
795 *
796 * Deprecated: This function uses the locale-specific toupper() function,
797 * which is almost never the right thing. Use g_string_ascii_up() or
798 * g_utf8_strup() instead.
799 **/
800GString*
801g_string_up (GString *string)
802{
803  guchar *s;
804  glong n;
805
806  g_return_val_if_fail (string != NULL, NULL);
807
808  n = string->len;
809  s = (guchar *) string->str;
810
811  while (n)
812    {
813      if (islower (*s))
814        *s = toupper (*s);
815      s++;
816      n--;
817    }
818
819  return string;
820}
821
822static void
823g_string_append_printf_internal (GString     *string,
824                                 const gchar *fmt,
825                                 va_list      args)
826{
827  gchar *buffer;
828  gint length;
829 
830  length = g_vasprintf (&buffer, fmt, args);
831  g_string_append_len (string, buffer, length);
832  g_free (buffer);
833}
834
835void
836g_string_printf (GString *string,
837                 const gchar *fmt,
838                 ...)
839{
840  va_list args;
841
842  g_string_truncate (string, 0);
843
844  va_start (args, fmt);
845  g_string_append_printf_internal (string, fmt, args);
846  va_end (args);
847}
848
849void
850g_string_append_printf (GString *string,
851                        const gchar *fmt,
852                        ...)
853{
854  va_list args;
855
856  va_start (args, fmt);
857  g_string_append_printf_internal (string, fmt, args);
858  va_end (args);
859}
Note: See TracBrowser for help on using the repository browser.