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>
This commit is contained in:
Peter Hutterer 2013-02-14 15:34:32 +10:00
parent d3d4af5f9e
commit 5ea21560dd
2 changed files with 155 additions and 13 deletions

View File

@ -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 * Signal-safe snprintf, with some limitations over snprintf. Be careful
* which directives you use. * which directives you use.
@ -297,6 +346,7 @@ pnprintf(char *string, size_t size, const char *f, va_list args)
int64_t si; int64_t si;
for (; f_idx < f_len && s_idx < size - 1; f_idx++) { for (; f_idx < f_len && s_idx < size - 1; f_idx++) {
int length_modifier = 0;
if (f[f_idx] != '%') { if (f[f_idx] != '%') {
string[s_idx++] = f[f_idx]; string[s_idx++] = f[f_idx];
continue; continue;
@ -304,10 +354,18 @@ pnprintf(char *string, size_t size, const char *f, va_list args)
f_idx++; 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] == '.')) while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9') || f[f_idx] == '.'))
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) if (f_idx >= f_len)
break; break;
@ -321,7 +379,15 @@ pnprintf(char *string, size_t size, const char *f, va_list args)
break; break;
case 'u': 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); FormatUInt64(ui, number);
p_len = strlen_sigsafe(number); p_len = strlen_sigsafe(number);
@ -330,7 +396,15 @@ pnprintf(char *string, size_t size, const char *f, va_list args)
break; break;
case 'i': case 'i':
case 'd': 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); FormatInt64(si, number);
p_len = strlen_sigsafe(number); p_len = strlen_sigsafe(number);
@ -351,7 +425,15 @@ pnprintf(char *string, size_t size, const char *f, va_list args)
break; break;
case 'x': 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); FormatUInt64Hex(ui, number);
p_len = strlen_sigsafe(number); p_len = strlen_sigsafe(number);

View File

@ -158,6 +158,8 @@ static void logging_format(void)
char buf[1024]; char buf[1024];
int i; int i;
unsigned int ui; unsigned int ui;
long li;
unsigned long lui;
FILE *f; FILE *f;
char read_buf[2048]; char read_buf[2048];
char *logmsg; char *logmsg;
@ -207,6 +209,14 @@ static void logging_format(void)
LogMessageVerbSigSafe(X_ERROR, -1, "\n"); LogMessageVerbSigSafe(X_ERROR, -1, "\n");
fseek(f, 0, SEEK_END); 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 */ /* number substitution */
ui = 0; ui = 0;
do { do {
@ -215,12 +225,47 @@ static void logging_format(void)
LogMessageVerbSigSafe(X_ERROR, -1, "%u\n", ui); LogMessageVerbSigSafe(X_ERROR, -1, "%u\n", ui);
read_log_msg(logmsg); read_log_msg(logmsg);
assert(strcmp(logmsg, expected) == 0); 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) if (ui == 0)
ui = 1; ui = 1;
else else
ui <<= 1; ui <<= 1;
} while(ui); } 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 */ /* signed number substitution */
i = 0; i = 0;
do { do {
@ -230,7 +275,6 @@ static void logging_format(void)
read_log_msg(logmsg); read_log_msg(logmsg);
assert(strcmp(logmsg, expected) == 0); assert(strcmp(logmsg, expected) == 0);
sprintf(expected, "(EE) %d\n", i | INT_MIN); sprintf(expected, "(EE) %d\n", i | INT_MIN);
LogMessageVerbSigSafe(X_ERROR, -1, "%d\n", i | INT_MIN); LogMessageVerbSigSafe(X_ERROR, -1, "%d\n", i | INT_MIN);
read_log_msg(logmsg); read_log_msg(logmsg);
@ -242,19 +286,35 @@ static void logging_format(void)
i <<= 1; i <<= 1;
} while(i > INT_MIN); } while(i > INT_MIN);
/* hex number substitution */ li = 0;
ui = 0;
do { do {
char expected[30]; char expected[30];
sprintf(expected, "(EE) %x\n", ui); sprintf(expected, "(EE) %ld\n", li);
LogMessageVerbSigSafe(X_ERROR, -1, "%x\n", ui); LogMessageVerbSigSafe(X_ERROR, -1, "%ld\n", li);
read_log_msg(logmsg); read_log_msg(logmsg);
assert(strcmp(logmsg, expected) == 0); 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 else
ui <<= 1; li <<= 1;
} while(ui); } while(li > LONG_MIN);
/* pointer substitution */ /* pointer substitution */
/* we print a null-pointer differently to printf */ /* we print a null-pointer differently to printf */