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

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