Merge branch 'printf-width'
This commit is contained in:
commit
e40daec29a
92
hiredis.c
92
hiredis.c
@ -770,33 +770,79 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|||||||
while (*_p != '\0' && isdigit(*_p)) _p++;
|
while (*_p != '\0' && isdigit(*_p)) _p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modifiers */
|
/* Copy va_list before consuming with va_arg */
|
||||||
if (*_p != '\0') {
|
va_copy(_cpy,ap);
|
||||||
if (*_p == 'h' || *_p == 'l') {
|
|
||||||
/* Allow a single repetition for these modifiers */
|
/* Integer conversion (without modifiers) */
|
||||||
if (_p[0] == _p[1]) _p++;
|
if (strchr("diouxX",*_p) != NULL) {
|
||||||
_p++;
|
va_arg(ap,int);
|
||||||
}
|
goto fmt_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Conversion specifier */
|
/* Double conversion (without modifiers) */
|
||||||
if (*_p != '\0' && strchr("diouxXeEfFgGaA",*_p) != NULL) {
|
if (strchr("eEfFgGaA",*_p) != NULL) {
|
||||||
_l = (_p+1)-c;
|
va_arg(ap,double);
|
||||||
if (_l < sizeof(_format)-2) {
|
goto fmt_valid;
|
||||||
memcpy(_format,c,_l);
|
|
||||||
_format[_l] = '\0';
|
|
||||||
va_copy(_cpy,ap);
|
|
||||||
newarg = sdscatvprintf(curarg,_format,_cpy);
|
|
||||||
va_end(_cpy);
|
|
||||||
|
|
||||||
/* Update current position (note: outer blocks
|
|
||||||
* increment c twice so compensate here) */
|
|
||||||
c = _p-1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Consume and discard vararg */
|
/* Size: char */
|
||||||
va_arg(ap,void);
|
if (_p[0] == 'h' && _p[1] == 'h') {
|
||||||
|
_p += 2;
|
||||||
|
if (*_p != '\0' && strchr("diouxX",*_p) != NULL) {
|
||||||
|
va_arg(ap,int); /* char gets promoted to int */
|
||||||
|
goto fmt_valid;
|
||||||
|
}
|
||||||
|
goto fmt_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Size: short */
|
||||||
|
if (_p[0] == 'h') {
|
||||||
|
_p += 1;
|
||||||
|
if (*_p != '\0' && strchr("diouxX",*_p) != NULL) {
|
||||||
|
va_arg(ap,int); /* short gets promoted to int */
|
||||||
|
goto fmt_valid;
|
||||||
|
}
|
||||||
|
goto fmt_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Size: long long */
|
||||||
|
if (_p[0] == 'l' && _p[1] == 'l') {
|
||||||
|
_p += 2;
|
||||||
|
if (*_p != '\0' && strchr("diouxX",*_p) != NULL) {
|
||||||
|
va_arg(ap,long long);
|
||||||
|
goto fmt_valid;
|
||||||
|
}
|
||||||
|
goto fmt_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Size: long */
|
||||||
|
if (_p[0] == 'l') {
|
||||||
|
_p += 1;
|
||||||
|
if (*_p != '\0' && strchr("diouxX",*_p) != NULL) {
|
||||||
|
va_arg(ap,long);
|
||||||
|
goto fmt_valid;
|
||||||
|
}
|
||||||
|
goto fmt_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_invalid:
|
||||||
|
va_end(_cpy);
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
fmt_valid:
|
||||||
|
_l = (_p+1)-c;
|
||||||
|
if (_l < sizeof(_format)-2) {
|
||||||
|
memcpy(_format,c,_l);
|
||||||
|
_format[_l] = '\0';
|
||||||
|
newarg = sdscatvprintf(curarg,_format,_cpy);
|
||||||
|
|
||||||
|
/* Update current position (note: outer blocks
|
||||||
|
* increment c twice so compensate here) */
|
||||||
|
c = _p-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(_cpy);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
52
test.c
52
test.c
@ -142,29 +142,43 @@ static void test_format_commands(void) {
|
|||||||
len == 4+4+(3+2)+4+(1+2)+4+(1+2));
|
len == 4+4+(3+2)+4+(1+2)+4+(1+2));
|
||||||
free(cmd);
|
free(cmd);
|
||||||
|
|
||||||
test("Format command with printf-delegation (long long): ");
|
/* Vararg width depends on the type. These tests make sure that the
|
||||||
len = redisFormatCommand(&cmd,"key:%08lld",1234ll);
|
* width is correctly determined using the format and subsequent varargs
|
||||||
test_cond(strncmp(cmd,"*1\r\n$12\r\nkey:00001234\r\n",len) == 0 &&
|
* can correctly be interpolated. */
|
||||||
len == 4+5+(12+2));
|
#define INTEGER_WIDTH_TEST(fmt, type) do { \
|
||||||
free(cmd);
|
type value = 123; \
|
||||||
|
test("Format command with printf-delegation (" #type "): "); \
|
||||||
|
len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \
|
||||||
|
test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \
|
||||||
|
len == 4+5+(12+2)+4+(9+2)); \
|
||||||
|
free(cmd); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
test("Format command with printf-delegation (float): ");
|
#define FLOAT_WIDTH_TEST(type) do { \
|
||||||
len = redisFormatCommand(&cmd,"v:%06.1f",12.34f);
|
type value = 123.0; \
|
||||||
test_cond(strncmp(cmd,"*1\r\n$8\r\nv:0012.3\r\n",len) == 0 &&
|
test("Format command with printf-delegation (" #type "): "); \
|
||||||
len == 4+4+(8+2));
|
len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \
|
||||||
free(cmd);
|
test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \
|
||||||
|
len == 4+5+(12+2)+4+(9+2)); \
|
||||||
|
free(cmd); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
test("Format command with printf-delegation and extra interpolation: ");
|
INTEGER_WIDTH_TEST("d", int);
|
||||||
len = redisFormatCommand(&cmd,"key:%d %b",1234,"foo",3);
|
INTEGER_WIDTH_TEST("hhd", char);
|
||||||
test_cond(strncmp(cmd,"*2\r\n$8\r\nkey:1234\r\n$3\r\nfoo\r\n",len) == 0 &&
|
INTEGER_WIDTH_TEST("hd", short);
|
||||||
len == 4+4+(8+2)+4+(3+2));
|
INTEGER_WIDTH_TEST("ld", long);
|
||||||
free(cmd);
|
INTEGER_WIDTH_TEST("lld", long long);
|
||||||
|
INTEGER_WIDTH_TEST("u", unsigned int);
|
||||||
|
INTEGER_WIDTH_TEST("hhu", unsigned char);
|
||||||
|
INTEGER_WIDTH_TEST("hu", unsigned short);
|
||||||
|
INTEGER_WIDTH_TEST("lu", unsigned long);
|
||||||
|
INTEGER_WIDTH_TEST("llu", unsigned long long);
|
||||||
|
FLOAT_WIDTH_TEST(float);
|
||||||
|
FLOAT_WIDTH_TEST(double);
|
||||||
|
|
||||||
test("Format command with wrong printf format and extra interpolation: ");
|
test("Format command with invalid printf format: ");
|
||||||
len = redisFormatCommand(&cmd,"key:%08p %b",1234,"foo",3);
|
len = redisFormatCommand(&cmd,"key:%08p %b",1234,"foo",3);
|
||||||
test_cond(strncmp(cmd,"*2\r\n$6\r\nkey:8p\r\n$3\r\nfoo\r\n",len) == 0 &&
|
test_cond(len == -1);
|
||||||
len == 4+4+(6+2)+4+(3+2));
|
|
||||||
free(cmd);
|
|
||||||
|
|
||||||
const char *argv[3];
|
const char *argv[3];
|
||||||
argv[0] = "SET";
|
argv[0] = "SET";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user