nanoprintf.h 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. /* nanoprintf v0.5.5: a tiny embeddable printf replacement written in C.
  2. https://github.com/charlesnicholson/nanoprintf
  3. [email protected]
  4. dual-licensed under 0bsd and unlicense, take your pick. see eof for details. */
  5. #ifndef NPF_H_INCLUDED
  6. #define NPF_H_INCLUDED
  7. #include <stdarg.h>
  8. #include <stddef.h>
  9. // Define this to fully sandbox nanoprintf inside of a translation unit.
  10. #ifdef NANOPRINTF_VISIBILITY_STATIC
  11. #define NPF_VISIBILITY static
  12. #else
  13. #define NPF_VISIBILITY extern
  14. #endif
  15. #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
  16. #define NPF_PRINTF_ATTR(FORMAT_INDEX, VARGS_INDEX) \
  17. __attribute__((format(printf, FORMAT_INDEX, VARGS_INDEX)))
  18. #else
  19. #define NPF_PRINTF_ATTR(FORMAT_INDEX, VARGS_INDEX)
  20. #endif
  21. // Public API
  22. #ifdef __cplusplus
  23. #define NPF_RESTRICT
  24. extern "C" {
  25. #else
  26. #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
  27. #define NPF_RESTRICT restrict
  28. #else
  29. #define NPF_RESTRICT
  30. #endif
  31. #endif
  32. // The npf_ functions all return the number of bytes required to express the
  33. // fully-formatted string, not including the null terminator character.
  34. // The npf_ functions do not return negative values, since the lack of 'l' length
  35. // modifier support makes encoding errors impossible.
  36. NPF_VISIBILITY int npf_snprintf(char * NPF_RESTRICT buffer,
  37. size_t bufsz,
  38. const char * NPF_RESTRICT format,
  39. ...) NPF_PRINTF_ATTR(3, 4);
  40. NPF_VISIBILITY int npf_vsnprintf(char * NPF_RESTRICT buffer,
  41. size_t bufsz,
  42. char const * NPF_RESTRICT format,
  43. va_list vlist) NPF_PRINTF_ATTR(3, 0);
  44. typedef void (*npf_putc)(int c, void *ctx);
  45. NPF_VISIBILITY int npf_pprintf(npf_putc pc,
  46. void * NPF_RESTRICT pc_ctx,
  47. char const * NPF_RESTRICT format,
  48. ...) NPF_PRINTF_ATTR(3, 4);
  49. NPF_VISIBILITY int npf_vpprintf(npf_putc pc,
  50. void * NPF_RESTRICT pc_ctx,
  51. char const * NPF_RESTRICT format,
  52. va_list vlist) NPF_PRINTF_ATTR(3, 0);
  53. #ifdef __cplusplus
  54. }
  55. #endif
  56. #endif // NPF_H_INCLUDED
  57. /* The implementation of nanoprintf begins here, to be compiled only if
  58. NANOPRINTF_IMPLEMENTATION is defined. In a multi-file library what follows would
  59. be nanoprintf.c. */
  60. #ifdef NANOPRINTF_IMPLEMENTATION
  61. #ifndef NPF_IMPLEMENTATION_INCLUDED
  62. #define NPF_IMPLEMENTATION_INCLUDED
  63. #include <limits.h>
  64. #include <stdint.h>
  65. // The conversion buffer must fit at least UINT64_MAX in octal format with the leading '0'.
  66. #ifndef NANOPRINTF_CONVERSION_BUFFER_SIZE
  67. #define NANOPRINTF_CONVERSION_BUFFER_SIZE 23
  68. #endif
  69. #if NANOPRINTF_CONVERSION_BUFFER_SIZE < 23
  70. #error The size of the conversion buffer must be at least 23 bytes.
  71. #endif
  72. // Pick reasonable defaults if nothing's been configured.
  73. #if !defined(NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS) && \
  74. !defined(NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS) && \
  75. !defined(NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS) && \
  76. !defined(NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS) && \
  77. !defined(NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS) && \
  78. !defined(NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS) && \
  79. !defined(NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS) && \
  80. !defined(NANOPRINTF_USE_ALT_FORM_FLAG)
  81. #define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1
  82. #define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 1
  83. #define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS 1
  84. #define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS 0
  85. #define NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS 1
  86. #define NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS 0
  87. #define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS 0
  88. #define NANOPRINTF_USE_ALT_FORM_FLAG 1
  89. #endif
  90. // If anything's been configured, everything must be configured.
  91. #ifndef NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS
  92. #error NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS must be #defined to 0 or 1
  93. #endif
  94. #ifndef NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS
  95. #error NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS must be #defined to 0 or 1
  96. #endif
  97. #ifndef NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS
  98. #error NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS must be #defined to 0 or 1
  99. #endif
  100. #ifndef NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS
  101. #error NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS must be #defined to 0 or 1
  102. #endif
  103. #ifndef NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS
  104. #error NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS must be #defined to 0 or 1
  105. #endif
  106. #ifndef NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS
  107. #error NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS must be #defined to 0 or 1
  108. #endif
  109. #ifndef NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS
  110. #error NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS must be #defined to 0 or 1
  111. #endif
  112. // Ensure flags are compatible.
  113. #if (NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1) && \
  114. (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 0)
  115. #error Precision format specifiers must be enabled if float support is enabled.
  116. #endif
  117. // intmax_t / uintmax_t require stdint from c99 / c++11
  118. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  119. #ifndef _MSC_VER
  120. #ifdef __cplusplus
  121. #if __cplusplus < 201103L
  122. #error large format specifier support requires C++11 or later.
  123. #endif
  124. #else
  125. #if __STDC_VERSION__ < 199409L
  126. #error nanoprintf requires C99 or later.
  127. #endif
  128. #endif
  129. #endif
  130. #endif
  131. // Figure out if we can disable warnings with pragmas.
  132. #ifdef __clang__
  133. #define NPF_CLANG 1
  134. #define NPF_GCC_PAST_4_6 0
  135. #else
  136. #define NPF_CLANG 0
  137. #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)))
  138. #define NPF_GCC_PAST_4_6 1
  139. #else
  140. #define NPF_GCC_PAST_4_6 0
  141. #endif
  142. #endif
  143. #if NPF_CLANG || NPF_GCC_PAST_4_6
  144. #define NPF_HAVE_GCC_WARNING_PRAGMAS 1
  145. #else
  146. #define NPF_HAVE_GCC_WARNING_PRAGMAS 0
  147. #endif
  148. #if NPF_HAVE_GCC_WARNING_PRAGMAS
  149. #pragma GCC diagnostic push
  150. #pragma GCC diagnostic ignored "-Wunused-function"
  151. #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
  152. #ifdef __cplusplus
  153. #pragma GCC diagnostic ignored "-Wold-style-cast"
  154. #endif
  155. #pragma GCC diagnostic ignored "-Wpadded"
  156. #pragma GCC diagnostic ignored "-Wfloat-equal"
  157. #if NPF_CLANG
  158. #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"
  159. #pragma GCC diagnostic ignored "-Wcovered-switch-default"
  160. #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
  161. #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
  162. #ifndef __APPLE__
  163. #pragma GCC diagnostic ignored "-Wunsafe-buffer-usage"
  164. #endif
  165. #elif NPF_GCC_PAST_4_6
  166. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  167. #endif
  168. #endif
  169. #ifdef _MSC_VER
  170. #pragma warning(push)
  171. #pragma warning(disable:4619) // there is no warning number 'number'
  172. // C4619 has to be disabled first!
  173. #pragma warning(disable:4127) // conditional expression is constant
  174. #pragma warning(disable:4505) // unreferenced local function has been removed
  175. #pragma warning(disable:4514) // unreferenced inline function has been removed
  176. #pragma warning(disable:4701) // potentially uninitialized local variable used
  177. #pragma warning(disable:4706) // assignment within conditional expression
  178. #pragma warning(disable:4710) // function not inlined
  179. #pragma warning(disable:4711) // function selected for inline expansion
  180. #pragma warning(disable:4820) // padding added after struct member
  181. #pragma warning(disable:5039) // potentially throwing function passed to extern C function
  182. #pragma warning(disable:5045) // compiler will insert Spectre mitigation for memory load
  183. #pragma warning(disable:5262) // implicit switch fall-through
  184. #pragma warning(disable:26812) // enum type is unscoped
  185. #endif
  186. #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
  187. #define NPF_NOINLINE __attribute__((noinline))
  188. #define NPF_FORCE_INLINE inline __attribute__((always_inline))
  189. #elif defined(_MSC_VER)
  190. #define NPF_NOINLINE __declspec(noinline)
  191. #define NPF_FORCE_INLINE inline __forceinline
  192. #else
  193. #define NPF_NOINLINE
  194. #define NPF_FORCE_INLINE
  195. #endif
  196. #if (NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1) || \
  197. (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1)
  198. enum {
  199. NPF_FMT_SPEC_OPT_NONE,
  200. NPF_FMT_SPEC_OPT_LITERAL,
  201. NPF_FMT_SPEC_OPT_STAR,
  202. };
  203. #endif
  204. enum {
  205. NPF_FMT_SPEC_LEN_MOD_NONE,
  206. #if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1
  207. NPF_FMT_SPEC_LEN_MOD_SHORT, // 'h'
  208. NPF_FMT_SPEC_LEN_MOD_CHAR, // 'hh'
  209. #endif
  210. NPF_FMT_SPEC_LEN_MOD_LONG, // 'l'
  211. NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE, // 'L'
  212. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  213. NPF_FMT_SPEC_LEN_MOD_LARGE_LONG_LONG, // 'll'
  214. NPF_FMT_SPEC_LEN_MOD_LARGE_INTMAX, // 'j'
  215. NPF_FMT_SPEC_LEN_MOD_LARGE_SIZET, // 'z'
  216. NPF_FMT_SPEC_LEN_MOD_LARGE_PTRDIFFT, // 't'
  217. #endif
  218. };
  219. enum {
  220. NPF_FMT_SPEC_CONV_NONE,
  221. NPF_FMT_SPEC_CONV_PERCENT, // '%'
  222. NPF_FMT_SPEC_CONV_CHAR, // 'c'
  223. NPF_FMT_SPEC_CONV_STRING, // 's'
  224. NPF_FMT_SPEC_CONV_SIGNED_INT, // 'i', 'd'
  225. #if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
  226. NPF_FMT_SPEC_CONV_BINARY, // 'b'
  227. #endif
  228. NPF_FMT_SPEC_CONV_OCTAL, // 'o'
  229. NPF_FMT_SPEC_CONV_HEX_INT, // 'x', 'X'
  230. NPF_FMT_SPEC_CONV_UNSIGNED_INT, // 'u'
  231. NPF_FMT_SPEC_CONV_POINTER, // 'p'
  232. #if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1
  233. NPF_FMT_SPEC_CONV_WRITEBACK, // 'n'
  234. #endif
  235. #if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
  236. NPF_FMT_SPEC_CONV_FLOAT_DEC, // 'f', 'F'
  237. NPF_FMT_SPEC_CONV_FLOAT_SCI, // 'e', 'E'
  238. NPF_FMT_SPEC_CONV_FLOAT_SHORTEST, // 'g', 'G'
  239. NPF_FMT_SPEC_CONV_FLOAT_HEX, // 'a', 'A'
  240. #endif
  241. };
  242. typedef struct npf_format_spec {
  243. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  244. int field_width;
  245. #endif
  246. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  247. int prec;
  248. uint8_t prec_opt;
  249. #endif
  250. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  251. uint8_t field_width_opt;
  252. char left_justified; // '-'
  253. char leading_zero_pad; // '0'
  254. #endif
  255. char prepend; // ' ' or '+'
  256. #if NANOPRINTF_USE_ALT_FORM_FLAG == 1
  257. char alt_form; // '#'
  258. #endif
  259. char case_adjust; // 'a' - 'A' , or 0 (must be non-negative to work)
  260. uint8_t length_modifier;
  261. uint8_t conv_spec;
  262. } npf_format_spec_t;
  263. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 0
  264. typedef long npf_int_t;
  265. typedef unsigned long npf_uint_t;
  266. #else
  267. typedef intmax_t npf_int_t;
  268. typedef uintmax_t npf_uint_t;
  269. #endif
  270. typedef struct npf_bufputc_ctx {
  271. char *dst;
  272. size_t len;
  273. size_t cur;
  274. } npf_bufputc_ctx_t;
  275. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  276. typedef char npf_size_is_ptrdiff[(sizeof(size_t) == sizeof(ptrdiff_t)) ? 1 : -1];
  277. typedef ptrdiff_t npf_ssize_t;
  278. typedef size_t npf_uptrdiff_t;
  279. #endif
  280. #ifdef _MSC_VER
  281. #include <intrin.h>
  282. #endif
  283. #define NPF_MIN(x, y) ((x) <= (y) ? (x) : (y))
  284. #define NPF_MAX(x, y) ((x) >= (y) ? (x) : (y))
  285. static int npf_parse_format_spec(char const *format, npf_format_spec_t *out_spec) {
  286. char const *cur = format;
  287. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  288. out_spec->left_justified = 0;
  289. out_spec->leading_zero_pad = 0;
  290. #endif
  291. out_spec->case_adjust = 'a' - 'A'; // lowercase
  292. out_spec->prepend = 0;
  293. #if NANOPRINTF_USE_ALT_FORM_FLAG == 1
  294. out_spec->alt_form = 0;
  295. #endif
  296. while (*++cur) { // cur points at the leading '%' character
  297. switch (*cur) { // Optional flags
  298. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  299. case '-': out_spec->left_justified = '-'; out_spec->leading_zero_pad = 0; continue;
  300. case '0': out_spec->leading_zero_pad = !out_spec->left_justified; continue;
  301. #endif
  302. case '+': out_spec->prepend = '+'; continue;
  303. case ' ': if (out_spec->prepend == 0) { out_spec->prepend = ' '; } continue;
  304. #if NANOPRINTF_USE_ALT_FORM_FLAG == 1
  305. case '#': out_spec->alt_form = '#'; continue;
  306. #endif
  307. default: break;
  308. }
  309. break;
  310. }
  311. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  312. out_spec->field_width = 0;
  313. out_spec->field_width_opt = NPF_FMT_SPEC_OPT_NONE;
  314. if (*cur == '*') {
  315. out_spec->field_width_opt = NPF_FMT_SPEC_OPT_STAR;
  316. ++cur;
  317. } else {
  318. while ((*cur >= '0') && (*cur <= '9')) {
  319. out_spec->field_width_opt = NPF_FMT_SPEC_OPT_LITERAL;
  320. out_spec->field_width = (out_spec->field_width * 10) + (*cur++ - '0');
  321. }
  322. }
  323. #endif
  324. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  325. out_spec->prec = 0;
  326. out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
  327. if (*cur == '.') {
  328. ++cur;
  329. if (*cur == '*') {
  330. out_spec->prec_opt = NPF_FMT_SPEC_OPT_STAR;
  331. ++cur;
  332. } else {
  333. if (*cur == '-') {
  334. ++cur;
  335. } else {
  336. out_spec->prec_opt = NPF_FMT_SPEC_OPT_LITERAL;
  337. }
  338. while ((*cur >= '0') && (*cur <= '9')) {
  339. out_spec->prec = (out_spec->prec * 10) + (*cur++ - '0');
  340. }
  341. }
  342. }
  343. #endif
  344. uint_fast8_t tmp_conv = NPF_FMT_SPEC_CONV_NONE;
  345. out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_NONE;
  346. switch (*cur++) { // Length modifier
  347. #if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1
  348. case 'h':
  349. out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_SHORT;
  350. if (*cur == 'h') {
  351. out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_CHAR;
  352. ++cur;
  353. }
  354. break;
  355. #endif
  356. case 'l':
  357. out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LONG;
  358. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  359. if (*cur == 'l') {
  360. out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_LONG_LONG;
  361. ++cur;
  362. }
  363. #endif
  364. break;
  365. #if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
  366. case 'L': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE; break;
  367. #endif
  368. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  369. case 'j': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_INTMAX; break;
  370. case 'z': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_SIZET; break;
  371. case 't': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_PTRDIFFT; break;
  372. #endif
  373. default: --cur; break;
  374. }
  375. switch (*cur++) { // Conversion specifier
  376. case '%': out_spec->conv_spec = NPF_FMT_SPEC_CONV_PERCENT;
  377. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  378. out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
  379. out_spec->prec = 0;
  380. #endif
  381. break;
  382. case 'c': out_spec->conv_spec = NPF_FMT_SPEC_CONV_CHAR;
  383. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  384. out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
  385. out_spec->prec = 0;
  386. #endif
  387. break;
  388. case 's': out_spec->conv_spec = NPF_FMT_SPEC_CONV_STRING;
  389. break;
  390. case 'i':
  391. case 'd': tmp_conv = NPF_FMT_SPEC_CONV_SIGNED_INT; goto finish;
  392. case 'o': tmp_conv = NPF_FMT_SPEC_CONV_OCTAL; goto finish;
  393. case 'u': tmp_conv = NPF_FMT_SPEC_CONV_UNSIGNED_INT; goto finish;
  394. case 'X': out_spec->case_adjust = 0;
  395. case 'x': tmp_conv = NPF_FMT_SPEC_CONV_HEX_INT; goto finish;
  396. finish:
  397. out_spec->conv_spec = (uint8_t)tmp_conv;
  398. #if (NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1) && \
  399. (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1)
  400. if (out_spec->prec_opt != NPF_FMT_SPEC_OPT_NONE) { out_spec->leading_zero_pad = 0; }
  401. #endif
  402. break;
  403. #if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
  404. case 'F': out_spec->case_adjust = 0;
  405. case 'f':
  406. out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_DEC;
  407. if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
  408. break;
  409. case 'E': out_spec->case_adjust = 0;
  410. case 'e':
  411. out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_SCI;
  412. if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
  413. break;
  414. case 'G': out_spec->case_adjust = 0;
  415. case 'g':
  416. out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_SHORTEST;
  417. if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
  418. break;
  419. case 'A': out_spec->case_adjust = 0;
  420. case 'a':
  421. out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_HEX;
  422. if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
  423. break;
  424. #endif
  425. #if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1
  426. case 'n':
  427. // todo: reject string if flags or width or precision exist
  428. out_spec->conv_spec = NPF_FMT_SPEC_CONV_WRITEBACK;
  429. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  430. out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
  431. #endif
  432. break;
  433. #endif
  434. case 'p':
  435. out_spec->conv_spec = NPF_FMT_SPEC_CONV_POINTER;
  436. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  437. out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
  438. #endif
  439. break;
  440. #if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
  441. case 'B':
  442. out_spec->case_adjust = 0;
  443. case 'b':
  444. out_spec->conv_spec = NPF_FMT_SPEC_CONV_BINARY;
  445. break;
  446. #endif
  447. default: return 0;
  448. }
  449. return (int)(cur - format);
  450. }
  451. static NPF_NOINLINE int npf_utoa_rev(
  452. npf_uint_t val, char *buf, uint_fast8_t base, char case_adj) {
  453. uint_fast8_t n = 0;
  454. do {
  455. int_fast8_t const d = (int_fast8_t)(val % base);
  456. *buf++ = (char)(((d < 10) ? '0' : ('A' - 10 + case_adj)) + d);
  457. ++n;
  458. val /= base;
  459. } while (val);
  460. return (int)n;
  461. }
  462. #if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
  463. #include <float.h>
  464. #if (DBL_MANT_DIG <= 11) && (DBL_MAX_EXP <= 16)
  465. typedef uint_fast16_t npf_double_bin_t;
  466. typedef int_fast8_t npf_ftoa_exp_t;
  467. #elif (DBL_MANT_DIG <= 24) && (DBL_MAX_EXP <= 128)
  468. typedef uint_fast32_t npf_double_bin_t;
  469. typedef int_fast8_t npf_ftoa_exp_t;
  470. #elif (DBL_MANT_DIG <= 53) && (DBL_MAX_EXP <= 1024)
  471. typedef uint_fast64_t npf_double_bin_t;
  472. typedef int_fast16_t npf_ftoa_exp_t;
  473. #else
  474. #error Unsupported width of the double type.
  475. #endif
  476. // The floating point conversion code works with an unsigned integer type of any size.
  477. #ifndef NANOPRINTF_CONVERSION_FLOAT_TYPE
  478. #define NANOPRINTF_CONVERSION_FLOAT_TYPE unsigned int
  479. #endif
  480. typedef NANOPRINTF_CONVERSION_FLOAT_TYPE npf_ftoa_man_t;
  481. #if (NANOPRINTF_CONVERSION_BUFFER_SIZE <= UINT_FAST8_MAX) && (UINT_FAST8_MAX <= INT_MAX)
  482. typedef uint_fast8_t npf_ftoa_dec_t;
  483. #else
  484. typedef int npf_ftoa_dec_t;
  485. #endif
  486. enum {
  487. NPF_DOUBLE_EXP_MASK = DBL_MAX_EXP * 2 - 1,
  488. NPF_DOUBLE_EXP_BIAS = DBL_MAX_EXP - 1,
  489. NPF_DOUBLE_MAN_BITS = DBL_MANT_DIG - 1,
  490. NPF_DOUBLE_BIN_BITS = sizeof(npf_double_bin_t) * CHAR_BIT,
  491. NPF_DOUBLE_SIGN_POS = sizeof(double) * CHAR_BIT - 1,
  492. NPF_FTOA_MAN_BITS = sizeof(npf_ftoa_man_t) * CHAR_BIT,
  493. NPF_FTOA_SHIFT_BITS =
  494. ((NPF_FTOA_MAN_BITS < DBL_MANT_DIG) ? NPF_FTOA_MAN_BITS : DBL_MANT_DIG) - 1
  495. };
  496. /* Generally, floating-point conversion implementations use
  497. grisu2 (https://bit.ly/2JgMggX) and ryu (https://bit.ly/2RLXSg0) algorithms,
  498. which are mathematically exact and fast, but require large lookup tables.
  499. This implementation was inspired by Wojciech Muła's (zdję[email protected])
  500. algorithm (http://0x80.pl/notesen/2015-12-29-float-to-string.html) and
  501. extended further by adding dynamic scaling and configurable integer width by
  502. Oskars Rubenis (https://github.com/Okarss). */
  503. static NPF_FORCE_INLINE npf_double_bin_t npf_double_to_int_rep(double f) {
  504. // Union-cast is UB pre-C11 and in all C++; the compiler optimizes the code below.
  505. npf_double_bin_t bin;
  506. char const *src = (char const *)&f;
  507. char *dst = (char *)&bin;
  508. for (uint_fast8_t i = 0; i < sizeof(f); ++i) { dst[i] = src[i]; }
  509. return bin;
  510. }
  511. static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) {
  512. char const *ret = NULL;
  513. npf_double_bin_t bin = npf_double_to_int_rep(f);
  514. // Unsigned -> signed int casting is IB and can raise a signal but generally doesn't.
  515. npf_ftoa_exp_t exp =
  516. (npf_ftoa_exp_t)((npf_ftoa_exp_t)(bin >> NPF_DOUBLE_MAN_BITS) & NPF_DOUBLE_EXP_MASK);
  517. bin &= ((npf_double_bin_t)0x1 << NPF_DOUBLE_MAN_BITS) - 1;
  518. if (exp == (npf_ftoa_exp_t)NPF_DOUBLE_EXP_MASK) { // special value
  519. ret = (bin) ? "NAN" : "FNI";
  520. goto exit;
  521. }
  522. if (spec->prec > (NANOPRINTF_CONVERSION_BUFFER_SIZE - 2)) { goto exit; }
  523. if (exp) { // normal number
  524. bin |= (npf_double_bin_t)0x1 << NPF_DOUBLE_MAN_BITS;
  525. } else { // subnormal number
  526. ++exp;
  527. }
  528. exp = (npf_ftoa_exp_t)(exp - NPF_DOUBLE_EXP_BIAS);
  529. uint_fast8_t carry; carry = 0;
  530. npf_ftoa_dec_t end, dec; dec = (npf_ftoa_dec_t)spec->prec;
  531. if (dec
  532. #if NANOPRINTF_USE_ALT_FORM_FLAG == 1
  533. || spec->alt_form
  534. #endif
  535. ) {
  536. buf[dec++] = '.';
  537. }
  538. { // Integer part
  539. npf_ftoa_man_t man_i;
  540. if (exp >= 0) {
  541. int_fast8_t shift_i =
  542. (int_fast8_t)((exp > NPF_FTOA_SHIFT_BITS) ? (int)NPF_FTOA_SHIFT_BITS : exp);
  543. npf_ftoa_exp_t exp_i = (npf_ftoa_exp_t)(exp - shift_i);
  544. shift_i = (int_fast8_t)(NPF_DOUBLE_MAN_BITS - shift_i);
  545. man_i = (npf_ftoa_man_t)(bin >> shift_i);
  546. if (exp_i) {
  547. if (shift_i) {
  548. carry = (bin >> (shift_i - 1)) & 0x1;
  549. }
  550. exp = NPF_DOUBLE_MAN_BITS; // invalidate the fraction part
  551. }
  552. // Scale the exponent from base-2 to base-10.
  553. for (; exp_i; --exp_i) {
  554. if (!(man_i & ((npf_ftoa_man_t)0x1 << (NPF_FTOA_MAN_BITS - 1)))) {
  555. man_i = (npf_ftoa_man_t)(man_i << 1);
  556. man_i = (npf_ftoa_man_t)(man_i | carry); carry = 0;
  557. } else {
  558. if (dec >= NANOPRINTF_CONVERSION_BUFFER_SIZE) { goto exit; }
  559. buf[dec++] = '0';
  560. carry = (((uint_fast8_t)(man_i % 5) + carry) > 2);
  561. man_i /= 5;
  562. }
  563. }
  564. } else {
  565. man_i = 0;
  566. }
  567. end = dec;
  568. do { // Print the integer
  569. if (end >= NANOPRINTF_CONVERSION_BUFFER_SIZE) { goto exit; }
  570. buf[end++] = (char)('0' + (char)(man_i % 10));
  571. man_i /= 10;
  572. } while (man_i);
  573. }
  574. { // Fraction part
  575. npf_ftoa_man_t man_f;
  576. npf_ftoa_dec_t dec_f = (npf_ftoa_dec_t)spec->prec;
  577. if (exp < NPF_DOUBLE_MAN_BITS) {
  578. int_fast8_t shift_f = (int_fast8_t)((exp < 0) ? -1 : exp);
  579. npf_ftoa_exp_t exp_f = (npf_ftoa_exp_t)(exp - shift_f);
  580. npf_double_bin_t bin_f =
  581. bin << ((NPF_DOUBLE_BIN_BITS - NPF_DOUBLE_MAN_BITS) + shift_f);
  582. // This if-else statement can be completely optimized at compile time.
  583. if (NPF_DOUBLE_BIN_BITS > NPF_FTOA_MAN_BITS) {
  584. man_f = (npf_ftoa_man_t)(bin_f >> ((unsigned)(NPF_DOUBLE_BIN_BITS -
  585. NPF_FTOA_MAN_BITS) %
  586. NPF_DOUBLE_BIN_BITS));
  587. carry = (uint_fast8_t)((bin_f >> ((unsigned)(NPF_DOUBLE_BIN_BITS -
  588. NPF_FTOA_MAN_BITS - 1) %
  589. NPF_DOUBLE_BIN_BITS)) & 0x1);
  590. } else {
  591. man_f = (npf_ftoa_man_t)((npf_ftoa_man_t)bin_f
  592. << ((unsigned)(NPF_FTOA_MAN_BITS -
  593. NPF_DOUBLE_BIN_BITS) % NPF_FTOA_MAN_BITS));
  594. carry = 0;
  595. }
  596. // Scale the exponent from base-2 to base-10 and prepare the first digit.
  597. for (uint_fast8_t digit = 0; dec_f && (exp_f < 4); ++exp_f) {
  598. if ((man_f > ((npf_ftoa_man_t)-4 / 5)) || digit) {
  599. carry = (uint_fast8_t)(man_f & 0x1);
  600. man_f = (npf_ftoa_man_t)(man_f >> 1);
  601. } else {
  602. man_f = (npf_ftoa_man_t)(man_f * 5);
  603. if (carry) { man_f = (npf_ftoa_man_t)(man_f + 3); carry = 0; }
  604. if (exp_f < 0) {
  605. buf[--dec_f] = '0';
  606. } else {
  607. ++digit;
  608. }
  609. }
  610. }
  611. man_f = (npf_ftoa_man_t)(man_f + carry);
  612. carry = (exp_f >= 0);
  613. dec = 0;
  614. } else {
  615. man_f = 0;
  616. }
  617. if (dec_f) {
  618. // Print the fraction
  619. for (;;) {
  620. buf[--dec_f] = (char)('0' + (char)(man_f >> (NPF_FTOA_MAN_BITS - 4)));
  621. man_f = (npf_ftoa_man_t)(man_f & ~((npf_ftoa_man_t)0xF << (NPF_FTOA_MAN_BITS - 4)));
  622. if (!dec_f) { break; }
  623. man_f = (npf_ftoa_man_t)(man_f * 10);
  624. }
  625. man_f = (npf_ftoa_man_t)(man_f << 4);
  626. }
  627. if (exp < NPF_DOUBLE_MAN_BITS) {
  628. carry &= (uint_fast8_t)(man_f >> (NPF_FTOA_MAN_BITS - 1));
  629. }
  630. }
  631. // Round the number
  632. for (; carry; ++dec) {
  633. if (dec >= NANOPRINTF_CONVERSION_BUFFER_SIZE) { goto exit; }
  634. if (dec >= end) { buf[end++] = '0'; }
  635. if (buf[dec] == '.') { continue; }
  636. carry = (buf[dec] == '9');
  637. buf[dec] = (char)(carry ? '0' : (buf[dec] + 1));
  638. }
  639. return (int)end;
  640. exit:
  641. if (!ret) { ret = "RRE"; }
  642. uint_fast8_t i;
  643. for (i = 0; ret[i]; ++i) { buf[i] = (char)(ret[i] + spec->case_adjust); }
  644. return -(int)i;
  645. }
  646. #endif // NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS
  647. #if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
  648. static int npf_bin_len(npf_uint_t u) {
  649. // Return the length of the binary string format of 'u', preferring intrinsics.
  650. if (!u) { return 1; }
  651. #ifdef _MSC_VER // Win64, use _BSR64 for everything. If x86, use _BSR when non-large.
  652. #ifdef _M_X64
  653. #define NPF_HAVE_BUILTIN_CLZ
  654. #define NPF_CLZ _BitScanReverse64
  655. #elif NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 0
  656. #define NPF_HAVE_BUILTIN_CLZ
  657. #define NPF_CLZ _BitScanReverse
  658. #endif
  659. #ifdef NPF_HAVE_BUILTIN_CLZ
  660. unsigned long idx;
  661. NPF_CLZ(&idx, u);
  662. return (int)(idx + 1);
  663. #endif
  664. #elif NPF_CLANG || NPF_GCC_PAST_4_6
  665. #define NPF_HAVE_BUILTIN_CLZ
  666. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  667. #define NPF_CLZ(X) ((sizeof(long long) * CHAR_BIT) - (size_t)__builtin_clzll(X))
  668. #else
  669. #define NPF_CLZ(X) ((sizeof(long) * CHAR_BIT) - (size_t)__builtin_clzl(X))
  670. #endif
  671. return (int)NPF_CLZ(u);
  672. #endif
  673. #ifndef NPF_HAVE_BUILTIN_CLZ
  674. int n;
  675. for (n = 0; u; ++n, u >>= 1); // slow but small software fallback
  676. return n;
  677. #else
  678. #undef NPF_HAVE_BUILTIN_CLZ
  679. #undef NPF_CLZ
  680. #endif
  681. }
  682. #endif
  683. static void npf_bufputc(int c, void *ctx) {
  684. npf_bufputc_ctx_t *bpc = (npf_bufputc_ctx_t *)ctx;
  685. if (bpc->cur < bpc->len) { bpc->dst[bpc->cur++] = (char)c; }
  686. }
  687. static void npf_bufputc_nop(int c, void *ctx) { (void)c; (void)ctx; }
  688. typedef struct npf_cnt_putc_ctx {
  689. npf_putc pc;
  690. void *ctx;
  691. int n;
  692. } npf_cnt_putc_ctx_t;
  693. static void npf_putc_cnt(int c, void *ctx) {
  694. npf_cnt_putc_ctx_t *pc_cnt = (npf_cnt_putc_ctx_t *)ctx;
  695. ++pc_cnt->n;
  696. pc_cnt->pc(c, pc_cnt->ctx); // sibling-call optimization
  697. }
  698. #define NPF_PUTC(VAL) do { npf_putc_cnt((int)(VAL), &pc_cnt); } while (0)
  699. #define NPF_EXTRACT(MOD, CAST_TO, EXTRACT_AS) \
  700. case NPF_FMT_SPEC_LEN_MOD_##MOD: val = (CAST_TO)va_arg(args, EXTRACT_AS); break
  701. #define NPF_WRITEBACK(MOD, TYPE) \
  702. case NPF_FMT_SPEC_LEN_MOD_##MOD: *(va_arg(args, TYPE *)) = (TYPE)pc_cnt.n; break
  703. int npf_vpprintf(npf_putc pc, void *pc_ctx, char const *format, va_list args) {
  704. npf_format_spec_t fs;
  705. char const *cur = format;
  706. npf_cnt_putc_ctx_t pc_cnt;
  707. pc_cnt.pc = pc;
  708. pc_cnt.ctx = pc_ctx;
  709. pc_cnt.n = 0;
  710. while (*cur) {
  711. int const fs_len = (*cur != '%') ? 0 : npf_parse_format_spec(cur, &fs);
  712. if (!fs_len) { NPF_PUTC(*cur++); continue; }
  713. cur += fs_len;
  714. // Extract star-args immediately
  715. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  716. if (fs.field_width_opt == NPF_FMT_SPEC_OPT_STAR) {
  717. fs.field_width = va_arg(args, int);
  718. if (fs.field_width < 0) {
  719. fs.field_width = -fs.field_width;
  720. fs.left_justified = 1;
  721. }
  722. }
  723. #endif
  724. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  725. if (fs.prec_opt == NPF_FMT_SPEC_OPT_STAR) {
  726. fs.prec = va_arg(args, int);
  727. if (fs.prec < 0) { fs.prec_opt = NPF_FMT_SPEC_OPT_NONE; }
  728. }
  729. #endif
  730. union { char cbuf_mem[NANOPRINTF_CONVERSION_BUFFER_SIZE]; npf_uint_t binval; } u;
  731. char *cbuf = u.cbuf_mem, sign_c = 0;
  732. int cbuf_len = 0;
  733. char need_0x = 0;
  734. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  735. int field_pad = 0;
  736. char pad_c = 0;
  737. #endif
  738. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  739. int prec_pad = 0;
  740. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  741. uint_fast8_t zero = 0;
  742. #endif
  743. #endif
  744. // Extract and convert the argument to string, point cbuf at the text.
  745. switch (fs.conv_spec) {
  746. case NPF_FMT_SPEC_CONV_PERCENT:
  747. *cbuf = '%';
  748. cbuf_len = 1;
  749. break;
  750. case NPF_FMT_SPEC_CONV_CHAR:
  751. *cbuf = (char)va_arg(args, int);
  752. cbuf_len = (*cbuf) ? 1 : 0;
  753. break;
  754. case NPF_FMT_SPEC_CONV_STRING: {
  755. cbuf = va_arg(args, char *);
  756. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  757. for (char const *s = cbuf;
  758. ((fs.prec_opt == NPF_FMT_SPEC_OPT_NONE) || (cbuf_len < fs.prec)) && cbuf && *s;
  759. ++s, ++cbuf_len);
  760. #else
  761. for (char const *s = cbuf; cbuf && *s; ++s, ++cbuf_len); // strlen
  762. #endif
  763. } break;
  764. case NPF_FMT_SPEC_CONV_SIGNED_INT: {
  765. npf_int_t val = 0;
  766. switch (fs.length_modifier) {
  767. NPF_EXTRACT(NONE, int, int);
  768. #if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1
  769. NPF_EXTRACT(SHORT, short, int);
  770. NPF_EXTRACT(CHAR, signed char, int);
  771. #endif
  772. NPF_EXTRACT(LONG, long, long);
  773. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  774. NPF_EXTRACT(LARGE_LONG_LONG, long long, long long);
  775. NPF_EXTRACT(LARGE_INTMAX, intmax_t, intmax_t);
  776. NPF_EXTRACT(LARGE_SIZET, npf_ssize_t, npf_ssize_t);
  777. NPF_EXTRACT(LARGE_PTRDIFFT, ptrdiff_t, ptrdiff_t);
  778. #endif
  779. default: break;
  780. }
  781. sign_c = (val < 0) ? '-' : fs.prepend;
  782. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  783. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  784. zero = !val;
  785. #endif
  786. // special case, if prec and value are 0, skip
  787. if (!val && (fs.prec_opt != NPF_FMT_SPEC_OPT_NONE) && !fs.prec) {
  788. cbuf_len = 0;
  789. } else
  790. #endif
  791. {
  792. npf_uint_t uval = (npf_uint_t)val;
  793. if (val < 0) { uval = 0 - uval; }
  794. cbuf_len = npf_utoa_rev(uval, cbuf, 10, fs.case_adjust);
  795. }
  796. } break;
  797. #if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
  798. case NPF_FMT_SPEC_CONV_BINARY:
  799. #endif
  800. case NPF_FMT_SPEC_CONV_OCTAL:
  801. case NPF_FMT_SPEC_CONV_HEX_INT:
  802. case NPF_FMT_SPEC_CONV_UNSIGNED_INT:
  803. case NPF_FMT_SPEC_CONV_POINTER: {
  804. npf_uint_t val = 0;
  805. if (fs.conv_spec == NPF_FMT_SPEC_CONV_POINTER) {
  806. val = (npf_uint_t)(uintptr_t)va_arg(args, void *);
  807. } else {
  808. switch (fs.length_modifier) {
  809. NPF_EXTRACT(NONE, unsigned, unsigned);
  810. #if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1
  811. NPF_EXTRACT(SHORT, unsigned short, unsigned);
  812. NPF_EXTRACT(CHAR, unsigned char, unsigned);
  813. #endif
  814. NPF_EXTRACT(LONG, unsigned long, unsigned long);
  815. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  816. NPF_EXTRACT(LARGE_LONG_LONG, unsigned long long, unsigned long long);
  817. NPF_EXTRACT(LARGE_INTMAX, uintmax_t, uintmax_t);
  818. NPF_EXTRACT(LARGE_SIZET, size_t, size_t);
  819. NPF_EXTRACT(LARGE_PTRDIFFT, npf_uptrdiff_t, npf_uptrdiff_t);
  820. #endif
  821. default: break;
  822. }
  823. }
  824. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  825. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  826. zero = !val;
  827. #endif
  828. if (!val && (fs.prec_opt != NPF_FMT_SPEC_OPT_NONE) && !fs.prec) {
  829. // Zero value and explicitly-requested zero precision means "print nothing".
  830. #if NANOPRINTF_USE_ALT_FORM_FLAG == 1
  831. if ((fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL) && fs.alt_form) {
  832. fs.prec = 1; // octal special case, print a single '0'
  833. }
  834. #endif
  835. } else
  836. #endif
  837. #if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
  838. if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) {
  839. cbuf_len = npf_bin_len(val); u.binval = val;
  840. } else
  841. #endif
  842. {
  843. uint_fast8_t const base = (fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL) ?
  844. 8u : ((fs.conv_spec == NPF_FMT_SPEC_CONV_UNSIGNED_INT) ? 10u : 16u);
  845. cbuf_len = npf_utoa_rev(val, cbuf, base, fs.case_adjust);
  846. }
  847. #if NANOPRINTF_USE_ALT_FORM_FLAG == 1
  848. if (val && fs.alt_form && (fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL)) {
  849. cbuf[cbuf_len++] = '0'; // OK to add leading octal '0' immediately.
  850. }
  851. if (val && fs.alt_form) { // 0x or 0b but can't write it yet.
  852. if ((fs.conv_spec == NPF_FMT_SPEC_CONV_HEX_INT) ||
  853. (fs.conv_spec == NPF_FMT_SPEC_CONV_POINTER)) { need_0x = 'X'; }
  854. #if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
  855. else if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) { need_0x = 'B'; }
  856. #endif
  857. if (need_0x) { need_0x = (char)(need_0x + fs.case_adjust); }
  858. }
  859. #endif
  860. } break;
  861. #if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1
  862. case NPF_FMT_SPEC_CONV_WRITEBACK:
  863. switch (fs.length_modifier) {
  864. NPF_WRITEBACK(NONE, int);
  865. #if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1
  866. NPF_WRITEBACK(SHORT, short);
  867. NPF_WRITEBACK(CHAR, signed char);
  868. #endif
  869. NPF_WRITEBACK(LONG, long);
  870. #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
  871. NPF_WRITEBACK(LARGE_LONG_LONG, long long);
  872. NPF_WRITEBACK(LARGE_INTMAX, intmax_t);
  873. NPF_WRITEBACK(LARGE_SIZET, npf_ssize_t);
  874. NPF_WRITEBACK(LARGE_PTRDIFFT, ptrdiff_t);
  875. #endif
  876. default: break;
  877. } break;
  878. #endif
  879. #if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
  880. case NPF_FMT_SPEC_CONV_FLOAT_DEC:
  881. case NPF_FMT_SPEC_CONV_FLOAT_SCI:
  882. case NPF_FMT_SPEC_CONV_FLOAT_SHORTEST:
  883. case NPF_FMT_SPEC_CONV_FLOAT_HEX: {
  884. double val;
  885. if (fs.length_modifier == NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE) {
  886. val = (double)va_arg(args, long double);
  887. } else {
  888. val = va_arg(args, double);
  889. }
  890. sign_c = (npf_double_to_int_rep(val) >> NPF_DOUBLE_SIGN_POS) ? '-' : fs.prepend;
  891. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  892. zero = (val == 0.);
  893. #endif
  894. cbuf_len = npf_ftoa_rev(cbuf, &fs, val);
  895. if (cbuf_len < 0) { // negative means text (not number), so ignore the '0' flag
  896. cbuf_len = -cbuf_len;
  897. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  898. fs.leading_zero_pad = 0;
  899. #endif
  900. }
  901. } break;
  902. #endif
  903. default: break;
  904. }
  905. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  906. // Compute the field width pad character
  907. if (fs.field_width_opt != NPF_FMT_SPEC_OPT_NONE) {
  908. if (fs.leading_zero_pad) {
  909. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  910. if ((fs.prec_opt != NPF_FMT_SPEC_OPT_NONE) && !fs.prec && zero) {
  911. pad_c = ' ';
  912. } else
  913. #endif
  914. { pad_c = '0'; }
  915. } else { pad_c = ' '; }
  916. }
  917. #endif
  918. // Compute the number of bytes to truncate or '0'-pad.
  919. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  920. if (fs.conv_spec != NPF_FMT_SPEC_CONV_STRING) {
  921. #if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
  922. // float precision is after the decimal point
  923. if ((fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_DEC) &&
  924. (fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_SCI) &&
  925. (fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_SHORTEST) &&
  926. (fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_HEX))
  927. #endif
  928. { prec_pad = NPF_MAX(0, fs.prec - cbuf_len); }
  929. }
  930. #endif
  931. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  932. // Given the full converted length, how many pad bytes?
  933. field_pad = fs.field_width - cbuf_len - !!sign_c;
  934. if (need_0x) { field_pad -= 2; }
  935. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  936. field_pad -= prec_pad;
  937. #endif
  938. field_pad = NPF_MAX(0, field_pad);
  939. // Apply right-justified field width if requested
  940. if (!fs.left_justified && pad_c) { // If leading zeros pad, sign goes first.
  941. if (pad_c == '0') {
  942. if (sign_c) { NPF_PUTC(sign_c); sign_c = 0; }
  943. // Pad byte is '0', write '0x' before '0' pad chars.
  944. if (need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); }
  945. }
  946. while (field_pad-- > 0) { NPF_PUTC(pad_c); }
  947. // Pad byte is ' ', write '0x' after ' ' pad chars but before number.
  948. if ((pad_c != '0') && need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); }
  949. } else
  950. #endif
  951. { if (need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); } } // no pad, '0x' requested.
  952. // Write the converted payload
  953. if (fs.conv_spec == NPF_FMT_SPEC_CONV_STRING) {
  954. for (int i = 0; cbuf && (i < cbuf_len); ++i) { NPF_PUTC(cbuf[i]); }
  955. } else {
  956. if (sign_c) { NPF_PUTC(sign_c); }
  957. #if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
  958. while (prec_pad-- > 0) { NPF_PUTC('0'); } // int precision leads.
  959. #endif
  960. #if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
  961. if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) {
  962. while (cbuf_len) { NPF_PUTC('0' + ((u.binval >> --cbuf_len) & 1)); }
  963. } else
  964. #endif
  965. { while (cbuf_len-- > 0) { NPF_PUTC(cbuf[cbuf_len]); } } // payload is reversed
  966. }
  967. #if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
  968. if (fs.left_justified && pad_c) { // Apply left-justified field width
  969. while (field_pad-- > 0) { NPF_PUTC(pad_c); }
  970. }
  971. #endif
  972. }
  973. return pc_cnt.n;
  974. }
  975. #undef NPF_PUTC
  976. #undef NPF_EXTRACT
  977. #undef NPF_WRITEBACK
  978. int npf_pprintf(npf_putc pc,
  979. void * NPF_RESTRICT pc_ctx,
  980. char const * NPF_RESTRICT format,
  981. ...) {
  982. va_list val;
  983. va_start(val, format);
  984. int const rv = npf_vpprintf(pc, pc_ctx, format, val);
  985. va_end(val);
  986. return rv;
  987. }
  988. int npf_snprintf(char * NPF_RESTRICT buffer,
  989. size_t bufsz,
  990. const char * NPF_RESTRICT format,
  991. ...) {
  992. va_list val;
  993. va_start(val, format);
  994. int const rv = npf_vsnprintf(buffer, bufsz, format, val);
  995. va_end(val);
  996. return rv;
  997. }
  998. int npf_vsnprintf(char * NPF_RESTRICT buffer,
  999. size_t bufsz,
  1000. char const * NPF_RESTRICT format,
  1001. va_list vlist) {
  1002. npf_bufputc_ctx_t bufputc_ctx;
  1003. bufputc_ctx.dst = buffer;
  1004. bufputc_ctx.len = bufsz;
  1005. bufputc_ctx.cur = 0;
  1006. npf_putc const pc = buffer ? npf_bufputc : npf_bufputc_nop;
  1007. int const n = npf_vpprintf(pc, &bufputc_ctx, format, vlist);
  1008. if (buffer && bufsz) {
  1009. #ifdef NANOPRINTF_SNPRINTF_SAFE_EMPTY_STRING_ON_OVERFLOW
  1010. buffer[(n < 0 || (unsigned)n >= bufsz) ? 0 : n] = '\0';
  1011. #else
  1012. buffer[n < 0 ? 0 : NPF_MIN((unsigned)n, bufsz - 1)] = '\0';
  1013. #endif
  1014. }
  1015. return n;
  1016. }
  1017. #if NPF_HAVE_GCC_WARNING_PRAGMAS
  1018. #pragma GCC diagnostic pop
  1019. #endif
  1020. #ifdef _MSC_VER
  1021. #pragma warning(pop)
  1022. #endif
  1023. #endif // NPF_IMPLEMENTATION_INCLUDED
  1024. #endif // NANOPRINTF_IMPLEMENTATION
  1025. /*
  1026. nanoprintf is dual-licensed under both the "Unlicense" and the
  1027. "Zero-Clause BSD" (0BSD) licenses. The intent of this dual-licensing
  1028. structure is to make nanoprintf as consumable as possible in as many
  1029. environments / countries / companies as possible without any
  1030. encumberances.
  1031. The text of the two licenses follows below:
  1032. ============================== UNLICENSE ==============================
  1033. This is free and unencumbered software released into the public domain.
  1034. Anyone is free to copy, modify, publish, use, compile, sell, or
  1035. distribute this software, either in source code form or as a compiled
  1036. binary, for any purpose, commercial or non-commercial, and by any
  1037. means.
  1038. In jurisdictions that recognize copyright laws, the author or authors
  1039. of this software dedicate any and all copyright interest in the
  1040. software to the public domain. We make this dedication for the benefit
  1041. of the public at large and to the detriment of our heirs and
  1042. successors. We intend this dedication to be an overt act of
  1043. relinquishment in perpetuity of all present and future rights to this
  1044. software under copyright law.
  1045. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  1046. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  1047. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  1048. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  1049. OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  1050. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  1051. OTHER DEALINGS IN THE SOFTWARE.
  1052. For more information, please refer to <http://unlicense.org>
  1053. ================================ 0BSD =================================
  1054. Copyright (C) 2019- by Charles Nicholson <[email protected]>
  1055. Permission to use, copy, modify, and/or distribute this software for
  1056. any purpose with or without fee is hereby granted.
  1057. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  1058. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  1059. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  1060. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  1061. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  1062. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  1063. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  1064. */