3 #ifndef _LIBCXXEXTRAS_PRINTF_
4 #define _LIBCXXEXTRAS_PRINTF_
13 class cprintf_toomanyargs:
14 public ::std::exception
17 class cprintf_toofewargs:
18 public ::std::exception
21 class cprintf_badformat:
22 public ::std::exception
26 cprintf_badformat(const char *reason):
30 const char* what() const noexcept override {
54 unsigned int precision;
58 constexpr PrintfFlags(PrintfFlags x, Left _): width(x.width), precision(x.precision), flags(x.flags | 1) {}
60 constexpr PrintfFlags(PrintfFlags x, Sign _): width(x.width), precision(x.precision), flags(x.flags | 2) {}
62 constexpr PrintfFlags(PrintfFlags x, Space _): width(x.width), precision(x.precision), flags(x.flags | 4) {}
64 constexpr PrintfFlags(PrintfFlags x, Alt _): width(x.width), precision(x.precision), flags(x.flags | 8) {}
66 constexpr PrintfFlags(PrintfFlags x, Zero _): width(x.width), precision(x.precision), flags(x.flags | 16) {}
69 constexpr PrintfFlags(PrintfFlags x, ArgWidth _, unsigned int v): width(v), precision(x.precision), flags(x.flags) {}
71 constexpr PrintfFlags(PrintfFlags x, ArgPrec _, unsigned int v): width(x.width), precision(v), flags(x.flags) {}
74 constexpr PrintfFlags(PrintfFlags x, FAuto _): width(x.width), precision(x.precision), flags(x.flags | 0x000) {}
76 constexpr PrintfFlags(PrintfFlags x, FString _): width(x.width), precision(x.precision), flags(x.flags | 0x100) {}
78 constexpr PrintfFlags(PrintfFlags x, FBool _): width(x.width), precision(x.precision), flags(x.flags | 0x200) {}
80 constexpr PrintfFlags(PrintfFlags x, FBinary _): width(x.width), precision(x.precision), flags(x.flags | 0x300) {}
82 constexpr PrintfFlags(PrintfFlags x, FOct _): width(x.width), precision(x.precision), flags(x.flags | 0x400) {}
84 constexpr PrintfFlags(PrintfFlags x, FUDec _): width(x.width), precision(x.precision), flags(x.flags | 0x500) {}
86 constexpr PrintfFlags(PrintfFlags x, FSDec _): width(x.width), precision(x.precision), flags(x.flags | 0x600) {}
88 constexpr PrintfFlags(PrintfFlags x, FHexL _): width(x.width), precision(x.precision), flags(x.flags | 0x700) {}
90 constexpr PrintfFlags(PrintfFlags x, FHexU _): width(x.width), precision(x.precision), flags(x.flags | 0x800) {}
92 constexpr PrintfFlags():
93 width(0), precision(0), flags(0)
100 unsigned int precision = 0;
101 unsigned int minLength = 0;
102 bool padLeft = false;
103 bool showSign = false;
104 bool showSpace = false;
105 bool altFormat = false;
106 bool padZero = false;
107 enum e_cprintf_type type;
111 constexpr bool isdigit_s(const char ch) {
112 return '0' <= ch && ch <= '9';
114 constexpr unsigned todigit(const char ch) {
119 }; // namespace _bits
121 typedef ::std::function<void(const char*,size_t)> cprintf_cb;
122 template <typename Arg> size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags &fmt, Arg arg);
123 template <typename Arg> constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, Arg arg);
125 constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, const char* arg) {
128 size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, const char* arg) {
130 for(len = 0; arg[len]; len ++)
135 constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, int arg) {
138 size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, int arg) {
139 size_t len = ::std::snprintf(nullptr, 0, "%i", arg);
141 ::std::snprintf(buf, len+1, "%i", arg);
145 constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, unsigned int arg) {
148 size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, unsigned int arg) {
149 size_t len = ::std::snprintf(nullptr, 0, "%u", arg);
151 ::std::snprintf(buf, len+1, "%u", arg);
160 template <unsigned N>
166 constexpr _str(const char buf[N]):
171 constexpr _str(const char buf[N], unsigned ofs):
176 constexpr _str<N> operator+(const unsigned o) {
177 return _str(m_buf, m_ofs+o);
179 constexpr char operator*() {
184 template <typename... Args>
185 constexpr bool val(const char* fmt, Args... args);
187 template <typename Fmt>
188 constexpr bool val_fmt_done(const char * fmt, PrintfFlags item, Fmt fmtcode)
190 return false ? false : throw "Too few arguments";
192 template <typename Fmt, typename Arg, typename... Args>
193 constexpr bool val_fmt_done(const char* fmt, PrintfFlags item, Fmt fmtcode, Arg arg, Args... args)
195 return cprintf_val_chk(item, arg) && val(fmt+1, args...);
198 template <typename ...Args>
199 constexpr bool val_fmt_fmt(const char * fmt, PrintfFlags item, Args... args)
201 return *fmt == '\0' ? throw "ERROR: NUL byte in format specifier"
202 : *fmt == '?' ? val_fmt_done(fmt, item, PrintfFlags::FAuto(), args...)
203 : *fmt == 's' ? val_fmt_done(fmt, item, PrintfFlags::FString(),args...)
204 : *fmt == 'B' ? val_fmt_done(fmt, item, PrintfFlags::FBool(), args...)
205 : *fmt == 'b' ? val_fmt_done(fmt, item, PrintfFlags::FBinary(),args...)
206 : *fmt == 'o' ? val_fmt_done(fmt, item, PrintfFlags::FOct(), args...)
207 : *fmt == 'i' ? val_fmt_done(fmt, item, PrintfFlags::FSDec(), args...)
208 : *fmt == 'u' ? val_fmt_done(fmt, item, PrintfFlags::FUDec(), args...)
209 : *fmt == 'x' ? val_fmt_done(fmt, item, PrintfFlags::FHexL(), args...)
210 : *fmt == 'X' ? val_fmt_done(fmt, item, PrintfFlags::FHexU(), args...)
211 : throw cprintf_badformat("Unknown character in format string");
213 // --- Size modifier (not implemented, not needed?)
214 template <typename ...Args>
215 constexpr bool val_fmt_size(const char * fmt, PrintfFlags item, Args... args)
217 // TODO: Size characters?
218 return val_fmt_fmt(fmt, item, args...);
221 template <typename ...Args>
222 constexpr bool val_fmt_prec_val(const char * fmt, unsigned int value, PrintfFlags item, Args... args)
224 return _bits::isdigit_s(*fmt) ? val_fmt_prec_val(fmt+1, value*10+_bits::todigit(*fmt), item, args...)
225 : val_fmt_size(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), value), args...);
227 template <typename ...Args>
228 constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args)
230 return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...);
232 template <typename Arg, typename ...Args>
233 constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, Arg size, Args... args)
235 //static_assert(false, "Invalid type for precision modifier, must be 'unsigned int'");
236 return false ? false : throw "Invalid type for precision modifier, must be 'unsigned int'";
238 constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item)
240 //static_assert(false, "Too few arguments when getting precision modifier");
241 return false ? false : throw "Too few arguments when getting precision modifier";
243 template <typename ...Args>
244 constexpr bool val_fmt_prec(const char * fmt, PrintfFlags item, Args... args)
246 return _bits::isdigit_s(*fmt) ? val_fmt_prec_val(fmt+1, _bits::todigit(*fmt), item, args...)
247 : *fmt == '*' ? val_fmt_prec_arg(fmt+1, item, args...)
248 : val_fmt_size(fmt, item, args...);
250 template <typename ...Args>
251 constexpr bool val_fmt_prec_opt(const char * fmt, PrintfFlags item, Args... args)
253 return *fmt == '.' ? val_fmt_prec(fmt+1, item, args...)
254 : val_fmt_size(fmt, item, args...);
256 // --- Field Width ---
257 template <typename ...Args>
258 constexpr bool val_fmt_width_val(const char* fmt, unsigned int size, PrintfFlags item, Args... args)
260 return _bits::isdigit_s(*fmt) ? val_fmt_width_val(fmt+1, size*10+_bits::todigit(*fmt), item, args...)
261 : val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
263 template <typename ...Args>
264 constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args)
266 return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
268 template <typename Arg, typename ...Args>
269 constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, Arg size, Args... args)
271 //static_assert(false, "Invalid type for width modifier, must be 'unsigned int'");
272 return false ? false : throw "Invalid type for width modifier, must be 'unsigned int'";
274 constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item)
276 //static_assert(false, "Too few arguments when reading width for width modifier");
277 return false ? false : throw "Too few arguments when reading width for width modifier";
279 template <typename ...Args>
280 constexpr bool val_fmt_width(const char * fmt, PrintfFlags item, Args... args)
282 return _bits::isdigit_s(*fmt) ? val_fmt_width_val(fmt+1, _bits::todigit(*fmt), item, args...)
283 : *fmt == '*' ? val_fmt_width_arg(fmt+1, item, args...)
284 : val_fmt_prec_opt(fmt, item, args...);
287 template <typename ...Args>
288 constexpr bool val_fmt_flags(const char * fmt, PrintfFlags item, Args... args)
291 *fmt == '-' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Left()) , args...)
292 : *fmt == '+' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Sign()) , args...)
293 : *fmt == ' ' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Space()), args...)
294 : *fmt == '#' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Alt()) , args...)
295 : *fmt == '0' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Zero()) , args...)
296 : val_fmt_width(fmt, item, args...);
299 template <typename ...Args>
300 constexpr bool val_fmt_start(const char* fmt, Args... args)
302 return *fmt == '%' ? val(fmt+1, args...) : val_fmt_flags(fmt, PrintfFlags(), args...);
304 template <typename... Args>
305 constexpr bool val(const char* fmt, Args... args)
307 return *fmt == '\0' ? true
308 : *fmt == '%' ? val_fmt_start(fmt+1, args...)
309 : val(fmt+1, args...);
312 size_t run(cprintf_cb puts, const char *fmt);
313 template <typename... Args> size_t run(cprintf_cb puts, const char * fmt, Args... args);
315 // --- Print formatted value
316 template <typename Fmt>
317 constexpr size_t run_fmt_done(cprintf_cb puts, const char * fmt, PrintfFlags item, Fmt fmtcode)
319 throw cprintf_toofewargs();
321 template <typename Fmt, typename Arg, typename... Args>
322 size_t run_fmt_done(cprintf_cb puts, const char * fmt, PrintfFlags item, Fmt fmtcode, Arg val, Args... args)
325 return run(puts, fmt+1, args...);
327 return ::cxxextras::cprintf_val(puts, PrintfFlags(item, fmtcode), val) + run(puts, fmt+1, args...);
330 template <typename ...Args>
331 size_t run_fmt_fmt(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
333 return *fmt == '\0' ? throw "ERROR: NUL byte in format specifier"
334 : *fmt == '?' ? run_fmt_done(puts, fmt, item, PrintfFlags::FAuto(), args...)
335 : *fmt == 's' ? run_fmt_done(puts, fmt, item, PrintfFlags::FString(),args...)
336 : *fmt == 'B' ? run_fmt_done(puts, fmt, item, PrintfFlags::FBool(), args...)
337 : *fmt == 'b' ? run_fmt_done(puts, fmt, item, PrintfFlags::FBinary(),args...)
338 : *fmt == 'o' ? run_fmt_done(puts, fmt, item, PrintfFlags::FOct(), args...)
339 : *fmt == 'i' ? run_fmt_done(puts, fmt, item, PrintfFlags::FSDec(), args...)
340 : *fmt == 'u' ? run_fmt_done(puts, fmt, item, PrintfFlags::FUDec(), args...)
341 : *fmt == 'x' ? run_fmt_done(puts, fmt, item, PrintfFlags::FHexL(), args...)
342 : *fmt == 'X' ? run_fmt_done(puts, fmt, item, PrintfFlags::FHexU(), args...)
343 : throw cprintf_badformat("Unknown character in format string");
345 // --- Size modifier (not implemented, not needed?)
346 template <typename ...Args>
347 size_t run_fmt_size(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
349 // TODO: Size characters?
350 return run_fmt_fmt(puts, fmt, item, args...);
353 template <typename ...Args>
354 size_t run_fmt_prec_val(cprintf_cb puts, const char * fmt, unsigned int val, PrintfFlags item, Args... args)
356 return _bits::isdigit_s(*fmt) ? run_fmt_prec_val(puts, fmt+1, val*10+_bits::todigit(*fmt), item, args...)
357 : run_fmt_size(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), val), args...);
359 template <typename ...Args>
360 size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args)
362 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...);
364 template <typename Arg, typename ...Args>
365 size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, Arg size, Args... args)
367 throw cprintf_badformat("Invalid type for printf precision modifier");
369 size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item)
371 throw cprintf_toofewargs();
373 template <typename ...Args>
374 size_t run_fmt_prec(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
376 return _bits::isdigit_s(*fmt) ? run_fmt_prec_val(puts, fmt+1, _bits::todigit(*fmt), item, args...)
377 : *fmt == '*' ? run_fmt_prec_arg(puts, fmt+1, item, args...)
378 : run_fmt_size(puts, fmt, item, args...);
380 template <typename ...Args>
381 size_t run_fmt_prec_opt(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
383 return *fmt == '.' ? run_fmt_prec(puts, fmt+1, item, args...)
384 : run_fmt_size(puts, fmt, item, args...);
386 // --- Field Width ---
387 template <typename ...Args>
388 size_t run_fmt_width_val(cprintf_cb puts, const char* fmt, unsigned int val, PrintfFlags item, Args... args)
390 return _bits::isdigit_s(*fmt) ? run_fmt_width_val(puts, fmt+1, val*10+_bits::todigit(*fmt), item, args...)
391 : run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), val), args...);
393 template <typename ...Args>
394 size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args)
396 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
398 template <typename Arg, typename ...Args>
399 size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, Arg size, Args... args)
401 throw cprintf_badformat("Invalid type for printf width modifier");
403 size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item)
405 throw cprintf_toofewargs();
407 template <typename ...Args>
408 size_t run_fmt_width(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
410 return _bits::isdigit_s(*fmt) ? run_fmt_width_val(puts, fmt+1, _bits::todigit(*fmt), item, args...)
411 : *fmt == '*' ? run_fmt_width_arg(puts, fmt+1, item, args...)
412 : run_fmt_prec_opt(puts, fmt, item, args...);
415 template <typename ...Args>
416 size_t run_fmt_flags(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
419 *fmt == '-' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Left()) , args...)
420 : *fmt == '+' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Sign()) , args...)
421 : *fmt == ' ' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Space()), args...)
422 : *fmt == '#' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Alt()) , args...)
423 : *fmt == '0' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Zero()) , args...)
424 : run_fmt_width(puts, fmt, item, args...);
427 template <typename ...Args>
428 size_t run_fmt_start(cprintf_cb puts, const char * fmt, Args... args)
431 ? (puts("%", 1), 1 + run(puts, fmt+1, args...))
432 : run_fmt_flags(puts, fmt, PrintfFlags(), args...);
435 template <typename... Args>
436 size_t run(cprintf_cb puts, const char * fmt, Args... args)
439 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
441 if( fmt[ofs] != '%' )
442 throw cprintf_toomanyargs();
443 if(ofs > 0 && puts) puts(fmt, ofs);
444 return ofs + run_fmt_start(puts, fmt+ofs+1, args...);
446 size_t run(cprintf_cb puts, const char *fmt)
449 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
451 if(ofs > 0 && puts) puts(fmt, ofs);
452 return ofs + (fmt[ofs] == '%' ? run_fmt_start(puts, fmt+ofs+1) : 0);
457 }; // namespace _bits
459 #define cprintf(puts, fmt, ...) static_assert(::cxxextras::_bits::_printf::val(fmt, __VA_ARGS__),"");::cxxextras::_bits::_printf::run(puts, fmt, __VA_ARGS__)
461 //template <typename ... Args>
462 //size_t cprintf(cprintf_cb puts, const char *fmt, Args... args)
464 // _bits::_printf::run(nullptr, fmt, args...);
465 // return _bits::_printf::run(puts, fmt, args...);