Usermode/libc - Fix time conversion code
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / printf.c
index 223518f..905f790 100644 (file)
 #include <ctype.h>     // toupper
 #include <assert.h>    // assert() 
 
+// Quick booleans
+typedef char   BOOL;
+#define TRUE   1
+#define FALSE  0
+
 // === TYPES ===
-typedef void   (*printf_putch_t)(void *h, char ch);
+typedef void   (*printf_puts_t)(void *h, const char *s, size_t len);
 enum eFPN {
        FPN_STD,
        FPN_SCI,
@@ -22,8 +27,12 @@ enum eFPN {
 
 // === PROTOTYPES ===
 void   itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned);
-size_t _printf_itoa(printf_putch_t putch_cb, void *putch_h, uint64_t num, size_t base, int minLength, char pad, int bSigned);
-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);
+size_t _printf_itoa(printf_puts_t puts_cb, void *puts_h, uint64_t num,
+       size_t base, int bUpper,
+       int bSigned, char SignChar, int Precision,
+       int PadLength, char PadChar, int bPadRight);
+size_t _printf_ftoa_hex(printf_puts_t puts_cb, void *puts_h, long double num, int Precision, int bForcePoint, int bForceSign, int bCapitals);
+size_t _printf_ftoa(printf_puts_t puts_cb, void *puts_h, long double num, size_t Base, enum eFPN Notation, int Precision, int bForcePoint, int bForceSign, int bCapitals);
 
 // === CODE ===
 /**
@@ -33,30 +42,32 @@ size_t      _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, siz
  * \param format       String - Format String
  * \param args VarArgs List - Arguments
  */
-EXPORT int _vcprintf_int(printf_putch_t putch_cb, void *putch_h, const char *format, va_list args)
+EXPORT int _vcprintf_int(printf_puts_t puts_cb, void *puts_h, const char *format, va_list args)
 {
-       char    tmp[65];
         int    c, minSize, precision, len;
        size_t  pos = 0;
        char    *p;
-       char    pad;
        uint64_t        arg;
        long double     arg_f;
 //     char    cPositiveChar;
-        int    bLongLong, bPadLeft, bLong;
+       BOOL    bLongLong, bLong, bJustifyLeft, bAltForm;
+       char    cNumPad, cPlus;
 
        #define _addchar(ch) do { \
-               putch_cb(putch_h, ch); \
+               char _ch = ch; \
+               puts_cb(puts_h, &_ch, 1); \
                pos ++; \
        } while(0)
 
-       tmp[32] = '\0';
-       
        while((c = *format++) != 0)
        {
                // Non-control character
                if (c != '%') {
-                       _addchar(c);
+                       const char      *start = format-1;
+                       while( (c = *format) != 0 && c != '%' )
+                               format ++;
+                       puts_cb(puts_h, start, format - start);
+                       pos += format - start;
                        continue;
                }
                
@@ -67,41 +78,42 @@ EXPORT int _vcprintf_int(printf_putch_t putch_cb, void *putch_h, const char *for
                        continue;
                }
                
-               bPadLeft = 0;
+               bAltForm = 0;
+               cNumPad = ' ';
+               bJustifyLeft = 0;
+               cPlus = '\0';
                bLong = 0;
                bLongLong = 0;
                minSize = 0;
                precision = -1;
-//             cPositiveChar = '\0';
-               pad = ' ';
                
                // - Flags
-               // Alternate form (0<oct>, 0x<hex>, 123.)
-               if(c == '#') {
-                       // TODO:
-                       c = *format++;
-               }
-               // Padding with '0'
-               if(c == '0') {
-                       pad = '0';
-                       c = *format++;
-               }
-               // Pad on left
-               if(c == '-') {
-                       bPadLeft = 1;
-                       c = *format++;
-               }
-               // Include space for positive sign
-               if(c == ' ') {
-                       // TODO:
-//                     cPositiveChar = ' ';
-                       c = *format++;
-               }
-               // Always include sign
-               if(c == '+') {
-//                     cPositiveChar = '+';
-                       c = *format++;
+               do
+               {
+                       // Alternate form (0<oct>, 0x<hex>, 123.)
+                       if(c == '#') {
+                               bAltForm = 1;
+                       }
+                       // Padding with '0'
+                       else if(c == '0') {
+                               cNumPad = '0';
+                       }
+                       // Pad on left
+                       else if(c == '-') {
+                               bJustifyLeft = 1;
+                       }
+                       // Include space for positive sign
+                       else if(c == ' ') {
+                               cPlus = ' ';
+                       }
+                       // Always include sign
+                       else if(c == '+') {
+                               cPlus = '+';
+                       }
+                       else
+                               break;
                }
+               while( (c = *format++) );
                
                // Padding length
                if( c == '*' ) {
@@ -150,29 +162,26 @@ EXPORT int _vcprintf_int(printf_putch_t putch_cb, void *putch_h, const char *for
                        }
                }
                
-               // Just help things along later
-               p = tmp;
-               
                // Get Type
                switch( c )
                {
                // Signed Integer
-               case 'd':       case 'i':
+               case 'd':
+               case 'i':
                        // Get Argument
-                       if(bLongLong)   arg = va_arg(args, int64_t);
-                       else                    arg = va_arg(args, int32_t);
-                       itoa(tmp, arg, 10, minSize, pad, 1);
-                       precision = -1;
-                       goto sprintf_puts;
+                       arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
+                       if( arg == 0 && precision == 0 )
+                               break;
+                       pos += _printf_itoa(puts_cb, puts_h, arg, 10, FALSE,
+                               TRUE, cPlus, precision, minSize, cNumPad, bJustifyLeft);
+                       break;
                
                // Unsigned Integer
                case 'u':
-                       // Get Argument
-                       if(bLongLong)   arg = va_arg(args, uint64_t);
-                       else                    arg = va_arg(args, uint32_t);
-                       itoa(tmp, arg, 10, minSize, pad, 0);
-                       precision = -1;
-                       goto sprintf_puts;
+                       arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
+                       pos += _printf_itoa(puts_cb, puts_h, arg, 10, FALSE,
+                               FALSE, '\0', precision, minSize, cNumPad, bJustifyLeft);
+                       break;
                
                // Pointer
                case 'p':
@@ -180,73 +189,84 @@ EXPORT int _vcprintf_int(printf_putch_t putch_cb, void *putch_h, const char *for
                        _addchar('0');
                        _addchar('x');
                        arg = va_arg(args, intptr_t);
-                       itoa(tmp, arg, 16, minSize, pad, 0);
-                       precision = -1;
-                       goto sprintf_puts;
+                       pos += _printf_itoa(puts_cb, puts_h, arg, 16, FALSE,
+                               FALSE, '\0', sizeof(intptr_t)*2, 0,'\0',FALSE);
+                       break;
                // Unsigned Hexadecimal
+               case 'X':
                case 'x':
-                       if(bLongLong)   arg = va_arg(args, uint64_t);
-                       else                    arg = va_arg(args, uint32_t);
-                       itoa(tmp, arg, 16, minSize, pad, 0);
-                       precision = -1;
-                       goto sprintf_puts;
+                       if(bAltForm) {
+                               _addchar('0');
+                               _addchar(c);
+                       }
+                       arg = bLongLong ? va_arg(args, uint64_t) : va_arg(args, uint32_t);
+                       pos += _printf_itoa(puts_cb, puts_h, arg, 16, c=='X',
+                               FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
+                       break;
                
                // Unsigned Octal
                case 'o':
-                       if(bLongLong)   arg = va_arg(args, uint64_t);
-                       else                    arg = va_arg(args, uint32_t);
-                       itoa(tmp, arg, 8, minSize, pad, 0);
-                       precision = -1;
-                       goto sprintf_puts;
+                       if(bAltForm) {
+                               _addchar('0');
+                       }
+                       arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
+                       pos += _printf_itoa(puts_cb, puts_h, arg, 8, FALSE,
+                               FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
+                       break;
                
                // Unsigned binary
                case 'b':
-                       if(bLongLong)   arg = va_arg(args, uint64_t);
-                       else                    arg = va_arg(args, uint32_t);
-                       itoa(tmp, arg, 2, minSize, pad, 0);
-                       precision = -1;
-                       goto sprintf_puts;
+                       if(bAltForm) {
+                               _addchar('0');
+                               _addchar('b');
+                       }
+                       arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
+                       pos += _printf_itoa(puts_cb, puts_h, arg, 2, FALSE,
+                               FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
+                       break;
 
                // Standard float
                case 'f':
-                       if(bLong)       arg_f = va_arg(args, long double);
-                       else    arg_f = va_arg(args, double);
-                       pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_STD, precision, 0, bPadLeft, 0);
-                       break;
                case 'F':
-                       if(bLong)       arg_f = va_arg(args, long double);
-                       else    arg_f = va_arg(args, double);
-                       pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_STD, precision, 0, bPadLeft, 1);
+                       arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
+                       pos += _printf_ftoa(puts_cb, puts_h, arg_f, 10, FPN_STD,
+                               precision, 0, bJustifyLeft, c == 'F');
                        break;
                // Scientific Float
                case 'e':
-                       if(bLong)       arg_f = va_arg(args, long double);
-                       else    arg_f = va_arg(args, double);
-                       pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_SCI, precision, 0, bPadLeft, 0);
-                       break;
                case 'E':
-                       if(bLong)       arg_f = va_arg(args, long double);
-                       else    arg_f = va_arg(args, double);
-                       pos += _printf_ftoa(putch_cb, putch_h, arg_f, 10, FPN_SCI, precision, 0, bPadLeft, 1);
+                       arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
+                       pos += _printf_ftoa(puts_cb, puts_h, arg_f, 10, FPN_SCI,
+                               precision, 0, bJustifyLeft, c == 'E');
+                       break;
+               // Scientific Float
+               case 'g':
+               case 'G':
+                       arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
+                       pos += _printf_ftoa(puts_cb, puts_h, arg_f, 10, FPN_SHORTEST,
+                               precision, 0, bJustifyLeft, c == 'G');
+                       break;
+               // Hexadecimal Scientific
+               case 'a':
+               case 'A':
+                       arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
+                       pos += _printf_ftoa_hex(puts_cb, puts_h, arg_f, precision, 0, bJustifyLeft, c == 'A');
                        break;
 
                // String
                case 's':
                        p = va_arg(args, char*);
-               sprintf_puts:
                        if(!p)  p = "(null)";
                        //_SysDebug("vsnprintf: p = '%s'", p);
                        if(precision >= 0)
                                len = strnlen(p, precision);
                        else
                                len = strlen(p);
-                       if(bPadLeft)    while(minSize > len++)  _addchar(pad);
-                       while( *p ) {
-                               if(precision >= 0 && precision -- == 0)
-                                       break;
-                               _addchar(*p++);
-                       }
-                       if(!bPadLeft)   while(minSize > len++)  _addchar(pad);
+                       if(!bJustifyLeft)
+                               while(minSize-- > len)  _addchar(' ');
+                       puts_cb(puts_h, p, len); pos += len;
+                       if(bJustifyLeft)
+                               while(minSize-- > len)  _addchar(' ');
                        break;
 
                // Unknown, just treat it as a character
@@ -267,19 +287,19 @@ struct s_sprintf_info {
        size_t  maxlen;
 };
 
-void _vsnprintf_putch(void *h, char ch)
+void _vsnprintf_puts(void *h, const char *str, size_t len)
 {
        struct s_sprintf_info   *info = h;
-       if(info->ofs < info->maxlen)
-               info->dest[info->ofs++] = ch;
+       while( info->ofs < info->maxlen && len -- )
+               info->dest[info->ofs++] = *str++;
 }
 
 EXPORT int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list __args)
 {
        struct s_sprintf_info   info = {__s, 0, __maxlen};
        int ret;
-       ret = _vcprintf_int(_vsnprintf_putch, &info, __format, __args);
-       _vsnprintf_putch(&info, '\0');
+       ret = _vcprintf_int(_vsnprintf_puts, &info, __format, __args);
+       _vsnprintf_puts(&info, "", 1);
        return ret;
 }
 
@@ -308,14 +328,14 @@ EXPORT int sprintf(char *buf, const char *format, ...)
        return ret;
 }
 
-void _vfprintf_putch(void *h, char ch)
+void _vfprintf_puts(void *h, const char *str, size_t len)
 {
-       fputc(ch, h);
+       fwrite(str, len, 1, h);
 }
 
 EXPORT int vfprintf(FILE *__fp, const char *__format, va_list __args)
 {
-       return _vcprintf_int(_vfprintf_putch, __fp, __format, __args);
+       return _vcprintf_int(_vfprintf_puts, __fp, __format, __args);
 }
 
 EXPORT int fprintf(FILE *fp, const char *format, ...)
@@ -354,11 +374,12 @@ void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSi
 {
        struct s_sprintf_info   info = {buf, 0, 1024};
        if(!buf)        return;
-       _printf_itoa(_vsnprintf_putch, &info, num, base, minLength, pad, bSigned);
+       _printf_itoa(_vsnprintf_puts, &info, num, base, FALSE, bSigned, '\0', 0, minLength, pad, FALSE);
        buf[info.ofs] = '\0';
 }
 
 const char cDIGITS[] = "0123456789abcdef";
+const char cUDIGITS[] = "0123456789ABCDEF";
 /**
  * \brief Convert an integer into a character string
  * \param buf  Destination Buffer
@@ -368,11 +389,16 @@ const char cDIGITS[] = "0123456789abcdef";
  * \param pad  Padding used to ensure minLength
  * \param bSigned      Signed number output?
  */
-size_t _printf_itoa(printf_putch_t putch_cb, void *putch_h, uint64_t num, size_t base, int minLength, char pad, int bSigned)
+size_t _printf_itoa(printf_puts_t puts_cb, void *puts_h, uint64_t num,
+       size_t base, int bUpper,
+       int bSigned, char SignChar, int Precision,
+       int PadLength, char PadChar, int bPadRight)
 {
-       char    tmpBuf[64];
-        int    pos=0;
-       size_t ret = 0;
+       char    tmpBuf[64+1];
+        int    pos = sizeof(tmpBuf);
+       size_t  ret = 0;
+        int    sign_is_neg = 0;
+       const char *map = bUpper ? cUDIGITS : cDIGITS;
 
        if(base > 16 || base < 2) {
                return 0;
@@ -380,28 +406,47 @@ size_t _printf_itoa(printf_putch_t putch_cb, void *putch_h, uint64_t num, size_t
        
        if(bSigned && (int64_t)num < 0)
        {
-               num = -num;
-               bSigned = 1;
-       } else
-               bSigned = 0;
+               num = -(int64_t)num;
+               sign_is_neg = 1;
+       }
        
-       // Encode into reversed string
+       // Encode into string
        while(num > base-1) {
-               tmpBuf[pos++] = cDIGITS[ num % base ];
+               tmpBuf[--pos] = map[ num % base ];
                num = (uint64_t) num / (uint64_t)base;          // Shift {number} right 1 digit
        }
-
-       tmpBuf[pos++] = cDIGITS[ num % base ];          // Last digit of {number}
-       if(bSigned)     tmpBuf[pos++] = '-';    // Append sign symbol if needed
+       tmpBuf[--pos] = map[ num % base ];              // Most significant digit of {number}
+
+       // TODO: This assertion may not be valid
+       assert(Precision <= (int)sizeof(tmpBuf));
+       Precision -= sizeof(tmpBuf)-pos + (sign_is_neg || SignChar != '\0');
+       while( Precision-- > 0 )
+               tmpBuf[--pos] = '0';
+
+       // Sign 
+       if(sign_is_neg)
+               tmpBuf[--pos] = '-';    // Negative sign character
+       else if(SignChar)
+               tmpBuf[--pos] = SignChar;       // positive sign character
+       else {
+       }
        
-       minLength -= pos;
-       while(minLength-- > 0) {
-               putch_cb(putch_h, pad);
-               ret ++;
+       // length of number, minus the sign character
+       size_t len = sizeof(tmpBuf)-pos;
+       PadLength -= len;
+       if( !bPadRight )
+       {
+               while(PadLength-- > 0)
+                       puts_cb(puts_h, &PadChar, 1), ret ++;
        }
-       while(pos-- > 0) {
-               putch_cb(putch_h, tmpBuf[pos]); // Reverse the order of characters
-               ret ++;
+       
+       puts_cb(puts_h, tmpBuf+pos, len);
+       ret += len;
+
+       if( bPadRight )
+       {
+               while(PadLength-- > 0)
+                       puts_cb(puts_h, &PadChar, 1), ret ++;
        }
        
        return ret;
@@ -427,13 +472,13 @@ int expand_double(double num, uint64_t *Significand, int16_t *Exponent, int *Sig
 //     printf("%llx %i %i %llx\n", *bit_rep, (int)*SignIsNeg, (int)*Exponent, *Significand);
 
        // Subnormals
-       if( *Exponent == -1023 && *Significand != 0 )
+       if( *Exponent == -0x3FF && *Significand != 0 )
                return 1;
        // Infinity
-       if( *Exponent == 0x800 && *Significand == 0)
+       if( *Exponent == 0x400 && *Significand == 0)
                return 2;
        // NaNs
-       if( *Exponent == 0x800 && *Significand != 0)
+       if( *Exponent == 0x400 && *Significand != 0)
                return 3;
 
        return 0;
@@ -461,7 +506,7 @@ double _longdiv(double num, double den, int *quot)
        return num;
 }
 
-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)
+size_t _printf_ftoa_hex(printf_puts_t puts_cb, void *puts_h, long double num, int Precision, int bForcePoint, int bForceSign, int bCapitals)
 {
        uint64_t        significand;
        int16_t exponent;
@@ -470,10 +515,175 @@ size_t _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, siz
        size_t  ret = 0;
 
        #define _putch(_ch) do{\
-               if(bCapitals)\
-                       putch_cb(putch_h, toupper(_ch));\
-               else\
-                       putch_cb(putch_h, _ch);\
+               char __ch = (bCapitals ? toupper(_ch) : _ch);\
+               puts_cb(puts_h, &__ch, 1); \
+               ret ++;\
+       }while(0)
+
+       if( Precision == -1 )
+               Precision = (64-4)/4;
+
+       rv = expand_double(num, &significand, &exponent, &signisneg);
+       switch(rv)
+       {
+       // 0: No errors, nothing special
+       case 0:
+               break;
+       // 1: Subnormals
+       case 1:
+               // TODO: Subnormal = 0?
+               break;
+       // 2: Infinity
+       case 2:
+               puts_cb(puts_h, "inf", 3);
+               return 3;
+       case 3:
+               puts_cb(puts_h, "NaN", 3);
+               return 3;
+       }
+       
+       // int  exp_ofs = exponent % 4;
+       // int  exp_16 = exponent - exp_ofs;
+       //uint8_t       whole = (1 << exp_ofs) | ((significand >> (64-3)) >> exp_ofs);
+       //significand <<= 3 - exp_ofs;
+       uint8_t whole = (rv != 1) ? 1 : 0;
+       
+       if( signisneg )
+               _putch('-');
+       else if( bForceSign )
+               _putch('+');
+       else {
+       }
+       _putch('0');
+       _putch('x');
+       _putch(cDIGITS[whole]);
+       if( significand || bForcePoint )
+               _putch('.');
+       // Fractional
+       while( significand && Precision -- )
+       {
+               uint8_t val = significand >> (64-4);
+               _putch(cDIGITS[val]);
+               significand <<= 4;
+       }
+       _putch('p');
+       //ret += _printf_itoa(puts_cb, puts_h, exp_16, 16, bCapitals, TRUE, '+', 0, 0, '\0', 0);
+       ret += _printf_itoa(puts_cb, puts_h, exponent, 10, bCapitals, TRUE, '+', 0, 0, '\0', 0);
+       
+       #undef _putch
+       return ret;
+}
+
+#if 0
+size_t _printf_itoa_fixed(printf_putch_t putch_cb, void *putch_h, uint64_t num, size_t Base)
+{
+       uint64_t        den;
+       size_t  ret = 0;
+
+       den = 1ULL << (64-1);
+       
+       while( den )
+       {
+               putch_cb(putch_h, cDIGITS[num / den]);
+               ret ++;
+               num %= den;
+               den /= Base;
+       }
+
+       return ret;
+}
+
+size_t _printf_ftoa_dec(printf_putch_t putch_cb, void *putch_h, long double num, enum eFPN Notation, int Precision, int bForcePoint, int bForceSign, int bCapitals)
+{
+       size_t  ret = 0;
+        int    i;
+
+       #define _putch(_ch) do{\
+               putch_cb(putch_h, bCapitals ? toupper(_ch) : _ch), ret++;\
+       }while(0)
+       
+       uint64_t        significand;
+        int16_t        exponent;
+        int    signisneg;
+        int    rv = expand_double(num, &significand, &exponent, &signisneg);
+       switch(rv)
+       {
+       // 0: No errors, nothing special
+       case 0:
+               break;
+       // 1: Subnormals
+       case 1:
+               // TODO: Subnormal = 0?
+               break;
+       // 2: Infinity
+       case 2:
+               _putch('i');
+               _putch('n');
+               _putch('f');
+               return 3;
+       case 3:
+               _putch('N');
+               _putch('a');
+               _putch('N');
+               return 3;
+       }
+
+       uint64_t        whole, part;
+        int    pre_zeros, post_zeros;
+
+       #define XXX     0
+       if( Notation == FPN_SCI )
+       {
+       }
+       else if( exponent < 0 )
+       {
+               whole = 0;
+               part = XXX;
+               pre_zeros = 0;
+               post_zeros = XXX;
+       }
+       else if( exponent >= 64 )
+       {
+               part = 0;
+               whole = XXX;
+               pre_zeros = XXX;
+               post_zeros = 0;
+       }
+       else
+       {
+               // Split into fixed point
+               whole = (1 << exponent) | (significand >> (64-exponent));
+               part = significand << exponent;
+               pre_zeros = 0;
+               post_zeros = 0;
+       }
+
+       
+       // Whole portion
+       ret += _printf_itoa(putch_cb, putch_h, whole, 10, FALSE, FALSE, '\0', 0, 0, '\0', FALSE);
+       for(i = pre_zeros; i --; )      _putch('0');
+       // TODO: Conditional point
+       _putch('-');
+       for(i = post_zeros; i--; )      _putch('0');
+       ret += _printf_itoa_fixed(putch_cb, putch_h, part, 10);
+       
+       #undef _putch
+
+       return 0;
+}
+#endif
+
+size_t _printf_ftoa(printf_puts_t puts_cb, void *puts_h, long double num, size_t Base, enum eFPN Notation, int Precision, int bForcePoint, int bForceSign, int bCapitals)
+{
+       uint64_t        significand;
+       int16_t exponent;
+        int    signisneg;
+        int    rv, i;
+       size_t  ret = 0;
+
+       #define _putch(_ch) do{\
+               char __ch = (bCapitals ? toupper(_ch) : _ch);\
+               puts_cb(puts_h, &__ch, 1); \
                ret ++;\
        }while(0)
 
@@ -519,12 +729,24 @@ size_t _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, siz
        {
                //TODO:
                //int   first_set_sig = BSL(significand);
-       //      TODO: if( num > pos(Base, 2+Precision+2+log_base(exponent) )
-               Notation = FPN_SCI;
+               // bSign+log10(num)+1+precision vs. bSign+1+1+precision+1+1+log10(exponent)
+                int    log10_num = exponent * 301 / 1000;      // log_10(2) = 0.30102999566...
+                int    log10_exp10 = 2;
+                int    sci_len = (signisneg || bForceSign) + 2 + (Precision-1) + 2 + log10_exp10;
+                int    std_whole_len = (log10_num > 0 ? log10_num : 1);
+                int    std_len = (signisneg || bForceSign) + std_whole_len + 1 + (Precision-std_whole_len);
+               if( sci_len > std_len ) {
+                       Precision -= std_whole_len;
+                       Notation = FPN_STD;
+               }
+               else {
+                       Precision -= 1;
+                       Notation = FPN_SCI;
+               }
        }
 
        double precision_max = 1;
-       while(Precision--)
+       for(i = Precision; i--; )
                precision_max /= Base;
 
        // Determine scientific's exponent and starting denominator
@@ -554,9 +776,9 @@ size_t _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, siz
                }
                den = 1;
        }
-       else
+       else if( num != 0.0 )
        {
-               while( den < num )
+               while( den <= num )
                        den *= Base;
                den /= Base;
        }
@@ -568,6 +790,8 @@ size_t _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, siz
                _putch('+');
        else {
        }
+       
+       num += precision_max/10 * 4.999;
 
         int    value;
        // Whole section
@@ -579,10 +803,10 @@ size_t _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, siz
        } while( den >= 1 );
 
        // Decimal point (if needed/forced)     
-       if( den >= precision_max || bForcePoint )
+       if( Precision > 0 || bForcePoint )
                _putch('.');
        // Decimal section
-       while( den >= precision_max )
+       for(i = Precision; i--; )
        {
                num = _longdiv(num, den, &value);
                _putch(cDIGITS[value]);
@@ -595,14 +819,7 @@ size_t _printf_ftoa(printf_putch_t putch_cb, void *putch_h, long double num, siz
                        _putch('p');
                else
                        _putch('e');
-               if(sci_exponent < 0)
-               {
-                       _putch('-');
-                       sci_exponent = -sci_exponent;
-               }
-               else
-                       _putch('+');
-               _printf_itoa(putch_cb, putch_h, sci_exponent, Base, 0, 0, 0);
+               ret += _printf_itoa(puts_cb, puts_h, sci_exponent, Base, FALSE, TRUE, '+', 3, 0, '\0', FALSE);
        }       
 
        #undef _putch

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