blob: ccb64fd67833a2f48d2d452c1c51941281f46d82 [file] [log] [blame]
Uwe Hermannc52761b2008-03-20 00:02:07 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * It has originally been taken from the HelenOS project
5 * (http://www.helenos.eu), and slightly modified for our purposes.
6 *
7 * Copyright (C) 2001-2004 Jakub Jermar
8 * Copyright (C) 2006 Josef Cejka
9 * Copyright (C) 2008 Uwe Hermann <uwe@hermann-uwe.de>
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * - Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * - Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * - The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include <libpayload.h>
Patrick Georgi980a69b2010-06-24 11:16:10 +000037#include <ctype.h>
Uwe Hermannc52761b2008-03-20 00:02:07 +000038
Patrick Georgic977c7d2011-02-24 07:18:11 +000039static struct _FILE {
40} _stdout, _stdin, _stderr;
41
42FILE *stdout = &_stdout;
43FILE *stdin = &_stdin;
44FILE *stderr = &_stderr;
45
Uwe Hermannc52761b2008-03-20 00:02:07 +000046/** Structure for specifying output methods for different printf clones. */
47struct printf_spec {
48 /* Output function, returns count of printed characters or EOF. */
Mathias Krause6efbebd2012-04-03 21:02:33 +020049 int (*write) (const char *, size_t, void *);
Uwe Hermannc52761b2008-03-20 00:02:07 +000050 /* Support data - output stream specification, its state, locks, ... */
51 void *data;
52};
53
54/** Show prefixes 0x or 0. */
55#define __PRINTF_FLAG_PREFIX 0x00000001
56/** Signed / unsigned number. */
57#define __PRINTF_FLAG_SIGNED 0x00000002
58/** Print leading zeroes. */
59#define __PRINTF_FLAG_ZEROPADDED 0x00000004
60/** Align to left. */
61#define __PRINTF_FLAG_LEFTALIGNED 0x00000010
62/** Always show + sign. */
63#define __PRINTF_FLAG_SHOWPLUS 0x00000020
64/** Print space instead of plus. */
65#define __PRINTF_FLAG_SPACESIGN 0x00000040
66/** Show big characters. */
67#define __PRINTF_FLAG_BIGCHARS 0x00000080
68/** Number has - sign. */
69#define __PRINTF_FLAG_NEGATIVE 0x00000100
70
71/**
72 * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
73 * to terminate string (last one is only for better testing end of buffer by
74 * zero-filling subroutine).
75 */
76#define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
77
78/** Enumeration of possible arguments types. */
79typedef enum {
80 PrintfQualifierByte = 0,
81 PrintfQualifierShort,
82 PrintfQualifierInt,
83 PrintfQualifierLong,
84 PrintfQualifierLongLong,
85 PrintfQualifierPointer,
86} qualifier_t;
87
Mathias Krause67997d32012-04-03 20:42:01 +020088static const char digits_small[] = "0123456789abcdef";
89static const char digits_big[] = "0123456789ABCDEF";
Uwe Hermannc52761b2008-03-20 00:02:07 +000090
91/**
92 * Print one or more characters without adding newline.
93 *
94 * @param buf Buffer of >= count bytesi size. NULL pointer is not allowed!
95 * @param count Number of characters to print.
96 * @param ps Output method and its data.
97 * @return Number of characters printed.
98 */
99static int printf_putnchars(const char *buf, size_t count,
100 struct printf_spec *ps)
101{
Mathias Krause6efbebd2012-04-03 21:02:33 +0200102 return ps->write(buf, count, ps->data);
Uwe Hermannc52761b2008-03-20 00:02:07 +0000103}
104
105/**
106 * Print a string without adding a newline.
107 *
108 * @param str String to print.
109 * @param ps Write function specification and support data.
110 * @return Number of characters printed.
111 */
Mathias Krause67997d32012-04-03 20:42:01 +0200112static inline int printf_putstr(const char *str, struct printf_spec *ps)
Uwe Hermannc52761b2008-03-20 00:02:07 +0000113{
Mathias Krause67997d32012-04-03 20:42:01 +0200114 return printf_putnchars(str, strlen(str), ps);
Uwe Hermannc52761b2008-03-20 00:02:07 +0000115}
116
117/**
118 * Print one character.
119 *
120 * @param c Character to be printed.
121 * @param ps Output method.
122 * @return Number of characters printed.
123 */
124static int printf_putchar(int c, struct printf_spec *ps)
125{
Mathias Krause6efbebd2012-04-03 21:02:33 +0200126 char ch = c;
Uwe Hermannc52761b2008-03-20 00:02:07 +0000127
Mathias Krause6efbebd2012-04-03 21:02:33 +0200128 return ps->write(&ch, 1, ps->data);
Uwe Hermannc52761b2008-03-20 00:02:07 +0000129}
130
131/**
132 * Print one formatted character.
133 *
134 * @param c Character to print.
135 * @param width Width modifier.
136 * @param flags Flags that change the way the character is printed.
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000137 * @param ps Output methods spec for different printf clones.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000138 * @return Number of characters printed, negative value on failure.
139 */
140static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
141{
142 int counter = 0;
143
144 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
145 while (--width > 0) {
146 if (printf_putchar(' ', ps) > 0)
147 ++counter;
148 }
149 }
150
151 if (printf_putchar(c, ps) > 0)
152 counter++;
153
154 while (--width > 0) {
155 if (printf_putchar(' ', ps) > 0)
156 ++counter;
157 }
158
Jordan Croused772e1e2008-04-25 23:10:23 +0000159 return counter;
Uwe Hermannc52761b2008-03-20 00:02:07 +0000160}
161
162/**
163 * Print string.
164 *
165 * @param s String to be printed.
166 * @param width Width modifier.
167 * @param precision Precision modifier.
168 * @param flags Flags that modify the way the string is printed.
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000169 * @param ps Output methods spec for different printf clones.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000170 * @return Number of characters printed, negative value on failure.
171 */
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000172/** Structure for specifying output methods for different printf clones. */
Uwe Hermannc52761b2008-03-20 00:02:07 +0000173static int print_string(char *s, int width, unsigned int precision,
174 uint64_t flags, struct printf_spec *ps)
175{
176 int counter = 0, retval;
177 size_t size;
178
179 if (s == NULL)
180 return printf_putstr("(NULL)", ps);
181 size = strlen(s);
182 /* Print leading spaces. */
183 if (precision == 0)
184 precision = size;
185 width -= precision;
186
187 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
188 while (width-- > 0) {
189 if (printf_putchar(' ', ps) == 1)
190 counter++;
191 }
192 }
193
194 if ((retval = printf_putnchars(s, MIN(size, precision), ps)) < 0)
195 return -counter;
196 counter += retval;
197
198 while (width-- > 0) {
199 if (printf_putchar(' ', ps) == 1)
200 ++counter;
201 }
202
203 return counter;
204}
205
206/**
207 * Print a number in a given base.
208 *
209 * Print significant digits of a number in given base.
210 *
211 * @param num Number to print.
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000212 * @param width Width modifier.h
Uwe Hermannc52761b2008-03-20 00:02:07 +0000213 * @param precision Precision modifier.
214 * @param base Base to print the number in (must be between 2 and 16).
215 * @param flags Flags that modify the way the number is printed.
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000216 * @param ps Output methods spec for different printf clones.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000217 * @return Number of characters printed.
218 */
219static int print_number(uint64_t num, int width, int precision, int base,
220 uint64_t flags, struct printf_spec *ps)
221{
Mathias Krause67997d32012-04-03 20:42:01 +0200222 const char *digits = digits_small;
Uwe Hermannc52761b2008-03-20 00:02:07 +0000223 char d[PRINT_NUMBER_BUFFER_SIZE];
224 char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
225 int size = 0; /* Size of number with all prefixes and signs. */
226 int number_size; /* Size of plain number. */
227 char sgn;
228 int retval;
229 int counter = 0;
230
231 if (flags & __PRINTF_FLAG_BIGCHARS)
232 digits = digits_big;
233
234 *ptr-- = 0; /* Put zero at end of string. */
235
236 if (num == 0) {
237 *ptr-- = '0';
238 size++;
239 } else {
240 do {
241 *ptr-- = digits[num % base];
242 size++;
243 } while (num /= base);
244 }
245
246 number_size = size;
247
248 /*
249 * Collect the sum of all prefixes/signs/... to calculate padding and
250 * leading zeroes.
251 */
252 if (flags & __PRINTF_FLAG_PREFIX) {
253 switch (base) {
254 case 2: /* Binary formating is not standard, but useful. */
255 size += 2;
256 break;
257 case 8:
258 size++;
259 break;
260 case 16:
261 size += 2;
262 break;
263 }
264 }
265
266 sgn = 0;
267 if (flags & __PRINTF_FLAG_SIGNED) {
268 if (flags & __PRINTF_FLAG_NEGATIVE) {
269 sgn = '-';
270 size++;
271 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
272 sgn = '+';
273 size++;
274 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
275 sgn = ' ';
276 size++;
277 }
278 }
279
280 if (flags & __PRINTF_FLAG_LEFTALIGNED)
281 flags &= ~__PRINTF_FLAG_ZEROPADDED;
282
283 /*
Uwe Hermann661e3802008-03-21 18:37:23 +0000284 * If the number is left-aligned or precision is specified then
285 * zero-padding is ignored.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000286 */
287 if (flags & __PRINTF_FLAG_ZEROPADDED) {
288 if ((precision == 0) && (width > size))
289 precision = width - size + number_size;
290 }
291
292 /* Print leading spaces. */
293 if (number_size > precision) {
294 /* Print the whole number not only a part. */
295 precision = number_size;
296 }
297
298 width -= precision + size - number_size;
299
300 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
301 while (width-- > 0) {
302 if (printf_putchar(' ', ps) == 1)
303 counter++;
304 }
305 }
306
307 /* Print sign. */
308 if (sgn) {
309 if (printf_putchar(sgn, ps) == 1)
310 counter++;
311 }
312
313 /* Print prefix. */
314 if (flags & __PRINTF_FLAG_PREFIX) {
315 switch (base) {
316 case 2: /* Binary formating is not standard, but useful. */
317 if (printf_putchar('0', ps) == 1)
318 counter++;
319 if (flags & __PRINTF_FLAG_BIGCHARS) {
320 if (printf_putchar('B', ps) == 1)
321 counter++;
322 } else {
323 if (printf_putchar('b', ps) == 1)
324 counter++;
325 }
326 break;
327 case 8:
328 if (printf_putchar('o', ps) == 1)
329 counter++;
330 break;
331 case 16:
332 if (printf_putchar('0', ps) == 1)
333 counter++;
334 if (flags & __PRINTF_FLAG_BIGCHARS) {
335 if (printf_putchar('X', ps) == 1)
336 counter++;
337 } else {
338 if (printf_putchar('x', ps) == 1)
339 counter++;
340 }
341 break;
342 }
343 }
344
345 /* Print leading zeroes. */
346 precision -= number_size;
347 while (precision-- > 0) {
348 if (printf_putchar('0', ps) == 1)
349 counter++;
350 }
351
352 /* Print number itself. */
353 if ((retval = printf_putstr(++ptr, ps)) > 0)
354 counter += retval;
355
356 /* Print ending spaces. */
357 while (width-- > 0) {
358 if (printf_putchar(' ', ps) == 1)
359 counter++;
360 }
361
362 return counter;
363}
364
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000365/**
366 * Print formatted string.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000367 *
368 * Print string formatted according to the fmt parameter and variadic arguments.
369 * Each formatting directive must have the following form:
Stefan Reinauer14e22772010-04-27 06:56:47 +0000370 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000371 * \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
372 *
373 * FLAGS:@n
374 * - "#" Force to print prefix.For \%o conversion, the prefix is 0, for
375 * \%x and \%X prefixes are 0x and 0X and for conversion \%b the
376 * prefix is 0b.
377 *
378 * - "-" Align to left.
379 *
380 * - "+" Print positive sign just as negative.
381 *
382 * - " " If the printed number is positive and "+" flag is not set,
383 * print space in place of sign.
384 *
385 * - "0" Print 0 as padding instead of spaces. Zeroes are placed between
386 * sign and the rest of the number. This flag is ignored if "-"
387 * flag is specified.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000388 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000389 * WIDTH:@n
390 * - Specify the minimal width of a printed argument. If it is bigger,
391 * width is ignored. If width is specified with a "*" character instead of
392 * number, width is taken from parameter list. And integer parameter is
393 * expected before parameter for processed conversion specification. If
394 * this value is negative its absolute value is taken and the "-" flag is
395 * set.
396 *
397 * PRECISION:@n
398 * - Value precision. For numbers it specifies minimum valid numbers.
399 * Smaller numbers are printed with leading zeroes. Bigger numbers are not
400 * affected. Strings with more than precision characters are cut off. Just
401 * as with width, an "*" can be used used instead of a number. An integer
402 * value is then expected in parameters. When both width and precision are
403 * specified using "*", the first parameter is used for width and the
404 * second one for precision.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000405 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000406 * TYPE:@n
407 * - "hh" Signed or unsigned char.@n
408 * - "h" Signed or unsigned short.@n
409 * - "" Signed or unsigned int (default value).@n
410 * - "l" Signed or unsigned long int.@n
411 * - "ll" Signed or unsigned long long int.@n
Stefan Reinauer14e22772010-04-27 06:56:47 +0000412 *
413 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000414 * CONVERSION:@n
415 * - % Print percentile character itself.
416 *
417 * - c Print single character.
418 *
419 * - s Print zero terminated string. If a NULL value is passed as
420 * value, "(NULL)" is printed instead.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000421 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000422 * - P, p Print value of a pointer. Void * value is expected and it is
423 * printed in hexadecimal notation with prefix (as with \%#X / \%#x
424 * for 32-bit or \%#X / \%#x for 64-bit long pointers).
425 *
426 * - b Print value as unsigned binary number. Prefix is not printed by
427 * default. (Nonstandard extension.)
Stefan Reinauer14e22772010-04-27 06:56:47 +0000428 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000429 * - o Print value as unsigned octal number. Prefix is not printed by
Stefan Reinauer14e22772010-04-27 06:56:47 +0000430 * default.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000431 *
432 * - d, i Print signed decimal number. There is no difference between d
433 * and i conversion.
434 *
435 * - u Print unsigned decimal number.
436 *
437 * - X, x Print hexadecimal number with upper- or lower-case. Prefix is
438 * not printed by default.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000439 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000440 * All other characters from fmt except the formatting directives are printed in
441 * verbatim.
442 *
443 * @param fmt Formatting NULL terminated string.
444 * @param ps TODO.
445 * @param ap TODO.
446 * @return Number of characters printed, negative value on failure.
447 */
448static int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
449{
450 int i = 0; /* Index of the currently processed char from fmt */
451 int j = 0; /* Index to the first not printed nonformating character */
452 int end;
453 int counter; /* Counter of printed characters */
454 int retval; /* Used to store return values from called functions */
455 char c;
456 qualifier_t qualifier; /* Type of argument */
457 int base; /* Base in which a numeric parameter will be printed */
458 uint64_t number; /* Argument value */
459 size_t size; /* Byte size of integer parameter */
460 int width, precision;
461 uint64_t flags;
462
463 counter = 0;
464
465 while ((c = fmt[i])) {
466 /* Control character. */
467 if (c == '%') {
468 /* Print common characters if any processed. */
469 if (i > j) {
470 if ((retval = printf_putnchars(&fmt[j],
471 (size_t) (i - j), ps)) < 0) {
472 counter = -counter;
473 goto out; /* Error */
474 }
475 counter += retval;
476 }
477
478 j = i;
479 /* Parse modifiers. */
480 flags = 0;
481 end = 0;
482
483 do {
484 ++i;
485 switch (c = fmt[i]) {
486 case '#':
487 flags |= __PRINTF_FLAG_PREFIX;
488 break;
489 case '-':
490 flags |= __PRINTF_FLAG_LEFTALIGNED;
491 break;
492 case '+':
493 flags |= __PRINTF_FLAG_SHOWPLUS;
494 break;
495 case ' ':
496 flags |= __PRINTF_FLAG_SPACESIGN;
497 break;
498 case '0':
499 flags |= __PRINTF_FLAG_ZEROPADDED;
500 break;
501 default:
502 end = 1;
503 };
504
505 } while (end == 0);
506
507 /* Width & '*' operator. */
508 width = 0;
509 if (isdigit(fmt[i])) {
510 while (isdigit(fmt[i])) {
511 width *= 10;
512 width += fmt[i++] - '0';
513 }
514 } else if (fmt[i] == '*') {
515 /* Get width value from argument list. */
516 i++;
517 width = (int)va_arg(ap, int);
518 if (width < 0) {
519 /* Negative width sets '-' flag. */
520 width *= -1;
521 flags |= __PRINTF_FLAG_LEFTALIGNED;
522 }
523 }
524
525 /* Precision and '*' operator. */
526 precision = 0;
527 if (fmt[i] == '.') {
528 ++i;
529 if (isdigit(fmt[i])) {
530 while (isdigit(fmt[i])) {
531 precision *= 10;
532 precision += fmt[i++] - '0';
533 }
534 } else if (fmt[i] == '*') {
535 /* Get precision from argument list. */
536 i++;
537 precision = (int)va_arg(ap, int);
538 /* Ignore negative precision. */
539 if (precision < 0)
540 precision = 0;
541 }
542 }
543
544 switch (fmt[i++]) {
545 /** @todo unimplemented qualifiers:
546 * t ptrdiff_t - ISO C 99
547 */
548 case 'h': /* char or short */
549 qualifier = PrintfQualifierShort;
550 if (fmt[i] == 'h') {
551 i++;
552 qualifier = PrintfQualifierByte;
553 }
554 break;
555 case 'l': /* long or long long */
556 qualifier = PrintfQualifierLong;
557 if (fmt[i] == 'l') {
558 i++;
559 qualifier = PrintfQualifierLongLong;
560 }
561 break;
562 default:
563 /* default type */
564 qualifier = PrintfQualifierInt;
565 --i;
566 }
567
568 base = 10;
569
570 switch (c = fmt[i]) {
571 /* String and character conversions */
572 case 's':
573 if ((retval = print_string(va_arg(ap, char *),
574 width, precision, flags, ps)) < 0) {
575 counter = -counter;
576 goto out;
577 };
578 counter += retval;
579 j = i + 1;
580 goto next_char;
581 case 'c':
582 c = va_arg(ap, unsigned int);
583 retval = print_char(c, width, flags, ps);
584 if (retval < 0) {
585 counter = -counter;
586 goto out;
587 };
588 counter += retval;
589 j = i + 1;
590 goto next_char;
591
592 /* Integer values */
593 case 'P': /* pointer */
594 flags |= __PRINTF_FLAG_BIGCHARS;
595 case 'p':
596 flags |= __PRINTF_FLAG_PREFIX;
597 base = 16;
598 qualifier = PrintfQualifierPointer;
599 break;
600 case 'b':
601 base = 2;
602 break;
603 case 'o':
604 base = 8;
605 break;
606 case 'd':
607 case 'i':
608 flags |= __PRINTF_FLAG_SIGNED;
609 case 'u':
610 break;
611 case 'X':
612 flags |= __PRINTF_FLAG_BIGCHARS;
613 case 'x':
614 base = 16;
615 break;
616 case '%': /* percentile itself */
617 j = i;
618 goto next_char;
619 default: /* Bad formatting */
620 /*
621 * Unknown format. Now, j is the index of '%'
622 * so we will print whole bad format sequence.
623 */
624 goto next_char;
625 }
626
627 /* Print integers. */
628 /* Print number. */
629 switch (qualifier) {
630 case PrintfQualifierByte:
631 size = sizeof(unsigned char);
632 number = (uint64_t) va_arg(ap, unsigned int);
633 break;
634 case PrintfQualifierShort:
635 size = sizeof(unsigned short);
636 number = (uint64_t) va_arg(ap, unsigned int);
637 break;
638 case PrintfQualifierInt:
639 size = sizeof(unsigned int);
640 number = (uint64_t) va_arg(ap, unsigned int);
641 break;
642 case PrintfQualifierLong:
643 size = sizeof(unsigned long);
644 number = (uint64_t) va_arg(ap, unsigned long);
645 break;
646 case PrintfQualifierLongLong:
647 size = sizeof(unsigned long long);
648 number = (uint64_t) va_arg(ap, unsigned long long);
649 break;
650 case PrintfQualifierPointer:
651 size = sizeof(void *);
652 number = (uint64_t) (unsigned long)va_arg(ap, void *);
653 break;
654 default: /* Unknown qualifier */
655 counter = -counter;
656 goto out;
657 }
658
659 if (flags & __PRINTF_FLAG_SIGNED) {
660 if (number & (0x1 << (size * 8 - 1))) {
661 flags |= __PRINTF_FLAG_NEGATIVE;
662
663 if (size == sizeof(uint64_t)) {
664 number = -((int64_t) number);
665 } else {
666 number = ~number;
667 number &= ~(0xFFFFFFFFFFFFFFFFll << (size * 8));
668 number++;
669 }
670 }
671 }
672
673 if ((retval = print_number(number, width, precision,
674 base, flags, ps)) < 0) {
675 counter = -counter;
676 goto out;
677 }
678
679 counter += retval;
680 j = i + 1;
681 }
682next_char:
683 ++i;
684 }
685
686 if (i > j) {
687 if ((retval = printf_putnchars(&fmt[j],
688 (u64) (i - j), ps)) < 0) {
689 counter = -counter;
690 goto out; /* Error */
691
692 }
693 counter += retval;
694 }
695
696out:
697 return counter;
698}
699
Uwe Hermann0a896252008-04-02 12:35:45 +0000700int snprintf(char *str, size_t size, const char *fmt, ...)
701{
702 int ret;
703 va_list args;
704
705 va_start(args, fmt);
706 ret = vsnprintf(str, size, fmt, args);
707 va_end(args);
708
709 return ret;
710}
711
Uwe Hermannc52761b2008-03-20 00:02:07 +0000712int sprintf(char *str, const char *fmt, ...)
713{
714 int ret;
715 va_list args;
716
717 va_start(args, fmt);
718 ret = vsprintf(str, fmt, args);
719 va_end(args);
720
721 return ret;
722}
723
Patrick Georgicd913bd2011-02-14 19:25:27 +0000724int fprintf(FILE *file, const char *fmt, ...)
725{
726 int ret;
727 if ((file == stdout) || (file == stderr)) {
728 va_list args;
729 va_start(args, fmt);
730 ret = vprintf(fmt, args);
731 va_end(args);
732
733 return ret;
734 }
735 return -1;
736}
737
Uwe Hermannc52761b2008-03-20 00:02:07 +0000738struct vsnprintf_data {
739 size_t size; /* Total space for string */
740 size_t len; /* Count of currently used characters */
741 char *string; /* Destination string */
742};
743
744/**
745 * Write string to given buffer.
746 *
747 * Write at most data->size characters including trailing zero. According to
748 * C99, snprintf() has to return number of characters that would have been
749 * written if enough space had been available. Hence the return value is not
750 * number of really printed characters but size of the input string.
751 * Number of really used characters is stored in data->len.
752 *
753 * @param str Source string to print.
754 * @param count Size of source string.
Mathias Krause6efbebd2012-04-03 21:02:33 +0200755 * @param _data Structure with destination string, counter of used space
Uwe Hermannc52761b2008-03-20 00:02:07 +0000756 * and total string size.
757 * @return Number of characters to print (not characters really printed!).
758 */
Mathias Krause6efbebd2012-04-03 21:02:33 +0200759static int vsnprintf_write(const char *str, size_t count, void *_data)
Uwe Hermannc52761b2008-03-20 00:02:07 +0000760{
Mathias Krause6efbebd2012-04-03 21:02:33 +0200761 struct vsnprintf_data *data = _data;
Uwe Hermannc52761b2008-03-20 00:02:07 +0000762 size_t i;
763
764 i = data->size - data->len;
765 if (i == 0)
766 return count;
767
768 /* We have only one free byte left in buffer => write trailing zero. */
769 if (i == 1) {
770 data->string[data->size - 1] = 0;
771 data->len = data->size;
772 return count;
773 }
774
775 /*
776 * We have not enough space for whole string with the trailing
777 * zero => print only a part of string.
778 */
779 if (i <= count) {
780 memcpy((void *)(data->string + data->len), (void *)str, i - 1);
781 data->string[data->size - 1] = 0;
782 data->len = data->size;
783 return count;
784 }
785
786 /* Buffer is big enough to print whole string. */
787 memcpy((void *)(data->string + data->len), (void *)str, count);
788 data->len += count;
789 /*
790 * Put trailing zero at end, but not count it into data->len so
791 * it could be rewritten next time.
792 */
793 data->string[data->len] = 0;
794
795 return count;
796}
797
798int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
799{
800 struct vsnprintf_data data = { size, 0, str };
Mathias Krause6efbebd2012-04-03 21:02:33 +0200801 struct printf_spec ps = { vsnprintf_write, &data };
Uwe Hermannc52761b2008-03-20 00:02:07 +0000802
803 /* Print 0 at end of string - fix case that nothing will be printed. */
804 if (size > 0)
805 str[0] = 0;
806
807 /* vsnprintf_write() ensures that str will be terminated by zero. */
808 return printf_core(fmt, &ps, ap);
809}
810
811int vsprintf(char *str, const char *fmt, va_list ap)
812{
813 return vsnprintf(str, (size_t) - 1, fmt, ap);
814}
815
816int printf(const char *fmt, ...)
817{
818 int ret;
819 va_list args;
820
821 va_start(args, fmt);
822 ret = vprintf(fmt, args);
823 va_end(args);
824
825 return ret;
826}
827
828static int vprintf_write(const char *str, size_t count, void *unused)
829{
830 size_t i;
831
832 for (i = 0; i < count; i++)
833 putchar(str[i]);
834
835 return i;
836}
837
838int vprintf(const char *fmt, va_list ap)
839{
Mathias Krause6efbebd2012-04-03 21:02:33 +0200840 struct printf_spec ps = { vprintf_write, NULL };
Uwe Hermannc52761b2008-03-20 00:02:07 +0000841
842 return printf_core(fmt, &ps, ap);
843}