?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  1. /*-----------------------------------------------------------------
  2.    printf_large.c - formatted output conversion
  3.  
  4.    Copyright (C) 1999, Martijn van Balen <aed AT iae.nl>
  5.    Added %f By - <johan.knol AT iduna.nl> (2000)
  6.    Refactored by - Maarten Brock (2004)
  7.  
  8.    This library is free software; you can redistribute it and/or modify it
  9.    under the terms of the GNU General Public License as published by the
  10.    Free Software Foundation; either version 2, or (at your option) any
  11.    later version.
  12.  
  13.    This library is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this library; see the file COPYING. If not, write to the
  20.    Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
  21.    MA 02110-1301, USA.
  22.  
  23.    As a special exception, if you link this library with other files,
  24.    some of which are compiled with SDCC, to produce an executable,
  25.    this library does not by itself cause the resulting executable to
  26.    be covered by the GNU General Public License. This exception does
  27.    not however invalidate any other reasons why the executable file
  28.    might be covered by the GNU General Public License.
  29. -------------------------------------------------------------------------*/
  30.  
  31. #if defined (__SDCC_ds390) || defined (__SDCC_USE_XSTACK) || defined (__SDCC_MODEL_HUGE)
  32. #define USE_FLOATS 1
  33. #endif
  34.  
  35. #include <stdarg.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38. #include <stdio.h>
  39. #include <stdbool.h>
  40. #include <sdcc-lib.h>
  41.  
  42. #define PTR value.ptr
  43.  
  44. #ifdef __SDCC_ds390
  45. #define NULL_STRING "<NULL>"
  46. #define NULL_STRING_LENGTH 6
  47. #endif
  48.  
  49. #if defined (__SDCC_mcs51) && defined (__SDCC_MODEL_SMALL) && !defined (__SDCC_STACK_AUTO)
  50. # define MEM_SPACE_BUF __idata
  51. # define MEM_SPACE_BUF_PP __idata
  52. #else
  53. # define MEM_SPACE_BUF
  54. # define MEM_SPACE_BUF_PP _AUTOMEM
  55. #endif
  56.  
  57. /****************************************************************************/
  58.  
  59. //typedef const char * ptr_t;
  60. #define ptr_t const char *
  61.  
  62. #ifdef toupper
  63. #undef toupper
  64. #endif
  65. #ifdef tolower
  66. #undef tolower
  67. #endif
  68. #ifdef islower
  69. #undef islower
  70. #endif
  71. #ifdef isdigit
  72. #undef isdigit
  73. #endif
  74.  
  75. //#define toupper(c) ((c)&=~0x20)
  76. #define toupper(c) ((c)&=0xDF)
  77. #define tolower(c) ((c)|=0x20)
  78. #define islower(c) ((unsigned char)c >= (unsigned char)'a' && (unsigned char)c <= (unsigned char)'z')
  79. #define isdigit(c) ((unsigned char)c >= (unsigned char)'0' && (unsigned char)c <= (unsigned char)'9')
  80.  
  81. typedef union
  82. {
  83.   unsigned char  byte[5];
  84.   long           l;
  85.   unsigned long  ul;
  86.   float          f;
  87.   const char     *ptr;
  88. } value_t;
  89.  
  90. #ifndef __SDCC_STACK_AUTO
  91.   static bool lower_case;
  92.   static pfn_outputchar output_char;
  93.   static void* p;
  94.   static value_t value;
  95.   static int charsOutputted;
  96. #endif
  97.  
  98. /****************************************************************************/
  99.  
  100. #ifdef __SDCC_STACK_AUTO
  101.   #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
  102. #else
  103.   #define OUTPUT_CHAR(c, p) _output_char (c)
  104.   static void
  105.   _output_char (unsigned char c)
  106.   {
  107.     output_char( c, p );
  108.     charsOutputted++;
  109.   }
  110. #endif
  111.  
  112. /*--------------------------------------------------------------------------*/
  113.  
  114. #ifdef __SDCC_STACK_AUTO
  115.   static void
  116.   output_digit (unsigned char n, bool lower_case, pfn_outputchar output_char, void* p)
  117.   {
  118.     register unsigned char c = n + (unsigned char)'0';
  119.  
  120.     if (c > (unsigned char)'9')
  121.     {
  122.       c += (unsigned char)('A' - '0' - 10);
  123.       if (lower_case)
  124.          c += (unsigned char)('a' - 'A');
  125.     }
  126.     output_char( c, p );
  127.   }
  128. #else
  129.   static void
  130.   output_digit (unsigned char n)
  131.   {
  132.     register unsigned char c = n + (unsigned char)'0';
  133.  
  134.     if (c > (unsigned char)'9')
  135.     {
  136.       c += (unsigned char)('A' - '0' - 10);
  137.       if (lower_case)
  138.          c = tolower(c);
  139.     }
  140.     _output_char( c );
  141.   }
  142. #endif
  143.  
  144. /*--------------------------------------------------------------------------*/
  145.  
  146. #ifdef __SDCC_STACK_AUTO
  147.   #define OUTPUT_2DIGITS( B )   { output_2digits( B, lower_case, output_char, p ); charsOutputted += 2; }
  148.   static void
  149.   output_2digits (unsigned char b, bool lower_case, pfn_outputchar output_char, void* p)
  150.   {
  151.     output_digit( b>>4,   lower_case, output_char, p );
  152.     output_digit( b&0x0F, lower_case, output_char, p );
  153.   }
  154. #else
  155.   #define OUTPUT_2DIGITS( B )   output_2digits( B )
  156.   static void
  157.   output_2digits (unsigned char b)
  158.   {
  159.     output_digit( b>>4   );
  160.     output_digit( b&0x0F );
  161.   }
  162. #endif
  163.  
  164. /*--------------------------------------------------------------------------*/
  165.  
  166. #if defined __SDCC_STACK_AUTO
  167. static void
  168. calculate_digit (value_t _AUTOMEM * value, unsigned char radix)
  169. {
  170.   unsigned long ul = value->ul;
  171.   unsigned char _AUTOMEM * pb4 = &value->byte[4];
  172.   unsigned char i = 32;
  173.  
  174.   do
  175.   {
  176.     *pb4 = (*pb4 << 1) | ((ul >> 31) & 0x01);
  177.     ul <<= 1;
  178.  
  179.     if (radix <= *pb4 )
  180.     {
  181.       *pb4 -= radix;
  182.       ul |= 1;
  183.     }
  184.   } while (--i);
  185.   value->ul = ul;
  186. }
  187. #else
  188. static void
  189. calculate_digit (unsigned char radix)
  190. {
  191.   register unsigned long ul = value.ul;
  192.   register unsigned char b4 = value.byte[4];
  193.   register unsigned char i = 32;
  194.  
  195.   do
  196.   {
  197.     b4 = (b4 << 1);
  198.     b4 |= (ul >> 31) & 0x01;
  199.     ul <<= 1;
  200.  
  201.     if (radix <= b4 )
  202.     {
  203.       b4 -= radix;
  204.       ul |= 1;
  205.     }
  206.   } while (--i);
  207.   value.ul = ul;
  208.   value.byte[4] = b4;
  209. }
  210. #endif
  211.  
  212. #if USE_FLOATS
  213.  
  214. /* This is a very inefficient but direct approach, since we have no math
  215.    library yet (e.g. log()).
  216.    It does most of the modifiers, but has some restrictions. E.g. the
  217.    abs(float) shouldn't be bigger than an unsigned long (that's
  218.    about 4294967295), but still makes it usefull for most real-life
  219.    applications.
  220. */
  221.  
  222. #define DEFAULT_FLOAT_PRECISION 6
  223.  
  224. #ifdef __SDCC_STACK_AUTO
  225. #define OUTPUT_FLOAT(F, W, D, L, Z, S, P)       output_float(F, W, D, L, Z, S, P, output_char, p)
  226. static unsigned char
  227. output_float (float f, unsigned char reqWidth,
  228.               signed char reqDecimals,
  229.               bool left, bool zero, bool sign, bool space,
  230.               pfn_outputchar output_char, void* p)
  231. {
  232.   unsigned char charsOutputted = 0;
  233.  #if defined (__SDCC_mcs51)
  234.   char fpBuffer[16];      //mcs51 has only a small stack
  235.  #else
  236.   char fpBuffer[128];
  237.  #endif
  238. #else
  239. #define OUTPUT_FLOAT(F, W, D, L, Z, S, P)       output_float(F, W, D, L, Z, S, P)
  240. static void
  241. output_float (float f, unsigned char reqWidth,
  242.               signed char reqDecimals,
  243.               bool left, bool zero, bool sign, bool space)
  244. {
  245.   __xdata char fpBuffer[128];
  246. #endif //__SDCC_STACK_AUTO
  247.   bool negative = 0;
  248.   unsigned long integerPart;
  249.   float rounding;
  250.   float decimalPart;
  251.   char fpBI=0, fpBD;
  252.   unsigned char minWidth, i;
  253.   signed char exp = -128;
  254.  
  255.   // save the sign
  256.   if (f<0)
  257.   {
  258.     negative=1;
  259.     f=-f;
  260.   }
  261.  
  262.   if (f>0x00ffffff)
  263.   {
  264.     // this part is from Frank van der Hulst
  265.  
  266.     for (exp = 0; f >= 10.0; exp++) f /=10.0;
  267.     for (       ; f < 1.0;   exp--) f *=10.0;
  268.  
  269.     if (negative)
  270.     {
  271.       OUTPUT_CHAR ('-', p);
  272.     }
  273.     else
  274.     {
  275.       if (sign)
  276.       {
  277.         OUTPUT_CHAR ('+', p);
  278.       }
  279.     }
  280.     reqWidth = 0;
  281.     left = 0;
  282.     zero = 0;
  283.     sign = 0;
  284.     space = 0;
  285.   }
  286.  
  287.   // display some decimals as default
  288.   if (reqDecimals==-1)
  289.     reqDecimals=DEFAULT_FLOAT_PRECISION;
  290.  
  291.   // round the float
  292.   rounding = 0.5;
  293.   for (i=reqDecimals; i>0; i--)
  294.   {
  295.       rounding /= 10.0;
  296.   }
  297.   f += rounding;
  298.  
  299.   // split the float
  300.   integerPart = f;
  301.   decimalPart = f - integerPart;
  302.  
  303.   // fill the buffer with the integerPart (in reversed order!)
  304.   while (integerPart)
  305.   {
  306.     fpBuffer[fpBI++]='0' + integerPart%10;
  307.     integerPart /= 10;
  308.   }
  309.   if (!fpBI)
  310.   {
  311.     // we need at least a 0
  312.     fpBuffer[fpBI++]='0';
  313.   }
  314.  
  315.   // fill buffer with the decimalPart (in normal order)
  316.   fpBD=fpBI;
  317.  
  318.   for (i=reqDecimals; i>0; i--)
  319.   {
  320.       decimalPart *= 10.0;
  321.       // truncate the float
  322.       integerPart = decimalPart;
  323.       fpBuffer[fpBD++] = '0' + integerPart;
  324.       decimalPart -= integerPart;
  325.   }
  326.  
  327.   minWidth=fpBI; // we need at least these
  328.   minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
  329.   if (negative || sign || space)
  330.     minWidth++; // and maybe even this :)
  331.  
  332.   if (!left && reqWidth>i)
  333.   {
  334.     if (zero)
  335.     {
  336.       if (negative)
  337.       {
  338.         OUTPUT_CHAR('-', p);
  339.       }
  340.       else if (sign)
  341.       {
  342.         OUTPUT_CHAR('+', p);
  343.       }
  344.       else if (space)
  345.       {
  346.         OUTPUT_CHAR(' ', p);
  347.       }
  348.       while (reqWidth-->minWidth)
  349.       {
  350.         OUTPUT_CHAR('0', p);
  351.       }
  352.     }
  353.     else
  354.     {
  355.       while (reqWidth-->minWidth)
  356.       {
  357.         OUTPUT_CHAR(' ', p);
  358.       }
  359.       if (negative)
  360.       {
  361.         OUTPUT_CHAR('-', p);
  362.       }
  363.       else if (sign)
  364.       {
  365.         OUTPUT_CHAR('+', p);
  366.       }
  367.       else if (space)
  368.       {
  369.         OUTPUT_CHAR(' ', p);
  370.       }
  371.     }
  372.   }
  373.   else
  374.   {
  375.     if (negative)
  376.     {
  377.       OUTPUT_CHAR('-', p);
  378.     }
  379.     else if (sign)
  380.     {
  381.       OUTPUT_CHAR('+', p);
  382.     }
  383.     else if (space)
  384.     {
  385.       OUTPUT_CHAR(' ', p);
  386.     }
  387.   }
  388.  
  389.   // output the integer part
  390.   i=fpBI-1;
  391.   do {
  392.     OUTPUT_CHAR (fpBuffer[i], p);
  393.   } while (i--);
  394.  
  395.   // ouput the decimal part
  396.   if (reqDecimals)
  397.   {
  398.     OUTPUT_CHAR ('.', p);
  399.     i=fpBI;
  400.     while (reqDecimals--)
  401.     {
  402.       OUTPUT_CHAR (fpBuffer[i++], p);
  403.     }
  404.   }
  405.  
  406.   if (left && reqWidth>minWidth)
  407.   {
  408.     while (reqWidth-->minWidth)
  409.     {
  410.       OUTPUT_CHAR(' ', p);
  411.     }
  412.   }
  413.  
  414.   if (exp != -128)
  415.   {
  416.     OUTPUT_CHAR ('e', p);
  417.     if (exp<0)
  418.     {
  419.       OUTPUT_CHAR ('-', p);
  420.       exp = -exp;
  421.     }
  422.     OUTPUT_CHAR ('0'+exp/10, p);
  423.     OUTPUT_CHAR ('0'+exp%10, p);
  424.   }
  425. #ifdef __SDCC_STACK_AUTO
  426.   return charsOutputted;
  427. #else
  428.   return;
  429. #endif //__SDCC_STACK_AUTO
  430. }
  431. #endif //USE_FLOATS
  432.  
  433. int
  434. _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
  435. {
  436.   bool   left_justify;
  437.   bool   zero_padding;
  438.   bool   prefix_sign;
  439.   bool   prefix_space;
  440.   bool   signed_argument;
  441.   bool   char_argument;
  442.   bool   long_argument;
  443.   bool   float_argument;
  444. #ifdef __SDCC_STACK_AUTO
  445.   bool   lower_case;
  446.   value_t value;
  447.   int charsOutputted;
  448. #endif
  449.   bool   lsd;
  450.  
  451.   unsigned char radix;
  452.   size_t  width;
  453.   int decimals;
  454.   size_t  length;
  455.   char           c;
  456.  
  457. #ifdef __SDCC_STACK_AUTO
  458.   #define output_char   pfn
  459.   #define p             pvoid
  460. #else
  461.   output_char = pfn;
  462.   p = pvoid;
  463. #endif
  464.  
  465.   // reset output chars
  466.   charsOutputted = 0;
  467.  
  468. #ifdef __SDCC_ds390
  469.   if (format==0)
  470.   {
  471.     format=NULL_STRING;
  472.   }
  473. #endif
  474.  
  475.   while( c=*format++ )
  476.   {
  477.     if ( c=='%' )
  478.     {
  479.       left_justify    = 0;
  480.       zero_padding    = 0;
  481.       prefix_sign     = 0;
  482.       prefix_space    = 0;
  483.       signed_argument = 0;
  484.       char_argument   = 0;
  485.       long_argument   = 0;
  486.       float_argument  = 0;
  487.       radix           = 0;
  488.       width           = 0;
  489.       decimals        = -1;
  490.  
  491. get_conversion_spec:
  492.  
  493.       c = *format++;
  494.  
  495.       if (c=='%')
  496.       {
  497.         OUTPUT_CHAR(c, p);
  498.         continue;
  499.       }
  500.  
  501.       if (isdigit(c))
  502.       {
  503.         if (decimals==-1)
  504.         {
  505.           width = 10*width + c - '0';
  506.           if (width == 0)
  507.           {
  508.             /* first character of width is a zero */
  509.             zero_padding = 1;
  510.           }
  511.         }
  512.         else
  513.         {
  514.           decimals = 10*decimals + c - '0';
  515.         }
  516.         goto get_conversion_spec;
  517.       }
  518.  
  519.       if (c=='.')
  520.       {
  521.         if (decimals==-1)
  522.           decimals=0;
  523.         else
  524.           ; // duplicate, ignore
  525.         goto get_conversion_spec;
  526.       }
  527.  
  528.       if (islower(c))
  529.       {
  530.         c = toupper(c);
  531.         lower_case = 1;
  532.       }
  533.       else
  534.         lower_case = 0;
  535.  
  536.       switch( c )
  537.       {
  538.       case '-':
  539.         left_justify = 1;
  540.         goto get_conversion_spec;
  541.       case '+':
  542.         prefix_sign = 1;
  543.         goto get_conversion_spec;
  544.       case ' ':
  545.         prefix_space = 1;
  546.         goto get_conversion_spec;
  547.       case 'B': /* byte */
  548.         char_argument = 1;
  549.         goto get_conversion_spec;
  550. //      case '#': /* not supported */
  551.       case 'H': /* short */
  552.       case 'J': /* intmax_t */
  553.       case 'T': /* ptrdiff_t */
  554.       case 'Z': /* size_t */
  555.         goto get_conversion_spec;
  556.       case 'L': /* long */
  557.         long_argument = 1;
  558.         goto get_conversion_spec;
  559.  
  560.       case 'C':
  561.         if( char_argument )
  562.           c = va_arg(ap,char);
  563.         else
  564.           c = va_arg(ap,int);
  565.         OUTPUT_CHAR( c, p );
  566.         break;
  567.  
  568.       case 'S':
  569.         PTR = va_arg(ap,ptr_t);
  570.  
  571. #ifdef __SDCC_ds390
  572.         if (PTR==0)
  573.         {
  574.           PTR=NULL_STRING;
  575.           length=NULL_STRING_LENGTH;
  576.         }
  577.         else
  578.         {
  579.           length = strlen(PTR);
  580.         }
  581. #else
  582.         length = strlen(PTR);
  583. #endif
  584.         if ( decimals == -1 )
  585.         {
  586.           decimals = length;
  587.         }
  588.         if ( ( !left_justify ) && (length < width) )
  589.         {
  590.           width -= length;
  591.           while( width-- != 0 )
  592.           {
  593.             OUTPUT_CHAR( ' ', p );
  594.           }
  595.         }
  596.  
  597.         while ( (c = *PTR)  && (decimals-- > 0))
  598.         {
  599.           OUTPUT_CHAR( c, p );
  600.           PTR++;
  601.         }
  602.  
  603.         if ( left_justify && (length < width))
  604.         {
  605.           width -= length;
  606.           while( width-- != 0 )
  607.           {
  608.             OUTPUT_CHAR( ' ', p );
  609.           }
  610.         }
  611.         break;
  612.  
  613.       case 'P':
  614.         PTR = va_arg(ap,ptr_t);
  615.  
  616. #if defined (__SDCC_ds390)
  617.         {
  618.           unsigned char memtype = value.byte[3];
  619.           if (memtype >= 0x80)
  620.             c = 'C';
  621.           else if (memtype >= 0x60)
  622.             c = 'P';
  623.           else if (memtype >= 0x40)
  624.             c = 'I';
  625.           else
  626.             c = 'X';
  627.         }
  628.         OUTPUT_CHAR(c, p);
  629.         OUTPUT_CHAR(':', p);
  630.         OUTPUT_CHAR('0', p);
  631.         OUTPUT_CHAR('x', p);
  632.         OUTPUT_2DIGITS( value.byte[2] );
  633.         OUTPUT_2DIGITS( value.byte[1] );
  634.         OUTPUT_2DIGITS( value.byte[0] );
  635. #elif defined (__SDCC_mcs51)
  636.         {
  637.           unsigned char memtype = value.byte[2];
  638.           if (memtype >= 0x80)
  639.             c = 'C';
  640.           else if (memtype >= 0x60)
  641.             c = 'P';
  642.           else if (memtype >= 0x40)
  643.             c = 'I';
  644.           else
  645.             c = 'X';
  646.         }
  647.         OUTPUT_CHAR(c, p);
  648.         OUTPUT_CHAR(':', p);
  649.         OUTPUT_CHAR('0', p);
  650.         OUTPUT_CHAR('x', p);
  651.         if ((c != 'I' /* idata */) &&
  652.             (c != 'P' /* pdata */))
  653.         {
  654.           OUTPUT_2DIGITS( value.byte[1] );
  655.         }
  656.         OUTPUT_2DIGITS( value.byte[0] );
  657. #else
  658.         OUTPUT_CHAR('0', p);
  659.         OUTPUT_CHAR('x', p);
  660.         OUTPUT_2DIGITS( value.byte[1] );
  661.         OUTPUT_2DIGITS( value.byte[0] );
  662. #endif
  663.         break;
  664.  
  665.       case 'D':
  666.       case 'I':
  667.         signed_argument = 1;
  668.         radix = 10;
  669.         break;
  670.  
  671.       case 'O':
  672.         radix = 8;
  673.         break;
  674.  
  675.       case 'U':
  676.         radix = 10;
  677.         break;
  678.  
  679.       case 'X':
  680.         radix = 16;
  681.         break;
  682.  
  683.       case 'F':
  684.         float_argument=1;
  685.         break;
  686.  
  687.       default:
  688.         // nothing special, just output the character
  689.         OUTPUT_CHAR( c, p );
  690.         break;
  691.       }
  692.  
  693.       if (float_argument)
  694.       {
  695.         value.f = va_arg(ap, float);
  696. #if !USE_FLOATS
  697.         PTR="<NO FLOAT>";
  698.         while (c=*PTR++)
  699.         {
  700.           OUTPUT_CHAR (c, p);
  701.         }
  702.         // treat as long hex
  703.         //radix=16;
  704.         //long_argument=1;
  705.         //zero_padding=1;
  706.         //width=8;
  707. #else
  708.         // ignore b and l conversion spec for now
  709. #ifdef __SDCC_STACK_AUTO
  710.         charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
  711.                                      zero_padding, prefix_sign, prefix_space);
  712. #else
  713.         OUTPUT_FLOAT(value.f, width, decimals, left_justify,
  714.                      zero_padding, prefix_sign, prefix_space);
  715. #endif //__SDCC_STACK_AUTO
  716. #endif //USE_FLOATS
  717.       }
  718.       else if (radix != 0)
  719.       {
  720.         // Apparently we have to output an integral type
  721.         // with radix "radix"
  722.         unsigned char MEM_SPACE_BUF store[6];
  723.         unsigned char MEM_SPACE_BUF_PP *pstore = &store[5];
  724.  
  725.         // store value in byte[0] (LSB) ... byte[3] (MSB)
  726.         if (char_argument)
  727.         {
  728.           value.l = va_arg(ap, char);
  729.           if (!signed_argument)
  730.           {
  731.             value.l &= 0xFF;
  732.           }
  733.         }
  734.         else if (long_argument)
  735.         {
  736.           value.l = va_arg(ap, long);
  737.         }
  738.         else // must be int
  739.         {
  740.           value.l = va_arg(ap, int);
  741.           if (!signed_argument)
  742.           {
  743.             value.l &= 0xFFFF;
  744.           }
  745.         }
  746.  
  747.         if ( signed_argument )
  748.         {
  749.           if (value.l < 0)
  750.             value.l = -value.l;
  751.           else
  752.             signed_argument = 0;
  753.         }
  754.  
  755.         length=0;
  756.         lsd = 1;
  757.  
  758.         do {
  759.           value.byte[4] = 0;
  760. #if defined __SDCC_STACK_AUTO
  761.           calculate_digit(&value, radix);
  762. #else
  763.           calculate_digit(radix);
  764. #endif
  765.           if (!lsd)
  766.           {
  767.             *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
  768.             pstore--;
  769.           }
  770.           else
  771.           {
  772.             *pstore = value.byte[4];
  773.           }
  774.           length++;
  775.           lsd = !lsd;
  776.         } while( value.ul );
  777.  
  778.         if (width == 0)
  779.         {
  780.           // default width. We set it to 1 to output
  781.           // at least one character in case the value itself
  782.           // is zero (i.e. length==0)
  783.           width = 1;
  784.         }
  785.  
  786.         /* prepend spaces if needed */
  787.         if (!zero_padding && !left_justify)
  788.         {
  789.           while ( width > (unsigned char) (length+1) )
  790.           {
  791.             OUTPUT_CHAR( ' ', p );
  792.             width--;
  793.           }
  794.         }
  795.  
  796.         if (signed_argument) // this now means the original value was negative
  797.         {
  798.           OUTPUT_CHAR( '-', p );
  799.           // adjust width to compensate for this character
  800.           width--;
  801.         }
  802.         else if (length != 0)
  803.         {
  804.           // value > 0
  805.           if (prefix_sign)
  806.           {
  807.             OUTPUT_CHAR( '+', p );
  808.             // adjust width to compensate for this character
  809.             width--;
  810.           }
  811.           else if (prefix_space)
  812.           {
  813.             OUTPUT_CHAR( ' ', p );
  814.             // adjust width to compensate for this character
  815.             width--;
  816.           }
  817.         }
  818.  
  819.         /* prepend zeroes/spaces if needed */
  820.         if (!left_justify)
  821.         {
  822.           while ( width-- > length )
  823.           {
  824.             OUTPUT_CHAR( zero_padding ? '0' : ' ', p );
  825.           }
  826.         }
  827.         else
  828.         {
  829.           /* spaces are appended after the digits */
  830.           if (width > length)
  831.             width -= length;
  832.           else
  833.             width = 0;
  834.         }
  835.  
  836.         /* output the digits */
  837.         while( length-- )
  838.         {
  839.           lsd = !lsd;
  840.           if (!lsd)
  841.           {
  842.             pstore++;
  843.             value.byte[4] = *pstore >> 4;
  844.           }
  845.           else
  846.           {
  847.             value.byte[4] = *pstore & 0x0F;
  848.           }
  849. #ifdef __SDCC_STACK_AUTO
  850.           output_digit( value.byte[4], lower_case, output_char, p );
  851.           charsOutputted++;
  852. #else
  853.           output_digit( value.byte[4] );
  854. #endif
  855.         }
  856.         if (left_justify)
  857.         {
  858.           while (width-- > 0)
  859.           {
  860.             OUTPUT_CHAR(' ', p);
  861.           }
  862.         }
  863.       }
  864.     }
  865.     else
  866.     {
  867.       // nothing special, just output the character
  868.       OUTPUT_CHAR( c, p );
  869.     }
  870.   }
  871.  
  872.   return charsOutputted;
  873. }
  874.  
  875. /****************************************************************************/
  876.