1 /* 2 Copyright (c) 2019-2019, David Anderson 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with 6 or without modification, are permitted provided that the 7 following conditions are met: 8 9 Redistributions of source code must retain the above 10 copyright notice, this list of conditions and the following 11 disclaimer. 12 13 Redistributions in binary form must reproduce the above 14 copyright notice, this list of conditions and the following 15 disclaimer in the documentation and/or other materials 16 provided with the distribution. 17 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 19 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* A lighly generalized data buffer. 34 Works for more than just strings, 35 but has features (such as ensuring 36 data always has a NUL byte following 37 the data area used) most useful for C strings. 38 39 All these return either TRUE (the values altered) 40 or FALSE (something went wrong, quite likely 41 the caller presented a bad format string for the 42 value). 43 */ 44 45 #include "config.h" 46 #include <stdio.h> /* for malloc */ 47 #ifdef HAVE_STDLIB_H 48 #include <stdlib.h> /* for malloc */ 49 #endif /* HAVE_STDLIB_H */ 50 #include <string.h> /* for strlen */ 51 #ifdef HAVE_MALLOC_H 52 /* Useful include for some Windows compilers. */ 53 #include <malloc.h> 54 #endif /* HAVE_MALLOC_H */ 55 #include "dwarfstring.h" 56 #ifndef TRUE 57 #define TRUE 1 58 #endif /* TRUE */ 59 #ifndef FALSE 60 #define FALSE 0 61 #endif /* FALSE */ 62 63 #ifdef HAVE_UNUSED_ATTRIBUTE 64 #define UNUSEDARG __attribute__ ((unused)) 65 #else 66 #define UNUSEDARG 67 #endif 68 69 70 static unsigned long minimumnewlen = 30; 71 /* 72 struct dwarfstring_s { 73 char * s_data; 74 unsigned long s_size; 75 unsigned long s_avail; 76 unsigned char s_malloc; 77 }; 78 */ 79 80 int 81 dwarfstring_constructor(struct dwarfstring_s *g) 82 { 83 g->s_data = ""; 84 g->s_size = 0; 85 g->s_avail = 0; 86 g->s_malloc = FALSE; 87 return TRUE; 88 } 89 90 static int 91 dwarfstring_resize_to(struct dwarfstring_s *g,unsigned long newlen) 92 { 93 char *b = 0; 94 unsigned long lastpos = 95 g->s_size - g->s_avail; 96 unsigned long malloclen = newlen+1; 97 98 if(malloclen < minimumnewlen) { 99 malloclen = minimumnewlen; 100 } 101 b = malloc(malloclen); 102 if (!b) { 103 return FALSE; 104 } 105 if (lastpos > 0) { 106 memcpy(b,g->s_data,lastpos); 107 } 108 if (g->s_malloc) { 109 free(g->s_data); 110 g->s_data = 0; 111 } 112 g->s_data = b; 113 g->s_data[lastpos] = 0; 114 g->s_size = newlen; 115 g->s_avail = newlen - lastpos; 116 g->s_malloc = TRUE; 117 return TRUE; 118 } 119 120 int 121 dwarfstring_reset(struct dwarfstring_s *g) 122 { 123 if (!g->s_size) { 124 /* In initial condition, nothing to do. */ 125 return TRUE; 126 } 127 g->s_avail = g->s_size; 128 g->s_data[0] = 0; 129 return TRUE; 130 } 131 132 int 133 dwarfstring_constructor_fixed(struct dwarfstring_s *g,unsigned long len) 134 { 135 int r = FALSE; 136 137 dwarfstring_constructor(g); 138 if (len == 0) { 139 return TRUE; 140 } 141 r = dwarfstring_resize_to(g,len); 142 if (!r) { 143 return FALSE; 144 } 145 return TRUE; 146 } 147 148 int 149 dwarfstring_constructor_static(struct dwarfstring_s *g, 150 char * space, 151 unsigned long len) 152 { 153 dwarfstring_constructor(g); 154 g->s_data = space; 155 g->s_data[0] = 0; 156 g->s_size = len; 157 g->s_avail = len; 158 g->s_malloc = FALSE; 159 return TRUE; 160 } 161 162 void 163 dwarfstring_destructor(struct dwarfstring_s *g) 164 { 165 if (g->s_malloc) { 166 free(g->s_data); 167 g->s_data = 0; 168 g->s_malloc = 0; 169 } 170 dwarfstring_constructor(g); 171 } 172 173 /* For the case where one wants just the first 'len' 174 characters of 'str'. NUL terminator provided 175 for you in s_data. 176 */ 177 int 178 dwarfstring_append_length(struct dwarfstring_s *g,char *str, 179 unsigned long slen) 180 { 181 unsigned long lastpos = g->s_size - g->s_avail; 182 int r = 0; 183 184 if (!str || slen ==0) { 185 return TRUE; 186 } 187 if (slen >= g->s_avail) { 188 unsigned long newlen = 0; 189 190 newlen = g->s_size + slen+2; 191 r = dwarfstring_resize_to(g,newlen); 192 if (!r) { 193 return FALSE; 194 } 195 } 196 memcpy(g->s_data + lastpos,str,slen); 197 g->s_avail -= slen; 198 g->s_data[g->s_size - g->s_avail] = 0; 199 return TRUE; 200 } 201 202 int 203 dwarfstring_append(struct dwarfstring_s *g,char *str) 204 { 205 unsigned long dlen = 0; 206 207 if(!str) { 208 return TRUE; 209 } 210 dlen = strlen(str); 211 return dwarfstring_append_length(g,str,dlen); 212 } 213 214 char * 215 dwarfstring_string(struct dwarfstring_s *g) 216 { 217 return g->s_data; 218 } 219 220 unsigned long 221 dwarfstring_strlen(struct dwarfstring_s *g) 222 { 223 return g->s_size - g->s_avail; 224 } 225 226 static int 227 _dwarfstring_append_spaces(dwarfstring *data, 228 size_t count) 229 { 230 int res = 0; 231 char spacebuf[] = {" "}; 232 size_t charct = sizeof(spacebuf)-1; 233 size_t l = count; 234 235 while (l > charct) { 236 res = dwarfstring_append_length(data,spacebuf,charct); 237 l -= charct; 238 if (res != TRUE) { 239 return res; 240 } 241 } 242 /* ASSERT: l > 0 */ 243 res = dwarfstring_append_length(data,spacebuf,l); 244 return res; 245 } 246 static int 247 _dwarfstring_append_zeros(dwarfstring *data, size_t l) 248 { 249 int res = 0; 250 static char zeros[] = {"0000000000000000000000000000000000000000"}; 251 size_t charct = sizeof(zeros)-1; 252 253 while (l > charct) { 254 res = dwarfstring_append_length(data,zeros,charct); 255 l -= charct; 256 if (res != TRUE) { 257 return res; 258 } 259 } 260 /* ASSERT: l > 0 */ 261 dwarfstring_append_length(data,zeros,l); 262 return res; 263 } 264 265 266 int dwarfstring_append_printf_s(dwarfstring *data, 267 char *format,char *s) 268 { 269 size_t stringlen = strlen(s); 270 size_t next = 0; 271 long val = 0; 272 char *endptr = 0; 273 const char *numptr = 0; 274 /* was %[-]fixedlen. Zero means no len provided. */ 275 size_t fixedlen = 0; 276 /* was %-, nonzero means left-justify */ 277 long leftjustify = 0; 278 size_t prefixlen = 0; 279 int res = 0; 280 281 while (format[next] && format[next] != '%') { 282 ++next; 283 ++prefixlen; 284 } 285 if (prefixlen) { 286 dwarfstring_append_length(data,format,prefixlen); 287 } 288 if (!format[next]) { 289 return TRUE; 290 } 291 next++; 292 if (format[next] == '-') { 293 leftjustify++; 294 next++; 295 } 296 numptr = format+next; 297 val = strtol(numptr,&endptr,10); 298 if ( endptr != numptr) { 299 fixedlen = val; 300 } 301 next = (endptr - format); 302 if (format[next] != 's') { 303 return FALSE; 304 } 305 next++; 306 307 if (fixedlen && (stringlen >= fixedlen)) { 308 /* Ignore leftjustify (if any) and the stringlen 309 as the actual string overrides those. */ 310 leftjustify = 0; 311 } 312 if (leftjustify) { 313 314 dwarfstring_append_length(data,s,stringlen); 315 if(fixedlen) { 316 size_t trailingspaces = fixedlen - stringlen; 317 318 _dwarfstring_append_spaces(data,trailingspaces); 319 } 320 } else { 321 if (fixedlen && fixedlen < stringlen) { 322 /* This lets us have fixedlen < stringlen by 323 taking all the chars from s*/ 324 dwarfstring_append_length(data,s,stringlen); 325 } else { 326 if(fixedlen) { 327 size_t leadingspaces = fixedlen - stringlen; 328 size_t k = 0; 329 330 for ( ; k < leadingspaces; ++k) { 331 dwarfstring_append_length(data," ",1); 332 } 333 } 334 dwarfstring_append_length(data,s,stringlen); 335 } 336 } 337 if (!format[next]) { 338 return TRUE; 339 } 340 { 341 char * startpt = format+next; 342 size_t suffixlen = strlen(startpt); 343 344 res = dwarfstring_append_length(data,startpt,suffixlen); 345 } 346 return res; 347 } 348 349 static char v32m[] = {"-2147483648"}; 350 static char v64m[] = {"-9223372036854775808"}; 351 static char dtable[10] = { 352 '0','1','2','3','4','5','6','7','8','9' 353 }; 354 static char xtable[16] = { 355 '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' 356 }; 357 static char Xtable[16] = { 358 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' 359 }; 360 361 /* We deal with formats like: 362 %d %5d %05d %+d %+5d %-5d (and ld and lld too). */ 363 int dwarfstring_append_printf_i(dwarfstring *data, 364 char *format, 365 dwarfstring_i v) 366 { 367 int res = TRUE; 368 size_t next = 0; 369 long val = 0; 370 char *endptr = 0; 371 const char *numptr = 0; 372 size_t fixedlen = 0; 373 int leadingzero = 0; 374 int minuscount = 0; /*left justify */ 375 int pluscount = 0; 376 int lcount = 0; 377 int ucount = 0; 378 int dcount = 0; 379 int xcount = 0; 380 int Xcount = 0; 381 char *ctable = dtable; 382 size_t prefixlen = 0; 383 int done = 0; 384 385 while (format[next] && format[next] != '%') { 386 ++next; 387 ++prefixlen; 388 } 389 dwarfstring_append_length(data,format,prefixlen); 390 if (format[next] != '%') { 391 /* No % operator found, we are done */ 392 return TRUE; 393 } 394 next++; 395 if (format[next] == '-') { 396 minuscount++; 397 return FALSE; 398 } 399 if (format[next] == '+') { 400 pluscount++; 401 next++; 402 } 403 if (format[next] == '0') { 404 leadingzero = 1; 405 next++; 406 } 407 numptr = format+next; 408 val = strtol(numptr,&endptr,10); 409 if ( endptr != numptr) { 410 fixedlen = val; 411 } 412 next = (endptr - format); 413 /* Following is lx lu or u or llx llu , we take 414 all this to mean 64 bits, */ 415 #if defined(_WIN32) && defined(HAVE_NONSTANDARD_PRINTF_64_FORMAT) 416 if (format[next] == 'I') { 417 /*lcount++;*/ 418 next++; 419 } 420 if (format[next] == '6') { 421 /*lcount++;*/ 422 next++; 423 } 424 if (format[next] == '4') { 425 /*lcount++;*/ 426 next++; 427 } 428 #endif /* HAVE_NONSTANDARD_PRINTF_64_FORMAT */ 429 if (format[next] == 'l') { 430 lcount++; 431 next++; 432 } 433 if (format[next] == 'l') { 434 lcount++; 435 next++; 436 } 437 if (format[next] == 'u') { 438 ucount++; 439 next++; 440 } 441 if (format[next] == 'd') { 442 dcount++; 443 next++; 444 } 445 if (format[next] == 'x') { 446 xcount++; 447 next++; 448 } 449 if (format[next] == 'X') { 450 Xcount++; 451 next++; 452 } 453 if (format[next] == 's') { 454 /* ESBERR("ESBERR_pct_scount_in_i"); */ 455 return FALSE; 456 } 457 if (xcount || Xcount) { 458 /* Use the printf_u for %x and the like 459 just copying the entire format makes 460 it easier for coders to understand 461 nothing much was done */ 462 dwarfstring_append(data,format+prefixlen); 463 return FALSE; 464 } 465 if (!dcount || (lcount >2) || 466 (Xcount+xcount+dcount+ucount) > 1) { 467 /* error */ 468 /* ESBERR("ESBERR_xcount_etc_i"); */ 469 return FALSE; 470 } 471 if (pluscount && minuscount) { 472 /* We don't allow format +- */ 473 return FALSE; 474 } 475 { 476 char digbuf[36]; 477 char *digptr = digbuf+sizeof(digbuf) -1; 478 size_t digcharlen = 0; 479 dwarfstring_i remaining = v; 480 int vissigned = 0; 481 dwarfstring_i divisor = 10; 482 483 *digptr = 0; 484 --digptr; 485 if (v < 0) { 486 vissigned = 1; 487 /* This test is for twos-complement 488 machines and would be better done via 489 configure with a compile-time check 490 so we do not need a size test at runtime. */ 491 if (sizeof(v) == 8) { 492 dwarfstring_u vm = 0x7fffffffffffffffULL; 493 if (vm == (dwarfstring_u)~v) { 494 memcpy(digbuf,v64m,sizeof(v64m)); 495 digcharlen = sizeof(v64m)-1; 496 digptr = digbuf; 497 done = 1; 498 } else { 499 remaining = -v; 500 } 501 } else if (sizeof(v) == 4) { 502 dwarfstring_u vm = 0x7fffffffL; 503 if (vm == (dwarfstring_u)~v) { 504 memcpy(digbuf,v32m,sizeof(v32m)); 505 digcharlen = sizeof(v32m)-1; 506 digptr = digbuf; 507 done = 1; 508 } else { 509 remaining = -v; 510 } 511 }else { 512 /* ESBERR("ESBERR_sizeof_v_i"); */ 513 /* error */ 514 return FALSE; 515 } 516 } 517 if(!done) { 518 for ( ;; ) { 519 dwarfstring_u dig = 0; 520 521 dig = remaining % divisor; 522 remaining /= divisor; 523 *digptr = ctable[dig]; 524 digcharlen++; 525 if (!remaining) { 526 break; 527 } 528 --digptr; 529 } 530 if (vissigned) { /* could check minuscount instead */ 531 --digptr; 532 digcharlen++; 533 *digptr = '-'; 534 } else if (pluscount) { 535 --digptr; 536 digcharlen++; 537 *digptr = '+'; 538 } 539 } 540 if (fixedlen > 0) { 541 if (fixedlen <= digcharlen) { 542 dwarfstring_append_length(data,digptr,digcharlen); 543 } else { 544 size_t prefixcount = fixedlen - digcharlen; 545 if (!leadingzero) { 546 _dwarfstring_append_spaces(data,prefixcount); 547 dwarfstring_append_length(data,digptr,digcharlen); 548 } else { 549 if (*digptr == '-') { 550 dwarfstring_append_length(data,"-",1); 551 _dwarfstring_append_zeros(data,prefixcount); 552 digptr++; 553 dwarfstring_append_length(data,digptr, 554 digcharlen-1); 555 } else if (*digptr == '+') { 556 dwarfstring_append_length(data,"+",1); 557 _dwarfstring_append_zeros(data,prefixcount); 558 digptr++; 559 dwarfstring_append_length(data,digptr, 560 digcharlen-1); 561 } else { 562 _dwarfstring_append_zeros(data,prefixcount); 563 dwarfstring_append_length(data,digptr, 564 digcharlen); 565 } 566 } 567 } 568 } else { 569 res = dwarfstring_append_length(data,digptr,digcharlen); 570 } 571 } 572 if (format[next]) { 573 size_t trailinglen = strlen(format+next); 574 res = dwarfstring_append_length(data,format+next,trailinglen); 575 } 576 return res; 577 } 578 579 #if 0 580 /* Counts hex chars. divide by two to get bytes from input 581 integer. */ 582 static unsigned 583 trimleadingzeros(char *ptr,unsigned digits,unsigned keepcount) 584 { 585 char *cp = ptr; 586 unsigned leadzeroscount = 0; 587 unsigned trimoff = 0; 588 589 for(; *cp; ++cp) { 590 if (*cp == '0') { 591 leadzeroscount++; 592 continue; 593 } 594 } 595 trimoff = keepcount - digits; 596 if (trimoff&1) { 597 trimoff--; 598 } 599 return trimoff; 600 } 601 #endif /* 0 */ 602 603 /* With gcc version 5.4.0 20160609 a version using 604 const char *formatp instead of format[next] 605 and deleting the 'next' variable 606 is a few hundredths of a second slower, repeatably. 607 608 We deal with formats like: 609 %u %5u %05u (and ld and lld too). 610 %x %5x %05x (and ld and lld too). */ 611 612 int dwarfstring_append_printf_u(dwarfstring *data, 613 char *format, 614 dwarfstring_u v) 615 { 616 617 size_t next = 0; 618 long val = 0; 619 char *endptr = 0; 620 const char *numptr = 0; 621 size_t fixedlen = 0; 622 int leadingzero = 0; 623 int lcount = 0; 624 int ucount = 0; 625 int dcount = 0; 626 int xcount = 0; 627 int Xcount = 0; 628 char *ctable = 0; 629 size_t divisor = 0; 630 size_t prefixlen = 0; 631 632 while (format[next] && format[next] != '%') { 633 ++next; 634 ++prefixlen; 635 } 636 dwarfstring_append_length(data,format,prefixlen); 637 if (format[next] != '%') { 638 /* No % operator found, we are done */ 639 return TRUE; 640 } 641 next++; 642 if (format[next] == '-') { 643 /*ESBERR("ESBERR_printf_u - format not supported"); */ 644 next++; 645 } 646 if (format[next] == '0') { 647 leadingzero = 1; 648 next++; 649 } 650 numptr = format+next; 651 val = strtol(numptr,&endptr,10); 652 if ( endptr != numptr) { 653 fixedlen = val; 654 } 655 next = (endptr - format); 656 /* Following is lx lu or u or llx llu , we take 657 all this to mean 64 bits, */ 658 #if defined(_WIN32) && defined(HAVE_NONSTANDARD_PRINTF_64_FORMAT) 659 if (format[next] == 'I') { 660 /*lcount++;*/ 661 next++; 662 } 663 if (format[next] == '6') { 664 /*lcount++;*/ 665 next++; 666 } 667 if (format[next] == '4') { 668 /*lcount++;*/ 669 next++; 670 } 671 #endif /* HAVE_NONSTANDARD_PRINTF_64_FORMAT */ 672 if (format[next] == 'l') { 673 lcount++; 674 next++; 675 } 676 if (format[next] == 'l') { 677 lcount++; 678 next++; 679 } 680 if (format[next] == 'u') { 681 ucount++; 682 next++; 683 } 684 if (format[next] == 'd') { 685 dcount++; 686 next++; 687 } 688 if (format[next] == 'x') { 689 xcount++; 690 next++; 691 } 692 if (format[next] == 'X') { 693 Xcount++; 694 next++; 695 } 696 if (format[next] == 's') { 697 /* ESBERR("ESBERR_pct_scount_in_u"); */ 698 return FALSE; 699 } 700 701 if ( (Xcount +xcount+dcount+ucount) > 1) { 702 /* ESBERR("ESBERR_pct_xcount_etc_u"); */ 703 return FALSE; 704 } 705 if (lcount > 2) { 706 /* ESBERR("ESBERR_pct_lcount_error_u"); */ 707 /* error */ 708 return FALSE; 709 } 710 if (dcount > 0) { 711 /*ESBERR("ESBERR_pct_dcount_error_u");*/ 712 /* error */ 713 return FALSE; 714 } 715 if (ucount) { 716 divisor = 10; 717 ctable = dtable; 718 } else { 719 divisor = 16; 720 if (xcount) { 721 ctable = xtable; 722 } else { 723 ctable = Xtable; 724 } 725 } 726 { 727 char digbuf[36]; 728 char *digptr = 0; 729 unsigned digcharlen = 0; 730 dwarfstring_u remaining = v; 731 732 if (divisor == 16) { 733 digptr = digbuf+sizeof(digbuf) -1; 734 for ( ;; ) { 735 dwarfstring_u dig; 736 dig = remaining & 0xf; 737 remaining = remaining >> 4; 738 *digptr = ctable[dig]; 739 ++digcharlen; 740 if (!remaining) { 741 break; 742 } 743 --digptr; 744 } 745 } else { 746 digptr = digbuf+sizeof(digbuf) -1; 747 *digptr = 0; 748 --digptr; 749 for ( ;; ) { 750 dwarfstring_u dig; 751 dig = remaining % divisor; 752 remaining /= divisor; 753 *digptr = ctable[dig]; 754 ++digcharlen; 755 if (!remaining) { 756 break; 757 } 758 --digptr; 759 } 760 } 761 if (fixedlen <= digcharlen) { 762 dwarfstring_append_length(data,digptr,digcharlen); 763 } else { 764 if (!leadingzero) { 765 size_t justcount = fixedlen - digcharlen; 766 _dwarfstring_append_spaces(data,justcount); 767 dwarfstring_append_length(data,digptr,digcharlen); 768 } else { 769 size_t prefixcount = fixedlen - digcharlen; 770 _dwarfstring_append_zeros(data,prefixcount); 771 dwarfstring_append_length(data,digptr,digcharlen); 772 } 773 } 774 } 775 if (format[next]) { 776 size_t trailinglen = strlen(format+next); 777 dwarfstring_append_length(data,format+next,trailinglen); 778 } 779 return FALSE; 780 } 781