1 /*
2 * Copyright (c) 1998-2002, Darren Hiebert
3 *
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
6 *
7 * This module contains functions supporting resizeable strings.
8 */
9
10 /*
11 * INCLUDE FILES
12 */
13 #include "general.h" /* must always come first */
14
15 #include <limits.h> /* to define INT_MAX */
16 #include <string.h>
17 #include <ctype.h>
18
19 #include "debug.h"
20 #include "routines.h"
21 #include "vstring.h"
22 #include "trashbox.h"
23
24 /*
25 * DATA DEFINITIONS
26 */
27 static const size_t vStringInitialSize = 32;
28
29 /*
30 * FUNCTION DEFINITIONS
31 */
32
33 /*
34 * External interface
35 */
36
vStringResize(vString * const string,const size_t newSize)37 extern void vStringResize (vString *const string, const size_t newSize)
38 {
39 size_t size = vStringInitialSize;
40
41 while (size < newSize)
42 size *= 2;
43
44 if (size > string->size)
45 {
46 string->size = size;
47 string->buffer = xRealloc (string->buffer, size, char);
48 }
49 }
50
vStringTruncate(vString * const string,const size_t length)51 extern void vStringTruncate (vString *const string, const size_t length)
52 {
53 Assert (length <= string->length);
54 string->length = length;
55 string->buffer[string->length] = '\0';
56 DebugStatement ( memset (string->buffer + string->length, 0,
57 string->size - string->length); )
58 }
59
vStringDelete(vString * const string)60 extern void vStringDelete (vString *const string)
61 {
62 if (string != NULL)
63 {
64 if (string->buffer != NULL)
65 eFree (string->buffer);
66 eFree (string);
67 }
68 }
69
vStringNew(void)70 extern vString *vStringNew (void)
71 {
72 vString *const string = xMalloc (1, vString);
73
74 string->length = 0;
75 string->size = vStringInitialSize;
76 string->buffer = xMalloc (string->size, char);
77
78 vStringClear (string);
79
80 return string;
81 }
82
vStringNewCopy(const vString * const string)83 extern vString *vStringNewCopy (const vString *const string)
84 {
85 vString *vs = vStringNew ();
86 vStringCatS (vs, string->buffer);
87 return vs;
88 }
89
vStringNewInit(const char * const s)90 extern vString *vStringNewInit (const char *const s)
91 {
92 vString *vs = vStringNew ();
93 vStringCatS (vs, s);
94 return vs;
95 }
96
vStringNewNInit(const char * const s,const size_t length)97 extern vString *vStringNewNInit (const char *const s, const size_t length)
98 {
99 vString *vs = vStringNew ();
100 vStringNCatS (vs, s, length);
101 return vs;
102 }
103
stringCat(vString * const string,const char * const s,const size_t length)104 static void stringCat (
105 vString *const string, const char *const s, const size_t length)
106 {
107 if (string->length + length + 1 > string->size)
108 vStringResize (string, string->length + length + 1);
109
110 memcpy (string->buffer + string->length, s, length);
111 string->length += length;
112 vStringPut (string, '\0');
113 }
114
vStringNCat(vString * const string,const vString * const s,const size_t length)115 extern void vStringNCat (
116 vString *const string, const vString *const s, const size_t length)
117 {
118 size_t len = vStringLength (s);
119
120 len = len < length ? len: length;
121 stringCat (string, s->buffer, len);
122 }
123
vStringNCatS(vString * const string,const char * const s,const size_t length)124 extern void vStringNCatS (
125 vString *const string, const char *const s, const size_t length)
126 {
127 size_t len = strlen (s);
128
129 len = len < length ? len : length;
130 stringCat (string, s, len);
131 }
132
vStringNCatSUnsafe(vString * const string,const char * const s,const size_t length)133 extern void vStringNCatSUnsafe (
134 vString *const string, const char *const s, const size_t length)
135 {
136 stringCat (string, s, length);
137 }
138
vStringCat(vString * const string,const vString * const s)139 extern void vStringCat (vString *const string, const vString *const s)
140 {
141 size_t len = vStringLength (s);
142
143 stringCat (string, s->buffer, len);
144 }
145
vStringCatS(vString * const string,const char * const s)146 extern void vStringCatS (vString *const string, const char *const s)
147 {
148 size_t len = strlen (s);
149
150 stringCat (string, s, len);
151 }
152
153 /* Strip trailing newline from string.
154 */
vStringStripNewline(vString * const string)155 extern bool vStringStripNewline (vString *const string)
156 {
157 const size_t final = string->length - 1;
158
159 if (string->length == 0)
160 return false;
161
162 if (string->buffer [final] == '\n')
163 {
164 string->buffer [final] = '\0';
165 string->length--;
166 return true;
167 }
168
169 return false;
170 }
171
172 /* Strip leading white space from string.
173 */
vStringStripLeading(vString * const string)174 extern void vStringStripLeading (vString *const string)
175 {
176 size_t n = 0;
177
178 while (n < string->length && isspace ((int) string->buffer [n]))
179 n++;
180 if (n > 0)
181 {
182 memmove (string->buffer, string->buffer + n, string->length - n);
183 vStringTruncate (string, string->length - n);
184 }
185 }
186
187 /* Strip trailing white space from string.
188 */
vStringStripTrailing(vString * const string)189 extern void vStringStripTrailing (vString *const string)
190 {
191 while (string->length > 0 &&
192 isspace ((int) string->buffer [string->length - 1]))
193 {
194 string->length--;
195 string->buffer [string->length] = '\0';
196 }
197 }
198
199 /* Chop last character from string.
200 */
vStringChop(vString * const string)201 extern void vStringChop (vString *const string)
202 {
203 if (string->length > 0)
204 {
205 --string->length;
206 string->buffer [string->length] = '\0';
207 }
208 }
209
vStringCopy(vString * const string,const vString * const s)210 extern void vStringCopy (vString *const string, const vString *const s)
211 {
212 vStringClear (string);
213 vStringCat (string, s);
214 }
215
vStringCopyS(vString * const string,const char * const s)216 extern void vStringCopyS (vString *const string, const char *const s)
217 {
218 vStringClear (string);
219 vStringCatS (string, s);
220 }
221
vStringNCopy(vString * const string,const vString * const s,const size_t length)222 extern void vStringNCopy (
223 vString *const string, const vString *const s, const size_t length)
224 {
225 vStringClear (string);
226 vStringNCat (string, s, length);
227 }
228
vStringNCopyS(vString * const string,const char * const s,const size_t length)229 extern void vStringNCopyS (
230 vString *const string, const char *const s, const size_t length)
231 {
232 vStringClear (string);
233 vStringNCatS (string, s, length);
234 }
235
vStringCopyToLower(vString * const dest,const vString * const src)236 extern void vStringCopyToLower (vString *const dest, const vString *const src)
237 {
238 const size_t length = src->length;
239 const char *s = src->buffer;
240 char *d;
241 size_t i;
242
243 if (dest->size < src->size)
244 vStringResize (dest, src->size);
245 d = dest->buffer;
246 for (i = 0 ; i < length ; ++i)
247 {
248 int c = s [i];
249
250 d [i] = tolower (c);
251 }
252 d [i] = '\0';
253 }
254
vStringSetLength(vString * const string)255 extern void vStringSetLength (vString *const string)
256 {
257 string->length = strlen (string->buffer);
258 }
259
vStringNewOwn(char * s)260 extern vString *vStringNewOwn (char *s)
261 {
262 vString *r;
263
264 r = vStringNewInit (s);
265 eFree (s);
266
267 return r;
268 }
269
vStringDeleteUnwrap(vString * const string)270 extern char *vStringDeleteUnwrap (vString *const string)
271 {
272 char *buffer = NULL;
273
274
275 if (string != NULL)
276 {
277 buffer = string->buffer;
278 string->buffer = NULL;
279
280 string->size = 0;
281 string->length = 0;
282
283 eFree (string);
284 }
285
286 return buffer;
287 }
288
vStringStrdup(const vString * const string)289 extern char *vStringStrdup (const vString *const string)
290 {
291 char *str = xMalloc (vStringLength(string) + 1, char);
292 str[vStringLength(string)] = '\0';
293 memcpy (str, string->buffer, vStringLength(string));
294 return str;
295 }
296
valueToXDigit(int v)297 static char valueToXDigit (int v)
298 {
299 Assert (v >= 0 && v <= 0xF);
300
301 if (v >= 0xA)
302 return 'A' + (v - 0xA);
303 else
304 return '0' + v;
305 }
306
vStringCatSWithEscaping(vString * b,const char * s)307 extern void vStringCatSWithEscaping (vString* b, const char *s)
308 {
309 for(; *s; s++)
310 {
311 int c = *s;
312
313 /* escape control characters (incl. \t) */
314 if ((c > 0x00 && c <= 0x1F) || c == 0x7F || c == '\\')
315 {
316 vStringPut (b, '\\');
317
318 switch (c)
319 {
320 /* use a short form for known escapes */
321 case '\a':
322 c = 'a'; break;
323 case '\b':
324 c = 'b'; break;
325 case '\t':
326 c = 't'; break;
327 case '\n':
328 c = 'n'; break;
329 case '\v':
330 c = 'v'; break;
331 case '\f':
332 c = 'f'; break;
333 case '\r':
334 c = 'r'; break;
335 case '\\':
336 c = '\\'; break;
337 default:
338 vStringPut (b, 'x');
339 vStringPut (b, valueToXDigit ((c & 0xF0) >> 4));
340 vStringPut (b, valueToXDigit (c & 0x0F));
341 continue;
342 }
343 }
344 vStringPut (b, c);
345 }
346 }
347
vStringCatSWithEscapingAsPattern(vString * output,const char * input)348 extern void vStringCatSWithEscapingAsPattern (vString *output, const char* input)
349 {
350 while (*input)
351 {
352 switch (*input)
353 {
354 case '\\':
355 vStringPut(output, '\\');
356 vStringPut(output, '\\');
357 break;
358 case '/':
359 vStringPut(output, '\\');
360 vStringPut(output, '/');
361 break;
362 default:
363 vStringPut(output, *input);
364 break;
365
366 }
367 input++;
368 }
369 }
370
vStringNewOrClear(vString * const string)371 extern vString *vStringNewOrClear (vString *const string)
372 {
373 if (string)
374 {
375 vStringClear (string);
376 return string;
377 }
378 else
379 return vStringNew ();
380 }
381
vStringNewOrClearWithAutoRelease(vString * const string)382 extern vString *vStringNewOrClearWithAutoRelease (vString *const string)
383 {
384 vString *r;
385
386 bool autoRelease = false;
387 if (!string)
388 autoRelease = true;
389
390 r = vStringNewOrClear(string);
391 if (autoRelease)
392 DEFAULT_TRASH_BOX(r, vStringDelete);
393
394 return r;
395 }
396
vStringTranslate(vString * const string,char fromC,char toC)397 extern void vStringTranslate(vString *const string, char fromC, char toC)
398 {
399 for (unsigned int i = 0; i < vStringLength(string); i++)
400 {
401 if (string->buffer[i] == fromC)
402 string->buffer[i] = toC;
403 }
404 }
405