3 * - By John Hodge (thePowersGang)
6 * - *scanf family of functions
12 #include <ctype.h> // toupper
13 #include <assert.h> // assert()
21 typedef void (*printf_putch_t)(void *h, char ch);
29 void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned);
30 size_t _printf_itoa(printf_putch_t putch_cb, void *putch_h, uint64_t num,
31 size_t base, int bUpper,
32 int bSigned, char SignChar, int Precision,
33 int PadLength, char PadChar, int bPadRight);
34 size_t _printf_ftoa_hex(printf_putch_t putch_cb, void *putch_h, long double num, int Precision, int bForcePoint, int bForceSign, int bCapitals);
35 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);
39 * \fn EXPORT void vsnprintf(char *buf, const char *format, va_list args)
40 * \brief Prints a formatted string to a buffer
41 * \param buf Pointer - Destination Buffer
42 * \param format String - Format String
43 * \param args VarArgs List - Arguments
45 EXPORT int _vcprintf_int(printf_putch_t putch_cb, void *putch_h, const char *format, va_list args)
48 int c, minSize, precision, len;
53 // char cPositiveChar;
54 BOOL bLongLong, bLong, bJustifyLeft, bAltForm;
57 #define _addchar(ch) do { \
58 putch_cb(putch_h, ch); \
64 while((c = *format++) != 0)
66 // Non-control character
74 if(c == '%') { // Literal %
91 // Alternate form (0<oct>, 0x<hex>, 123.)
103 // Include space for positive sign
107 // Always include sign
114 while( (c = *format++) );
119 minSize = va_arg(args, size_t);
122 else if('1' <= c && c <= '9')
125 while('0' <= c && c <= '9')
137 precision = va_arg(args, size_t);
140 else if('1' <= c && c <= '9')
143 while('0' <= c && c <= '9')
146 precision += c - '0';
152 // Check for long long
163 // Just help things along later
173 arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
174 if( arg == 0 && precision == 0 )
176 pos += _printf_itoa(putch_cb, putch_h, arg, 10, FALSE,
177 TRUE, cPlus, precision, minSize, cNumPad, bJustifyLeft);
182 arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
183 pos += _printf_itoa(putch_cb, putch_h, arg, 10, FALSE,
184 FALSE, '\0', precision, minSize, cNumPad, bJustifyLeft);
192 arg = va_arg(args, intptr_t);
193 pos += _printf_itoa(putch_cb, putch_h, arg, 16, FALSE,
194 FALSE, '\0', sizeof(intptr_t)*2, 0,'\0',FALSE);
196 // Unsigned Hexadecimal
203 arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
204 pos += _printf_itoa(putch_cb, putch_h, arg, 16, c=='X',
205 FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
213 arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
214 pos += _printf_itoa(putch_cb, putch_h, arg, 8, FALSE,
215 FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
224 arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
225 pos += _printf_itoa(putch_cb, putch_h, arg, 2, FALSE,
226 FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
232 arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
233 pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_STD,
234 precision, 0, bJustifyLeft, c == 'F');
239 arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
240 pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_SCI,
241 precision, 0, bJustifyLeft, c == 'E');
243 // Hexadecimal Scientific
246 arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
247 pos += _printf_ftoa_hex(putch_cb, putch_h, arg_f, precision, 0, bJustifyLeft, c == 'A');
252 p = va_arg(args, char*);
254 //_SysDebug("vsnprintf: p = '%s'", p);
256 len = strnlen(p, precision);
260 while(minSize > len++) _addchar(' ');
262 if(precision >= 0 && precision -- == 0)
267 while(minSize > len++) _addchar(' ');
270 // Unknown, just treat it as a character
272 arg = va_arg(args, uint32_t);
282 struct s_sprintf_info {
288 void _vsnprintf_putch(void *h, char ch)
290 struct s_sprintf_info *info = h;
291 if(info->ofs < info->maxlen)
292 info->dest[info->ofs++] = ch;
295 EXPORT int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list __args)
297 struct s_sprintf_info info = {__s, 0, __maxlen};
299 ret = _vcprintf_int(_vsnprintf_putch, &info, __format, __args);
300 _vsnprintf_putch(&info, '\0');
304 EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...)
308 va_start(args, format);
309 ret = vsnprintf((char*)buf, maxlen, (char*)format, args);
315 EXPORT int vsprintf(char * __s, const char *__format, va_list __args)
317 return vsnprintf(__s, 0x7FFFFFFF, __format, __args);
319 EXPORT int sprintf(char *buf, const char *format, ...)
323 va_start(args, format);
324 ret = vsprintf((char*)buf, (char*)format, args);
329 void _vfprintf_putch(void *h, char ch)
334 EXPORT int vfprintf(FILE *__fp, const char *__format, va_list __args)
336 return _vcprintf_int(_vfprintf_putch, __fp, __format, __args);
339 EXPORT int fprintf(FILE *fp, const char *format, ...)
345 va_start(args, format);
346 ret = vfprintf(fp, (char*)format, args);
352 EXPORT int vprintf(const char *__format, va_list __args)
354 return vfprintf(stdout, __format, __args);
357 EXPORT int printf(const char *format, ...)
363 va_start(args, format);
364 ret = vprintf(format, args);
371 void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned)
373 struct s_sprintf_info info = {buf, 0, 1024};
375 _printf_itoa(_vsnprintf_putch, &info, num, base, FALSE, bSigned, '\0', 0, minLength, pad, FALSE);
376 buf[info.ofs] = '\0';
379 const char cDIGITS[] = "0123456789abcdef";
380 const char cUDIGITS[] = "0123456789ABCDEF";
382 * \brief Convert an integer into a character string
383 * \param buf Destination Buffer
384 * \param num Number to convert
385 * \param base Base-n number output
386 * \param minLength Minimum length of output
387 * \param pad Padding used to ensure minLength
388 * \param bSigned Signed number output?
390 size_t _printf_itoa(printf_putch_t putch_cb, void *putch_h, uint64_t num,
391 size_t base, int bUpper,
392 int bSigned, char SignChar, int Precision,
393 int PadLength, char PadChar, int bPadRight)
399 const char *map = bUpper ? cUDIGITS : cDIGITS;
401 if(base > 16 || base < 2) {
405 if(bSigned && (int64_t)num < 0)
411 // Encode into reversed string
412 while(num > base-1) {
413 tmpBuf[pos++] = map[ num % base ];
414 num = (uint64_t) num / (uint64_t)base; // Shift {number} right 1 digit
417 tmpBuf[pos++] = map[ num % base ]; // Last digit of {number}
419 // length of number, minus the sign character
420 PadLength -= pos - sign_is_neg - (SignChar != '\0');
423 while(PadLength-- > 0)
424 putch_cb(putch_h, PadChar), ret ++;
428 putch_cb(putch_h, '-'), ret++; // Negative sign character
430 putch_cb(putch_h, SignChar), ret++; // positive sign character
434 while( Precision-- > 0 )
435 putch_cb(putch_h, '0'), ret++;
437 putch_cb(putch_h, tmpBuf[pos]), ret++; // Reverse the order of characters
441 while(PadLength-- > 0)
442 putch_cb(putch_h, PadChar), ret ++;
448 int expand_double(double num, uint64_t *Significand, int16_t *Exponent, int *SignIsNeg)
453 uint64_t test_exp = 0xC000000000000000;
454 double test_value = -2.0f;
455 assert( *((uint64_t*)&test_value) == test_exp );
459 const uint64_t *bit_rep = (void*)#
461 *SignIsNeg = *bit_rep >> 63;
462 *Exponent = ((*bit_rep >> 52) & 0x7FF) - 1023;
463 *Significand = (*bit_rep & ((1ULL << 52)-1)) << (64-52);
465 // printf("%llx %i %i %llx\n", *bit_rep, (int)*SignIsNeg, (int)*Exponent, *Significand);
468 if( *Exponent == -1023 && *Significand != 0 )
471 if( *Exponent == 0x800 && *Significand == 0)
474 if( *Exponent == 0x800 && *Significand != 0)
484 double _longdiv(double num, double den, int *quot)
488 // printf("%llu / %llu\n", (long long int)num, (long long int)den);
491 assert(num < den*10);
496 assert( *quot < 10 );
498 // printf(" %i\n", *quot);
502 size_t _printf_ftoa_hex(printf_putch_t putch_cb, void *putch_h, long double num, int Precision, int bForcePoint, int bForceSign, int bCapitals)
504 uint64_t significand;
510 #define _putch(_ch) do{\
512 putch_cb(putch_h, toupper(_ch));\
514 putch_cb(putch_h, _ch);\
518 if( Precision == -1 )
519 Precision = (64-4)/4;
521 rv = expand_double(num, &significand, &exponent, &signisneg);
524 // 0: No errors, nothing special
529 // TODO: Subnormal = 0?
544 // int exp_ofs = exponent % 4;
545 // int exp_16 = exponent - exp_ofs;
546 //uint8_t whole = (1 << exp_ofs) | ((significand >> (64-3)) >> exp_ofs);
547 //significand <<= 3 - exp_ofs;
548 uint8_t whole = (rv != 1) ? 1 : 0;
552 else if( bForceSign )
558 _putch(cDIGITS[whole]);
559 if( significand || bForcePoint )
562 while( significand && Precision -- )
564 uint8_t val = significand >> (64-4);
565 _putch(cDIGITS[val]);
569 //ret += _printf_itoa(putch_cb, putch_h, exp_16, 16, bCapitals, TRUE, '+', 0, 0, '\0', 0);
570 ret += _printf_itoa(putch_cb, putch_h, exponent, 10, bCapitals, TRUE, '+', 0, 0, '\0', 0);
576 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)
578 uint64_t significand;
584 #define _putch(_ch) do{\
586 putch_cb(putch_h, toupper(_ch));\
588 putch_cb(putch_h, _ch);\
592 if( Base <= 1 || Base > 16 )
595 rv = expand_double(num, &significand, &exponent, &signisneg);
598 // 0: No errors, nothing special
603 // TODO: Subnormal = 0?
618 // - Used as 0/1 bools in arithmatic later on
619 bForcePoint = !!bForcePoint;
620 bForceSign = !!bForceSign;
622 // Apply default to precision
623 if( Precision == -1 )
629 // Select optimum type
630 if( Notation == FPN_SHORTEST )
633 //int first_set_sig = BSL(significand);
634 // TODO: if( num > pos(Base, 2+Precision+2+log_base(exponent) )
638 double precision_max = 1;
640 precision_max /= Base;
642 // Determine scientific's exponent and starting denominator
644 int sci_exponent = 0;
645 if( Notation == FPN_SCI )
655 else if( num >= Base )
679 else if( bForceSign )
688 num = _longdiv(num, den, &value);
689 _putch(cDIGITS[value]);
693 // Decimal point (if needed/forced)
694 if( den >= precision_max || bForcePoint )
697 while( den >= precision_max )
699 num = _longdiv(num, den, &value);
700 _putch(cDIGITS[value]);
704 if( Notation == FPN_SCI )
710 ret += _printf_itoa(putch_cb, putch_h, sci_exponent, Base, FALSE, TRUE, '+', 0, 0, '\0', FALSE);