1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* strbuf.h */ |
4 | /* */ |
5 | /* Variable sized string buffers */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2001-2009, Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 52 */ |
11 | /* D-70794 Filderstadt */ |
12 | /* EMail: uz@cc65.org */ |
13 | /* */ |
14 | /* */ |
15 | /* This software is provided 'as-is', without any expressed or implied */ |
16 | /* warranty. In no event will the authors be held liable for any damages */ |
17 | /* arising from the use of this software. */ |
18 | /* */ |
19 | /* Permission is granted to anyone to use this software for any purpose, */ |
20 | /* including commercial applications, and to alter it and redistribute it */ |
21 | /* freely, subject to the following restrictions: */ |
22 | /* */ |
23 | /* 1. The origin of this software must not be misrepresented; you must not */ |
24 | /* claim that you wrote the original software. If you use this software */ |
25 | /* in a product, an acknowledgment in the product documentation would be */ |
26 | /* appreciated but is not required. */ |
27 | /* 2. Altered source versions must be plainly marked as such, and must not */ |
28 | /* be misrepresented as being the original software. */ |
29 | /* 3. This notice may not be removed or altered from any source */ |
30 | /* distribution. */ |
31 | /* */ |
32 | /*****************************************************************************/ |
33 | |
34 | |
35 | |
36 | #ifndef STRBUF_H |
37 | #define STRBUF_H |
38 | |
39 | |
40 | |
41 | #include <stdarg.h> |
42 | #include <string.h> |
43 | |
44 | /* common */ |
45 | #include "attrib.h" |
46 | #include "check.h" |
47 | #include "inline.h" |
48 | |
49 | |
50 | |
51 | /*****************************************************************************/ |
52 | /* Data */ |
53 | /*****************************************************************************/ |
54 | |
55 | |
56 | |
57 | typedef struct StrBuf StrBuf; |
58 | struct StrBuf { |
59 | char* Buf; /* Pointer to buffer */ |
60 | unsigned Len; /* Length of the string */ |
61 | unsigned Index; /* Used for reading (Get and friends) */ |
62 | unsigned Allocated; /* Size of allocated memory */ |
63 | }; |
64 | |
65 | /* An empty string buf */ |
66 | extern const StrBuf EmptyStrBuf; |
67 | |
68 | /* Initializer for static string bufs */ |
69 | #define STATIC_STRBUF_INITIALIZER { 0, 0, 0, 0 } |
70 | |
71 | /* Initializer for auto string bufs */ |
72 | #define AUTO_STRBUF_INITIALIZER { 0, 0, 0, 0 } |
73 | |
74 | /* Initialize with a string literal (beware: evaluates str twice!) */ |
75 | #define LIT_STRBUF_INITIALIZER(str) { (char*)str, sizeof(str)-1, 0, 0 } |
76 | |
77 | |
78 | |
79 | /*****************************************************************************/ |
80 | /* Code */ |
81 | /*****************************************************************************/ |
82 | |
83 | |
84 | |
85 | #if defined(HAVE_INLINE) |
86 | INLINE StrBuf* SB_Init (StrBuf* B) |
87 | /* Initialize a string buffer */ |
88 | { |
89 | *B = EmptyStrBuf; |
90 | return B; |
91 | } |
92 | #else |
93 | StrBuf* SB_Init (StrBuf* B); |
94 | #endif |
95 | |
96 | StrBuf* SB_InitFromString (StrBuf* B, const char* S); |
97 | /* Initialize a string buffer from a literal string. Beware: The buffer won't |
98 | ** store a copy but a pointer to the actual string. A buffer initialized with |
99 | ** this routine may be "forgotten" without calling SB_Done, since no memory |
100 | ** has been allocated. |
101 | */ |
102 | |
103 | void SB_Done (StrBuf* B); |
104 | /* Free the data of a string buffer (but not the struct itself) */ |
105 | |
106 | StrBuf* NewStrBuf (void); |
107 | /* Allocate, initialize and return a new StrBuf */ |
108 | |
109 | void FreeStrBuf (StrBuf* B); |
110 | /* Free a string buffer */ |
111 | |
112 | void SB_Realloc (StrBuf* B, unsigned NewSize); |
113 | /* Reallocate the string buffer space, make sure at least NewSize bytes are |
114 | ** available. |
115 | */ |
116 | |
117 | #if defined(HAVE_INLINE) |
118 | INLINE unsigned SB_GetLen (const StrBuf* B) |
119 | /* Return the length of the buffer contents */ |
120 | { |
121 | return B->Len; |
122 | } |
123 | #else |
124 | # define SB_GetLen(B) (B)->Len |
125 | #endif |
126 | |
127 | #if defined(HAVE_INLINE) |
128 | INLINE unsigned SB_GetIndex (const StrBuf* B) |
129 | /* Return the user index of the string buffer */ |
130 | { |
131 | return B->Index; |
132 | } |
133 | #else |
134 | # define SB_GetIndex(B) (B)->Index |
135 | #endif |
136 | |
137 | #if defined(HAVE_INLINE) |
138 | INLINE void SB_SetIndex (StrBuf* B, unsigned Index) |
139 | /* Set the user index of the string buffer */ |
140 | { |
141 | B->Index = Index; |
142 | } |
143 | #else |
144 | # define SB_SetIndex(B, Idx) ((B)->Index = (Idx)) |
145 | #endif |
146 | |
147 | #if defined(HAVE_INLINE) |
148 | INLINE const char* SB_GetConstBuf (const StrBuf* B) |
149 | /* Return a buffer pointer */ |
150 | { |
151 | return B->Buf; |
152 | } |
153 | #else |
154 | # define SB_GetConstBuf(B) (B)->Buf |
155 | #endif |
156 | |
157 | #if defined(HAVE_INLINE) |
158 | INLINE char* SB_GetBuf (StrBuf* B) |
159 | /* Return a buffer pointer */ |
160 | { |
161 | return B->Buf; |
162 | } |
163 | #else |
164 | # define SB_GetBuf(B) (B)->Buf |
165 | #endif |
166 | |
167 | #if defined(HAVE_INLINE) |
168 | INLINE char SB_At (const StrBuf* B, unsigned Index) |
169 | /* Get a character from the buffer */ |
170 | { |
171 | PRECONDITION (Index < B->Len); |
172 | return B->Buf[Index]; |
173 | } |
174 | #else |
175 | char SB_At (const StrBuf* B, unsigned Index); |
176 | /* Get a character from the buffer */ |
177 | #endif |
178 | |
179 | #if defined(HAVE_INLINE) |
180 | INLINE char SB_AtUnchecked (const StrBuf* B, unsigned Index) |
181 | /* Get a character from the buffer */ |
182 | { |
183 | return B->Buf[Index]; |
184 | } |
185 | #else |
186 | # define SB_AtUnchecked(B, Index) ((B)->Buf[Index]) |
187 | #endif |
188 | |
189 | #if defined(HAVE_INLINE) |
190 | INLINE int SB_IsEmpty (const StrBuf* B) |
191 | /* Return true if the string buffer is empty */ |
192 | { |
193 | return (B->Len == 0); |
194 | } |
195 | #else |
196 | # define SB_IsEmpty(B) ((B)->Len == 0) |
197 | #endif |
198 | |
199 | #if defined(HAVE_INLINE) |
200 | INLINE int SB_NotEmpty (const StrBuf* B) |
201 | /* Return true if the string buffer is not empty */ |
202 | { |
203 | return (B->Len > 0); |
204 | } |
205 | #else |
206 | # define SB_NotEmpty(B) ((B)->Len > 0) |
207 | #endif |
208 | |
209 | #if defined(HAVE_INLINE) |
210 | INLINE void SB_Clear (StrBuf* B) |
211 | /* Clear the string buffer (make it empty) */ |
212 | { |
213 | B->Len = B->Index = 0; |
214 | } |
215 | #else |
216 | # define SB_Clear(B) ((B)->Len = (B)->Index = 0) |
217 | #endif |
218 | |
219 | #if defined(HAVE_INLINE) |
220 | INLINE void SB_Reset (StrBuf* B) |
221 | /* Reset the string buffer index to zero */ |
222 | { |
223 | B->Index = 0; |
224 | } |
225 | #else |
226 | # define SB_Reset(B) ((B)->Index = 0) |
227 | #endif |
228 | |
229 | #if defined(HAVE_INLINE) |
230 | INLINE char SB_Get (StrBuf* B) |
231 | /* Return the next character from the string incrementing Index. Returns NUL |
232 | ** if the end of the string is reached. |
233 | */ |
234 | { |
235 | return (B->Index < B->Len)? B->Buf[B->Index++] : '\0'; |
236 | } |
237 | #else |
238 | # define SB_Get(B) (((B)->Index < (B)->Len)? (B)->Buf[(B)->Index++] : '\0') |
239 | #endif |
240 | |
241 | #if defined(HAVE_INLINE) |
242 | INLINE char SB_Peek (const StrBuf* B) |
243 | /* Look at the next character from the string without incrementing Index. |
244 | ** Returns NUL if the end of the string is reached. |
245 | */ |
246 | { |
247 | return (B->Index < B->Len)? B->Buf[B->Index] : '\0'; |
248 | } |
249 | #else |
250 | # define SB_Peek(B) (((B)->Index < (B)->Len)? (B)->Buf[(B)->Index] : '\0') |
251 | #endif |
252 | |
253 | #if defined(HAVE_INLINE) |
254 | INLINE char SB_LookAt (const StrBuf* B, unsigned Index) |
255 | /* Look at a specific character from the string. Returns NUL if the given |
256 | ** index is greater than the size of the string. |
257 | */ |
258 | { |
259 | return (Index < B->Len)? B->Buf[Index] : '\0'; |
260 | } |
261 | #else |
262 | # define SB_LookAt(B,Index) (((Index) < (B)->Len)? (B)->Buf[(Index)] : '\0') |
263 | #endif |
264 | |
265 | #if defined(HAVE_INLINE) |
266 | INLINE char SB_LookAtLast (const StrBuf* B) |
267 | /* Look at the last character from the string. Returns NUL if the string buffer |
268 | ** is empty. |
269 | */ |
270 | { |
271 | return (B->Len > 0)? B->Buf[B->Len-1] : '\0'; |
272 | } |
273 | #else |
274 | # define SB_LookAtLast(B) (((B)->Len > 0)? (B)->Buf[(B)->Len-1] : '\0') |
275 | #endif |
276 | |
277 | #if defined(HAVE_INLINE) |
278 | INLINE void SB_Skip (StrBuf* B) |
279 | /* Skip the next character in the string buffer if this is possible. */ |
280 | { |
281 | if (B->Index < B->Len) { |
282 | ++B->Index; |
283 | } |
284 | } |
285 | #else |
286 | # define SB_Skip(B) do { if ((B)->Index < (B)->Len) ++(B)->Index; } while (0) |
287 | #endif |
288 | |
289 | #if defined(HAVE_INLINE) |
290 | INLINE void SB_SkipMultiple (StrBuf* B, unsigned Count) |
291 | /* Skip a number of characters in the string buffer if this is possible. */ |
292 | { |
293 | if ((B->Index += Count) > B->Len) { |
294 | B->Index = B->Len; |
295 | } |
296 | } |
297 | #else |
298 | # define SB_SkipMultiple(B, Count) \ |
299 | do { if (((B)->Index += (Count)) > (B)->Len) (B)->Index = (B)->Len; } while (0) |
300 | #endif |
301 | |
302 | void SB_Drop (StrBuf* B, unsigned Count); |
303 | /* Drop characters from the end of the string. */ |
304 | |
305 | void SB_Terminate (StrBuf* B); |
306 | /* Zero terminate the given string buffer. NOTE: The terminating zero is not |
307 | ** accounted for in B->Len, if you want that, you have to use AppendChar! |
308 | */ |
309 | |
310 | void SB_CopyBuf (StrBuf* Target, const char* Buf, unsigned Size); |
311 | /* Copy Buf to Target, discarding the old contents of Target */ |
312 | |
313 | #if defined(HAVE_INLINE) |
314 | INLINE void SB_CopyStr (StrBuf* Target, const char* S) |
315 | /* Copy S to Target, discarding the old contents of Target */ |
316 | { |
317 | SB_CopyBuf (Target, S, strlen (S)); |
318 | } |
319 | #else |
320 | void SB_CopyStr (StrBuf* Target, const char* S); |
321 | /* Copy S to Target, discarding the old contents of Target */ |
322 | #endif |
323 | |
324 | #if defined(HAVE_INLINE) |
325 | INLINE void SB_Copy (StrBuf* Target, const StrBuf* Source) |
326 | /* Copy Source to Target, discarding the old contents of Target */ |
327 | { |
328 | SB_CopyBuf (Target, Source->Buf, Source->Len); |
329 | Target->Index = Source->Index; |
330 | } |
331 | #else |
332 | void SB_Copy (StrBuf* Target, const StrBuf* Source); |
333 | /* Copy Source to Target, discarding the old contents of Target */ |
334 | #endif |
335 | |
336 | void SB_AppendChar (StrBuf* B, int C); |
337 | /* Append a character to a string buffer */ |
338 | |
339 | void SB_AppendBuf (StrBuf* B, const char* S, unsigned Size); |
340 | /* Append a character buffer to the end of the string buffer */ |
341 | |
342 | #if defined(HAVE_INLINE) |
343 | INLINE void SB_AppendStr (StrBuf* B, const char* S) |
344 | /* Append a string to the end of the string buffer */ |
345 | { |
346 | SB_AppendBuf (B, S, strlen (S)); |
347 | } |
348 | #else |
349 | void SB_AppendStr (StrBuf* B, const char* S); |
350 | /* Append a string to the end of the string buffer */ |
351 | #endif |
352 | |
353 | #if defined(HAVE_INLINE) |
354 | INLINE void SB_Append (StrBuf* Target, const StrBuf* Source) |
355 | /* Append the contents of Source to Target */ |
356 | { |
357 | SB_AppendBuf (Target, Source->Buf, Source->Len); |
358 | } |
359 | #else |
360 | void SB_Append (StrBuf* Target, const StrBuf* Source); |
361 | /* Append the contents of Source to Target */ |
362 | #endif |
363 | |
364 | #if defined(HAVE_INLINE) |
365 | INLINE void SB_Cut (StrBuf* B, unsigned Len) |
366 | /* Cut the contents of B at the given length. If the current length of the |
367 | ** buffer is smaller than Len, nothing will happen. |
368 | */ |
369 | { |
370 | if (Len < B->Len) { |
371 | B->Len = Len; |
372 | } |
373 | } |
374 | #else |
375 | void SB_Cut (StrBuf* B, unsigned Len); |
376 | /* Cut the contents of B at the given length. If the current length of the |
377 | ** buffer is smaller than Len, nothing will happen. |
378 | */ |
379 | #endif |
380 | |
381 | void SB_Slice (StrBuf* Target, const StrBuf* Source, unsigned Start, unsigned Len); |
382 | /* Copy a slice from Source into Target. The current contents of Target are |
383 | ** destroyed. If Start is greater than the length of Source, or if Len |
384 | ** characters aren't available, the result will be a buffer with less than Len |
385 | ** bytes. |
386 | */ |
387 | |
388 | void SB_Move (StrBuf* Target, StrBuf* Source); |
389 | /* Move the complete contents of Source to target. This will delete the old |
390 | ** contents of Target, and Source will be empty after the call. |
391 | */ |
392 | |
393 | void SB_ToLower (StrBuf* S); |
394 | /* Convert all characters in S to lower case */ |
395 | |
396 | void SB_ToUpper (StrBuf* S); |
397 | /* Convert all characters in S to upper case */ |
398 | |
399 | int SB_Compare (const StrBuf* S1, const StrBuf* S2); |
400 | /* Do a lexical compare of S1 and S2. See strcmp for result codes. */ |
401 | |
402 | int SB_CompareStr (const StrBuf* S1, const char* S2); |
403 | /* Do a lexical compare of S1 and S2. See strcmp for result codes. */ |
404 | |
405 | void SB_VPrintf (StrBuf* S, const char* Format, va_list ap) attribute ((format (printf, 2, 0))); |
406 | /* printf function with S as target. The function is safe, which means that |
407 | ** the current contents of S are discarded, and are allocated again with |
408 | ** a matching size for the output. The function will call FAIL when problems |
409 | ** are detected (anything that let xsnprintf return -1). |
410 | */ |
411 | |
412 | void SB_Printf (StrBuf* S, const char* Format, ...) attribute ((format (printf, 2, 3))); |
413 | /* vprintf function with S as target. The function is safe, which means that |
414 | ** the current contents of S are discarded, and are allocated again with |
415 | ** a matching size for the output. The function will call FAIL when problems |
416 | ** are detected (anything that let xsnprintf return -1). |
417 | */ |
418 | |
419 | |
420 | |
421 | /* End of strbuf.h */ |
422 | |
423 | #endif |
424 | |