1 /*-------------------------------------------------------------------------
2 vfprintf.c - source file for reduced version of printf
4 Copyright (C) 1999, Sandeep Dutta <sandeep.dutta AT ieee.org>
5 Modified for pic16 port, by Vangelis Rokas, 2005 <vrokas AT otenet.gr>
6 Bug-fixed and feature-enhanced by Mauro Giachero, 2008 <mauro.giachero AT gmail.com>
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
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.
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,
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 -------------------------------------------------------------------------*/
31 /* following formats are supported :-
32 format output type argument-type
47 %l[xX] hexadecimal long
48 %h[xX] hexadecimal char
53 %s character generic pointer
55 - the '0', '-' and ' ' alignment modifiers
56 - the '+' and ' ' modifiers
57 - the width field for integral types
58 - the precision field for strings
66 /***********************************************************
67 * The following switches enable some "advanced" features. *
68 * With all the switches enabled: *
70 * ; code size: 2062 (0x080e) bytes ( 1.57%) *
71 * ; 1031 (0x0407) words *
72 * ; udata size: 16 (0x0010) bytes ( 1.25%) *
73 * ; access size: 31 (0x001f) bytes *
74 * With all the switches disabled: *
76 * ; code size: 1278 (0x04fe) bytes ( 0.98%) *
77 * ; 639 (0x027f) words *
78 * ; udata size: 16 (0x0010) bytes ( 1.25%) *
79 * ; access size: 25 (0x0019) bytes *
80 ***********************************************************/
82 * Define this to enable support of the field width, which
83 * allows to specify the minimum number of characters an
85 * Costs ~200 code words and 3 bytes in access RAM.
89 * Define this to enable support of the precision, which
90 * allows to specify the maximum number of characters a
91 * string can use. Note that this implementation doesn't
92 * use this field for integers (as it should).
93 * Costs ~85 code words and 1 byte in access RAM.
97 * Define this to enable support of the '+' and ' ' modifiers,
98 * which specify that a positive signed number must be
99 * preceded respectively with a '+' or a ' ' character.
100 * Costs ~70 code words and 2 words of access RAM
102 #define SIGN_MODIFIERS
104 * With this macro defined, trying to print a float number
105 * will generate the "<NO FLOAT>" string.
106 * Costs ~25 code words
108 #define FLOAT_PLACEHOLDER
110 * With this macro defined, printing floats will work.
111 * This also enables PRECISION and disables FLOAT_PLACEHOLDER.
113 #if defined(USE_FLOATS)
114 /* The configure script always defines USE_FLOATS to 0 or 1. */
119 /* # define USE_FLOATS */
122 #if defined(USE_FLOATS)
124 #undef FLOAT_PLACEHOLDER
127 * This macro enables the use of the 'b' binary specifier and
128 * the use of "%b", "%hb" and "%lb"
130 /* #define BINARY_SPECIFIER */
132 * This macro enables the use of the 'i' integer specifier and
133 * the use of "%u", "%lu", ... in place of "%ud", "%lud", ... .
134 * costs ~10 code words
136 #define EXTRA_INTEGER
138 #if defined(USE_FLOATS)
139 /* x_ftoa requires up to 8 digits (integral part) + '.' + 24 digits
140 * (fractional part). Adding a sign and a NUL byte yields 35 byte. */
142 #elif defined(BINARY_SPECIFIER)
143 /* "%lb" = "0" - "11111111111111111111111111111111" */
146 /* "%lo" = "0" - "37777777777" or "-20000000000" - "17777777777" */
151 extern void io_long (unsigned long);
152 extern void io_str (char *);
153 extern void io_int (unsigned int);
157 vfprintf (FILE * stream
, const char *fmt
, va_list ap
)
163 #if defined(FLOAT_PLACEHOLDER) || defined(USE_FLOATS)
164 unsigned char ffloat
;
166 unsigned char nosign
;
167 unsigned char upcase
;
169 unsigned char fieldwidth
;
170 unsigned char lalign
;
175 unsigned char precision
;
177 #ifdef SIGN_MODIFIERS
178 unsigned char printsign
;
185 char buffer
[BUF_SIZE
];
188 if (0x80 == (unsigned char)(((unsigned long)stream
) >> 16)) {
189 /* strmputchar will modify *(char **)stream, thus confusing the user */
190 stringbuffer
= (char *) stream
;
191 stream
= (FILE *) &stringbuffer
;
195 io_str ("vfprintf: ");
196 io_long ((unsigned long) stream
);
197 io_long ((unsigned long) fmt
);
203 while (*ch
) //for (; *fmt ; fmt++ )
210 #if defined(FLOAT_PLACEHOLDER) || defined(USE_FLOATS)
222 // precision == -1 is used as an "unlimited" precision marker
223 precision
= (unsigned char)-1;
225 #ifdef SIGN_MODIFIERS
233 __stream_putchar (stream
, *ch
);
252 #ifdef SIGN_MODIFIERS
268 if ((*ch
>= '1') && (*ch
<= '9'))
270 while ((*ch
>= '0') && (*ch
<= '9'))
272 fieldwidth
= 10 * fieldwidth
+ (*ch
) - '0';
283 while ((*ch
>= '0') && (*ch
<= '9'))
285 precision
= 10 * precision
+ (*ch
) - '0';
312 padchar
= ' '; /* Strings are always space-padded */
326 #ifdef BINARX_SPECIFIER
330 #if defined(FLOAT_PLACEHOLDER) || defined(USE_FLOATS)
337 else if ((*ch
== 'd') || (*ch
== 'i')) /* This is the default */
339 else if (nosign
) /* %u alone is the same as %ud */
347 __stream_putchar (stream
, *ch
);
355 str
= va_arg (ap
, char *);
356 #if defined(USE_FLOATS)
360 float f
= va_arg(ap
, float);
362 x_ftoa (f
, buffer
, BUF_SIZE
, precision
);
364 #elif defined(FLOAT_PLACEHOLDER)
368 str
= (char*)"<NO FLOAT>";
371 precision
= (unsigned char)-1;
372 #endif /* PRECISION */
373 #endif /* FLOAT_PLACEHOLDER */
378 precision
= (unsigned char)-1; //FIXME: No support for the precision field on numerals
383 val
= va_arg (ap
, long);
390 val
= (char) va_arg (ap
, int); // FIXME: SDCC passes 1-byte char varargs as 2-byte ints...
391 if ((radix
!= 10) || nosign
)
392 val
= (unsigned char) val
; //Avoid unwanted sign extension
399 val
= va_arg (ap
, int);
400 if ((radix
!= 10) || nosign
)
401 val
= (unsigned int) val
; //Avoid unwanted sign extension
407 str
= buffer
+ 1; //Reserve space for a forced '+'
411 ultoa (val
, buffer
+ 1, radix
);
413 ltoa (val
, buffer
+ 1, radix
);
414 #ifdef SIGN_MODIFIERS
415 if (printsign
&& (*str
!= '-'))
424 *str
= (unsigned char) val
;
430 //Count how many pad chars are required in fieldwidth
432 while (fieldwidth
&& *str1
)
442 __stream_putchar (stream
, padchar
);
450 && (!~precision
|| precision
--)
457 radix
= toupper (radix
);
459 __stream_putchar (stream
, radix
);
468 //Right padding (with spaces)
473 __stream_putchar (stream
, ' ');
482 __stream_putchar (stream
, *ch
);