source: mainline/generic/src/debug/print.c@ 50de918

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 50de918 was 50de918, checked in by Josef Cejka <malyzelenyhnus@…>, 19 years ago

Update comments in printf.

  • Property mode set to 100644
File size: 16.3 KB
Line 
1/*
2 * Copyright (C) 2001-2004 Jakub Jermar
3 * Copyright (C) 2006 Josef Cejka
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <putchar.h>
31#include <print.h>
32#include <synch/spinlock.h>
33#include <arch/arg.h>
34#include <arch/asm.h>
35
36#include <arch.h>
37
38SPINLOCK_INITIALIZE(printflock); /**< printf spinlock */
39
40#define __PRINTF_FLAG_PREFIX 0x00000001 /* show prefixes 0x or 0*/
41#define __PRINTF_FLAG_SIGNED 0x00000002 /* signed / unsigned number */
42#define __PRINTF_FLAG_ZEROPADDED 0x00000004 /* print leading zeroes */
43#define __PRINTF_FLAG_LEFTALIGNED 0x00000010 /* align to left */
44#define __PRINTF_FLAG_SHOWPLUS 0x00000020 /* always show + sign */
45#define __PRINTF_FLAG_SPACESIGN 0x00000040 /* print space instead of plus */
46#define __PRINTF_FLAG_BIGCHARS 0x00000080 /* show big characters */
47#define __PRINTF_FLAG_NEGATIVE 0x00000100 /* number has - sign */
48
49#define PRINT_NUMBER_BUFFER_SIZE (64+5) /* Buffer big enought for 64 bit number
50 * printed in base 2, sign, prefix and
51 * 0 to terminate string.. (last one is only for better testing
52 * end of buffer by zero-filling subroutine)
53 */
54typedef enum {
55 PrintfQualifierByte = 0,
56 PrintfQualifierShort,
57 PrintfQualifierInt,
58 PrintfQualifierLong,
59 PrintfQualifierLongLong,
60 PrintfQualifierNative,
61 PrintfQualifierPointer
62} qualifier_t;
63
64static char digits_small[] = "0123456789abcdef"; /* Small hexadecimal characters */
65static char digits_big[] = "0123456789ABCDEF"; /* Big hexadecimal characters */
66
67static inline int isdigit(int c)
68{
69 return ((c >= '0' )&&( c <= '9'));
70}
71
72static __native strlen(const char *str)
73{
74 __native counter = 0;
75
76 while (str[counter] != 0) {
77 counter++;
78 }
79
80 return counter;
81}
82
83/** Print one string without adding \n at end
84 * Dont use this function directly - printflock is not locked here
85 * */
86static int putstr(const char *str)
87{
88 int count;
89 if (str == NULL) {
90 str = "(NULL)";
91 }
92
93 for (count = 0; str[count] != 0; count++) {
94 putchar(str[count]);
95 }
96 return count;
97}
98
99/** Print count characters from buffer to output
100 *
101 */
102static int putnchars(const char *buffer, __native count)
103{
104 int i;
105 if (buffer == NULL) {
106 buffer = "(NULL)";
107 count = 6;
108 }
109
110 for (i = 0; i < count; i++) {
111 putchar(buffer[i]);
112 }
113
114 return count;
115}
116
117/** Print one formatted character
118 * @param c character to print
119 * @param width
120 * @param flags
121 * @return number of printed characters or EOF
122 */
123static int print_char(char c, int width, __u64 flags)
124{
125 int counter = 0;
126
127 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
128 while (--width > 0) { /* one space is consumed by character itself hence predecrement */
129 /* FIXME: painful slow */
130 putchar(' ');
131 ++counter;
132 }
133 }
134
135 putchar(c);
136 ++counter;
137
138 while (--width > 0) { /* one space is consumed by character itself hence predecrement */
139 putchar(' ');
140 ++counter;
141 }
142
143 return counter;
144}
145
146/** Print one string
147 * @param s string
148 * @param width
149 * @param precision
150 * @param flags
151 * @return number of printed characters or EOF
152 */
153
154static int print_string(char *s, int width, int precision, __u64 flags)
155{
156 int counter = 0;
157 __native size;
158
159 if (s == NULL) {
160 return putstr("(NULL)");
161 }
162
163 size = strlen(s);
164
165 /* print leading spaces */
166
167 if (precision == 0)
168 precision = size;
169
170 width -= precision;
171
172 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
173 while (width-- > 0) {
174 putchar(' ');
175 counter++;
176 }
177 }
178
179 while (precision > size) {
180 precision--;
181 putchar(' ');
182 ++counter;
183 }
184
185 if (putnchars(s, precision) == EOF) {
186 return EOF;
187 }
188
189 counter += precision;
190
191 while (width-- > 0) {
192 putchar(' ');
193 ++counter;
194 }
195
196 return ++counter;
197}
198
199
200/** Print number in given base
201 *
202 * Print significant digits of a number in given
203 * base.
204 *
205 * @param num Number to print.
206 * @param width
207 * @param precision
208 * @param base Base to print the number in (should
209 * be in range 2 .. 16).
210 * @param flags output modifiers
211 * @return number of written characters or negative value on fail.
212 */
213static int print_number(__u64 num, int width, int precision, int base , __u64 flags)
214{
215 char *digits = digits_small;
216 char d[PRINT_NUMBER_BUFFER_SIZE]; /* this is good enough even for base == 2, prefix and sign */
217 char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
218 int size = 0;
219 int written = 0;
220 char sgn;
221
222 if (flags & __PRINTF_FLAG_BIGCHARS)
223 digits = digits_big;
224
225 *ptr-- = 0; /* Put zero at end of string */
226
227 if (num == 0) {
228 *ptr-- = '0';
229 size++;
230 } else {
231 do {
232 *ptr-- = digits[num % base];
233 size++;
234 } while (num /= base);
235 }
236
237 /* Collect sum of all prefixes/signs/... to calculate padding and leading zeroes */
238 if (flags & __PRINTF_FLAG_PREFIX) {
239 switch(base) {
240 case 2: /* Binary formating is not standard, but usefull */
241 size += 2;
242 break;
243 case 8:
244 size++;
245 break;
246 case 16:
247 size += 2;
248 break;
249 }
250 }
251
252 sgn = 0;
253 if (flags & __PRINTF_FLAG_SIGNED) {
254 if (flags & __PRINTF_FLAG_NEGATIVE) {
255 sgn = '-';
256 size++;
257 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
258 sgn = '+';
259 size++;
260 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
261 sgn = ' ';
262 size++;
263 }
264 }
265
266 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
267 flags &= ~__PRINTF_FLAG_ZEROPADDED;
268 }
269
270 /* if number is leftaligned or precision is specified then zeropadding is ignored */
271 if (flags & __PRINTF_FLAG_ZEROPADDED) {
272 if ((precision == 0) && (width > size)) {
273 precision = width - size;
274 }
275 }
276
277 /* print leading spaces */
278 if (size > precision) /* We must print whole number not only a part */
279 precision = size;
280
281 width -= precision;
282
283 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
284 while (width-- > 0) {
285 putchar(' ');
286 written++;
287 }
288 }
289
290 /* print sign */
291 if (sgn) {
292 putchar(sgn);
293 written++;
294 }
295
296 /* print prefix */
297
298 if (flags & __PRINTF_FLAG_PREFIX) {
299 switch(base) {
300 case 2: /* Binary formating is not standard, but usefull */
301 putchar('0');
302 if (flags & __PRINTF_FLAG_BIGCHARS) {
303 putchar('B');
304 } else {
305 putchar('b');
306 }
307 written += 2;
308 break;
309 case 8:
310 putchar('o');
311 written++;
312 break;
313 case 16:
314 putchar('0');
315 if (flags & __PRINTF_FLAG_BIGCHARS) {
316 putchar('X');
317 } else {
318 putchar('x');
319 }
320 written += 2;
321 break;
322 }
323 }
324
325 /* print leading zeroes */
326 precision -= size;
327 while (precision-- > 0) {
328 putchar('0');
329 written++;
330 }
331
332
333 /* print number itself */
334
335 written += putstr(++ptr);
336
337 /* print ending spaces */
338
339 while (width-- > 0) {
340 putchar(' ');
341 written++;
342 }
343
344 return written;
345}
346
347/** General formatted text print
348 *
349 * Print string formatted according the fmt parameter
350 * and variant arguments. Each formatting directive
351 * must have the following form:
352 * % [ flags ] [ width ] [ .precision ] [ type ] conversion
353 *
354 * FLAGS:
355 * # Force to print prefix. For conversion %o is prefix 0, for %x and %X are prefixes 0x and 0X and for conversion %b is prefix 0b.
356 * - Align to left.
357 * + Print positive sign just as negative.
358 * (space) If printed number is positive and '+' flag is not set, print space in place of sign.
359 * 0 Print 0 as padding instead of spaces. Zeroes are placed between sign and the rest of number. This flag is ignored if '-' flag is specified.
360 *
361 * WIDTH:
362 * Specify minimal width of printed argument. If it is bigger, width is ignored.
363 * If width is specified with a '*' character instead of number, width is taken from parameter list.
364 * Int parameter expected before parameter for processed conversion specification.
365 * If this value is negative it is taken its absolute value and the '-' flag is set.
366 *
367 * PRECISION:
368 * Value precision. For numbers it specifies minimum valid numbers.
369 * Smaller numbers are printed with leading zeroes. Bigger numbers are not affected.
370 * Strings with more than precision characters are cutted of.
371 * Just as width could be '*' used instead a number.
372 * A int value is then expected in parameters. When both width and precision are specified using '*',
373 * first parameter is used for width and second one for precision.
374 *
375 * TYPE:
376 * hh signed or unsigned char
377 * h signed or usigned short
378 * signed or usigned int (default value)
379 * l signed or usigned long int
380 * ll signed or usigned long long int
381 * z __native (non-standard extension)
382 *
383 *
384 * CONVERSIONS:
385 *
386 * % Print percentage character.
387 *
388 * c Print single character.
389 *
390 * s Print zero terminated string. If a NULL value is passed as value, "(NULL)" is printed instead.
391 *
392 * P, p Print value of a pointer. Void * value is expected and it is printed in hexadecimal notation with prefix
393 * ( as with %#X or %#x for 32bit or %#X / %#x for 64bit long pointers).
394 *
395 * b Print value as unsigned binary number. Prefix is not printed by default. (Nonstandard extension.)
396 *
397 * o Print value as unsigned octal number. Prefix is not printed by default.
398 *
399 * d,i Print signed decimal number. There is no difference between d and i conversion.
400 *
401 * u Print unsigned decimal number.
402 *
403 * X, x Print hexadecimal number with upper- or lower-case. Prefix is not printed by default.
404 *
405 * All other characters from fmt except the formatting directives
406 * are printed in verbatim.
407 *
408 * @param fmt Formatting NULL terminated string.
409 * @return count of printed characters or negative value on fail.
410 */
411int printf(const char *fmt, ...)
412{
413 int irqpri;
414 int i = 0, j = 0; /* i is index of currently processed char from fmt, j is index to the first not printed nonformating character */
415 int end;
416 int counter; /* counter of printed characters */
417 int retval; /* used to store return values from called functions */
418 va_list ap;
419 char c;
420 qualifier_t qualifier; /* type of argument */
421 int base; /* base in which will be parameter (numbers only) printed */
422 __u64 number; /* argument value */
423 __native size; /* byte size of integer parameter */
424 int width, precision;
425 __u64 flags;
426
427 counter = 0;
428
429 va_start(ap, fmt);
430
431 irqpri = interrupts_disable();
432 spinlock_lock(&printflock);
433
434
435 while ((c = fmt[i])) {
436 /* control character */
437 if (c == '%' ) {
438 /* print common characters if any processed */
439 if (i > j) {
440 if ((retval = putnchars(&fmt[j], (__native)(i - j))) == EOF) { /* error */
441 counter = -counter;
442 goto out;
443 }
444 counter += retval;
445 }
446
447 j = i;
448 /* parse modifiers */
449 flags = 0;
450 end = 0;
451
452 do {
453 ++i;
454 switch (c = fmt[i]) {
455 case '#': flags |= __PRINTF_FLAG_PREFIX; break;
456 case '-': flags |= __PRINTF_FLAG_LEFTALIGNED; break;
457 case '+': flags |= __PRINTF_FLAG_SHOWPLUS; break;
458 case ' ': flags |= __PRINTF_FLAG_SPACESIGN; break;
459 case '0': flags |= __PRINTF_FLAG_ZEROPADDED; break;
460 default: end = 1;
461 };
462
463 } while (end == 0);
464
465 /* width & '*' operator */
466 width = 0;
467 if (isdigit(fmt[i])) {
468 while (isdigit(fmt[i])) {
469 width *= 10;
470 width += fmt[i++] - '0';
471 }
472 } else if (fmt[i] == '*') {
473 /* get width value from argument list*/
474 i++;
475 width = (int)va_arg(ap, int);
476 if (width < 0) {
477 /* negative width means to set '-' flag */
478 width *= -1;
479 flags |= __PRINTF_FLAG_LEFTALIGNED;
480 }
481 }
482
483 /* precision and '*' operator */
484 precision = 0;
485 if (fmt[i] == '.') {
486 ++i;
487 if (isdigit(fmt[i])) {
488 while (isdigit(fmt[i])) {
489 precision *= 10;
490 precision += fmt[i++] - '0';
491 }
492 } else if (fmt[i] == '*') {
493 /* get precision value from argument list*/
494 i++;
495 precision = (int)va_arg(ap, int);
496 if (precision < 0) {
497 /* negative precision means to ignore it */
498 precision = 0;
499 }
500 }
501 }
502
503 switch (fmt[i++]) {
504 /** TODO: unimplemented qualifiers:
505 * t ptrdiff_t - ISO C 99
506 */
507 case 'h': /* char or short */
508 qualifier = PrintfQualifierShort;
509 if (fmt[i] == 'h') {
510 i++;
511 qualifier = PrintfQualifierByte;
512 }
513 break;
514 case 'l': /* long or long long*/
515 qualifier = PrintfQualifierLong;
516 if (fmt[i] == 'l') {
517 i++;
518 qualifier = PrintfQualifierLongLong;
519 }
520 break;
521 case 'z': /* __native */
522 qualifier = PrintfQualifierNative;
523 break;
524 default:
525 qualifier = PrintfQualifierInt; /* default type */
526 --i;
527 }
528
529 base = 10;
530
531 switch (c = fmt[i]) {
532
533 /*
534 * String and character conversions.
535 */
536 case 's':
537 if ((retval = print_string(va_arg(ap, char*), width, precision, flags)) == EOF) {
538 counter = -counter;
539 goto out;
540 };
541
542 counter += retval;
543 j = i + 1;
544 goto next_char;
545 case 'c':
546 c = va_arg(ap, unsigned int);
547 if ((retval = print_char(c, width, flags )) == EOF) {
548 counter = -counter;
549 goto out;
550 };
551
552 counter += retval;
553 j = i + 1;
554 goto next_char;
555
556 /*
557 * Integer values
558 */
559 case 'P': /* pointer */
560 flags |= __PRINTF_FLAG_BIGCHARS;
561 case 'p':
562 flags |= __PRINTF_FLAG_PREFIX;
563 base = 16;
564 qualifier = PrintfQualifierPointer;
565 break;
566 case 'b':
567 base = 2;
568 break;
569 case 'o':
570 base = 8;
571 break;
572 case 'd':
573 case 'i':
574 flags |= __PRINTF_FLAG_SIGNED;
575 case 'u':
576 break;
577 case 'X':
578 flags |= __PRINTF_FLAG_BIGCHARS;
579 case 'x':
580 base = 16;
581 break;
582 /* percentile itself */
583 case '%':
584 j = i;
585 goto next_char;
586 /*
587 * Bad formatting.
588 */
589 default:
590 /* Unknown format
591 * now, the j is index of '%' so we will
592 * print whole bad format sequence
593 */
594 goto next_char;
595 }
596
597
598 /* Print integers */
599 /* print number */
600 switch (qualifier) {
601 case PrintfQualifierByte:
602 size = sizeof(unsigned char);
603 number = (__u64)va_arg(ap, unsigned int);
604 break;
605 case PrintfQualifierShort:
606 size = sizeof(unsigned short);
607 number = (__u64)va_arg(ap, unsigned int);
608 break;
609 case PrintfQualifierInt:
610 size = sizeof(unsigned int);
611 number = (__u64)va_arg(ap, unsigned int);
612 break;
613 case PrintfQualifierLong:
614 size = sizeof(unsigned long);
615 number = (__u64)va_arg(ap, unsigned long);
616 break;
617 case PrintfQualifierLongLong:
618 size = sizeof(unsigned long long);
619 number = (__u64)va_arg(ap, unsigned long long);
620 break;
621 case PrintfQualifierPointer:
622 size = sizeof(void *);
623 number = (__u64)(unsigned long)va_arg(ap, void *);
624 break;
625 case PrintfQualifierNative:
626 size = sizeof(__native);
627 number = (__u64)va_arg(ap, __native);
628 break;
629 default: /* Unknown qualifier */
630 counter = -counter;
631 goto out;
632
633 }
634
635 if (flags & __PRINTF_FLAG_SIGNED) {
636 if (number & (0x1 << (size*8 - 1))) {
637 flags |= __PRINTF_FLAG_NEGATIVE;
638
639 if (size == sizeof(__u64)) {
640 number = -((__s64)number);
641 } else {
642 number = ~number;
643 number &= (~((0xFFFFFFFFFFFFFFFFll) << (size * 8)));
644 number++;
645 }
646 }
647 }
648
649 if ((retval = print_number(number, width, precision, base, flags)) == EOF ) {
650 counter = -counter;
651 goto out;
652 };
653
654 counter += retval;
655 j = i + 1;
656 }
657next_char:
658
659 ++i;
660 }
661
662 if (i > j) {
663 if ((retval = putnchars(&fmt[j], (__native)(i - j))) == EOF) { /* error */
664 counter = -counter;
665 goto out;
666 }
667 counter += retval;
668 }
669out:
670 spinlock_unlock(&printflock);
671 interrupts_restore(irqpri);
672
673 va_end(ap);
674 return counter;
675}
676
Note: See TracBrowser for help on using the repository browser.