3 * - By John Hodge (thePowersGang)
6 * - *scanf family of functions
12 #include <ctype.h> // toupper
13 #include <assert.h> // assert()
16 typedef void (*printf_putch_t)(void *h, char ch);
24 void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned);
25 size_t _printf_itoa(printf_putch_t putch_cb, void *putch_h, uint64_t num, size_t base, int minLength, char pad, int bSigned);
26 size_t _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, size_t Base, enum eFPN Notation, int Precision, int bForcePoint, int bForceSign, int bCapitals);
30 * \fn EXPORT void vsnprintf(char *buf, const char *format, va_list args)
31 * \brief Prints a formatted string to a buffer
32 * \param buf Pointer - Destination Buffer
33 * \param format String - Format String
34 * \param args VarArgs List - Arguments
36 EXPORT int _vcprintf_int(printf_putch_t putch_cb, void *putch_h, const char *format, va_list args)
39 int c, minSize, precision, len;
45 // char cPositiveChar;
46 int bLongLong, bPadLeft, bLong;
48 #define _addchar(ch) do { \
49 putch_cb(putch_h, ch); \
55 while((c = *format++) != 0)
57 // Non-control character
65 if(c == '%') { // Literal %
75 // cPositiveChar = '\0';
79 // Alternate form (0<oct>, 0x<hex>, 123.)
94 // Include space for positive sign
97 // cPositiveChar = ' ';
100 // Always include sign
102 // cPositiveChar = '+';
109 minSize = va_arg(args, size_t);
112 else if('1' <= c && c <= '9')
115 while('0' <= c && c <= '9')
127 precision = va_arg(args, size_t);
130 else if('1' <= c && c <= '9')
133 while('0' <= c && c <= '9')
136 precision += c - '0';
142 // Check for long long
153 // Just help things along later
162 if(bLongLong) arg = va_arg(args, int64_t);
163 else arg = va_arg(args, int32_t);
164 itoa(tmp, arg, 10, minSize, pad, 1);
171 if(bLongLong) arg = va_arg(args, uint64_t);
172 else arg = va_arg(args, uint32_t);
173 itoa(tmp, arg, 10, minSize, pad, 0);
182 arg = va_arg(args, intptr_t);
183 itoa(tmp, arg, 16, minSize, pad, 0);
186 // Unsigned Hexadecimal
188 if(bLongLong) arg = va_arg(args, uint64_t);
189 else arg = va_arg(args, uint32_t);
190 itoa(tmp, arg, 16, minSize, pad, 0);
196 if(bLongLong) arg = va_arg(args, uint64_t);
197 else arg = va_arg(args, uint32_t);
198 itoa(tmp, arg, 8, minSize, pad, 0);
204 if(bLongLong) arg = va_arg(args, uint64_t);
205 else arg = va_arg(args, uint32_t);
206 itoa(tmp, arg, 2, minSize, pad, 0);
212 if(bLong) arg_f = va_arg(args, long double);
213 else arg_f = va_arg(args, double);
214 pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_STD, precision, 0, bPadLeft, 0);
217 if(bLong) arg_f = va_arg(args, long double);
218 else arg_f = va_arg(args, double);
219 pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_STD, precision, 0, bPadLeft, 1);
223 if(bLong) arg_f = va_arg(args, long double);
224 else arg_f = va_arg(args, double);
225 pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_SCI, precision, 0, bPadLeft, 0);
228 if(bLong) arg_f = va_arg(args, long double);
229 else arg_f = va_arg(args, double);
230 pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_SCI, precision, 0, bPadLeft, 1);
235 p = va_arg(args, char*);
238 //_SysDebug("vsnprintf: p = '%s'", p);
240 len = strnlen(p, precision);
243 if(bPadLeft) while(minSize > len++) _addchar(pad);
245 if(precision >= 0 && precision -- == 0)
249 if(!bPadLeft) while(minSize > len++) _addchar(pad);
252 // Unknown, just treat it as a character
254 arg = va_arg(args, uint32_t);
264 struct s_sprintf_info {
270 void _vsnprintf_putch(void *h, char ch)
272 struct s_sprintf_info *info = h;
273 if(info->ofs < info->maxlen)
274 info->dest[info->ofs++] = ch;
277 EXPORT int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list __args)
279 struct s_sprintf_info info = {__s, 0, __maxlen};
281 ret = _vcprintf_int(_vsnprintf_putch, &info, __format, __args);
282 _vsnprintf_putch(&info, '\0');
286 EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...)
290 va_start(args, format);
291 ret = vsnprintf((char*)buf, maxlen, (char*)format, args);
297 EXPORT int vsprintf(char * __s, const char *__format, va_list __args)
299 return vsnprintf(__s, 0x7FFFFFFF, __format, __args);
301 EXPORT int sprintf(char *buf, const char *format, ...)
305 va_start(args, format);
306 ret = vsprintf((char*)buf, (char*)format, args);
311 void _vfprintf_putch(void *h, char ch)
316 EXPORT int vfprintf(FILE *__fp, const char *__format, va_list __args)
318 return _vcprintf_int(_vfprintf_putch, __fp, __format, __args);
321 EXPORT int fprintf(FILE *fp, const char *format, ...)
327 va_start(args, format);
328 ret = vfprintf(fp, (char*)format, args);
334 EXPORT int vprintf(const char *__format, va_list __args)
336 return vfprintf(stdout, __format, __args);
339 EXPORT int printf(const char *format, ...)
345 va_start(args, format);
346 ret = vprintf(format, args);
353 void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned)
355 struct s_sprintf_info info = {buf, 0, 1024};
357 _printf_itoa(_vsnprintf_putch, &info, num, base, minLength, pad, bSigned);
358 buf[info.ofs] = '\0';
361 const char cDIGITS[] = "0123456789abcdef";
363 * \brief Convert an integer into a character string
364 * \param buf Destination Buffer
365 * \param num Number to convert
366 * \param base Base-n number output
367 * \param minLength Minimum length of output
368 * \param pad Padding used to ensure minLength
369 * \param bSigned Signed number output?
371 size_t _printf_itoa(printf_putch_t putch_cb, void *putch_h, uint64_t num, size_t base, int minLength, char pad, int bSigned)
377 if(base > 16 || base < 2) {
381 if(bSigned && (int64_t)num < 0)
388 // Encode into reversed string
389 while(num > base-1) {
390 tmpBuf[pos++] = cDIGITS[ num % base ];
391 num = (uint64_t) num / (uint64_t)base; // Shift {number} right 1 digit
394 tmpBuf[pos++] = cDIGITS[ num % base ]; // Last digit of {number}
395 if(bSigned) tmpBuf[pos++] = '-'; // Append sign symbol if needed
398 while(minLength-- > 0) {
399 putch_cb(putch_h, pad);
403 putch_cb(putch_h, tmpBuf[pos]); // Reverse the order of characters
410 int expand_double(double num, uint64_t *Significand, int16_t *Exponent, int *SignIsNeg)
415 uint64_t test_exp = 0xC000000000000000;
416 double test_value = -2.0f;
417 assert( *((uint64_t*)&test_value) == test_exp );
421 const uint64_t *bit_rep = (void*)#
423 *SignIsNeg = *bit_rep >> 63;
424 *Exponent = ((*bit_rep >> 52) & 0x7FF) - 1023;
425 *Significand = (*bit_rep & ((1ULL << 52)-1)) << (64-52);
427 // printf("%llx %i %i %llx\n", *bit_rep, (int)*SignIsNeg, (int)*Exponent, *Significand);
430 if( *Exponent == -1023 && *Significand != 0 )
433 if( *Exponent == 0x800 && *Significand == 0)
436 if( *Exponent == 0x800 && *Significand != 0)
446 double _longdiv(double num, double den, int *quot)
450 // printf("%llu / %llu\n", (long long int)num, (long long int)den);
453 assert(num < den*10);
458 assert( *quot < 10 );
460 // printf(" %i\n", *quot);
464 size_t _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, size_t Base, enum eFPN Notation, int Precision, int bForcePoint, int bForceSign, int bCapitals)
466 uint64_t significand;
472 #define _putch(_ch) do{\
474 putch_cb(putch_h, toupper(_ch));\
476 putch_cb(putch_h, _ch);\
480 if( Base <= 1 || Base > 16 )
483 rv = expand_double(num, &significand, &exponent, &signisneg);
486 // 0: No errors, nothing special
491 // TODO: Subnormal = 0?
506 // - Used as 0/1 bools in arithmatic later on
507 bForcePoint = !!bForcePoint;
508 bForceSign = !!bForceSign;
510 // Apply default to precision
511 if( Precision == -1 )
517 // Select optimum type
518 if( Notation == FPN_SHORTEST )
521 //int first_set_sig = BSL(significand);
522 // TODO: if( num > pos(Base, 2+Precision+2+log_base(exponent) )
526 double precision_max = 1;
528 precision_max /= Base;
530 // Determine scientific's exponent and starting denominator
532 int sci_exponent = 0;
533 if( Notation == FPN_SCI )
543 else if( num >= Base )
567 else if( bForceSign )
576 num = _longdiv(num, den, &value);
577 _putch(cDIGITS[value]);
581 // Decimal point (if needed/forced)
582 if( den >= precision_max || bForcePoint )
585 while( den >= precision_max )
587 num = _longdiv(num, den, &value);
588 _putch(cDIGITS[value]);
592 if( Notation == FPN_SCI )
601 sci_exponent = -sci_exponent;
605 _printf_itoa(putch_cb, putch_h, sci_exponent, Base, 0, 0, 0);