Line data Source code
1 : /******************************************************************************
2 : * Darmstadtium - a library of data structures
3 : * Ds_str - a string library
4 : * One of the Bohr Game Libraries (see chaoslizard.org/devel/bohr)
5 : * Copyright (C) 2008 Charles Lindsay. Some rights reserved; see COPYING.
6 : * $Id: ds_str.h 323 2008-01-06 03:55:26Z chaz $
7 : ******************************************************************************/
8 :
9 :
10 : #ifndef __bohr_ds_str_h__
11 : #define __bohr_ds_str_h__
12 :
13 : #include <kdbhelper.h>
14 : #include <stdarg.h>
15 : #include <stddef.h>
16 : #include <stdio.h>
17 : #include <stdlib.h>
18 : #include <string.h>
19 :
20 :
21 : // Controls inlining of this library's functions.
22 : #ifndef Ds_STR_INLINE
23 : #ifdef Ds_INLINE
24 : #define Ds_STR_INLINE Ds_INLINE
25 : #else
26 : #define Ds_STR_INLINE inline static
27 : #endif
28 : #endif
29 :
30 : // Nix non-critical C99 keywords in compilers that don't support them.
31 : #if ((!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(restrict))
32 : #define restrict
33 : #define _Ds_STR_DEFINED_RESTRICT
34 : #endif
35 :
36 :
37 : // How to grow when the buffer is insufficient. The following values are
38 : // available: 1 - the buffer will grow to the exact needed size; 2 - the buffer
39 : // will double in size until sufficient (default); or 4 - the buffer will
40 : // quadruple in size until sufficient.
41 : #ifndef Ds_STR_BEHAVIOR
42 : #define Ds_STR_BEHAVIOR 2
43 : #endif
44 :
45 :
46 : // A string.
47 : typedef struct Ds_str
48 : {
49 : char * str; // the string itself
50 : int len; // its length
51 : int size; // how big the str buffer is
52 :
53 : } Ds_str;
54 : #define Ds_STR_INIT \
55 : { \
56 : NULL, 0, 0 \
57 : } // initializer
58 :
59 :
60 : /* Initializes the Ds_str. Only necessary to reserve initial space (if the
61 : * Ds_str was initialized to Ds_STR_INIT as it was declared, it can be used
62 : * without first having Ds_InitStr() called on it). Returns 0/nonzero on
63 : * failure/success. Will not fail if size is 0.
64 : */
65 : Ds_STR_INLINE int Ds_InitStr (Ds_str * restrict s, int size)
66 : {
67 103 : *s = (Ds_str) Ds_STR_INIT;
68 :
69 : if (size > 0)
70 : {
71 103 : if (!(s->str = (char *) malloc (size * sizeof (char)))) return 0;
72 :
73 103 : s->str[0] = '\0';
74 103 : s->size = size;
75 : }
76 :
77 : return 1;
78 : }
79 :
80 : /* Frees all memory associated with the Ds_str.
81 : */
82 : Ds_STR_INLINE void Ds_FreeStr (Ds_str * restrict s)
83 : {
84 2193 : if (s->str)
85 : {
86 1943 : elektraFree (s->str);
87 : }
88 2090 : *s = (Ds_str) Ds_STR_INIT;
89 : }
90 :
91 : /* Appends a string onto the Ds_str (note: setting the destination's length to
92 : * 0 before calling this function makes it copy instead of append). If the
93 : * source string length isn't known, use a negative number. Returns the source
94 : * string length (as given or calculated) on success, or a negative number on
95 : * failure.
96 : */
97 1902 : Ds_STR_INLINE int Ds_StrCat (Ds_str * restrict dest, const char * restrict source, int source_len)
98 : {
99 : int new_size;
100 :
101 1902 : if (source_len < 0) source_len = (int) strlen (source);
102 :
103 : #if (Ds_STR_BEHAVIOR == 1)
104 : new_size = dest->len + source_len + 1;
105 : #else
106 1902 : new_size = (dest->size ? dest->size : 1);
107 5456 : while (new_size < dest->len + source_len + 1)
108 : #if (Ds_STR_BEHAVIOR == 4)
109 : new_size <<= 2; // the same as *= 4
110 : #else
111 3554 : new_size <<= 1; // the same as *= 2
112 : #endif
113 : #endif
114 1902 : if (new_size > dest->size)
115 : {
116 : char * new_str;
117 1840 : if (!(new_str = (char *) realloc (dest->str, new_size * sizeof (char)))) return -1;
118 1840 : dest->str = new_str;
119 1840 : dest->size = new_size;
120 : }
121 :
122 1902 : memcpy (dest->str + dest->len, source, source_len * sizeof (char));
123 1902 : dest->len += source_len;
124 1902 : dest->str[dest->len] = '\0';
125 :
126 1902 : return source_len;
127 : }
128 :
129 : /* Appends a printf()-formatted string onto the Ds_str (note: setting the
130 : * destination's length to 0 before calling this function makes it copy instead
131 : * of append). Returns the length of the formatted string on success, or a
132 : * negative number on failure (in which case the contents of the destination
133 : * may have changed, unfortunately).
134 : */
135 8 : Ds_STR_INLINE int Ds_StrCatVPrint (Ds_str * restrict dest, const char * restrict format, va_list args)
136 : {
137 : va_list args_copy;
138 : int len;
139 :
140 8 : va_copy (args_copy, args);
141 8 : len = vsnprintf (dest->str + dest->len, dest->size - dest->len, format, args_copy);
142 8 : va_end (args_copy);
143 :
144 8 : if (len >= dest->size - dest->len)
145 : {
146 : int new_size;
147 : #if (Ds_STR_BEHAVIOR == 1)
148 : new_size = dest->len + len + 1;
149 : #else
150 2 : new_size = (dest->size ? dest->size : 1);
151 6 : while (new_size < dest->len + len + 1)
152 : #if (Ds_STR_BEHAVIOR == 4)
153 : new_size <<= 2; // the same as *= 4
154 : #else
155 4 : new_size <<= 1; // the same as *= 2
156 : #endif
157 : #endif
158 2 : if (new_size > dest->size)
159 : {
160 : char * new_str;
161 2 : if (!(new_str = (char *) realloc (dest->str, new_size * sizeof (char)))) return -1;
162 2 : dest->str = new_str;
163 2 : dest->size = new_size;
164 : }
165 :
166 2 : len = vsnprintf (dest->str + dest->len, dest->size - dest->len, format, args);
167 : }
168 :
169 8 : if (len >= dest->size - dest->len)
170 : {
171 : len = -1;
172 : }
173 : else
174 : {
175 8 : dest->len += len;
176 : }
177 :
178 : return len;
179 : }
180 :
181 : /* Same as Ds_StrCatVPrint(), except it takes an argument list instead of a
182 : * va_list.
183 : */
184 : Ds_STR_INLINE int Ds_StrCatPrint (Ds_str * restrict dest, const char * restrict format, ...)
185 : {
186 : int len;
187 : va_list args;
188 :
189 : va_start (args, format);
190 : len = Ds_StrCatVPrint (dest, format, args);
191 : va_end (args);
192 :
193 : return len;
194 : }
195 :
196 : /* Manually sets the buffer size for the Ds_str, truncating it if necessary.
197 : * Use a size of s->len+1 to shrink the buffer down to exactly the necessary
198 : * size to hold its current contents. Returns 0/nonzero on failure/success.
199 : * Succeeds but does nothing if size is 0 or less.
200 : */
201 0 : Ds_STR_INLINE int Ds_ResizeStr (Ds_str * restrict s, int size)
202 : {
203 0 : if (size > 0)
204 : {
205 : char * new_str;
206 :
207 0 : if (!(new_str = (char *) realloc (s->str, size * sizeof (char)))) return 0;
208 :
209 0 : s->str = new_str;
210 0 : s->size = size;
211 :
212 0 : if (s->len > size - 1)
213 : {
214 0 : s->str[s->len = size - 1] = '\0';
215 : }
216 : }
217 :
218 : return 1;
219 : }
220 :
221 :
222 : #ifdef _Ds_STR_DEFINED_RESTRICT
223 : #undef _Ds_STR_DEFINED_RESTRICT
224 : #undef restrict
225 : #endif
226 :
227 : #endif
|