formatwr.c

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