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