summaryrefslogtreecommitdiff
path: root/openbsd-compat/bsd-snprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsd-compat/bsd-snprintf.c')
-rw-r--r--openbsd-compat/bsd-snprintf.c188
1 files changed, 118 insertions, 70 deletions
diff --git a/openbsd-compat/bsd-snprintf.c b/openbsd-compat/bsd-snprintf.c
index e4ba154fd..41d2be238 100644
--- a/openbsd-compat/bsd-snprintf.c
+++ b/openbsd-compat/bsd-snprintf.c
@@ -85,12 +85,15 @@
85 * 85 *
86 * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even 86 * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
87 * if the C library has some snprintf functions already. 87 * if the C library has some snprintf functions already.
88 *
89 * Damien Miller (djm@mindrot.org) Jan 2007
90 * Fix integer overflows in return value.
91 * Make formatting quite a bit faster by inlining dopr_outch()
92 *
88 **************************************************************/ 93 **************************************************************/
89 94
90#include "includes.h" 95#include "includes.h"
91 96
92RCSID("$Id: bsd-snprintf.c,v 1.11 2005/12/17 11:32:04 dtucker Exp $");
93
94#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */ 97#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */
95# undef HAVE_SNPRINTF 98# undef HAVE_SNPRINTF
96# undef HAVE_VSNPRINTF 99# undef HAVE_VSNPRINTF
@@ -110,6 +113,13 @@ RCSID("$Id: bsd-snprintf.c,v 1.11 2005/12/17 11:32:04 dtucker Exp $");
110 113
111#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) 114#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
112 115
116#include <ctype.h>
117#include <stdarg.h>
118#include <stdlib.h>
119#include <string.h>
120#include <limits.h>
121#include <errno.h>
122
113#ifdef HAVE_LONG_DOUBLE 123#ifdef HAVE_LONG_DOUBLE
114# define LDOUBLE long double 124# define LDOUBLE long double
115#else 125#else
@@ -156,17 +166,28 @@ RCSID("$Id: bsd-snprintf.c,v 1.11 2005/12/17 11:32:04 dtucker Exp $");
156# define MAX(p,q) (((p) >= (q)) ? (p) : (q)) 166# define MAX(p,q) (((p) >= (q)) ? (p) : (q))
157#endif 167#endif
158 168
159static size_t dopr(char *buffer, size_t maxlen, const char *format, 169#define DOPR_OUTCH(buf, pos, buflen, thechar) \
160 va_list args_in); 170 do { \
161static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, 171 if (pos + 1 >= INT_MAX) { \
162 char *value, int flags, int min, int max); 172 errno = ERANGE; \
163static void fmtint(char *buffer, size_t *currlen, size_t maxlen, 173 return -1; \
164 long value, int base, int min, int max, int flags); 174 } \
165static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, 175 if (pos < buflen) \
166 LDOUBLE fvalue, int min, int max, int flags); 176 buf[pos] = thechar; \
167static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); 177 (pos)++; \
168 178 } while (0)
169static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) 179
180static int dopr(char *buffer, size_t maxlen, const char *format,
181 va_list args_in);
182static int fmtstr(char *buffer, size_t *currlen, size_t maxlen,
183 char *value, int flags, int min, int max);
184static int fmtint(char *buffer, size_t *currlen, size_t maxlen,
185 LLONG value, int base, int min, int max, int flags);
186static int fmtfp(char *buffer, size_t *currlen, size_t maxlen,
187 LDOUBLE fvalue, int min, int max, int flags);
188
189static int
190dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
170{ 191{
171 char ch; 192 char ch;
172 LLONG value; 193 LLONG value;
@@ -195,8 +216,8 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
195 case DP_S_DEFAULT: 216 case DP_S_DEFAULT:
196 if (ch == '%') 217 if (ch == '%')
197 state = DP_S_FLAGS; 218 state = DP_S_FLAGS;
198 else 219 else
199 dopr_outch (buffer, &currlen, maxlen, ch); 220 DOPR_OUTCH(buffer, currlen, maxlen, ch);
200 ch = *format++; 221 ch = *format++;
201 break; 222 break;
202 case DP_S_FLAGS: 223 case DP_S_FLAGS:
@@ -295,7 +316,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
295 value = va_arg (args, LLONG); 316 value = va_arg (args, LLONG);
296 else 317 else
297 value = va_arg (args, int); 318 value = va_arg (args, int);
298 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 319 if (fmtint(buffer, &currlen, maxlen,
320 value, 10, min, max, flags) == -1)
321 return -1;
299 break; 322 break;
300 case 'o': 323 case 'o':
301 flags |= DP_F_UNSIGNED; 324 flags |= DP_F_UNSIGNED;
@@ -307,7 +330,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
307 value = (long)va_arg (args, unsigned LLONG); 330 value = (long)va_arg (args, unsigned LLONG);
308 else 331 else
309 value = (long)va_arg (args, unsigned int); 332 value = (long)va_arg (args, unsigned int);
310 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); 333 if (fmtint(buffer, &currlen, maxlen, value,
334 8, min, max, flags) == -1)
335 return -1;
311 break; 336 break;
312 case 'u': 337 case 'u':
313 flags |= DP_F_UNSIGNED; 338 flags |= DP_F_UNSIGNED;
@@ -319,7 +344,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
319 value = (LLONG)va_arg (args, unsigned LLONG); 344 value = (LLONG)va_arg (args, unsigned LLONG);
320 else 345 else
321 value = (long)va_arg (args, unsigned int); 346 value = (long)va_arg (args, unsigned int);
322 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 347 if (fmtint(buffer, &currlen, maxlen, value,
348 10, min, max, flags) == -1)
349 return -1;
323 break; 350 break;
324 case 'X': 351 case 'X':
325 flags |= DP_F_UP; 352 flags |= DP_F_UP;
@@ -333,15 +360,18 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
333 value = (LLONG)va_arg (args, unsigned LLONG); 360 value = (LLONG)va_arg (args, unsigned LLONG);
334 else 361 else
335 value = (long)va_arg (args, unsigned int); 362 value = (long)va_arg (args, unsigned int);
336 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); 363 if (fmtint(buffer, &currlen, maxlen, value,
364 16, min, max, flags) == -1)
365 return -1;
337 break; 366 break;
338 case 'f': 367 case 'f':
339 if (cflags == DP_C_LDOUBLE) 368 if (cflags == DP_C_LDOUBLE)
340 fvalue = va_arg (args, LDOUBLE); 369 fvalue = va_arg (args, LDOUBLE);
341 else 370 else
342 fvalue = va_arg (args, double); 371 fvalue = va_arg (args, double);
343 /* um, floating point? */ 372 if (fmtfp(buffer, &currlen, maxlen, fvalue,
344 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 373 min, max, flags) == -1)
374 return -1;
345 break; 375 break;
346 case 'E': 376 case 'E':
347 flags |= DP_F_UP; 377 flags |= DP_F_UP;
@@ -350,7 +380,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
350 fvalue = va_arg (args, LDOUBLE); 380 fvalue = va_arg (args, LDOUBLE);
351 else 381 else
352 fvalue = va_arg (args, double); 382 fvalue = va_arg (args, double);
353 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 383 if (fmtfp(buffer, &currlen, maxlen, fvalue,
384 min, max, flags) == -1)
385 return -1;
354 break; 386 break;
355 case 'G': 387 case 'G':
356 flags |= DP_F_UP; 388 flags |= DP_F_UP;
@@ -359,10 +391,13 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
359 fvalue = va_arg (args, LDOUBLE); 391 fvalue = va_arg (args, LDOUBLE);
360 else 392 else
361 fvalue = va_arg (args, double); 393 fvalue = va_arg (args, double);
362 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 394 if (fmtfp(buffer, &currlen, maxlen, fvalue,
395 min, max, flags) == -1)
396 return -1;
363 break; 397 break;
364 case 'c': 398 case 'c':
365 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); 399 DOPR_OUTCH(buffer, currlen, maxlen,
400 va_arg (args, int));
366 break; 401 break;
367 case 's': 402 case 's':
368 strvalue = va_arg (args, char *); 403 strvalue = va_arg (args, char *);
@@ -371,11 +406,15 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
371 max = strlen(strvalue); 406 max = strlen(strvalue);
372 } 407 }
373 if (min > 0 && max >= 0 && min > max) max = min; 408 if (min > 0 && max >= 0 && min > max) max = min;
374 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); 409 if (fmtstr(buffer, &currlen, maxlen,
410 strvalue, flags, min, max) == -1)
411 return -1;
375 break; 412 break;
376 case 'p': 413 case 'p':
377 strvalue = va_arg (args, void *); 414 strvalue = va_arg (args, void *);
378 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); 415 if (fmtint(buffer, &currlen, maxlen,
416 (long) strvalue, 16, min, max, flags) == -1)
417 return -1;
379 break; 418 break;
380 case 'n': 419 case 'n':
381 if (cflags == DP_C_SHORT) { 420 if (cflags == DP_C_SHORT) {
@@ -397,7 +436,7 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
397 } 436 }
398 break; 437 break;
399 case '%': 438 case '%':
400 dopr_outch (buffer, &currlen, maxlen, ch); 439 DOPR_OUTCH(buffer, currlen, maxlen, ch);
401 break; 440 break;
402 case 'w': 441 case 'w':
403 /* not supported yet, treat as next char */ 442 /* not supported yet, treat as next char */
@@ -426,11 +465,12 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
426 buffer[maxlen - 1] = '\0'; 465 buffer[maxlen - 1] = '\0';
427 } 466 }
428 467
429 return currlen; 468 return currlen < INT_MAX ? (int)currlen : -1;
430} 469}
431 470
432static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, 471static int
433 char *value, int flags, int min, int max) 472fmtstr(char *buffer, size_t *currlen, size_t maxlen,
473 char *value, int flags, int min, int max)
434{ 474{
435 int padlen, strln; /* amount to pad */ 475 int padlen, strln; /* amount to pad */
436 int cnt = 0; 476 int cnt = 0;
@@ -450,28 +490,31 @@ static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
450 padlen = -padlen; /* Left Justify */ 490 padlen = -padlen; /* Left Justify */
451 491
452 while ((padlen > 0) && (cnt < max)) { 492 while ((padlen > 0) && (cnt < max)) {
453 dopr_outch (buffer, currlen, maxlen, ' '); 493 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
454 --padlen; 494 --padlen;
455 ++cnt; 495 ++cnt;
456 } 496 }
457 while (*value && (cnt < max)) { 497 while (*value && (cnt < max)) {
458 dopr_outch (buffer, currlen, maxlen, *value++); 498 DOPR_OUTCH(buffer, *currlen, maxlen, *value);
499 *value++;
459 ++cnt; 500 ++cnt;
460 } 501 }
461 while ((padlen < 0) && (cnt < max)) { 502 while ((padlen < 0) && (cnt < max)) {
462 dopr_outch (buffer, currlen, maxlen, ' '); 503 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
463 ++padlen; 504 ++padlen;
464 ++cnt; 505 ++cnt;
465 } 506 }
507 return 0;
466} 508}
467 509
468/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ 510/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
469 511
470static void fmtint(char *buffer, size_t *currlen, size_t maxlen, 512static int
471 long value, int base, int min, int max, int flags) 513fmtint(char *buffer, size_t *currlen, size_t maxlen,
514 LLONG value, int base, int min, int max, int flags)
472{ 515{
473 int signvalue = 0; 516 int signvalue = 0;
474 unsigned long uvalue; 517 unsigned LLONG uvalue;
475 char convert[20]; 518 char convert[20];
476 int place = 0; 519 int place = 0;
477 int spadlen = 0; /* amount to space pad */ 520 int spadlen = 0; /* amount to space pad */
@@ -524,31 +567,34 @@ static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
524 567
525 /* Spaces */ 568 /* Spaces */
526 while (spadlen > 0) { 569 while (spadlen > 0) {
527 dopr_outch (buffer, currlen, maxlen, ' '); 570 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
528 --spadlen; 571 --spadlen;
529 } 572 }
530 573
531 /* Sign */ 574 /* Sign */
532 if (signvalue) 575 if (signvalue)
533 dopr_outch (buffer, currlen, maxlen, signvalue); 576 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
534 577
535 /* Zeros */ 578 /* Zeros */
536 if (zpadlen > 0) { 579 if (zpadlen > 0) {
537 while (zpadlen > 0) { 580 while (zpadlen > 0) {
538 dopr_outch (buffer, currlen, maxlen, '0'); 581 DOPR_OUTCH(buffer, *currlen, maxlen, '0');
539 --zpadlen; 582 --zpadlen;
540 } 583 }
541 } 584 }
542 585
543 /* Digits */ 586 /* Digits */
544 while (place > 0) 587 while (place > 0) {
545 dopr_outch (buffer, currlen, maxlen, convert[--place]); 588 --place;
589 DOPR_OUTCH(buffer, *currlen, maxlen, convert[place]);
590 }
546 591
547 /* Left Justified spaces */ 592 /* Left Justified spaces */
548 while (spadlen < 0) { 593 while (spadlen < 0) {
549 dopr_outch (buffer, currlen, maxlen, ' '); 594 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
550 ++spadlen; 595 ++spadlen;
551 } 596 }
597 return 0;
552} 598}
553 599
554static LDOUBLE abs_val(LDOUBLE value) 600static LDOUBLE abs_val(LDOUBLE value)
@@ -561,13 +607,13 @@ static LDOUBLE abs_val(LDOUBLE value)
561 return result; 607 return result;
562} 608}
563 609
564static LDOUBLE POW10(int exp) 610static LDOUBLE POW10(int val)
565{ 611{
566 LDOUBLE result = 1; 612 LDOUBLE result = 1;
567 613
568 while (exp) { 614 while (val) {
569 result *= 10; 615 result *= 10;
570 exp--; 616 val--;
571 } 617 }
572 618
573 return result; 619 return result;
@@ -601,7 +647,10 @@ static double my_modf(double x0, double *iptr)
601 } 647 }
602 648
603 if (i == 100) { 649 if (i == 100) {
604 /* yikes! the number is beyond what we can handle. What do we do? */ 650 /*
651 * yikes! the number is beyond what we can handle.
652 * What do we do?
653 */
605 (*iptr) = 0; 654 (*iptr) = 0;
606 return 0; 655 return 0;
607 } 656 }
@@ -620,8 +669,9 @@ static double my_modf(double x0, double *iptr)
620} 669}
621 670
622 671
623static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, 672static int
624 LDOUBLE fvalue, int min, int max, int flags) 673fmtfp (char *buffer, size_t *currlen, size_t maxlen,
674 LDOUBLE fvalue, int min, int max, int flags)
625{ 675{
626 int signvalue = 0; 676 int signvalue = 0;
627 double ufvalue; 677 double ufvalue;
@@ -726,24 +776,26 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
726 776
727 if ((flags & DP_F_ZERO) && (padlen > 0)) { 777 if ((flags & DP_F_ZERO) && (padlen > 0)) {
728 if (signvalue) { 778 if (signvalue) {
729 dopr_outch (buffer, currlen, maxlen, signvalue); 779 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
730 --padlen; 780 --padlen;
731 signvalue = 0; 781 signvalue = 0;
732 } 782 }
733 while (padlen > 0) { 783 while (padlen > 0) {
734 dopr_outch (buffer, currlen, maxlen, '0'); 784 DOPR_OUTCH(buffer, *currlen, maxlen, '0');
735 --padlen; 785 --padlen;
736 } 786 }
737 } 787 }
738 while (padlen > 0) { 788 while (padlen > 0) {
739 dopr_outch (buffer, currlen, maxlen, ' '); 789 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
740 --padlen; 790 --padlen;
741 } 791 }
742 if (signvalue) 792 if (signvalue)
743 dopr_outch (buffer, currlen, maxlen, signvalue); 793 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
744 794
745 while (iplace > 0) 795 while (iplace > 0) {
746 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); 796 --iplace;
797 DOPR_OUTCH(buffer, *currlen, maxlen, iconvert[iplace]);
798 }
747 799
748#ifdef DEBUG_SNPRINTF 800#ifdef DEBUG_SNPRINTF
749 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); 801 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
@@ -754,41 +806,38 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
754 * char to print out. 806 * char to print out.
755 */ 807 */
756 if (max > 0) { 808 if (max > 0) {
757 dopr_outch (buffer, currlen, maxlen, '.'); 809 DOPR_OUTCH(buffer, *currlen, maxlen, '.');
758 810
759 while (zpadlen > 0) { 811 while (zpadlen > 0) {
760 dopr_outch (buffer, currlen, maxlen, '0'); 812 DOPR_OUTCH(buffer, *currlen, maxlen, '0');
761 --zpadlen; 813 --zpadlen;
762 } 814 }
763 815
764 while (fplace > 0) 816 while (fplace > 0) {
765 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); 817 --fplace;
818 DOPR_OUTCH(buffer, *currlen, maxlen, fconvert[fplace]);
819 }
766 } 820 }
767 821
768 while (padlen < 0) { 822 while (padlen < 0) {
769 dopr_outch (buffer, currlen, maxlen, ' '); 823 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
770 ++padlen; 824 ++padlen;
771 } 825 }
772} 826 return 0;
773
774static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
775{
776 if (*currlen < maxlen) {
777 buffer[(*currlen)] = c;
778 }
779 (*currlen)++;
780} 827}
781#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ 828#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
782 829
783#if !defined(HAVE_VSNPRINTF) 830#if !defined(HAVE_VSNPRINTF)
784int vsnprintf (char *str, size_t count, const char *fmt, va_list args) 831int
832vsnprintf (char *str, size_t count, const char *fmt, va_list args)
785{ 833{
786 return dopr(str, count, fmt, args); 834 return dopr(str, count, fmt, args);
787} 835}
788#endif 836#endif
789 837
790#if !defined(HAVE_SNPRINTF) 838#if !defined(HAVE_SNPRINTF)
791int snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...) 839int
840snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...)
792{ 841{
793 size_t ret; 842 size_t ret;
794 va_list ap; 843 va_list ap;
@@ -799,4 +848,3 @@ int snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...)
799 return ret; 848 return ret;
800} 849}
801#endif 850#endif
802