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         #if SIZEOF_SIZE_T == SIZEOF_LONG
00509             case 'z':
00510                 flags.l_L_modifier = true;
00511         #elif SIZEOF_SIZE_T == SIZEOF_INT
00512                 flags.l_L_modifier = true;
00513             case 'z':
00514         #endif
00515                 format++;
00516                 break;
00517 
00518             case 'h':
00519                 flags.h_modifier = true;
00520                 format++;
00521                 break;
00522 
00523         }
00524 
00525         /*
00526          * At exit from the following switch, we will emit
00527          * the characters starting at "buf_pointer" and
00528          * ending at "ptr"-1
00529          */
00530         switch (format_flag = PGM_READ_CHAR(format++))
00531         {
00532 #if CONFIG_PRINTF_N_FORMATTER
00533             case 'n':
00534                 if (sizeof(short) != sizeof(int))
00535                 {
00536                     if (sizeof(int) != sizeof(long))
00537                     {
00538                         if (h_modifier)
00539                             *va_arg(ap, short *) = nr_of_chars;
00540                         else if (flags.l_L_modifier)
00541                             *va_arg(ap, long *) = nr_of_chars;
00542                         else
00543                             *va_arg(ap, int *) = nr_of_chars;
00544                     }
00545                     else
00546                     {
00547                         if (h_modifier)
00548                             *va_arg(ap, short *) = nr_of_chars;
00549                         else
00550                             *va_arg(ap, int *) = nr_of_chars;
00551                     }
00552                 }
00553                 else
00554                 {
00555                     if (flags.l_L_modifier)
00556                         *va_arg(ap, long *) = nr_of_chars;
00557                     else
00558                         *va_arg(ap, int *) = nr_of_chars;
00559                 }
00560                 continue;
00561 #endif
00562             case 'c':
00563                 buf[0] = va_arg(ap, int);
00564                 ptr++;
00565                 break;
00566 
00567             /* Custom formatter for strings in program memory. */
00568             case 'S':
00569 #if CPU_HARVARD
00570                 flags.progmem = true;
00571 #endif
00572                 /* Fall trough */
00573 
00574             case 's':
00575                 if ( !(buf_pointer = va_arg(ap, char *)) )
00576                     buf_pointer = null_pointer;
00577                 if (precision < 0)
00578                     precision = 10000;
00579 
00580                 /*
00581                  * Move `ptr' to the last character of the
00582                  * string that will be actually printed.
00583                  */
00584                 ptr = buf_pointer;
00585 #if CPU_HARVARD
00586                 if (flags.progmem)
00587                 {
00588                     for (n=0; pgm_read_char(ptr) && n < precision; n++)
00589                         ++ptr;
00590                 }
00591                 else
00592 #endif
00593                 for (n=0; *ptr && n < precision; n++)
00594                     ++ptr;
00595                 break;
00596 
00597 #if CONFIG_PRINTF_OCTAL_FORMATTER
00598             case 'o':
00599                 if (flags.alternate_flag && !precision)
00600                     precision++;
00601 #endif
00602             case 'x':
00603                 hex = hex_tab;
00604             case 'u':
00605             case 'p':
00606             case 'X':
00607                 if (format_flag == 'p')
00608 #if defined(__AVR__) || defined(__I196__) /* 16bit pointers */
00609                     ulong = (unsigned long)(unsigned short)va_arg(ap, char *);
00610 #else /* 32bit pointers */
00611                     ulong = (unsigned long)va_arg(ap, char *);
00612 #endif /* 32bit pointers */
00613                 else if (flags.l_L_modifier)
00614                     ulong = va_arg(ap, unsigned long);
00615                 else if (flags.h_modifier)
00616                     ulong = (unsigned long)(unsigned short)va_arg(ap, unsigned int);
00617                 else
00618                     ulong = va_arg(ap, unsigned int);
00619 
00620                 flags.div_factor =
00621 #if CONFIG_PRINTF_OCTAL_FORMATTER
00622                     (format_flag == 'o') ? DIV_OCT :
00623 #endif
00624                     (format_flag == 'u') ? DIV_DEC : DIV_HEX;
00625                 flags.plus_space_flag = PSF_NONE;
00626                 goto INTEGRAL_CONVERSION;
00627 
00628             case 'd':
00629             case 'i':
00630                 if (flags.l_L_modifier)
00631                     ulong = (unsigned long)(long)va_arg(ap, long);
00632                 else
00633                     ulong = (unsigned long)(long)va_arg(ap, int);
00634 
00635                 /* Extract sign */
00636                 if ((signed long)ulong < 0)
00637                 {
00638                     flags.plus_space_flag = PSF_MINUS;
00639                     ulong = (unsigned long)(-((signed long)ulong));
00640                 }
00641 
00642                 flags.div_factor = DIV_DEC;
00643 
00644                 /* Now convert to digits */
00645 INTEGRAL_CONVERSION:
00646                 ptr = buf_pointer = &buf[FRMWRI_BUFSIZE - 1];
00647                 flags.nonzero_value = (ulong != 0);
00648 
00649                 /* No char if zero and zero precision */
00650                 if (precision != 0 || flags.nonzero_value)
00651                 {
00652                     switch (flags.div_factor)
00653                     {
00654                     case DIV_DEC:
00655                         do
00656                             *--buf_pointer = hex[ulong % 10];
00657                         while (ulong /= 10);
00658                         break;
00659 
00660                     case DIV_HEX:
00661                         do
00662                             *--buf_pointer = hex[ulong % 16];
00663                         while (ulong /= 16);
00664                         break;
00665 #if CONFIG_PRINTF_OCTAL_FORMATTER
00666                     case DIV_OCT:
00667                         do
00668                             *--buf_pointer = hex[ulong % 8];
00669                         while (ulong /= 8);
00670                         break;
00671 #endif
00672                     }
00673                 }
00674 
00675                 /* "precision" takes precedence */
00676                 if (precision < 0)
00677                     if (flags.zeropad)
00678                         precision = field_width - (flags.plus_space_flag != PSF_NONE);
00679                 while (precision > (int)(ptr - buf_pointer))
00680                     *--buf_pointer = '0';
00681 
00682                 if (flags.alternate_flag && flags.nonzero_value)
00683                 {
00684                     if (format_flag == 'x' || format_flag == 'X')
00685                     {
00686                         *--buf_pointer = format_flag;
00687                         *--buf_pointer = '0';
00688                     }
00689 #if CONFIG_PRINTF_OCTAL_FORMATTER
00690                     else if ((format_flag == 'o') && (*buf_pointer != '0'))
00691                     {
00692                         *--buf_pointer = '0';
00693                     }
00694 #endif
00695                 }
00696                 ASSERT(buf_pointer >= buf);
00697                 break;
00698 
00699 #if CONFIG_PRINTF > PRINTF_NOFLOAT
00700             case 'g':
00701             case 'G':
00702                 n = 1;
00703                 format_flag -= 2;
00704                 if (! precision)
00705                 {
00706                     precision = 1;
00707                 }
00708                 goto FLOATING_CONVERSION;
00709             case 'f':
00710                 format_flag = 0;
00711             case 'e':
00712             case 'E':
00713                 n = 0;
00714 FLOATING_CONVERSION:
00715                 if (precision < 0)
00716                 {
00717                     precision = 6;
00718                 }
00719 
00720                 if (sizeof(double) != sizeof(max_float_t))
00721                 {
00722                     fvalue = flags.l_L_modifier ?
00723                         va_arg(ap,max_float_t) : va_arg(ap,double);
00724                 }
00725                 else
00726                     fvalue = va_arg(ap,max_float_t);
00727 
00728                 if (fvalue < 0)
00729                 {
00730                     flags.plus_space_flag = PSF_MINUS;
00731                     fvalue = -fvalue;
00732                 }
00733                 ptr = float_conversion (fvalue,
00734                         (short)precision,
00735                         buf_pointer += field_width,
00736                         format_flag,
00737                         (char)n,
00738                         flags.alternate_flag);
00739                 if (flags.zeropad)
00740                 {
00741                     precision = field_width - (flags.plus_space_flag != PSF_NONE);
00742                     while (precision > ptr - buf_pointer)
00743                         *--buf_pointer = '0';
00744                 }
00745                 break;
00746 
00747 #endif /* CONFIG_PRINTF <= PRINTF_NOFLOAT */
00748 
00749             case '\0': /* Really bad place to find NUL in */
00750                 format--;
00751 
00752             default:
00753                 /* Undefined conversion! */
00754                 ptr = buf_pointer = bad_conversion;
00755                 ptr += sizeof(bad_conversion) - 1;
00756                 break;
00757 
00758         }
00759 
00760         /*
00761          * This part emittes the formatted string to "put_one_char".
00762          */
00763 
00764         /* If field_width == 0 then nothing should be written. */
00765         precision = ptr - buf_pointer;
00766 
00767         if ( precision > field_width)
00768         {
00769             n = 0;
00770         }
00771         else
00772         {
00773             n = field_width - precision - (flags.plus_space_flag != PSF_NONE);
00774         }
00775 
00776         /* emit any leading pad characters */
00777         if (!flags.left_adjust)
00778             while (--n >= 0)
00779             {
00780                 put_one_char(' ', secret_pointer);
00781 #if CONFIG_PRINTF_COUNT_CHARS
00782                 nr_of_chars++;
00783 #endif
00784             }
00785 
00786         /* emit flag characters (if any) */
00787         if (flags.plus_space_flag)
00788         {
00789             put_one_char(flags.plus_space_flag == PSF_PLUS ? '+' : '-', secret_pointer);
00790 #if CONFIG_PRINTF_COUNT_CHARS
00791             nr_of_chars++;
00792 #endif
00793         }
00794 
00795 #if CPU_HARVARD
00796         if (flags.progmem)
00797         {
00798             while (--precision >= 0)
00799             {
00800                 put_one_char(pgm_read_char(buf_pointer++), secret_pointer);
00801 #if CONFIG_PRINTF_COUNT_CHARS
00802                 nr_of_chars++;
00803 #endif
00804             }
00805         }
00806         else
00807 #endif /* CPU_HARVARD */
00808         {
00809             /* emit the string itself */
00810             while (--precision >= 0)
00811             {
00812                 put_one_char(*buf_pointer++, secret_pointer);
00813 #if CONFIG_PRINTF_COUNT_CHARS
00814                 nr_of_chars++;
00815 #endif
00816             }
00817         }
00818 
00819         /* emit trailing space characters */
00820         if (flags.left_adjust)
00821             while (--n >= 0)
00822             {
00823                 put_one_char(' ', secret_pointer);
00824 #if CONFIG_PRINTF_COUNT_CHARS
00825                 nr_of_chars++;
00826 #endif
00827             }
00828     }
00829 
00830 #else /* PRINTF_REDUCED starts here */
00831 
00832 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
00833     bool l_modifier, h_modifier;
00834     unsigned long u_val, div_val;
00835 #else
00836     unsigned int u_val, div_val;
00837 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00838 
00839     char format_flag;
00840     unsigned int nr_of_chars, base;
00841     char outChar;
00842     char *ptr;
00843 
00844     nr_of_chars = 0;
00845     for (;;)    /* Until full format string read */
00846     {
00847         while ((format_flag = PGM_READ_CHAR(format++)) != '%')    /* Until '%' or '\0' */
00848         {
00849             if (!format_flag)
00850                 return (nr_of_chars);
00851             put_one_char(format_flag, secret_pointer);
00852             nr_of_chars++;
00853         }
00854 
00855 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
00856         /*
00857          * Optional 'l', 'z' or 'h' modifiers?
00858          */
00859         l_modifier = h_modifier = false;
00860         switch (PGM_READ_CHAR(format))
00861         {
00862             case 'l':
00863         #if SIZEOF_SIZE_T == SIZEOF_LONG
00864             case 'z':
00865                 l_modifier = true;
00866         #elif SIZEOF_SIZE_T == SIZEOF_INT
00867                 l_modifier = true;
00868             case 'z':
00869         #endif
00870                 format++;
00871                 break;
00872 
00873             case 'h':
00874                 h_modifier = true;
00875                 format++;
00876                 break;
00877         }
00878 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00879 
00880         switch (format_flag = PGM_READ_CHAR(format++))
00881         {
00882             case 'c':
00883                 format_flag = va_arg(ap, int);
00884             default:
00885                 put_one_char(format_flag, secret_pointer);
00886                 nr_of_chars++;
00887                 continue;
00888 
00889             case 's':
00890                 ptr = va_arg(ap, char *);
00891                 while ((format_flag = *ptr++))
00892                 {
00893                     put_one_char(format_flag, secret_pointer);
00894                     nr_of_chars++;
00895                 }
00896                 continue;
00897 
00898             case 'o':
00899                 base = 8;
00900                 if (IS_SHORT)
00901                     div_val = 0x8000;
00902                 else
00903                     div_val = 0x40000000;
00904                 goto CONVERSION_LOOP;
00905 
00906             case 'd':
00907                 base = 10;
00908                 if (IS_SHORT)
00909                     div_val = 10000;
00910                 else
00911                     div_val = 1000000000;
00912                 goto CONVERSION_LOOP;
00913 
00914             case 'X':
00915             case 'x':
00916                 base = 16;
00917                 if (IS_SHORT)
00918                     div_val = 0x1000;
00919                 else
00920                     div_val = 0x10000000;
00921 
00922 CONVERSION_LOOP:
00923 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
00924                 if (h_modifier)
00925                 {
00926                     if (format_flag == 'd')
00927                         u_val = (short)va_arg(ap, int);
00928                     else
00929                         u_val = (unsigned short)va_arg(ap, int);
00930                 }
00931                 else if (l_modifier)
00932                     u_val = va_arg(ap, long);
00933                 else
00934                 {
00935                     if (format_flag == 'd')
00936                         u_val = va_arg(ap, int);
00937                     else
00938                         u_val = va_arg(ap, unsigned int);
00939                 }
00940 
00941 #else /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00942                 u_val = va_arg(ap,int);
00943 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
00944                 if (format_flag == 'd')
00945                 {
00946                     if (((int)u_val) < 0)
00947                     {
00948                         u_val = - u_val;
00949                         put_one_char('-', secret_pointer);
00950                         nr_of_chars++;
00951                     }
00952                 }
00953                 while (div_val > 1 && div_val > u_val)
00954                 {
00955                     div_val /= base;
00956                 }
00957                 do
00958                 {
00959                     outChar = (u_val / div_val) + '0';
00960                     if (outChar > '9')
00961                     {
00962                         if (format_flag == 'x')
00963                             outChar += 'a'-'9'-1;
00964                         else
00965                             outChar += 'A'-'9'-1;
00966                     }
00967                     put_one_char(outChar, secret_pointer);
00968                     nr_of_chars++;
00969                     u_val %= div_val;
00970                     div_val /= base;
00971                 }
00972                 while (div_val);
00973 
00974         } /* end switch(format_flag...) */
00975     }
00976 #endif /* CONFIG_PRINTF > PRINTF_REDUCED */
00977 }
00978 
00979 #endif /* CONFIG_PRINTF */