No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / vstring.c
blob793433f6d7573f2161bf58a17b6c4d4a1b6d9697
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* vstring 3
6 /* SUMMARY
7 /* arbitrary-length string manager
8 /* SYNOPSIS
9 /* #include <vstring.h>
11 /* VSTRING *vstring_alloc(len)
12 /* ssize_t len;
14 /* vstring_ctl(vp, type, value, ..., VSTRING_CTL_END)
15 /* VSTRING *vp;
16 /* int type;
18 /* VSTRING *vstring_free(vp)
19 /* VSTRING *vp;
21 /* char *vstring_str(vp)
22 /* VSTRING *vp;
24 /* ssize_t VSTRING_LEN(vp)
25 /* VSTRING *vp;
27 /* char *vstring_end(vp)
28 /* VSTRING *vp;
30 /* void VSTRING_ADDCH(vp, ch)
31 /* VSTRING *vp;
32 /* int ch;
34 /* int VSTRING_SPACE(vp, len)
35 /* VSTRING *vp;
36 /* ssize_t len;
38 /* ssize_t vstring_avail(vp)
39 /* VSTRING *vp;
41 /* VSTRING *vstring_truncate(vp, len)
42 /* VSTRING *vp;
43 /* ssize_t len;
45 /* void VSTRING_RESET(vp)
46 /* VSTRING *vp;
48 /* void VSTRING_TERMINATE(vp)
49 /* VSTRING *vp;
51 /* void VSTRING_SKIP(vp)
52 /* VSTRING *vp;
54 /* VSTRING *vstring_strcpy(vp, src)
55 /* VSTRING *vp;
56 /* const char *src;
58 /* VSTRING *vstring_strncpy(vp, src, len)
59 /* VSTRING *vp;
60 /* const char *src;
61 /* ssize_t len;
63 /* VSTRING *vstring_strcat(vp, src)
64 /* VSTRING *vp;
65 /* const char *src;
67 /* VSTRING *vstring_strncat(vp, src, len)
68 /* VSTRING *vp;
69 /* const char *src;
70 /* ssize_t len;
72 /* VSTRING *vstring_memcpy(vp, src, len)
73 /* VSTRING *vp;
74 /* const char *src;
75 /* ssize_t len;
77 /* VSTRING *vstring_memcat(vp, src, len)
78 /* VSTRING *vp;
79 /* const char *src;
80 /* ssize_t len;
82 /* char *vstring_memchr(vp, ch)
83 /* VSTRING *vp;
84 /* int ch;
86 /* VSTRING *vstring_insert(vp, start, src, len)
87 /* VSTRING *vp;
88 /* ssize_t start;
89 /* const char *src;
90 /* ssize_t len;
92 /* VSTRING *vstring_prepend(vp, src, len)
93 /* VSTRING *vp;
94 /* const char *src;
95 /* ssize_t len;
97 /* VSTRING *vstring_sprintf(vp, format, ...)
98 /* VSTRING *vp;
99 /* const char *format;
101 /* VSTRING *vstring_sprintf_append(vp, format, ...)
102 /* VSTRING *vp;
103 /* const char *format;
105 /* VSTRING *vstring_sprintf_prepend(vp, format, ...)
106 /* VSTRING *vp;
107 /* const char *format;
109 /* VSTRING *vstring_vsprintf(vp, format, ap)
110 /* VSTRING *vp;
111 /* const char *format;
112 /* va_list ap;
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;
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.
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.
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.
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
221 /* null-terminated.
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.
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 /*--*/
269 /* System libraries. */
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>
277 /* Utility library. */
279 #include "mymalloc.h"
280 #include "msg.h"
281 #include "vbuf_print.h"
282 #include "vstring.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;
289 ssize_t new_len;
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);
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;
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);
324 return (0);
327 /* vstring_buf_space - vbuf callback to reserve space */
329 static int vstring_buf_space(VBUF *bp, ssize_t len)
331 ssize_t need;
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);
340 /* vstring_alloc - create variable-length string */
342 VSTRING *vstring_alloc(ssize_t len)
344 VSTRING *vp;
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);
362 /* vstring_free - destroy variable-length string */
364 VSTRING *vstring_free(VSTRING *vp)
366 if (vp->vbuf.data)
367 myfree((char *) vp->vbuf.data);
368 myfree((char *) vp);
369 return (0);
372 /* vstring_ctl - modify memory management policy */
374 void vstring_ctl(VSTRING *vp,...)
376 va_list ap;
377 int code;
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;
391 va_end(ap);
394 /* vstring_truncate - truncate string */
396 VSTRING *vstring_truncate(VSTRING *vp, ssize_t len)
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);
405 /* vstring_strcpy - copy string */
407 VSTRING *vstring_strcpy(VSTRING *vp, const char *src)
409 VSTRING_RESET(vp);
411 while (*src) {
412 VSTRING_ADDCH(vp, *src);
413 src++;
415 VSTRING_TERMINATE(vp);
416 return (vp);
419 /* vstring_strncpy - copy string of limited length */
421 VSTRING *vstring_strncpy(VSTRING *vp, const char *src, ssize_t len)
423 VSTRING_RESET(vp);
425 while (len-- > 0 && *src) {
426 VSTRING_ADDCH(vp, *src);
427 src++;
429 VSTRING_TERMINATE(vp);
430 return (vp);
433 /* vstring_strcat - append string */
435 VSTRING *vstring_strcat(VSTRING *vp, const char *src)
437 while (*src) {
438 VSTRING_ADDCH(vp, *src);
439 src++;
441 VSTRING_TERMINATE(vp);
442 return (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);
451 src++;
453 VSTRING_TERMINATE(vp);
454 return (vp);
457 /* vstring_memcpy - copy buffer of limited length */
459 VSTRING *vstring_memcpy(VSTRING *vp, const char *src, ssize_t len)
461 VSTRING_RESET(vp);
463 VSTRING_SPACE(vp, len);
464 memcpy(vstring_str(vp), src, len);
465 VSTRING_AT_OFFSET(vp, len);
466 return (vp);
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);
477 return (vp);
480 /* vstring_memchr - locate byte in buffer */
482 char *vstring_memchr(VSTRING *vp, int ch)
484 unsigned char *cp;
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);
492 /* vstring_insert - insert text into string */
494 VSTRING *vstring_insert(VSTRING *vp, ssize_t start, const char *buf, ssize_t len)
496 ssize_t new_len;
499 * Sanity check.
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);
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);
516 return (vp);
519 /* vstring_prepend - prepend text to string */
521 VSTRING *vstring_prepend(VSTRING *vp, const char *buf, ssize_t len)
523 ssize_t new_len;
526 * Sanity check.
528 if (len < 0)
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);
540 return (vp);
543 /* vstring_export - VSTRING to bare string */
545 char *vstring_export(VSTRING *vp)
547 char *cp;
549 cp = (char *) vp->vbuf.data;
550 vp->vbuf.data = 0;
551 myfree((char *) vp);
552 return (cp);
555 /* vstring_import - bare string to vstring */
557 VSTRING *vstring_import(char *str)
559 VSTRING *vp;
560 ssize_t len;
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);
571 /* vstring_sprintf - formatted string */
573 VSTRING *vstring_sprintf(VSTRING *vp, const char *format,...)
575 va_list ap;
577 va_start(ap, format);
578 vp = vstring_vsprintf(vp, format, ap);
579 va_end(ap);
580 return (vp);
583 /* vstring_vsprintf - format string, vsprintf-like interface */
585 VSTRING *vstring_vsprintf(VSTRING *vp, const char *format, va_list ap)
587 VSTRING_RESET(vp);
588 vbuf_print(&vp->vbuf, format, ap);
589 VSTRING_TERMINATE(vp);
590 return (vp);
593 /* vstring_sprintf_append - append formatted string */
595 VSTRING *vstring_sprintf_append(VSTRING *vp, const char *format,...)
597 va_list ap;
599 va_start(ap, format);
600 vp = vstring_vsprintf_append(vp, format, ap);
601 va_end(ap);
602 return (vp);
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);
611 return (vp);
614 /* vstring_sprintf_prepend - format + prepend string, vsprintf-like interface */
616 VSTRING *vstring_sprintf_prepend(VSTRING *vp, const char *format,...)
618 va_list ap;
619 ssize_t old_len = VSTRING_LEN(vp);
620 ssize_t result_len;
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);
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);
636 return (vp);
639 #ifdef TEST
642 * Test program - concatenate all command-line arguments into one string.
644 #include <stdio.h>
646 int main(int argc, char **argv)
648 VSTRING *vp = vstring_alloc(1);
650 while (argc-- > 0) {
651 vstring_strcat(vp, *argv++);
652 vstring_strcat(vp, ".");
654 printf("argv concatenated: %s\n", vstring_str(vp));
655 vstring_free(vp);
656 return (0);
659 #endif