casprintf.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #ifndef _GNU_SOURCE
  2. #define _GNU_SOURCE /* But only when HAVE_ASPRINTF */
  3. #endif
  4. #include <stdarg.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <limits.h>
  8. #include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */
  9. #include "bool.h"
  10. #include "casprintf.h"
  11. static __inline__ void
  12. newVsnprintf(char * const buffer,
  13. size_t const bufferSize,
  14. const char * const fmt,
  15. va_list varargs,
  16. size_t * const formattedSizeP) {
  17. /*----------------------------------------------------------------------------
  18. This is vsnprintf() with the new behavior, where not fitting in the buffer
  19. is not a failure.
  20. Unfortunately, we can't practically return the size of the formatted string
  21. if the C library has old vsnprintf() and the formatted string doesn't fit
  22. in the buffer, so in that case we just return something larger than the
  23. buffer.
  24. -----------------------------------------------------------------------------*/
  25. if (bufferSize > INT_MAX/2) {
  26. /* There's a danger we won't be able to coerce the return value
  27. of XMLRPC_VSNPRINTF to an integer (which we have to do because,
  28. while for POSIX its return value is ssize_t, on Windows it is int),
  29. or return double the buffer size.
  30. */
  31. *formattedSizeP = 0;
  32. } else {
  33. int rc;
  34. rc = XMLRPC_VSNPRINTF(buffer, bufferSize, fmt, varargs);
  35. if (rc < 0) {
  36. /* We have old vsnprintf() (or Windows) and the formatted value
  37. doesn't fit in the buffer, but we don't know how big a buffer it
  38. needs.
  39. */
  40. *formattedSizeP = bufferSize * 2;
  41. } else {
  42. /* Either the string fits in the buffer or we have new vsnprintf()
  43. which tells us how big the string is regardless.
  44. */
  45. *formattedSizeP = rc;
  46. }
  47. }
  48. }
  49. static __inline__ void
  50. simpleVasprintf(char ** const retvalP,
  51. const char * const fmt,
  52. va_list varargs) {
  53. /*----------------------------------------------------------------------------
  54. This is a poor man's implementation of vasprintf(), of GNU fame.
  55. -----------------------------------------------------------------------------*/
  56. char * result;
  57. size_t bufferSize;
  58. bool outOfMemory;
  59. for (result = NULL, bufferSize = 4096, outOfMemory = false;
  60. !result && !outOfMemory;
  61. ) {
  62. result = malloc(bufferSize);
  63. if (!result)
  64. outOfMemory = true;
  65. else {
  66. size_t bytesNeeded;
  67. newVsnprintf(result, bufferSize, fmt, varargs, &bytesNeeded);
  68. if (bytesNeeded > bufferSize) {
  69. free(result);
  70. result = NULL;
  71. bufferSize = bytesNeeded;
  72. }
  73. }
  74. }
  75. *retvalP = result;
  76. }
  77. const char * const strsol = "[Insufficient memory to build string]";
  78. void
  79. cvasprintf(const char ** const retvalP,
  80. const char * const fmt,
  81. va_list varargs) {
  82. char * string;
  83. #if HAVE_ASPRINTF
  84. vasprintf(&string, fmt, varargs);
  85. #else
  86. simpleVasprintf(&string, fmt, varargs);
  87. #endif
  88. if (string == NULL)
  89. *retvalP = strsol;
  90. else
  91. *retvalP = string;
  92. }
  93. void GNU_PRINTF_ATTR(2,3)
  94. casprintf(const char ** const retvalP, const char * const fmt, ...) {
  95. va_list varargs; /* mysterious structure used by variable arg facility */
  96. va_start(varargs, fmt); /* start up the mysterious variable arg facility */
  97. cvasprintf(retvalP, fmt, varargs);
  98. va_end(varargs);
  99. }
  100. void
  101. strfree(const char * const string) {
  102. if (string != strsol)
  103. free((void *)string);
  104. }