]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/printf.c
xnu-123.5.tar.gz
[apple/xnu.git] / osfmk / kern / printf.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * @OSF_COPYRIGHT@
24 */
25
26/*
27 * Mach Operating System
28 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
29 * All Rights Reserved.
30 *
31 * Permission to use, copy, modify and distribute this software and its
32 * documentation is hereby granted, provided that both the copyright
33 * notice and this permission notice appear in all copies of the
34 * software, derivative works or modified versions, and any portions
35 * thereof, and that both notices appear in supporting documentation.
36 *
37 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
38 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
39 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 *
41 * Carnegie Mellon requests users of this software to return to
42 *
43 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
44 * School of Computer Science
45 * Carnegie Mellon University
46 * Pittsburgh PA 15213-3890
47 *
48 * any improvements or extensions that they make and grant Carnegie Mellon
49 * the rights to redistribute these changes.
50 */
51
52/*
53 * Common code for printf et al.
54 *
55 * The calling routine typically takes a variable number of arguments,
56 * and passes the address of the first one. This implementation
57 * assumes a straightforward, stack implementation, aligned to the
58 * machine's wordsize. Increasing addresses are assumed to point to
59 * successive arguments (left-to-right), as is the case for a machine
60 * with a downward-growing stack with arguments pushed right-to-left.
61 *
62 * To write, for example, fprintf() using this routine, the code
63 *
64 * fprintf(fd, format, args)
65 * FILE *fd;
66 * char *format;
67 * {
68 * _doprnt(format, &args, fd);
69 * }
70 *
71 * would suffice. (This example does not handle the fprintf's "return
72 * value" correctly, but who looks at the return value of fprintf
73 * anyway?)
74 *
75 * This version implements the following printf features:
76 *
77 * %d decimal conversion
78 * %u unsigned conversion
79 * %x hexadecimal conversion
80 * %X hexadecimal conversion with capital letters
81 * %o octal conversion
82 * %c character
83 * %s string
84 * %m.n field width, precision
85 * %-m.n left adjustment
86 * %0m.n zero-padding
87 * %*.* width and precision taken from arguments
88 *
89 * This version does not implement %f, %e, or %g. It accepts, but
90 * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
91 * work correctly on machines for which sizeof(long) != sizeof(int).
92 * It does not even parse %D, %O, or %U; you should be using %ld, %o and
93 * %lu if you mean long conversion.
94 *
95 * As mentioned, this version does not return any reasonable value.
96 *
97 * Permission is granted to use, modify, or propagate this code as
98 * long as this notice is incorporated.
99 *
100 * Steve Summit 3/25/87
101 */
102
103/*
104 * Added formats for decoding device registers:
105 *
106 * printf("reg = %b", regval, "<base><arg>*")
107 *
108 * where <base> is the output base expressed as a control character:
109 * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of
110 * characters, the first of which gives the bit number to be inspected
111 * (origin 1), and the rest (up to a control character (<= 32)) give the
112 * name of the register. Thus
113 * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
114 * would produce
115 * reg = 3<BITTWO,BITONE>
116 *
117 * If the second character in <arg> is also a control character, it
118 * indicates the last bit of a bit field. In this case, printf will extract
119 * bits <1> to <2> and print it. Characters following the second control
120 * character are printed before the bit field.
121 * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
122 * would produce
123 * reg = b<FIELD1=2,BITONE>
124 *
125 * The %B format is like %b but the bits are numbered from the most
126 * significant (the bit weighted 31), which is called 1, to the least
127 * significant, called 32.
128 */
129/*
130 * Added for general use:
131 * # prefix for alternate format:
132 * 0x (0X) for hex
133 * leading 0 for octal
134 * + print '+' if positive
135 * blank print ' ' if positive
136 *
137 * z signed hexadecimal
138 * r signed, 'radix'
139 * n unsigned, 'radix'
140 *
141 * D,U,O,Z same as corresponding lower-case versions
142 * (compatibility)
143 */
144
145#include <platforms.h>
146#include <mach/boolean.h>
147#include <cpus.h>
148#include <kern/cpu_number.h>
149#include <kern/lock.h>
150#include <kern/thread.h>
151#include <kern/sched_prim.h>
152#include <kern/misc_protos.h>
153#include <stdarg.h>
154#include <string.h>
155#include <mach_assert.h>
156#ifdef MACH_BSD
157#include <sys/msgbuf.h>
158#endif
159
160#ifdef __ppc__
161#include <ppc/Firmware.h>
162#endif
163
164/*
165 * Forward declarations
166 */
167void printnum(
168 register unsigned int u,
169 register int base,
170 void (*putc)(char));
171
172
173#define isdigit(d) ((d) >= '0' && (d) <= '9')
174#define Ctod(c) ((c) - '0')
175
176#define MAXBUF (sizeof(long int) * 8) /* enough for binary */
177
178void
179printnum(
180 register unsigned int u, /* number to print */
181 register int base,
182 void (*putc)(char))
183{
184 char buf[MAXBUF]; /* build number here */
185 register char * p = &buf[MAXBUF-1];
186 static char digs[] = "0123456789abcdef";
187
188 do {
189 *p-- = digs[u % base];
190 u /= base;
191 } while (u != 0);
192
193 while (++p != &buf[MAXBUF])
194 (*putc)(*p);
195
196}
197
198boolean_t _doprnt_truncates = FALSE;
199
200void
201_doprnt(
202 register const char *fmt,
203 va_list *argp,
204 /* character output routine */
205 void (*putc)(char),
206 int radix) /* default radix - for '%r' */
207{
208 int length;
209 int prec;
210 boolean_t ladjust;
211 char padc;
212 long n;
213 unsigned long u;
214 int plus_sign;
215 int sign_char;
216 boolean_t altfmt, truncate;
217 int base;
218 register char c;
219 int capitals;
220
221 while ((c = *fmt) != '\0') {
222 if (c != '%') {
223 (*putc)(c);
224 fmt++;
225 continue;
226 }
227
228 fmt++;
229
230 length = 0;
231 prec = -1;
232 ladjust = FALSE;
233 padc = ' ';
234 plus_sign = 0;
235 sign_char = 0;
236 altfmt = FALSE;
237
238 while (TRUE) {
239 c = *fmt;
240 if (c == '#') {
241 altfmt = TRUE;
242 }
243 else if (c == '-') {
244 ladjust = TRUE;
245 }
246 else if (c == '+') {
247 plus_sign = '+';
248 }
249 else if (c == ' ') {
250 if (plus_sign == 0)
251 plus_sign = ' ';
252 }
253 else
254 break;
255 fmt++;
256 }
257
258 if (c == '0') {
259 padc = '0';
260 c = *++fmt;
261 }
262
263 if (isdigit(c)) {
264 while(isdigit(c)) {
265 length = 10 * length + Ctod(c);
266 c = *++fmt;
267 }
268 }
269 else if (c == '*') {
270 length = va_arg(*argp, int);
271 c = *++fmt;
272 if (length < 0) {
273 ladjust = !ladjust;
274 length = -length;
275 }
276 }
277
278 if (c == '.') {
279 c = *++fmt;
280 if (isdigit(c)) {
281 prec = 0;
282 while(isdigit(c)) {
283 prec = 10 * prec + Ctod(c);
284 c = *++fmt;
285 }
286 }
287 else if (c == '*') {
288 prec = va_arg(*argp, int);
289 c = *++fmt;
290 }
291 }
292
293 if (c == 'l')
294 c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
295
296 truncate = FALSE;
297 capitals=0; /* Assume lower case printing */
298
299 switch(c) {
300 case 'b':
301 case 'B':
302 {
303 register char *p;
304 boolean_t any;
305 register int i;
306
307 u = va_arg(*argp, unsigned long);
308 p = va_arg(*argp, char *);
309 base = *p++;
310 printnum(u, base, putc);
311
312 if (u == 0)
313 break;
314
315 any = FALSE;
316 while ((i = *p++) != '\0') {
317 if (*fmt == 'B')
318 i = 33 - i;
319 if (*p <= 32) {
320 /*
321 * Bit field
322 */
323 register int j;
324 if (any)
325 (*putc)(',');
326 else {
327 (*putc)('<');
328 any = TRUE;
329 }
330 j = *p++;
331 if (*fmt == 'B')
332 j = 32 - j;
333 for (; (c = *p) > 32; p++)
334 (*putc)(c);
335 printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
336 base, putc);
337 }
338 else if (u & (1<<(i-1))) {
339 if (any)
340 (*putc)(',');
341 else {
342 (*putc)('<');
343 any = TRUE;
344 }
345 for (; (c = *p) > 32; p++)
346 (*putc)(c);
347 }
348 else {
349 for (; *p > 32; p++)
350 continue;
351 }
352 }
353 if (any)
354 (*putc)('>');
355 break;
356 }
357
358 case 'c':
359 c = va_arg(*argp, int);
360 (*putc)(c);
361 break;
362
363 case 's':
364 {
365 register char *p;
366 register char *p2;
367
368 if (prec == -1)
369 prec = 0x7fffffff; /* MAXINT */
370
371 p = va_arg(*argp, char *);
372
373 if (p == (char *)0)
374 p = "";
375
376 if (length > 0 && !ladjust) {
377 n = 0;
378 p2 = p;
379
380 for (; *p != '\0' && n < prec; p++)
381 n++;
382
383 p = p2;
384
385 while (n < length) {
386 (*putc)(' ');
387 n++;
388 }
389 }
390
391 n = 0;
392
393 while (*p != '\0') {
394 if (++n > prec || (length > 0 && n > length))
395 break;
396
397 (*putc)(*p++);
398 }
399
400 if (n < length && ladjust) {
401 while (n < length) {
402 (*putc)(' ');
403 n++;
404 }
405 }
406
407 break;
408 }
409
410 case 'o':
411 truncate = _doprnt_truncates;
412 case 'O':
413 base = 8;
414 goto print_unsigned;
415
416 case 'd':
417 truncate = _doprnt_truncates;
418 case 'D':
419 base = 10;
420 goto print_signed;
421
422 case 'u':
423 truncate = _doprnt_truncates;
424 case 'U':
425 base = 10;
426 goto print_unsigned;
427
428 case 'p':
429 altfmt = TRUE;
430 case 'x':
431 truncate = _doprnt_truncates;
432 base = 16;
433 goto print_unsigned;
434
435 case 'X':
436 base = 16;
437 capitals=16; /* Print in upper case */
438 goto print_unsigned;
439
440 case 'z':
441 truncate = _doprnt_truncates;
442 base = 16;
443 goto print_signed;
444
445 case 'Z':
446 base = 16;
447 capitals=16; /* Print in upper case */
448 goto print_signed;
449
450 case 'r':
451 truncate = _doprnt_truncates;
452 case 'R':
453 base = radix;
454 goto print_signed;
455
456 case 'n':
457 truncate = _doprnt_truncates;
458 case 'N':
459 base = radix;
460 goto print_unsigned;
461
462 print_signed:
463 n = va_arg(*argp, long);
464 if (n >= 0) {
465 u = n;
466 sign_char = plus_sign;
467 }
468 else {
469 u = -n;
470 sign_char = '-';
471 }
472 goto print_num;
473
474 print_unsigned:
475 u = va_arg(*argp, unsigned long);
476 goto print_num;
477
478 print_num:
479 {
480 char buf[MAXBUF]; /* build number here */
481 register char * p = &buf[MAXBUF-1];
482 static char digits[] = "0123456789abcdef0123456789ABCDEF";
483 char *prefix = 0;
484
485 if (truncate) u = (long)((int)(u));
486
487 if (u != 0 && altfmt) {
488 if (base == 8)
489 prefix = "0";
490 else if (base == 16)
491 prefix = "0x";
492 }
493
494 do {
495 /* Print in the correct case */
496 *p-- = digits[(u % base)+capitals];
497 u /= base;
498 } while (u != 0);
499
500 length -= (&buf[MAXBUF-1] - p);
501 if (sign_char)
502 length--;
503 if (prefix)
504 length -= strlen((const char *) prefix);
505
506 if (padc == ' ' && !ladjust) {
507 /* blank padding goes before prefix */
508 while (--length >= 0)
509 (*putc)(' ');
510 }
511 if (sign_char)
512 (*putc)(sign_char);
513 if (prefix)
514 while (*prefix)
515 (*putc)(*prefix++);
516 if (padc == '0') {
517 /* zero padding goes after sign and prefix */
518 while (--length >= 0)
519 (*putc)('0');
520 }
521 while (++p != &buf[MAXBUF])
522 (*putc)(*p);
523
524 if (ladjust) {
525 while (--length >= 0)
526 (*putc)(' ');
527 }
528 break;
529 }
530
531 case '\0':
532 fmt--;
533 break;
534
535 default:
536 (*putc)(c);
537 }
538 fmt++;
539 }
540}
541
542#if MP_PRINTF
543boolean_t new_printf_cpu_number = FALSE;
544#endif /* MP_PRINTF */
545
546
547decl_simple_lock_data(,printf_lock)
548decl_mutex_data(,sprintf_lock)
549
550void
551printf_init(void)
552{
553 /*
554 * Lock is only really needed after the first thread is created.
555 */
556 simple_lock_init(&printf_lock, ETAP_MISC_PRINTF);
557 mutex_init(&sprintf_lock, ETAP_MISC_PRINTF);
558}
559
560/* derived from boot_gets */
561void
562safe_gets(
563 char *str,
564 int maxlen)
565{
566 register char *lp;
567 register int c;
568 char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
569
570 lp = str;
571 for (;;) {
572 c = cngetc();
573 switch (c) {
574 case '\n':
575 case '\r':
576 printf("\n");
577 *lp++ = 0;
578 return;
579
580 case '\b':
581 case '#':
582 case '\177':
583 if (lp > str) {
584 printf("\b \b");
585 lp--;
586 }
587 continue;
588
589 case '@':
590 case 'u'&037:
591 lp = str;
592 printf("\n\r");
593 continue;
594
595 default:
596 if (c >= ' ' && c < '\177') {
597 if (lp < strmax) {
598 *lp++ = c;
599 printf("%c", c);
600 }
601 else {
602 printf("%c", '\007'); /* beep */
603 }
604 }
605 }
606 }
607}
608
609void
610conslog_putc(
611 char c)
612{
613 extern unsigned int debug_mode, disableDebugOuput, disableConsoleOutput;
614
615 if ((debug_mode && !disableDebugOuput) || !disableConsoleOutput)
616 cnputc(c);
617
618#ifdef MACH_BSD
619 log_putc(c);
620#endif
621}
622
623void
624printf(const char *fmt, ...)
625{
626 va_list listp;
627
628 disable_preemption();
629 va_start(listp, fmt);
630 _doprnt(fmt, &listp, conslog_putc, 16);
631 va_end(listp);
632 enable_preemption();
633}
634
635static char *copybyte_str;
636
637static void
638copybyte(
639 char byte)
640{
641 *copybyte_str++ = byte;
642 *copybyte_str = '\0';
643}
644
645int
646sprintf(char *buf, const char *fmt, ...)
647{
648 va_list listp;
649
650 va_start(listp, fmt);
651 mutex_lock(&sprintf_lock);
652 copybyte_str = buf;
653 _doprnt(fmt, &listp, copybyte, 16);
654 mutex_unlock(&sprintf_lock);
655 va_end(listp);
656 return strlen(buf);
657}