vsnprintf.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. #ifdef __STDIO_BUFFERS
  10. /* NB: we can still have __USE_OLD_VFPRINTF__ defined in this case! */
  11. int vsnprintf(char *__restrict buf, size_t size,
  12. const char * __restrict format, va_list arg)
  13. {
  14. FILE f;
  15. int rv;
  16. f.__filedes = __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES;
  17. f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
  18. #ifdef __UCLIBC_HAS_WCHAR__
  19. f.__ungot_width[0] = 0;
  20. #endif /* __UCLIBC_HAS_WCHAR__ */
  21. #ifdef __STDIO_MBSTATE
  22. __INIT_MBSTATE(&(f.__state));
  23. #endif /* __STDIO_MBSTATE */
  24. #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__)
  25. f.__user_locking = 1; /* Set user locking. */
  26. STDIO_INIT_MUTEX(f.__lock);
  27. #endif
  28. f.__nextopen = NULL;
  29. if (size > SIZE_MAX - (size_t) buf) {
  30. size = SIZE_MAX - (size_t) buf;
  31. }
  32. /* TODO: this comment seems to be wrong */
  33. /* Set these last since __bufputc initialization depends on
  34. * __user_locking and only gets set if user locking is on. */
  35. f.__bufstart = (unsigned char *) buf;
  36. f.__bufend = (unsigned char *) buf + size;
  37. __STDIO_STREAM_INIT_BUFREAD_BUFPOS(&f);
  38. __STDIO_STREAM_DISABLE_GETC(&f);
  39. __STDIO_STREAM_ENABLE_PUTC(&f);
  40. #ifdef __USE_OLD_VFPRINTF__
  41. rv = vfprintf(&f, format, arg);
  42. #else
  43. rv = _vfprintf_internal(&f, format, arg);
  44. #endif
  45. if (size) {
  46. if (f.__bufpos == f.__bufend) {
  47. --f.__bufpos;
  48. }
  49. *f.__bufpos = 0;
  50. }
  51. return rv;
  52. }
  53. libc_hidden_def(vsnprintf)
  54. #elif defined(__USE_OLD_VFPRINTF__)
  55. typedef struct {
  56. FILE f;
  57. unsigned char *bufend; /* pointer to 1 past end of buffer */
  58. unsigned char *bufpos;
  59. } __FILE_vsnprintf;
  60. int vsnprintf(char *__restrict buf, size_t size,
  61. const char * __restrict format, va_list arg)
  62. {
  63. __FILE_vsnprintf f;
  64. int rv;
  65. f.bufpos = buf;
  66. if (size > SIZE_MAX - (size_t) buf) {
  67. size = SIZE_MAX - (size_t) buf;
  68. }
  69. f.bufend = buf + size;
  70. f.f.__filedes = __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES_NB;
  71. f.f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
  72. #ifdef __UCLIBC_HAS_WCHAR__
  73. f.f.__ungot_width[0] = 0;
  74. #endif /* __UCLIBC_HAS_WCHAR__ */
  75. #ifdef __STDIO_MBSTATE
  76. __INIT_MBSTATE(&(f.f.__state));
  77. #endif /* __STDIO_MBSTATE */
  78. #ifdef __UCLIBC_HAS_THREADS__
  79. f.f.__user_locking = 1; /* Set user locking. */
  80. STDIO_INIT_MUTEX(f.f.__lock);
  81. #endif
  82. f.f.__nextopen = NULL;
  83. rv = vfprintf((FILE *) &f, format, arg);
  84. if (size) {
  85. if (f.bufpos == f.bufend) {
  86. --f.bufpos;
  87. }
  88. *f.bufpos = 0;
  89. }
  90. return rv;
  91. }
  92. libc_hidden_def(vsnprintf)
  93. #elif defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
  94. typedef struct {
  95. size_t pos;
  96. size_t len;
  97. char *buf;
  98. FILE *fp;
  99. } __snpf_cookie;
  100. #define COOKIE ((__snpf_cookie *) cookie)
  101. static ssize_t snpf_write(register void *cookie, const char *buf,
  102. size_t bufsize)
  103. {
  104. size_t count;
  105. register char *p;
  106. /* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
  107. if (COOKIE->len > COOKIE->pos) {
  108. count = COOKIE->len - COOKIE->pos - 1; /* Leave space for nul. */
  109. if (count > bufsize) {
  110. count = bufsize;
  111. }
  112. p = COOKIE->buf + COOKIE->pos;
  113. while (count) {
  114. *p++ = *buf++;
  115. --count;
  116. }
  117. *p = 0;
  118. }
  119. COOKIE->pos += bufsize;
  120. return bufsize;
  121. }
  122. #undef COOKIE
  123. int vsnprintf(char *__restrict buf, size_t size,
  124. const char * __restrict format, va_list arg)
  125. {
  126. _IO_cookie_file_t cf;
  127. __snpf_cookie cookie;
  128. int rv;
  129. cookie.buf = buf;
  130. cookie.len = size;
  131. cookie.pos = 0;
  132. cookie.fp = &cf.__fp;
  133. cf.__cookie = &cookie;
  134. cf.__gcs.write = snpf_write;
  135. cf.__gcs.read = NULL;
  136. cf.__gcs.seek = NULL;
  137. cf.__gcs.close = NULL;
  138. cf.__fp.__filedes = __STDIO_STREAM_GLIBC_CUSTOM_FILEDES;
  139. cf.__fp.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
  140. #ifdef __UCLIBC_HAS_WCHAR__
  141. cf.__fp.__ungot_width[0] = 0;
  142. #endif /* __UCLIBC_HAS_WCHAR__ */
  143. #ifdef __STDIO_MBSTATE
  144. __INIT_MBSTATE(&(cf.__fp.__state));
  145. #endif /* __STDIO_MBSTATE */
  146. cf.__fp.__nextopen = NULL;
  147. rv = _vfprintf_internal(&cf.__fp, format, arg);
  148. return rv;
  149. }
  150. libc_hidden_def(vsnprintf)
  151. #else
  152. #warning Skipping vsnprintf since no buffering, no custom streams, and not old vfprintf!
  153. #ifdef __STDIO_HAS_VSNPRINTF
  154. #error WHOA! __STDIO_HAS_VSNPRINTF is defined!
  155. #endif
  156. #endif