]>
Commit | Line | Data |
---|---|---|
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 | */ | |
167 | void 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 | ||
178 | void | |
179 | printnum( | |
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 | ||
198 | boolean_t _doprnt_truncates = FALSE; | |
199 | ||
200 | void | |
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 | |
543 | boolean_t new_printf_cpu_number = FALSE; | |
544 | #endif /* MP_PRINTF */ | |
545 | ||
546 | ||
547 | decl_simple_lock_data(,printf_lock) | |
548 | decl_mutex_data(,sprintf_lock) | |
549 | ||
550 | void | |
551 | printf_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 */ | |
561 | void | |
562 | safe_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 | ||
609 | void | |
610 | conslog_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 | ||
623 | void | |
624 | printf(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 | ||
635 | static char *copybyte_str; | |
636 | ||
637 | static void | |
638 | copybyte( | |
639 | char byte) | |
640 | { | |
641 | *copybyte_str++ = byte; | |
642 | *copybyte_str = '\0'; | |
643 | } | |
644 | ||
645 | int | |
646 | sprintf(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 | } |