blob: 760be55cc12afd0a5d3f9dbb5b188431095fbc36 [file] [log] [blame]
Bjorn Reese026d29f2002-01-19 15:40:18 +00001/*************************************************************************
2 *
3 * $Id$
4 *
5 * Copyright (C) 2001 Bjorn Reese and Daniel Stenberg.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 ************************************************************************/
17
18static const char rcsid[] = "@(#)$Id$";
19
20/*************************************************************************
21 * Include files
22 */
23
24#include <assert.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include "triostr.h"
30
31/*************************************************************************
32 * Definitions
33 */
34
35#ifndef NULL
36# define NULL 0
37#endif
38#define NIL ((char)0)
39#ifndef FALSE
40# define FALSE (1 == 0)
41# define TRUE (! FALSE)
42#endif
43#define BOOLEAN_T int
44
45#if defined(TRIO_COMPILER_SUPPORTS_C99)
46# define USE_STRTOD
47# define USE_STRTOF
48#elif defined(TRIO_COMPILER_MSVC)
49# define USE_STRTOD
50#endif
51
52#if defined(TRIO_PLATFORM_UNIX)
53# define USE_STRCASECMP
54# define USE_STRNCASECMP
55# define USE_STRERROR
56# if defined(TRIO_PLATFORM_QNX)
57# define strcasecmp(x,y) stricmp(x,y)
58# define strncasecmp(x,y,n) strnicmp(x,y,n)
59# endif
60#elif defined(TRIO_PLATFORM_WIN32)
61# define USE_STRCASECMP
62# define strcasecmp(x,y) strcmpi(x,y)
63#endif
64
65/*************************************************************************
66 * Structures
67 */
68
69struct _trio_string_t
70{
71 char *content;
72 size_t length;
73 size_t allocated;
74};
75
76/*************************************************************************
77 * Static String Functions
78 */
79
80#if defined(TRIO_DOCUMENTATION)
81# include "doc/doc_static.h"
82#endif
83/** @addtogroup StaticStrings
84 @{
85*/
86
87/**
88 Create new string.
89
90 @param size Size of new string.
91 @return Pointer to string, or NULL if allocation failed.
92*/
93TRIO_PUBLIC TRIO_INLINE char *
94trio_create(size_t size)
95{
96 return (char *)TRIO_MALLOC(size);
97}
98
99
100/**
101 Destroy string.
102
103 @param string String to be freed.
104*/
105TRIO_PUBLIC TRIO_INLINE void
106trio_destroy(char *string)
107{
108 if (string)
109 {
110 TRIO_FREE(string);
111 }
112}
113
114
115/**
116 Count the number of characters in a string.
117
118 @param string String to measure.
119 @return Number of characters in @string.
120*/
121TRIO_PUBLIC TRIO_INLINE size_t
122trio_length(const char *string)
123{
124 return strlen(string);
125}
126
127
128/*
129 * TrioDuplicateMax
130 */
131TRIO_PRIVATE char *
132TrioDuplicateMax(const char *source, size_t size)
133{
134 char *target;
135
136 assert(source);
137
138 /* Make room for string plus a terminating zero */
139 size++;
140 target = trio_create(size);
141 if (target)
142 {
143 trio_copy_max(target, size, source);
144 }
145 return target;
146}
147
148
149/**
150 Append @p source at the end of @p target.
151
152 @param target Target string.
153 @param source Source string.
154 @return Boolean value indicating success or failure.
155
156 @pre @p target must point to a memory chunk with sufficient room to
157 contain the @p target string and @p source string.
158 @pre No boundary checking is performed, so insufficient memory will
159 result in a buffer overrun.
160 @post @p target will be zero terminated.
161*/
162TRIO_PUBLIC int
163trio_append(char *target,
164 const char *source)
165{
166 assert(target);
167 assert(source);
168
169 return (strcat(target, source) != NULL);
170}
171
172
173/**
174 Append at most @p max characters from @p source to @p target.
175
176 @param target Target string.
177 @param max Maximum number of characters to append.
178 @param source Source string.
179 @return Boolean value indicating success or failure.
180
181 @pre @p target must point to a memory chuck with sufficient room to
182 contain the @p target string and the @p source string (at most @p max
183 characters).
184 @pre No boundary checking is performed, so insufficient memory will
185 result in a buffer overrun.
186 @post @p target will be zero terminated.
187*/
188TRIO_PUBLIC int
189trio_append_max(char *target,
190 size_t max,
191 const char *source)
192{
193 size_t length;
194
195 assert(target);
196 assert(source);
197
198 length = trio_length(target);
199
200 if (max > length)
201 {
202 strncat(target, source, max - length - 1);
203 }
204 return TRUE;
205}
206
207
208/**
209 Determine if a string contains a substring.
210
211 @param string String to be searched.
212 @param substring String to be found.
213 @return Boolean value indicating success or failure.
214*/
215TRIO_PUBLIC TRIO_INLINE int
216trio_contains(const char *string,
217 const char *substring)
218{
219 assert(string);
220 assert(substring);
221
222 return (0 != strstr(string, substring));
223}
224
225
226/**
227 Copy @p source to @p target.
228
229 @param target Target string.
230 @param source Source string.
231 @return Boolean value indicating success or failure.
232
233 @pre @p target must point to a memory chunk with sufficient room to
234 contain the @p source string.
235 @pre No boundary checking is performed, so insufficient memory will
236 result in a buffer overrun.
237 @post @p target will be zero terminated.
238*/
239TRIO_PUBLIC int
240trio_copy(char *target,
241 const char *source)
242{
243 assert(target);
244 assert(source);
245
246 (void)strcpy(target, source);
247 return TRUE;
248}
249
250
251/**
252 Copy at most @p max characters from @p source to @p target.
253
254 @param target Target string.
255 @param max Maximum number of characters to append.
256 @param source Source string.
257 @return Boolean value indicating success or failure.
258
259 @pre @p target must point to a memory chunk with sufficient room to
260 contain the @p source string (at most @p max characters).
261 @pre No boundary checking is performed, so insufficient memory will
262 result in a buffer overrun.
263 @post @p target will be zero terminated.
264*/
265TRIO_PUBLIC int
266trio_copy_max(char *target,
267 size_t max,
268 const char *source)
269{
270 assert(target);
271 assert(source);
272 assert(max > 0); /* Includes != 0 */
273
274 (void)strncpy(target, source, max - 1);
275 target[max - 1] = (char)0;
276 return TRUE;
277}
278
279
280/**
281 Duplicate @p source.
282
283 @param source Source string.
284 @return A copy of the @p source string.
285
286 @post @p target will be zero terminated.
287*/
288TRIO_PUBLIC char *
289trio_duplicate(const char *source)
290{
291 return TrioDuplicateMax(source, trio_length(source));
292}
293
294
295/**
296 Duplicate at most @p max characters of @p source.
297
298 @param source Source string.
299 @param max Maximum number of characters to duplicate.
300 @return A copy of the @p source string.
301
302 @post @p target will be zero terminated.
303*/
304TRIO_PUBLIC char *
305trio_duplicate_max(const char *source,
306 size_t max)
307{
308 size_t length;
309
310 assert(source);
311 assert(max > 0);
312
313 length = trio_length(source);
314 if (length > max)
315 {
316 length = max;
317 }
318 return TrioDuplicateMax(source, length);
319}
320
321
322/**
323 Compare if two strings are equal.
324
325 @param first First string.
326 @param second Second string.
327 @return Boolean indicating whether the two strings are equal or not.
328
329 Case-insensitive comparison.
330*/
331TRIO_PUBLIC int
332trio_equal(const char *first,
333 const char *second)
334{
335 assert(first);
336 assert(second);
337
338 if ((first != NULL) && (second != NULL))
339 {
340#if defined(USE_STRCASECMP)
341 return (0 == strcasecmp(first, second));
342#else
343 while ((*first != NIL) && (*second != NIL))
344 {
345 if (toupper(*first) != toupper(*second))
346 {
347 break;
348 }
349 first++;
350 second++;
351 }
352 return ((*first == NIL) && (*second == NIL));
353#endif
354 }
355 return FALSE;
356}
357
358
359/**
360 Compare if two strings are equal.
361
362 @param first First string.
363 @param second Second string.
364 @return Boolean indicating whether the two strings are equal or not.
365
366 Case-sensitive comparison.
367*/
368TRIO_PUBLIC int
369trio_equal_case(const char *first,
370 const char *second)
371{
372 assert(first);
373 assert(second);
374
375 if ((first != NULL) && (second != NULL))
376 {
377 return (0 == strcmp(first, second));
378 }
379 return FALSE;
380}
381
382
383/**
384 Compare if two strings up until the first @p max characters are equal.
385
386 @param first First string.
387 @param max Maximum number of characters to compare.
388 @param second Second string.
389 @return Boolean indicating whether the two strings are equal or not.
390
391 Case-sensitive comparison.
392*/
393TRIO_PUBLIC int
394trio_equal_case_max(const char *first,
395 size_t max,
396 const char *second)
397{
398 assert(first);
399 assert(second);
400
401 if ((first != NULL) && (second != NULL))
402 {
403 return (0 == strncmp(first, second, max));
404 }
405 return FALSE;
406}
407
408
409/**
410 Compare if two strings are equal.
411
412 @param first First string.
413 @param second Second string.
414 @return Boolean indicating whether the two strings are equal or not.
415
416 Collating characters are considered equal.
417*/
418TRIO_PUBLIC int
419trio_equal_locale(const char *first,
420 const char *second)
421{
422 assert(first);
423 assert(second);
424
425#if defined(LC_COLLATE)
426 return (strcoll(first, second) == 0);
427#else
428 return trio_equal(first, second);
429#endif
430}
431
432
433/**
434 Compare if two strings up until the first @p max characters are equal.
435
436 @param first First string.
437 @param max Maximum number of characters to compare.
438 @param second Second string.
439 @return Boolean indicating whether the two strings are equal or not.
440
441 Case-insensitive comparison.
442*/
443TRIO_PUBLIC int
444trio_equal_max(const char *first,
445 size_t max,
446 const char *second)
447{
448 assert(first);
449 assert(second);
450
451 if ((first != NULL) && (second != NULL))
452 {
453#if defined(USE_STRNCASECMP)
454 return (0 == strncasecmp(first, second, max));
455#else
456 /* Not adequately tested yet */
457 size_t cnt = 0;
458 while ((*first != NIL) && (*second != NIL) && (cnt <= max))
459 {
460 if (toupper(*first) != toupper(*second))
461 {
462 break;
463 }
464 first++;
465 second++;
466 cnt++;
467 }
468 return ((cnt == max) || ((*first == NIL) && (*second == NIL)));
469#endif
470 }
471 return FALSE;
472}
473
474
475/**
476 Provide a textual description of an error code (errno).
477
478 @param error_number Error number.
479 @return Textual description of @p error_number.
480*/
481TRIO_PUBLIC const char *
482trio_error(int error_number)
483{
484#if defined(USE_STRERROR)
485 return strerror(error_number);
486#else
487 return "unknown";
488#endif
489}
490
491
492/**
493 Format the date/time according to @p format.
494
495 @param target Target string.
496 @param max Maximum number of characters to format.
497 @param format Formatting string.
498 @param datetime Date/time structure.
499 @return Number of formatted characters.
500
501 The formatting string accepts the same specifiers as the standard C
502 function strftime.
503*/
504TRIO_PUBLIC size_t
505trio_format_date_max(char *target,
506 size_t max,
507 const char *format,
508 const struct tm *datetime)
509{
510 assert(target);
511 assert(format);
512 assert(datetime);
513 assert(max > 0);
514
515 return strftime(target, max, format, datetime);
516}
517
518
519/**
520 Calculate a hash value for a string.
521
522 @param string String to be calculated on.
523 @param type Hash function.
524 @return Calculated hash value.
525
526 @p type can be one of the following
527 @li @c TRIO_HASH_PLAIN Plain hash function.
528*/
529TRIO_PUBLIC unsigned long
530trio_hash(const char *string,
531 int type)
532{
533 unsigned long value = 0L;
534 char ch;
535
536 assert(string);
537
538 switch (type)
539 {
540 case TRIO_HASH_PLAIN:
541 while ( (ch = *string++) != NIL )
542 {
543 value *= 31;
544 value += (unsigned long)ch;
545 }
546 break;
547 default:
548 assert(FALSE);
549 break;
550 }
551 return value;
552}
553
554
555/**
556 Find first occurrence of a character in a string.
557
558 @param string String to be searched.
559 @param character Character to be found.
560 @param A pointer to the found character, or NULL if character was not found.
561 */
562TRIO_PUBLIC TRIO_INLINE char *
563trio_index(const char *string,
564 char character)
565{
566 assert(string);
567
568 return strchr(string, character);
569}
570
571
572/**
573 Find last occurrence of a character in a string.
574
575 @param string String to be searched.
576 @param character Character to be found.
577 @param A pointer to the found character, or NULL if character was not found.
578 */
579TRIO_PUBLIC TRIO_INLINE char *
580trio_index_last(const char *string,
581 char character)
582{
583 assert(string);
584
585 return strchr(string, character);
586}
587
588
589/**
590 Convert the alphabetic letters in the string to lower-case.
591
592 @param target String to be converted.
593 @return Number of processed characters (converted or not).
594*/
595TRIO_PUBLIC TRIO_INLINE int
596trio_lower(char *target)
597{
598 assert(target);
599
600 return trio_span_function(target, target, tolower);
601}
602
603
604/**
605 Compare two strings using wildcards.
606
607 @param string String to be searched.
608 @param pattern Pattern, including wildcards, to search for.
609 @return Boolean value indicating success or failure.
610
611 Case-insensitive comparison.
612
613 The following wildcards can be used
614 @li @c * Match any number of characters.
615 @li @c ? Match a single character.
616*/
617TRIO_PUBLIC int
618trio_match(const char *string,
619 const char *pattern)
620{
621 assert(string);
622 assert(pattern);
623
624 for (; ('*' != *pattern); ++pattern, ++string)
625 {
626 if (NIL == *string)
627 {
628 return (NIL == *pattern);
629 }
630 if ((toupper((int)*string) != toupper((int)*pattern))
631 && ('?' != *pattern))
632 {
633 return FALSE;
634 }
635 }
636 /* two-line patch to prevent *too* much recursiveness: */
637 while ('*' == pattern[1])
638 pattern++;
639
640 do
641 {
642 if ( trio_match(string, &pattern[1]) )
643 {
644 return TRUE;
645 }
646 }
647 while (*string++);
648
649 return FALSE;
650}
651
652
653/**
654 Compare two strings using wildcards.
655
656 @param string String to be searched.
657 @param pattern Pattern, including wildcards, to search for.
658 @return Boolean value indicating success or failure.
659
660 Case-sensitive comparison.
661
662 The following wildcards can be used
663 @li @c * Match any number of characters.
664 @li @c ? Match a single character.
665*/
666TRIO_PUBLIC int
667trio_match_case(const char *string,
668 const char *pattern)
669{
670 assert(string);
671 assert(pattern);
672
673 for (; ('*' != *pattern); ++pattern, ++string)
674 {
675 if (NIL == *string)
676 {
677 return (NIL == *pattern);
678 }
679 if ((*string != *pattern)
680 && ('?' != *pattern))
681 {
682 return FALSE;
683 }
684 }
685 /* two-line patch to prevent *too* much recursiveness: */
686 while ('*' == pattern[1])
687 pattern++;
688
689 do
690 {
691 if ( trio_match_case(string, &pattern[1]) )
692 {
693 return TRUE;
694 }
695 }
696 while (*string++);
697
698 return FALSE;
699}
700
701
702/**
703 Execute a function on each character in string.
704
705 @param target Target string.
706 @param source Source string.
707 @param Function Function to be executed.
708 @return Number of processed characters.
709*/
710TRIO_PUBLIC size_t
711trio_span_function(char *target,
712 const char *source,
713 int (*Function)(int))
714{
715 size_t count = 0;
716
717 assert(target);
718 assert(source);
719 assert(Function);
720
721 while (*source != NIL)
722 {
723 *target++ = Function(*source++);
724 count++;
725 }
726 return count;
727}
728
729
730/**
731 Search for a substring in a string.
732
733 @param string String to be searched.
734 @param substring String to be found.
735 @return Pointer to first occurrence of @p substring in @p string, or NULL
736 if no match was found.
737*/
738TRIO_PUBLIC TRIO_INLINE char *
739trio_substring(const char *string,
740 const char *substring)
741{
742 assert(string);
743 assert(substring);
744
745 return strstr(string, substring);
746}
747
748
749/**
750 Search for a substring in the first @p max characters of a string.
751
752 @param string String to be searched.
753 @param max Maximum characters to be searched.
754 @param substring String to be found.
755 @return Pointer to first occurrence of @p substring in @p string, or NULL
756 if no match was found.
757*/
758TRIO_PUBLIC char *
759trio_substring_max(const char *string,
760 size_t max,
761 const char *substring)
762{
763 size_t count;
764 size_t size;
765 char *result = NULL;
766
767 assert(string);
768 assert(substring);
769
770 size = trio_length(substring);
771 if (size <= max)
772 {
773 for (count = 0; count <= max - size; count++)
774 {
775 if (trio_equal_max(substring, size, &string[count]))
776 {
777 result = (char *)&string[count];
778 break;
779 }
780 }
781 }
782 return result;
783}
784
785
786/**
787 Tokenize string.
788
789 @param string String to be tokenized.
790 @param tokens String containing list of delimiting characters.
791 @return Start of new token.
792
793 @warning @p string will be destroyed.
794*/
795TRIO_PUBLIC TRIO_INLINE char *
796trio_tokenize(char *string, const char *delimiters)
797{
798 assert(delimiters);
799
800 return strtok(string, delimiters);
801}
802
803
804/**
805 Convert string to floating-point number.
806
807 @param source String to be converted.
808 @param endp Pointer to end of the converted string.
809 @return A floating-point number.
810
811 The following Extended Backus-Naur form is used
812 @verbatim
813 double ::= [ <sign> ]
814 ( <number> |
815 <number> <decimal_point> <number> |
816 <decimal_point> <number> )
817 [ <exponential> [ <sign> ] <number> ]
818 number ::= 1*( <digit> )
819 digit ::= ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
820 exponential ::= ( 'e' | 'E' )
821 sign ::= ( '-' | '+' )
822 decimal_point ::= '.'
823 @endverbatim
824*/
825/* FIXME: Add EBNF for hex-floats */
826TRIO_PUBLIC double
827trio_to_double(const char *source,
828 const char **endp)
829{
830#if defined(USE_STRTOD)
831 return strtod(source, (char **)endp);
832#else
833 /* Preliminary code */
834 int isNegative = FALSE;
835 int isExponentNegative = FALSE;
836 unsigned long integer = 0;
837 unsigned long fraction = 0;
838 unsigned long fracdiv = 1;
839 unsigned long exponent = 0;
840 double value = 0.0;
841
842 /* First try hex-floats */
843 if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X')))
844 {
845 source += 2;
846 while (isxdigit((int)*source))
847 {
848 integer *= 16;
849 integer += (isdigit((int)*source)
850 ? (*source - '0')
851 : 10 + (toupper((int)*source) - 'A'));
852 source++;
853 }
854 if (*source == '.')
855 {
856 source++;
857 while (isxdigit((int)*source))
858 {
859 fraction *= 16;
860 fraction += (isdigit((int)*source)
861 ? (*source - '0')
862 : 10 + (toupper((int)*source) - 'A'));
863 fracdiv *= 16;
864 source++;
865 }
866 if ((*source == 'p') || (*source == 'P'))
867 {
868 source++;
869 if ((*source == '+') || (*source == '-'))
870 {
871 isExponentNegative = (*source == '-');
872 source++;
873 }
874 while (isdigit((int)*source))
875 {
876 exponent *= 10;
877 exponent += (*source - '0');
878 source++;
879 }
880 }
881 }
882 }
883 else /* Then try normal decimal floats */
884 {
885 isNegative = (*source == '-');
886 /* Skip sign */
887 if ((*source == '+') || (*source == '-'))
888 source++;
889
890 /* Integer part */
891 while (isdigit((int)*source))
892 {
893 integer *= 10;
894 integer += (*source - '0');
895 source++;
896 }
897
898 if (*source == '.')
899 {
900 source++; /* skip decimal point */
901 while (isdigit((int)*source))
902 {
903 fraction *= 10;
904 fraction += (*source - '0');
905 fracdiv *= 10;
906 source++;
907 }
908 }
909 if ((*source == 'e')
910 || (*source == 'E')
911#if TRIO_MICROSOFT
912 || (*source == 'd')
913 || (*source == 'D')
914#endif
915 )
916 {
917 source++; /* Skip exponential indicator */
918 isExponentNegative = (*source == '-');
919 if ((*source == '+') || (*source == '-'))
920 source++;
921 while (isdigit((int)*source))
922 {
923 exponent *= 10;
924 exponent += (*source - '0');
925 source++;
926 }
927 }
928 }
929
930 value = (double)integer;
931 if (fraction != 0)
932 {
933 value += (double)fraction / (double)fracdiv;
934 }
935 if (exponent != 0)
936 {
937 if (isExponentNegative)
938 value /= pow((double)10, (double)exponent);
939 else
940 value *= pow((double)10, (double)exponent);
941 }
942 if (isNegative)
943 value = -value;
944
945 if (endp)
946 *endp = source;
947 return value;
948#endif
949}
950
951
952/**
953 Convert string to floating-point number.
954
955 @param source String to be converted.
956 @param endp Pointer to end of the converted string.
957 @return A floating-point number.
958
959 See @ref trio_to_double.
960*/
961TRIO_PUBLIC TRIO_INLINE float
962trio_to_float(const char *source,
963 const char **endp)
964{
965#if defined(USE_STRTOF)
966 return strtof(source, (char **)endp);
967#else
968 return (float)trio_to_double(source, endp);
969#endif
970}
971
972
973/**
974 Convert string to signed integer.
975
976 @param string String to be converted.
977 @param endp Pointer to end of converted string.
978 @param base Radix number of number.
979*/
980TRIO_PUBLIC TRIO_INLINE long
981trio_to_long(const char *string,
982 char **endp,
983 int base)
984{
985 assert(string);
986 assert((base >= 2) && (base <= 36));
987
988 return strtol(string, endp, base);
989}
990
991
992/**
993 Convert string to unsigned integer.
994
995 @param string String to be converted.
996 @param endp Pointer to end of converted string.
997 @param base Radix number of number.
998*/
999TRIO_PUBLIC TRIO_INLINE unsigned long
1000trio_to_unsigned_long(const char *string,
1001 char **endp,
1002 int base)
1003{
1004 assert(string);
1005 assert((base >= 2) && (base <= 36));
1006
1007 return strtoul(string, endp, base);
1008}
1009
1010
1011/**
1012 Convert the alphabetic letters in the string to upper-case.
1013
1014 @param target The string to be converted.
1015 @return The number of processed characters (converted or not).
1016*/
1017TRIO_PUBLIC TRIO_INLINE int
1018trio_upper(char *target)
1019{
1020 assert(target);
1021
1022 return trio_span_function(target, target, toupper);
1023}
1024
1025
1026/** @} End of StaticStrings */
1027
1028
1029/*************************************************************************
1030 * Dynamic String Functions
1031 */
1032
1033#if defined(TRIO_DOCUMENTATION)
1034# include "doc/doc_dynamic.h"
1035#endif
1036/** @addtogroup DynamicStrings
1037 @{
1038*/
1039
1040/*
1041 * TrioStringAlloc
1042 */
1043TRIO_PRIVATE trio_string_t *
1044TrioStringAlloc(void)
1045{
1046 trio_string_t *self;
1047
1048 self = (trio_string_t *)TRIO_MALLOC(sizeof(trio_string_t));
1049 if (self)
1050 {
1051 self->content = NULL;
1052 self->length = 0;
1053 self->allocated = 0;
1054 }
1055 return self;
1056}
1057
1058
1059/*
1060 * TrioStringGrow
1061 *
1062 * The size of the string will be increased by 'delta' characters. If
1063 * 'delta' is zero, the size will be doubled.
1064 */
1065TRIO_PRIVATE BOOLEAN_T
1066TrioStringGrow(trio_string_t *self,
1067 size_t delta)
1068{
1069 BOOLEAN_T status = FALSE;
1070 char *new_content;
1071 size_t new_size;
1072
1073 new_size = (delta == 0)
1074 ? ( (self->allocated == 0) ? 1 : self->allocated * 2 )
1075 : self->allocated + delta;
1076
1077 new_content = (char *)TRIO_REALLOC(self->content, new_size);
1078 if (new_content)
1079 {
1080 self->content = new_content;
1081 self->allocated = new_size;
1082 status = TRUE;
1083 }
1084 return status;
1085}
1086
1087
1088/*
1089 * TrioStringGrowTo
1090 *
1091 * The size of the string will be increased to 'length' plus one characters.
1092 * If 'length' is less than the original size, the original size will be
1093 * used (that is, the size of the string is never decreased).
1094 */
1095TRIO_PRIVATE BOOLEAN_T
1096TrioStringGrowTo(trio_string_t *self,
1097 size_t length)
1098{
1099 length++; /* Room for terminating zero */
1100 return (self->allocated < length)
1101 ? TrioStringGrow(self, length - self->allocated)
1102 : TRUE;
1103}
1104
1105
1106/**
1107 Create a new dynamic string.
1108
1109 @param initial_size Initial size of the buffer.
1110 @return Newly allocated dynamic string, or NULL if memory allocation failed.
1111*/
1112TRIO_PUBLIC trio_string_t *
1113trio_string_create(int initial_size)
1114{
1115 trio_string_t *self;
1116
1117 self = TrioStringAlloc();
1118 if (self)
1119 {
1120 if (TrioStringGrow(self,
1121 (size_t)((initial_size > 0) ? initial_size : 1)))
1122 {
1123 self->content[0] = (char)0;
1124 self->allocated = initial_size;
1125 }
1126 else
1127 {
1128 trio_string_destroy(self);
1129 self = NULL;
1130 }
1131 }
1132 return self;
1133}
1134
1135
1136/**
1137 Deallocate the dynamic string and its contents.
1138
1139 @param self Dynamic string
1140*/
1141TRIO_PUBLIC void
1142trio_string_destroy(trio_string_t *self)
1143{
1144 assert(self);
1145
1146 if (self)
1147 {
1148 trio_destroy(self->content);
1149 TRIO_FREE(self);
1150 }
1151}
1152
1153
1154/**
1155 Get a pointer to the content.
1156
1157 @param self Dynamic string.
1158 @param offset Offset into content.
1159 @return Pointer to the content.
1160
1161 @p Offset can be zero, positive, or negative. If @p offset is zero,
1162 then the start of the content will be returned. If @p offset is positive,
1163 then a pointer to @p offset number of characters from the beginning of the
1164 content is returned. If @p offset is negative, then a pointer to @p offset
1165 number of characters from the ending of the string, starting at the
1166 terminating zero, is returned.
1167*/
1168TRIO_PUBLIC char *
1169trio_string_get(trio_string_t *self, int offset)
1170{
1171 char *result = NULL;
1172
1173 assert(self);
1174
1175 if (self->content != NULL)
1176 {
1177 if (self->length == 0)
1178 {
1179 (void)trio_string_length(self);
1180 }
1181 if (offset >= 0)
1182 {
1183 if (offset > self->length)
1184 {
1185 offset = self->length;
1186 }
1187 }
1188 else
1189 {
1190 offset += self->length + 1;
1191 if (offset < 0)
1192 {
1193 offset = 0;
1194 }
1195 }
1196 result = &(self->content[offset]);
1197 }
1198 return result;
1199}
1200
1201
1202/**
1203 Extract the content.
1204
1205 @param self Dynamic String
1206 @return Content of dynamic string.
1207
1208 The content is removed from the dynamic string. This enables destruction
1209 of the dynamic string without deallocation of the content.
1210*/
1211TRIO_PUBLIC char *
1212trio_string_extract(trio_string_t *self)
1213{
1214 char *result;
1215
1216 assert(self);
1217
1218 result = self->content;
1219 /* FIXME: Allocate new empty buffer? */
1220 self->content = NULL;
1221 self->length = self->allocated = 0;
1222 return result;
1223}
1224
1225
1226/**
1227 Set the content of the dynamic string.
1228
1229 @param self Dynamic String
1230 @param buffer The new content.
1231
1232 Sets the content of the dynamic string to a copy @p buffer.
1233 An existing content will be deallocated first, if necessary.
1234
1235 @remark
1236 This function will make a copy of @p buffer.
1237 You are responsible for deallocating @p buffer yourself.
1238*/
1239TRIO_PUBLIC void
1240trio_xstring_set(trio_string_t *self,
1241 char *buffer)
1242{
1243 assert(self);
1244
1245 trio_destroy(self->content);
1246 self->content = trio_duplicate(buffer);
1247}
1248
1249
1250/*
1251 * trio_string_size
1252 */
1253TRIO_PUBLIC int
1254trio_string_size(trio_string_t *self)
1255{
1256 assert(self);
1257
1258 return self->allocated;
1259}
1260
1261
1262/*
1263 * trio_string_terminate
1264 */
1265TRIO_PUBLIC void
1266trio_string_terminate(trio_string_t *self)
1267{
1268 char *end;
1269
1270 assert(self);
1271
1272 end = trio_string_get(self, -1);
1273 if (end)
1274 {
1275 *end = NIL;
1276 }
1277}
1278
1279
1280/**
1281 Append the second string to the first.
1282
1283 @param self Dynamic string to be modified.
1284 @param other Dynamic string to copy from.
1285 @return Boolean value indicating success or failure.
1286*/
1287TRIO_PUBLIC int
1288trio_string_append(trio_string_t *self,
1289 trio_string_t *other)
1290{
1291 size_t length;
1292
1293 assert(self);
1294 assert(other);
1295
1296 length = self->length + other->length;
1297 if (!TrioStringGrowTo(self, length))
1298 goto error;
1299 trio_copy(&self->content[self->length], other->content);
1300 self->length = length;
1301 return TRUE;
1302
1303 error:
1304 return FALSE;
1305}
1306
1307
1308/*
1309 * trio_xstring_append
1310 */
1311TRIO_PUBLIC int
1312trio_xstring_append(trio_string_t *self,
1313 const char *other)
1314{
1315 size_t length;
1316
1317 assert(self);
1318 assert(other);
1319
1320 length = self->length + trio_length(other);
1321 if (!TrioStringGrowTo(self, length))
1322 goto error;
1323 trio_copy(&self->content[self->length], other);
1324 self->length = length;
1325 return TRUE;
1326
1327 error:
1328 return FALSE;
1329}
1330
1331
1332/*
1333 * trio_xstring_append_char
1334 */
1335TRIO_PUBLIC int
1336trio_xstring_append_char(trio_string_t *self,
1337 char character)
1338{
1339 assert(self);
1340
1341 if (self->length >= trio_string_size(self))
1342 {
1343 if (!TrioStringGrow(self, 0))
1344 goto error;
1345 }
1346 self->content[self->length] = character;
1347 self->length++;
1348 return TRUE;
1349
1350 error:
1351 return FALSE;
1352}
1353
1354
1355/**
1356 Search for the first occurrence of second parameter in the first.
1357
1358 @param self Dynamic string to be modified.
1359 @param other Dynamic string to copy from.
1360 @return Boolean value indicating success or failure.
1361*/
1362TRIO_PUBLIC int
1363trio_string_contains(trio_string_t *self,
1364 trio_string_t *other)
1365{
1366 assert(self);
1367 assert(other);
1368
1369 return trio_contains(self->content, other->content);
1370}
1371
1372
1373/*
1374 * trio_xstring_contains
1375 */
1376TRIO_PUBLIC int
1377trio_xstring_contains(trio_string_t *self,
1378 const char *other)
1379{
1380 assert(self);
1381 assert(other);
1382
1383 return trio_contains(self->content, other);
1384}
1385
1386
1387/*
1388 * trio_string_copy
1389 */
1390TRIO_PUBLIC int
1391trio_string_copy(trio_string_t *self,
1392 trio_string_t *other)
1393{
1394 assert(self);
1395 assert(other);
1396
1397 self->length = 0;
1398 return trio_string_append(self, other);
1399}
1400
1401
1402/*
1403 * trio_xstring_copy
1404 */
1405TRIO_PUBLIC int
1406trio_xstring_copy(trio_string_t *self,
1407 const char *other)
1408{
1409 assert(self);
1410 assert(other);
1411
1412 self->length = 0;
1413 return trio_xstring_append(self, other);
1414}
1415
1416
1417/*
1418 * trio_string_duplicate
1419 */
1420TRIO_PUBLIC trio_string_t *
1421trio_string_duplicate(trio_string_t *other)
1422{
1423 trio_string_t *self;
1424
1425 assert(other);
1426
1427 self = TrioStringAlloc();
1428 if (self)
1429 {
1430 self->content = TrioDuplicateMax(other->content, other->length);
1431 if (self->content)
1432 {
1433 self->length = other->length;
1434 self->allocated = self->length + 1;
1435 }
1436 else
1437 {
1438 self->length = self->allocated = 0;
1439 }
1440 }
1441 return self;
1442}
1443
1444
1445/*
1446 * trio_xstring_duplicate
1447 */
1448TRIO_PUBLIC trio_string_t *
1449trio_xstring_duplicate(const char *other)
1450{
1451 trio_string_t *self;
1452
1453 assert(other);
1454
1455 self = TrioStringAlloc();
1456 if (self)
1457 {
1458 self->content = TrioDuplicateMax(other, trio_length(other));
1459 if (self->content)
1460 {
1461 self->length = trio_length(self->content);
1462 self->allocated = self->length + 1;
1463 }
1464 else
1465 {
1466 self->length = self->allocated = 0;
1467 }
1468 }
1469 return self;
1470}
1471
1472
1473/*
1474 * trio_string_equal
1475 */
1476TRIO_PUBLIC int
1477trio_string_equal(trio_string_t *self,
1478 trio_string_t *other)
1479{
1480 assert(self);
1481 assert(other);
1482
1483 return trio_equal(self->content, other->content);
1484}
1485
1486
1487/*
1488 * trio_xstring_equal
1489 */
1490TRIO_PUBLIC int
1491trio_xstring_equal(trio_string_t *self,
1492 const char *other)
1493{
1494 assert(self);
1495 assert(other);
1496
1497 return trio_equal(self->content, other);
1498}
1499
1500
1501/*
1502 * trio_string_equal_max
1503 */
1504TRIO_PUBLIC int
1505trio_string_equal_max(trio_string_t *self,
1506 size_t max,
1507 trio_string_t *other)
1508{
1509 assert(self);
1510 assert(other);
1511
1512 return trio_equal_max(self->content, max, other->content);
1513}
1514
1515
1516/*
1517 * trio_xstring_equal_max
1518 */
1519TRIO_PUBLIC int
1520trio_xstring_equal_max(trio_string_t *self,
1521 size_t max,
1522 const char *other)
1523{
1524 assert(self);
1525 assert(other);
1526
1527 return trio_equal_max(self->content, max, other);
1528}
1529
1530
1531/*
1532 * trio_string_equal_case
1533 */
1534TRIO_PUBLIC int
1535trio_string_equal_case(trio_string_t *self,
1536 trio_string_t *other)
1537{
1538 assert(self);
1539 assert(other);
1540
1541 return trio_equal_case(self->content, other->content);
1542}
1543
1544
1545/*
1546 * trio_xstring_equal_case
1547 */
1548TRIO_PUBLIC int
1549trio_xstring_equal_case(trio_string_t *self,
1550 const char *other)
1551{
1552 assert(self);
1553 assert(other);
1554
1555 return trio_equal_case(self->content, other);
1556}
1557
1558
1559/*
1560 * trio_string_equal_case_max
1561 */
1562TRIO_PUBLIC int
1563trio_string_equal_case_max(trio_string_t *self,
1564 size_t max,
1565 trio_string_t *other)
1566{
1567 assert(self);
1568 assert(other);
1569
1570 return trio_equal_case_max(self->content, max, other->content);
1571}
1572
1573
1574/*
1575 * trio_xstring_equal_case_max
1576 */
1577TRIO_PUBLIC int
1578trio_xstring_equal_case_max(trio_string_t *self,
1579 size_t max,
1580 const char *other)
1581{
1582 assert(self);
1583 assert(other);
1584
1585 return trio_equal_case_max(self->content, max, other);
1586}
1587
1588
1589/*
1590 * trio_string_format_data_max
1591 */
1592TRIO_PUBLIC size_t
1593trio_string_format_date_max(trio_string_t *self,
1594 size_t max,
1595 const char *format,
1596 const struct tm *datetime)
1597{
1598 assert(self);
1599
1600 return trio_format_date_max(self->content, max, format, datetime);
1601}
1602
1603
1604/*
1605 * trio_string_index
1606 */
1607TRIO_PUBLIC char *
1608trio_string_index(trio_string_t *self,
1609 int character)
1610{
1611 assert(self);
1612
1613 return trio_index(self->content, character);
1614}
1615
1616
1617/*
1618 * trio_string_index_last
1619 */
1620TRIO_PUBLIC char *
1621trio_string_index_last(trio_string_t *self,
1622 int character)
1623{
1624 assert(self);
1625
1626 return trio_index_last(self->content, character);
1627}
1628
1629
1630/*
1631 * trio_string_length
1632 */
1633TRIO_PUBLIC int
1634trio_string_length(trio_string_t *self)
1635{
1636 assert(self);
1637
1638 if (self->length == 0)
1639 {
1640 self->length = trio_length(self->content);
1641 }
1642 return self->length;
1643}
1644
1645
1646/*
1647 * trio_string_lower
1648 */
1649TRIO_PUBLIC int
1650trio_string_lower(trio_string_t *self)
1651{
1652 assert(self);
1653
1654 return trio_lower(self->content);
1655}
1656
1657
1658/*
1659 * trio_string_match
1660 */
1661TRIO_PUBLIC int
1662trio_string_match(trio_string_t *self,
1663 trio_string_t *other)
1664{
1665 assert(self);
1666 assert(other);
1667
1668 return trio_match(self->content, other->content);
1669}
1670
1671
1672/*
1673 * trio_xstring_match
1674 */
1675TRIO_PUBLIC int
1676trio_xstring_match(trio_string_t *self,
1677 const char *other)
1678{
1679 assert(self);
1680 assert(other);
1681
1682 return trio_match(self->content, other);
1683}
1684
1685
1686/*
1687 * trio_string_match_case
1688 */
1689TRIO_PUBLIC int
1690trio_string_match_case(trio_string_t *self,
1691 trio_string_t *other)
1692{
1693 assert(self);
1694 assert(other);
1695
1696 return trio_match_case(self->content, other->content);
1697}
1698
1699
1700/*
1701 * trio_xstring_match_case
1702 */
1703TRIO_PUBLIC int
1704trio_xstring_match_case(trio_string_t *self,
1705 const char *other)
1706{
1707 assert(self);
1708 assert(other);
1709
1710 return trio_match_case(self->content, other);
1711}
1712
1713
1714/*
1715 * trio_string_substring
1716 */
1717TRIO_PUBLIC char *
1718trio_string_substring(trio_string_t *self,
1719 trio_string_t *other)
1720{
1721 assert(self);
1722 assert(other);
1723
1724 return trio_substring(self->content, other->content);
1725}
1726
1727
1728/*
1729 * trio_xstring_substring
1730 */
1731TRIO_PUBLIC char *
1732trio_xstring_substring(trio_string_t *self,
1733 const char *other)
1734{
1735 assert(self);
1736 assert(other);
1737
1738 return trio_substring(self->content, other);
1739}
1740
1741
1742/*
1743 * trio_string_upper
1744 */
1745TRIO_PUBLIC int
1746trio_string_upper(trio_string_t *self)
1747{
1748 assert(self);
1749
1750 return trio_upper(self->content);
1751}
1752
1753/** @} End of DynamicStrings */