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