vsnprintf.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * "$Id: vsnprintf.c 9325 2012-04-05 05:12:30Z fabien $"
  3. *
  4. * snprintf() and vsnprintf() functions for the Fast Light Tool Kit (FLTK).
  5. *
  6. * Copyright 1998-2010 by Bill Spitzak and others.
  7. *
  8. * This library is free software. Distribution and use rights are outlined in
  9. * the file "COPYING" which should have been included with this file. If this
  10. * file is missing or damaged, see the license at:
  11. *
  12. * http://www.fltk.org/COPYING.php
  13. *
  14. * Please report all bugs and problems on the following page:
  15. *
  16. * http://www.fltk.org/str.php
  17. */
  18. #include <stdio.h>
  19. #include "flstring.h"
  20. #ifdef HAVE_SYS_STDTYPES_H
  21. # include <sys/stdtypes.h>
  22. #endif /* HAVE_SYS_STDTYPES_H */
  23. #ifdef __cplusplus
  24. extern "C" {
  25. #endif
  26. int fl_vsnprintf(char* buffer, size_t bufsize, const char* format, va_list ap) {
  27. char *bufptr, /* Pointer to position in buffer */
  28. *bufend, /* Pointer to end of buffer */
  29. sign, /* Sign of format width */
  30. size, /* Size character (h, l, L) */
  31. type; /* Format type character */
  32. int width, /* Width of field */
  33. prec; /* Number of characters of precision */
  34. char tformat[100], /* Temporary format string for sprintf() */
  35. *tptr, /* Pointer into temporary format */
  36. temp[1024]; /* Buffer for formatted numbers */
  37. char *s; /* Pointer to string */
  38. int slen; /* Length of string */
  39. int bytes; /* Total number of bytes needed */
  40. /*
  41. * Loop through the format string, formatting as needed...
  42. */
  43. bufptr = buffer;
  44. bufend = buffer + bufsize - 1;
  45. bytes = 0;
  46. while (*format) {
  47. if (*format == '%') {
  48. tptr = tformat;
  49. *tptr++ = *format++;
  50. if (*format == '%') {
  51. if (bufptr && bufptr < bufend) *bufptr++ = *format;
  52. bytes ++;
  53. format ++;
  54. continue;
  55. } else if (strchr(" -+#\'", *format)) {
  56. *tptr++ = *format;
  57. sign = *format++;
  58. } else sign = 0;
  59. if (*format == '*') {
  60. /* Get width from argument... */
  61. format ++;
  62. width = va_arg(ap, int);
  63. snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
  64. tptr += strlen(tptr);
  65. } else {
  66. width = 0;
  67. while (isdigit(*format & 255)) {
  68. if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
  69. width = width * 10 + *format++ - '0';
  70. }
  71. }
  72. if (*format == '.') {
  73. if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
  74. format ++;
  75. if (*format == '*') {
  76. /* Get precision from argument... */
  77. format ++;
  78. prec = va_arg(ap, int);
  79. snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
  80. tptr += strlen(tptr);
  81. } else {
  82. prec = 0;
  83. while (isdigit(*format & 255)) {
  84. if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
  85. prec = prec * 10 + *format++ - '0';
  86. }
  87. }
  88. } else prec = -1;
  89. size = '\0';
  90. if (*format == 'l' && format[1] == 'l') {
  91. size = 'L';
  92. if (tptr < (tformat + sizeof(tformat) - 2)) {
  93. *tptr++ = 'l';
  94. *tptr++ = 'l';
  95. }
  96. format += 2;
  97. } else if (*format == 'h' || *format == 'l' || *format == 'L') {
  98. if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
  99. size = *format++;
  100. }
  101. if (!*format) break;
  102. if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
  103. type = *format++;
  104. *tptr = '\0';
  105. switch (type) {
  106. case 'E' : /* Floating point formats */
  107. case 'G' :
  108. case 'e' :
  109. case 'f' :
  110. case 'g' :
  111. if ((width + 2) > sizeof(temp)) break;
  112. sprintf(temp, tformat, va_arg(ap, double));
  113. bytes += (int) strlen(temp);
  114. if (bufptr) {
  115. if ((bufptr + strlen(temp)) > bufend) {
  116. strncpy(bufptr, temp, (size_t)(bufend - bufptr));
  117. bufptr = bufend;
  118. } else {
  119. strcpy(bufptr, temp);
  120. bufptr += strlen(temp);
  121. }
  122. }
  123. break;
  124. case 'B' : /* Integer formats */
  125. case 'X' :
  126. case 'b' :
  127. case 'd' :
  128. case 'i' :
  129. case 'o' :
  130. case 'u' :
  131. case 'x' :
  132. if ((width + 2) > sizeof(temp)) break;
  133. #ifdef HAVE_LONG_LONG
  134. if (size == 'L')
  135. sprintf(temp, tformat, va_arg(ap, long long));
  136. else
  137. #endif /* HAVE_LONG_LONG */
  138. if (size == 'l')
  139. sprintf(temp, tformat, va_arg(ap, long));
  140. else
  141. sprintf(temp, tformat, va_arg(ap, int));
  142. bytes += (int) strlen(temp);
  143. if (bufptr) {
  144. if ((bufptr + strlen(temp)) > bufend) {
  145. strncpy(bufptr, temp, (size_t)(bufend - bufptr));
  146. bufptr = bufend;
  147. } else {
  148. strcpy(bufptr, temp);
  149. bufptr += strlen(temp);
  150. }
  151. }
  152. break;
  153. case 'p' : /* Pointer value */
  154. if ((width + 2) > sizeof(temp)) break;
  155. sprintf(temp, tformat, va_arg(ap, void *));
  156. bytes += (int) strlen(temp);
  157. if (bufptr) {
  158. if ((bufptr + strlen(temp)) > bufend) {
  159. strncpy(bufptr, temp, (size_t)(bufend - bufptr));
  160. bufptr = bufend;
  161. } else {
  162. strcpy(bufptr, temp);
  163. bufptr += strlen(temp);
  164. }
  165. }
  166. break;
  167. case 'c' : /* Character or character array */
  168. bytes += width;
  169. if (bufptr) {
  170. if (width <= 1) *bufptr++ = va_arg(ap, int);
  171. else {
  172. if ((bufptr + width) > bufend) width = (int) (bufend - bufptr);
  173. memcpy(bufptr, va_arg(ap, char *), (size_t)width);
  174. bufptr += width;
  175. }
  176. }
  177. break;
  178. case 's' : /* String */
  179. if ((s = va_arg(ap, char *)) == NULL) s = "(null)";
  180. slen = (int) strlen(s);
  181. if (slen > width && prec != width) width = slen;
  182. bytes += width;
  183. if (bufptr) {
  184. if ((bufptr + width) > bufend) width = (int) (bufend - bufptr);
  185. if (slen > width) slen = width;
  186. if (sign == '-') {
  187. strncpy(bufptr, s, (size_t)slen);
  188. memset(bufptr + slen, ' ', (size_t)(width - slen));
  189. } else {
  190. memset(bufptr, ' ', (size_t)(width - slen));
  191. strncpy(bufptr + width - slen, s, (size_t)slen);
  192. }
  193. bufptr += width;
  194. }
  195. break;
  196. case 'n' : /* Output number of chars so far */
  197. *(va_arg(ap, int *)) = bytes;
  198. break;
  199. }
  200. } else {
  201. bytes ++;
  202. if (bufptr && bufptr < bufend) *bufptr++ = *format;
  203. format ++;
  204. }
  205. }
  206. /*
  207. * Nul-terminate the string and return the number of characters needed.
  208. */
  209. if (bufptr) *bufptr = '\0';
  210. return (bytes);
  211. }
  212. int fl_snprintf(char* str, size_t size, const char* fmt, ...) {
  213. int ret;
  214. va_list ap;
  215. va_start(ap, fmt);
  216. ret = vsnprintf(str, size, fmt, ap);
  217. va_end(ap);
  218. return ret;
  219. }
  220. #ifdef __cplusplus
  221. }
  222. #endif
  223. /*
  224. * End of "$Id: vsnprintf.c 9325 2012-04-05 05:12:30Z fabien $".
  225. */