Skip to content

Commit

Permalink
parse %g and %G, they don't format but they end up in the spec struct (
Browse files Browse the repository at this point in the history
…#226)

* parse %g and %G, they don't format but they end up in the spec struct

* delete comment
  • Loading branch information
charlesnicholson committed Sep 20, 2022
1 parent 9bc57a9 commit 5eb27bc
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 45 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,9 @@ Like `printf`, `nanoprintf` expects a conversion specification string of the fol
* `p`: Pointers
* `n`: Write the number of bytes written to the pointer vararg
* `f`/`F`: Floating-point decimal
* `e`/`E`: Floating-point scientific (unimplemented, prints decimal)
* `a`/`A`: Floating-point hex (unimplemented, prints decimal)
* `e`/`E`: Floating-point scientific (unimplemented, prints float decimal)
* `g`/`G`: Floating-point shortest (unimplemented, prints float decimal)
* `a`/`A`: Floating-point hex (unimplemented, prints float decimal)
* `b`/`B`: Binary integers

## Floating Point
Expand All @@ -154,7 +155,7 @@ Floating point conversion is performed by extracting the value into 64:64 fixed-

Because the float -> fixed code operates on the raw float value bits, no floating point operations are performed. This allows nanoprintf to efficiently format floats on soft-float architectures like Cortex-M0, and to function identically with or without optimizations like "fast math". Despite `nano` in the name, there's no way to do away with double entirely, since the C language standard says that floats are promoted to double any time they're passed into variadic argument lists. nanoprintf casts all doubles back down to floats before doing any conversions. No other single- or double- precision operations are performed.

The `%e`/`%E` and `%a`/`%A` specifiers are parsed but not formatted. If used, the output will be identical to if `%f`/`%F` was used. Pull requests welcome! :)
The `%e`/`%E`, `%a`/`%A`, and `%g`/`%G` specifiers are parsed but not formatted. If used, the output will be identical to if `%f`/`%F` was used. Pull requests welcome! :)

## Limitations

Expand Down
15 changes: 12 additions & 3 deletions nanoprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,10 @@ typedef enum {
NPF_FMT_SPEC_CONV_WRITEBACK, // 'n'
#endif
#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
NPF_FMT_SPEC_CONV_FLOAT_DEC, // 'f', 'F'
NPF_FMT_SPEC_CONV_FLOAT_SCI, // 'e', 'E'
NPF_FMT_SPEC_CONV_FLOAT_HEX, // 'a', 'A'
NPF_FMT_SPEC_CONV_FLOAT_DEC, // 'f', 'F'
NPF_FMT_SPEC_CONV_FLOAT_SCI, // 'e', 'E'
NPF_FMT_SPEC_CONV_FLOAT_SHORTEST, // 'g', 'G'
NPF_FMT_SPEC_CONV_FLOAT_HEX, // 'a', 'A'
#endif
} npf_format_spec_conversion_t;

Expand Down Expand Up @@ -447,6 +448,13 @@ int npf_parse_format_spec(char const *format, npf_format_spec_t *out_spec) {
if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
break;

case 'G':
out_spec->case_adjust = 0;
case 'g':
out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_SHORTEST;
if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
break;

case 'A':
out_spec->case_adjust = 0;
case 'a':
Expand Down Expand Up @@ -878,6 +886,7 @@ int npf_vpprintf(npf_putc pc, void *pc_ctx, char const *format, va_list args) {
#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
case NPF_FMT_SPEC_CONV_FLOAT_DEC:
case NPF_FMT_SPEC_CONV_FLOAT_SCI:
case NPF_FMT_SPEC_CONV_FLOAT_SHORTEST:
case NPF_FMT_SPEC_CONV_FLOAT_HEX: {
float val;
if (fs.length_modifier == NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE) {
Expand Down
51 changes: 12 additions & 39 deletions tests/unit_parse_format_spec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,18 @@ TEST_CASE("npf_parse_format_spec") {
REQUIRE(spec.case_adjust == 0);
}

SUBCASE("g") {
REQUIRE(npf_parse_format_spec("%g", &spec) == 2);
REQUIRE(spec.conv_spec == NPF_FMT_SPEC_CONV_FLOAT_SHORTEST);
REQUIRE(spec.case_adjust == 'a' - 'A');
}

SUBCASE("G") {
REQUIRE(npf_parse_format_spec("%G", &spec) == 2);
REQUIRE(spec.conv_spec == NPF_FMT_SPEC_CONV_FLOAT_SHORTEST);
REQUIRE(spec.case_adjust == 0);
}

SUBCASE("a") {
REQUIRE(npf_parse_format_spec("%a", &spec) == 2);
REQUIRE(spec.conv_spec == NPF_FMT_SPEC_CONV_FLOAT_HEX);
Expand All @@ -473,42 +485,3 @@ TEST_CASE("npf_parse_format_spec") {
}
}

/*
Not implemented yet
TEST(npf_parse_format_spec, e) {
CHECK_EQUAL(2, npf_parse_format_spec("%e", &spec));
CHECK_EQUAL(NPF_FMT_SPEC_CONV_FLOAT_EXPONENT, spec.conv_spec);
CHECK_EQUAL(NPF_FMT_SPEC_CONV_CASE_LOWER, spec.conv_spec_case);
}
TEST(npf_parse_format_spec, E) {
CHECK_EQUAL(2, npf_parse_format_spec("%E", &spec));
CHECK_EQUAL(NPF_FMT_SPEC_CONV_FLOAT_EXPONENT, spec.conv_spec);
CHECK_EQUAL(NPF_FMT_SPEC_CONV_CASE_UPPER, spec.conv_spec_case);
}
TEST(npf_parse_format_spec, a) {
CHECK_EQUAL(2, npf_parse_format_spec("%a", &spec));
CHECK_EQUAL(NPF_FMT_SPEC_CONV_FLOAT_HEXPONENT, spec.conv_spec);
CHECK_EQUAL(NPF_FMT_SPEC_CONV_CASE_LOWER, spec.conv_spec_case);
}
TEST(npf_parse_format_spec, A) {
CHECK_EQUAL(2, npf_parse_format_spec("%A", &spec));
CHECK_EQUAL(NPF_FMT_SPEC_CONV_FLOAT_HEXPONENT, spec.conv_spec);
CHECK_EQUAL(NPF_FMT_SPEC_CONV_CASE_UPPER, spec.conv_spec_case);
}
TEST(npf_parse_format_spec, g) {
CHECK_EQUAL(2, npf_parse_format_spec("%g", &spec));
CHECK_EQUAL(NPF_FMT_SPEC_CONV_FLOAT_DYNAMIC, spec.conv_spec);
CHECK_EQUAL(NPF_FMT_SPEC_CONV_CASE_LOWER, spec.conv_spec_case);
}
TEST(npf_parse_format_spec, G) {
CHECK_EQUAL(2, npf_parse_format_spec("%G", &spec));
CHECK_EQUAL(NPF_FMT_SPEC_CONV_FLOAT_DYNAMIC, spec.conv_spec);
CHECK_EQUAL(NPF_FMT_SPEC_CONV_CASE_UPPER, spec.conv_spec_case);
}
*/

0 comments on commit 5eb27bc

Please sign in to comment.