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