Usermode/libc++_extras - Work on a C++ printf implementation (no formatters written...
[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 typedef ::std::function<size_t(const char*,size_t)>     t_cprintf_callback;
38
39 enum e_cprintf_type
40 {
41         TYPE_AUTO,
42         TYPE_BOOLEAN,
43         TYPE_BINARY,
44         TYPE_OCT,
45         TYPE_INT,
46         TYPE_INTU,
47         TYPE_INTS,
48         TYPE_HEXLC,
49         TYPE_HEXUC,
50         TYPE_STRING,
51 };
52
53 struct PrintfFlags
54 {
55         unsigned int width;
56         unsigned int precision;
57         unsigned int flags;
58         
59         struct Left {};
60         constexpr PrintfFlags(PrintfFlags x, Left  _): width(x.width), precision(x.precision), flags(x.flags | 1) {}
61         struct Sign {};
62         constexpr PrintfFlags(PrintfFlags x, Sign  _): width(x.width), precision(x.precision), flags(x.flags | 2) {}
63         struct Space {};
64         constexpr PrintfFlags(PrintfFlags x, Space _): width(x.width), precision(x.precision), flags(x.flags | 4) {}
65         struct Alt {};
66         constexpr PrintfFlags(PrintfFlags x, Alt   _): width(x.width), precision(x.precision), flags(x.flags | 8) {}
67         struct Zero {};
68         constexpr PrintfFlags(PrintfFlags x, Zero  _): width(x.width), precision(x.precision), flags(x.flags | 16) {}
69         
70         struct ArgWidth {};
71         constexpr PrintfFlags(PrintfFlags x, ArgWidth _, unsigned int v): width(v), precision(x.precision), flags(x.flags) {}
72         struct ArgPrec {};
73         constexpr PrintfFlags(PrintfFlags x, ArgPrec  _, unsigned int v): width(x.width), precision(v), flags(x.flags) {}
74         
75         struct FAuto {};
76         constexpr PrintfFlags(PrintfFlags x, FAuto   _): width(x.width), precision(x.precision), flags(x.flags | 0x000) {}
77         struct FString {};
78         constexpr PrintfFlags(PrintfFlags x, FString _): width(x.width), precision(x.precision), flags(x.flags | 0x100) {}
79         struct FBool {};
80         constexpr PrintfFlags(PrintfFlags x, FBool   _): width(x.width), precision(x.precision), flags(x.flags | 0x200) {}
81         struct FBinary {};
82         constexpr PrintfFlags(PrintfFlags x, FBinary _): width(x.width), precision(x.precision), flags(x.flags | 0x300) {}
83         struct FOct {};
84         constexpr PrintfFlags(PrintfFlags x, FOct   _): width(x.width), precision(x.precision), flags(x.flags | 0x400) {}
85         struct FUDec {};
86         constexpr PrintfFlags(PrintfFlags x, FUDec  _): width(x.width), precision(x.precision), flags(x.flags | 0x500) {}
87         struct FSDec {};
88         constexpr PrintfFlags(PrintfFlags x, FSDec  _): width(x.width), precision(x.precision), flags(x.flags | 0x600) {}
89         struct FHexL {};
90         constexpr PrintfFlags(PrintfFlags x, FHexL  _): width(x.width), precision(x.precision), flags(x.flags | 0x700) {}
91         struct FHexU {};
92         constexpr PrintfFlags(PrintfFlags x, FHexU  _): width(x.width), precision(x.precision), flags(x.flags | 0x800) {}
93         
94         PrintfFlags():
95                 width(0), precision(0), flags(0)
96         {
97         }
98 };
99 struct s_cprintf_fmt
100 {
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;
110 };
111
112 constexpr bool isdigit_s(const char ch) {
113         return '0' <= ch && ch <= '9';
114 }
115 constexpr unsigned todigit(const char ch) {
116         return ch - '0';
117 }
118         
119
120 };      // namespace _bits
121
122 template <typename Arg> size_t cprintf_val(_bits::t_cprintf_callback puts, const _bits::PrintfFlags &fmt, Arg arg);
123
124 size_t cprintf_val(_bits::t_cprintf_callback puts, const _bits::PrintfFlags& fmt, const char* arg) {
125         unsigned int len;
126         for(len = 0; arg[len]; len ++)
127                 ;
128         return puts(arg, len);
129 }
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);
132         char buf[len+1];
133         ::std::snprintf(buf, len+1, "%i", arg);
134         return puts(buf, len);
135 }
136
137 namespace _bits
138 {
139 namespace _printf
140 {
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);
143
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)
147         {
148                 throw cprintf_toofewargs();
149         }
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)
152         {
153                 return ::cxxextras::cprintf_val(puts, PrintfFlags(item, fmtcode), val) + run(puts, fmt+1, args...);
154         }
155         // --- Format code
156         template <typename ...Args>
157         size_t run_fmt_fmt(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
158         {
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");
170         }
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)
174         {
175                 // TODO: Size characters?
176                 return run_fmt_fmt(puts, fmt, item, args...);
177         }
178         // --- Precision
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)
181         {
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...);
184         }
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)
187         {
188                 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...);
189         }
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)
192         {
193                 throw cprintf_badformat("Invalid type for printf precision modifier");
194         }
195         size_t run_fmt_prec_arg(_bits::t_cprintf_callback puts, const char *fmt, PrintfFlags item)
196         {
197                 throw cprintf_toofewargs();
198         }
199         template <typename ...Args>
200         size_t run_fmt_prec(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
201         {
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...);
205         }
206         template <typename ...Args>
207         size_t run_fmt_prec_opt(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
208         {
209                 return *fmt == '.' ? run_fmt_prec(puts, fmt+1, item, args...)
210                      : run_fmt_size(puts, fmt, item, args...);
211         }
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)
215         {
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...);
218         }
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)
221         {
222                 return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
223         }
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)
226         {
227                 throw cprintf_badformat("Invalid type for printf width modifier");
228         }
229         size_t run_fmt_width_arg(_bits::t_cprintf_callback puts, const char *fmt, PrintfFlags item)
230         {
231                 throw cprintf_toofewargs();
232         }
233         template <typename ...Args>
234         size_t run_fmt_width(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
235         {
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...);
239         }
240         // --- Flags
241         template <typename ...Args>
242         size_t run_fmt_flags(_bits::t_cprintf_callback puts, const char * fmt, PrintfFlags item, Args... args)
243         {
244                 return
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...);
251         }
252         // --- Literal '%'
253         template <typename ...Args>
254         size_t run_fmt_start(_bits::t_cprintf_callback puts, const char * fmt, Args... args)
255         {
256                 //printf("> DEBUG: '%s'\n", fmt);
257                 return *fmt == '%'
258                         ? (puts("%", 1), 1 + run(puts, fmt+1, args...))
259                         : run_fmt_flags(puts, fmt, PrintfFlags(), args...);
260         }
261         // --- Root
262         template <typename... Args>
263         size_t run(_bits::t_cprintf_callback puts, const char * fmt, Args... args)
264         {
265                 int ofs;
266                 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
267                         ;
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...);
273         }
274         size_t run(_bits::t_cprintf_callback puts, const char *fmt)
275         {
276                 int ofs;
277                 for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ )
278                         ;
279                 if( fmt[ofs] == '%' )
280                         throw cprintf_toofewargs();
281                 if(ofs > 0) puts(fmt, ofs);
282                 return ofs;
283         }
284
285 }
286
287 };      // namespace _bits
288
289 template <typename ... Args>
290 size_t cprintf(_bits::t_cprintf_callback puts, const char *fmt, Args... args)
291 {
292         return _bits::_printf::run(puts, fmt, args...);
293 }
294
295 };
296
297 #endif
298
299 // vim: ft=cpp
300

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