struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / support / regression / tests / bug1115321.c
blob7741caedcde258898d2d8d686ff1e75fc88d6f3e
1 /*
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
19 #include <testfwk.h>
20 #include <stdarg.h>
21 #include <string.h>
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"
43 * variables).
45 * I hope this saves you the day it took me to write and debug.
48 #include <stdio.h>
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
58 #else
59 # define VA_ARG_CHAR char
60 # define VA_ARG(args,type) va_arg((args),type)
61 # define SDCC_SNPRINTF snprintf
62 #endif
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
68 * a buffer overrun.
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
73 * breakdown:
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
84 * \
85 * \-- optional padding value
87 * For more detail on what this formatting means, google 'man printf'
89 * Parameters:
90 * ----------------------------------------------------------------------
91 * char *buffer -- the buffer to write into (assumed to
92 * not be NULL)
93 * const unsigned char size -- the maximum number of bytes to write
94 * into the buffer
95 * const char *format -- the printf style formatter string (see
96 * above for supported formats.
98 * Return Values:
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, ... )
111 va_list args;
112 char *start = buffer;
113 char *end = &buffer[size];
115 va_start( args, format );
117 while( (buffer < end) && ('\0' != *format) ) {
118 if( '%' == *format ) {
119 format++;
120 switch( *format ) {
121 #ifdef SUPPORT_CHAR_C
122 case 'c':
123 *buffer = VA_ARG( args, VA_ARG_CHAR );
124 buffer++;
125 break;
126 #endif /* SUPPORT_CHAR_C */
128 case '%':
129 *buffer = '%';
130 buffer++;
131 break;
133 default:
135 char padding = ' ';
136 short digits = 0;
138 /* Determine the padding */
139 switch( *format ) {
140 case '0':
141 padding = '0';
142 case ' ':
143 format++;
144 break;
147 /* Determine how many digits to display */
148 while( ('\0' != *format)
149 && ((*format >= '0') && (*format <= '9')) )
151 digits = digits * 10 + (*format - '0');
152 format++;
155 switch( *format ) {
156 case 's':
158 char *val, *val_end;
159 short length;
161 val = VA_ARG( args, char * );
162 val_end = val;
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) ) {
171 length = digits;
174 /* Add padding */
175 while( (digits > length) && (buffer < end) ) {
176 *buffer = padding;
177 buffer++;
178 digits--;
181 /* Copy string */
182 while( (length > 0) && (buffer < end) ) {
183 *buffer = *val;
184 buffer++;
185 val++;
186 length--;
189 break;
192 default:
193 goto clean_and_bail;
195 break;
198 } else {
199 *buffer = *format;
200 buffer++;
203 format++;
206 clean_and_bail:
207 if( buffer < end ) {
208 *buffer = '\0';
209 buffer++;
210 } else {
211 *(buffer-1) = '\0';
214 va_end( args );
216 return (buffer - start);
218 #endif
219 #endif
221 void test_s( void )
223 #ifndef __SDCC_pdk14 // Lack of memory
224 #if !(defined (__SDCC_pdk15) && defined(__SDCC_STACK_AUTO)) // Lack of code memory
225 char buffer[32];
226 int ret;
227 int i = 0;
229 for( i = 0; i < 31; i++ ) {
230 buffer[i] = 'P';
232 buffer[31] = '\0';
234 ret = SDCC_SNPRINTF( buffer, 32, "->|%%|<-" );
235 // printf( "->|%s|<- %d \n", buffer, ret );
236 ASSERT (strcmp(buffer, "->|%|<-") == 0);
237 ASSERT (ret == 8);
238 ret = SDCC_SNPRINTF( buffer, 32, "%s, %s.", "Hello", "world" );
239 // printf( "->|%s|<- %d \n", buffer, ret );
240 ASSERT (strcmp(buffer, "Hello, world.") == 0);
241 ASSERT (ret == 14);
242 ret = SDCC_SNPRINTF( buffer, 32, "% 10s, % 10s.", "Hello", "world" );
243 // printf( "->|%s|<- %d \n", buffer, ret );
244 ASSERT (strcmp(buffer, " Hello, world.") == 0);
245 ASSERT (ret == 24);
246 ret = SDCC_SNPRINTF( buffer, 32, "% 3s, % 3s.", "Hello", "world" );
247 // printf( "->|%s|<- %d \n", buffer, ret );
248 ASSERT (strcmp(buffer, "Hel, wor.") == 0);
249 ASSERT (ret == 10);
250 ret = SDCC_SNPRINTF( buffer, 32, "%03s, %03s.", "Hello", "world" );
251 // printf( "->|%s|<- %d \n", buffer, ret );
252 ASSERT (strcmp(buffer, "Hel, wor.") == 0);
253 ASSERT (ret == 10);
254 ret = SDCC_SNPRINTF( buffer, 10, "%s", "Hello, world" );
255 // printf( "->|%s|<- %d \n", buffer, ret );
256 ASSERT (strcmp(buffer, "Hello, wo") == 0);
257 ASSERT (ret == 10);
258 #endif
259 #endif
262 #if defined SDCC
263 extern void _putchar(char c);
265 int putchar(int c)
267 _putchar(c);
268 return(c);
270 #endif