1 /* $NetBSD: vstring.c,v 1.2 2017/02/14 01:16:49 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 /* 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 or 137 /* more macros with zer or more arguments, terminated with 138 /* CA_VSTRING_CTL_END which has none. 139 /* .IP "CA_VSTRING_CTL_MAXLEN(ssize_t len)" 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 "CA_VSTRING_CTL_END (no argument)" 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. If length is negative, the trailing portion is kept. 179 /* The operation has no effect when the string is shorter. 180 /* The string is not null-terminated. 181 /* 182 /* VSTRING_RESET() is a macro that resets the write position of its 183 /* string argument to the very beginning. Note that VSTRING_RESET() 184 /* is an unsafe macro that evaluates some arguments more than once. 185 /* The result is NOT null-terminated. 186 /* 187 /* VSTRING_TERMINATE() null-terminates its string argument. 188 /* VSTRING_TERMINATE() is an unsafe macro that evaluates some 189 /* arguments more than once. 190 /* VSTRING_TERMINATE() does not return an interesting result. 191 /* 192 /* VSTRING_SKIP() is a macro that moves the write position to the first 193 /* null byte after the current write position. VSTRING_SKIP() is an unsafe 194 /* macro that evaluates some arguments more than once. 195 /* 196 /* vstring_strcpy() copies a null-terminated string to a variable-length 197 /* string. \fIsrc\fP provides the data to be copied; \fIvp\fP is the 198 /* target and result value. The result is null-terminated. 199 /* 200 /* vstring_strncpy() copies at most \fIlen\fR characters. Otherwise it is 201 /* identical to vstring_strcpy(). 202 /* 203 /* vstring_strcat() appends a null-terminated string to a variable-length 204 /* string. \fIsrc\fP provides the data to be copied; \fIvp\fP is the 205 /* target and result value. The result is null-terminated. 206 /* 207 /* vstring_strncat() copies at most \fIlen\fR characters. Otherwise it is 208 /* identical to vstring_strcat(). 209 /* 210 /* vstring_memcpy() copies \fIlen\fR bytes to a variable-length string. 211 /* \fIsrc\fP provides the data to be copied; \fIvp\fP is the 212 /* target and result value. The result is not null-terminated. 213 /* 214 /* vstring_memcat() appends \fIlen\fR bytes to a variable-length string. 215 /* \fIsrc\fP provides the data to be copied; \fIvp\fP is the 216 /* target and result value. The result is not null-terminated. 217 /* 218 /* vstring_memchr() locates a byte in a variable-length string. 219 /* 220 /* vstring_insert() inserts a buffer content into a variable-length 221 /* string at the specified start position. The result is 222 /* null-terminated. 223 /* 224 /* vstring_prepend() prepends a buffer content to a variable-length 225 /* string. The result is null-terminated. 226 /* 227 /* vstring_sprintf() produces a formatted string according to its 228 /* \fIformat\fR argument. See vstring_vsprintf() for details. 229 /* 230 /* vstring_sprintf_append() is like vstring_sprintf(), but appends 231 /* to the end of the result buffer. 232 /* 233 /* vstring_sprintf_append() is like vstring_sprintf(), but prepends 234 /* to the beginning of the result buffer. 235 /* 236 /* vstring_vsprintf() returns a null-terminated string according to 237 /* the \fIformat\fR argument. It understands the s, c, d, u, 238 /* o, x, X, p, e, f and g format types, the l modifier, field width 239 /* and precision, sign, and null or space padding. This module 240 /* can format strings as large as available memory permits. 241 /* 242 /* vstring_vsprintf_append() is like vstring_vsprintf(), but appends 243 /* to the end of the result buffer. 244 /* 245 /* In addition to stdio-like format specifiers, vstring_vsprintf() 246 /* recognizes %m and expands it to the corresponding errno text. 247 /* 248 /* vstring_export() extracts the string value from a VSTRING. 249 /* The VSTRING is destroyed. The result should be passed to myfree(). 250 /* 251 /* vstring_import() takes a `bare' string and converts it to 252 /* a VSTRING. The string argument must be obtained from mymalloc(). 253 /* The string argument is not copied. 254 /* DIAGNOSTICS 255 /* Fatal errors: memory allocation failure. 256 /* BUGS 257 /* Auto-resizing may change the address of the string data in 258 /* a vstring structure. Beware of dangling pointers. 259 /* HISTORY 260 /* .ad 261 /* .fi 262 /* A vstring module appears in the UNPROTO software by Wietse Venema. 263 /* AUTHOR(S) 264 /* Wietse Venema 265 /* IBM T.J. Watson Research 266 /* P.O. Box 704 267 /* Yorktown Heights, NY 10598, USA 268 /*--*/ 269 270 /* System libraries. */ 271 272 #include <sys_defs.h> 273 #include <stddef.h> 274 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */ 275 #include <stdarg.h> 276 #include <string.h> 277 278 /* Utility library. */ 279 280 #include "mymalloc.h" 281 #include "msg.h" 282 #include "vbuf_print.h" 283 #include "vstring.h" 284 285 /* vstring_extend - variable-length string buffer extension policy */ 286 287 static void vstring_extend(VBUF *bp, ssize_t incr) 288 { 289 size_t used = bp->ptr - bp->data; 290 ssize_t new_len; 291 292 /* 293 * Note: vp->vbuf.len is the current buffer size (both on entry and on 294 * exit of this routine). We round up the increment size to the buffer 295 * size to avoid silly little buffer increments. With really large 296 * strings we might want to abandon the length doubling strategy, and go 297 * to fixed increments. 298 * 299 * The length overflow tests here and in vstring_alloc() should protect us 300 * against all length overflow problems within vstring library routines. 301 * (The tests are redundant as long as mymalloc() and myrealloc() reject 302 * negative length parameters). 303 */ 304 new_len = bp->len + (bp->len > incr ? bp->len : incr); 305 if (new_len <= bp->len) 306 msg_fatal("vstring_extend: length overflow"); 307 bp->data = (unsigned char *) myrealloc((void *) bp->data, new_len); 308 bp->len = new_len; 309 bp->ptr = bp->data + used; 310 bp->cnt = bp->len - used; 311 } 312 313 /* vstring_buf_get_ready - vbuf callback for read buffer empty condition */ 314 315 static int vstring_buf_get_ready(VBUF *unused_buf) 316 { 317 msg_panic("vstring_buf_get: write-only buffer"); 318 } 319 320 /* vstring_buf_put_ready - vbuf callback for write buffer full condition */ 321 322 static int vstring_buf_put_ready(VBUF *bp) 323 { 324 vstring_extend(bp, 0); 325 return (0); 326 } 327 328 /* vstring_buf_space - vbuf callback to reserve space */ 329 330 static int vstring_buf_space(VBUF *bp, ssize_t len) 331 { 332 ssize_t need; 333 334 if (len < 0) 335 msg_panic("vstring_buf_space: bad length %ld", (long) len); 336 if ((need = len - bp->cnt) > 0) 337 vstring_extend(bp, need); 338 return (0); 339 } 340 341 /* vstring_alloc - create variable-length string */ 342 343 VSTRING *vstring_alloc(ssize_t len) 344 { 345 VSTRING *vp; 346 347 if (len < 1) 348 msg_panic("vstring_alloc: bad length %ld", (long) len); 349 vp = (VSTRING *) mymalloc(sizeof(*vp)); 350 vp->vbuf.flags = 0; 351 vp->vbuf.len = 0; 352 vp->vbuf.data = (unsigned char *) mymalloc(len); 353 vp->vbuf.len = len; 354 VSTRING_RESET(vp); 355 vp->vbuf.data[0] = 0; 356 vp->vbuf.get_ready = vstring_buf_get_ready; 357 vp->vbuf.put_ready = vstring_buf_put_ready; 358 vp->vbuf.space = vstring_buf_space; 359 vp->maxlen = 0; 360 return (vp); 361 } 362 363 /* vstring_free - destroy variable-length string */ 364 365 VSTRING *vstring_free(VSTRING *vp) 366 { 367 if (vp->vbuf.data) 368 myfree((void *) vp->vbuf.data); 369 myfree((void *) vp); 370 return (0); 371 } 372 373 /* vstring_ctl - modify memory management policy */ 374 375 void vstring_ctl(VSTRING *vp,...) 376 { 377 va_list ap; 378 int code; 379 380 va_start(ap, vp); 381 while ((code = va_arg(ap, int)) != VSTRING_CTL_END) { 382 switch (code) { 383 default: 384 msg_panic("vstring_ctl: unknown code: %d", code); 385 case VSTRING_CTL_MAXLEN: 386 vp->maxlen = va_arg(ap, ssize_t); 387 if (vp->maxlen < 0) 388 msg_panic("vstring_ctl: bad max length %ld", (long) vp->maxlen); 389 break; 390 } 391 } 392 va_end(ap); 393 } 394 395 /* vstring_truncate - truncate string */ 396 397 VSTRING *vstring_truncate(VSTRING *vp, ssize_t len) 398 { 399 ssize_t move; 400 401 if (len < 0) { 402 len = (-len); 403 if ((move = VSTRING_LEN(vp) - len) > 0) 404 memmove(vstring_str(vp), vstring_str(vp) + move, len); 405 } 406 if (len < VSTRING_LEN(vp)) 407 VSTRING_AT_OFFSET(vp, len); 408 return (vp); 409 } 410 411 /* vstring_strcpy - copy string */ 412 413 VSTRING *vstring_strcpy(VSTRING *vp, const char *src) 414 { 415 VSTRING_RESET(vp); 416 417 while (*src) { 418 VSTRING_ADDCH(vp, *src); 419 src++; 420 } 421 VSTRING_TERMINATE(vp); 422 return (vp); 423 } 424 425 /* vstring_strncpy - copy string of limited length */ 426 427 VSTRING *vstring_strncpy(VSTRING *vp, const char *src, ssize_t len) 428 { 429 VSTRING_RESET(vp); 430 431 while (len-- > 0 && *src) { 432 VSTRING_ADDCH(vp, *src); 433 src++; 434 } 435 VSTRING_TERMINATE(vp); 436 return (vp); 437 } 438 439 /* vstring_strcat - append string */ 440 441 VSTRING *vstring_strcat(VSTRING *vp, const char *src) 442 { 443 while (*src) { 444 VSTRING_ADDCH(vp, *src); 445 src++; 446 } 447 VSTRING_TERMINATE(vp); 448 return (vp); 449 } 450 451 /* vstring_strncat - append string of limited length */ 452 453 VSTRING *vstring_strncat(VSTRING *vp, const char *src, ssize_t len) 454 { 455 while (len-- > 0 && *src) { 456 VSTRING_ADDCH(vp, *src); 457 src++; 458 } 459 VSTRING_TERMINATE(vp); 460 return (vp); 461 } 462 463 /* vstring_memcpy - copy buffer of limited length */ 464 465 VSTRING *vstring_memcpy(VSTRING *vp, const char *src, ssize_t len) 466 { 467 VSTRING_RESET(vp); 468 469 VSTRING_SPACE(vp, len); 470 memcpy(vstring_str(vp), src, len); 471 VSTRING_AT_OFFSET(vp, len); 472 return (vp); 473 } 474 475 /* vstring_memcat - append buffer of limited length */ 476 477 VSTRING *vstring_memcat(VSTRING *vp, const char *src, ssize_t len) 478 { 479 VSTRING_SPACE(vp, len); 480 memcpy(vstring_end(vp), src, len); 481 len += VSTRING_LEN(vp); 482 VSTRING_AT_OFFSET(vp, len); 483 return (vp); 484 } 485 486 /* vstring_memchr - locate byte in buffer */ 487 488 char *vstring_memchr(VSTRING *vp, int ch) 489 { 490 unsigned char *cp; 491 492 for (cp = (unsigned char *) vstring_str(vp); cp < (unsigned char *) vstring_end(vp); cp++) 493 if (*cp == ch) 494 return ((char *) cp); 495 return (0); 496 } 497 498 /* vstring_insert - insert text into string */ 499 500 VSTRING *vstring_insert(VSTRING *vp, ssize_t start, const char *buf, ssize_t len) 501 { 502 ssize_t new_len; 503 504 /* 505 * Sanity check. 506 */ 507 if (start < 0 || start >= VSTRING_LEN(vp)) 508 msg_panic("vstring_insert: bad start %ld", (long) start); 509 if (len < 0) 510 msg_panic("vstring_insert: bad length %ld", (long) len); 511 512 /* 513 * Move the existing content and copy the new content. 514 */ 515 new_len = VSTRING_LEN(vp) + len; 516 VSTRING_SPACE(vp, len); 517 memmove(vstring_str(vp) + start + len, vstring_str(vp) + start, 518 VSTRING_LEN(vp) - start); 519 memcpy(vstring_str(vp) + start, buf, len); 520 VSTRING_AT_OFFSET(vp, new_len); 521 VSTRING_TERMINATE(vp); 522 return (vp); 523 } 524 525 /* vstring_prepend - prepend text to string */ 526 527 VSTRING *vstring_prepend(VSTRING *vp, const char *buf, ssize_t len) 528 { 529 ssize_t new_len; 530 531 /* 532 * Sanity check. 533 */ 534 if (len < 0) 535 msg_panic("vstring_prepend: bad length %ld", (long) len); 536 537 /* 538 * Move the existing content and copy the new content. 539 */ 540 new_len = VSTRING_LEN(vp) + len; 541 VSTRING_SPACE(vp, len); 542 memmove(vstring_str(vp) + len, vstring_str(vp), VSTRING_LEN(vp)); 543 memcpy(vstring_str(vp), buf, len); 544 VSTRING_AT_OFFSET(vp, new_len); 545 VSTRING_TERMINATE(vp); 546 return (vp); 547 } 548 549 /* vstring_export - VSTRING to bare string */ 550 551 char *vstring_export(VSTRING *vp) 552 { 553 char *cp; 554 555 cp = (char *) vp->vbuf.data; 556 vp->vbuf.data = 0; 557 myfree((void *) vp); 558 return (cp); 559 } 560 561 /* vstring_import - bare string to vstring */ 562 563 VSTRING *vstring_import(char *str) 564 { 565 VSTRING *vp; 566 ssize_t len; 567 568 vp = (VSTRING *) mymalloc(sizeof(*vp)); 569 len = strlen(str); 570 vp->vbuf.flags = 0; 571 vp->vbuf.len = 0; 572 vp->vbuf.data = (unsigned char *) str; 573 vp->vbuf.len = len + 1; 574 VSTRING_AT_OFFSET(vp, len); 575 vp->vbuf.get_ready = vstring_buf_get_ready; 576 vp->vbuf.put_ready = vstring_buf_put_ready; 577 vp->vbuf.space = vstring_buf_space; 578 vp->maxlen = 0; 579 return (vp); 580 } 581 582 /* vstring_sprintf - formatted string */ 583 584 VSTRING *vstring_sprintf(VSTRING *vp, const char *format,...) 585 { 586 va_list ap; 587 588 va_start(ap, format); 589 vp = vstring_vsprintf(vp, format, ap); 590 va_end(ap); 591 return (vp); 592 } 593 594 /* vstring_vsprintf - format string, vsprintf-like interface */ 595 596 VSTRING *vstring_vsprintf(VSTRING *vp, const char *format, va_list ap) 597 { 598 VSTRING_RESET(vp); 599 vbuf_print(&vp->vbuf, format, ap); 600 VSTRING_TERMINATE(vp); 601 return (vp); 602 } 603 604 /* vstring_sprintf_append - append formatted string */ 605 606 VSTRING *vstring_sprintf_append(VSTRING *vp, const char *format,...) 607 { 608 va_list ap; 609 610 va_start(ap, format); 611 vp = vstring_vsprintf_append(vp, format, ap); 612 va_end(ap); 613 return (vp); 614 } 615 616 /* vstring_vsprintf_append - format + append string, vsprintf-like interface */ 617 618 VSTRING *vstring_vsprintf_append(VSTRING *vp, const char *format, va_list ap) 619 { 620 vbuf_print(&vp->vbuf, format, ap); 621 VSTRING_TERMINATE(vp); 622 return (vp); 623 } 624 625 /* vstring_sprintf_prepend - format + prepend string, vsprintf-like interface */ 626 627 VSTRING *vstring_sprintf_prepend(VSTRING *vp, const char *format,...) 628 { 629 va_list ap; 630 ssize_t old_len = VSTRING_LEN(vp); 631 ssize_t result_len; 632 633 /* Construct: old|new|free */ 634 va_start(ap, format); 635 vp = vstring_vsprintf_append(vp, format, ap); 636 va_end(ap); 637 result_len = VSTRING_LEN(vp); 638 639 /* Construct: old|new|old|free */ 640 VSTRING_SPACE(vp, old_len); 641 vstring_memcat(vp, vstring_str(vp), old_len); 642 643 /* Construct: new|old|free */ 644 memmove(vstring_str(vp), vstring_str(vp) + old_len, result_len); 645 VSTRING_AT_OFFSET(vp, result_len); 646 VSTRING_TERMINATE(vp); 647 return (vp); 648 } 649 650 #ifdef TEST 651 652 /* 653 * Test program - concatenate all command-line arguments into one string. 654 */ 655 #include <stdio.h> 656 657 int main(int argc, char **argv) 658 { 659 VSTRING *vp = vstring_alloc(1); 660 661 while (argc-- > 0) { 662 vstring_strcat(vp, *argv++); 663 vstring_strcat(vp, "."); 664 } 665 printf("argv concatenated: %s\n", vstring_str(vp)); 666 vstring_free(vp); 667 return (0); 668 } 669 670 #endif 671