123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- $OpenBSD: patch-fast_snprintf_c,v 1.1 2002/08/10 01:14:04 naddy Exp $
- --- fast_snprintf.c.orig Fri Aug 2 22:15:44 2002
- +++ fast_snprintf.c Tue Mar 6 00:49:52 2001
- @@ -0,0 +1,235 @@
- +/* Copyright (C) 2000-1 drscholl@users.sourceforge.net
- + This is free software distributed under the terms of the
- + GNU Public License. See the file COPYING for details.
- +
- + fast_snprintf.c,v 1.12 2001/03/06 06:49:52 drscholl Exp */
- +
- +#ifdef HAVE_CONFIG_H
- +#include "config.h"
- +#endif
- +
- +#include <stdarg.h>
- +#include <assert.h>
- +#include <sys/types.h>
- +#include <sys/time.h>
- +#include <stdio.h>
- +
- +#define DIGIT(n,ui) \
- + if(ui>=(n)) { *out++ = '0' + (ui / (n)) % 10; if (--outsize == 0) break; }
- +
- +void fast_vsnprintf (char *out, size_t outsize, const char *fmt, va_list ap);
- +void fast_snprintf (char *out, size_t outsize, const char *fmt, ...);
- +
- +void
- +fast_vsnprintf (char *out, size_t outsize, const char *fmt, va_list ap)
- +{
- + unsigned int ui;
- + unsigned short us;
- + int i, len;
- + char *s;
- + char c;
- +
- + if (outsize == 0)
- + return;
- +
- + outsize--;
- +
- + while (*fmt && outsize > 0)
- + {
- + if ((c = *fmt++) != '%')
- + {
- + *out++ = c;
- + outsize--;
- + }
- + else
- + {
- + c = *fmt++;
- + if (c == 's')
- + {
- + s = va_arg (ap, char *);
- +
- + if (s == NULL)
- + {
- + if (outsize < 6)
- + break;
- + strcpy (out, "{null}");
- + out+=6;
- + outsize-=6;
- + }
- + else
- + while (*s && outsize > 0)
- + {
- + *out++ = *s++;
- + outsize--;
- + }
- + }
- + else if (c == 'd')
- + {
- + i = va_arg (ap, int);
- +
- + if (i == 0)
- + {
- + /* zero occurs often, so optimize for it */
- + *out++ = '0';
- + outsize--;
- + }
- + else
- + {
- + /* optimized for small ints */
- + if (i < 0)
- + {
- + /* handle negative numbers */
- + *out++ = '-';
- + if (--outsize == 0)
- + break;
- + i *= -1;
- + }
- + DIGIT (100000000, i);
- + DIGIT (10000000, i);
- + DIGIT (1000000, i);
- + DIGIT (100000, i);
- + DIGIT (10000, i);
- + DIGIT (1000, i);
- + DIGIT (100, i);
- + DIGIT (10, i);
- + *out++ = '0' + i % 10;
- + outsize--;
- + }
- + }
- + else if (c == 'h' && *fmt == 'u')
- + {
- + fmt++;
- + /* have to promote short to int */
- + us = (unsigned short) va_arg (ap, unsigned int);
- +
- + DIGIT (10000, us);
- + DIGIT (1000, us);
- + DIGIT (100, us);
- + DIGIT (10, us);
- + *out++ = '0' + us % 10;
- + outsize--;
- + }
- + /* %u . assume 10 digit number. this is typically used
- + * to either print a time_t or an ip address.
- + */
- + else if (c == 'u')
- + {
- + ui = va_arg (ap, unsigned int);
- +
- +#if 1
- + /* this appears to be faster than the other way. my guess
- + * is that the store of the leading 0's takes much longer
- + * than doing ten if() evaluations. The performance is only
- + * slightly better, and solves the problem of those ugly
- + * leading zeros
- + */
- + DIGIT (1000000000, ui);
- + DIGIT (100000000, ui);
- + DIGIT (10000000, ui);
- + DIGIT (1000000, ui);
- + DIGIT (100000, ui);
- + DIGIT (10000, ui);
- + DIGIT (1000, ui);
- + DIGIT (100, ui);
- + DIGIT (10, ui);
- + *out++ = '0' + ui % 10;
- + outsize--;
- +#else
- + if (outsize < 10)
- + break;
- + *out++ = '0' + (ui / 1000000000) % 10;
- + *out++ = '0' + (ui / 100000000) % 10;
- + *out++ = '0' + (ui / 10000000) % 10;
- + *out++ = '0' + (ui / 1000000) % 10;
- + *out++ = '0' + (ui / 100000) % 10;
- + *out++ = '0' + (ui / 10000) % 10;
- + *out++ = '0' + (ui / 1000) % 10;
- + *out++ = '0' + (ui / 100) % 10;
- + *out++ = '0' + (ui / 10) % 10;
- + *out++ = '0' + ui % 10;
- + outsize -= 10;
- +#endif
- + }
- + else if (c == 'c')
- + {
- + /* va_arg only takes fully promoted types, so we need
- + * a cast here
- + */
- + c = (char) va_arg (ap, int);
- +
- + *out++ = c;
- + outsize--;
- + }
- + /* %f is typically used to print an integer larger than a %u */
- + else if (c == 'f')
- + {
- + double f = va_arg (ap, double);
- +
- + snprintf (out, outsize, "%.0f", f);
- + len = strlen (out);
- + out += len;
- + outsize -= len;
- + }
- + else
- + assert (0); /* not supported */
- + }
- + }
- + *out = 0;
- +}
- +
- +void
- +fast_snprintf (char *out, size_t outsize, const char *fmt, ...)
- +{
- + va_list ap;
- +
- + va_start (ap, fmt);
- + fast_vsnprintf (out, outsize, fmt, ap);
- + va_end (ap);
- +}
- +
- +#if TEST
- +
- +#if 1
- +#define FUNC fast_snprintf
- +#else
- +#define FUNC snprintf
- +#endif
- +
- +int
- +main (int argc, char **argv)
- +{
- + char buf[1024];
- + char *fmt1 = "The %s brown %s jumped %s the %s dogs.";
- + char *fmt2 = "%d %d %d %d";
- + char *fmt3 = "blah blah blah";
- + char *fmt4 = "%u %hu";
- + char *fmt5 = "%d";
- + char *fmt6 = "%u %u %u %u";
- + int i;
- + struct timeval s, e;
- + char small[16];
- +
- + memset(small,0xff,sizeof(small));
- + fast_snprintf(small,sizeof(small)-1,"this is a very long string");
- + memset(small,0xff,sizeof(small));
- + fast_snprintf(small,sizeof(small)-1,"this is a ver%d", 123456);
- + memset(small,0xff,sizeof(small));
- + fast_snprintf(small,sizeof(small)-1,"this is a ver%s", "blah blah blah");
- +
- + gettimeofday (&s, 0);
- + for (i = 0; i < 10000; i++)
- + {
- + //FUNC (buf, sizeof (buf), fmt1, "quick", "fox", "over", "lazy");
- + //FUNC (buf, sizeof (buf), fmt2, 1, 11, 111, 1111);
- + //FUNC (buf, sizeof (buf), fmt3);
- + //FUNC (buf, sizeof (buf), fmt4, 0x7fffffff, 0xffff);
- + //FUNC (buf, sizeof (buf), fmt5, -10134);
- + FUNC(buf,sizeof(buf),fmt6,0x7fffffff,0x0fffffff,0x00ffffff,0x000fffff);
- + puts(buf);
- + }
- + gettimeofday (&e, 0);
- +
- + printf ("%d\n",
- + (e.tv_sec - s.tv_sec) * 1000000 + (e.tv_usec - s.tv_usec));
- +}
- +#endif
|