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
dwarfstring_constructor(struct dwarfstring_s * g)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
dwarfstring_resize_to(struct dwarfstring_s * g,unsigned long newlen)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
dwarfstring_reset(struct dwarfstring_s * g)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
dwarfstring_constructor_fixed(struct dwarfstring_s * g,unsigned long len)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
dwarfstring_constructor_static(struct dwarfstring_s * g,char * space,unsigned long len)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
dwarfstring_destructor(struct dwarfstring_s * g)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
dwarfstring_append_length(struct dwarfstring_s * g,char * str,unsigned long slen)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
dwarfstring_append(struct dwarfstring_s * g,char * str)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 *
dwarfstring_string(struct dwarfstring_s * g)215 dwarfstring_string(struct dwarfstring_s *g)
216 {
217 return g->s_data;
218 }
219
220 unsigned long
dwarfstring_strlen(struct dwarfstring_s * g)221 dwarfstring_strlen(struct dwarfstring_s *g)
222 {
223 return g->s_size - g->s_avail;
224 }
225
226 static int
_dwarfstring_append_spaces(dwarfstring * data,size_t count)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
_dwarfstring_append_zeros(dwarfstring * data,size_t l)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
dwarfstring_append_printf_s(dwarfstring * data,char * format,char * s)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). */
dwarfstring_append_printf_i(dwarfstring * data,char * format,dwarfstring_i v)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
dwarfstring_append_printf_u(dwarfstring * data,char * format,dwarfstring_u v)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