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 {
37 typedef ::std::function<size_t(const char*,size_t)> t_cprintf_callback;
56 unsigned int precision;
60 constexpr PrintfFlags(PrintfFlags x, Left _): width(x.width), precision(x.precision), flags(x.flags | 1) {}
62 constexpr PrintfFlags(PrintfFlags x, Sign _): width(x.width), precision(x.precision), flags(x.flags | 2) {}
64 constexpr PrintfFlags(PrintfFlags x, Space _): width(x.width), precision(x.precision), flags(x.flags | 4) {}
66 constexpr PrintfFlags(PrintfFlags x, Alt _): width(x.width), precision(x.precision), flags(x.flags | 8) {}
68 constexpr PrintfFlags(PrintfFlags x, Zero _): width(x.width), precision(x.precision), flags(x.flags | 16) {}
71 constexpr PrintfFlags(PrintfFlags x, ArgWidth _, unsigned int v): width(v), precision(x.precision), flags(x.flags) {}
73 constexpr PrintfFlags(PrintfFlags x, ArgPrec _, unsigned int v): width(x.width), precision(v), flags(x.flags) {}
76 constexpr PrintfFlags(PrintfFlags x, FAuto _): width(x.width), precision(x.precision), flags(x.flags | 0x000) {}
78 constexpr PrintfFlags(PrintfFlags x, FString _): width(x.width), precision(x.precision), flags(x.flags | 0x100) {}
80 constexpr PrintfFlags(PrintfFlags x, FBool _): width(x.width), precision(x.precision), flags(x.flags | 0x200) {}
82 constexpr PrintfFlags(PrintfFlags x, FBinary _): width(x.width), precision(x.precision), flags(x.flags | 0x300) {}
84 constexpr PrintfFlags(PrintfFlags x, FOct _): width(x.width), precision(x.precision), flags(x.flags | 0x400) {}
86 constexpr PrintfFlags(PrintfFlags x, FUDec _): width(x.width), precision(x.precision), flags(x.flags | 0x500) {}
88 constexpr PrintfFlags(PrintfFlags x, FSDec _): width(x.width), precision(x.precision), flags(x.flags | 0x600) {}
90 constexpr PrintfFlags(PrintfFlags x, FHexL _): width(x.width), precision(x.precision), flags(x.flags | 0x700) {}
92 constexpr PrintfFlags(PrintfFlags x, FHexU _): width(x.width), precision(x.precision), flags(x.flags | 0x800) {}
95 width(0), precision(0), flags(0)
101 bool isValid = false;
102 unsigned int precision = 0;
103 unsigned int minLength = 0;
104 bool padLeft = false;
105 bool showSign = false;
106 bool showSpace = false;
107 bool altFormat = false;
108 bool padZero = false;
109 enum e_cprintf_type type;
112 constexpr bool isdigit_s(const char ch) {
113 return '0' <= ch && ch <= '9';
115 constexpr unsigned todigit(const char ch) {
120 }; // namespace _bits
122 template <typename Arg> size_t cprintf_val(_bits::t_cprintf_callback puts, const _bits::PrintfFlags &fmt, Arg arg);
124 size_t cprintf_val(_bits::t_cprintf_callback puts, const _bits::PrintfFlags& fmt, const char* arg) {
126 for(len = 0; arg[len]; len ++)
128 return puts(arg, len);
130 size_t cprintf_val(_bits::t_cprintf_callback puts, const _bits::PrintfFlags& fmt, int arg) {
131 size_t len = ::std::snprintf(nullptr, 0, "%i", arg);
133 ::std::snprintf(buf, len+1, "%i", arg);
134 return puts(buf, len);
141 size_t run(_bits::t_cprintf_callback puts, const char *fmt);
142 template <typename... Args> size_t run(_bits::t_cprintf_callback puts, const char * fmt, Args... args);
144 // --- Print formatted value
145 template <typename Fmt>
146 size_t run_fmt_done(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Fmt fmtcode)
148 throw cprintf_toofewargs();
150 template <typename Fmt, typename Arg, typename... Args>
151 size_t run_fmt_done(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Fmt fmtcode, Arg val, Args... args)
153 return ::cxxextras::cprintf_val(puts, PrintfFlags(item, fmtcode), val) + run(puts, fmt+1, args...);
156 template <typename ...Args>
157 size_t run_fmt_fmt(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
159 return *fmt == '\0' ? throw "ERROR: NUL byte in format specifier"
160 : *fmt == '?' ? run_fmt_done(puts, fmt, item, PrintfFlags::FAuto(), args...)
161 : *fmt == 's' ? run_fmt_done(puts, fmt, item, PrintfFlags::FString(),args...)
162 : *fmt == 'B' ? run_fmt_done(puts, fmt, item, PrintfFlags::FBool(), args...)
163 : *fmt == 'b' ? run_fmt_done(puts, fmt, item, PrintfFlags::FBinary(),args...)
164 : *fmt == 'o' ? run_fmt_done(puts, fmt, item, PrintfFlags::FOct(), args...)
165 : *fmt == 'i' ? run_fmt_done(puts, fmt, item, PrintfFlags::FSDec(), args...)
166 : *fmt == 'u' ? run_fmt_done(puts, fmt, item, PrintfFlags::FUDec(), args...)
167 : *fmt == 'x' ? run_fmt_done(puts, fmt, item, PrintfFlags::FHexL(), args...)
168 : *fmt == 'X' ? run_fmt_done(puts, fmt, item, PrintfFlags::FHexU(), args...)
169 : throw cprintf_badformat("Unknown character in format string");
171 // --- Size modifier (not implemented, not needed?)
172 template <typename ...Args>
173 size_t run_fmt_size(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
175 // TODO: Size characters?
176 return run_fmt_fmt(puts, fmt, item, args...);
179 template <typename ...Args>
180 size_t run_fmt_prec_val(_bits::t_cprintf_callback puts, const char * fmt, unsigned int val, PrintfFlags item, Args... args)
182 return _bits::isdigit_s(*fmt) ? run_fmt_prec_val(puts, fmt+1, val*10+_bits::todigit(*fmt), item, args...)
183 : run_fmt_size(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), val), args...);
185 template <typename ...Args>
186 size_t run_fmt_prec_arg(_bits::t_cprintf_callback puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args)
188 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...);
190 template <typename Arg, typename ...Args>
191 size_t run_fmt_prec_arg(_bits::t_cprintf_callback puts, const char *fmt, PrintfFlags item, Arg size, Args... args)
193 throw cprintf_badformat("Invalid type for printf precision modifier");
195 size_t run_fmt_prec_arg(_bits::t_cprintf_callback puts, const char *fmt, PrintfFlags item)
197 throw cprintf_toofewargs();
199 template <typename ...Args>
200 size_t run_fmt_prec(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
202 return _bits::isdigit_s(*fmt) ? run_fmt_prec_val(puts, fmt+1, _bits::todigit(*fmt), item, args...)
203 : *fmt == '*' ? run_fmt_prec_arg(puts, fmt+1, item, args...)
204 : run_fmt_size(puts, fmt, item, args...);
206 template <typename ...Args>
207 size_t run_fmt_prec_opt(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
209 return *fmt == '.' ? run_fmt_prec(puts, fmt+1, item, args...)
210 : run_fmt_size(puts, fmt, item, args...);
212 // --- Field Width ---
213 template <typename ...Args>
214 size_t run_fmt_width_val(_bits::t_cprintf_callback puts, const char * fmt, unsigned int val, PrintfFlags item, Args... args)
216 return _bits::isdigit_s(*fmt) ? run_fmt_width_val(puts, fmt+1, val*10+_bits::todigit(*fmt), item, args...)
217 : run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), val), args...);
219 template <typename ...Args>
220 size_t run_fmt_width_arg(_bits::t_cprintf_callback puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args)
222 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
224 template <typename Arg, typename ...Args>
225 size_t run_fmt_width_arg(_bits::t_cprintf_callback puts, const char *fmt, PrintfFlags item, Arg size, Args... args)
227 throw cprintf_badformat("Invalid type for printf width modifier");
229 size_t run_fmt_width_arg(_bits::t_cprintf_callback puts, const char *fmt, PrintfFlags item)
231 throw cprintf_toofewargs();
233 template <typename ...Args>
234 size_t run_fmt_width(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
236 return _bits::isdigit_s(*fmt) ? run_fmt_width_val(puts, fmt+1, _bits::todigit(*fmt), item, args...)
237 : *fmt == '*' ? run_fmt_width_arg(puts, fmt+1, item, args...)
238 : run_fmt_prec_opt(puts, fmt, item, args...);
241 template <typename ...Args>
242 size_t run_fmt_flags(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
245 *fmt == '-' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Left()) , args...)
246 : *fmt == '+' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Sign()) , args...)
247 : *fmt == ' ' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Space()), args...)
248 : *fmt == '#' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Alt()) , args...)
249 : *fmt == '0' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Zero()) , args...)
250 : run_fmt_width(puts, fmt, item, args...);
253 template <typename ...Args>
254 size_t run_fmt_start(_bits::t_cprintf_callback puts, const char * fmt, Args... args)
256 //printf("> DEBUG: '%s'\n", fmt);
258 ? (puts("%", 1), 1 + run(puts, fmt+1, args...))
259 : run_fmt_flags(puts, fmt, PrintfFlags(), args...);
262 template <typename... Args>
263 size_t run(_bits::t_cprintf_callback puts, const char * fmt, Args... args)
266 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
268 if( fmt[ofs] != '%' )
269 throw cprintf_toomanyargs();
270 if(ofs > 0) puts(fmt, ofs);
271 //printf("> DEBUG: run: '%s'\n", fmt+ofs);
272 return ofs + run_fmt_start(puts, fmt+ofs+1, args...);
274 size_t run(_bits::t_cprintf_callback puts, const char *fmt)
277 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
279 if( fmt[ofs] == '%' )
280 throw cprintf_toofewargs();
281 if(ofs > 0) puts(fmt, ofs);
287 }; // namespace _bits
289 template <typename ... Args>
290 size_t cprintf(_bits::t_cprintf_callback puts, const char *fmt, Args... args)
292 return _bits::_printf::run(puts, fmt, args...);