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) {}
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);
124 size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, const char* arg) {
126 for(len = 0; arg[len]; len ++)
131 size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, int arg) {
132 size_t len = ::std::snprintf(nullptr, 0, "%i", arg);
134 ::std::snprintf(buf, len+1, "%i", arg);
138 size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, unsigned int arg) {
139 size_t len = ::std::snprintf(nullptr, 0, "%u", arg);
141 ::std::snprintf(buf, len+1, "%u", arg);
150 size_t run(cprintf_cb puts, const char *fmt);
151 template <typename... Args> size_t run(cprintf_cb puts, const char * fmt, Args... args);
153 // --- Print formatted value
154 template <typename Fmt>
155 constexpr size_t run_fmt_done(cprintf_cb puts, const char * fmt, PrintfFlags item, Fmt fmtcode)
157 throw cprintf_toofewargs();
159 template <typename Fmt, typename Arg, typename... Args>
160 size_t run_fmt_done(cprintf_cb puts, const char * fmt, PrintfFlags item, Fmt fmtcode, Arg val, Args... args)
163 return run(puts, fmt+1, args...);
165 return ::cxxextras::cprintf_val(puts, PrintfFlags(item, fmtcode), val) + run(puts, fmt+1, args...);
168 template <typename ...Args>
169 size_t run_fmt_fmt(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
171 return *fmt == '\0' ? throw "ERROR: NUL byte in format specifier"
172 : *fmt == '?' ? run_fmt_done(puts, fmt, item, PrintfFlags::FAuto(), args...)
173 : *fmt == 's' ? run_fmt_done(puts, fmt, item, PrintfFlags::FString(),args...)
174 : *fmt == 'B' ? run_fmt_done(puts, fmt, item, PrintfFlags::FBool(), args...)
175 : *fmt == 'b' ? run_fmt_done(puts, fmt, item, PrintfFlags::FBinary(),args...)
176 : *fmt == 'o' ? run_fmt_done(puts, fmt, item, PrintfFlags::FOct(), args...)
177 : *fmt == 'i' ? run_fmt_done(puts, fmt, item, PrintfFlags::FSDec(), args...)
178 : *fmt == 'u' ? run_fmt_done(puts, fmt, item, PrintfFlags::FUDec(), args...)
179 : *fmt == 'x' ? run_fmt_done(puts, fmt, item, PrintfFlags::FHexL(), args...)
180 : *fmt == 'X' ? run_fmt_done(puts, fmt, item, PrintfFlags::FHexU(), args...)
181 : throw cprintf_badformat("Unknown character in format string");
183 // --- Size modifier (not implemented, not needed?)
184 template <typename ...Args>
185 size_t run_fmt_size(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
187 // TODO: Size characters?
188 return run_fmt_fmt(puts, fmt, item, args...);
191 template <typename ...Args>
192 size_t run_fmt_prec_val(cprintf_cb puts, const char * fmt, unsigned int val, PrintfFlags item, Args... args)
194 return _bits::isdigit_s(*fmt) ? run_fmt_prec_val(puts, fmt+1, val*10+_bits::todigit(*fmt), item, args...)
195 : run_fmt_size(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), val), args...);
197 template <typename ...Args>
198 size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args)
200 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...);
202 template <typename Arg, typename ...Args>
203 size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, Arg size, Args... args)
205 throw cprintf_badformat("Invalid type for printf precision modifier");
207 size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item)
209 throw cprintf_toofewargs();
211 template <typename ...Args>
212 size_t run_fmt_prec(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
214 return _bits::isdigit_s(*fmt) ? run_fmt_prec_val(puts, fmt+1, _bits::todigit(*fmt), item, args...)
215 : *fmt == '*' ? run_fmt_prec_arg(puts, fmt+1, item, args...)
216 : run_fmt_size(puts, fmt, item, args...);
218 template <typename ...Args>
219 size_t run_fmt_prec_opt(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
221 return *fmt == '.' ? run_fmt_prec(puts, fmt+1, item, args...)
222 : run_fmt_size(puts, fmt, item, args...);
224 // --- Field Width ---
225 template <typename ...Args>
226 size_t run_fmt_width_val(cprintf_cb puts, const char* fmt, unsigned int val, PrintfFlags item, Args... args)
228 return _bits::isdigit_s(*fmt) ? run_fmt_width_val(puts, fmt+1, val*10+_bits::todigit(*fmt), item, args...)
229 : run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), val), args...);
231 template <typename ...Args>
232 size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args)
234 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
236 template <typename Arg, typename ...Args>
237 size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, Arg size, Args... args)
239 throw cprintf_badformat("Invalid type for printf width modifier");
241 size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item)
243 throw cprintf_toofewargs();
245 template <typename ...Args>
246 size_t run_fmt_width(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
248 return _bits::isdigit_s(*fmt) ? run_fmt_width_val(puts, fmt+1, _bits::todigit(*fmt), item, args...)
249 : *fmt == '*' ? run_fmt_width_arg(puts, fmt+1, item, args...)
250 : run_fmt_prec_opt(puts, fmt, item, args...);
253 template <typename ...Args>
254 size_t run_fmt_flags(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
257 *fmt == '-' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Left()) , args...)
258 : *fmt == '+' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Sign()) , args...)
259 : *fmt == ' ' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Space()), args...)
260 : *fmt == '#' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Alt()) , args...)
261 : *fmt == '0' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Zero()) , args...)
262 : run_fmt_width(puts, fmt, item, args...);
265 template <typename ...Args>
266 size_t run_fmt_start(cprintf_cb puts, const char * fmt, Args... args)
269 ? (puts("%", 1), 1 + run(puts, fmt+1, args...))
270 : run_fmt_flags(puts, fmt, PrintfFlags(), args...);
273 template <typename... Args>
274 size_t run(cprintf_cb puts, const char * fmt, Args... args)
277 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
279 if( fmt[ofs] != '%' )
280 throw cprintf_toomanyargs();
281 if(ofs > 0 && puts) puts(fmt, ofs);
282 return ofs + run_fmt_start(puts, fmt+ofs+1, args...);
284 size_t run(cprintf_cb puts, const char *fmt)
287 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
289 if(ofs > 0 && puts) puts(fmt, ofs);
290 return ofs + (fmt[ofs] == '%' ? run_fmt_start(puts, fmt+ofs+1) : 0);
295 }; // namespace _bits
297 template <typename ... Args>
298 size_t cprintf(cprintf_cb puts, const char *fmt, Args... args)
300 _bits::_printf::run(nullptr, fmt, args...);
301 return _bits::_printf::run(puts, fmt, args...);