printf.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. #include "lib/string/printf.h"
  6. #include "lib/err/torerr.h"
  7. #include "lib/cc/torint.h"
  8. #include "lib/malloc/util_malloc.h"
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. /** Replacement for snprintf. Differs from platform snprintf in two
  12. * ways: First, always NUL-terminates its output. Second, always
  13. * returns -1 if the result is truncated. (Note that this return
  14. * behavior does <i>not</i> conform to C99; it just happens to be
  15. * easier to emulate "return -1" with conformant implementations than
  16. * it is to emulate "return number that would be written" with
  17. * non-conformant implementations.) */
  18. int
  19. tor_snprintf(char *str, size_t size, const char *format, ...)
  20. {
  21. va_list ap;
  22. int r;
  23. va_start(ap,format);
  24. r = tor_vsnprintf(str,size,format,ap);
  25. va_end(ap);
  26. return r;
  27. }
  28. /** Replacement for vsnprintf; behavior differs as tor_snprintf differs from
  29. * snprintf.
  30. */
  31. int
  32. tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
  33. {
  34. int r;
  35. if (size == 0)
  36. return -1; /* no place for the NUL */
  37. if (size > SIZE_T_CEILING)
  38. return -1;
  39. #ifdef _WIN32
  40. r = _vsnprintf(str, size, format, args);
  41. #else
  42. r = vsnprintf(str, size, format, args);
  43. #endif
  44. str[size-1] = '\0';
  45. if (r < 0 || r >= (ssize_t)size)
  46. return -1;
  47. return r;
  48. }
  49. /**
  50. * Portable asprintf implementation. Does a printf() into a newly malloc'd
  51. * string. Sets *<b>strp</b> to this string, and returns its length (not
  52. * including the terminating NUL character).
  53. *
  54. * You can treat this function as if its implementation were something like
  55. <pre>
  56. char buf[_INFINITY_];
  57. tor_snprintf(buf, sizeof(buf), fmt, args);
  58. *strp = tor_strdup(buf);
  59. return strlen(*strp):
  60. </pre>
  61. * Where _INFINITY_ is an imaginary constant so big that any string can fit
  62. * into it.
  63. */
  64. int
  65. tor_asprintf(char **strp, const char *fmt, ...)
  66. {
  67. int r;
  68. va_list args;
  69. va_start(args, fmt);
  70. r = tor_vasprintf(strp, fmt, args);
  71. va_end(args);
  72. if (!*strp || r < 0) {
  73. /* LCOV_EXCL_START */
  74. raw_assert_unreached_msg("Internal error in asprintf");
  75. /* LCOV_EXCL_STOP */
  76. }
  77. return r;
  78. }
  79. /**
  80. * Portable vasprintf implementation. Does a printf() into a newly malloc'd
  81. * string. Differs from regular vasprintf in the same ways that
  82. * tor_asprintf() differs from regular asprintf.
  83. */
  84. int
  85. tor_vasprintf(char **strp, const char *fmt, va_list args)
  86. {
  87. /* use a temporary variable in case *strp is in args. */
  88. char *strp_tmp=NULL;
  89. #ifdef HAVE_VASPRINTF
  90. /* If the platform gives us one, use it. */
  91. int r = vasprintf(&strp_tmp, fmt, args);
  92. if (r < 0)
  93. *strp = NULL;
  94. else
  95. *strp = strp_tmp;
  96. return r;
  97. #elif defined(HAVE__VSCPRINTF)
  98. /* On Windows, _vsnprintf won't tell us the length of the string if it
  99. * overflows, so we need to use _vcsprintf to tell how much to allocate */
  100. int len, r;
  101. va_list tmp_args;
  102. va_copy(tmp_args, args);
  103. len = _vscprintf(fmt, tmp_args);
  104. va_end(tmp_args);
  105. if (len < 0) {
  106. *strp = NULL;
  107. return -1;
  108. }
  109. strp_tmp = tor_malloc(len + 1);
  110. r = _vsnprintf(strp_tmp, len+1, fmt, args);
  111. if (r != len) {
  112. tor_free(strp_tmp);
  113. *strp = NULL;
  114. return -1;
  115. }
  116. *strp = strp_tmp;
  117. return len;
  118. #else
  119. /* Everywhere else, we have a decent vsnprintf that tells us how many
  120. * characters we need. We give it a try on a short buffer first, since
  121. * it might be nice to avoid the second vsnprintf call.
  122. */
  123. char buf[128];
  124. int len, r;
  125. va_list tmp_args;
  126. va_copy(tmp_args, args);
  127. /* vsnprintf() was properly checked but tor_vsnprintf() available so
  128. * why not use it? */
  129. len = tor_vsnprintf(buf, sizeof(buf), fmt, tmp_args);
  130. va_end(tmp_args);
  131. if (len < (int)sizeof(buf)) {
  132. *strp = tor_strdup(buf);
  133. return len;
  134. }
  135. strp_tmp = tor_malloc(len+1);
  136. /* use of tor_vsnprintf() will ensure string is null terminated */
  137. r = tor_vsnprintf(strp_tmp, len+1, fmt, args);
  138. if (r != len) {
  139. tor_free(strp_tmp);
  140. *strp = NULL;
  141. return -1;
  142. }
  143. *strp = strp_tmp;
  144. return len;
  145. #endif /* defined(HAVE_VASPRINTF) || ... */
  146. }