2568ae827cc6af2497d91dbb49eb11ac2fd70195
[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 <ctype.h>      // toupper
13 #include <assert.h>     // assert() 
14
15 // Quick booleans
16 typedef char    BOOL;
17 #define TRUE    1
18 #define FALSE   0
19
20 // === TYPES ===
21 typedef void    (*printf_puts_t)(void *h, const char *s, size_t len);
22 enum eFPN {
23         FPN_STD,
24         FPN_SCI,
25         FPN_SHORTEST,
26 };
27
28 // === PROTOTYPES ===
29 void    itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned);
30 size_t  _printf_itoa(printf_puts_t puts_cb, void *puts_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_puts_t puts_cb, void *puts_h, long double num, int Precision, int bForcePoint, int bForceSign, int bCapitals);
35 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);
36
37 // === CODE ===
38 /**
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
44  */
45 EXPORT int _vcprintf_int(printf_puts_t puts_cb, void *puts_h, const char *format, va_list args)
46 {
47         char    tmp[65];
48          int    c, minSize, precision, len;
49         size_t  pos = 0;
50         char    *p;
51         uint64_t        arg;
52         long double     arg_f;
53 //      char    cPositiveChar;
54         BOOL    bLongLong, bLong, bJustifyLeft, bAltForm;
55         char    cNumPad, cPlus;
56
57         #define _addchar(ch) do { \
58                 char _ch = ch; \
59                 puts_cb(puts_h, &_ch, 1); \
60                 pos ++; \
61         } while(0)
62
63         tmp[32] = '\0';
64         
65         while((c = *format++) != 0)
66         {
67                 // Non-control character
68                 if (c != '%') {
69                         const char      *start = format-1;
70                         while( (c = *format) != 0 && c != '%' )
71                                 format ++;
72                         puts_cb(puts_h, start, format - start);
73                         pos += format - start;
74                         continue;
75                 }
76                 
77                 // Control Character
78                 c = *format++;
79                 if(c == '%') {  // Literal %
80                         _addchar('%');
81                         continue;
82                 }
83                 
84                 bAltForm = 0;
85                 cNumPad = ' ';
86                 bJustifyLeft = 0;
87                 cPlus = '\0';
88                 bLong = 0;
89                 bLongLong = 0;
90                 minSize = 0;
91                 precision = -1;
92                 
93                 // - Flags
94                 do
95                 {
96                         // Alternate form (0<oct>, 0x<hex>, 123.)
97                         if(c == '#') {
98                                 bAltForm = 1;
99                         }
100                         // Padding with '0'
101                         else if(c == '0') {
102                                 cNumPad = '0';
103                         }
104                         // Pad on left
105                         else if(c == '-') {
106                                 bJustifyLeft = 1;
107                         }
108                         // Include space for positive sign
109                         else if(c == ' ') {
110                                 cPlus = ' ';
111                         }
112                         // Always include sign
113                         else if(c == '+') {
114                                 cPlus = '+';
115                         }
116                         else
117                                 break;
118                 }
119                 while( (c = *format++) );
120                 
121                 // Padding length
122                 if( c == '*' ) {
123                         // Variable length
124                         minSize = va_arg(args, size_t);
125                         c = *format++;
126                 }
127                 else if('1' <= c && c <= '9')
128                 {
129                         minSize = 0;
130                         while('0' <= c && c <= '9')
131                         {
132                                 minSize *= 10;
133                                 minSize += c - '0';
134                                 c = *format++;
135                         }
136                 }
137
138                 // Precision
139                 if(c == '.') {
140                         c = *format++;
141                         if(c == '*') {
142                                 precision = va_arg(args, size_t);
143                                 c = *format++;
144                         }
145                         else if('1' <= c && c <= '9')
146                         {
147                                 precision = 0;
148                                 while('0' <= c && c <= '9')
149                                 {
150                                         precision *= 10;
151                                         precision += c - '0';
152                                         c = *format++;
153                                 }
154                         }
155                 }
156         
157                 // Check for long long
158                 if(c == 'l')
159                 {
160                         bLong = 1;
161                         c = *format++;
162                         if(c == 'l') {
163                                 bLongLong = 1;
164                                 c = *format++;
165                         }
166                 }
167                 
168                 // Just help things along later
169                 p = tmp;
170                 
171                 // Get Type
172                 switch( c )
173                 {
174                 // Signed Integer
175                 case 'd':
176                 case 'i':
177                         // Get Argument
178                         arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
179                         if( arg == 0 && precision == 0 )
180                                 break;
181                         pos += _printf_itoa(puts_cb, puts_h, arg, 10, FALSE,
182                                 TRUE, cPlus, precision, minSize, cNumPad, bJustifyLeft);
183                         break;
184                 
185                 // Unsigned Integer
186                 case 'u':
187                         arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
188                         pos += _printf_itoa(puts_cb, puts_h, arg, 10, FALSE,
189                                 FALSE, '\0', precision, minSize, cNumPad, bJustifyLeft);
190                         break;
191                 
192                 // Pointer
193                 case 'p':
194                         _addchar('*');
195                         _addchar('0');
196                         _addchar('x');
197                         arg = va_arg(args, intptr_t);
198                         pos += _printf_itoa(puts_cb, puts_h, arg, 16, FALSE,
199                                 FALSE, '\0', sizeof(intptr_t)*2, 0,'\0',FALSE);
200                         break;
201                 // Unsigned Hexadecimal
202                 case 'X':
203                 case 'x':
204                         if(bAltForm) {
205                                 _addchar('0');
206                                 _addchar(c);
207                         }
208                         arg = bLongLong ? va_arg(args, uint64_t) : va_arg(args, uint32_t);
209                         pos += _printf_itoa(puts_cb, puts_h, arg, 16, c=='X',
210                                 FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
211                         break;
212                 
213                 // Unsigned Octal
214                 case 'o':
215                         if(bAltForm) {
216                                 _addchar('0');
217                         }
218                         arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
219                         pos += _printf_itoa(puts_cb, puts_h, arg, 8, FALSE,
220                                 FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
221                         break;
222                 
223                 // Unsigned binary
224                 case 'b':
225                         if(bAltForm) {
226                                 _addchar('0');
227                                 _addchar('b');
228                         }
229                         arg = bLongLong ? va_arg(args, int64_t) : va_arg(args, int32_t);
230                         pos += _printf_itoa(puts_cb, puts_h, arg, 2, FALSE,
231                                 FALSE, '\0', precision, minSize,cNumPad,bJustifyLeft);
232                         break;
233
234                 // Standard float
235                 case 'f':
236                 case 'F':
237                         arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
238                         pos += _printf_ftoa(puts_cb, puts_h, arg_f, 10, FPN_STD,
239                                 precision, 0, bJustifyLeft, c == 'F');
240                         break;
241                 // Scientific Float
242                 case 'e':
243                 case 'E':
244                         arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
245                         pos += _printf_ftoa(puts_cb, puts_h, arg_f, 10, FPN_SCI,
246                                 precision, 0, bJustifyLeft, c == 'E');
247                         break;
248                 // Scientific Float
249                 case 'g':
250                 case 'G':
251                         arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
252                         pos += _printf_ftoa(puts_cb, puts_h, arg_f, 10, FPN_SHORTEST,
253                                 precision, 0, bJustifyLeft, c == 'G');
254                         break;
255                 // Hexadecimal Scientific
256                 case 'a':
257                 case 'A':
258                         arg_f = bLong ? va_arg(args, long double) : va_arg(args, double);
259                         pos += _printf_ftoa_hex(puts_cb, puts_h, arg_f, precision, 0, bJustifyLeft, c == 'A');
260                         break;
261
262                 // String
263                 case 's':
264                         p = va_arg(args, char*);
265                         if(!p)  p = "(null)";
266                         //_SysDebug("vsnprintf: p = '%s'", p);
267                         if(precision >= 0)
268                                 len = strnlen(p, precision);
269                         else
270                                 len = strlen(p);
271                         if(!bJustifyLeft)
272                                 while(minSize-- > len)  _addchar(' ');
273                         puts_cb(puts_h, p, len); pos += len;
274                         if(bJustifyLeft)
275                                 while(minSize-- > len)  _addchar(' ');
276                         break;
277
278                 // Unknown, just treat it as a character
279                 default:
280                         arg = va_arg(args, uint32_t);
281                         _addchar(arg);
282                         break;
283                 }
284         }
285         #undef _addchar
286         
287         return pos;
288 }
289
290 struct s_sprintf_info {
291         char    *dest;
292         size_t  ofs;
293         size_t  maxlen;
294 };
295
296 void _vsnprintf_puts(void *h, const char *str, size_t len)
297 {
298         struct s_sprintf_info   *info = h;
299         while( info->ofs < info->maxlen && len -- )
300                 info->dest[info->ofs++] = *str++;
301 }
302
303 EXPORT int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list __args)
304 {
305         struct s_sprintf_info   info = {__s, 0, __maxlen};
306         int ret;
307         ret = _vcprintf_int(_vsnprintf_puts, &info, __format, __args);
308         _vsnprintf_puts(&info, "", 1);
309         return ret;
310 }
311
312 EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...)
313 {
314          int    ret;
315         va_list args;
316         va_start(args, format);
317         ret = vsnprintf((char*)buf, maxlen, (char*)format, args);
318         va_end(args);
319         return ret;
320 }
321
322
323 EXPORT int vsprintf(char * __s, const char *__format, va_list __args)
324 {
325         return vsnprintf(__s, 0x7FFFFFFF, __format, __args);
326 }
327 EXPORT int sprintf(char *buf, const char *format, ...)
328 {
329          int    ret;
330         va_list args;
331         va_start(args, format);
332         ret = vsprintf((char*)buf, (char*)format, args);
333         va_end(args);
334         return ret;
335 }
336
337 void _vfprintf_puts(void *h, const char *str, size_t len)
338 {
339         fwrite(str, len, 1, h);
340 }
341
342 EXPORT int vfprintf(FILE *__fp, const char *__format, va_list __args)
343 {
344         return _vcprintf_int(_vfprintf_puts, __fp, __format, __args);
345 }
346
347 EXPORT int fprintf(FILE *fp, const char *format, ...)
348 {
349         va_list args;
350          int    ret;
351         
352         // Get Size
353         va_start(args, format);
354         ret = vfprintf(fp, (char*)format, args);
355         va_end(args);
356         
357         return ret;
358 }
359
360 EXPORT int vprintf(const char *__format, va_list __args)
361 {
362         return vfprintf(stdout, __format, __args);
363 }
364
365 EXPORT int printf(const char *format, ...)
366 {
367         va_list args;
368          int    ret;
369         
370         // Get final size
371         va_start(args, format);
372         ret = vprintf(format, args);
373         va_end(args);
374         
375         // Return
376         return ret;
377 }
378
379 void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned)
380 {
381         struct s_sprintf_info   info = {buf, 0, 1024};
382         if(!buf)        return;
383         _printf_itoa(_vsnprintf_puts, &info, num, base, FALSE, bSigned, '\0', 0, minLength, pad, FALSE);
384         buf[info.ofs] = '\0';
385 }
386
387 const char cDIGITS[] = "0123456789abcdef";
388 const char cUDIGITS[] = "0123456789ABCDEF";
389 /**
390  * \brief Convert an integer into a character string
391  * \param buf   Destination Buffer
392  * \param num   Number to convert
393  * \param base  Base-n number output
394  * \param minLength     Minimum length of output
395  * \param pad   Padding used to ensure minLength
396  * \param bSigned       Signed number output?
397  */
398 size_t _printf_itoa(printf_puts_t puts_cb, void *puts_h, uint64_t num,
399         size_t base, int bUpper,
400         int bSigned, char SignChar, int Precision,
401         int PadLength, char PadChar, int bPadRight)
402 {
403         char    tmpBuf[64+1];
404          int    pos = sizeof(tmpBuf);
405         size_t  ret = 0;
406          int    sign_is_neg = 0;
407         const char *map = bUpper ? cUDIGITS : cDIGITS;
408
409         if(base > 16 || base < 2) {
410                 return 0;
411         }
412         
413         if(bSigned && (int64_t)num < 0)
414         {
415                 num = -(int64_t)num;
416                 sign_is_neg = 1;
417         }
418         
419         // Encode into string
420         while(num > base-1) {
421                 tmpBuf[--pos] = map[ num % base ];
422                 num = (uint64_t) num / (uint64_t)base;          // Shift {number} right 1 digit
423         }
424         tmpBuf[--pos] = map[ num % base ];              // Most significant digit of {number}
425
426         // TODO: This assertion may not be valid
427         assert(Precision <= (int)sizeof(tmpBuf));
428         Precision -= sizeof(tmpBuf)-pos + (sign_is_neg || SignChar != '\0');
429         while( Precision-- > 0 )
430                 tmpBuf[--pos] = '0';
431
432         // Sign 
433         if(sign_is_neg)
434                 tmpBuf[--pos] = '-';    // Negative sign character
435         else if(SignChar)
436                 tmpBuf[--pos] = SignChar;       // positive sign character
437         else {
438         }
439         
440         // length of number, minus the sign character
441         size_t len = sizeof(tmpBuf)-pos;
442         PadLength -= len;
443         if( !bPadRight )
444         {
445                 while(PadLength-- > 0)
446                         puts_cb(puts_h, &PadChar, 1), ret ++;
447         }
448         
449         puts_cb(puts_h, tmpBuf+pos, len);
450         ret += len;
451
452         if( bPadRight )
453         {
454                 while(PadLength-- > 0)
455                         puts_cb(puts_h, &PadChar, 1), ret ++;
456         }
457         
458         return ret;
459 }
460
461 int expand_double(double num, uint64_t *Significand, int16_t *Exponent, int *SignIsNeg)
462 {
463         // IEEE 754 binary64
464         #if 0
465         {
466                 uint64_t test_exp = 0xC000000000000000;
467                 double test_value = -2.0f;
468                 assert( *((uint64_t*)&test_value) == test_exp );
469         }
470         #endif
471         
472         const uint64_t  *bit_rep = (void*)&num;
473         
474         *SignIsNeg = *bit_rep >> 63;
475         *Exponent = ((*bit_rep >> 52) & 0x7FF) - 1023;
476         *Significand = (*bit_rep & ((1ULL << 52)-1)) << (64-52);
477
478 //      printf("%llx %i %i %llx\n", *bit_rep, (int)*SignIsNeg, (int)*Exponent, *Significand);
479
480         // Subnormals
481         if( *Exponent == -0x3FF && *Significand != 0 )
482                 return 1;
483         // Infinity
484         if( *Exponent == 0x400 && *Significand == 0)
485                 return 2;
486         // NaNs
487         if( *Exponent == 0x400 && *Significand != 0)
488                 return 3;
489
490         return 0;
491 }
492
493 /**
494  * Internal function
495  * \return Remainder
496  */
497 double _longdiv(double num, double den, int *quot)
498 {
499         assert(num >= 0);
500         assert(den > 0);
501 //      printf("%llu / %llu\n", (long long int)num, (long long int)den);
502         
503         *quot = 0;
504         assert(num < den*10);
505         while(num >= den)
506         {
507                 num -= den;
508                 (*quot) ++;
509                 assert( *quot < 10 );
510         }
511 //      printf(" %i\n", *quot);
512         return num;
513 }
514
515 size_t _printf_ftoa_hex(printf_puts_t puts_cb, void *puts_h, long double num, int Precision, int bForcePoint, int bForceSign, int bCapitals)
516 {
517         uint64_t        significand;
518         int16_t exponent;
519          int    signisneg;
520          int    rv;
521         size_t  ret = 0;
522
523         #define _putch(_ch) do{\
524                 char __ch = (bCapitals ? toupper(_ch) : _ch);\
525                 puts_cb(puts_h, &__ch, 1); \
526                 ret ++;\
527         }while(0)
528
529         if( Precision == -1 )
530                 Precision = (64-4)/4;
531
532         rv = expand_double(num, &significand, &exponent, &signisneg);
533         switch(rv)
534         {
535         // 0: No errors, nothing special
536         case 0:
537                 break;
538         // 1: Subnormals
539         case 1:
540                 // TODO: Subnormal = 0?
541                 break;
542         // 2: Infinity
543         case 2:
544                 puts_cb(puts_h, "inf", 3);
545                 return 3;
546         case 3:
547                 puts_cb(puts_h, "NaN", 3);
548                 return 3;
549         }
550         
551         // int  exp_ofs = exponent % 4;
552         // int  exp_16 = exponent - exp_ofs;
553         //uint8_t       whole = (1 << exp_ofs) | ((significand >> (64-3)) >> exp_ofs);
554         //significand <<= 3 - exp_ofs;
555         uint8_t whole = (rv != 1) ? 1 : 0;
556         
557         if( signisneg )
558                 _putch('-');
559         else if( bForceSign )
560                 _putch('+');
561         else {
562         }
563         _putch('0');
564         _putch('x');
565         _putch(cDIGITS[whole]);
566         if( significand || bForcePoint )
567                 _putch('.');
568         // Fractional
569         while( significand && Precision -- )
570         {
571                 uint8_t val = significand >> (64-4);
572                 _putch(cDIGITS[val]);
573                 significand <<= 4;
574         }
575         _putch('p');
576         //ret += _printf_itoa(puts_cb, puts_h, exp_16, 16, bCapitals, TRUE, '+', 0, 0, '\0', 0);
577         ret += _printf_itoa(puts_cb, puts_h, exponent, 10, bCapitals, TRUE, '+', 0, 0, '\0', 0);
578         
579         #undef _putch
580         return ret;
581 }
582
583 #if 0
584 size_t _printf_itoa_fixed(printf_putch_t putch_cb, void *putch_h, uint64_t num, size_t Base)
585 {
586         uint64_t        den;
587         size_t  ret = 0;
588
589         den = 1ULL << (64-1);
590         
591         while( den )
592         {
593                 putch_cb(putch_h, cDIGITS[num / den]);
594                 ret ++;
595                 num %= den;
596                 den /= Base;
597         }
598
599         return ret;
600 }
601
602 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)
603 {
604         size_t  ret = 0;
605          int    i;
606
607         #define _putch(_ch) do{\
608                 putch_cb(putch_h, bCapitals ? toupper(_ch) : _ch), ret++;\
609         }while(0)
610         
611         uint64_t        significand;
612          int16_t        exponent;
613          int    signisneg;
614          int    rv = expand_double(num, &significand, &exponent, &signisneg);
615         switch(rv)
616         {
617         // 0: No errors, nothing special
618         case 0:
619                 break;
620         // 1: Subnormals
621         case 1:
622                 // TODO: Subnormal = 0?
623                 break;
624         // 2: Infinity
625         case 2:
626                 _putch('i');
627                 _putch('n');
628                 _putch('f');
629                 return 3;
630         case 3:
631                 _putch('N');
632                 _putch('a');
633                 _putch('N');
634                 return 3;
635         }
636
637         uint64_t        whole, part;
638          int    pre_zeros, post_zeros;
639
640         #define XXX     0
641         if( Notation == FPN_SCI )
642         {
643         }
644         else if( exponent < 0 )
645         {
646                 whole = 0;
647                 part = XXX;
648                 pre_zeros = 0;
649                 post_zeros = XXX;
650         }
651         else if( exponent >= 64 )
652         {
653                 part = 0;
654                 whole = XXX;
655                 pre_zeros = XXX;
656                 post_zeros = 0;
657         }
658         else
659         {
660                 // Split into fixed point
661                 whole = (1 << exponent) | (significand >> (64-exponent));
662                 part = significand << exponent;
663                 pre_zeros = 0;
664                 post_zeros = 0;
665         }
666
667         
668         // Whole portion
669         ret += _printf_itoa(putch_cb, putch_h, whole, 10, FALSE, FALSE, '\0', 0, 0, '\0', FALSE);
670         for(i = pre_zeros; i --; )      _putch('0');
671         // TODO: Conditional point
672         _putch('-');
673         for(i = post_zeros; i--; )      _putch('0');
674         ret += _printf_itoa_fixed(putch_cb, putch_h, part, 10);
675         
676         #undef _putch
677
678         return 0;
679 }
680 #endif
681
682 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)
683 {
684         uint64_t        significand;
685         int16_t exponent;
686          int    signisneg;
687          int    rv, i;
688         size_t  ret = 0;
689
690         #define _putch(_ch) do{\
691                 char __ch = (bCapitals ? toupper(_ch) : _ch);\
692                 puts_cb(puts_h, &__ch, 1); \
693                 ret ++;\
694         }while(0)
695
696         if( Base <= 1 || Base > 16 )
697                 return 0;
698
699         rv = expand_double(num, &significand, &exponent, &signisneg);
700         switch(rv)
701         {
702         // 0: No errors, nothing special
703         case 0:
704                 break;
705         // 1: Subnormals
706         case 1:
707                 // TODO: Subnormal = 0?
708                 break;
709         // 2: Infinity
710         case 2:
711                 _putch('i');
712                 _putch('n');
713                 _putch('f');
714                 return 3;
715         case 3:
716                 _putch('N');
717                 _putch('a');
718                 _putch('N');
719                 return 3;
720         }
721
722         // - Used as 0/1 bools in arithmatic later on
723         bForcePoint = !!bForcePoint;
724         bForceSign = !!bForceSign;
725
726         // Apply default to precision
727         if( Precision == -1 )
728                 Precision = 6;
729
730         if( num < 0 )
731                 num = -num;
732
733         // Select optimum type
734         if( Notation == FPN_SHORTEST )
735         {
736                 //TODO:
737                 //int   first_set_sig = BSL(significand);
738                 // bSign+log10(num)+1+precision vs. bSign+1+1+precision+1+1+log10(exponent)
739                  int    log10_num = exponent * 301 / 1000;      // log_10(2) = 0.30102999566...
740                  int    log10_exp10 = 2;
741                  int    sci_len = (signisneg || bForceSign) + 2 + (Precision-1) + 2 + log10_exp10;
742                  int    std_whole_len = (log10_num > 0 ? log10_num : 1);
743                  int    std_len = (signisneg || bForceSign) + std_whole_len + 1 + (Precision-std_whole_len);
744                 if( sci_len > std_len ) {
745                         Precision -= std_whole_len;
746                         Notation = FPN_STD;
747                 }
748                 else {
749                         Precision -= 1;
750                         Notation = FPN_SCI;
751                 }
752         }
753
754         double precision_max = 1;
755         for(i = Precision; i--; )
756                 precision_max /= Base;
757
758         // Determine scientific's exponent and starting denominator
759         double den = 1;
760          int    sci_exponent = 0;
761         if( Notation == FPN_SCI )
762         {
763                 if( num < 1 )
764                 {
765                         while(num < 1)
766                         {
767                                 num *= Base;
768                                 sci_exponent ++;
769                         }
770                 }
771                 else if( num >= Base )
772                 {
773                         while(num >= Base)
774                         {
775                                 num /= Base;
776                                 sci_exponent ++;
777                         }
778                 }
779                 else
780                 {
781                         // no exponent
782                 }
783                 den = 1;
784         }
785         else if( num != 0.0 )
786         {
787                 while( den <= num )
788                         den *= Base;
789                 den /= Base;
790         }
791
792         // Leading sign
793         if( signisneg )
794                 _putch('-');
795         else if( bForceSign )
796                 _putch('+');
797         else {
798         }
799         
800         num += precision_max/10 * 4.999;
801
802          int    value;
803         // Whole section
804         do
805         {
806                 num = _longdiv(num, den, &value);
807                 _putch(cDIGITS[value]);
808                 den /= Base;
809         } while( den >= 1 );
810
811         // Decimal point (if needed/forced)     
812         if( Precision > 0 || bForcePoint )
813                 _putch('.');
814         // Decimal section
815         for(i = Precision; i--; )
816         {
817                 num = _longdiv(num, den, &value);
818                 _putch(cDIGITS[value]);
819                 den /= Base;
820         }
821
822         if( Notation == FPN_SCI )
823         {
824                 if( Base == 16 )
825                         _putch('p');
826                 else
827                         _putch('e');
828                 ret += _printf_itoa(puts_cb, puts_h, sci_exponent, Base, FALSE, TRUE, '+', 3, 0, '\0', FALSE);
829         }       
830
831         #undef _putch
832
833         return ret;
834 }

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