7d05e21938356c9757fdc7b02c5085580d878202
[tpg/acess2.git] / Usermode / Libraries / libc++_extras.so_src / include_exp / cxxextras_printf
1 /*
2  */
3 #ifndef _LIBCXXEXTRAS_PRINTF_
4 #define _LIBCXXEXTRAS_PRINTF_
5
6 #include <cstddef>
7 #include <cstdlib>
8 #include <cstdio>
9 #include <functional>
10
11 namespace cxxextras {
12
13 class cprintf_toomanyargs:
14         public ::std::exception
15 {
16 };
17 class cprintf_toofewargs:
18         public ::std::exception
19 {
20 };
21 class cprintf_badformat:
22         public ::std::exception
23 {
24         const char *m_reason;
25 public:
26         cprintf_badformat(const char *reason):
27                 m_reason(reason)
28         {
29         }
30         const char* what() const noexcept override {
31                 return m_reason;
32         }
33 };
34
35 namespace _bits {
36
37 enum e_cprintf_type
38 {
39         TYPE_AUTO,
40         TYPE_BOOLEAN,
41         TYPE_BINARY,
42         TYPE_OCT,
43         TYPE_INT,
44         TYPE_INTU,
45         TYPE_INTS,
46         TYPE_HEXLC,
47         TYPE_HEXUC,
48         TYPE_STRING,
49 };
50
51 struct PrintfFlags
52 {
53         unsigned int width;
54         unsigned int precision;
55         unsigned int flags;
56         
57         struct Left {};
58         constexpr PrintfFlags(PrintfFlags x, Left  _): width(x.width), precision(x.precision), flags(x.flags | 1) {}
59         struct Sign {};
60         constexpr PrintfFlags(PrintfFlags x, Sign  _): width(x.width), precision(x.precision), flags(x.flags | 2) {}
61         struct Space {};
62         constexpr PrintfFlags(PrintfFlags x, Space _): width(x.width), precision(x.precision), flags(x.flags | 4) {}
63         struct Alt {};
64         constexpr PrintfFlags(PrintfFlags x, Alt   _): width(x.width), precision(x.precision), flags(x.flags | 8) {}
65         struct Zero {};
66         constexpr PrintfFlags(PrintfFlags x, Zero  _): width(x.width), precision(x.precision), flags(x.flags | 16) {}
67         
68         struct ArgWidth {};
69         constexpr PrintfFlags(PrintfFlags x, ArgWidth _, unsigned int v): width(v), precision(x.precision), flags(x.flags) {}
70         struct ArgPrec {};
71         constexpr PrintfFlags(PrintfFlags x, ArgPrec  _, unsigned int v): width(x.width), precision(v), flags(x.flags) {}
72         
73         struct FAuto {};
74         constexpr PrintfFlags(PrintfFlags x, FAuto   _): width(x.width), precision(x.precision), flags(x.flags | 0x000) {}
75         struct FString {};
76         constexpr PrintfFlags(PrintfFlags x, FString _): width(x.width), precision(x.precision), flags(x.flags | 0x100) {}
77         struct FBool {};
78         constexpr PrintfFlags(PrintfFlags x, FBool   _): width(x.width), precision(x.precision), flags(x.flags | 0x200) {}
79         struct FBinary {};
80         constexpr PrintfFlags(PrintfFlags x, FBinary _): width(x.width), precision(x.precision), flags(x.flags | 0x300) {}
81         struct FOct {};
82         constexpr PrintfFlags(PrintfFlags x, FOct   _): width(x.width), precision(x.precision), flags(x.flags | 0x400) {}
83         struct FUDec {};
84         constexpr PrintfFlags(PrintfFlags x, FUDec  _): width(x.width), precision(x.precision), flags(x.flags | 0x500) {}
85         struct FSDec {};
86         constexpr PrintfFlags(PrintfFlags x, FSDec  _): width(x.width), precision(x.precision), flags(x.flags | 0x600) {}
87         struct FHexL {};
88         constexpr PrintfFlags(PrintfFlags x, FHexL  _): width(x.width), precision(x.precision), flags(x.flags | 0x700) {}
89         struct FHexU {};
90         constexpr PrintfFlags(PrintfFlags x, FHexU  _): width(x.width), precision(x.precision), flags(x.flags | 0x800) {}
91         
92         constexpr PrintfFlags():
93                 width(0), precision(0), flags(0)
94         {
95         }
96 };
97 struct s_cprintf_fmt
98 {
99         bool isValid = false;
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;
108 };
109 ;
110
111 constexpr bool isdigit_s(const char ch) {
112         return '0' <= ch && ch <= '9';
113 }
114 constexpr unsigned todigit(const char ch) {
115         return ch - '0';
116 }
117         
118
119 };      // namespace _bits
120
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);
124
125 constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, const char* arg) {
126         return true;
127 }
128 size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, const char* arg) {
129         unsigned int len;
130         for(len = 0; arg[len]; len ++)
131                 ;
132         puts(arg, len);
133         return len;
134 }
135 constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, int arg) {
136         return true;
137 }
138 size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, int arg) {
139         size_t len = ::std::snprintf(nullptr, 0, "%i", arg);
140         char buf[len+1];
141         ::std::snprintf(buf, len+1, "%i", arg);
142         puts(buf, len);
143         return len;
144 }
145 constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, unsigned int arg) {
146         return true;
147 }
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);
150         char buf[len+1];
151         ::std::snprintf(buf, len+1, "%u", arg);
152         puts(buf, len);
153         return len;
154 }
155
156 namespace _bits
157 {
158 namespace _printf
159 {
160         template <unsigned N>
161         class _str
162         {
163                 const char      m_buf[N];
164                 unsigned m_ofs;
165         public:
166                 constexpr _str(const char buf[N]):
167                         m_buf(buf),
168                         m_ofs(0)
169                 {
170                 }
171                 constexpr _str(const char buf[N], unsigned ofs):
172                         m_buf(buf),
173                         m_ofs(ofs)
174                 {
175                 }
176                 constexpr _str<N> operator+(const unsigned o) {
177                         return _str(m_buf, m_ofs+o);
178                 }
179                 constexpr char operator*() {
180                         return m_buf[m_ofs];
181                 }
182         };
183         
184         template <typename... Args>
185         constexpr bool val(const char* fmt, Args... args);
186         
187         template <typename Fmt>
188         constexpr bool val_fmt_done(const char * fmt, PrintfFlags item, Fmt fmtcode)
189         {
190                 return false ? false : throw "Too few arguments";
191         }
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)
194         {
195                 return cprintf_val_chk(item, arg) && val(fmt+1, args...);
196         }
197         // --- Format code
198         template <typename ...Args>
199         constexpr bool val_fmt_fmt(const char * fmt, PrintfFlags item, Args... args)
200         {
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");
212         }
213         // --- Size modifier (not implemented, not needed?)
214         template <typename ...Args>
215         constexpr bool val_fmt_size(const char * fmt, PrintfFlags item, Args... args)
216         {
217                 // TODO: Size characters?
218                 return val_fmt_fmt(fmt, item, args...);
219         }
220         // --- Precision
221         template <typename ...Args>
222         constexpr bool val_fmt_prec_val(const char * fmt, unsigned int value, PrintfFlags item, Args... args)
223         {
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...);
226         }
227         template <typename ...Args>
228         constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args)
229         {
230                 return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...);
231         }
232         template <typename Arg, typename ...Args>
233         constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, Arg size, Args... args)
234         {
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'";
237         }
238         constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item)
239         {
240                 //static_assert(false, "Too few arguments when getting precision modifier");
241                 return false ? false : throw "Too few arguments when getting precision modifier";
242         }
243         template <typename ...Args>
244         constexpr bool val_fmt_prec(const char * fmt, PrintfFlags item, Args... args)
245         {
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...);
249         }
250         template <typename ...Args>
251         constexpr bool val_fmt_prec_opt(const char * fmt, PrintfFlags item, Args... args)
252         {
253                 return *fmt == '.' ? val_fmt_prec(fmt+1, item, args...)
254                      : val_fmt_size(fmt, item, args...);
255         }
256         // --- Field Width ---  
257         template <typename ...Args>
258         constexpr bool val_fmt_width_val(const char* fmt, unsigned int size, PrintfFlags item, Args... args)
259         {
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...);
262         }
263         template <typename ...Args>
264         constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args)
265         {
266                 return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
267         }
268         template <typename Arg, typename ...Args>
269         constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, Arg size, Args... args)
270         {
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'";
273         }
274         constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item)
275         {
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";
278         }
279         template <typename ...Args>
280         constexpr bool val_fmt_width(const char * fmt, PrintfFlags item, Args... args)
281         {
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...);
285         }
286         // --- Flags
287         template <typename ...Args>
288         constexpr bool val_fmt_flags(const char * fmt, PrintfFlags item, Args... args)
289         {
290                 return
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...);
297         }
298         // --- Literal '%'
299         template <typename ...Args>
300         constexpr bool val_fmt_start(const char* fmt, Args... args)
301         {
302                 return *fmt == '%' ? val(fmt+1, args...) : val_fmt_flags(fmt, PrintfFlags(), args...);
303         }
304         template <typename... Args>
305         constexpr bool val(const char* fmt, Args... args)
306         {
307                 return *fmt == '\0' ? true
308                      : *fmt == '%' ? val_fmt_start(fmt+1, args...)
309                      : val(fmt+1, args...);
310         }
311         
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);
314
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)
318         {
319                 throw cprintf_toofewargs();
320         }
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)
323         {
324                 if( !puts )
325                         return run(puts, fmt+1, args...);
326                 else
327                         return ::cxxextras::cprintf_val(puts, PrintfFlags(item, fmtcode), val) + run(puts, fmt+1, args...);
328         }
329         // --- Format code
330         template <typename ...Args>
331         size_t run_fmt_fmt(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
332         {
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");
344         }
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)
348         {
349                 // TODO: Size characters?
350                 return run_fmt_fmt(puts, fmt, item, args...);
351         }
352         // --- Precision
353         template <typename ...Args>
354         size_t run_fmt_prec_val(cprintf_cb puts, const char * fmt, unsigned int val, PrintfFlags item, Args... args)
355         {
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...);
358         }
359         template <typename ...Args>
360         size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args)
361         {
362                 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...);
363         }
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)
366         {
367                 throw cprintf_badformat("Invalid type for printf precision modifier");
368         }
369         size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item)
370         {
371                 throw cprintf_toofewargs();
372         }
373         template <typename ...Args>
374         size_t run_fmt_prec(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
375         {
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...);
379         }
380         template <typename ...Args>
381         size_t run_fmt_prec_opt(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
382         {
383                 return *fmt == '.' ? run_fmt_prec(puts, fmt+1, item, args...)
384                      : run_fmt_size(puts, fmt, item, args...);
385         }
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)
389         {
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...);
392         }
393         template <typename ...Args>
394         size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args)
395         {
396                 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
397         }
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)
400         {
401                 throw cprintf_badformat("Invalid type for printf width modifier");
402         }
403         size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item)
404         {
405                 throw cprintf_toofewargs();
406         }
407         template <typename ...Args>
408         size_t run_fmt_width(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
409         {
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...);
413         }
414         // --- Flags
415         template <typename ...Args>
416         size_t run_fmt_flags(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args)
417         {
418                 return
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...);
425         }
426         // --- Literal '%'
427         template <typename ...Args>
428         size_t run_fmt_start(cprintf_cb puts, const char * fmt, Args... args)
429         {
430                 return *fmt == '%'
431                         ? (puts("%", 1), 1 + run(puts, fmt+1, args...))
432                         : run_fmt_flags(puts, fmt, PrintfFlags(), args...);
433         }
434         // --- Root
435         template <typename... Args>
436         size_t run(cprintf_cb puts, const char * fmt, Args... args)
437         {
438                 int ofs;
439                 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
440                         ;
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...);
445         }
446         size_t run(cprintf_cb puts, const char *fmt)
447         {
448                 int ofs;
449                 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
450                         ;
451                 if(ofs > 0 && puts) puts(fmt, ofs);
452                 return ofs + (fmt[ofs] == '%' ? run_fmt_start(puts, fmt+ofs+1) : 0);
453         }
454
455 }
456
457 };      // namespace _bits
458
459 #define cprintf(puts, fmt, ...) static_assert(::cxxextras::_bits::_printf::val(fmt, __VA_ARGS__),"");::cxxextras::_bits::_printf::run(puts, fmt, __VA_ARGS__)
460
461 //template <typename ... Args>
462 //size_t cprintf(cprintf_cb puts, const char *fmt, Args... args)
463 //{
464 //      _bits::_printf::run(nullptr, fmt, args...);
465 //      return _bits::_printf::run(puts, fmt, args...);
466 //}
467
468 };
469
470 #endif
471
472 // vim: ft=cpp
473

UCC git Repository :: git.ucc.asn.au