blob: 32bd617e86d72f928cf2108eba8f76cfaa0772b1 [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).
Harald Welteee9ebb32017-03-02 16:52:08 +010057#define MAX_STRING_SIZE 512
Harald Welted09829d2017-02-27 22:58:59 +010058
59//------------------------------------------------------------------------------
60// Global Variables
61//------------------------------------------------------------------------------
Harald Weltec430ac12017-02-28 01:25:12 +010062//
63FILE* const stdin = NULL;
64FILE* const stdout = NULL;
65FILE* const stderr = NULL;
Harald Welted09829d2017-02-27 22:58:59 +010066
Harald Welted09829d2017-02-27 22:58:59 +010067
68//------------------------------------------------------------------------------
69// Local Functions
70//------------------------------------------------------------------------------
71
72//------------------------------------------------------------------------------
73// Writes a character inside the given string. Returns 1.
74// \param pStr Storage string.
75// \param c Character to write.
76//------------------------------------------------------------------------------
77signed int PutChar(char *pStr, char c)
78{
79 *pStr = c;
80 return 1;
81}
82
83//------------------------------------------------------------------------------
84// Writes a string inside the given string.
85// Returns the size of the written
86// string.
87// \param pStr Storage string.
88// \param pSource Source string.
89//------------------------------------------------------------------------------
90signed int PutString(char *pStr, const char *pSource)
91{
92 signed int num = 0;
93
94 while (*pSource != 0) {
95
96 *pStr++ = *pSource++;
97 num++;
98 }
99
100 return num;
101}
102
103//------------------------------------------------------------------------------
104// Writes an unsigned int inside the given string, using the provided fill &
105// width parameters.
106// Returns the size in characters of the written integer.
107// \param pStr Storage string.
108// \param fill Fill character.
109// \param width Minimum integer width.
110// \param value Integer value.
111//------------------------------------------------------------------------------
112signed int PutUnsignedInt(
113 char *pStr,
114 char fill,
115 signed int width,
116 unsigned int value)
117{
118 signed int num = 0;
119
120 // Take current digit into account when calculating width
121 width--;
122
123 // Recursively write upper digits
124 if ((value / 10) > 0) {
125
126 num = PutUnsignedInt(pStr, fill, width, value / 10);
127 pStr += num;
128 }
129 // Write filler characters
130 else {
131
132 while (width > 0) {
133
134 PutChar(pStr, fill);
135 pStr++;
136 num++;
137 width--;
138 }
139 }
140
141 // Write lower digit
142 num += PutChar(pStr, (value % 10) + '0');
143
144 return num;
145}
146
147//------------------------------------------------------------------------------
148// Writes a signed int inside the given string, using the provided fill & width
149// parameters.
150// Returns the size of the written integer.
151// \param pStr Storage string.
152// \param fill Fill character.
153// \param width Minimum integer width.
154// \param value Signed integer value.
155//------------------------------------------------------------------------------
156signed int PutSignedInt(
157 char *pStr,
158 char fill,
159 signed int width,
160 signed int value)
161{
162 signed int num = 0;
163 unsigned int absolute;
164
165 // Compute absolute value
166 if (value < 0) {
167
168 absolute = -value;
169 }
170 else {
171
172 absolute = value;
173 }
174
175 // Take current digit into account when calculating width
176 width--;
177
178 // Recursively write upper digits
179 if ((absolute / 10) > 0) {
180
181 if (value < 0) {
182
183 num = PutSignedInt(pStr, fill, width, -(absolute / 10));
184 }
185 else {
186
187 num = PutSignedInt(pStr, fill, width, absolute / 10);
188 }
189 pStr += num;
190 }
191 else {
192
193 // Reserve space for sign
194 if (value < 0) {
195
196 width--;
197 }
198
199 // Write filler characters
200 while (width > 0) {
201
202 PutChar(pStr, fill);
203 pStr++;
204 num++;
205 width--;
206 }
207
208 // Write sign
209 if (value < 0) {
210
211 num += PutChar(pStr, '-');
212 pStr++;
213 }
214 }
215
216 // Write lower digit
217 num += PutChar(pStr, (absolute % 10) + '0');
218
219 return num;
220}
221
222//------------------------------------------------------------------------------
223// Writes an hexadecimal value into a string, using the given fill, width &
224// capital parameters.
225// Returns the number of char written.
226// \param pStr Storage string.
227// \param fill Fill character.
228// \param width Minimum integer width.
229// \param maj Indicates if the letters must be printed in lower- or upper-case.
230// \param value Hexadecimal value.
231//------------------------------------------------------------------------------
232signed int PutHexa(
233 char *pStr,
234 char fill,
235 signed int width,
236 unsigned char maj,
237 unsigned int value)
238{
239 signed int num = 0;
240
241 // Decrement width
242 width--;
243
244 // Recursively output upper digits
245 if ((value >> 4) > 0) {
246
247 num += PutHexa(pStr, fill, width, maj, value >> 4);
248 pStr += num;
249 }
250 // Write filler chars
251 else {
252
253 while (width > 0) {
254
255 PutChar(pStr, fill);
256 pStr++;
257 num++;
258 width--;
259 }
260 }
261
262 // Write current digit
263 if ((value & 0xF) < 10) {
264
265 PutChar(pStr, (value & 0xF) + '0');
266 }
267 else if (maj) {
268
269 PutChar(pStr, (value & 0xF) - 10 + 'A');
270 }
271 else {
272
273 PutChar(pStr, (value & 0xF) - 10 + 'a');
274 }
275 num++;
276
277 return num;
278}
279
280//------------------------------------------------------------------------------
281// Global Functions
282//------------------------------------------------------------------------------
283
284//------------------------------------------------------------------------------
285/// Stores the result of a formatted string into another string. Format
286/// arguments are given in a va_list instance.
287/// Return the number of characters written.
288/// \param pStr Destination string.
289/// \param length Length of Destination string.
290/// \param pFormat Format string.
291/// \param ap Argument list.
292//------------------------------------------------------------------------------
293signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap)
294{
295 char fill;
296 unsigned char width;
297 signed int num = 0;
Harald Welte96e62a42017-02-27 23:05:15 +0100298 size_t size = 0;
Harald Welted09829d2017-02-27 22:58:59 +0100299
300 // Clear the string
301 if (pStr) {
302
303 *pStr = 0;
304 }
305
306 // Phase string
307 while (*pFormat != 0 && size < length) {
308
309 // Normal character
310 if (*pFormat != '%') {
311
312 *pStr++ = *pFormat++;
313 size++;
314 }
315 // Escaped '%'
316 else if (*(pFormat+1) == '%') {
317
318 *pStr++ = '%';
319 pFormat += 2;
320 size++;
321 }
322 // Token delimiter
323 else {
324
325 fill = ' ';
326 width = 0;
327 pFormat++;
328
329 // Parse filler
330 if (*pFormat == '0') {
331
332 fill = '0';
333 pFormat++;
334 }
335
336 // Parse width
337 while ((*pFormat >= '0') && (*pFormat <= '9')) {
338
339 width = (width*10) + *pFormat-'0';
340 pFormat++;
341 }
342
343 // Check if there is enough space
344 if (size + width > length) {
345
346 width = length - size;
347 }
348
349 // Parse type
350 switch (*pFormat) {
351 case 'd':
352 case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break;
353 case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break;
354 case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break;
355 case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break;
356 case 's': num = PutString(pStr, va_arg(ap, char *)); break;
357 case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break;
358 default:
359 return EOF;
360 }
361
362 pFormat++;
363 pStr += num;
364 size += num;
365 }
366 }
367
368 // NULL-terminated (final \0 is not counted)
369 if (size < length) {
370
371 *pStr = 0;
372 }
373 else {
374
375 *(--pStr) = 0;
376 size--;
377 }
378
379 return size;
380}
381
382//------------------------------------------------------------------------------
383/// Stores the result of a formatted string into another string. Format
384/// arguments are given in a va_list instance.
385/// Return the number of characters written.
386/// \param pString Destination string.
387/// \param length Length of Destination string.
388/// \param pFormat Format string.
389/// \param ... Other arguments
390//------------------------------------------------------------------------------
391signed int snprintf(char *pString, size_t length, const char *pFormat, ...)
392{
393 va_list ap;
394 signed int rc;
395
396 va_start(ap, pFormat);
397 rc = vsnprintf(pString, length, pFormat, ap);
398 va_end(ap);
399
400 return rc;
401}
402
403//------------------------------------------------------------------------------
404/// Stores the result of a formatted string into another string. Format
405/// arguments are given in a va_list instance.
406/// Return the number of characters written.
407/// \param pString Destination string.
408/// \param pFormat Format string.
409/// \param ap Argument list.
410//------------------------------------------------------------------------------
411signed int vsprintf(char *pString, const char *pFormat, va_list ap)
412{
413 return vsnprintf(pString, MAX_STRING_SIZE, pFormat, ap);
414}
415
416//------------------------------------------------------------------------------
417/// Outputs a formatted string on the given stream. Format arguments are given
418/// in a va_list instance.
419/// \param pStream Output stream.
420/// \param pFormat Format string
421/// \param ap Argument list.
422//------------------------------------------------------------------------------
423signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap)
424{
425 char pStr[MAX_STRING_SIZE];
426 char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
427
428 // Write formatted string in buffer
429 if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) {
430
431 fputs(pError, stderr);
Harald Welted09829d2017-02-27 22:58:59 +0100432 }
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