Test precision.
This commit is contained in:
@@ -72,6 +72,7 @@ void fmt::Formatter::Format() {
|
||||
const char *s = start;
|
||||
while (*s) {
|
||||
if (*s++ != '{') continue;
|
||||
// TODO: handle escape sequence
|
||||
buffer_.insert(buffer_.end(), start, s - 1);
|
||||
|
||||
// Parse argument index.
|
||||
@@ -90,26 +91,31 @@ void fmt::Formatter::Format() {
|
||||
int width = -1;
|
||||
int precision = -1;
|
||||
char type = 0;
|
||||
bool is_floating_point = false;
|
||||
if (*s == ':') {
|
||||
++s;
|
||||
if (*s == '+') {
|
||||
if (arg.type > LAST_NUMERIC_TYPE) {
|
||||
Throw<FormatError>(s,
|
||||
"format specifier '+' used with non-numeric type");
|
||||
"format specifier '+' requires numeric argument");
|
||||
}
|
||||
if (arg.type == UINT || arg.type == ULONG) {
|
||||
Throw<FormatError>(s,
|
||||
"format specifier '+' requires signed argument");
|
||||
}
|
||||
*arg_format_ptr++ = *s++;
|
||||
}
|
||||
if (*s == '0') {
|
||||
if (arg.type > LAST_NUMERIC_TYPE) {
|
||||
Throw<FormatError>(s,
|
||||
"format specifier '0' used with non-numeric type");
|
||||
"format specifier '0' requires numeric argument");
|
||||
}
|
||||
*arg_format_ptr++ = *s++;
|
||||
}
|
||||
|
||||
// Parse width.
|
||||
if ('0' <= *s && *s <= '9') {
|
||||
if (arg.type > LAST_NUMERIC_TYPE)
|
||||
if (arg.type > LAST_NUMERIC_TYPE && arg.type != POINTER)
|
||||
*arg_format_ptr++ = '-';
|
||||
*arg_format_ptr++ = '*';
|
||||
unsigned value = ParseUInt(s);
|
||||
@@ -127,16 +133,36 @@ void fmt::Formatter::Format() {
|
||||
if ('0' <= *s && *s <= '9') {
|
||||
unsigned value = ParseUInt(s);
|
||||
if (value > INT_MAX)
|
||||
Throw<FormatError>(s, "number is too big in format"); // TODO: test
|
||||
Throw<FormatError>(s, "number is too big in format");
|
||||
precision = value;
|
||||
} else {
|
||||
// TODO: error
|
||||
Throw<FormatError>(s, "missing precision in format");
|
||||
}
|
||||
if (arg.type > LAST_NUMERIC_TYPE ||
|
||||
(*s == '}' && arg.type != DOUBLE && arg.type != LONG_DOUBLE)) {
|
||||
Throw<FormatError>(s,
|
||||
"precision specifier requires floating-point type");
|
||||
}
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (*s == 'f' || *s == 'g')
|
||||
type = *s++; // TODO: check if the type matches
|
||||
if (*s != '}' && *s) {
|
||||
type = *s++;
|
||||
if (arg.type <= LAST_NUMERIC_TYPE) {
|
||||
switch (type) {
|
||||
case 'd': case 'o': case 'x': case 'X':
|
||||
// TODO: check that argument is integer
|
||||
break;
|
||||
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
|
||||
is_floating_point = true;
|
||||
break;
|
||||
default:
|
||||
// TODO: error
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: check non-numeric types (string, character)
|
||||
}
|
||||
}
|
||||
|
||||
if (*s++ != '}')
|
||||
@@ -145,36 +171,39 @@ void fmt::Formatter::Format() {
|
||||
|
||||
// Format argument.
|
||||
switch (arg.type) {
|
||||
case CHAR:
|
||||
if (width == -1 && precision == -1) {
|
||||
buffer_.push_back(arg.int_value);
|
||||
break;
|
||||
}
|
||||
*arg_format_ptr++ = 'c';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.int_value, width, precision);
|
||||
break;
|
||||
case INT:
|
||||
*arg_format_ptr++ = 'd';
|
||||
*arg_format_ptr++ = type ? type : 'd';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.int_value, width, precision);
|
||||
if (is_floating_point)
|
||||
FormatBuiltinArg<double>(arg_format, arg.int_value, width, precision);
|
||||
else
|
||||
FormatBuiltinArg(arg_format, arg.int_value, width, precision);
|
||||
break;
|
||||
case UINT:
|
||||
*arg_format_ptr++ = 'd';
|
||||
*arg_format_ptr++ = type ? type : 'u';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.uint_value, width, precision);
|
||||
if (is_floating_point)
|
||||
FormatBuiltinArg<double>(arg_format, arg.uint_value, width, precision);
|
||||
else
|
||||
FormatBuiltinArg(arg_format, arg.uint_value, width, precision);
|
||||
break;
|
||||
case LONG:
|
||||
*arg_format_ptr++ = 'l';
|
||||
*arg_format_ptr++ = 'd';
|
||||
*arg_format_ptr++ = type ? type : 'd';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.long_value, width, precision);
|
||||
if (is_floating_point)
|
||||
FormatBuiltinArg<double>(arg_format, arg.long_value, width, precision);
|
||||
else
|
||||
FormatBuiltinArg(arg_format, arg.long_value, width, precision);
|
||||
break;
|
||||
case ULONG:
|
||||
*arg_format_ptr++ = 'l';
|
||||
*arg_format_ptr++ = 'd';
|
||||
*arg_format_ptr++ = type ? type : 'u';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.ulong_value, width, precision);
|
||||
if (is_floating_point)
|
||||
FormatBuiltinArg<double>(arg_format, arg.ulong_value, width, precision);
|
||||
else
|
||||
FormatBuiltinArg(arg_format, arg.ulong_value, width, precision);
|
||||
break;
|
||||
case DOUBLE:
|
||||
*arg_format_ptr++ = type ? type : 'g';
|
||||
@@ -183,15 +212,31 @@ void fmt::Formatter::Format() {
|
||||
break;
|
||||
case LONG_DOUBLE:
|
||||
*arg_format_ptr++ = 'L';
|
||||
*arg_format_ptr++ = 'g';
|
||||
*arg_format_ptr++ = type ? type : 'g';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.long_double_value, width, precision);
|
||||
break;
|
||||
case POINTER:
|
||||
// TODO: don't allow any type specifiers other than 'p'
|
||||
*arg_format_ptr++ = 'p';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.pointer_value, width, precision);
|
||||
break;
|
||||
case CHAR:
|
||||
// TODO: check if type is 'c' or none
|
||||
if (width <= 1) {
|
||||
buffer_.push_back(arg.int_value);
|
||||
break;
|
||||
}
|
||||
*arg_format_ptr++ = 'c';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.int_value, width, precision);
|
||||
break;
|
||||
case STRING:
|
||||
// TODO: align string left by default
|
||||
if (width == -1 && precision == -1) {
|
||||
// TODO: check if type is 's' or none
|
||||
if (width == -1 || width <= arg.size) {
|
||||
const char *str = arg.string_value;
|
||||
std::size_t size = arg.size;
|
||||
size_t size = arg.size;
|
||||
if (size == 0 && *str)
|
||||
size = std::strlen(str);
|
||||
buffer_.reserve(buffer_.size() + size + 1);
|
||||
@@ -203,17 +248,14 @@ void fmt::Formatter::Format() {
|
||||
FormatBuiltinArg(arg_format, arg.string_value, width, precision);
|
||||
break;
|
||||
case WSTRING:
|
||||
// TODO: check if type is 's' or none
|
||||
*arg_format_ptr++ = 'l';
|
||||
*arg_format_ptr++ = 's';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.wstring_value, width, precision);
|
||||
break;
|
||||
case POINTER:
|
||||
*arg_format_ptr++ = 'p';
|
||||
*arg_format_ptr = '\0';
|
||||
FormatBuiltinArg(arg_format, arg.pointer_value, width, precision);
|
||||
break;
|
||||
case CUSTOM:
|
||||
// TODO: check if type is 's' or none
|
||||
(this->*arg.format)(arg.custom_value, width);
|
||||
break;
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user