patch-fast_snprintf_c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. $OpenBSD: patch-fast_snprintf_c,v 1.1 2002/08/10 01:14:04 naddy Exp $
  2. --- fast_snprintf.c.orig Fri Aug 2 22:15:44 2002
  3. +++ fast_snprintf.c Tue Mar 6 00:49:52 2001
  4. @@ -0,0 +1,235 @@
  5. +/* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  6. + This is free software distributed under the terms of the
  7. + GNU Public License. See the file COPYING for details.
  8. +
  9. + fast_snprintf.c,v 1.12 2001/03/06 06:49:52 drscholl Exp */
  10. +
  11. +#ifdef HAVE_CONFIG_H
  12. +#include "config.h"
  13. +#endif
  14. +
  15. +#include <stdarg.h>
  16. +#include <assert.h>
  17. +#include <sys/types.h>
  18. +#include <sys/time.h>
  19. +#include <stdio.h>
  20. +
  21. +#define DIGIT(n,ui) \
  22. + if(ui>=(n)) { *out++ = '0' + (ui / (n)) % 10; if (--outsize == 0) break; }
  23. +
  24. +void fast_vsnprintf (char *out, size_t outsize, const char *fmt, va_list ap);
  25. +void fast_snprintf (char *out, size_t outsize, const char *fmt, ...);
  26. +
  27. +void
  28. +fast_vsnprintf (char *out, size_t outsize, const char *fmt, va_list ap)
  29. +{
  30. + unsigned int ui;
  31. + unsigned short us;
  32. + int i, len;
  33. + char *s;
  34. + char c;
  35. +
  36. + if (outsize == 0)
  37. + return;
  38. +
  39. + outsize--;
  40. +
  41. + while (*fmt && outsize > 0)
  42. + {
  43. + if ((c = *fmt++) != '%')
  44. + {
  45. + *out++ = c;
  46. + outsize--;
  47. + }
  48. + else
  49. + {
  50. + c = *fmt++;
  51. + if (c == 's')
  52. + {
  53. + s = va_arg (ap, char *);
  54. +
  55. + if (s == NULL)
  56. + {
  57. + if (outsize < 6)
  58. + break;
  59. + strcpy (out, "{null}");
  60. + out+=6;
  61. + outsize-=6;
  62. + }
  63. + else
  64. + while (*s && outsize > 0)
  65. + {
  66. + *out++ = *s++;
  67. + outsize--;
  68. + }
  69. + }
  70. + else if (c == 'd')
  71. + {
  72. + i = va_arg (ap, int);
  73. +
  74. + if (i == 0)
  75. + {
  76. + /* zero occurs often, so optimize for it */
  77. + *out++ = '0';
  78. + outsize--;
  79. + }
  80. + else
  81. + {
  82. + /* optimized for small ints */
  83. + if (i < 0)
  84. + {
  85. + /* handle negative numbers */
  86. + *out++ = '-';
  87. + if (--outsize == 0)
  88. + break;
  89. + i *= -1;
  90. + }
  91. + DIGIT (100000000, i);
  92. + DIGIT (10000000, i);
  93. + DIGIT (1000000, i);
  94. + DIGIT (100000, i);
  95. + DIGIT (10000, i);
  96. + DIGIT (1000, i);
  97. + DIGIT (100, i);
  98. + DIGIT (10, i);
  99. + *out++ = '0' + i % 10;
  100. + outsize--;
  101. + }
  102. + }
  103. + else if (c == 'h' && *fmt == 'u')
  104. + {
  105. + fmt++;
  106. + /* have to promote short to int */
  107. + us = (unsigned short) va_arg (ap, unsigned int);
  108. +
  109. + DIGIT (10000, us);
  110. + DIGIT (1000, us);
  111. + DIGIT (100, us);
  112. + DIGIT (10, us);
  113. + *out++ = '0' + us % 10;
  114. + outsize--;
  115. + }
  116. + /* %u . assume 10 digit number. this is typically used
  117. + * to either print a time_t or an ip address.
  118. + */
  119. + else if (c == 'u')
  120. + {
  121. + ui = va_arg (ap, unsigned int);
  122. +
  123. +#if 1
  124. + /* this appears to be faster than the other way. my guess
  125. + * is that the store of the leading 0's takes much longer
  126. + * than doing ten if() evaluations. The performance is only
  127. + * slightly better, and solves the problem of those ugly
  128. + * leading zeros
  129. + */
  130. + DIGIT (1000000000, ui);
  131. + DIGIT (100000000, ui);
  132. + DIGIT (10000000, ui);
  133. + DIGIT (1000000, ui);
  134. + DIGIT (100000, ui);
  135. + DIGIT (10000, ui);
  136. + DIGIT (1000, ui);
  137. + DIGIT (100, ui);
  138. + DIGIT (10, ui);
  139. + *out++ = '0' + ui % 10;
  140. + outsize--;
  141. +#else
  142. + if (outsize < 10)
  143. + break;
  144. + *out++ = '0' + (ui / 1000000000) % 10;
  145. + *out++ = '0' + (ui / 100000000) % 10;
  146. + *out++ = '0' + (ui / 10000000) % 10;
  147. + *out++ = '0' + (ui / 1000000) % 10;
  148. + *out++ = '0' + (ui / 100000) % 10;
  149. + *out++ = '0' + (ui / 10000) % 10;
  150. + *out++ = '0' + (ui / 1000) % 10;
  151. + *out++ = '0' + (ui / 100) % 10;
  152. + *out++ = '0' + (ui / 10) % 10;
  153. + *out++ = '0' + ui % 10;
  154. + outsize -= 10;
  155. +#endif
  156. + }
  157. + else if (c == 'c')
  158. + {
  159. + /* va_arg only takes fully promoted types, so we need
  160. + * a cast here
  161. + */
  162. + c = (char) va_arg (ap, int);
  163. +
  164. + *out++ = c;
  165. + outsize--;
  166. + }
  167. + /* %f is typically used to print an integer larger than a %u */
  168. + else if (c == 'f')
  169. + {
  170. + double f = va_arg (ap, double);
  171. +
  172. + snprintf (out, outsize, "%.0f", f);
  173. + len = strlen (out);
  174. + out += len;
  175. + outsize -= len;
  176. + }
  177. + else
  178. + assert (0); /* not supported */
  179. + }
  180. + }
  181. + *out = 0;
  182. +}
  183. +
  184. +void
  185. +fast_snprintf (char *out, size_t outsize, const char *fmt, ...)
  186. +{
  187. + va_list ap;
  188. +
  189. + va_start (ap, fmt);
  190. + fast_vsnprintf (out, outsize, fmt, ap);
  191. + va_end (ap);
  192. +}
  193. +
  194. +#if TEST
  195. +
  196. +#if 1
  197. +#define FUNC fast_snprintf
  198. +#else
  199. +#define FUNC snprintf
  200. +#endif
  201. +
  202. +int
  203. +main (int argc, char **argv)
  204. +{
  205. + char buf[1024];
  206. + char *fmt1 = "The %s brown %s jumped %s the %s dogs.";
  207. + char *fmt2 = "%d %d %d %d";
  208. + char *fmt3 = "blah blah blah";
  209. + char *fmt4 = "%u %hu";
  210. + char *fmt5 = "%d";
  211. + char *fmt6 = "%u %u %u %u";
  212. + int i;
  213. + struct timeval s, e;
  214. + char small[16];
  215. +
  216. + memset(small,0xff,sizeof(small));
  217. + fast_snprintf(small,sizeof(small)-1,"this is a very long string");
  218. + memset(small,0xff,sizeof(small));
  219. + fast_snprintf(small,sizeof(small)-1,"this is a ver%d", 123456);
  220. + memset(small,0xff,sizeof(small));
  221. + fast_snprintf(small,sizeof(small)-1,"this is a ver%s", "blah blah blah");
  222. +
  223. + gettimeofday (&s, 0);
  224. + for (i = 0; i < 10000; i++)
  225. + {
  226. + //FUNC (buf, sizeof (buf), fmt1, "quick", "fox", "over", "lazy");
  227. + //FUNC (buf, sizeof (buf), fmt2, 1, 11, 111, 1111);
  228. + //FUNC (buf, sizeof (buf), fmt3);
  229. + //FUNC (buf, sizeof (buf), fmt4, 0x7fffffff, 0xffff);
  230. + //FUNC (buf, sizeof (buf), fmt5, -10134);
  231. + FUNC(buf,sizeof(buf),fmt6,0x7fffffff,0x0fffffff,0x00ffffff,0x000fffff);
  232. + puts(buf);
  233. + }
  234. + gettimeofday (&e, 0);
  235. +
  236. + printf ("%d\n",
  237. + (e.tv_sec - s.tv_sec) * 1000000 + (e.tv_usec - s.tv_usec));
  238. +}
  239. +#endif