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