summaryrefslogtreecommitdiff
path: root/os
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2013-02-14 15:34:32 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2013-05-07 09:41:05 +1000
commit5ea21560dd071ea4ab87430000d087fd5fe1f092 (patch)
tree2bac3b8720d344998f2a5d111a116ee669609dc9 /os
parentd3d4af5f9e505d444b6c82c6ea238206433fd24b (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>
Diffstat (limited to 'os')
-rw-r--r--os/log.c90
1 files changed, 86 insertions, 4 deletions
diff --git a/os/log.c b/os/log.c
index dc6e2888b..df025fbca 100644
--- a/os/log.c
+++ b/os/log.c
@@ -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);