1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 2006-2019 Free Software Foundation, Inc.
3 *
4 * This file is not part of the GNU gettext program, but is used with
5 * GNU gettext.
6 *
7 * The original copyright notice is as follows:
8 */
9
10 /* GLIB - Library of useful routines for C programming
11 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 * Boston, MA 02111-1307, USA.
27 */
28
29 /*
30 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
31 * file for a list of people on the GLib Team. See the ChangeLog
32 * files for a list of changes. These files are distributed with
33 * GLib at ftp://ftp.gtk.org/pub/gtk/.
34 */
35
36 /*
37 * Modified by Bruno Haible for use as a gnulib module.
38 */
39
40 /*
41 * MT safe
42 */
43
44 #include "config.h"
45
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #include <stdarg.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <ctype.h>
54
55 #include "glib.h"
56 #if 0
57 #include "gprintf.h"
58
59 #include "galias.h"
60
61 struct _GStringChunk
62 {
63 GHashTable *const_table;
64 GSList *storage_list;
65 gsize storage_next;
66 gsize this_size;
67 gsize default_size;
68 };
69 #endif
70
71 /* Hash Functions.
72 */
73
74 /**
75 * g_str_equal:
76 * @v1: a key.
77 * @v2: a key to compare with @v1.
78 *
79 * Compares two strings and returns %TRUE if they are equal.
80 * It can be passed to g_hash_table_new() as the @key_equal_func
81 * parameter, when using strings as keys in a #GHashTable.
82 *
83 * Returns: %TRUE if the two keys match.
84 */
85 gboolean
g_str_equal(gconstpointer v1,gconstpointer v2)86 g_str_equal (gconstpointer v1,
87 gconstpointer v2)
88 {
89 const gchar *string1 = v1;
90 const gchar *string2 = v2;
91
92 return strcmp (string1, string2) == 0;
93 }
94
95 /**
96 * g_str_hash:
97 * @v: a string key.
98 *
99 * Converts a string to a hash value.
100 * It can be passed to g_hash_table_new() as the @hash_func parameter,
101 * when using strings as keys in a #GHashTable.
102 *
103 * Returns: a hash value corresponding to the key.
104 */
105 guint
g_str_hash(gconstpointer v)106 g_str_hash (gconstpointer v)
107 {
108 /* 31 bit hash function */
109 const signed char *p = v;
110 guint32 h = *p;
111
112 if (h)
113 for (p += 1; *p != '\0'; p++)
114 h = (h << 5) - h + *p;
115
116 return h;
117 }
118
119 #define MY_MAXSIZE ((gsize)-1)
120
121 static inline gsize
nearest_power(gsize base,gsize num)122 nearest_power (gsize base, gsize num)
123 {
124 if (num > MY_MAXSIZE / 2)
125 {
126 return MY_MAXSIZE;
127 }
128 else
129 {
130 gsize n = base;
131
132 while (n < num)
133 n <<= 1;
134
135 return n;
136 }
137 }
138
139 #if 0
140
141 /* String Chunks.
142 */
143
144 GStringChunk*
145 g_string_chunk_new (gsize default_size)
146 {
147 GStringChunk *new_chunk = g_new (GStringChunk, 1);
148 gsize size = 1;
149
150 size = nearest_power (1, default_size);
151
152 new_chunk->const_table = NULL;
153 new_chunk->storage_list = NULL;
154 new_chunk->storage_next = size;
155 new_chunk->default_size = size;
156 new_chunk->this_size = size;
157
158 return new_chunk;
159 }
160
161 void
162 g_string_chunk_free (GStringChunk *chunk)
163 {
164 GSList *tmp_list;
165
166 g_return_if_fail (chunk != NULL);
167
168 if (chunk->storage_list)
169 {
170 for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
171 g_free (tmp_list->data);
172
173 g_slist_free (chunk->storage_list);
174 }
175
176 if (chunk->const_table)
177 g_hash_table_destroy (chunk->const_table);
178
179 g_free (chunk);
180 }
181
182 gchar*
183 g_string_chunk_insert (GStringChunk *chunk,
184 const gchar *string)
185 {
186 g_return_val_if_fail (chunk != NULL, NULL);
187
188 return g_string_chunk_insert_len (chunk, string, -1);
189 }
190
191 gchar*
192 g_string_chunk_insert_const (GStringChunk *chunk,
193 const gchar *string)
194 {
195 char* lookup;
196
197 g_return_val_if_fail (chunk != NULL, NULL);
198
199 if (!chunk->const_table)
200 chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
201
202 lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
203
204 if (!lookup)
205 {
206 lookup = g_string_chunk_insert (chunk, string);
207 g_hash_table_insert (chunk->const_table, lookup, lookup);
208 }
209
210 return lookup;
211 }
212
213 /**
214 * g_string_chunk_insert_len:
215 * @chunk: a #GStringChunk
216 * @string: bytes to insert
217 * @len: number of bytes of @string to insert, or -1 to insert a
218 * nul-terminated string.
219 *
220 * Adds a copy of the first @len bytes of @string to the #GStringChunk. The
221 * copy is nul-terminated.
222 *
223 * The characters in the string can be changed, if necessary, though you
224 * should not change anything after the end of the string.
225 *
226 * Return value: a pointer to the copy of @string within the #GStringChunk
227 *
228 * Since: 2.4
229 **/
230 gchar*
231 g_string_chunk_insert_len (GStringChunk *chunk,
232 const gchar *string,
233 gssize len)
234 {
235 gssize size;
236 gchar* pos;
237
238 g_return_val_if_fail (chunk != NULL, NULL);
239
240 if (len < 0)
241 size = strlen (string);
242 else
243 size = len;
244
245 if ((chunk->storage_next + size + 1) > chunk->this_size)
246 {
247 gsize new_size = nearest_power (chunk->default_size, size + 1);
248
249 chunk->storage_list = g_slist_prepend (chunk->storage_list,
250 g_new (gchar, new_size));
251
252 chunk->this_size = new_size;
253 chunk->storage_next = 0;
254 }
255
256 pos = ((gchar *) chunk->storage_list->data) + chunk->storage_next;
257
258 *(pos + size) = '\0';
259
260 strncpy (pos, string, size);
261 if (len > 0)
262 size = strlen (pos);
263
264 chunk->storage_next += size + 1;
265
266 return pos;
267 }
268
269 #endif
270
271 /* Strings.
272 */
273 static void
g_string_maybe_expand(GString * string,gsize len)274 g_string_maybe_expand (GString* string,
275 gsize len)
276 {
277 if (string->len + len >= string->allocated_len)
278 {
279 string->allocated_len = nearest_power (1, string->len + len + 1);
280 string->str = g_realloc (string->str, string->allocated_len);
281 }
282 }
283
284 GString*
g_string_sized_new(gsize dfl_size)285 g_string_sized_new (gsize dfl_size)
286 {
287 GString *string = g_slice_new (GString);
288
289 string->allocated_len = 0;
290 string->len = 0;
291 string->str = NULL;
292
293 g_string_maybe_expand (string, MAX (dfl_size, 2));
294 string->str[0] = 0;
295
296 return string;
297 }
298
299 GString*
g_string_new(const gchar * init)300 g_string_new (const gchar *init)
301 {
302 GString *string;
303
304 if (init == NULL || *init == '\0')
305 string = g_string_sized_new (2);
306 else
307 {
308 gint len;
309
310 len = strlen (init);
311 string = g_string_sized_new (len + 2);
312
313 g_string_append_len (string, init, len);
314 }
315
316 return string;
317 }
318
319 GString*
g_string_new_len(const gchar * init,gssize len)320 g_string_new_len (const gchar *init,
321 gssize len)
322 {
323 GString *string;
324
325 if (len < 0)
326 return g_string_new (init);
327 else
328 {
329 string = g_string_sized_new (len);
330
331 if (init)
332 g_string_append_len (string, init, len);
333
334 return string;
335 }
336 }
337
338 gchar*
g_string_free(GString * string,gboolean free_segment)339 g_string_free (GString *string,
340 gboolean free_segment)
341 {
342 gchar *segment;
343
344 g_return_val_if_fail (string != NULL, NULL);
345
346 if (free_segment)
347 {
348 g_free (string->str);
349 segment = NULL;
350 }
351 else
352 segment = string->str;
353
354 g_slice_free (GString, string);
355
356 return segment;
357 }
358
359 #if 0
360
361 gboolean
362 g_string_equal (const GString *v,
363 const GString *v2)
364 {
365 gchar *p, *q;
366 GString *string1 = (GString *) v;
367 GString *string2 = (GString *) v2;
368 gsize i = string1->len;
369
370 if (i != string2->len)
371 return FALSE;
372
373 p = string1->str;
374 q = string2->str;
375 while (i)
376 {
377 if (*p != *q)
378 return FALSE;
379 p++;
380 q++;
381 i--;
382 }
383 return TRUE;
384 }
385
386 /* 31 bit hash function */
387 guint
388 g_string_hash (const GString *str)
389 {
390 const gchar *p = str->str;
391 gsize n = str->len;
392 guint h = 0;
393
394 while (n--)
395 {
396 h = (h << 5) - h + *p;
397 p++;
398 }
399
400 return h;
401 }
402
403 GString*
404 g_string_assign (GString *string,
405 const gchar *rval)
406 {
407 g_return_val_if_fail (string != NULL, NULL);
408 g_return_val_if_fail (rval != NULL, string);
409
410 /* Make sure assigning to itself doesn't corrupt the string. */
411 if (string->str != rval)
412 {
413 /* Assigning from substring should be ok since g_string_truncate
414 does not realloc. */
415 g_string_truncate (string, 0);
416 g_string_append (string, rval);
417 }
418
419 return string;
420 }
421
422 GString*
423 g_string_truncate (GString *string,
424 gsize len)
425 {
426 g_return_val_if_fail (string != NULL, NULL);
427
428 string->len = MIN (len, string->len);
429 string->str[string->len] = 0;
430
431 return string;
432 }
433
434 /**
435 * g_string_set_size:
436 * @string: a #GString
437 * @len: the new length
438 *
439 * Sets the length of a #GString. If the length is less than
440 * the current length, the string will be truncated. If the
441 * length is greater than the current length, the contents
442 * of the newly added area are undefined. (However, as
443 * always, string->str[string->len] will be a nul byte.)
444 *
445 * Return value: @string
446 **/
447 GString*
448 g_string_set_size (GString *string,
449 gsize len)
450 {
451 g_return_val_if_fail (string != NULL, NULL);
452
453 if (len >= string->allocated_len)
454 g_string_maybe_expand (string, len - string->len);
455
456 string->len = len;
457 string->str[len] = 0;
458
459 return string;
460 }
461
462 #endif
463
464 GString*
g_string_insert_len(GString * string,gssize pos,const gchar * val,gssize len)465 g_string_insert_len (GString *string,
466 gssize pos,
467 const gchar *val,
468 gssize len)
469 {
470 g_return_val_if_fail (string != NULL, NULL);
471 g_return_val_if_fail (val != NULL, string);
472
473 if (len < 0)
474 len = strlen (val);
475
476 if (pos < 0)
477 pos = string->len;
478 else
479 g_return_val_if_fail (pos <= string->len, string);
480
481 /* Check whether val represents a substring of string. This test
482 probably violates chapter and verse of the C standards, since
483 ">=" and "<=" are only valid when val really is a substring.
484 In practice, it will work on modern archs. */
485 if (val >= string->str && val <= string->str + string->len)
486 {
487 gsize offset = val - string->str;
488 gsize precount = 0;
489
490 g_string_maybe_expand (string, len);
491 val = string->str + offset;
492 /* At this point, val is valid again. */
493
494 /* Open up space where we are going to insert. */
495 if (pos < string->len)
496 g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
497
498 /* Move the source part before the gap, if any. */
499 if (offset < pos)
500 {
501 precount = MIN (len, pos - offset);
502 memcpy (string->str + pos, val, precount);
503 }
504
505 /* Move the source part after the gap, if any. */
506 if (len > precount)
507 memcpy (string->str + pos + precount,
508 val + /* Already moved: */ precount + /* Space opened up: */ len,
509 len - precount);
510 }
511 else
512 {
513 g_string_maybe_expand (string, len);
514
515 /* If we aren't appending at the end, move a hunk
516 * of the old string to the end, opening up space
517 */
518 if (pos < string->len)
519 g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
520
521 /* insert the new string */
522 if (len == 1)
523 string->str[pos] = *val;
524 else
525 memcpy (string->str + pos, val, len);
526 }
527
528 string->len += len;
529
530 string->str[string->len] = 0;
531
532 return string;
533 }
534
535 GString*
g_string_append(GString * string,const gchar * val)536 g_string_append (GString *string,
537 const gchar *val)
538 {
539 g_return_val_if_fail (string != NULL, NULL);
540 g_return_val_if_fail (val != NULL, string);
541
542 return g_string_insert_len (string, -1, val, -1);
543 }
544
545 GString*
g_string_append_len(GString * string,const gchar * val,gssize len)546 g_string_append_len (GString *string,
547 const gchar *val,
548 gssize len)
549 {
550 g_return_val_if_fail (string != NULL, NULL);
551 g_return_val_if_fail (val != NULL, string);
552
553 return g_string_insert_len (string, -1, val, len);
554 }
555
556 #if !defined IN_LIBTEXTSTYLE
557 #undef g_string_append_c
558 #endif
559 GString*
g_string_append_c(GString * string,gchar c)560 g_string_append_c (GString *string,
561 gchar c)
562 {
563 g_return_val_if_fail (string != NULL, NULL);
564
565 return g_string_insert_c (string, -1, c);
566 }
567
568 /**
569 * g_string_append_unichar:
570 * @string: a #GString
571 * @wc: a Unicode character
572 *
573 * Converts a Unicode character into UTF-8, and appends it
574 * to the string.
575 *
576 * Return value: @string
577 **/
578 GString*
g_string_append_unichar(GString * string,gunichar wc)579 g_string_append_unichar (GString *string,
580 gunichar wc)
581 {
582 g_return_val_if_fail (string != NULL, NULL);
583
584 return g_string_insert_unichar (string, -1, wc);
585 }
586
587 #if 0
588
589 GString*
590 g_string_prepend (GString *string,
591 const gchar *val)
592 {
593 g_return_val_if_fail (string != NULL, NULL);
594 g_return_val_if_fail (val != NULL, string);
595
596 return g_string_insert_len (string, 0, val, -1);
597 }
598
599 GString*
600 g_string_prepend_len (GString *string,
601 const gchar *val,
602 gssize len)
603 {
604 g_return_val_if_fail (string != NULL, NULL);
605 g_return_val_if_fail (val != NULL, string);
606
607 return g_string_insert_len (string, 0, val, len);
608 }
609
610 GString*
611 g_string_prepend_c (GString *string,
612 gchar c)
613 {
614 g_return_val_if_fail (string != NULL, NULL);
615
616 return g_string_insert_c (string, 0, c);
617 }
618
619 /**
620 * g_string_prepend_unichar:
621 * @string: a #GString.
622 * @wc: a Unicode character.
623 *
624 * Converts a Unicode character into UTF-8, and prepends it
625 * to the string.
626 *
627 * Return value: @string.
628 **/
629 GString*
630 g_string_prepend_unichar (GString *string,
631 gunichar wc)
632 {
633 g_return_val_if_fail (string != NULL, NULL);
634
635 return g_string_insert_unichar (string, 0, wc);
636 }
637
638 GString*
639 g_string_insert (GString *string,
640 gssize pos,
641 const gchar *val)
642 {
643 g_return_val_if_fail (string != NULL, NULL);
644 g_return_val_if_fail (val != NULL, string);
645 if (pos >= 0)
646 g_return_val_if_fail (pos <= string->len, string);
647
648 return g_string_insert_len (string, pos, val, -1);
649 }
650
651 #endif
652
653 GString*
g_string_insert_c(GString * string,gssize pos,gchar c)654 g_string_insert_c (GString *string,
655 gssize pos,
656 gchar c)
657 {
658 g_return_val_if_fail (string != NULL, NULL);
659
660 g_string_maybe_expand (string, 1);
661
662 if (pos < 0)
663 pos = string->len;
664 else
665 g_return_val_if_fail (pos <= string->len, string);
666
667 /* If not just an append, move the old stuff */
668 if (pos < string->len)
669 g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
670
671 string->str[pos] = c;
672
673 string->len += 1;
674
675 string->str[string->len] = 0;
676
677 return string;
678 }
679
680 /**
681 * g_string_insert_unichar:
682 * @string: a #GString
683 * @pos: the position at which to insert character, or -1 to
684 * append at the end of the string.
685 * @wc: a Unicode character
686 *
687 * Converts a Unicode character into UTF-8, and insert it
688 * into the string at the given position.
689 *
690 * Return value: @string
691 **/
692 GString*
g_string_insert_unichar(GString * string,gssize pos,gunichar wc)693 g_string_insert_unichar (GString *string,
694 gssize pos,
695 gunichar wc)
696 {
697 gint charlen, first, i;
698 gchar *dest;
699
700 g_return_val_if_fail (string != NULL, NULL);
701
702 /* Code copied from g_unichar_to_utf() */
703 if (wc < 0x80)
704 {
705 first = 0;
706 charlen = 1;
707 }
708 else if (wc < 0x800)
709 {
710 first = 0xc0;
711 charlen = 2;
712 }
713 else if (wc < 0x10000)
714 {
715 first = 0xe0;
716 charlen = 3;
717 }
718 else if (wc < 0x200000)
719 {
720 first = 0xf0;
721 charlen = 4;
722 }
723 else if (wc < 0x4000000)
724 {
725 first = 0xf8;
726 charlen = 5;
727 }
728 else
729 {
730 first = 0xfc;
731 charlen = 6;
732 }
733 /* End of copied code */
734
735 g_string_maybe_expand (string, charlen);
736
737 if (pos < 0)
738 pos = string->len;
739 else
740 g_return_val_if_fail (pos <= string->len, string);
741
742 /* If not just an append, move the old stuff */
743 if (pos < string->len)
744 g_memmove (string->str + pos + charlen, string->str + pos, string->len - pos);
745
746 dest = string->str + pos;
747 /* Code copied from g_unichar_to_utf() */
748 for (i = charlen - 1; i > 0; --i)
749 {
750 dest[i] = (wc & 0x3f) | 0x80;
751 wc >>= 6;
752 }
753 dest[0] = wc | first;
754 /* End of copied code */
755
756 string->len += charlen;
757
758 string->str[string->len] = 0;
759
760 return string;
761 }
762
763 #if 0
764
765 GString*
766 g_string_erase (GString *string,
767 gssize pos,
768 gssize len)
769 {
770 g_return_val_if_fail (string != NULL, NULL);
771 g_return_val_if_fail (pos >= 0, string);
772 g_return_val_if_fail (pos <= string->len, string);
773
774 if (len < 0)
775 len = string->len - pos;
776 else
777 {
778 g_return_val_if_fail (pos + len <= string->len, string);
779
780 if (pos + len < string->len)
781 g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
782 }
783
784 string->len -= len;
785
786 string->str[string->len] = 0;
787
788 return string;
789 }
790
791 /**
792 * g_string_ascii_down:
793 * @string: a GString
794 *
795 * Converts all upper case ASCII letters to lower case ASCII letters.
796 *
797 * Return value: passed-in @string pointer, with all the upper case
798 * characters converted to lower case in place, with
799 * semantics that exactly match g_ascii_tolower.
800 **/
801 GString*
802 g_string_ascii_down (GString *string)
803 {
804 gchar *s;
805 gint n;
806
807 g_return_val_if_fail (string != NULL, NULL);
808
809 n = string->len;
810 s = string->str;
811
812 while (n)
813 {
814 *s = g_ascii_tolower (*s);
815 s++;
816 n--;
817 }
818
819 return string;
820 }
821
822 /**
823 * g_string_ascii_up:
824 * @string: a GString
825 *
826 * Converts all lower case ASCII letters to upper case ASCII letters.
827 *
828 * Return value: passed-in @string pointer, with all the lower case
829 * characters converted to upper case in place, with
830 * semantics that exactly match g_ascii_toupper.
831 **/
832 GString*
833 g_string_ascii_up (GString *string)
834 {
835 gchar *s;
836 gint n;
837
838 g_return_val_if_fail (string != NULL, NULL);
839
840 n = string->len;
841 s = string->str;
842
843 while (n)
844 {
845 *s = g_ascii_toupper (*s);
846 s++;
847 n--;
848 }
849
850 return string;
851 }
852
853 /**
854 * g_string_down:
855 * @string: a #GString
856 *
857 * Converts a #GString to lowercase.
858 *
859 * Returns: the #GString.
860 *
861 * Deprecated:2.2: This function uses the locale-specific tolower() function,
862 * which is almost never the right thing. Use g_string_ascii_down() or
863 * g_utf8_strdown() instead.
864 */
865 GString*
866 g_string_down (GString *string)
867 {
868 guchar *s;
869 glong n;
870
871 g_return_val_if_fail (string != NULL, NULL);
872
873 n = string->len;
874 s = (guchar *) string->str;
875
876 while (n)
877 {
878 if (isupper (*s))
879 *s = tolower (*s);
880 s++;
881 n--;
882 }
883
884 return string;
885 }
886
887 /**
888 * g_string_up:
889 * @string: a #GString
890 *
891 * Converts a #GString to uppercase.
892 *
893 * Return value: the #GString
894 *
895 * Deprecated:2.2: This function uses the locale-specific toupper() function,
896 * which is almost never the right thing. Use g_string_ascii_up() or
897 * g_utf8_strup() instead.
898 **/
899 GString*
900 g_string_up (GString *string)
901 {
902 guchar *s;
903 glong n;
904
905 g_return_val_if_fail (string != NULL, NULL);
906
907 n = string->len;
908 s = (guchar *) string->str;
909
910 while (n)
911 {
912 if (islower (*s))
913 *s = toupper (*s);
914 s++;
915 n--;
916 }
917
918 return string;
919 }
920
921 #endif
922
923 static void
g_string_append_printf_internal(GString * string,const gchar * fmt,va_list args)924 g_string_append_printf_internal (GString *string,
925 const gchar *fmt,
926 va_list args)
927 {
928 gchar *buffer;
929 gint length;
930
931 length = g_vasprintf (&buffer, fmt, args);
932 g_string_append_len (string, buffer, length);
933 g_free (buffer);
934 }
935
936 #if 0
937
938 void
939 g_string_printf (GString *string,
940 const gchar *fmt,
941 ...)
942 {
943 va_list args;
944
945 g_string_truncate (string, 0);
946
947 va_start (args, fmt);
948 g_string_append_printf_internal (string, fmt, args);
949 va_end (args);
950 }
951
952 #endif
953
954 void
g_string_append_printf(GString * string,const gchar * fmt,...)955 g_string_append_printf (GString *string,
956 const gchar *fmt,
957 ...)
958 {
959 va_list args;
960
961 va_start (args, fmt);
962 g_string_append_printf_internal (string, fmt, args);
963 va_end (args);
964 }
965
966 #if 0
967 #define __G_STRING_C__
968 #include "galiasdef.c"
969 #endif
970