X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/71b70599a2cd81c13cc4326499a5d0c45358cd7d..refs/heads/master:/lib/printf.c
diff --git a/lib/printf.c b/lib/printf.c
index 15478ce..9f1b57a 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -1,40 +1,42 @@
/*
* 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
+ * 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
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
+ * along with this program. If not, see .
+ */
+/** @file lib/printf.c
+ * @brief UTF-8 *printf workalike (core)
*/
#define NO_MEMORY_ALLOCATION
/* because byte_snprintf used from log.c */
-#include
-#include "types.h"
+#include "common.h"
-#include
#include
-#include
#include
-#include
#include
#include "printf.h"
+#include "log.h"
#include "sink.h"
#include "vacopy.h"
+/** @brief Flags from a converstion specification
+ *
+ * Order significant!
+ */
enum flags {
f_thousands = 1,
f_left = 2,
@@ -46,6 +48,7 @@ enum flags {
f_precision = 512
};
+/** @brief Possible lengths of a conversion specification */
enum lengths {
l_char = 1,
l_short,
@@ -59,29 +62,65 @@ enum lengths {
struct conversion;
+/** @brief Formatter state */
struct state {
+ /** @brief Output stream */
struct sink *output;
+
+ /** @brief Number of bytes written */
int bytes;
+
+ /** @brief Argument list */
va_list ap;
};
+/** @brief Definition of a conversion specifier */
struct specifier {
+ /** @brief Defining character ('d', 's' etc) */
int ch;
+
+ /** @brief Consistency check
+ * @param c Conversion being processed
+ * @return 0 if OK, -1 on error
+ */
int (*check)(const struct conversion *c);
+
+ /** @brief Generate output
+ * @param s Formatter state
+ * @param c Conversion being processed
+ * @return 0 on success, -1 on error
+ */
int (*output)(struct state *s, struct conversion *c);
+
+ /** @brief Number base */
int base;
+
+ /** @brief Digit set */
const char *digits;
+
+ /** @brief Alternative-form prefix */
const char *xform;
};
+/** @brief One conversion specified as it's handled */
struct conversion {
+ /** @brief Flags in this conversion */
unsigned flags;
+
+ /** @brief Field width (if @ref f_width) */
int width;
+
+ /** @brief Precision (if @ref f_precision) */
int precision;
+
+ /** @brief Length modifier or 0 */
int length;
+
+ /** @brief Specifier used */
const struct specifier *specifier;
};
+/** @brief Flag characters (order significant!) */
static const char flags[] = "'-+ #0";
/* write @nbytes@ to the output. Return -1 on error, 0 on success.
@@ -95,7 +134,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 +153,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 +170,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 +206,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 +280,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 +330,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 +384,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 +409,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 +466,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 +479,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 +492,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 +517,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 +548,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 +567,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 +577,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