vsnprintf.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
  2. *
  3. * GNU Library General Public License (LGPL) version 2 or later.
  4. *
  5. * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
  6. */
  7. #include "_stdio.h"
  8. #include <stdarg.h>
  9. /* libc_hidden_proto(vsnprintf) */
  10. #ifdef __USE_OLD_VFPRINTF__
  11. /* libc_hidden_proto(vfprintf) */
  12. #endif
  13. #ifdef __UCLIBC_MJN3_ONLY__
  14. #warning WISHLIST: Implement vsnprintf for non-buffered and no custom stream case.
  15. #endif /* __UCLIBC_MJN3_ONLY__ */
  16. #ifdef __STDIO_BUFFERS
  17. /* NB: we can still have __USE_OLD_VFPRINTF__ defined in this case! */
  18. int vsnprintf(char *__restrict buf, size_t size,
  19. const char * __restrict format, va_list arg)
  20. {
  21. FILE f;
  22. int rv;
  23. /* __STDIO_STREAM_RESET_GCS(&f); */
  24. #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
  25. f.__cookie = &(f.__filedes);
  26. f.__gcs.read = NULL;
  27. f.__gcs.write = NULL;
  28. f.__gcs.seek = NULL;
  29. f.__gcs.close = NULL;
  30. #endif
  31. f.__filedes = __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES;
  32. f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
  33. #ifdef __UCLIBC_HAS_WCHAR__
  34. f.__ungot_width[0] = 0;
  35. #endif /* __UCLIBC_HAS_WCHAR__ */
  36. #ifdef __STDIO_MBSTATE
  37. __INIT_MBSTATE(&(f.__state));
  38. #endif /* __STDIO_MBSTATE */
  39. #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__)
  40. f.__user_locking = 1; /* Set user locking. */
  41. __stdio_init_mutex(&f.__lock);
  42. #endif
  43. f.__nextopen = NULL;
  44. if (size > SIZE_MAX - (size_t) buf) {
  45. size = SIZE_MAX - (size_t) buf;
  46. }
  47. /* TODO: this comment seems to be wrong */
  48. /* Set these last since __bufputc initialization depends on
  49. * __user_locking and only gets set if user locking is on. */
  50. f.__bufstart = (unsigned char *) buf;
  51. f.__bufend = (unsigned char *) buf + size;
  52. __STDIO_STREAM_INIT_BUFREAD_BUFPOS(&f);
  53. __STDIO_STREAM_DISABLE_GETC(&f);
  54. __STDIO_STREAM_ENABLE_PUTC(&f);
  55. #ifdef __USE_OLD_VFPRINTF__
  56. rv = vfprintf(&f, format, arg);
  57. #else
  58. rv = _vfprintf_internal(&f, format, arg);
  59. #endif
  60. if (size) {
  61. if (f.__bufpos == f.__bufend) {
  62. --f.__bufpos;
  63. }
  64. *f.__bufpos = 0;
  65. }
  66. return rv;
  67. }
  68. libc_hidden_def(vsnprintf)
  69. #elif defined(__USE_OLD_VFPRINTF__)
  70. typedef struct {
  71. FILE f;
  72. unsigned char *bufend; /* pointer to 1 past end of buffer */
  73. unsigned char *bufpos;
  74. } __FILE_vsnprintf;
  75. int vsnprintf(char *__restrict buf, size_t size,
  76. const char * __restrict format, va_list arg)
  77. {
  78. __FILE_vsnprintf f;
  79. int rv;
  80. f.bufpos = buf;
  81. if (size > SIZE_MAX - (size_t) buf) {
  82. size = SIZE_MAX - (size_t) buf;
  83. }
  84. f.bufend = buf + size;
  85. /* __STDIO_STREAM_RESET_GCS(&f.f); */
  86. #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
  87. f.f.__cookie = &(f.f.__filedes);
  88. f.f.__gcs.read = NULL;
  89. f.f.__gcs.write = NULL;
  90. f.f.__gcs.seek = NULL;
  91. f.f.__gcs.close = NULL;
  92. #endif
  93. f.f.__filedes = __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES_NB;
  94. f.f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
  95. #ifdef __UCLIBC_HAS_WCHAR__
  96. f.f.__ungot_width[0] = 0;
  97. #endif /* __UCLIBC_HAS_WCHAR__ */
  98. #ifdef __STDIO_MBSTATE
  99. __INIT_MBSTATE(&(f.f.__state));
  100. #endif /* __STDIO_MBSTATE */
  101. #ifdef __UCLIBC_HAS_THREADS__
  102. f.f.__user_locking = 1; /* Set user locking. */
  103. __stdio_init_mutex(&f.f.__lock);
  104. #endif
  105. f.f.__nextopen = NULL;
  106. rv = vfprintf((FILE *) &f, format, arg);
  107. if (size) {
  108. if (f.bufpos == f.bufend) {
  109. --f.bufpos;
  110. }
  111. *f.bufpos = 0;
  112. }
  113. return rv;
  114. }
  115. libc_hidden_def(vsnprintf)
  116. #elif defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
  117. typedef struct {
  118. size_t pos;
  119. size_t len;
  120. unsigned char *buf;
  121. FILE *fp;
  122. } __snpf_cookie;
  123. #define COOKIE ((__snpf_cookie *) cookie)
  124. static ssize_t snpf_write(register void *cookie, const char *buf,
  125. size_t bufsize)
  126. {
  127. size_t count;
  128. register char *p;
  129. /* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
  130. if (COOKIE->len > COOKIE->pos) {
  131. count = COOKIE->len - COOKIE->pos - 1; /* Leave space for nul. */
  132. if (count > bufsize) {
  133. count = bufsize;
  134. }
  135. p = COOKIE->buf + COOKIE->pos;
  136. while (count) {
  137. *p++ = *buf++;
  138. --count;
  139. }
  140. *p = 0;
  141. }
  142. COOKIE->pos += bufsize;
  143. return bufsize;
  144. }
  145. #undef COOKIE
  146. int vsnprintf(char *__restrict buf, size_t size,
  147. const char * __restrict format, va_list arg)
  148. {
  149. FILE f;
  150. __snpf_cookie cookie;
  151. int rv;
  152. cookie.buf = buf;
  153. cookie.len = size;
  154. cookie.pos = 0;
  155. cookie.fp = &f;
  156. f.__cookie = &cookie;
  157. f.__gcs.write = snpf_write;
  158. f.__gcs.read = NULL;
  159. f.__gcs.seek = NULL;
  160. f.__gcs.close = NULL;
  161. f.__filedes = -1; /* For debugging. */
  162. f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
  163. #ifdef __UCLIBC_HAS_WCHAR__
  164. f.__ungot_width[0] = 0;
  165. #endif /* __UCLIBC_HAS_WCHAR__ */
  166. #ifdef __STDIO_MBSTATE
  167. __INIT_MBSTATE(&(f.__state));
  168. #endif /* __STDIO_MBSTATE */
  169. f.__nextopen = NULL;
  170. rv = _vfprintf_internal(&f, format, arg);
  171. return rv;
  172. }
  173. libc_hidden_def(vsnprintf)
  174. #else
  175. #warning Skipping vsnprintf since no buffering, no custom streams, and not old vfprintf!
  176. #ifdef __STDIO_HAS_VSNPRINTF
  177. #error WHOA! __STDIO_HAS_VSNPRINTF is defined!
  178. #endif
  179. #endif