struct/dstr-putf.c: Different way to represent type lengths; new types.
authorMark Wooding <mdw@distorted.org.uk>
Mon, 16 Jun 2014 21:09:38 +0000 (22:09 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 20 Jul 2014 09:06:31 +0000 (10:06 +0100)
Support the full menagerie of C99 and POSIX types.

configure.ac
struct/dstr-putf.c

index 2d4f0fb..5973f45 100644 (file)
@@ -52,6 +52,7 @@ dnl C programming environment.
 
 dnl Headers.
 AC_CHECK_HEADERS([float.h])
+AC_CHECK_HEADERS([stdint.h])
 
 dnl Libraries.
 AC_SEARCH_LIBS([socket], [socket])
index 6f699e4..9ac8cf9 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <assert.h>
 #include <ctype.h>
+#include <limits.h>
 #include <math.h>
 #include <stdarg.h>
 #include <stdio.h>
 #  include <float.h>
 #endif
 
+#ifdef HAVE_STDINT_H
+#  include <stdint.h>
+#endif
+
 #include "darray.h"
 #include "dstr.h"
 
 
 /*----- Preliminary definitions -------------------------------------------*/
 
+#ifdef HAVE_FLOAT_H
+#  define IF_FLOAT(x) x
+#else
+#  define IF_FLOAT(x)
+#endif
+
+#if defined(LLONG_MAX) || defined(LONG_LONG_MAX)
+#  define IF_LONGLONG(x) x
+#else
+#  define IF_LONGLONG(x)
+#endif
+
+#ifdef INTMAX_MAX
+#  define IF_INTMAX(x) x
+#else
+#  define IF_INTMAX(x)
+#endif
+
 #define OUTPUT_FMTTYPES(_)                                             \
   _(i, unsigned int)                                                   \
   _(li, unsigned long)                                                 \
+  IF_LONGLONG( _(lli, unsigned long long) )                            \
+  _(zi, size_t)                                                                \
+  _(ti, ptrdiff_t)                                                     \
+  IF_INTMAX( _(ji, uintmax_t) )                                                \
   _(s, char *)                                                         \
   _(p, void *)                                                         \
   _(f, double)                                                         \
   _(Lf, long double)
 
 #define PERCENT_N_FMTTYPES(_)                                          \
-  _(hn, short *)                                                       \
   _(n, int *)                                                          \
-  _(ln, long *)
+  _(hhn, char *)                                                       \
+  _(hn, short *)                                                       \
+  _(ln, long *)                                                                \
+  _(zn, size_t *)                                                      \
+  _(tn, ptrdiff_t *)                                                   \
+  IF_LONGLONG( _(lln, long long *) )                                   \
+  IF_INTMAX( _(jn, intmax_t *) )
 
 #define FMTTYPES(_)                                                    \
   OUTPUT_FMTTYPES(_)                                                   \
@@ -93,9 +125,13 @@ DA_DECL(fmtarg_v, fmtarg);
 
 enum {
   len_std = 0,
+  len_hh,
   len_h,
   len_l,
   len_ll,
+  len_z,
+  len_t,
+  len_j,
   len_L
 };
 
@@ -275,9 +311,18 @@ int dstr_vputf(dstr *d, const char *p, va_list *ap)
     /* --- Maybe some length flags --- */
 
     switch (*p) {
-      case 'h': f |= len_h; p++; break;
-      case 'l': f |= len_l; p++; break;
+      case 'h':
+       p++;
+       if (*p == 'h') { f |= len_hh; p++; } else f |= len_h;
+       break;
+      case 'l':
+       p++;
+       IF_LONGLONG( if (*p == 'l') { f |= len_ll; p++; } else ) f |= len_l;
+       break;
       case 'L': f |= len_L; p++; break;
+      case 'z': f |= len_z; p++; break;
+      case 't': f |= len_t; p++; break;
+      IF_INTMAX( case 'j': f |= len_j; p++; break; )
     }
 
     /* --- The flags are now ready --- */
@@ -294,9 +339,14 @@ int dstr_vputf(dstr *d, const char *p, va_list *ap)
       case 'd': case 'i': case 'x': case 'X': case 'o': case 'u':
        switch (f & f_len) {
          case len_l: fs->fmt = fmt_li; break;
+         case len_z: fs->fmt = fmt_zi; break;
+         case len_t: fs->fmt = fmt_ti; break;
+         IF_LONGLONG( case len_ll: fs->fmt = fmt_lli; break; )
+         IF_INTMAX( case len_j: fs->fmt = fmt_ji; break; )
          default: fs->fmt = fmt_i;
        }
        break;
+      case 'a': case 'A':
       case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
        fs->fmt = (f & f_len) == len_L ? fmt_Lf : fmt_f;
        break;
@@ -311,8 +361,13 @@ int dstr_vputf(dstr *d, const char *p, va_list *ap)
        break;
       case 'n':
        switch (f & f_len) {
+         case len_hh: fs->fmt = fmt_hhn; break;
          case len_h: fs->fmt = fmt_hn; break;
          case len_l: fs->fmt = fmt_ln; break;
+         case len_z: fs->fmt = fmt_zn; break;
+         case len_t: fs->fmt = fmt_tn; break;
+         IF_LONGLONG( case len_ll: fs->fmt = fmt_lln; break; )
+         IF_INTMAX( case len_j: fs->fmt = fmt_jn; break; )
          default: fs->fmt = fmt_n;
        }
        break;
@@ -404,9 +459,14 @@ int dstr_vputf(dstr *d, const char *p, va_list *ap)
     /* --- Write out the length gadget --- */
 
     switch (f & f_len) {
+      case len_hh: DPUTC(&dd, 'h'); /* fall through */
       case len_h: DPUTC(&dd, 'h'); break;
+      IF_LONGLONG( case len_ll: DPUTC(&dd, 'l'); /* fall through */ )
       case len_l: DPUTC(&dd, 'l'); break;
+      case len_z: DPUTC(&dd, 'z'); break;
+      case len_t: DPUTC(&dd, 't'); break;
       case len_L: DPUTC(&dd, 'L'); break;
+      IF_INTMAX( case len_j: DPUTC(&dd, 'j'); break; )
       case len_std: break;
       default: abort();
     }