FreeBSD/Linux Kernel Cross Reference
sys/kern/printf.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: printf.c,v $
29 * Revision 2.15 93/03/09 10:55:12 danner
30 * Lint to quiet GCC.
31 * [93/03/07 13:25:20 af]
32 *
33 * A better, MP-safe sprintf.
34 * [93/03/05 af]
35 *
36 * Revision 2.14 93/01/27 09:34:37 danner
37 * printf_init(), sprintf() are void.
38 * [93/01/25 jfriedl]
39 *
40 * Updated copyright.
41 * [93/01/12 berman]
42 * Wrote a version of sprintf() for general use.
43 * [92/03/18 berman]
44 *
45 * Revision 2.13 93/01/14 17:35:37 danner
46 * 64bit cleanup. Tuned up doprnt slightly.
47 * [92/12/01 af]
48 *
49 * Revision 2.12 92/08/03 17:38:32 jfriedl
50 * removed silly prototypes
51 * [92/08/02 jfriedl]
52 *
53 * Revision 2.11 92/05/21 17:14:57 jfriedl
54 * Cleanup to quiet gcc warnings.
55 * Changed PUTC arg of _doprnt, etc. to be VOID (which it is)
56 * [92/05/16 jfriedl]
57 *
58 * Revision 2.10 92/04/01 19:33:21 rpd
59 * Renamed gets to safe_gets.
60 * [92/03/31 rpd]
61 *
62 * Revision 2.9 91/06/06 17:07:22 jsb
63 * Added gets (derived from boot_gets).
64 * [91/05/14 09:18:50 jsb]
65 *
66 * Revision 2.8 91/05/14 16:44:59 mrt
67 * Correcting copyright
68 *
69 * Revision 2.7 91/02/05 17:28:14 mrt
70 * Changed to new Mach copyright
71 * [91/02/01 16:15:41 mrt]
72 *
73 * Revision 2.6 90/10/25 14:45:18 rwd
74 * Purged uprintf.
75 * [90/10/21 rpd]
76 *
77 * Revision 2.5 90/08/27 22:03:08 dbg
78 * Add extra formats to printf: '#- ' prefixes, %z (signed hex),
79 * %r and %n (signed and unsigned, current radix).
80 * [90/08/20 dbg]
81 *
82 * Revision 2.4 90/01/11 11:43:44 dbg
83 * De-linted.
84 * [90/01/03 dbg]
85 *
86 * Revision 2.3 89/11/29 14:09:06 af
87 * Ooops, a typo.
88 * [89/10/29 09:34:26 af]
89 *
90 * Changed the case for %c to load ints and not chars. Or
91 * else it is byte-order dependent since C passes char as ints.
92 * [89/10/13 af]
93 *
94 * Turned the unused 'file descriptor' field for _doprnt and putchar
95 * into a more useful pointer to an (optional) specialized putchar
96 * routine. This can be used, for instance, to divert debugging
97 * printouts to some specialized interface or IOP.
98 * [89/10/09 af]
99 *
100 * Revision 2.2 89/09/25 11:00:58 rwd
101 * Added case 'X' same as 'x' for now.
102 * [89/09/20 rwd]
103 *
104 * Revision 2.1 89/08/03 15:51:14 rwd
105 * Created.
106 *
107 * 8-Aug-88 David Golub (dbg) at Carnegie-Mellon University
108 * Converted for MACH kernel use. Removed %r, %R, %b; added %b
109 * from Berkeley's kernel to print bit fields in device registers;
110 * changed to use varargs.
111 *
112 */
113
114 /*
115 * Common code for printf et al.
116 *
117 * The calling routine typically takes a variable number of arguments,
118 * and passes the address of the first one. This implementation
119 * assumes a straightforward, stack implementation, aligned to the
120 * machine's wordsize. Increasing addresses are assumed to point to
121 * successive arguments (left-to-right), as is the case for a machine
122 * with a downward-growing stack with arguments pushed right-to-left.
123 *
124 * To write, for example, fprintf() using this routine, the code
125 *
126 * fprintf(fd, format, args)
127 * FILE *fd;
128 * char *format;
129 * {
130 * _doprnt(format, &args, fd);
131 * }
132 *
133 * would suffice. (This example does not handle the fprintf's "return
134 * value" correctly, but who looks at the return value of fprintf
135 * anyway?)
136 *
137 * This version implements the following printf features:
138 *
139 * %d decimal conversion
140 * %u unsigned conversion
141 * %x hexadecimal conversion
142 * %X hexadecimal conversion with capital letters
143 * %o octal conversion
144 * %c character
145 * %s string
146 * %m.n field width, precision
147 * %-m.n left adjustment
148 * %0m.n zero-padding
149 * %*.* width and precision taken from arguments
150 *
151 * This version does not implement %f, %e, or %g. It accepts, but
152 * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
153 * work correctly on machines for which sizeof(long) != sizeof(int).
154 * It does not even parse %D, %O, or %U; you should be using %ld, %o and
155 * %lu if you mean long conversion.
156 *
157 * As mentioned, this version does not return any reasonable value.
158 *
159 * Permission is granted to use, modify, or propagate this code as
160 * long as this notice is incorporated.
161 *
162 * Steve Summit 3/25/87
163 */
164
165 /*
166 * Added formats for decoding device registers:
167 *
168 * printf("reg = %b", regval, "<base><arg>*")
169 *
170 * where <base> is the output base expressed as a control character:
171 * i.e. '\1' gives octal, '\2' gives hex. Each <arg> is a sequence of
172 * characters, the first of which gives the bit number to be inspected
173 * (origin 1), and the rest (up to a control character (<= 32)) give the
174 * name of the register. Thus
175 * printf("reg = %b\n", 3, "\1\2BITTWO\1BITONE")
176 * would produce
177 * reg = 3<BITTWO,BITONE>
178 *
179 * If the second character in <arg> is also a control character, it
180 * indicates the last bit of a bit field. In this case, printf will extract
181 * bits <1> to <2> and print it. Characters following the second control
182 * character are printed before the bit field.
183 * printf("reg = %b\n", 0xb, "\1\4\3FIELD1=\2BITTWO\1BITONE")
184 * would produce
185 * reg = b<FIELD1=2,BITONE>
186 */
187 /*
188 * Added for general use:
189 * # prefix for alternate format:
190 * 0x (0X) for hex
191 * leading 0 for octal
192 * + print '+' if positive
193 * blank print ' ' if positive
194 *
195 * z signed hexadecimal
196 * r signed, 'radix'
197 * n unsigned, 'radix'
198 *
199 * D,U,O,Z same as corresponding lower-case versions
200 * (compatibility)
201 */
202
203 #include <mach/boolean.h>
204 #include <kern/lock.h>
205 #include <kern/strings.h>
206 #include <sys/varargs.h>
207
208 #define isdigit(d) ((d) >= '' && (d) <= '9')
209 #define Ctod(c) ((c) - '')
210
211 #define MAXBUF (sizeof(long int) * 8) /* enough for binary */
212
213
214 void printnum(
215 register unsigned long u,
216 register int base,
217 void (*putc)( char, vm_offset_t ),
218 vm_offset_t putc_arg)
219 {
220 char buf[MAXBUF]; /* build number here */
221 register char * p = &buf[MAXBUF-1];
222 static char digs[] = "0123456789abcdef";
223
224 do {
225 *p-- = digs[u % base];
226 u /= base;
227 } while (u != 0);
228
229 while (++p != &buf[MAXBUF])
230 (*putc)(*p, putc_arg);
231
232 }
233
234 boolean_t _doprnt_truncates = FALSE;
235 decl_simple_lock_data(,_doprnt_lock)
236
237 void printf_init()
238 {
239 simple_lock_init(&_doprnt_lock);
240 }
241
242 void _doprnt(
243 register char *fmt,
244 va_list *argp,
245 /* character output routine */
246 void (*putc)( char, vm_offset_t),
247 int radix, /* default radix - for '%r' */
248 vm_offset_t putc_arg)
249 {
250 int length;
251 int prec;
252 boolean_t ladjust;
253 char padc;
254 long n;
255 unsigned long u;
256 int plus_sign;
257 int sign_char;
258 boolean_t altfmt, truncate;
259 int base;
260 register char c;
261
262 #if 0
263 /* Make sure that we get *some* printout, no matter what */
264 simple_lock(&_doprnt_lock);
265 #else
266 {
267 register int i = 0;
268 while (i < 1*1024*1024) {
269 if (simple_lock_try(&_doprnt_lock))
270 break;
271 i++;
272 }
273 }
274 #endif
275
276 while ((c = *fmt) != '\0') {
277 if (c != '%') {
278 (*putc)(c, putc_arg);
279 fmt++;
280 continue;
281 }
282
283 fmt++;
284
285 length = 0;
286 prec = -1;
287 ladjust = FALSE;
288 padc = ' ';
289 plus_sign = 0;
290 sign_char = 0;
291 altfmt = FALSE;
292
293 while (TRUE) {
294 c = *fmt;
295 if (c == '#') {
296 altfmt = TRUE;
297 }
298 else if (c == '-') {
299 ladjust = TRUE;
300 }
301 else if (c == '+') {
302 plus_sign = '+';
303 }
304 else if (c == ' ') {
305 if (plus_sign == 0)
306 plus_sign = ' ';
307 }
308 else
309 break;
310 fmt++;
311 }
312
313 if (c == '') {
314 padc = '';
315 c = *++fmt;
316 }
317
318 if (isdigit(c)) {
319 while(isdigit(c)) {
320 length = 10 * length + Ctod(c);
321 c = *++fmt;
322 }
323 }
324 else if (c == '*') {
325 length = va_arg(*argp, int);
326 c = *++fmt;
327 if (length < 0) {
328 ladjust = !ladjust;
329 length = -length;
330 }
331 }
332
333 if (c == '.') {
334 c = *++fmt;
335 if (isdigit(c)) {
336 prec = 0;
337 while(isdigit(c)) {
338 prec = 10 * prec + Ctod(c);
339 c = *++fmt;
340 }
341 }
342 else if (c == '*') {
343 prec = va_arg(*argp, int);
344 c = *++fmt;
345 }
346 }
347
348 if (c == 'l')
349 c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
350
351 truncate = FALSE;
352
353 switch(c) {
354 case 'b':
355 case 'B':
356 {
357 register char *p;
358 boolean_t any;
359 register int i;
360
361 u = va_arg(*argp, unsigned long);
362 p = va_arg(*argp, char *);
363 base = *p++;
364 printnum(u, base, putc, putc_arg);
365
366 if (u == 0)
367 break;
368
369 any = FALSE;
370 while (i = *p++) {
371 /* NOTE: The '32' here is because ascii space */
372 if (*p <= 32) {
373 /*
374 * Bit field
375 */
376 register int j;
377 if (any)
378 (*putc)(',', putc_arg);
379 else {
380 (*putc)('<', putc_arg);
381 any = TRUE;
382 }
383 j = *p++;
384 for (; (c = *p) > 32; p++)
385 (*putc)(c, putc_arg);
386 printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
387 base, putc, putc_arg);
388 }
389 else if (u & (1<<(i-1))) {
390 if (any)
391 (*putc)(',', putc_arg);
392 else {
393 (*putc)('<', putc_arg);
394 any = TRUE;
395 }
396 for (; (c = *p) > 32; p++)
397 (*putc)(c, putc_arg);
398 }
399 else {
400 for (; *p > 32; p++)
401 continue;
402 }
403 }
404 if (any)
405 (*putc)('>', putc_arg);
406 break;
407 }
408
409 case 'c':
410 c = va_arg(*argp, int);
411 (*putc)(c, putc_arg);
412 break;
413
414 case 's':
415 {
416 register char *p;
417 register char *p2;
418
419 if (prec == -1)
420 prec = 0x7fffffff; /* MAXINT */
421
422 p = va_arg(*argp, char *);
423
424 if (p == (char *)0)
425 p = "";
426
427 if (length > 0 && !ladjust) {
428 n = 0;
429 p2 = p;
430
431 for (; *p != '\0' && n < prec; p++)
432 n++;
433
434 p = p2;
435
436 while (n < length) {
437 (*putc)(' ', putc_arg);
438 n++;
439 }
440 }
441
442 n = 0;
443
444 while (*p != '\0') {
445 if (++n > prec)
446 break;
447
448 (*putc)(*p++, putc_arg);
449 }
450
451 if (n < length && ladjust) {
452 while (n < length) {
453 (*putc)(' ', putc_arg);
454 n++;
455 }
456 }
457
458 break;
459 }
460
461 case 'o':
462 truncate = _doprnt_truncates;
463 case 'O':
464 base = 8;
465 goto print_unsigned;
466
467 case 'd':
468 truncate = _doprnt_truncates;
469 case 'D':
470 base = 10;
471 goto print_signed;
472
473 case 'u':
474 truncate = _doprnt_truncates;
475 case 'U':
476 base = 10;
477 goto print_unsigned;
478
479 case 'x':
480 truncate = _doprnt_truncates;
481 case 'X':
482 base = 16;
483 goto print_unsigned;
484
485 case 'z':
486 truncate = _doprnt_truncates;
487 case 'Z':
488 base = 16;
489 goto print_signed;
490
491 case 'r':
492 truncate = _doprnt_truncates;
493 case 'R':
494 base = radix;
495 goto print_signed;
496
497 case 'n':
498 truncate = _doprnt_truncates;
499 case 'N':
500 base = radix;
501 goto print_unsigned;
502
503 print_signed:
504 n = va_arg(*argp, long);
505 if (n >= 0) {
506 u = n;
507 sign_char = plus_sign;
508 }
509 else {
510 u = -n;
511 sign_char = '-';
512 }
513 goto print_num;
514
515 print_unsigned:
516 u = va_arg(*argp, unsigned long);
517 goto print_num;
518
519 print_num:
520 {
521 char buf[MAXBUF]; /* build number here */
522 register char * p = &buf[MAXBUF-1];
523 static char digits[] = "0123456789abcdef";
524 char *prefix = 0;
525
526 if (truncate) u = (long)((int)(u));
527
528 if (u != 0 && altfmt) {
529 if (base == 8)
530 prefix = "";
531 else if (base == 16)
532 prefix = "0x";
533 }
534
535 do {
536 *p-- = digits[u % base];
537 u /= base;
538 } while (u != 0);
539
540 length -= (&buf[MAXBUF-1] - p);
541 if (sign_char)
542 length--;
543 if (prefix)
544 length -= strlen(prefix);
545
546 if (padc == ' ' && !ladjust) {
547 /* blank padding goes before prefix */
548 while (--length >= 0)
549 (*putc)(' ', putc_arg);
550 }
551 if (sign_char)
552 (*putc)(sign_char, putc_arg);
553 if (prefix)
554 while (*prefix)
555 (*putc)(*prefix++, putc_arg);
556 if (padc == '') {
557 /* zero padding goes after sign and prefix */
558 while (--length >= 0)
559 (*putc)('', putc_arg);
560 }
561 while (++p != &buf[MAXBUF])
562 (*putc)(*p, putc_arg);
563
564 if (ladjust) {
565 while (--length >= 0)
566 (*putc)(' ', putc_arg);
567 }
568 break;
569 }
570
571 case '\0':
572 fmt--;
573 break;
574
575 default:
576 (*putc)(c, putc_arg);
577 }
578 fmt++;
579 }
580
581 simple_unlock(&_doprnt_lock);
582 }
583
584 /*
585 * Printing (to console)
586 */
587 extern void cnputc( char, /*not really*/vm_offset_t);
588
589 /*VARARGS1*/
590 void printf(fmt, va_alist)
591 char * fmt;
592 va_dcl
593 {
594 va_list listp;
595 va_start(listp);
596 _doprnt(fmt, &listp, cnputc, 16, 0);
597 va_end(listp);
598 }
599
600 int indent = 0;
601
602 /*
603 * Printing (to console) with indentation.
604 */
605 /*VARARGS1*/
606 void iprintf(fmt, va_alist)
607 char * fmt;
608 va_dcl
609 {
610 va_list listp;
611 register int i;
612
613 for (i = indent; i > 0; ){
614 if (i >= 8) {
615 printf("\t");
616 i -= 8;
617 }
618 else {
619 printf(" ");
620 i--;
621 }
622 }
623 va_start(listp);
624 _doprnt(fmt, &listp, cnputc, 16, 0);
625 va_end(listp);
626 }
627
628 /*
629 * Printing to generic buffer
630 * Returns #bytes printed.
631 * Strings are zero-terminated.
632 */
633 static void
634 sputc(
635 char c,
636 vm_offset_t arg)
637 {
638 register char **bufp = (char **) arg;
639 register char *p = *bufp;
640 *p++ = c;
641 *bufp = p;
642 }
643
644 int
645 sprintf( buf, fmt, va_alist)
646 char *buf;
647 char *fmt;
648 va_dcl
649 {
650 va_list listp;
651 char *start = buf;
652
653 va_start(listp);
654 _doprnt(fmt, &listp, sputc, 16, (vm_offset_t)&buf);
655 va_end(listp);
656
657 *buf = 0;
658 return (buf - start);
659 }
660
661
662 void safe_gets(str, maxlen)
663 char *str;
664 int maxlen;
665 {
666 register char *lp;
667 register int c;
668 char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
669
670 lp = str;
671 for (;;) {
672 c = cngetc();
673 switch (c) {
674 case '\n':
675 case '\r':
676 printf("\n");
677 *lp++ = 0;
678 return;
679
680 case '\b':
681 case '#':
682 case '\177':
683 if (lp > str) {
684 printf("\b \b");
685 lp--;
686 }
687 continue;
688
689 case '@':
690 case 'u'&037:
691 lp = str;
692 printf("\n\r");
693 continue;
694
695 default:
696 if (c >= ' ' && c < '\177') {
697 if (lp < strmax) {
698 *lp++ = c;
699 printf("%c", c);
700 }
701 else {
702 printf("%c", '\007'); /* beep */
703 }
704 }
705 }
706 }
707 }
Cache object: 18b039c8ae0a7722be15df041d0b249e
|