source: mainline/generic/src/debug/print.c@ 17b1b99

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 17b1b99 was 17b1b99, checked in by Jakub Jermar <jakub@…>, 19 years ago

Some formatting and formulation changes.

  • Property mode set to 100644
File size: 16.4 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 appending '\n' to the end
84 *
85 * Dont use this function directly - printflock is not locked here
86 *
87 */
88static int putstr(const char *str)
89{
90 int count;
91 if (str == NULL) {
92 str = "(NULL)";
93 }
94
95 for (count = 0; str[count] != 0; count++) {
96 putchar(str[count]);
97 }
98 return count;
99}
100
101/** Print count characters from buffer to output
102 *
103 */
104static int putnchars(const char *buffer, __native count)
105{
106 int i;
107 if (buffer == NULL) {
108 buffer = "(NULL)";
109 count = 6;
110 }
111
112 for (i = 0; i < count; i++) {
113 putchar(buffer[i]);
114 }
115
116 return count;
117}
118
119/** Print one formatted character
120 *
121 * @param c character to print
122 * @param width
123 * @param flags
124 * @return number of printed characters or EOF
125 */
126static int print_char(char c, int width, __u64 flags)
127{
128 int counter = 0;
129
130 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
131 while (--width > 0) { /* one space is consumed by character itself hence the predecrement */
132 /* FIXME: painfully slow */
133 putchar(' ');
134 ++counter;
135 }
136 }
137
138 putchar(c);
139 ++counter;
140
141 while (--width > 0) { /* one space is consumed by character itself hence the predecrement */
142 putchar(' ');
143 ++counter;
144 }
145
146 return counter;
147}
148
149/** Print one string
150 * @param s string
151 * @param width
152 * @param precision
153 * @param flags
154 * @return number of printed characters or EOF
155 */
156static int print_string(char *s, int width, int precision, __u64 flags)
157{
158 int counter = 0;
159 __native size;
160
161 if (s == NULL) {
162 return putstr("(NULL)");
163 }
164
165 size = strlen(s);
166
167 /* print leading spaces */
168
169 if (precision == 0)
170 precision = size;
171
172 width -= precision;
173
174 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
175 while (width-- > 0) {
176 putchar(' ');
177 counter++;
178 }
179 }
180
181 while (precision > size) {
182 precision--;
183 putchar(' ');
184 ++counter;
185 }
186
187 if (putnchars(s, precision) == EOF) {
188 return EOF;
189 }
190
191 counter += precision;
192
193 while (width-- > 0) {
194 putchar(' ');
195 ++counter;
196 }
197
198 return ++counter;
199}
200
201
202/** Print number in given base
203 *
204 * Print significant digits of a number in given
205 * base.
206 *
207 * @param num Number to print.
208 * @param width
209 * @param precision
210 * @param base Base to print the number in (should
211 * be in range 2 .. 16).
212 * @param flags output modifiers
213 * @return number of written characters or negative value on fail.
214 */
215static int print_number(__u64 num, int width, int precision, int base , __u64 flags)
216{
217 char *digits = digits_small;
218 char d[PRINT_NUMBER_BUFFER_SIZE]; /* this is good enough even for base == 2, prefix and sign */
219 char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
220 int size = 0;
221 int written = 0;
222 char sgn;
223
224 if (flags & __PRINTF_FLAG_BIGCHARS)
225 digits = digits_big;
226
227 *ptr-- = 0; /* Put zero at end of string */
228
229 if (num == 0) {
230 *ptr-- = '0';
231 size++;
232 } else {
233 do {
234 *ptr-- = digits[num % base];
235 size++;
236 } while (num /= base);
237 }
238
239 /* Collect sum of all prefixes/signs/... to calculate padding and leading zeroes */
240 if (flags & __PRINTF_FLAG_PREFIX) {
241 switch(base) {
242 case 2: /* Binary formating is not standard, but usefull */
243 size += 2;
244 break;
245 case 8:
246 size++;
247 break;
248 case 16:
249 size += 2;
250 break;
251 }
252 }
253
254 sgn = 0;
255 if (flags & __PRINTF_FLAG_SIGNED) {
256 if (flags & __PRINTF_FLAG_NEGATIVE) {
257 sgn = '-';
258 size++;
259 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
260 sgn = '+';
261 size++;
262 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
263 sgn = ' ';
264 size++;
265 }
266 }
267
268 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
269 flags &= ~__PRINTF_FLAG_ZEROPADDED;
270 }
271
272 /* if number is leftaligned or precision is specified then zeropadding is ignored */
273 if (flags & __PRINTF_FLAG_ZEROPADDED) {
274 if ((precision == 0) && (width > size)) {
275 precision = width - size;
276 }
277 }
278
279 /* print leading spaces */
280 if (size > precision) /* We must print the whole number, not only a part */
281 precision = size;
282
283 width -= precision;
284
285 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
286 while (width-- > 0) {
287 putchar(' ');
288 written++;
289 }
290 }
291
292 /* print sign */
293 if (sgn) {
294 putchar(sgn);
295 written++;
296 }
297
298 /* print prefix */
299
300 if (flags & __PRINTF_FLAG_PREFIX) {
301 switch(base) {
302 case 2: /* Binary formating is not standard, but usefull */
303 putchar('0');
304 if (flags & __PRINTF_FLAG_BIGCHARS) {
305 putchar('B');
306 } else {
307 putchar('b');
308 }
309 written += 2;
310 break;
311 case 8:
312 putchar('o');
313 written++;
314 break;
315 case 16:
316 putchar('0');
317 if (flags & __PRINTF_FLAG_BIGCHARS) {
318 putchar('X');
319 } else {
320 putchar('x');
321 }
322 written += 2;
323 break;
324 }
325 }
326
327 /* print leading zeroes */
328 precision -= size;
329 while (precision-- > 0) {
330 putchar('0');
331 written++;
332 }
333
334
335 /* print number itself */
336
337 written += putstr(++ptr);
338
339 /* print ending spaces */
340
341 while (width-- > 0) {
342 putchar(' ');
343 written++;
344 }
345
346 return written;
347}
348
349/** General formatted text print
350 *
351 * Print string formatted according to the fmt parameter
352 * and variadic arguments. Each formatting directive
353 * must have the following form:
354 * % [ flags ] [ width ] [ .precision ] [ type ] conversion
355 *
356 * FLAGS:
357 * # Force to print prefix.
358 * For conversion %o the prefix is 0, for %x and %X prefixes are 0x and 0X and for conversion %b the prefix is 0b.
359 * - Align to left.
360 * + Print positive sign just as negative.
361 * (space) If printed number is positive and '+' flag is not set, print space in place of sign.
362 * 0 Print 0 as padding instead of spaces. Zeroes are placed between sign and the rest of number.
363 * This flag is ignored if '-' flag is specified.
364 *
365 * WIDTH:
366 * Specify minimal width of printed argument. If it is bigger, width is ignored.
367 * If width is specified with a '*' character instead of number, width is taken from parameter list.
368 * Int parameter expected before parameter for processed conversion specification.
369 * If this value is negative its absolute value is taken and the '-' flag is set.
370 *
371 * PRECISION:
372 * Value precision. For numbers it specifies minimum valid numbers.
373 * Smaller numbers are printed with leading zeroes. Bigger numbers are not affected.
374 * Strings with more than precision characters are cut off.
375 * Just as with width, an '*' can be used used instead of a number.
376 * An integer value is then expected in parameters. When both width and precision are specified using '*',
377 * first parameter is used for width and second one for precision.
378 *
379 * TYPE:
380 * hh signed or unsigned char
381 * h signed or usigned short
382 * signed or usigned int (default value)
383 * l signed or usigned long int
384 * ll signed or usigned long long int
385 * z __native (non-standard extension)
386 *
387 *
388 * CONVERSIONS:
389 *
390 * % Print percentage character.
391 *
392 * c Print single character.
393 *
394 * s Print zero terminated string. If a NULL value is passed as value, "(NULL)" is printed instead.
395 *
396 * P, p Print value of a pointer. Void * value is expected and it is printed in hexadecimal notation with prefix
397 * ( as with %#X or %#x for 32bit or %#X / %#x for 64bit long pointers).
398 *
399 * b Print value as unsigned binary number. Prefix is not printed by default. (Nonstandard extension.)
400 *
401 * o Print value as unsigned octal number. Prefix is not printed by default.
402 *
403 * d,i Print signed decimal number. There is no difference between d and i conversion.
404 *
405 * u Print unsigned decimal number.
406 *
407 * X, x Print hexadecimal number with upper- or lower-case. Prefix is not printed by default.
408 *
409 * All other characters from fmt except the formatting directives
410 * are printed in verbatim.
411 *
412 * @param fmt Formatting NULL terminated string.
413 * @return count of printed characters or negative value on fail.
414 */
415int printf(const char *fmt, ...)
416{
417 int irqpri;
418 int i = 0, j = 0; /* i is index of currently processed char from fmt, j is index to the first not printed nonformating character */
419 int end;
420 int counter; /* counter of printed characters */
421 int retval; /* used to store return values from called functions */
422 va_list ap;
423 char c;
424 qualifier_t qualifier; /* type of argument */
425 int base; /* base in which will be parameter (numbers only) printed */
426 __u64 number; /* argument value */
427 __native size; /* byte size of integer parameter */
428 int width, precision;
429 __u64 flags;
430
431 counter = 0;
432
433 va_start(ap, fmt);
434
435 irqpri = interrupts_disable();
436 spinlock_lock(&printflock);
437
438
439 while ((c = fmt[i])) {
440 /* control character */
441 if (c == '%' ) {
442 /* print common characters if any processed */
443 if (i > j) {
444 if ((retval = putnchars(&fmt[j], (__native)(i - j))) == EOF) { /* error */
445 counter = -counter;
446 goto out;
447 }
448 counter += retval;
449 }
450
451 j = i;
452 /* parse modifiers */
453 flags = 0;
454 end = 0;
455
456 do {
457 ++i;
458 switch (c = fmt[i]) {
459 case '#': flags |= __PRINTF_FLAG_PREFIX; break;
460 case '-': flags |= __PRINTF_FLAG_LEFTALIGNED; break;
461 case '+': flags |= __PRINTF_FLAG_SHOWPLUS; break;
462 case ' ': flags |= __PRINTF_FLAG_SPACESIGN; break;
463 case '0': flags |= __PRINTF_FLAG_ZEROPADDED; break;
464 default: end = 1;
465 };
466
467 } while (end == 0);
468
469 /* width & '*' operator */
470 width = 0;
471 if (isdigit(fmt[i])) {
472 while (isdigit(fmt[i])) {
473 width *= 10;
474 width += fmt[i++] - '0';
475 }
476 } else if (fmt[i] == '*') {
477 /* get width value from argument list*/
478 i++;
479 width = (int)va_arg(ap, int);
480 if (width < 0) {
481 /* negative width means to set '-' flag */
482 width *= -1;
483 flags |= __PRINTF_FLAG_LEFTALIGNED;
484 }
485 }
486
487 /* precision and '*' operator */
488 precision = 0;
489 if (fmt[i] == '.') {
490 ++i;
491 if (isdigit(fmt[i])) {
492 while (isdigit(fmt[i])) {
493 precision *= 10;
494 precision += fmt[i++] - '0';
495 }
496 } else if (fmt[i] == '*') {
497 /* get precision value from argument list*/
498 i++;
499 precision = (int)va_arg(ap, int);
500 if (precision < 0) {
501 /* negative precision means to ignore it */
502 precision = 0;
503 }
504 }
505 }
506
507 switch (fmt[i++]) {
508 /** TODO: unimplemented qualifiers:
509 * t ptrdiff_t - ISO C 99
510 */
511 case 'h': /* char or short */
512 qualifier = PrintfQualifierShort;
513 if (fmt[i] == 'h') {
514 i++;
515 qualifier = PrintfQualifierByte;
516 }
517 break;
518 case 'l': /* long or long long*/
519 qualifier = PrintfQualifierLong;
520 if (fmt[i] == 'l') {
521 i++;
522 qualifier = PrintfQualifierLongLong;
523 }
524 break;
525 case 'z': /* __native */
526 qualifier = PrintfQualifierNative;
527 break;
528 default:
529 qualifier = PrintfQualifierInt; /* default type */
530 --i;
531 }
532
533 base = 10;
534
535 switch (c = fmt[i]) {
536
537 /*
538 * String and character conversions.
539 */
540 case 's':
541 if ((retval = print_string(va_arg(ap, char*), width, precision, flags)) == EOF) {
542 counter = -counter;
543 goto out;
544 };
545
546 counter += retval;
547 j = i + 1;
548 goto next_char;
549 case 'c':
550 c = va_arg(ap, unsigned int);
551 if ((retval = print_char(c, width, flags )) == EOF) {
552 counter = -counter;
553 goto out;
554 };
555
556 counter += retval;
557 j = i + 1;
558 goto next_char;
559
560 /*
561 * Integer values
562 */
563 case 'P': /* pointer */
564 flags |= __PRINTF_FLAG_BIGCHARS;
565 case 'p':
566 flags |= __PRINTF_FLAG_PREFIX;
567 base = 16;
568 qualifier = PrintfQualifierPointer;
569 break;
570 case 'b':
571 base = 2;
572 break;
573 case 'o':
574 base = 8;
575 break;
576 case 'd':
577 case 'i':
578 flags |= __PRINTF_FLAG_SIGNED;
579 case 'u':
580 break;
581 case 'X':
582 flags |= __PRINTF_FLAG_BIGCHARS;
583 case 'x':
584 base = 16;
585 break;
586 /* percentile itself */
587 case '%':
588 j = i;
589 goto next_char;
590 /*
591 * Bad formatting.
592 */
593 default:
594 /* Unknown format
595 * now, the j is index of '%' so we will
596 * print whole bad format sequence
597 */
598 goto next_char;
599 }
600
601
602 /* Print integers */
603 /* print number */
604 switch (qualifier) {
605 case PrintfQualifierByte:
606 size = sizeof(unsigned char);
607 number = (__u64)va_arg(ap, unsigned int);
608 break;
609 case PrintfQualifierShort:
610 size = sizeof(unsigned short);
611 number = (__u64)va_arg(ap, unsigned int);
612 break;
613 case PrintfQualifierInt:
614 size = sizeof(unsigned int);
615 number = (__u64)va_arg(ap, unsigned int);
616 break;
617 case PrintfQualifierLong:
618 size = sizeof(unsigned long);
619 number = (__u64)va_arg(ap, unsigned long);
620 break;
621 case PrintfQualifierLongLong:
622 size = sizeof(unsigned long long);
623 number = (__u64)va_arg(ap, unsigned long long);
624 break;
625 case PrintfQualifierPointer:
626 size = sizeof(void *);
627 number = (__u64)(unsigned long)va_arg(ap, void *);
628 break;
629 case PrintfQualifierNative:
630 size = sizeof(__native);
631 number = (__u64)va_arg(ap, __native);
632 break;
633 default: /* Unknown qualifier */
634 counter = -counter;
635 goto out;
636
637 }
638
639 if (flags & __PRINTF_FLAG_SIGNED) {
640 if (number & (0x1 << (size*8 - 1))) {
641 flags |= __PRINTF_FLAG_NEGATIVE;
642
643 if (size == sizeof(__u64)) {
644 number = -((__s64)number);
645 } else {
646 number = ~number;
647 number &= (~((0xFFFFFFFFFFFFFFFFll) << (size * 8)));
648 number++;
649 }
650 }
651 }
652
653 if ((retval = print_number(number, width, precision, base, flags)) == EOF ) {
654 counter = -counter;
655 goto out;
656 };
657
658 counter += retval;
659 j = i + 1;
660 }
661next_char:
662
663 ++i;
664 }
665
666 if (i > j) {
667 if ((retval = putnchars(&fmt[j], (__native)(i - j))) == EOF) { /* error */
668 counter = -counter;
669 goto out;
670 }
671 counter += retval;
672 }
673out:
674 spinlock_unlock(&printflock);
675 interrupts_restore(irqpri);
676
677 va_end(ap);
678 return counter;
679}
Note: See TracBrowser for help on using the repository browser.