blob: f69e8bd035e0388daf29d122d4e2c10475c2998e [file] [log] [blame]
Harald Welted09829d2017-02-27 22:58:59 +01001/* ----------------------------------------------------------------------------
2 * ATMEL Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2008, Atmel Corporation
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the disclaimer below.
13 *
14 * Atmel's name may not be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * ----------------------------------------------------------------------------
28 */
29
30//------------------------------------------------------------------------------
31/// \unit
32///
33/// !Purpose
34///
35/// Implementation of several stdio.h methods, such as printf(), sprintf() and
36/// so on. This reduces the memory footprint of the binary when using those
37/// methods, compared to the libc implementation.
38///
39/// !Usage
40///
41/// Adds stdio.c to the list of file to compile for the project. This will
42/// automatically replace libc methods by the custom ones.
43//------------------------------------------------------------------------------
44
45//------------------------------------------------------------------------------
46// Headers
47//------------------------------------------------------------------------------
48
49#include <stdio.h>
50#include <stdarg.h>
51
52//------------------------------------------------------------------------------
53// Local Definitions
54//------------------------------------------------------------------------------
55
56// Maximum string size allowed (in bytes).
57#define MAX_STRING_SIZE 100
58
59//------------------------------------------------------------------------------
60// Global Variables
61//------------------------------------------------------------------------------
62
63// Required for proper compilation.
64struct _reent r = {0, (FILE *) 0, (FILE *) 1, (FILE *) 0};
65struct _reent *_impure_ptr = &r;
66
67//------------------------------------------------------------------------------
68// Local Functions
69//------------------------------------------------------------------------------
70
71//------------------------------------------------------------------------------
72// Writes a character inside the given string. Returns 1.
73// \param pStr Storage string.
74// \param c Character to write.
75//------------------------------------------------------------------------------
76signed int PutChar(char *pStr, char c)
77{
78 *pStr = c;
79 return 1;
80}
81
82//------------------------------------------------------------------------------
83// Writes a string inside the given string.
84// Returns the size of the written
85// string.
86// \param pStr Storage string.
87// \param pSource Source string.
88//------------------------------------------------------------------------------
89signed int PutString(char *pStr, const char *pSource)
90{
91 signed int num = 0;
92
93 while (*pSource != 0) {
94
95 *pStr++ = *pSource++;
96 num++;
97 }
98
99 return num;
100}
101
102//------------------------------------------------------------------------------
103// Writes an unsigned int inside the given string, using the provided fill &
104// width parameters.
105// Returns the size in characters of the written integer.
106// \param pStr Storage string.
107// \param fill Fill character.
108// \param width Minimum integer width.
109// \param value Integer value.
110//------------------------------------------------------------------------------
111signed int PutUnsignedInt(
112 char *pStr,
113 char fill,
114 signed int width,
115 unsigned int value)
116{
117 signed int num = 0;
118
119 // Take current digit into account when calculating width
120 width--;
121
122 // Recursively write upper digits
123 if ((value / 10) > 0) {
124
125 num = PutUnsignedInt(pStr, fill, width, value / 10);
126 pStr += num;
127 }
128 // Write filler characters
129 else {
130
131 while (width > 0) {
132
133 PutChar(pStr, fill);
134 pStr++;
135 num++;
136 width--;
137 }
138 }
139
140 // Write lower digit
141 num += PutChar(pStr, (value % 10) + '0');
142
143 return num;
144}
145
146//------------------------------------------------------------------------------
147// Writes a signed int inside the given string, using the provided fill & width
148// parameters.
149// Returns the size of the written integer.
150// \param pStr Storage string.
151// \param fill Fill character.
152// \param width Minimum integer width.
153// \param value Signed integer value.
154//------------------------------------------------------------------------------
155signed int PutSignedInt(
156 char *pStr,
157 char fill,
158 signed int width,
159 signed int value)
160{
161 signed int num = 0;
162 unsigned int absolute;
163
164 // Compute absolute value
165 if (value < 0) {
166
167 absolute = -value;
168 }
169 else {
170
171 absolute = value;
172 }
173
174 // Take current digit into account when calculating width
175 width--;
176
177 // Recursively write upper digits
178 if ((absolute / 10) > 0) {
179
180 if (value < 0) {
181
182 num = PutSignedInt(pStr, fill, width, -(absolute / 10));
183 }
184 else {
185
186 num = PutSignedInt(pStr, fill, width, absolute / 10);
187 }
188 pStr += num;
189 }
190 else {
191
192 // Reserve space for sign
193 if (value < 0) {
194
195 width--;
196 }
197
198 // Write filler characters
199 while (width > 0) {
200
201 PutChar(pStr, fill);
202 pStr++;
203 num++;
204 width--;
205 }
206
207 // Write sign
208 if (value < 0) {
209
210 num += PutChar(pStr, '-');
211 pStr++;
212 }
213 }
214
215 // Write lower digit
216 num += PutChar(pStr, (absolute % 10) + '0');
217
218 return num;
219}
220
221//------------------------------------------------------------------------------
222// Writes an hexadecimal value into a string, using the given fill, width &
223// capital parameters.
224// Returns the number of char written.
225// \param pStr Storage string.
226// \param fill Fill character.
227// \param width Minimum integer width.
228// \param maj Indicates if the letters must be printed in lower- or upper-case.
229// \param value Hexadecimal value.
230//------------------------------------------------------------------------------
231signed int PutHexa(
232 char *pStr,
233 char fill,
234 signed int width,
235 unsigned char maj,
236 unsigned int value)
237{
238 signed int num = 0;
239
240 // Decrement width
241 width--;
242
243 // Recursively output upper digits
244 if ((value >> 4) > 0) {
245
246 num += PutHexa(pStr, fill, width, maj, value >> 4);
247 pStr += num;
248 }
249 // Write filler chars
250 else {
251
252 while (width > 0) {
253
254 PutChar(pStr, fill);
255 pStr++;
256 num++;
257 width--;
258 }
259 }
260
261 // Write current digit
262 if ((value & 0xF) < 10) {
263
264 PutChar(pStr, (value & 0xF) + '0');
265 }
266 else if (maj) {
267
268 PutChar(pStr, (value & 0xF) - 10 + 'A');
269 }
270 else {
271
272 PutChar(pStr, (value & 0xF) - 10 + 'a');
273 }
274 num++;
275
276 return num;
277}
278
279//------------------------------------------------------------------------------
280// Global Functions
281//------------------------------------------------------------------------------
282
283//------------------------------------------------------------------------------
284/// Stores the result of a formatted string into another string. Format
285/// arguments are given in a va_list instance.
286/// Return the number of characters written.
287/// \param pStr Destination string.
288/// \param length Length of Destination string.
289/// \param pFormat Format string.
290/// \param ap Argument list.
291//------------------------------------------------------------------------------
292signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap)
293{
294 char fill;
295 unsigned char width;
296 signed int num = 0;
297 signed int size = 0;
298
299 // Clear the string
300 if (pStr) {
301
302 *pStr = 0;
303 }
304
305 // Phase string
306 while (*pFormat != 0 && size < length) {
307
308 // Normal character
309 if (*pFormat != '%') {
310
311 *pStr++ = *pFormat++;
312 size++;
313 }
314 // Escaped '%'
315 else if (*(pFormat+1) == '%') {
316
317 *pStr++ = '%';
318 pFormat += 2;
319 size++;
320 }
321 // Token delimiter
322 else {
323
324 fill = ' ';
325 width = 0;
326 pFormat++;
327
328 // Parse filler
329 if (*pFormat == '0') {
330
331 fill = '0';
332 pFormat++;
333 }
334
335 // Parse width
336 while ((*pFormat >= '0') && (*pFormat <= '9')) {
337
338 width = (width*10) + *pFormat-'0';
339 pFormat++;
340 }
341
342 // Check if there is enough space
343 if (size + width > length) {
344
345 width = length - size;
346 }
347
348 // Parse type
349 switch (*pFormat) {
350 case 'd':
351 case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break;
352 case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break;
353 case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break;
354 case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break;
355 case 's': num = PutString(pStr, va_arg(ap, char *)); break;
356 case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break;
357 default:
358 return EOF;
359 }
360
361 pFormat++;
362 pStr += num;
363 size += num;
364 }
365 }
366
367 // NULL-terminated (final \0 is not counted)
368 if (size < length) {
369
370 *pStr = 0;
371 }
372 else {
373
374 *(--pStr) = 0;
375 size--;
376 }
377
378 return size;
379}
380
381//------------------------------------------------------------------------------
382/// Stores the result of a formatted string into another string. Format
383/// arguments are given in a va_list instance.
384/// Return the number of characters written.
385/// \param pString Destination string.
386/// \param length Length of Destination string.
387/// \param pFormat Format string.
388/// \param ... Other arguments
389//------------------------------------------------------------------------------
390signed int snprintf(char *pString, size_t length, const char *pFormat, ...)
391{
392 va_list ap;
393 signed int rc;
394
395 va_start(ap, pFormat);
396 rc = vsnprintf(pString, length, pFormat, ap);
397 va_end(ap);
398
399 return rc;
400}
401
402//------------------------------------------------------------------------------
403/// Stores the result of a formatted string into another string. Format
404/// arguments are given in a va_list instance.
405/// Return the number of characters written.
406/// \param pString Destination string.
407/// \param pFormat Format string.
408/// \param ap Argument list.
409//------------------------------------------------------------------------------
410signed int vsprintf(char *pString, const char *pFormat, va_list ap)
411{
412 return vsnprintf(pString, MAX_STRING_SIZE, pFormat, ap);
413}
414
415//------------------------------------------------------------------------------
416/// Outputs a formatted string on the given stream. Format arguments are given
417/// in a va_list instance.
418/// \param pStream Output stream.
419/// \param pFormat Format string
420/// \param ap Argument list.
421//------------------------------------------------------------------------------
422signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap)
423{
424 char pStr[MAX_STRING_SIZE];
425 char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
426
427 // Write formatted string in buffer
428 if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) {
429
430 fputs(pError, stderr);
431 while (1); // Increase MAX_STRING_SIZE
432 }
433
434 // Display string
435 return fputs(pStr, pStream);
436}
437
438//------------------------------------------------------------------------------
439/// Outputs a formatted string on the DBGU stream. Format arguments are given
440/// in a va_list instance.
441/// \param pFormat Format string
442/// \param ap Argument list.
443//------------------------------------------------------------------------------
444signed int vprintf(const char *pFormat, va_list ap)
445{
446 return vfprintf(stdout, pFormat, ap);
447}
448
449//------------------------------------------------------------------------------
450/// Outputs a formatted string on the given stream, using a variable number of
451/// arguments.
452/// \param pStream Output stream.
453/// \param pFormat Format string.
454//------------------------------------------------------------------------------
455signed int fprintf(FILE *pStream, const char *pFormat, ...)
456{
457 va_list ap;
458 signed int result;
459
460 // Forward call to vfprintf
461 va_start(ap, pFormat);
462 result = vfprintf(pStream, pFormat, ap);
463 va_end(ap);
464
465 return result;
466}
467
468//------------------------------------------------------------------------------
469/// Outputs a formatted string on the DBGU stream, using a variable number of
470/// arguments.
471/// \param pFormat Format string.
472//------------------------------------------------------------------------------
473signed int printf(const char *pFormat, ...)
474{
475 va_list ap;
476 signed int result;
477
478 // Forward call to vprintf
479 va_start(ap, pFormat);
480 result = vprintf(pFormat, ap);
481 va_end(ap);
482
483 return result;
484}
485
486//------------------------------------------------------------------------------
487/// Writes a formatted string inside another string.
488/// \param pStr Storage string.
489/// \param pFormat Format string.
490//------------------------------------------------------------------------------
491signed int sprintf(char *pStr, const char *pFormat, ...)
492{
493 va_list ap;
494 signed int result;
495
496 // Forward call to vsprintf
497 va_start(ap, pFormat);
498 result = vsprintf(pStr, pFormat, ap);
499 va_end(ap);
500
501 return result;
502}
503
504//------------------------------------------------------------------------------
505/// Outputs a string on stdout.
506/// \param pStr String to output.
507//------------------------------------------------------------------------------
508signed int puts(const char *pStr)
509{
510 return fputs(pStr, stdout);
511}
512