formatwr.c

Go to the documentation of this file.
00001 
00080 #include "formatwr.h"
00081 #include <mware/pgm.h>
00082 #include <mware/hex.h>
00083 #include <cfg/debug.h> /* ASSERT */
00084 #include <appconfig.h> /* CONFIG_ macros */
00085 
00086 #ifndef CONFIG_PRINTF_N_FORMATTER
00087 
00088     #define CONFIG_PRINTF_N_FORMATTER 0
00089 #endif
00090 
00091 #ifndef CONFIG_PRINTF_OCTAL_FORMATTER
00092 
00093     #define CONFIG_PRINTF_OCTAL_FORMATTER 0
00094 #endif
00095 
00096 /* True if we must keep a count of the number of characters we print. */
00097 #define CONFIG_PRINTF_COUNT_CHARS (CONFIG_PRINTF_RETURN_COUNT || CONFIG_PRINTF_N_FORMATTER)
00098 
00099 #if CONFIG_PRINTF
00100 
00101 #if CONFIG_PRINTF > PRINTF_NOFLOAT
00102     #include <float.h>
00103 
00104     /* Maximum precision for floating point values */
00105     typedef long double max_float_t;
00106 
00107     /*bernie: save some memory, who cares about floats with lots of decimals? */
00108     #define FRMWRI_BUFSIZE 134
00109     #warning 134 is too much, the code must be fixed to have a lower precision limit
00110 #else
00111     /*
00112      * Conservative estimate. Should be (probably) 12 (which is the size necessary
00113      * to represent (2^32-1) in octal plus the sign bit.
00114      */
00115     #define FRMWRI_BUFSIZE 16
00116 #endif
00117 
00118 /* Probably useful for fancy microcontrollers such as the PIC, nobody knows. */
00119 #ifndef MEM_ATTRIBUTE
00120 #define MEM_ATTRIBUTE
00121 #endif
00122 
00123 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
00124     #define IS_SHORT (h_modifier || (sizeof(int) == 2 && !l_modifier))
00125 #else
00126     #define IS_SHORT (sizeof(int) == 2)
00127 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00128 
00129 
00130 #if CONFIG_PRINTF > PRINTF_NOFLOAT
00131 
00132 static char *float_conversion(MEM_ATTRIBUTE max_float_t value,
00133         MEM_ATTRIBUTE short nr_of_digits,
00134         MEM_ATTRIBUTE char *buf,
00135         MEM_ATTRIBUTE char format_flag,
00136         MEM_ATTRIBUTE char g_flag,
00137         MEM_ATTRIBUTE bool alternate_flag)
00138 {
00139     MEM_ATTRIBUTE char *cp;
00140     MEM_ATTRIBUTE char *buf_pointer;
00141     MEM_ATTRIBUTE short n, i, dec_point_pos, integral_10_log;
00142 
00143     buf_pointer = buf;
00144     integral_10_log = 0;
00145 
00146     if (value >= 1)
00147     {
00148         while (value >= 1e11) /* To speed up things a bit */
00149         {
00150             value /= 1e10;
00151             integral_10_log += 10;
00152         }
00153         while (value >= 10)
00154         {
00155             value /= 10;
00156             integral_10_log++;
00157         }
00158     }
00159     else if (value) /* Not just 0.0 */
00160     {
00161         while (value <= 1e-10) /* To speed up things a bit */
00162         {
00163             value *= 1e10;
00164             integral_10_log -= 10;
00165         }
00166         while (value < 1)
00167         {
00168             value *= 10;
00169             integral_10_log--;
00170         }
00171     }
00172     if (g_flag)
00173     {
00174         if (integral_10_log < nr_of_digits && integral_10_log >= -4)
00175         {
00176             format_flag = 0;
00177             nr_of_digits -= integral_10_log;
00178         }
00179         nr_of_digits--;
00180         if (alternate_flag)
00181             /* %#G - No removal of trailing zeros */
00182             g_flag = 0;
00183         else
00184             /* %G - Removal of trailing zeros */
00185             alternate_flag = true;
00186     }
00187 
00188     /* %e or %E */
00189     if (format_flag)
00190     {
00191         dec_point_pos = 0;
00192     }
00193     else
00194     {
00195         /* Less than one... */
00196         if (integral_10_log < 0)
00197         {
00198             *buf_pointer++ = '0';
00199             if ((n = nr_of_digits) || alternate_flag)
00200                 *buf_pointer++ = '.';
00201             i = 0;
00202             while (--i > integral_10_log && nr_of_digits)
00203             {
00204                 *buf_pointer++ = '0';
00205                 nr_of_digits--;
00206             }
00207             if (integral_10_log < (-n - 1))
00208                 /* Nothing more to do */
00209                 goto CLEAN_UP;
00210             dec_point_pos = 1;
00211         }
00212         else
00213         {
00214             dec_point_pos = - integral_10_log;
00215         }
00216     }
00217 
00218     i = dec_point_pos;
00219     while (i <= nr_of_digits )
00220     {
00221         value -= (max_float_t)(n = (short)value); /* n=Digit value=Remainder */
00222         value *= 10; /* Prepare for next shot */
00223         *buf_pointer++ = n + '0';
00224         if ( ! i++ && (nr_of_digits || alternate_flag))
00225             *buf_pointer++ = '.';
00226     }
00227 
00228     /* Rounding possible */
00229     if (value >= 5)
00230     {
00231         n = 1; /* Carry */
00232         cp = buf_pointer - 1;
00233         do
00234         {
00235             if (*cp != '.')
00236             {
00237                 if ( (*cp += n) == ('9' + 1) )
00238                 {
00239                     *cp = '0';
00240                     n = 1;
00241                 }
00242                 else
00243                     n = 0;
00244             }
00245         } while (cp-- > buf);
00246         if (n)
00247         {
00248             /* %e or %E */
00249             if (format_flag)
00250             {
00251                 cp = buf_pointer;
00252                 while (cp > buf)
00253                 {
00254                     if (*(cp - 1) == '.')
00255                     {
00256                         *cp = *(cp - 2);
00257                         cp--;
00258                     }
00259                     else
00260                         *cp = *(cp - 1);
00261                     cp--;
00262                 }
00263                 integral_10_log++;
00264             }
00265             else
00266             {
00267                 cp = ++buf_pointer;
00268                 while (cp > buf)
00269                 {
00270                     *cp = *(cp - 1);
00271                     cp--;
00272                 }
00273             }
00274             *buf = '1';
00275         }
00276     }
00277 
00278 CLEAN_UP:
00279     /* %G - Remove trailing zeros */
00280     if (g_flag)
00281     {
00282         while (*(buf_pointer - 1) == '0')
00283             buf_pointer--;
00284         if (*(buf_pointer - 1) == '.')
00285             buf_pointer--;
00286     }
00287 
00288     /* %e or %E */
00289     if (format_flag)
00290     {
00291         *buf_pointer++ = format_flag;
00292         if (integral_10_log < 0)
00293         {
00294             *buf_pointer++ = '-';
00295             integral_10_log = -integral_10_log;
00296         }
00297         else
00298             *buf_pointer++ = '+';
00299         n = 0;
00300         buf_pointer +=10;
00301         do
00302         {
00303             n++;
00304             *buf_pointer++ = (integral_10_log % 10) + '0';
00305             integral_10_log /= 10;
00306         } while ( integral_10_log || n < 2 );
00307         for ( i = n ; n > 0 ; n-- )
00308             *(buf_pointer - 11 - i + n) = *(buf_pointer - n);
00309         buf_pointer -= 10;
00310     }
00311     return (buf_pointer);
00312 }
00313 
00314 #endif /* CONFIG_PRINTF > PRINTF_NOFLOAT */
00315 
00321 int
00322 PGM_FUNC(_formatted_write)(const char * PGM_ATTR format,
00323         void put_one_char(char, void *),
00324         void *secret_pointer,
00325         va_list ap)
00326 {
00327 #if CONFIG_PRINTF > PRINTF_REDUCED
00328     MEM_ATTRIBUTE static char bad_conversion[] = "???";
00329     MEM_ATTRIBUTE static char null_pointer[] = "<NULL>";
00330 
00331     MEM_ATTRIBUTE int precision;
00332     MEM_ATTRIBUTE int n;
00333 #if CONFIG_PRINTF_COUNT_CHARS
00334     MEM_ATTRIBUTE int nr_of_chars;
00335 #endif
00336     MEM_ATTRIBUTE int field_width;
00337     MEM_ATTRIBUTE char format_flag;
00338     enum PLUS_SPACE_FLAGS {
00339         PSF_NONE, PSF_PLUS, PSF_MINUS
00340     };
00341     enum DIV_FACTOR {
00342         DIV_DEC, DIV_HEX,
00343 #if CONFIG_PRINTF_OCTAL_FORMATTER
00344         DIV_OCT,
00345 #endif
00346     };
00347     MEM_ATTRIBUTE struct {
00348         enum PLUS_SPACE_FLAGS plus_space_flag : 2;
00349 #if CONFIG_PRINTF_OCTAL_FORMATTER
00350         enum DIV_FACTOR div_factor : 2;
00351 #else
00352         enum DIV_FACTOR div_factor : 1;
00353 #endif
00354         bool left_adjust : 1;
00355         bool l_L_modifier : 1;
00356         bool h_modifier : 1;
00357         bool alternate_flag : 1;
00358         bool nonzero_value : 1;
00359         bool zeropad : 1;
00360 #if CPU_HARVARD
00361         bool progmem : 1;
00362 #endif
00363     } flags;
00364     MEM_ATTRIBUTE unsigned long ulong;
00365 
00366 #if CONFIG_PRINTF >  PRINTF_NOFLOAT
00367     MEM_ATTRIBUTE max_float_t fvalue;
00368 #endif
00369 
00370     MEM_ATTRIBUTE char *buf_pointer;
00371     MEM_ATTRIBUTE char *ptr;
00372     MEM_ATTRIBUTE const char *hex;
00373     MEM_ATTRIBUTE char buf[FRMWRI_BUFSIZE];
00374 
00375 #if CONFIG_PRINTF_COUNT_CHARS
00376     nr_of_chars = 0;
00377 #endif
00378     for (;;)    /* Until full format string read */
00379     {
00380         while ((format_flag = PGM_READ_CHAR(format++)) != '%')    /* Until '%' or '\0' */
00381         {
00382             if (!format_flag)
00383 #if CONFIG_PRINTF_RETURN_COUNT
00384                 return (nr_of_chars);
00385 #else
00386                 return 0;
00387 #endif
00388             put_one_char(format_flag, secret_pointer);
00389 #if CONFIG_PRINTF_COUNT_CHARS
00390             nr_of_chars++;
00391 #endif
00392         }
00393         if (PGM_READ_CHAR(format) == '%')    /* %% prints as % */
00394         {
00395             format++;
00396             put_one_char('%', secret_pointer);
00397 #if CONFIG_PRINTF_COUNT_CHARS
00398             nr_of_chars++;
00399 #endif
00400             continue;
00401         }
00402 
00403         flags.left_adjust = false;
00404         flags.alternate_flag = false;
00405         flags.plus_space_flag = PSF_NONE;
00406         flags.zeropad = false;
00407 #if CPU_HARVARD
00408         flags.progmem = false;
00409 #endif
00410         ptr = buf_pointer = &buf[0];
00411         hex = HEX_tab;
00412 
00413         /* check for leading '-', '+', ' ','#' or '0' flags  */
00414         for (;;)
00415         {
00416             switch (PGM_READ_CHAR(format))
00417             {
00418                 case ' ':
00419                     if (flags.plus_space_flag)
00420                         goto NEXT_FLAG;
00421                 case '+':
00422                     flags.plus_space_flag = PSF_PLUS;
00423                     goto NEXT_FLAG;
00424                 case '-':
00425                     flags.left_adjust = true;
00426                     goto NEXT_FLAG;
00427                 case '#':
00428                     flags.alternate_flag = true;
00429                     goto NEXT_FLAG;
00430                 case '0':
00431                     flags.zeropad = true;
00432                     goto NEXT_FLAG;
00433             }
00434             break;
00435 NEXT_FLAG:
00436             format++;
00437         }
00438 
00439         /* Optional field width (may be '*') */
00440         if (PGM_READ_CHAR(format) == '*')
00441         {
00442             field_width = va_arg(ap, int);
00443             if (field_width < 0)
00444             {
00445                 field_width = -field_width;
00446                 flags.left_adjust = true;
00447             }
00448             format++;
00449         }
00450         else
00451         {
00452             field_width = 0;
00453             while (PGM_READ_CHAR(format) >= '0' && PGM_READ_CHAR(format) <= '9')
00454                 field_width = field_width * 10 + (PGM_READ_CHAR(format++) - '0');
00455         }
00456 
00457         if (flags.left_adjust)
00458             flags.zeropad = false;
00459 
00460         /* Optional precision (or '*') */
00461         if (PGM_READ_CHAR(format) == '.')
00462         {
00463             if (PGM_READ_CHAR(++format) == '*')
00464             {
00465                 precision = va_arg(ap, int);
00466                 format++;
00467             }
00468             else
00469             {
00470                 precision = 0;
00471                 while (PGM_READ_CHAR(format) >= '0' && PGM_READ_CHAR(format) <= '9')
00472                     precision = precision * 10 + (PGM_READ_CHAR(format++) - '0');
00473             }
00474         }
00475         else
00476             precision = -1;
00477 
00478         /* At this point, "left_adjust" is nonzero if there was
00479          * a sign, "zeropad" is 1 if there was a leading zero
00480          * and 0 otherwise, "field_width" and "precision"
00481          * contain numbers corresponding to the digit strings
00482          * before and after the decimal point, respectively,
00483          * and "plus_space_flag" is either 0 (no flag) or
00484          * contains a plus or space character. If there was no
00485          * decimal point, "precision" will be -1.
00486          */
00487 
00488         flags.l_L_modifier = false;
00489         flags.h_modifier = false;
00490 
00491         /* Optional 'l','L','z' or 'h' modifier? */
00492         switch (PGM_READ_CHAR(format))
00493         {
00494             case 'l':
00495             case 'L':
00496             case 'z':
00497                 flags.l_L_modifier = true;
00498                 format++;
00499                 break;
00500             case 'h':
00501                 flags.h_modifier = true;
00502                 format++;
00503                 break;
00504         }
00505 
00506         /*
00507          * At exit from the following switch, we will emit
00508          * the characters starting at "buf_pointer" and
00509          * ending at "ptr"-1
00510          */
00511         switch (format_flag = PGM_READ_CHAR(format++))
00512         {
00513 #if CONFIG_PRINTF_N_FORMATTER
00514             case 'n':
00515                 if (sizeof(short) != sizeof(int))
00516                 {
00517                     if (sizeof(int) != sizeof(long))
00518                     {
00519                         if (h_modifier)
00520                             *va_arg(ap, short *) = nr_of_chars;
00521                         else if (flags.l_L_modifier)
00522                             *va_arg(ap, long *) = nr_of_chars;
00523                         else
00524                             *va_arg(ap, int *) = nr_of_chars;
00525                     }
00526                     else
00527                     {
00528                         if (h_modifier)
00529                             *va_arg(ap, short *) = nr_of_chars;
00530                         else
00531                             *va_arg(ap, int *) = nr_of_chars;
00532                     }
00533                 }
00534                 else
00535                 {
00536                     if (flags.l_L_modifier)
00537                         *va_arg(ap, long *) = nr_of_chars;
00538                     else
00539                         *va_arg(ap, int *) = nr_of_chars;
00540                 }
00541                 continue;
00542 #endif
00543             case 'c':
00544                 buf[0] = va_arg(ap, int);
00545                 ptr++;
00546                 break;
00547 
00548             /* Custom formatter for strings in program memory. */
00549             case 'S':
00550 #if CPU_HARVARD
00551                 flags.progmem = true;
00552 #endif
00553                 /* Fall trough */
00554 
00555             case 's':
00556                 if ( !(buf_pointer = va_arg(ap, char *)) )
00557                     buf_pointer = null_pointer;
00558                 if (precision < 0)
00559                     precision = 10000;
00560 
00561                 /*
00562                  * Move `ptr' to the last character of the
00563                  * string that will be actually printed.
00564                  */
00565                 ptr = buf_pointer;
00566 #if CPU_HARVARD
00567                 if (flags.progmem)
00568                 {
00569                     for (n=0; pgm_read_char(ptr) && n < precision; n++)
00570                         ++ptr;
00571                 }
00572                 else
00573 #endif
00574                 for (n=0; *ptr && n < precision; n++)
00575                     ++ptr;
00576                 break;
00577 
00578 #if CONFIG_PRINTF_OCTAL_FORMATTER
00579             case 'o':
00580                 if (flags.alternate_flag && !precision)
00581                     precision++;
00582 #endif
00583             case 'x':
00584                 hex = hex_tab;
00585             case 'u':
00586             case 'p':
00587             case 'X':
00588                 if (format_flag == 'p')
00589 #if defined(__AVR__) || defined(__I196__) /* 16bit pointers */
00590                     ulong = (unsigned long)(unsigned short)va_arg(ap, char *);
00591 #else /* 32bit pointers */
00592                     ulong = (unsigned long)va_arg(ap, char *);
00593 #endif /* 32bit pointers */
00594                 else if (flags.l_L_modifier)
00595                     ulong = va_arg(ap, unsigned long);
00596                 else if (flags.h_modifier)
00597                     ulong = (unsigned long)(unsigned short)va_arg(ap, unsigned int);
00598                 else
00599                     ulong = va_arg(ap, unsigned int);
00600 
00601                 flags.div_factor =
00602 #if CONFIG_PRINTF_OCTAL_FORMATTER
00603                     (format_flag == 'o') ? DIV_OCT :
00604 #endif
00605                     (format_flag == 'u') ? DIV_DEC : DIV_HEX;
00606                 flags.plus_space_flag = PSF_NONE;
00607                 goto INTEGRAL_CONVERSION;
00608 
00609             case 'd':
00610             case 'i':
00611                 if (flags.l_L_modifier)
00612                     ulong = (unsigned long)(long)va_arg(ap, long);
00613                 else
00614                     ulong = (unsigned long)(long)va_arg(ap, int);
00615 
00616                 /* Extract sign */
00617                 if ((signed long)ulong < 0)
00618                 {
00619                     flags.plus_space_flag = PSF_MINUS;
00620                     ulong = (unsigned long)(-((signed long)ulong));
00621                 }
00622 
00623                 flags.div_factor = DIV_DEC;
00624 
00625                 /* Now convert to digits */
00626 INTEGRAL_CONVERSION:
00627                 ptr = buf_pointer = &buf[FRMWRI_BUFSIZE - 1];
00628                 flags.nonzero_value = (ulong != 0);
00629 
00630                 /* No char if zero and zero precision */
00631                 if (precision != 0 || flags.nonzero_value)
00632                 {
00633                     switch (flags.div_factor)
00634                     {
00635                     case DIV_DEC:
00636                         do
00637                             *--buf_pointer = hex[ulong % 10];
00638                         while (ulong /= 10);
00639                         break;
00640 
00641                     case DIV_HEX:
00642                         do
00643                             *--buf_pointer = hex[ulong % 16];
00644                         while (ulong /= 16);
00645                         break;
00646 #if CONFIG_PRINTF_OCTAL_FORMATTER
00647                     case DIV_OCT:
00648                         do
00649                             *--buf_pointer = hex[ulong % 8];
00650                         while (ulong /= 8);
00651                         break;
00652 #endif
00653                     }
00654                 }
00655 
00656                 /* "precision" takes precedence */
00657                 if (precision < 0)
00658                     if (flags.zeropad)
00659                         precision = field_width - (flags.plus_space_flag != PSF_NONE);
00660                 while (precision > (int)(ptr - buf_pointer))
00661                     *--buf_pointer = '0';
00662 
00663                 if (flags.alternate_flag && flags.nonzero_value)
00664                 {
00665                     if (format_flag == 'x' || format_flag == 'X')
00666                     {
00667                         *--buf_pointer = format_flag;
00668                         *--buf_pointer = '0';
00669                     }
00670 #if CONFIG_PRINTF_OCTAL_FORMATTER
00671                     else if ((format_flag == 'o') && (*buf_pointer != '0'))
00672                     {
00673                         *--buf_pointer = '0';
00674                     }
00675 #endif
00676                 }
00677                 ASSERT(buf_pointer >= buf);
00678                 break;
00679 
00680 #if CONFIG_PRINTF > PRINTF_NOFLOAT
00681             case 'g':
00682             case 'G':
00683                 n = 1;
00684                 format_flag -= 2;
00685                 if (! precision)
00686                 {
00687                     precision = 1;
00688                 }
00689                 goto FLOATING_CONVERSION;
00690             case 'f':
00691                 format_flag = 0;
00692             case 'e':
00693             case 'E':
00694                 n = 0;
00695 FLOATING_CONVERSION:
00696                 if (precision < 0)
00697                 {
00698                     precision = 6;
00699                 }
00700 
00701                 if (sizeof(double) != sizeof(max_float_t))
00702                 {
00703                     fvalue = flags.l_L_modifier ?
00704                         va_arg(ap,max_float_t) : va_arg(ap,double);
00705                 }
00706                 else
00707                     fvalue = va_arg(ap,max_float_t);
00708 
00709                 if (fvalue < 0)
00710                 {
00711                     flags.plus_space_flag = PSF_MINUS;
00712                     fvalue = -fvalue;
00713                 }
00714                 ptr = float_conversion (fvalue,
00715                         (short)precision,
00716                         buf_pointer += field_width,
00717                         format_flag,
00718                         (char)n,
00719                         flags.alternate_flag);
00720                 if (flags.zeropad)
00721                 {
00722                     precision = field_width - (flags.plus_space_flag != PSF_NONE);
00723                     while (precision > ptr - buf_pointer)
00724                         *--buf_pointer = '0';
00725                 }
00726                 break;
00727 
00728 #endif /* CONFIG_PRINTF <= PRINTF_NOFLOAT */
00729 
00730             case '\0': /* Really bad place to find NUL in */
00731                 format--;
00732 
00733             default:
00734                 /* Undefined conversion! */
00735                 ptr = buf_pointer = bad_conversion;
00736                 ptr += sizeof(bad_conversion) - 1;
00737                 break;
00738 
00739         }
00740 
00741         /*
00742          * This part emittes the formatted string to "put_one_char".
00743          */
00744 
00745         /* If field_width == 0 then nothing should be written. */
00746         precision = ptr - buf_pointer;
00747 
00748         if ( precision > field_width)
00749         {
00750             n = 0;
00751         }
00752         else
00753         {
00754             n = field_width - precision - (flags.plus_space_flag != PSF_NONE);
00755         }
00756 
00757         /* emit any leading pad characters */
00758         if (!flags.left_adjust)
00759             while (--n >= 0)
00760             {
00761                 put_one_char(' ', secret_pointer);
00762 #if CONFIG_PRINTF_COUNT_CHARS
00763                 nr_of_chars++;
00764 #endif
00765             }
00766 
00767         /* emit flag characters (if any) */
00768         if (flags.plus_space_flag)
00769         {
00770             put_one_char(flags.plus_space_flag == PSF_PLUS ? '+' : '-', secret_pointer);
00771 #if CONFIG_PRINTF_COUNT_CHARS
00772             nr_of_chars++;
00773 #endif
00774         }
00775 
00776 #if CPU_HARVARD
00777         if (flags.progmem)
00778         {
00779             while (--precision >= 0)
00780             {
00781                 put_one_char(pgm_read_char(buf_pointer++), secret_pointer);
00782 #if CONFIG_PRINTF_COUNT_CHARS
00783                 nr_of_chars++;
00784 #endif
00785             }
00786         }
00787         else
00788 #endif /* CPU_HARVARD */
00789         {
00790             /* emit the string itself */
00791             while (--precision >= 0)
00792             {
00793                 put_one_char(*buf_pointer++, secret_pointer);
00794 #if CONFIG_PRINTF_COUNT_CHARS
00795                 nr_of_chars++;
00796 #endif
00797             }
00798         }
00799 
00800         /* emit trailing space characters */
00801         if (flags.left_adjust)
00802             while (--n >= 0)
00803             {
00804                 put_one_char(' ', secret_pointer);
00805 #if CONFIG_PRINTF_COUNT_CHARS
00806                 nr_of_chars++;
00807 #endif
00808             }
00809     }
00810 
00811 #else /* PRINTF_REDUCED starts here */
00812 
00813 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
00814     bool l_modifier, h_modifier;
00815     unsigned long u_val, div_val;
00816 #else
00817     unsigned int u_val, div_val;
00818 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00819 
00820     char format_flag;
00821     unsigned int nr_of_chars, base;
00822     char outChar;
00823     char *ptr;
00824 
00825     nr_of_chars = 0;
00826     for (;;)    /* Until full format string read */
00827     {
00828         while ((format_flag = PGM_READ_CHAR(format++)) != '%')    /* Until '%' or '\0' */
00829         {
00830             if (!format_flag)
00831                 return (nr_of_chars);
00832             put_one_char(format_flag, secret_pointer);
00833             nr_of_chars++;
00834         }
00835 
00836 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
00837         /*=================================*/
00838         /* Optional 'l' or 'h' modifiers ? */
00839         /*=================================*/
00840         l_modifier = h_modifier = false;
00841         switch (PGM_READ_CHAR(format))
00842         {
00843             case 'l':
00844                 l_modifier = true;
00845                 format++;
00846                 break;
00847 
00848             case 'h':
00849                 h_modifier = true;
00850                 format++;
00851                 break;
00852         }
00853 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00854 
00855         switch (format_flag = PGM_READ_CHAR(format++))
00856         {
00857             case 'c':
00858                 format_flag = va_arg(ap, int);
00859             default:
00860                 put_one_char(format_flag, secret_pointer);
00861                 nr_of_chars++;
00862                 continue;
00863 
00864             case 's':
00865                 ptr = va_arg(ap, char *);
00866                 while ((format_flag = *ptr++))
00867                 {
00868                     put_one_char(format_flag, secret_pointer);
00869                     nr_of_chars++;
00870                 }
00871                 continue;
00872 
00873             case 'o':
00874                 base = 8;
00875                 if (IS_SHORT)
00876                     div_val = 0x8000;
00877                 else
00878                     div_val = 0x40000000;
00879                 goto CONVERSION_LOOP;
00880 
00881             case 'd':
00882                 base = 10;
00883                 if (IS_SHORT)
00884                     div_val = 10000;
00885                 else
00886                     div_val = 1000000000;
00887                 goto CONVERSION_LOOP;
00888 
00889             case 'X':
00890             case 'x':
00891                 base = 16;
00892                 if (IS_SHORT)
00893                     div_val = 0x1000;
00894                 else
00895                     div_val = 0x10000000;
00896 
00897 CONVERSION_LOOP:
00898 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
00899                 if (h_modifier)
00900                     u_val = (format_flag == 'd') ?
00901                         (short)va_arg(ap, int) : (unsigned short)va_arg(ap, int);
00902                 else if (l_modifier)
00903                     u_val = va_arg(ap, long);
00904                 else
00905                     u_val = (format_flag == 'd') ?
00906                         va_arg(ap,int) : va_arg(ap,unsigned int);
00907 #else /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00908                 u_val = va_arg(ap,int);
00909 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00910                 if (format_flag == 'd')
00911                 {
00912                     if (((int)u_val) < 0)
00913                     {
00914                         u_val = - u_val;
00915                         put_one_char('-', secret_pointer);
00916                         nr_of_chars++;
00917                     }
00918                 }
00919                 while (div_val > 1 && div_val > u_val)
00920                 {
00921                     div_val /= base;
00922                 }
00923                 do
00924                 {
00925                     outChar = (u_val / div_val) + '0';
00926                     if (outChar > '9')
00927                     {
00928                         if (format_flag == 'x')
00929                             outChar += 'a'-'9'-1;
00930                         else
00931                             outChar += 'A'-'9'-1;
00932                     }
00933                     put_one_char(outChar, secret_pointer);
00934                     nr_of_chars++;
00935                     u_val %= div_val;
00936                     div_val /= base;
00937                 }
00938                 while (div_val);
00939 
00940         } /* end switch(format_flag...) */
00941     }
00942 #endif /* CONFIG_PRINTF > PRINTF_REDUCED */
00943 }
00944 
00945 #endif /* CONFIG_PRINTF */