diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2013-02-14 15:34:32 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2013-05-07 09:41:05 +1000 |
commit | 5ea21560dd071ea4ab87430000d087fd5fe1f092 (patch) | |
tree | 2bac3b8720d344998f2a5d111a116ee669609dc9 | |
parent | d3d4af5f9e505d444b6c82c6ea238206433fd24b (diff) |
os: support pnprintf length modifiers for integers
Mainly for %ld, smaller than int is propagated anyway, and %lld isn't really
used.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Keith Packard <keithp@keithp.com>
-rw-r--r-- | os/log.c | 90 | ||||
-rw-r--r-- | test/signal-logging.c | 78 |
2 files changed, 155 insertions, 13 deletions
@@ -279,6 +279,55 @@ LogSetParameter(LogParameter param, int value) } } +enum { + LMOD_LONG = 0x1, + LMOD_LONGLONG = 0x2, + LMOD_SHORT = 0x4, + LMOD_SIZET = 0x8, +}; + +/** + * Parse non-digit length modifiers and set the corresponding flag in + * flags_return. + * + * @return the number of bytes parsed + */ +static int parse_length_modifier(const char *format, size_t len, int *flags_return) +{ + int idx = 0; + int length_modifier = 0; + + while (idx < len) { + switch (format[idx]) { + case 'l': + BUG_RETURN_VAL(length_modifier & LMOD_SHORT, 0); + + if (length_modifier & LMOD_LONG) + length_modifier |= LMOD_LONGLONG; + else + length_modifier |= LMOD_LONG; + break; + case 'h': + BUG_RETURN_VAL(length_modifier & (LMOD_LONG|LMOD_LONGLONG), 0); + length_modifier |= LMOD_SHORT; + /* gcc says 'short int' is promoted to 'int' when + * passed through '...', so ignored during + * processing */ + break; + case 'z': + length_modifier |= LMOD_SIZET; + break; + default: + goto out; + } + idx++; + } + +out: + *flags_return = length_modifier; + return idx; +} + /** * Signal-safe snprintf, with some limitations over snprintf. Be careful * which directives you use. @@ -297,6 +346,7 @@ pnprintf(char *string, size_t size, const char *f, va_list args) int64_t si; for (; f_idx < f_len && s_idx < size - 1; f_idx++) { + int length_modifier = 0; if (f[f_idx] != '%') { string[s_idx++] = f[f_idx]; continue; @@ -304,10 +354,18 @@ pnprintf(char *string, size_t size, const char *f, va_list args) f_idx++; - /* silently swallow length modifiers */ + /* silently swallow digit length modifiers */ while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9') || f[f_idx] == '.')) f_idx++; + /* non-digit length modifiers */ + if (f_idx < f_len) { + int parsed_bytes = parse_length_modifier(&f[f_idx], f_len - f_idx, &length_modifier); + if (parsed_bytes < 0) + return 0; + f_idx += parsed_bytes; + } + if (f_idx >= f_len) break; @@ -321,7 +379,15 @@ pnprintf(char *string, size_t size, const char *f, va_list args) break; case 'u': - ui = va_arg(args, unsigned); + if (length_modifier & LMOD_LONGLONG) + ui = va_arg(args, unsigned long long); + else if (length_modifier & LMOD_LONG) + ui = va_arg(args, unsigned long); + else if (length_modifier & LMOD_SIZET) + ui = va_arg(args, size_t); + else + ui = va_arg(args, unsigned); + FormatUInt64(ui, number); p_len = strlen_sigsafe(number); @@ -330,7 +396,15 @@ pnprintf(char *string, size_t size, const char *f, va_list args) break; case 'i': case 'd': - si = va_arg(args, int); + if (length_modifier & LMOD_LONGLONG) + si = va_arg(args, long long); + else if (length_modifier & LMOD_LONG) + si = va_arg(args, long); + else if (length_modifier & LMOD_SIZET) + si = va_arg(args, ssize_t); + else + si = va_arg(args, int); + FormatInt64(si, number); p_len = strlen_sigsafe(number); @@ -351,7 +425,15 @@ pnprintf(char *string, size_t size, const char *f, va_list args) break; case 'x': - ui = va_arg(args, unsigned); + if (length_modifier & LMOD_LONGLONG) + ui = va_arg(args, unsigned long long); + else if (length_modifier & LMOD_LONG) + ui = va_arg(args, unsigned long); + else if (length_modifier & LMOD_SIZET) + ui = va_arg(args, size_t); + else + ui = va_arg(args, unsigned); + FormatUInt64Hex(ui, number); p_len = strlen_sigsafe(number); diff --git a/test/signal-logging.c b/test/signal-logging.c index e0eb81006..9038cf81f 100644 --- a/test/signal-logging.c +++ b/test/signal-logging.c @@ -158,6 +158,8 @@ static void logging_format(void) char buf[1024]; int i; unsigned int ui; + long li; + unsigned long lui; FILE *f; char read_buf[2048]; char *logmsg; @@ -207,6 +209,14 @@ static void logging_format(void) LogMessageVerbSigSafe(X_ERROR, -1, "\n"); fseek(f, 0, SEEK_END); +#warning Ignore compiler warning below "unknown conversion type character". This is intentional. + /* %hld is bogus */ + LogMessageVerbSigSafe(X_ERROR, -1, "%hld\n", 4); + read_log_msg(logmsg); + assert(strstr(logmsg, "BUG") != NULL); + LogMessageVerbSigSafe(X_ERROR, -1, "\n"); + fseek(f, 0, SEEK_END); + /* number substitution */ ui = 0; do { @@ -215,12 +225,47 @@ static void logging_format(void) LogMessageVerbSigSafe(X_ERROR, -1, "%u\n", ui); read_log_msg(logmsg); assert(strcmp(logmsg, expected) == 0); + + sprintf(expected, "(EE) %x\n", ui); + LogMessageVerbSigSafe(X_ERROR, -1, "%x\n", ui); + read_log_msg(logmsg); + assert(strcmp(logmsg, expected) == 0); + if (ui == 0) ui = 1; else ui <<= 1; } while(ui); + lui = 0; + do { + char expected[30]; + sprintf(expected, "(EE) %lu\n", lui); + LogMessageVerbSigSafe(X_ERROR, -1, "%lu\n", lui); + read_log_msg(logmsg); + + sprintf(expected, "(EE) %lld\n", (unsigned long long)ui); + LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (unsigned long long)ui); + read_log_msg(logmsg); + assert(strcmp(logmsg, expected) == 0); + + sprintf(expected, "(EE) %lx\n", lui); + printf("%s\n", expected); + LogMessageVerbSigSafe(X_ERROR, -1, "%lx\n", lui); + read_log_msg(logmsg); + assert(strcmp(logmsg, expected) == 0); + + sprintf(expected, "(EE) %llx\n", (unsigned long long)ui); + LogMessageVerbSigSafe(X_ERROR, -1, "%llx\n", (unsigned long long)ui); + read_log_msg(logmsg); + assert(strcmp(logmsg, expected) == 0); + + if (lui == 0) + lui = 1; + else + lui <<= 1; + } while(lui); + /* signed number substitution */ i = 0; do { @@ -230,7 +275,6 @@ static void logging_format(void) read_log_msg(logmsg); assert(strcmp(logmsg, expected) == 0); - sprintf(expected, "(EE) %d\n", i | INT_MIN); LogMessageVerbSigSafe(X_ERROR, -1, "%d\n", i | INT_MIN); read_log_msg(logmsg); @@ -242,19 +286,35 @@ static void logging_format(void) i <<= 1; } while(i > INT_MIN); - /* hex number substitution */ - ui = 0; + li = 0; do { char expected[30]; - sprintf(expected, "(EE) %x\n", ui); - LogMessageVerbSigSafe(X_ERROR, -1, "%x\n", ui); + sprintf(expected, "(EE) %ld\n", li); + LogMessageVerbSigSafe(X_ERROR, -1, "%ld\n", li); read_log_msg(logmsg); assert(strcmp(logmsg, expected) == 0); - if (ui == 0) - ui = 1; + + sprintf(expected, "(EE) %ld\n", li | LONG_MIN); + LogMessageVerbSigSafe(X_ERROR, -1, "%ld\n", li | LONG_MIN); + read_log_msg(logmsg); + assert(strcmp(logmsg, expected) == 0); + + sprintf(expected, "(EE) %lld\n", (long long)li); + LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (long long)li); + read_log_msg(logmsg); + assert(strcmp(logmsg, expected) == 0); + + sprintf(expected, "(EE) %lld\n", (long long)(li | LONG_MIN)); + LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (long long)(li | LONG_MIN)); + read_log_msg(logmsg); + assert(strcmp(logmsg, expected) == 0); + + if (li == 0) + li = 1; else - ui <<= 1; - } while(ui); + li <<= 1; + } while(li > LONG_MIN); + /* pointer substitution */ /* we print a null-pointer differently to printf */ |