1 /*	$NetBSD: vstring.c,v 1.1.1.1 2009/06/23 10:09:01 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	vstring 3
6 /* SUMMARY
7 /*	arbitrary-length string manager
8 /* SYNOPSIS
9 /*	#include <vstring.h>
10 /*
11 /*	VSTRING	*vstring_alloc(len)
12 /*	ssize_t	len;
13 /*
14 /*	vstring_ctl(vp, type, value, ..., VSTRING_CTL_END)
15 /*	VSTRING	*vp;
16 /*	int	type;
17 /*
18 /*	VSTRING	*vstring_free(vp)
19 /*	VSTRING	*vp;
20 /*
21 /*	char	*vstring_str(vp)
22 /*	VSTRING	*vp;
23 /*
24 /*	ssize_t	VSTRING_LEN(vp)
25 /*	VSTRING	*vp;
26 /*
27 /*	char	*vstring_end(vp)
28 /*	VSTRING	*vp;
29 /*
30 /*	void	VSTRING_ADDCH(vp, ch)
31 /*	VSTRING	*vp;
32 /*	int	ch;
33 /*
34 /*	int	VSTRING_SPACE(vp, len)
35 /*	VSTRING	*vp;
36 /*	ssize_t	len;
37 /*
38 /*	ssize_t	vstring_avail(vp)
39 /*	VSTRING	*vp;
40 /*
41 /*	VSTRING	*vstring_truncate(vp, len)
42 /*	VSTRING	*vp;
43 /*	ssize_t	len;
44 /*
45 /*	void	VSTRING_RESET(vp)
46 /*	VSTRING	*vp;
47 /*
48 /*	void	VSTRING_TERMINATE(vp)
49 /*	VSTRING	*vp;
50 /*
51 /*	void	VSTRING_SKIP(vp)
52 /*	VSTRING	*vp;
53 /*
54 /*	VSTRING	*vstring_strcpy(vp, src)
55 /*	VSTRING	*vp;
56 /*	const char *src;
57 /*
58 /*	VSTRING	*vstring_strncpy(vp, src, len)
59 /*	VSTRING	*vp;
60 /*	const char *src;
61 /*	ssize_t	len;
62 /*
63 /*	VSTRING	*vstring_strcat(vp, src)
64 /*	VSTRING	*vp;
65 /*	const char *src;
66 /*
67 /*	VSTRING	*vstring_strncat(vp, src, len)
68 /*	VSTRING	*vp;
69 /*	const char *src;
70 /*	ssize_t	len;
71 /*
72 /*	VSTRING	*vstring_memcpy(vp, src, len)
73 /*	VSTRING	*vp;
74 /*	const char *src;
75 /*	ssize_t	len;
76 /*
77 /*	VSTRING	*vstring_memcat(vp, src, len)
78 /*	VSTRING	*vp;
79 /*	const char *src;
80 /*	ssize_t	len;
81 /*
82 /*	char	*vstring_memchr(vp, ch)
83 /*	VSTRING	*vp;
84 /*	int	ch;
85 /*
86 /*	VSTRING	*vstring_insert(vp, start, src, len)
87 /*	VSTRING	*vp;
88 /*	ssize_t	start;
89 /*	const char *src;
90 /*	ssize_t	len;
91 /*
92 /*	VSTRING	*vstring_prepend(vp, src, len)
93 /*	VSTRING	*vp;
94 /*	const char *src;
95 /*	ssize_t	len;
96 /*
97 /*	VSTRING	*vstring_sprintf(vp, format, ...)
98 /*	VSTRING	*vp;
99 /*	const char *format;
100 /*
101 /*	VSTRING	*vstring_sprintf_append(vp, format, ...)
102 /*	VSTRING	*vp;
103 /*	const char *format;
104 /*
105 /*	VSTRING	*vstring_sprintf_prepend(vp, format, ...)
106 /*	VSTRING	*vp;
107 /*	const char *format;
108 /*
109 /*	VSTRING	*vstring_vsprintf(vp, format, ap)
110 /*	VSTRING	*vp;
111 /*	const char *format;
112 /*	va_list	ap;
113 /*
114 /*	VSTRING	*vstring_vsprintf_append(vp, format, ap)
115 /*	VSTRING	*vp;
116 /*	const char *format;
117 /*	va_list	ap;
118 /* AUXILIARY FUNCTIONS
119 /*	char	*vstring_export(vp)
120 /*	VSTRING	*vp;
121 /*
122 /*	VSTRING	*vstring_import(str)
123 /*	char	*str;
124 /* DESCRIPTION
125 /*	The functions and macros in this module implement arbitrary-length
126 /*	strings and common operations on those strings. The strings do not
127 /*	need to be null terminated and may contain arbitrary binary data.
128 /*	The strings manage their own memory and grow automatically when full.
129 /*	The optional string null terminator does not add to the string length.
130 /*
131 /*	vstring_alloc() allocates storage for a variable-length string
132 /*	of at least "len" bytes. The minimal length is 1. The result
133 /*	is a null-terminated string of length zero.
134 /*
135 /*	vstring_ctl() gives additional control over VSTRING behavior.
136 /*	The function takes a VSTRING pointer and a list of zero
137 /*	or more (name,value) pairs. The expected value type
138 /*	depends on the specified name. The value name codes are:
139 /* .IP "VSTRING_CTL_MAXLEN (ssize_t)"
140 /*	Specifies a hard upper limit on a string's length. When the
141 /*	length would be exceeded, the program simulates a memory
142 /*	allocation problem (i.e. it terminates through msg_fatal()).
143 /*	This fuctionality is currently unimplemented.
144 /* .IP "VSTRING_CTL_END (no value)"
145 /*	Specifies the end of the argument list. Forgetting to terminate
146 /*	the argument list may cause the program to crash.
147 /* .PP
148 /*	VSTRING_SPACE() ensures that the named string has room for
149 /*	"len" more characters. VSTRING_SPACE() is an unsafe macro
150 /*	that either returns zero or never returns.
151 /*
152 /*	vstring_avail() returns the number of bytes that can be placed
153 /*	into the buffer before the buffer would need to grow.
154 /*
155 /*	vstring_free() reclaims storage for a variable-length string.
156 /*	It conveniently returns a null pointer.
157 /*
158 /*	vstring_str() is a macro that returns the string value
159 /*	of a variable-length string. It is a safe macro that
160 /*	evaluates its argument only once.
161 /*
162 /*	VSTRING_LEN() is a macro that returns the current length of
163 /*	its argument (i.e. the distance from the start of the string
164 /*	to the current write position). VSTRING_LEN() is an unsafe macro
165 /*	that evaluates its argument more than once.
166 /*
167 /*	vstring_end() is a macro that returns the current write position of
168 /*	its argument. It is a safe macro that evaluates its argument only once.
169 /*
170 /*	VSTRING_ADDCH() adds a character to a variable-length string
171 /*	and extends the string if it fills up.  \fIvs\fP is a pointer
172 /*	to a VSTRING structure; \fIch\fP the character value to be written.
173 /*	The result is the written character.
174 /*	Note that VSTRING_ADDCH() is an unsafe macro that evaluates some
175 /*	arguments more than once. The result is NOT null-terminated.
176 /*
177 /*	vstring_truncate() truncates the named string to the specified
178 /*	length. The operation has no effect when the string is shorter.
179 /*	The string is not null-terminated.
180 /*
181 /*	VSTRING_RESET() is a macro that resets the write position of its
182 /*	string argument to the very beginning. Note that VSTRING_RESET()
183 /*	is an unsafe macro that evaluates some arguments more than once.
184 /*	The result is NOT null-terminated.
185 /*
186 /*	VSTRING_TERMINATE() null-terminates its string argument.
187 /*	VSTRING_TERMINATE() is an unsafe macro that evaluates some
188 /*	arguments more than once.
189 /*	VSTRING_TERMINATE() does not return an interesting result.
190 /*
191 /*	VSTRING_SKIP() is a macro that moves the write position to the first
192 /*	null byte after the current write position. VSTRING_SKIP() is an unsafe
193 /*	macro that evaluates some arguments more than once.
194 /*
195 /*	vstring_strcpy() copies a null-terminated string to a variable-length
196 /*	string. \fIsrc\fP provides the data to be copied; \fIvp\fP is the
197 /*	target and result value.  The result is null-terminated.
198 /*
199 /*	vstring_strncpy() copies at most \fIlen\fR characters. Otherwise it is
200 /*	identical to vstring_strcpy().
201 /*
202 /*	vstring_strcat() appends a null-terminated string to a variable-length
203 /*	string. \fIsrc\fP provides the data to be copied; \fIvp\fP is the
204 /*	target and result value.  The result is null-terminated.
205 /*
206 /*	vstring_strncat() copies at most \fIlen\fR characters. Otherwise it is
207 /*	identical to vstring_strcat().
208 /*
209 /*	vstring_memcpy() copies \fIlen\fR bytes to a variable-length string.
210 /*	\fIsrc\fP provides the data to be copied; \fIvp\fP is the
211 /*	target and result value.  The result is not null-terminated.
212 /*
213 /*	vstring_memcat() appends \fIlen\fR bytes to a variable-length string.
214 /*	\fIsrc\fP provides the data to be copied; \fIvp\fP is the
215 /*	target and result value.  The result is not null-terminated.
216 /*
217 /*	vstring_memchr() locates a byte in a variable-length string.
218 /*
219 /*	vstring_insert() inserts a buffer content into a variable-length
220 /*	string at the specified start position. The result is
221 /*	null-terminated.
222 /*
223 /*	vstring_prepend() prepends a buffer content to a variable-length
224 /*	string. The result is null-terminated.
225 /*
226 /*	vstring_sprintf() produces a formatted string according to its
227 /*	\fIformat\fR argument. See vstring_vsprintf() for details.
228 /*
229 /*	vstring_sprintf_append() is like vstring_sprintf(), but appends
230 /*	to the end of the result buffer.
231 /*
232 /*	vstring_sprintf_append() is like vstring_sprintf(), but prepends
233 /*	to the beginning of the result buffer.
234 /*
235 /*	vstring_vsprintf() returns a null-terminated string according to
236 /*	the \fIformat\fR argument. It understands the s, c, d, u,
237 /*	o, x, X, p, e, f and g format types, the l modifier, field width
238 /*	and precision, sign, and null or space padding. This module
239 /*	can format strings as large as available memory permits.
240 /*
241 /*	vstring_vsprintf_append() is like vstring_vsprintf(), but appends
242 /*	to the end of the result buffer.
243 /*
244 /*	In addition to stdio-like format specifiers, vstring_vsprintf()
245 /*	recognizes %m and expands it to the corresponding errno text.
246 /*
247 /*	vstring_export() extracts the string value from a VSTRING.
248 /*	The VSTRING is destroyed. The result should be passed to myfree().
249 /*
250 /*	vstring_import() takes a `bare' string and converts it to
251 /*	a VSTRING. The string argument must be obtained from mymalloc().
252 /*	The string argument is not copied.
253 /* DIAGNOSTICS
254 /*	Fatal errors: memory allocation failure.
255 /* BUGS
256 /*	Auto-resizing may change the address of the string data in
257 /*	a vstring structure. Beware of dangling pointers.
258 /* HISTORY
259 /* .ad
260 /* .fi
261 /*	A vstring module appears in the UNPROTO software by Wietse Venema.
262 /* AUTHOR(S)
263 /*	Wietse Venema
264 /*	IBM T.J. Watson Research
265 /*	P.O. Box 704
266 /*	Yorktown Heights, NY 10598, USA
267 /*--*/
268 
269 /* System libraries. */
270 
271 #include <sys_defs.h>
272 #include <stddef.h>
273 #include <stdlib.h>			/* 44BSD stdarg.h uses abort() */
274 #include <stdarg.h>
275 #include <string.h>
276 
277 /* Utility library. */
278 
279 #include "mymalloc.h"
280 #include "msg.h"
281 #include "vbuf_print.h"
282 #include "vstring.h"
283 
284 /* vstring_extend - variable-length string buffer extension policy */
285 
286 static void vstring_extend(VBUF *bp, ssize_t incr)
287 {
288     size_t  used = bp->ptr - bp->data;
289     ssize_t new_len;
290 
291     /*
292      * Note: vp->vbuf.len is the current buffer size (both on entry and on
293      * exit of this routine). We round up the increment size to the buffer
294      * size to avoid silly little buffer increments. With really large
295      * strings we might want to abandon the length doubling strategy, and go
296      * to fixed increments.
297      *
298      * The length overflow tests here and in vstring_alloc() should protect us
299      * against all length overflow problems within vstring library routines.
300      * (The tests are redundant as long as mymalloc() and myrealloc() reject
301      * negative length parameters).
302      */
303     new_len = bp->len + (bp->len > incr ? bp->len : incr);
304     if (new_len < 0)
305 	msg_fatal("vstring_extend: length overflow");
306     bp->data = (unsigned char *) myrealloc((char *) bp->data, new_len);
307     bp->len = new_len;
308     bp->ptr = bp->data + used;
309     bp->cnt = bp->len - used;
310 }
311 
312 /* vstring_buf_get_ready - vbuf callback for read buffer empty condition */
313 
314 static int vstring_buf_get_ready(VBUF *unused_buf)
315 {
316     msg_panic("vstring_buf_get: write-only buffer");
317 }
318 
319 /* vstring_buf_put_ready - vbuf callback for write buffer full condition */
320 
321 static int vstring_buf_put_ready(VBUF *bp)
322 {
323     vstring_extend(bp, 0);
324     return (0);
325 }
326 
327 /* vstring_buf_space - vbuf callback to reserve space */
328 
329 static int vstring_buf_space(VBUF *bp, ssize_t len)
330 {
331     ssize_t need;
332 
333     if (len < 0)
334 	msg_panic("vstring_buf_space: bad length %ld", (long) len);
335     if ((need = len - bp->cnt) > 0)
336 	vstring_extend(bp, need);
337     return (0);
338 }
339 
340 /* vstring_alloc - create variable-length string */
341 
342 VSTRING *vstring_alloc(ssize_t len)
343 {
344     VSTRING *vp;
345 
346     if (len < 1)
347 	msg_panic("vstring_alloc: bad length %ld", (long) len);
348     vp = (VSTRING *) mymalloc(sizeof(*vp));
349     vp->vbuf.flags = 0;
350     vp->vbuf.len = 0;
351     vp->vbuf.data = (unsigned char *) mymalloc(len);
352     vp->vbuf.len = len;
353     VSTRING_RESET(vp);
354     vp->vbuf.data[0] = 0;
355     vp->vbuf.get_ready = vstring_buf_get_ready;
356     vp->vbuf.put_ready = vstring_buf_put_ready;
357     vp->vbuf.space = vstring_buf_space;
358     vp->maxlen = 0;
359     return (vp);
360 }
361 
362 /* vstring_free - destroy variable-length string */
363 
364 VSTRING *vstring_free(VSTRING *vp)
365 {
366     if (vp->vbuf.data)
367 	myfree((char *) vp->vbuf.data);
368     myfree((char *) vp);
369     return (0);
370 }
371 
372 /* vstring_ctl - modify memory management policy */
373 
374 void    vstring_ctl(VSTRING *vp,...)
375 {
376     va_list ap;
377     int     code;
378 
379     va_start(ap, vp);
380     while ((code = va_arg(ap, int)) != VSTRING_CTL_END) {
381 	switch (code) {
382 	default:
383 	    msg_panic("vstring_ctl: unknown code: %d", code);
384 	case VSTRING_CTL_MAXLEN:
385 	    vp->maxlen = va_arg(ap, ssize_t);
386 	    if (vp->maxlen < 0)
387 		msg_panic("vstring_ctl: bad max length %ld", (long) vp->maxlen);
388 	    break;
389 	}
390     }
391     va_end(ap);
392 }
393 
394 /* vstring_truncate - truncate string */
395 
396 VSTRING *vstring_truncate(VSTRING *vp, ssize_t len)
397 {
398     if (len < 0)
399 	msg_panic("vstring_truncate: bad length %ld", (long) len);
400     if (len < VSTRING_LEN(vp))
401 	VSTRING_AT_OFFSET(vp, len);
402     return (vp);
403 }
404 
405 /* vstring_strcpy - copy string */
406 
407 VSTRING *vstring_strcpy(VSTRING *vp, const char *src)
408 {
409     VSTRING_RESET(vp);
410 
411     while (*src) {
412 	VSTRING_ADDCH(vp, *src);
413 	src++;
414     }
415     VSTRING_TERMINATE(vp);
416     return (vp);
417 }
418 
419 /* vstring_strncpy - copy string of limited length */
420 
421 VSTRING *vstring_strncpy(VSTRING *vp, const char *src, ssize_t len)
422 {
423     VSTRING_RESET(vp);
424 
425     while (len-- > 0 && *src) {
426 	VSTRING_ADDCH(vp, *src);
427 	src++;
428     }
429     VSTRING_TERMINATE(vp);
430     return (vp);
431 }
432 
433 /* vstring_strcat - append string */
434 
435 VSTRING *vstring_strcat(VSTRING *vp, const char *src)
436 {
437     while (*src) {
438 	VSTRING_ADDCH(vp, *src);
439 	src++;
440     }
441     VSTRING_TERMINATE(vp);
442     return (vp);
443 }
444 
445 /* vstring_strncat - append string of limited length */
446 
447 VSTRING *vstring_strncat(VSTRING *vp, const char *src, ssize_t len)
448 {
449     while (len-- > 0 && *src) {
450 	VSTRING_ADDCH(vp, *src);
451 	src++;
452     }
453     VSTRING_TERMINATE(vp);
454     return (vp);
455 }
456 
457 /* vstring_memcpy - copy buffer of limited length */
458 
459 VSTRING *vstring_memcpy(VSTRING *vp, const char *src, ssize_t len)
460 {
461     VSTRING_RESET(vp);
462 
463     VSTRING_SPACE(vp, len);
464     memcpy(vstring_str(vp), src, len);
465     VSTRING_AT_OFFSET(vp, len);
466     return (vp);
467 }
468 
469 /* vstring_memcat - append buffer of limited length */
470 
471 VSTRING *vstring_memcat(VSTRING *vp, const char *src, ssize_t len)
472 {
473     VSTRING_SPACE(vp, len);
474     memcpy(vstring_end(vp), src, len);
475     len += VSTRING_LEN(vp);
476     VSTRING_AT_OFFSET(vp, len);
477     return (vp);
478 }
479 
480 /* vstring_memchr - locate byte in buffer */
481 
482 char   *vstring_memchr(VSTRING *vp, int ch)
483 {
484     unsigned char *cp;
485 
486     for (cp = (unsigned char *) vstring_str(vp); cp < (unsigned char *) vstring_end(vp); cp++)
487 	if (*cp == ch)
488 	    return ((char *) cp);
489     return (0);
490 }
491 
492 /* vstring_insert - insert text into string */
493 
494 VSTRING *vstring_insert(VSTRING *vp, ssize_t start, const char *buf, ssize_t len)
495 {
496     ssize_t new_len;
497 
498     /*
499      * Sanity check.
500      */
501     if (start < 0 || start >= VSTRING_LEN(vp))
502 	msg_panic("vstring_insert: bad start %ld", (long) start);
503     if (len < 0)
504 	msg_panic("vstring_insert: bad length %ld", (long) len);
505 
506     /*
507      * Move the existing content and copy the new content.
508      */
509     new_len = VSTRING_LEN(vp) + len;
510     VSTRING_SPACE(vp, len);
511     memmove(vstring_str(vp) + start + len, vstring_str(vp) + start,
512 	    VSTRING_LEN(vp) - start);
513     memcpy(vstring_str(vp) + start, buf, len);
514     VSTRING_AT_OFFSET(vp, new_len);
515     VSTRING_TERMINATE(vp);
516     return (vp);
517 }
518 
519 /* vstring_prepend - prepend text to string */
520 
521 VSTRING *vstring_prepend(VSTRING *vp, const char *buf, ssize_t len)
522 {
523     ssize_t new_len;
524 
525     /*
526      * Sanity check.
527      */
528     if (len < 0)
529 	msg_panic("vstring_prepend: bad length %ld", (long) len);
530 
531     /*
532      * Move the existing content and copy the new content.
533      */
534     new_len = VSTRING_LEN(vp) + len;
535     VSTRING_SPACE(vp, len);
536     memmove(vstring_str(vp) + len, vstring_str(vp), VSTRING_LEN(vp));
537     memcpy(vstring_str(vp), buf, len);
538     VSTRING_AT_OFFSET(vp, new_len);
539     VSTRING_TERMINATE(vp);
540     return (vp);
541 }
542 
543 /* vstring_export - VSTRING to bare string */
544 
545 char   *vstring_export(VSTRING *vp)
546 {
547     char   *cp;
548 
549     cp = (char *) vp->vbuf.data;
550     vp->vbuf.data = 0;
551     myfree((char *) vp);
552     return (cp);
553 }
554 
555 /* vstring_import - bare string to vstring */
556 
557 VSTRING *vstring_import(char *str)
558 {
559     VSTRING *vp;
560     ssize_t len;
561 
562     vp = (VSTRING *) mymalloc(sizeof(*vp));
563     len = strlen(str);
564     vp->vbuf.data = (unsigned char *) str;
565     vp->vbuf.len = len + 1;
566     VSTRING_AT_OFFSET(vp, len);
567     vp->maxlen = 0;
568     return (vp);
569 }
570 
571 /* vstring_sprintf - formatted string */
572 
573 VSTRING *vstring_sprintf(VSTRING *vp, const char *format,...)
574 {
575     va_list ap;
576 
577     va_start(ap, format);
578     vp = vstring_vsprintf(vp, format, ap);
579     va_end(ap);
580     return (vp);
581 }
582 
583 /* vstring_vsprintf - format string, vsprintf-like interface */
584 
585 VSTRING *vstring_vsprintf(VSTRING *vp, const char *format, va_list ap)
586 {
587     VSTRING_RESET(vp);
588     vbuf_print(&vp->vbuf, format, ap);
589     VSTRING_TERMINATE(vp);
590     return (vp);
591 }
592 
593 /* vstring_sprintf_append - append formatted string */
594 
595 VSTRING *vstring_sprintf_append(VSTRING *vp, const char *format,...)
596 {
597     va_list ap;
598 
599     va_start(ap, format);
600     vp = vstring_vsprintf_append(vp, format, ap);
601     va_end(ap);
602     return (vp);
603 }
604 
605 /* vstring_vsprintf_append - format + append string, vsprintf-like interface */
606 
607 VSTRING *vstring_vsprintf_append(VSTRING *vp, const char *format, va_list ap)
608 {
609     vbuf_print(&vp->vbuf, format, ap);
610     VSTRING_TERMINATE(vp);
611     return (vp);
612 }
613 
614 /* vstring_sprintf_prepend - format + prepend string, vsprintf-like interface */
615 
616 VSTRING *vstring_sprintf_prepend(VSTRING *vp, const char *format,...)
617 {
618     va_list ap;
619     ssize_t old_len = VSTRING_LEN(vp);
620     ssize_t result_len;
621 
622     /* Construct: old|new|free */
623     va_start(ap, format);
624     vp = vstring_vsprintf_append(vp, format, ap);
625     va_end(ap);
626     result_len = VSTRING_LEN(vp);
627 
628     /* Construct: old|new|old|free */
629     VSTRING_SPACE(vp, old_len);
630     vstring_memcat(vp, vstring_str(vp), old_len);
631 
632     /* Construct: new|old|free */
633     memmove(vstring_str(vp), vstring_str(vp) + old_len, result_len);
634     VSTRING_AT_OFFSET(vp, result_len);
635     VSTRING_TERMINATE(vp);
636     return (vp);
637 }
638 
639 #ifdef TEST
640 
641  /*
642   * Test program - concatenate all command-line arguments into one string.
643   */
644 #include <stdio.h>
645 
646 int     main(int argc, char **argv)
647 {
648     VSTRING *vp = vstring_alloc(1);
649 
650     while (argc-- > 0) {
651 	vstring_strcat(vp, *argv++);
652 	vstring_strcat(vp, ".");
653     }
654     printf("argv concatenated: %s\n", vstring_str(vp));
655     vstring_free(vp);
656     return (0);
657 }
658 
659 #endif
660