2 * simple, small and self contained snprintf() function.
3 * Copyright (C) 2005 Weston Schmidt
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * General information about this file:
26 * This file has been created with the ability to be compiled using sdcc
27 * and gcc both. If gcc is used, the output file can be executed and
28 * the built in test vectors will be run.
30 * The test vectors I created are very simple and in no way test
31 * everything that should be tested or really come close. The output
32 * is visually inspected for correctness. Additionally, I have not
33 * done a thorough job testing this to ensure that no buffer overruns
34 * take place. Logically, everything looks pretty safe, and it works
35 * for the debug generation that I needed it to work for.
37 * I ran into problems when running this on my pic because I was allocating
38 * 80 byte long arrays on the stack (which was only 128 bytes is size).
39 * The end result was "it just didn't work" with no real hints. So if
40 * this happens to you, think about up-ing the stack size or moving your
41 * arrays out of automatic stack variables (defined inside {}s, which
42 * scope the variable) and out to statically declared memory (aka "global"
45 * I hope this saves you the day it took me to write and debug.
50 #define SUPPORT_CHAR_C
52 /* Normally a char is promoted to int when passed as varargs parameter */
53 /* but SDCC leaves it as char. */
54 #if !defined(__SDCC) || defined(__SDCC_pdk14) || defined(__SDCC_pdk15)
55 # define VA_ARG_CHAR int
56 # define VA_ARG(args,type) va_arg((args),type)
57 # define SDCC_SNPRINTF sdcc_snprintf
59 # define VA_ARG_CHAR char
60 # define VA_ARG(args,type) va_arg((args),type)
61 # define SDCC_SNPRINTF snprintf
65 * snprintf is a bound version of the popular sprintf() function.
66 * The purpose of snprintf is to format just like sprintf(), but
67 * to make sure that memory is never accidentally overwritten by
70 * A stripped down version of snprintf for the pic16 platform of the
71 * sdcc project. Depending on the compile flags set/unset above this
72 * function varies in size from ~16k down to ~5. Below is the
75 * SUPPORT_CHAR_C - c format - ~0.5k of program space required
76 * SUPPORT_STRING - s format - ~1.6k of program space required
78 * I don't think I have any type of optimization on when I did these
79 * measurements. They were taken with a snapshot build of sdcc from
80 * January 22, 2005 (end of day).
82 * Supported formatting:
83 * %%, %c, %[ 0][1-9][0-9]*s
85 * \-- optional padding value
87 * For more detail on what this formatting means, google 'man printf'
90 * ----------------------------------------------------------------------
91 * char *buffer -- the buffer to write into (assumed to
93 * const unsigned char size -- the maximum number of bytes to write
95 * const char *format -- the printf style formatter string (see
96 * above for supported formats.
99 * ----------------------------------------------------------------------
100 * The actual number of characters written into the buffer. The count
101 * includes the '\0' located at the end of the string. If there is
102 * not enough room for the entire string, the '\0' value is written in
103 * as the buffer[end - 1] value.
106 #ifndef __SDCC_pdk14 // Lack of memory
107 #if !(defined (__SDCC_pdk15) && defined(__SDCC_STACK_AUTO)) // Lack of code memory
108 unsigned char SDCC_SNPRINTF( char *buffer
, const unsigned char size
,
109 const char *format
, ... )
112 char *start
= buffer
;
113 char *end
= &buffer
[size
];
115 va_start( args
, format
);
117 while( (buffer
< end
) && ('\0' != *format
) ) {
118 if( '%' == *format
) {
121 #ifdef SUPPORT_CHAR_C
123 *buffer
= VA_ARG( args
, VA_ARG_CHAR
);
126 #endif /* SUPPORT_CHAR_C */
138 /* Determine the padding */
147 /* Determine how many digits to display */
148 while( ('\0' != *format
)
149 && ((*format
>= '0') && (*format
<= '9')) )
151 digits
= digits
* 10 + (*format
- '0');
161 val
= VA_ARG( args
, char * );
164 /* Find the end of the string. */
165 while( '\0' != *val_end
) { val_end
++; }
167 length
= val_end
- val
;
169 /* Optionally crop the output string */
170 if( (digits
> 0) && (length
> digits
) ) {
175 while( (digits
> length
) && (buffer
< end
) ) {
182 while( (length
> 0) && (buffer
< end
) ) {
216 return (buffer
- start
);
223 #ifndef __SDCC_pdk14 // Lack of memory
224 #if !(defined (__SDCC_pdk15) && defined(__SDCC_STACK_AUTO)) // Lack of code memory
229 for( i
= 0; i
< 31; i
++ ) {
234 ret
= SDCC_SNPRINTF( buffer
, 32, "->|%%|<-" );
235 // printf( "->|%s|<- %d \n", buffer, ret );
236 ASSERT (strcmp(buffer
, "->|%|<-") == 0);
238 ret
= SDCC_SNPRINTF( buffer
, 32, "%s, %s.", "Hello", "world" );
239 // printf( "->|%s|<- %d \n", buffer, ret );
240 ASSERT (strcmp(buffer
, "Hello, world.") == 0);
242 ret
= SDCC_SNPRINTF( buffer
, 32, "% 10s, % 10s.", "Hello", "world" );
243 // printf( "->|%s|<- %d \n", buffer, ret );
244 ASSERT (strcmp(buffer
, " Hello, world.") == 0);
246 ret
= SDCC_SNPRINTF( buffer
, 32, "% 3s, % 3s.", "Hello", "world" );
247 // printf( "->|%s|<- %d \n", buffer, ret );
248 ASSERT (strcmp(buffer
, "Hel, wor.") == 0);
250 ret
= SDCC_SNPRINTF( buffer
, 32, "%03s, %03s.", "Hello", "world" );
251 // printf( "->|%s|<- %d \n", buffer, ret );
252 ASSERT (strcmp(buffer
, "Hel, wor.") == 0);
254 ret
= SDCC_SNPRINTF( buffer
, 10, "%s", "Hello, world" );
255 // printf( "->|%s|<- %d \n", buffer, ret );
256 ASSERT (strcmp(buffer
, "Hello, wo") == 0);
263 extern void _putchar(char c
);