chiark / gitweb /
Further test coverage
authorRichard Kettlewell <rjk@greenend.org.uk>
Tue, 20 May 2008 21:16:32 +0000 (22:16 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Tue, 20 May 2008 21:16:32 +0000 (22:16 +0100)
lib/printf.c
lib/printf.h
lib/sink.c
lib/sink.h
lib/t-kvp.c
lib/t-printf.c

index 15478ce..c5b9ebd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * This file is part of DisOrder
- * Copyright (C) 2004, 2007 Richard Kettlewell
+ * Copyright (C) 2004, 2007, 2008 Richard Kettlewell
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -95,7 +95,8 @@ static int do_write(struct state *s,
 #endif
     return -1;
   }
-  if(s->output->write(s->output, buffer, nbytes) < 0) return -1;
+  if(s->output->write(s->output, buffer, nbytes) < 0)
+    return -1;
   s->bytes += nbytes;
   return 0;
 }
@@ -113,9 +114,11 @@ static int do_pad(struct state *s, int ch, unsigned n) {
   t = n / 32;
   n %= 32;
   while(t-- > 0)
-    if(do_write(s, padding, 32) < 0) return -1;
+    if(do_write(s, padding, 32) < 0)
+      return -1;
   if(n > 0)
-    if(do_write(s, padding, n) < 0) return -1;
+    if(do_write(s, padding, n) < 0)
+      return -1;
   return 0;
 }
 
@@ -128,7 +131,8 @@ static int get_integer(int *intp, const char *ptr) {
 
   errno = 0;
   n = strtol(ptr, &e, 10);
-  if(errno || n > INT_MAX || n < INT_MIN || e == ptr) return -1;
+  if(errno || n > INT_MAX || n < INT_MIN || e == ptr)
+    return -1;
   *intp = n;
   return e - ptr;
 }
@@ -163,12 +167,14 @@ static int check_string(const struct conversion *c) {
 }
 
 static int check_pointer(const struct conversion *c) {
-  if(c->length) return -1;
+  if(c->length)
+    return -1;
   return 0;
 }
 
 static int check_percent(const struct conversion *c) {
-  if(c->flags || c->width || c->precision || c->length) return -1;
+  if(c->flags || c->width || c->precision || c->length)
+    return -1;
   return 0;
 }
 
@@ -235,7 +241,8 @@ static int output_integer(struct state *s, struct conversion *c) {
   if(!(c->flags & f_precision))
     c->precision = 1;
   /* enforce sign */
-  if((c->flags & f_sign) && !sign) sign = '+';
+  if((c->flags & f_sign) && !sign)
+    sign = '+';
   /* compute the digits */
   iszero = (u == 0);
   dp = sizeof digits;
@@ -284,23 +291,38 @@ static int output_integer(struct state *s, struct conversion *c) {
    * '-' beats '0'.
    */
   if(c->flags & f_left) {
-    if(sign && do_write(s, &sign, 1)) return -1;
-    if(xform && do_write(s, c->specifier->xform, xform)) return -1;
-    if(prec && do_pad(s, '0', prec) < 0) return -1;
-    if(ndigits && do_write(s, digits + dp, ndigits)) return -1;
-    if(pad && do_pad(s, ' ', pad) < 0) return -1;
+    if(sign && do_write(s, &sign, 1))
+      return -1;
+    if(xform && do_write(s, c->specifier->xform, xform))
+      return -1;
+    if(prec && do_pad(s, '0', prec) < 0)
+      return -1;
+    if(ndigits && do_write(s, digits + dp, ndigits))
+      return -1;
+    if(pad && do_pad(s, ' ', pad) < 0)
+      return -1;
   } else if(c->flags & f_zero) {
-    if(sign && do_write(s, &sign, 1)) return -1;
-    if(xform && do_write(s, c->specifier->xform, xform)) return -1;
-    if(pad && do_pad(s, '0', pad) < 0) return -1;
-    if(prec && do_pad(s, '0', prec) < 0) return -1;
-    if(ndigits && do_write(s, digits + dp, ndigits)) return -1;
+    if(sign && do_write(s, &sign, 1))
+      return -1;
+    if(xform && do_write(s, c->specifier->xform, xform))
+      return -1;
+    if(pad && do_pad(s, '0', pad) < 0)
+      return -1;
+    if(prec && do_pad(s, '0', prec) < 0)
+      return -1;
+    if(ndigits && do_write(s, digits + dp, ndigits))
+      return -1;
   } else {
-    if(pad && do_pad(s, ' ', pad) < 0) return -1;
-    if(sign && do_write(s, &sign, 1)) return -1;
-    if(xform && do_write(s, c->specifier->xform, xform)) return -1;
-    if(prec && do_pad(s, '0', prec) < 0) return -1;
-    if(ndigits && do_write(s, digits + dp, ndigits)) return -1;
+    if(pad && do_pad(s, ' ', pad) < 0)
+      return -1;
+    if(sign && do_write(s, &sign, 1))
+      return -1;
+    if(xform && do_write(s, c->specifier->xform, xform))
+      return -1;
+    if(prec && do_pad(s, '0', prec) < 0)
+      return -1;
+    if(ndigits && do_write(s, digits + dp, ndigits))
+      return -1;
   }
   return 0;
 }
@@ -323,11 +345,15 @@ static int output_string(struct state *s, struct conversion *c) {
   } else
     pad = 0;
   if(c->flags & f_left) {
-    if(do_write(s, str, len) < 0) return -1;
-    if(pad && do_pad(s, ' ', pad) < 0) return -1;
+    if(do_write(s, str, len) < 0)
+      return -1;
+    if(pad && do_pad(s, ' ', pad) < 0)
+      return -1;
   } else {
-    if(pad && do_pad(s, ' ', pad) < 0) return -1;
-    if(do_write(s, str, len) < 0) return -1;
+    if(pad && do_pad(s, ' ', pad) < 0)
+      return -1;
+    if(do_write(s, str, len) < 0)
+      return -1;
   }
   return 0;
   
@@ -344,11 +370,15 @@ static int output_char(struct state *s, struct conversion *c) {
   } else
     pad = 0;
   if(c->flags & f_left) {
-    if(do_write(s, &ch, 1) < 0) return -1;
-    if(pad && do_pad(s, ' ', pad) < 0) return -1;
+    if(do_write(s, &ch, 1) < 0)
+      return -1;
+    if(pad && do_pad(s, ' ', pad) < 0)
+      return -1;
   } else {
-    if(pad && do_pad(s, ' ', pad) < 0) return -1;
-    if(do_write(s, &ch, 1) < 0) return -1;
+    if(pad && do_pad(s, ' ', pad) < 0)
+      return -1;
+    if(do_write(s, &ch, 1) < 0)
+      return -1;
   }
   return 0;
 }
@@ -397,7 +427,8 @@ static int parse_conversion(struct conversion *c, const char *ptr) {
   }
   /* minimum field width */
   if(*ptr >= '0' && *ptr <= '9') {
-    if((n = get_integer(&c->width, ptr)) < 0) return -1;
+    if((n = get_integer(&c->width, ptr)) < 0)
+      return -1;
     ptr += n;
     c->flags |= f_width;
   } else if(*ptr == '*') {
@@ -409,7 +440,8 @@ static int parse_conversion(struct conversion *c, const char *ptr) {
   if(*ptr == '.') {
     ++ptr;
     if(*ptr >= '0' && *ptr <= '9') {
-      if((n = get_integer(&c->precision, ptr)) < 0) return -1;
+      if((n = get_integer(&c->precision, ptr)) < 0)
+       return -1;
       ptr += n;
     } else if(*ptr == '*') {
       ++ptr;
@@ -421,12 +453,20 @@ static int parse_conversion(struct conversion *c, const char *ptr) {
   /* length modifier */
   switch(ch = *ptr++) {
   case 'h':
-    if((ch = *ptr++) == 'h') { c->length = l_char; ch = *ptr++; }
-    else c->length = l_short;
+    if((ch = *ptr++) == 'h') {
+      c->length = l_char;
+      ch = *ptr++;
+    }
+    else
+      c->length = l_short;
     break;
   case 'l':
-    if((ch = *ptr++) == 'l') { c->length = l_longlong; ch = *ptr++; }
-    else c->length = l_long;
+    if((ch = *ptr++) == 'l') {
+      c->length = l_longlong;
+      ch = *ptr++;
+    }
+    else
+      c->length = l_long;
     break;
   case 'q': c->length = l_longlong; ch = *ptr++; break;
   case 'j': c->length = l_intmax_t; ch = *ptr++; break;
@@ -438,10 +478,14 @@ static int parse_conversion(struct conversion *c, const char *ptr) {
   l = 0;
   r = sizeof specifiers / sizeof *specifiers;
   while(l <= r && (specifiers[m = (l + r) / 2].ch != ch))
-    if(ch < specifiers[m].ch) r = m - 1;
-    else l = m + 1;
-  if(specifiers[m].ch != ch) return -1;
-  if(specifiers[m].check(c)) return -1;
+    if(ch < specifiers[m].ch)
+      r = m - 1;
+    else
+      l = m + 1;
+  if(specifiers[m].ch != ch)
+    return -1;
+  if(specifiers[m].check(c))
+    return -1;
   c->specifier = &specifiers[m];
   return ptr - start;
 }
@@ -465,12 +509,14 @@ int byte_vsinkprintf(struct sink *output,
     for(ptr = fmt; *fmt && *fmt != '%'; ++fmt)
       ;
     if((n = fmt - ptr))
-      if(do_write(&s, ptr, n) < 0) goto error;
+      if(do_write(&s, ptr, n) < 0)
+       goto error;
     if(!*fmt)
       break;
     ++fmt;
     /* parse conversion */
-    if((n = parse_conversion(&c, fmt)) < 0) goto error;
+    if((n = parse_conversion(&c, fmt)) < 0)
+      goto error;
     fmt += n;
     /* fill in width and precision */
     if((c.flags & f_width) && c.width == -1)
@@ -482,7 +528,8 @@ int byte_vsinkprintf(struct sink *output,
       if((c.precision = va_arg(s.ap, int)) < 0)
        c.flags ^= f_precision;
     /* generate the output */
-    if(c.specifier->output(&s, &c) < 0) goto error;
+    if(c.specifier->output(&s, &c) < 0)
+      goto error;
   }
   va_end(s.ap);
   return s.bytes;
@@ -491,6 +538,16 @@ error:
   return -1;
 }
 
+int byte_sinkprintf(struct sink *output, const char *fmt, ...) {
+  int n;
+  va_list ap;
+
+  va_start(ap, fmt);
+  n = byte_vsinkprintf(output, fmt, ap);
+  va_end(ap);
+  return n;
+}
+
 /*
 Local Variables:
 c-basic-offset:2
index 9125ace..3b3b7c1 100644 (file)
@@ -25,6 +25,7 @@ struct sink;
 int byte_vsinkprintf(struct sink *output,
                     const char *fmt,
                     va_list ap);
+int byte_sinkprintf(struct sink *output, const char *fmt, ...);
 /* partial printf implementation that takes ASCII format strings but
  * arbitrary byte strings as args to %s and friends.  Lots of bits are
  * missing! */
index e904005..2c1279b 100644 (file)
@@ -147,6 +147,22 @@ struct sink *sink_discard(void) {
   return s;
 }
 
+/* error sink **************************************************************/
+
+static int sink_error_write(struct sink attribute((unused)) *s,
+                           const void attribute((unused)) *buffer,
+                           int attribute((unused)) nbytes) {
+  return -1;
+}
+
+/** @brief Return a sink which discards all output */
+struct sink *sink_error(void) {
+  struct sink *s = xmalloc(sizeof *s);
+
+  s->write = sink_error_write;
+  return s;
+}
+
 /*
 Local Variables:
 c-basic-offset:2
index 15462ae..13ea7d4 100644 (file)
@@ -51,7 +51,10 @@ struct sink *sink_dynstr(struct dynstr *output);
 /* return a sink which appends to @output@. */
 
 struct sink *sink_discard(void);
-/* reutrn a sink which junks everything */
+/* return a sink which junks everything */
+
+struct sink *sink_error(void);
+/* return a sink which fails all writes */
 
 int sink_vprintf(struct sink *s, const char *fmt, va_list ap);
 int sink_printf(struct sink *s, const char *fmt, ...)
index ce01a84..d463350 100644 (file)
@@ -57,6 +57,9 @@ static void test_kvp(void) {
   insist(n == strlen("bar=foo&zog=%25"));
   check_string(urlencodestring("abc% +\n"),
                "abc%25%20%2b%0a");
+  check_integer(urldecode(sink_error(), "bar=foo", 7), -1);
+  check_integer(urlencode(sink_error(), "wibble", 7), -1);
+  check_integer(urlencode(sink_error(), " ", 1), -1);
 }
 
 TEST(kvp);
index 85b85c9..85d1d01 100644 (file)
  */
 #include "test.h"
 
+/* launder a string constant to stop gcc warnings */
+static const char *L(const char *s) {
+  return s;
+}
+
 static void test_printf(void) {
   char c;
   short s;
@@ -34,6 +39,8 @@ static void test_printf(void) {
   
   check_string(do_printf("%d", 999), "999");
   check_string(do_printf("%d", -999), "-999");
+  check_string(do_printf("%+d", 999), "+999");
+  check_string(do_printf("%+d", -999), "-999");
   check_string(do_printf("%i", 999), "999");
   check_string(do_printf("%i", -999), "-999");
   check_string(do_printf("%u", 999), "999");
@@ -129,6 +136,44 @@ static void test_printf(void) {
   insist(fgets(buffer, sizeof buffer, fp) == buffer);
   check_string(buffer, "    wibble\n");
   fclose(fp);
+  check_integer(byte_snprintf(buffer, sizeof buffer,
+                              "%18446744073709551616d", 10), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer,
+                              "%.18446744073709551616d", 10), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%hs"), ""), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%qs"), ""), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%js"), ""), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%zs"), ""), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%ts"), ""), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%Ls"), ""), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%hp"), (void *)0), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%lp"), (void *)0), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%qp"), (void *)0), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%jp"), (void *)0), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%zp"), (void *)0), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%tp"), (void *)0), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%Lp"), (void *)0), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%h%")), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%l%")), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%q%")), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%j%")), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%z%")), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%t%")), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, L("%L%")), -1);
+  check_integer(byte_snprintf(buffer, sizeof buffer, "%2147483647s%2147483647s", "", ""), -1);
+  check_integer(byte_sinkprintf(sink_error(), ""), 0);
+  check_integer(byte_sinkprintf(sink_error(), "%5s", ""), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%d", 0), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%d", 1), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%2d", 0), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%d", -1), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%#x", 10), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%-d", 0), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%-d", 1), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%-2d", 0), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%-d", -1), -1);
+  check_integer(byte_sinkprintf(sink_error(), "%-#x", 10), -1);
+
 }
 
 TEST(printf);