#include <ctype.h>
#include <string.h>
#include <stdint.h>
+#include <math.h>
#include "kstring.h"
int ksprintf(kstring_t *s, const char *fmt, ...)
* fast sprintf *
****************/
+typedef struct {
+ int base, width, fill, left_aln, n_ell, n_Ell;
+} printf_conv_t;
+
static inline void enlarge(kstring_t *s, int l)
{
if (s->l + l + 1 >= s->m) {
}
}
-static int get_base(int c)
-{
- if (c == 'o') return 8;
- if (c == 'x') return 16;
- return 10;
-}
-
int ksprintf_fast(kstring_t *s, const char *fmt, ...)
{
-#define write_integer(_ap, _s, _type, _base) do { \
+#define write_integer0(_c, _s, _type, _z, _conv) do { \
+ char buf[32]; \
+ int l = 0, k, w, f; \
+ _type x; \
+ if (_c != 0) { \
+ for (x = _c < 0? -_c : _c; x > 0; x /= _z.base) buf[l++] = _conv[x%_z.base]; \
+ if (_c < 0) buf[l++] = '-'; \
+ } else buf[l++] = '0'; \
+ f = l > _z.fill? l : _z.fill; \
+ w = f > _z.width? f : _z.width; \
+ enlarge(_s, w); \
+ if (w > f && !_z.left_aln) \
+ for (k = f; k < w; ++k) _s->s[_s->l++] = ' '; \
+ if (f > l) \
+ for (k = l; k < f; ++k) _s->s[_s->l++] = '0'; \
+ for (k = l - 1; k >= 0; --k) _s->s[_s->l++] = buf[k]; \
+ if (w > f && _z.left_aln) \
+ for (k = f; k < w; ++k) _s->s[_s->l++] = ' '; \
+ } while (0)
+
+#define write_integer(_ap, _s, _type, _z, _conv) do { \
_type c = va_arg(_ap, _type); \
- if (c == 0) { \
- enlarge(_s, 1); \
- _s->s[_s->l++] = '0'; \
- _s->s[_s->l] = 0; \
- } else { \
- char buf[32]; \
- int l, ll; \
- _type x; \
- for (l = 0, x = c < 0? -c : c; x > 0; x /= _base) buf[l++] = "0123456789abcdef"[x%_base]; \
- if (c < 0) buf[l++] = '-'; \
- enlarge(_s, l); \
- for (ll = l - 1; ll >= 0; --ll) _s->s[_s->l++] = buf[ll]; \
- _s->s[_s->l] = 0; \
- } \
+ write_integer0(c, _s, _type, _z, _conv); \
} while (0)
va_list ap;
const char *p = fmt, *q;
+ int state = 0;
+ printf_conv_t z, ztmp;
+ memset(&z, 0, sizeof(printf_conv_t)); z.fill = -1;
+ ztmp = z;
va_start(ap, fmt);
while (*p) {
- if (*p == '%') {
- ++p;
+ if (state == 1) {
+ int finished = 0;
if (*p == '%') {
enlarge(s, 1);
s->s[s->l++] = '%';
- s->s[s->l] = 0;
+ finished = 1;
+ } else if (*p >= '0' && *p <= '9') { // width
+ char *r;
+ z.width = strtol(p, &r, 10);
+ p = r - 1;
+ } else if (*p == '.') { // fill
+ char *r;
+ z.fill = strtol(p + 1, &r, 10);
+ p = r - 1;
+ } else if (*p == 'l') { // %l
+ ++z.n_ell;
+ } else if (*p == 'L') { // %L
+ ++z.n_Ell;
+ } else if (*p == '-') { // %-
+ z.left_aln = 1;
} else if (*p == 's') { // %s
char *r = va_arg(ap, char*);
int l = strlen(r);
enlarge(s, l);
memcpy(s->s + s->l, r, l);
s->l += l;
- s->s[s->l] = 0;
+ finished = 1;
} else if (*p == 'c') { // %c
enlarge(s, 1);
s->s[s->l++] = va_arg(ap, int);
- s->s[s->l] = 0;
+ finished = 1;
} else if (*p == 'd' || *p == 'i') { // %d or %i
- write_integer(ap, s, int, 10);
- } else if (*p == 'u' || *p == 'o' || *p == 'x') { // %u, %o or %x
- int base = get_base(*p);
- write_integer(ap, s, unsigned, base);
- } else if (*p == 'l') {
- ++p;
- if (*p == 'l') {
- ++p;
- if (*p == 'd' || *p == 'i') { // %lld or %lli
- write_integer(ap, s, long long, 10);
- } else if (*p == 'u' || *p == 'o' || *p == 'x') {
- int base = get_base(*p);
- write_integer(ap, s, unsigned long long, base);
- }
- } else if (*p == 'd' || *p == 'i') { // %ld or %li
- write_integer(ap, s, long, 10);
- } else if (*p == 'u' || *p == 'o' || *p == 'x') {
- int base = get_base(*p);
- write_integer(ap, s, unsigned long, base);
+ z.base = 10;
+ if (z.n_ell == 0) write_integer(ap, s, int, z, "0123456789");
+ else if (z.n_ell == 1) write_integer(ap, s, long, z, "0123456789");
+ else write_integer(ap, s, long long, z, "0123456789");
+ finished = 1;
+ } else if (*p == 'u' || *p == 'o' || *p == 'x' || *p == 'X') { // %u, %o or %x
+ const char *conv = (*p == 'X')? "0123456789ABCDEF" : "0123456789abcdef";
+ if (*p == 'u') z.base = 10;
+ else if (*p == 'o') z.base = 8;
+ else if (*p == 'x' || *p == 'X') z.base = 16;
+ if (z.n_ell == 0) write_integer(ap, s, unsigned, z, conv);
+ else if (z.n_ell == 1) write_integer(ap, s, unsigned long, z, conv);
+ else write_integer(ap, s, unsigned long long, z, conv);
+ finished = 1;
+ } else if (*p == 'f' || *p == 'e') {
+ const char *t, *r = 0;
+ double x = va_arg(ap, double);
+ uint64_t *y = (uint64_t*)&x;
+ int l;
+ if ((*y >> 52 & 0x7ff) == 0x7ff) { // nan, inf or -inf
+ if (*y & 0x000fffffffffffffull) r = "nan";
+ else if (*y>>63) r = "-inf";
+ else r = "inf";
+ l = strlen(r);
+ enlarge(s, l);
+ for (t = r; *t; ++t) s->s[s->l++] = *t;
+ } else if (*p == 'f') {
}
+ finished = 1;
}
++p;
+ if (finished) state = 0;
} else {
q = p;
while (*p && *p != '%') ++p;
- enlarge(s, p - q);
- memcpy(s->s + s->l, q, p - q);
- s->l += p - q;
- s->s[s->l] = 0;
+ if (p > q) {
+ enlarge(s, p - q);
+ memcpy(s->s + s->l, q, p - q);
+ s->l += p - q;
+ }
+ if (*p == '%') {
+ state = 1;
+ ++p;
+ memset(&z, 0, sizeof(printf_conv_t)); z.fill = -1;
+ }
}
}
va_end(ap);
-
-#undef write_integer
-
+ s->s[s->l] = 0;
return 0;
}
s = (kstring_t*)calloc(1, sizeof(kstring_t));
{ // test ksprintf_fast()
long xx = -10;
- ksprintf_fast(s, " pooiu %% %s %ld %c %x", "+++", xx, '*', 100); printf("'%s'\n", s->s); s->l = 0;
+ ksprintf_fast(s, " pooiu %% %s %ld %c%-5.4X %f", "+++", xx, '*', 110, 2.45); printf("'%s'\n", s->s); s->l = 0;
+ printf("%4.3x, %.1f\n", 100, 1e30);
}
// test ksprintf()
ksprintf(s, " abcdefg: %d ", 100);