[PATCH 1/4] os: support pnprintf length modifiers for integers

Peter Hutterer peter.hutterer at who-t.net
Sun Apr 14 21:01:57 PDT 2013


Mainly for %ld, smaller than int is propagated anyway, and %lld isn't really
used.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 os/log.c              | 90 ++++++++++++++++++++++++++++++++++++++++++++++++---
 test/signal-logging.c | 78 ++++++++++++++++++++++++++++++++++++++------
 2 files changed, 155 insertions(+), 13 deletions(-)

diff --git a/os/log.c b/os/log.c
index d4faa07..c582aaa 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);
 
diff --git a/test/signal-logging.c b/test/signal-logging.c
index e0eb810..9038cf8 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 */
-- 
1.8.1.4



More information about the xorg-devel mailing list