Usermode/libc - Removed debug SysDebug
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / printf.c
1 /*
2  * Acess2 C Library
3  * - By John Hodge (thePowersGang)
4  *
5  * scanf.c
6  * - *scanf family of functions
7  */
8 #include "lib.h"
9 #include <stdio.h>
10 #include <stdarg.h>
11 #include <string.h>
12
13 // === TYPES ===
14 typedef void    (*printf_putch_t)(void *h, char ch);
15
16 // === PROTOTYPES ===
17 void    itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned);
18
19 // === CODE ===
20 /**
21  * \fn EXPORT void vsnprintf(char *buf, const char *format, va_list args)
22  * \brief Prints a formatted string to a buffer
23  * \param buf   Pointer - Destination Buffer
24  * \param format        String - Format String
25  * \param args  VarArgs List - Arguments
26  */
27 EXPORT int _vcprintf_int(printf_putch_t putch_cb, void *putch_h, const char *format, va_list args)
28 {
29         char    tmp[65];
30          int    c, minSize, precision, len;
31         size_t  pos = 0;
32         char    *p;
33         char    pad;
34         uint64_t        arg;
35          int    bLongLong, bPadLeft;
36
37         #define _addchar(ch) do { \
38                 putch_cb(putch_h, ch); \
39                 pos ++; \
40         } while(0)
41
42         tmp[32] = '\0';
43         
44         while((c = *format++) != 0)
45         {
46                 // Non-control character
47                 if (c != '%') {
48                         _addchar(c);
49                         continue;
50                 }
51                 
52                 // Control Character
53                 c = *format++;
54                 if(c == '%') {  // Literal %
55                         _addchar('%');
56                         continue;
57                 }
58                 
59                 bPadLeft = 0;
60                 bLongLong = 0;
61                 minSize = 0;
62                 precision = -1;
63                 pad = ' ';
64                 
65                 // Padding Character
66                 if(c == '0') {
67                         pad = '0';
68                         c = *format++;
69                 }
70                 // Padding length
71                 if( c == '*' ) {
72                         // Variable length
73                         minSize = va_arg(args, size_t);
74                         c = *format++;
75                 }
76                 else {
77                         if('1' <= c && c <= '9')
78                         {
79                                 minSize = 0;
80                                 while('0' <= c && c <= '9')
81                                 {
82                                         minSize *= 10;
83                                         minSize += c - '0';
84                                         c = *format++;
85                                 }
86                         }
87                 }
88
89                 // Precision
90                 if(c == '.') {
91                         c = *format++;
92                         if(c == '*') {
93                                 precision = va_arg(args, size_t);
94                                 c = *format++;
95                         }
96                         else if('1' <= c && c <= '9')
97                         {
98                                 precision = 0;
99                                 while('0' <= c && c <= '9')
100                                 {
101                                         precision *= 10;
102                                         precision += c - '0';
103                                         c = *format++;
104                                 }
105                         }
106                 }
107         
108                 // Check for long long
109                 bLongLong = 0;
110                 if(c == 'l')
111                 {
112                         c = *format++;
113                         if(c == 'l') {
114                                 bLongLong = 1;
115                         }
116                 }
117                 
118                 // Just help things along later
119                 p = tmp;
120                 
121                 // Get Type
122                 switch( c )
123                 {
124                 // Signed Integer
125                 case 'd':       case 'i':
126                         // Get Argument
127                         if(bLongLong)   arg = va_arg(args, int64_t);
128                         else                    arg = va_arg(args, int32_t);
129                         itoa(tmp, arg, 10, minSize, pad, 1);
130                         precision = -1;
131                         goto sprintf_puts;
132                 
133                 // Unsigned Integer
134                 case 'u':
135                         // Get Argument
136                         if(bLongLong)   arg = va_arg(args, uint64_t);
137                         else                    arg = va_arg(args, uint32_t);
138                         itoa(tmp, arg, 10, minSize, pad, 0);
139                         precision = -1;
140                         goto sprintf_puts;
141                 
142                 // Pointer
143                 case 'p':
144                         _addchar('*');
145                         _addchar('0');
146                         _addchar('x');
147                         arg = va_arg(args, intptr_t);
148                         itoa(tmp, arg, 16, minSize, pad, 0);
149                         precision = -1;
150                         goto sprintf_puts;
151                 // Unsigned Hexadecimal
152                 case 'x':
153                         if(bLongLong)   arg = va_arg(args, uint64_t);
154                         else                    arg = va_arg(args, uint32_t);
155                         itoa(tmp, arg, 16, minSize, pad, 0);
156                         precision = -1;
157                         goto sprintf_puts;
158                 
159                 // Unsigned Octal
160                 case 'o':
161                         if(bLongLong)   arg = va_arg(args, uint64_t);
162                         else                    arg = va_arg(args, uint32_t);
163                         itoa(tmp, arg, 8, minSize, pad, 0);
164                         precision = -1;
165                         goto sprintf_puts;
166                 
167                 // Unsigned binary
168                 case 'b':
169                         if(bLongLong)   arg = va_arg(args, uint64_t);
170                         else                    arg = va_arg(args, uint32_t);
171                         itoa(tmp, arg, 2, minSize, pad, 0);
172                         precision = -1;
173                         goto sprintf_puts;
174
175                 // String
176                 case 's':
177                         p = va_arg(args, char*);
178                 sprintf_puts:
179                         if(!p)  p = "(null)";
180                         //_SysDebug("vsnprintf: p = '%s'", p);
181                         if(precision >= 0)
182                                 len = strnlen(p, precision);
183                         else
184                                 len = strlen(p);
185                         if(bPadLeft)    while(minSize > len++)  _addchar(pad);
186                         while( *p ) {
187                                 if(precision >= 0 && precision -- == 0)
188                                         break;
189                                 _addchar(*p++);
190                         }
191                         if(!bPadLeft)   while(minSize > len++)  _addchar(pad);
192                         break;
193
194                 // Unknown, just treat it as a character
195                 default:
196                         arg = va_arg(args, uint32_t);
197                         _addchar(arg);
198                         break;
199                 }
200         }
201         #undef _addchar
202         
203         return pos;
204 }
205
206 struct s_sprintf_info {
207         char    *dest;
208         size_t  ofs;
209         size_t  maxlen;
210 };
211
212 void _vsnprintf_putch(void *h, char ch)
213 {
214         struct s_sprintf_info   *info = h;
215         if(info->ofs < info->maxlen)
216                 info->dest[info->ofs++] = ch;
217 }
218
219 EXPORT int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list __args)
220 {
221         struct s_sprintf_info   info = {__s, 0, __maxlen};
222         int ret;
223         ret = _vcprintf_int(_vsnprintf_putch, &info, __format, __args);
224         _vsnprintf_putch(&info, '\0');
225         return ret;
226 }
227
228 EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...)
229 {
230          int    ret;
231         va_list args;
232         va_start(args, format);
233         ret = vsnprintf((char*)buf, maxlen, (char*)format, args);
234         va_end(args);
235         return ret;
236 }
237
238
239 EXPORT int vsprintf(char * __s, const char *__format, va_list __args)
240 {
241         return vsnprintf(__s, 0x7FFFFFFF, __format, __args);
242 }
243 EXPORT int sprintf(char *buf, const char *format, ...)
244 {
245          int    ret;
246         va_list args;
247         va_start(args, format);
248         ret = vsprintf((char*)buf, (char*)format, args);
249         va_end(args);
250         return ret;
251 }
252
253 void _vfprintf_putch(void *h, char ch)
254 {
255         fputc(ch, h);
256 }
257
258 EXPORT int vfprintf(FILE *__fp, const char *__format, va_list __args)
259 {
260         return _vcprintf_int(_vfprintf_putch, __fp, __format, __args);
261 }
262
263 EXPORT int fprintf(FILE *fp, const char *format, ...)
264 {
265         va_list args;
266          int    ret;
267         
268         // Get Size
269         va_start(args, format);
270         ret = vfprintf(fp, (char*)format, args);
271         va_end(args);
272         
273         return ret;
274 }
275
276 EXPORT int vprintf(const char *__format, va_list __args)
277 {
278         return vfprintf(stdout, __format, __args);
279 }
280
281 EXPORT int printf(const char *format, ...)
282 {
283         va_list args;
284          int    ret;
285         
286         // Get final size
287         va_start(args, format);
288         ret = vprintf(format, args);
289         va_end(args);
290         
291         // Return
292         return ret;
293 }
294
295 const char cUCDIGITS[] = "0123456789ABCDEF";
296 /**
297  * \brief Convert an integer into a character string
298  * \param buf   Destination Buffer
299  * \param num   Number to convert
300  * \param base  Base-n number output
301  * \param minLength     Minimum length of output
302  * \param pad   Padding used to ensure minLength
303  * \param bSigned       Signed number output?
304  */
305 EXPORT void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned)
306 {
307         char    tmpBuf[64];
308          int    pos=0, i;
309
310         if(!buf)        return;
311         if(base > 16 || base < 2) {
312                 buf[0] = 0;
313                 return;
314         }
315         
316         if(bSigned && (int64_t)num < 0)
317         {
318                 num = -num;
319                 bSigned = 1;
320         } else
321                 bSigned = 0;
322         
323         // Encode into reversed string
324         while(num > base-1) {
325                 tmpBuf[pos++] = cUCDIGITS[ num % base ];
326                 num = (uint64_t) num / (uint64_t)base;          // Shift {number} right 1 digit
327         }
328
329         tmpBuf[pos++] = cUCDIGITS[ num % base ];                // Last digit of {number}
330         if(bSigned)     tmpBuf[pos++] = '-';    // Append sign symbol if needed
331         
332         i = 0;
333         minLength -= pos;
334         while(minLength-- > 0)  buf[i++] = pad;
335         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
336         buf[i] = 0;
337 }

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