1 /*-----------------------------------------------------------------
2 vfprintf.c - source file for reduced version of printf
4 Modified for pic16 port, by Vangelis Rokas, 2005 (vrokas@otenet.gr)
5 Bug-fixed and feature-enhanced by Mauro Giachero, 2008 (mauro.giachero@gmail.com)
7 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
9 This library is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Library General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 In other words, you are welcome to use, share and improve this program.
24 You are forbidden to forbid anyone else to use, share and improve
25 what you give them. Help stamp out software-hoarding!
27 As a special exception, if you link this library with other files,
28 some of which are compiled with SDCC, to produce an executable,
29 this library does not by itself cause the resulting executable
30 to be covered by the GNU General Public License.
31 This exception does not however invalidate any other reasons why
32 the executable file might be covered by the GNU General Public License.
33 -------------------------------------------------------------------------*/
35 /* following formats are supported :-
36 format output type argument-type
51 %l[xX] hexadecimal long
52 %h[xX] hexadecimal char
57 %s character generic pointer
59 - the '0', '-' and ' ' alignment modifiers
60 - the '+' and ' ' modifiers
61 - the width field for integral types
62 - the precision field for strings
70 /***********************************************************
71 * The following switches enable some "advanced" features. *
72 * With all the switches enabled: *
74 * ; code size: 2062 (0x080e) bytes ( 1.57%) *
75 * ; 1031 (0x0407) words *
76 * ; udata size: 16 (0x0010) bytes ( 1.25%) *
77 * ; access size: 31 (0x001f) bytes *
78 * With all the switches disabled: *
80 * ; code size: 1278 (0x04fe) bytes ( 0.98%) *
81 * ; 639 (0x027f) words *
82 * ; udata size: 16 (0x0010) bytes ( 1.25%) *
83 * ; access size: 25 (0x0019) bytes *
84 ***********************************************************/
86 * Define this to enable support of the field width, which
87 * allows to specify the minimum number of characters an
89 * Costs ~200 code words and 3 bytes in access RAM.
93 * Define this to enable support of the precision, which
94 * allows to specify the maximum number of characters a
95 * string can use. Note that this implementation doesn't
96 * use this field for integers (as it should).
97 * Costs ~85 code words and 1 byte in access RAM.
101 * Define this to enable support of the '+' and ' ' modifiers,
102 * which specify that a positive signed number must be
103 * preceded respectively with a '+' or a ' ' character.
104 * Costs ~70 code words and 2 words of access RAM
106 #define SIGN_MODIFIERS
108 * With this macro defined, trying to print a float number
109 * will generate the "<NO FLOAT>" string.
110 * Costs ~25 code words
112 #define FLOAT_PLACEHOLDER
114 * With this macro defined, printing floats will work.
115 * This also enables PRECISION and disables FLOAT_PLACEHOLDER.
117 #if defined(USE_FLOATS)
118 /* The configure script always defines USE_FLOATS to 0 or 1. */
123 /* # define USE_FLOATS */
126 #if defined(USE_FLOATS)
128 #undef FLOAT_PLACEHOLDER
131 * This macro enables the use of the 'b' binary specifier and
132 * the use of "%b", "%hb" and "%lb"
134 /* #define BINARY_SPECIFIER */
136 * This macro enables the use of the 'i' integer specifier and
137 * the use of "%u", "%lu", ... in place of "%ud", "%lud", ... .
138 * costs ~10 code words
140 #define EXTRA_INTEGER
142 #if defined(USE_FLOATS)
143 /* x_ftoa requires up to 8 digits (integral part) + '.' + 24 digits
144 * (fractional part). Adding a sign and a NUL byte yields 35 byte. */
146 #elif defined(BINARY_SPECIFIER)
147 /* "%lb" = "0" - "11111111111111111111111111111111" */
150 /* "%lo" = "0" - "37777777777" or "-20000000000" - "17777777777" */
155 extern void io_long (unsigned long);
156 extern void io_str (char *);
157 extern void io_int (unsigned int);
161 vfprintf (FILE * stream, const char *fmt, va_list ap)
167 #if defined(FLOAT_PLACEHOLDER) || defined(USE_FLOATS)
168 unsigned char ffloat;
170 unsigned char nosign;
171 unsigned char upcase;
173 unsigned char fieldwidth;
174 unsigned char lalign;
179 unsigned char precision;
181 #ifdef SIGN_MODIFIERS
182 unsigned char printsign;
188 char buffer[BUF_SIZE];
191 if (0x80 == (unsigned char)(((unsigned long)stream) >> 16)) {
192 /* strmputchar will modify *(char **)stream, thus confusing the user */
193 stringbuffer = (char *) stream;
194 stream = (FILE *) &stringbuffer;
198 io_str ("vfprintf: ");
199 io_long ((unsigned long) stream);
200 io_long ((unsigned long) fmt);
206 while (*ch) //for (; *fmt ; fmt++ )
213 #if defined(FLOAT_PLACEHOLDER) || defined(USE_FLOATS)
225 // precision == -1 is used as an "unlimited" precision marker
228 #ifdef SIGN_MODIFIERS
236 __stream_putchar (stream, *ch);
255 #ifdef SIGN_MODIFIERS
271 if ((*ch >= '1') && (*ch <= '9'))
273 while ((*ch >= '0') && (*ch <= '9'))
275 fieldwidth = 10 * fieldwidth + (*ch) - '0';
286 while ((*ch >= '0') && (*ch <= '9'))
288 precision = 10 * precision + (*ch) - '0';
315 padchar = ' '; /* Strings are always space-padded */
329 #ifdef BINARX_SPECIFIER
333 #if defined(FLOAT_PLACEHOLDER) || defined(USE_FLOATS)
340 else if ((*ch == 'd') || (*ch == 'i')) /* This is the default */
342 else if (nosign) /* %u alone is the same as %ud */
350 __stream_putchar (stream, *ch);
358 str = va_arg (ap, char *);
359 #if defined(USE_FLOATS)
363 float f = va_arg(ap, float);
365 x_ftoa (f, buffer, BUF_SIZE, precision);
367 #elif defined(FLOAT_PLACEHOLDER)
375 #endif /* PRECISION */
376 #endif /* FLOAT_PLACEHOLDER */
381 precision = -1; //FIXME: No support for the precision field on numerals
386 val = va_arg (ap, long);
393 val = (char) va_arg (ap, int); // FIXME: SDCC passes 1-byte char varargs as 2-byte ints...
394 if ((radix != 10) || nosign)
395 val = (unsigned char) val; //Avoid unwanted sign extension
402 val = va_arg (ap, int);
403 if ((radix != 10) || nosign)
404 val = (unsigned int) val; //Avoid unwanted sign extension
410 str = buffer + 1; //Reserve space for a forced '+'
414 ultoa (val, buffer + 1, radix);
416 ltoa (val, buffer + 1, radix);
417 #ifdef SIGN_MODIFIERS
418 if (printsign && (*str != '-'))
427 *str = (unsigned char) val;
433 //Count how many pad chars are required in fieldwidth
435 while (fieldwidth && *str1)
445 __stream_putchar (stream, padchar);
453 && (!~precision || precision--)
460 radix = toupper (radix);
462 __stream_putchar (stream, radix);
471 //Right padding (with spaces)
476 __stream_putchar (stream, ' ');
485 __stream_putchar (stream, *ch);