asprintf.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #define _XOPEN_SOURCE 600 /* Make sure strdup() is in <string.h> */
  2. #ifdef __APPLE__
  3. #define _DARWIN_C_SOURCE
  4. #endif
  5. #ifndef _GNU_SOURCE
  6. #define _GNU_SOURCE /* But only when HAVE_ASPRINTF */
  7. #endif
  8. #include <stdarg.h>
  9. #include <stdarg.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <limits.h>
  13. #include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */
  14. #include "xmlrpc-c/string_int.h"
  15. #include "bool.h"
  16. static __inline__ void
  17. newVsnprintf(char * const buffer,
  18. size_t const bufferSize,
  19. const char * const fmt,
  20. va_list varargs,
  21. size_t * const formattedSizeP) {
  22. /*----------------------------------------------------------------------------
  23. This is vsnprintf() with the new behavior, where not fitting in the buffer
  24. is not a failure.
  25. Unfortunately, we can't practically return the size of the formatted string
  26. if the C library has old vsnprintf() and the formatted string doesn't fit
  27. in the buffer, so in that case we just return something larger than the
  28. buffer.
  29. -----------------------------------------------------------------------------*/
  30. if (bufferSize > INT_MAX/2) {
  31. /* There's a danger we won't be able to coerce the return value
  32. of XMLRPC_VSNPRINTF to an integer (which we have to do because,
  33. while for POSIX its return value is ssize_t, on Windows it is int),
  34. or return double the buffer size.
  35. */
  36. *formattedSizeP = 0;
  37. } else {
  38. int rc;
  39. rc = XMLRPC_VSNPRINTF(buffer, bufferSize, fmt, varargs);
  40. if (rc < 0) {
  41. /* We have old vsnprintf() (or Windows) and the formatted value
  42. doesn't fit in the buffer, but we don't know how big a buffer it
  43. needs.
  44. */
  45. *formattedSizeP = bufferSize * 2;
  46. } else {
  47. /* Either the string fits in the buffer or we have new vsnprintf()
  48. which tells us how big the string is regardless.
  49. */
  50. *formattedSizeP = rc;
  51. }
  52. }
  53. }
  54. static __inline__ void
  55. simpleVasprintf(char ** const retvalP,
  56. const char * const fmt,
  57. va_list varargs) {
  58. /*----------------------------------------------------------------------------
  59. This is a poor man's implementation of vasprintf(), of GNU fame.
  60. -----------------------------------------------------------------------------*/
  61. char * result;
  62. size_t bufferSize;
  63. bool outOfMemory;
  64. for (result = NULL, bufferSize = 4096, outOfMemory = false;
  65. !result && !outOfMemory;
  66. ) {
  67. result = malloc(bufferSize);
  68. if (!result)
  69. outOfMemory = true;
  70. else {
  71. size_t bytesNeeded;
  72. newVsnprintf(result, bufferSize, fmt, varargs, &bytesNeeded);
  73. if (bytesNeeded > bufferSize) {
  74. free(result);
  75. result = NULL;
  76. bufferSize = bytesNeeded;
  77. }
  78. }
  79. }
  80. *retvalP = result;
  81. }
  82. static const char * const xmlrpc_strsol =
  83. "[insufficient memory to build string]";
  84. bool
  85. xmlrpc_strnomem(const char * const string) {
  86. /*----------------------------------------------------------------------------
  87. The string 'string' was generated by a function in this file because it
  88. couldn't get enough memory to generate the string that it was supposed to
  89. generate. I.e. a preceding call to a string function failed.
  90. -----------------------------------------------------------------------------*/
  91. return string == xmlrpc_strsol;
  92. }
  93. const char *
  94. xmlrpc_strnomemval() {
  95. return xmlrpc_strsol;
  96. }
  97. void
  98. xmlrpc_vasprintf(const char ** const retvalP,
  99. const char * const fmt,
  100. va_list varargs) {
  101. char * string;
  102. #if HAVE_ASPRINTF
  103. vasprintf(&string, fmt, varargs);
  104. #else
  105. simpleVasprintf(&string, fmt, varargs);
  106. #endif
  107. if (string == NULL)
  108. *retvalP = xmlrpc_strsol;
  109. else
  110. *retvalP = string;
  111. }
  112. void XMLRPC_PRINTF_ATTR(2,3)
  113. xmlrpc_asprintf(const char ** const retvalP, const char * const fmt, ...) {
  114. va_list varargs; /* mysterious structure used by variable arg facility */
  115. va_start(varargs, fmt); /* start up the mysterious variable arg facility */
  116. xmlrpc_vasprintf(retvalP, fmt, varargs);
  117. va_end(varargs);
  118. }
  119. const char *
  120. xmlrpc_strdupsol(const char * const string) {
  121. const char * retvalOrNull;
  122. retvalOrNull = strdup(string);
  123. return retvalOrNull ? retvalOrNull : xmlrpc_strsol;
  124. }
  125. void
  126. xmlrpc_strfree(const char * const string) {
  127. if (string != xmlrpc_strsol)
  128. free((void *)string);
  129. }
  130. const char *
  131. xmlrpc_strdupnull(const char * const string) {
  132. if (string)
  133. return strdup(string);
  134. else
  135. return NULL;
  136. }
  137. void
  138. xmlrpc_strfreenull(const char * const string) {
  139. if (string)
  140. xmlrpc_strfree(string);
  141. }