7 /* arbitrary-length string manager
9 /* #include <vstring.h>
11 /* VSTRING *vstring_alloc(len)
14 /* vstring_ctl(vp, type, value, ..., VSTRING_CTL_END)
18 /* VSTRING *vstring_free(vp)
21 /* char *vstring_str(vp)
24 /* ssize_t VSTRING_LEN(vp)
27 /* char *vstring_end(vp)
30 /* void VSTRING_ADDCH(vp, ch)
34 /* int VSTRING_SPACE(vp, len)
38 /* ssize_t vstring_avail(vp)
41 /* VSTRING *vstring_truncate(vp, len)
45 /* void VSTRING_RESET(vp)
48 /* void VSTRING_TERMINATE(vp)
51 /* void VSTRING_SKIP(vp)
54 /* VSTRING *vstring_strcpy(vp, src)
58 /* VSTRING *vstring_strncpy(vp, src, len)
63 /* VSTRING *vstring_strcat(vp, src)
67 /* VSTRING *vstring_strncat(vp, src, len)
72 /* VSTRING *vstring_memcpy(vp, src, len)
77 /* VSTRING *vstring_memcat(vp, src, len)
82 /* char *vstring_memchr(vp, ch)
86 /* VSTRING *vstring_insert(vp, start, src, len)
92 /* VSTRING *vstring_prepend(vp, src, len)
97 /* VSTRING *vstring_sprintf(vp, format, ...)
99 /* const char *format;
101 /* VSTRING *vstring_sprintf_append(vp, format, ...)
103 /* const char *format;
105 /* VSTRING *vstring_sprintf_prepend(vp, format, ...)
107 /* const char *format;
109 /* VSTRING *vstring_vsprintf(vp, format, ap)
111 /* const char *format;
114 /* VSTRING *vstring_vsprintf_append(vp, format, ap)
116 /* const char *format;
118 /* AUXILIARY FUNCTIONS
119 /* char *vstring_export(vp)
122 /* VSTRING *vstring_import(str)
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.
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.
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.
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.
152 /* vstring_avail() returns the number of bytes that can be placed
153 /* into the buffer before the buffer would need to grow.
155 /* vstring_free() reclaims storage for a variable-length string.
156 /* It conveniently returns a null pointer.
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.
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.
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.
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.
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.
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.
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.
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.
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.
199 /* vstring_strncpy() copies at most \fIlen\fR characters. Otherwise it is
200 /* identical to vstring_strcpy().
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.
206 /* vstring_strncat() copies at most \fIlen\fR characters. Otherwise it is
207 /* identical to vstring_strcat().
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.
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.
217 /* vstring_memchr() locates a byte in a variable-length string.
219 /* vstring_insert() inserts a buffer content into a variable-length
220 /* string at the specified start position. The result is
223 /* vstring_prepend() prepends a buffer content to a variable-length
224 /* string. The result is null-terminated.
226 /* vstring_sprintf() produces a formatted string according to its
227 /* \fIformat\fR argument. See vstring_vsprintf() for details.
229 /* vstring_sprintf_append() is like vstring_sprintf(), but appends
230 /* to the end of the result buffer.
232 /* vstring_sprintf_append() is like vstring_sprintf(), but prepends
233 /* to the beginning of the result buffer.
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.
241 /* vstring_vsprintf_append() is like vstring_vsprintf(), but appends
242 /* to the end of the result buffer.
244 /* In addition to stdio-like format specifiers, vstring_vsprintf()
245 /* recognizes %m and expands it to the corresponding errno text.
247 /* vstring_export() extracts the string value from a VSTRING.
248 /* The VSTRING is destroyed. The result should be passed to myfree().
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.
254 /* Fatal errors: memory allocation failure.
256 /* Auto-resizing may change the address of the string data in
257 /* a vstring structure. Beware of dangling pointers.
261 /* A vstring module appears in the UNPROTO software by Wietse Venema.
264 /* IBM T.J. Watson Research
266 /* Yorktown Heights, NY 10598, USA
269 /* System libraries. */
271 #include <sys_defs.h>
273 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */
277 /* Utility library. */
279 #include "mymalloc.h"
281 #include "vbuf_print.h"
284 /* vstring_extend - variable-length string buffer extension policy */
286 static void vstring_extend(VBUF
*bp
, ssize_t incr
)
288 size_t used
= bp
->ptr
- bp
->data
;
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.
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).
303 new_len
= bp
->len
+ (bp
->len
> incr
? bp
->len
: incr
);
305 msg_fatal("vstring_extend: length overflow");
306 bp
->data
= (unsigned char *) myrealloc((char *) bp
->data
, new_len
);
308 bp
->ptr
= bp
->data
+ used
;
309 bp
->cnt
= bp
->len
- used
;
312 /* vstring_buf_get_ready - vbuf callback for read buffer empty condition */
314 static int vstring_buf_get_ready(VBUF
*unused_buf
)
316 msg_panic("vstring_buf_get: write-only buffer");
319 /* vstring_buf_put_ready - vbuf callback for write buffer full condition */
321 static int vstring_buf_put_ready(VBUF
*bp
)
323 vstring_extend(bp
, 0);
327 /* vstring_buf_space - vbuf callback to reserve space */
329 static int vstring_buf_space(VBUF
*bp
, ssize_t len
)
334 msg_panic("vstring_buf_space: bad length %ld", (long) len
);
335 if ((need
= len
- bp
->cnt
) > 0)
336 vstring_extend(bp
, need
);
340 /* vstring_alloc - create variable-length string */
342 VSTRING
*vstring_alloc(ssize_t len
)
347 msg_panic("vstring_alloc: bad length %ld", (long) len
);
348 vp
= (VSTRING
*) mymalloc(sizeof(*vp
));
351 vp
->vbuf
.data
= (unsigned char *) mymalloc(len
);
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
;
362 /* vstring_free - destroy variable-length string */
364 VSTRING
*vstring_free(VSTRING
*vp
)
367 myfree((char *) vp
->vbuf
.data
);
372 /* vstring_ctl - modify memory management policy */
374 void vstring_ctl(VSTRING
*vp
,...)
380 while ((code
= va_arg(ap
, int)) != VSTRING_CTL_END
) {
383 msg_panic("vstring_ctl: unknown code: %d", code
);
384 case VSTRING_CTL_MAXLEN
:
385 vp
->maxlen
= va_arg(ap
, ssize_t
);
387 msg_panic("vstring_ctl: bad max length %ld", (long) vp
->maxlen
);
394 /* vstring_truncate - truncate string */
396 VSTRING
*vstring_truncate(VSTRING
*vp
, ssize_t len
)
399 msg_panic("vstring_truncate: bad length %ld", (long) len
);
400 if (len
< VSTRING_LEN(vp
))
401 VSTRING_AT_OFFSET(vp
, len
);
405 /* vstring_strcpy - copy string */
407 VSTRING
*vstring_strcpy(VSTRING
*vp
, const char *src
)
412 VSTRING_ADDCH(vp
, *src
);
415 VSTRING_TERMINATE(vp
);
419 /* vstring_strncpy - copy string of limited length */
421 VSTRING
*vstring_strncpy(VSTRING
*vp
, const char *src
, ssize_t len
)
425 while (len
-- > 0 && *src
) {
426 VSTRING_ADDCH(vp
, *src
);
429 VSTRING_TERMINATE(vp
);
433 /* vstring_strcat - append string */
435 VSTRING
*vstring_strcat(VSTRING
*vp
, const char *src
)
438 VSTRING_ADDCH(vp
, *src
);
441 VSTRING_TERMINATE(vp
);
445 /* vstring_strncat - append string of limited length */
447 VSTRING
*vstring_strncat(VSTRING
*vp
, const char *src
, ssize_t len
)
449 while (len
-- > 0 && *src
) {
450 VSTRING_ADDCH(vp
, *src
);
453 VSTRING_TERMINATE(vp
);
457 /* vstring_memcpy - copy buffer of limited length */
459 VSTRING
*vstring_memcpy(VSTRING
*vp
, const char *src
, ssize_t len
)
463 VSTRING_SPACE(vp
, len
);
464 memcpy(vstring_str(vp
), src
, len
);
465 VSTRING_AT_OFFSET(vp
, len
);
469 /* vstring_memcat - append buffer of limited length */
471 VSTRING
*vstring_memcat(VSTRING
*vp
, const char *src
, ssize_t len
)
473 VSTRING_SPACE(vp
, len
);
474 memcpy(vstring_end(vp
), src
, len
);
475 len
+= VSTRING_LEN(vp
);
476 VSTRING_AT_OFFSET(vp
, len
);
480 /* vstring_memchr - locate byte in buffer */
482 char *vstring_memchr(VSTRING
*vp
, int ch
)
486 for (cp
= (unsigned char *) vstring_str(vp
); cp
< (unsigned char *) vstring_end(vp
); cp
++)
488 return ((char *) cp
);
492 /* vstring_insert - insert text into string */
494 VSTRING
*vstring_insert(VSTRING
*vp
, ssize_t start
, const char *buf
, ssize_t len
)
501 if (start
< 0 || start
>= VSTRING_LEN(vp
))
502 msg_panic("vstring_insert: bad start %ld", (long) start
);
504 msg_panic("vstring_insert: bad length %ld", (long) len
);
507 * Move the existing content and copy the new content.
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
);
519 /* vstring_prepend - prepend text to string */
521 VSTRING
*vstring_prepend(VSTRING
*vp
, const char *buf
, ssize_t len
)
529 msg_panic("vstring_prepend: bad length %ld", (long) len
);
532 * Move the existing content and copy the new content.
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
);
543 /* vstring_export - VSTRING to bare string */
545 char *vstring_export(VSTRING
*vp
)
549 cp
= (char *) vp
->vbuf
.data
;
555 /* vstring_import - bare string to vstring */
557 VSTRING
*vstring_import(char *str
)
562 vp
= (VSTRING
*) mymalloc(sizeof(*vp
));
564 vp
->vbuf
.data
= (unsigned char *) str
;
565 vp
->vbuf
.len
= len
+ 1;
566 VSTRING_AT_OFFSET(vp
, len
);
571 /* vstring_sprintf - formatted string */
573 VSTRING
*vstring_sprintf(VSTRING
*vp
, const char *format
,...)
577 va_start(ap
, format
);
578 vp
= vstring_vsprintf(vp
, format
, ap
);
583 /* vstring_vsprintf - format string, vsprintf-like interface */
585 VSTRING
*vstring_vsprintf(VSTRING
*vp
, const char *format
, va_list ap
)
588 vbuf_print(&vp
->vbuf
, format
, ap
);
589 VSTRING_TERMINATE(vp
);
593 /* vstring_sprintf_append - append formatted string */
595 VSTRING
*vstring_sprintf_append(VSTRING
*vp
, const char *format
,...)
599 va_start(ap
, format
);
600 vp
= vstring_vsprintf_append(vp
, format
, ap
);
605 /* vstring_vsprintf_append - format + append string, vsprintf-like interface */
607 VSTRING
*vstring_vsprintf_append(VSTRING
*vp
, const char *format
, va_list ap
)
609 vbuf_print(&vp
->vbuf
, format
, ap
);
610 VSTRING_TERMINATE(vp
);
614 /* vstring_sprintf_prepend - format + prepend string, vsprintf-like interface */
616 VSTRING
*vstring_sprintf_prepend(VSTRING
*vp
, const char *format
,...)
619 ssize_t old_len
= VSTRING_LEN(vp
);
622 /* Construct: old|new|free */
623 va_start(ap
, format
);
624 vp
= vstring_vsprintf_append(vp
, format
, ap
);
626 result_len
= VSTRING_LEN(vp
);
628 /* Construct: old|new|old|free */
629 VSTRING_SPACE(vp
, old_len
);
630 vstring_memcat(vp
, vstring_str(vp
), old_len
);
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
);
642 * Test program - concatenate all command-line arguments into one string.
646 int main(int argc
, char **argv
)
648 VSTRING
*vp
= vstring_alloc(1);
651 vstring_strcat(vp
, *argv
++);
652 vstring_strcat(vp
, ".");
654 printf("argv concatenated: %s\n", vstring_str(vp
));