1 /*
2 Copyright (c) 2002 Perry Rapp
3 "The MIT license"
4 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7 */
8 /*======================================================================
9 * zstr.c -- dynamic buffer strings in C
10 *====================================================================*/
11
12 #include "llstdlib.h"
13 /* llstdlib.h pulls in standard.h, config.h, sys_inc.h */
14 #include "arch.h" /* vsnprintf */
15 #include "zstr.h"
16 #include "vtable.h"
17
18 #ifndef INCLUDED_STDARG_H
19 #include <stdarg.h>
20 #define INCLUDED_STDARG_H
21 #endif
22
23 /*********************************************
24 * local types
25 *********************************************/
26
27 /*
28 Each ZSTR takes two mallocs
29 But this cannot easily be changed, as clients
30 now assume that ZSTR pointers are stable
31 */
32 struct tag_zstr {
33 struct tag_vtable * vtable; /* generic object table (see vtable.h) */
34 int magic;
35 char * str;
36 char * end;
37 unsigned int max;
38 };
39
40 /*********************************************
41 * local function prototypes
42 *********************************************/
43
44 /* alphabetical */
45 static void dbgchk(ZSTR);
46 static void init_zstr_vtable(ZSTR zstr);
47 static unsigned int safelen(const char *txt);
48 static void zalloc(ZSTR zstr, unsigned int newmax);
49 static OBJECT zstr_copy(OBJECT obj, int deep);
50 static void zstr_destructor(VTABLE *obj);
51
52 /*********************************************
53 * local variables
54 *********************************************/
55
56 /* class vtable for ZSTR objects */
57 static struct tag_vtable vtable_for_zstr = {
58 VTABLE_MAGIC
59 , "zstring"
60 , &zstr_destructor
61 , &nonrefcountable_isref
62 , 0
63 , 0
64 , &zstr_copy /* copy_fnc */
65 , &generic_get_type_name
66 };
67
68 #define DEFSIZE 64
69
70 #define DBGCHK(zq) dbgchk(zq)
71
72 /*********************************************
73 * local function definitions
74 * body of module
75 *********************************************/
76
77
78 #ifdef TEST_ZSTR
79 static char *
safez(char * str)80 safez (char * str)
81 {
82 return str ? str : "";
83 }
84 int
main()85 main()
86 {
87 ZSTR zstr = zs_new();
88 ASSERT(zstr);
89
90 printf("zstr=%s\n", safez(zs_str(zstr)));
91
92 zs_cpy(zstr, "dogs");
93 ASSERT(0 == strcmp(zs_str(zstr), "dogs"));
94 ASSERT(4 == zs_len(zstr));
95
96 printf("zstr=%s\n", safez(zs_str(zstr)));
97
98
99 zs_del(&zstr);
100 ASSERT(!zstr);
101 }
102 #endif
103
104
105 /* reallocate buffer to be at least newmax */
106 static void
zalloc(ZSTR zstr,unsigned int newmax)107 zalloc (ZSTR zstr, unsigned int newmax)
108 {
109 char * ptr;
110 int len = zs_len(zstr);
111 while (zstr->max < newmax)
112 zstr->max = zstr->max << 1;
113 ptr = (char *)malloc(zstr->max);
114 /* use memcpy not strcpy in case has embedded nulls */
115 memcpy(ptr, zstr->str, len+1);
116 free(zstr->str);
117 zstr->str = ptr;
118 zstr->end = zstr->str + len;
119 DBGCHK(zstr);
120 }
121 /* validate zstring */
122 static void
dbgchk(ZSTR zstr)123 dbgchk (ZSTR zstr)
124 {
125 ASSERT(zstr);
126 ASSERT(zstr->magic == 7843);
127 ASSERT(zstr->str);
128 ASSERT(zstr->end);
129 ASSERT(zstr->max);
130 ASSERT(zstr->end >= zstr->str);
131 ASSERT(zstr->end < (zstr->str + zstr->max));
132 ASSERT(zstr->magic == 7843);
133 }
134 /* create & return new zstring */
135 ZSTR
zs_new(void)136 zs_new (void)
137 {
138 return zs_newn(DEFSIZE);
139 }
140 /* create & return new zstring with underlying buffer at least min bytes */
141 ZSTR
zs_newn(unsigned int min)142 zs_newn (unsigned int min)
143 {
144 ZSTR zstr = (ZSTR)malloc(sizeof(*zstr));
145 unsigned int bksiz = (min<2048)?(min<64?32:128):(min<16384?2048:16384);
146 while (bksiz < min)
147 bksiz = bksiz << 1;
148 init_zstr_vtable(zstr);
149 zstr->str = (char *)malloc(bksiz);
150 zstr->str[0] = 0;
151 zstr->end = zstr->str;
152 zstr->max = bksiz;
153 zstr->magic = 7843;
154 DBGCHK(zstr);
155 return zstr;
156 }
157 /* strlen but it handles null */
158 static unsigned int
safelen(const char * txt)159 safelen (const char *txt)
160 {
161 return txt ? strlen(txt) : 0;
162 }
163 /* create & return new zstring containing copy of input */
164 ZSTR
zs_news(const char * str)165 zs_news (const char * str)
166 {
167 ZSTR zstr=zs_newn(safelen(str)+4);
168 zs_sets(zstr, str);
169 return zstr;
170 }
171 /* create & return new zstring with copy of input zstring */
172 ZSTR
zs_newz(ZCSTR zsrc)173 zs_newz (ZCSTR zsrc)
174 {
175 ZSTR zstr = zs_newn(zs_len(zsrc)+4);
176 zs_setz(zstr, zsrc);
177 return zstr;
178 }
179 /* create & return new zstring copying from printf style input */
180 ZSTR
zs_newf(const char * fmt,...)181 zs_newf (const char * fmt, ...)
182 {
183 ZSTR zstr;
184 va_list args;
185 va_start(args, fmt);
186 zstr = zs_newvf(fmt, args);
187 va_end(args);
188 return zstr;
189 }
190 /* create & return new zstring copying from varargs input */
191 ZSTR
zs_newvf(const char * fmt,va_list args)192 zs_newvf (const char * fmt, va_list args)
193 {
194 ZSTR zstr = zs_newn(strlen(fmt)+8);
195 zs_setvf(zstr, fmt, args);
196 return zstr;
197 }
198 /* create & return new zstring containing first len bytes of str */
199 ZSTR
zs_newsubs(const char * str,unsigned int len)200 zs_newsubs (const char * str, unsigned int len)
201 {
202 ZSTR zstr = zs_news(str);
203 ASSERT(len<=safelen(str));
204 zstr->str[len]=0;
205 return zstr;
206 }
207 /* delete zstring & clear caller's pointer */
208 void
zs_free(ZSTR * pzstr)209 zs_free (ZSTR * pzstr)
210 {
211 ZSTR zstr = *pzstr;
212 if (!zstr) return;
213 DBGCHK(zstr);
214 free(zstr->str);
215 free(zstr);
216 *pzstr = NULL;
217 }
218 /* return current string */
219 STRING
zs_str(ZCSTR zstr)220 zs_str (ZCSTR zstr)
221 {
222 if (!zstr) return "";
223 DBGCHK(zstr);
224 return zstr->str;
225 }
226 /* return current length of string */
227 unsigned int
zs_len(ZCSTR zstr)228 zs_len (ZCSTR zstr)
229 {
230 if (!zstr) return 0;
231 DBGCHK(zstr);
232 return zstr->end - zstr->str;
233 }
234 /* return current size of underlying buffer */
235 unsigned int
zs_allocsize(ZCSTR zstr)236 zs_allocsize (ZCSTR zstr)
237 {
238 if (!zstr) return 0;
239 DBGCHK(zstr);
240 return zstr->max;
241 }
242 /* update state because caller changed string */
243 /* Assumes simple zero-terminated string */
244 char *
zs_fix(ZSTR zstr)245 zs_fix (ZSTR zstr)
246 {
247 DBGCHK(zstr);
248 zstr->end = zstr->str + strlen(zstr->str);
249 return zstr->str;
250 }
251 /* chop off string to specified length */
252 void
zs_chop(ZSTR zstr,unsigned int len)253 zs_chop (ZSTR zstr, unsigned int len)
254 {
255 DBGCHK(zstr);
256 if (len < zs_len(zstr)) {
257 zstr->str[len] = 0;
258 zstr->end = zstr->str + len;
259 }
260 }
261 /* set length directly; caller may use this if using embedded nulls */
262 char *
zs_set_len(ZSTR zstr,unsigned int len)263 zs_set_len (ZSTR zstr, unsigned int len)
264 {
265 DBGCHK(zstr);
266 if (len == (unsigned int)-1) {
267 len = strlen(zstr->str);
268 }
269 ASSERT(len < zstr->max);
270 zstr->end = zstr->str + len;
271 return zstr->str;
272 }
273 /* set zstring value to input zero-terminated string*/
274 static char *
zs_set_with_len(ZSTR zstr,const char * txt,unsigned int tlen)275 zs_set_with_len (ZSTR zstr, const char * txt, unsigned int tlen)
276 {
277 DBGCHK(zstr);
278 zs_reserve(zstr, tlen+1);
279 if (tlen) {
280 strcpy(zstr->str, txt);
281 zstr->end = zstr->str + tlen;
282 }
283 return zstr->str;
284 }
285 /* set zstring value to input zero-terminated string*/
286 char *
zs_sets(ZSTR zstr,const char * txt)287 zs_sets (ZSTR zstr, const char * txt)
288 {
289 unsigned int tlen = safelen(txt);
290 return zs_set_with_len(zstr, txt, tlen);
291 }
292 /* set zstring value to copy of another zstring value */
293 char *
zs_setz(ZSTR zstr,ZCSTR zsrc)294 zs_setz (ZSTR zstr, ZCSTR zsrc)
295 {
296 const char * txt = zsrc ? zsrc->str : "";
297 unsigned int tlen = zsrc ? (zsrc->end)-(zsrc->str) : 0;
298 DBGCHK(zstr);
299 return zs_set_with_len(zstr, txt, tlen);
300 }
301 /* append zero-terminated input to zstring */
302 char *
zs_apps(ZSTR zstr,const char * txt)303 zs_apps (ZSTR zstr, const char * txt)
304 {
305 int tlen = safelen(txt);
306 DBGCHK(zstr);
307 zs_reserve(zstr, zs_len(zstr)+tlen+1);
308 if (tlen) {
309 strcpy(zstr->end, txt);
310 zstr->end += tlen;
311 }
312 return zstr->str;
313 }
314 /* append input zstring to zstring */
315 char *
zs_appz(ZSTR zstr,ZCSTR zsrc)316 zs_appz(ZSTR zstr, ZCSTR zsrc)
317 {
318 if (!zsrc) return zstr->str;
319 return zs_apps(zstr, zsrc->str);
320 }
321 /* append input character to zstring */
322 char *
zs_appc(ZSTR zstr,char ch)323 zs_appc (ZSTR zstr, char ch)
324 {
325 char buffer[2];
326 buffer[0] = ch;
327 buffer[1] = 0;
328 return zs_apps(zstr, buffer);
329 }
330 /* set printf style input to zstring */
331 char *
zs_setf(ZSTR zstr,const char * fmt,...)332 zs_setf (ZSTR zstr, const char * fmt, ...)
333 {
334 va_list args;
335 va_start(args, fmt);
336 zs_setvf(zstr, fmt, args);
337 va_end(args);
338 return zstr->str;
339 }
340 /* append printf style input to zstring */
341 char *
zs_appf(ZSTR zstr,const char * fmt,...)342 zs_appf (ZSTR zstr, const char * fmt, ...)
343 {
344 va_list args;
345 va_start(args, fmt);
346 zs_appvf(zstr, fmt, args);
347 va_end(args);
348 return zstr->str;
349 }
350 /* set varargs printf style input to zstring */
351 char *
zs_setvf(ZSTR zstr,const char * fmt,va_list args)352 zs_setvf (ZSTR zstr, const char * fmt, va_list args)
353 {
354 zs_clear(zstr);
355 zs_appvf(zstr, fmt, args);
356 return zstr->str;
357 }
358 /* append varargs printf style input to zstring */
359 char *
zs_appvf(ZSTR zstr,const char * fmt,va_list args)360 zs_appvf (ZSTR zstr, const char * fmt, va_list args)
361 {
362 /* if we know that the system implementation of snprintf was
363 standards conformant, we could use snprintf(0, ...), but how to tell ? */
364 static char buffer[4096];
365 vsnprintf(buffer, sizeof(buffer), fmt, args);
366 zs_apps(zstr, buffer);
367 return zstr->str;
368 }
369 /* set zstring to empty */
370 char *
zs_clear(ZSTR zstr)371 zs_clear (ZSTR zstr)
372 {
373 DBGCHK(zstr);
374 zstr->str[0] = 0;
375 zstr->end = zstr->str;
376 return zstr->str;
377 }
378 /* ensure at least min bytes in underlying buffer */
379 char *
zs_reserve(ZSTR zstr,unsigned int min)380 zs_reserve (ZSTR zstr, unsigned int min)
381 {
382 DBGCHK(zstr);
383 if (min > zstr->max)
384 zalloc(zstr, min);
385 return zstr->str;
386 }
387 /* add at least min bytes more to underlying buffer */
388 char *
zs_reserve_extra(ZSTR zstr,unsigned int delta)389 zs_reserve_extra (ZSTR zstr, unsigned int delta)
390 {
391 zalloc(zstr, (zstr->max)+delta);
392 return zstr->str;
393 }
394 /* move data from pzsrc to zstr (clearing pzsrc) */
395 void
zs_move(ZSTR zstr,ZSTR * pzsrc)396 zs_move (ZSTR zstr, ZSTR * pzsrc)
397 {
398 DBGCHK(zstr);
399 ASSERT(pzsrc);
400 ASSERT(*pzsrc);
401 free(zstr->str);
402 memcpy(zstr, (*pzsrc), sizeof(*zstr));
403 free(*pzsrc);
404 *pzsrc = 0;
405 }
406 /*========================================
407 * init_zstr_vtable -- set this zstr's vtable
408 *======================================*/
409 static void
init_zstr_vtable(ZSTR zstr)410 init_zstr_vtable (ZSTR zstr)
411 {
412 zstr->vtable = &vtable_for_zstr;
413 }
414 /*=================================================
415 * zstr_destructor -- destructor for zstr
416 * (destructor entry in vtable)
417 *===============================================*/
418 static void
zstr_destructor(VTABLE * obj)419 zstr_destructor (VTABLE *obj)
420 {
421 ZSTR zstr = (ZSTR)obj;
422 ASSERT((*obj)->vtable_class == vtable_for_zstr.vtable_class);
423 zs_free(&zstr);
424 }
425 /*=================================================
426 * zstr_copy -- copy for zstr
427 *===============================================*/
428 static OBJECT
zstr_copy(OBJECT obj,int deep)429 zstr_copy (OBJECT obj, int deep)
430 {
431 ZSTR zstr = (ZSTR)obj, znew=0;
432 ASSERT((*obj)->vtable_class == vtable_for_zstr.vtable_class);
433 deep=deep; /* unused */
434 ASSERT((*obj)->vtable_class == vtable_for_zstr.vtable_class);
435 znew = zs_newz(zstr);
436 return (OBJECT)znew;
437 }
438
439