]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/subr_prf.c
814ac7056e526f1fddd44ad76d679084e202a020
[apple/xnu.git] / bsd / kern / subr_prf.c
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 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*-
24 * Copyright (c) 1986, 1988, 1991, 1993
25 * The Regents of the University of California. All rights reserved.
26 * (c) UNIX System Laboratories, Inc.
27 * All or some portions of this file are derived from material licensed
28 * to the University of California by American Telephone and Telegraph
29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
30 * the permission of UNIX System Laboratories, Inc.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)subr_prf.c 8.4 (Berkeley) 5/4/95
61 */
62 /* HISTORY
63 * 22-Sep-1997 Umesh Vaishampayan (umeshv@apple.com)
64 * Cleaned up m68k crud. Fixed vlog() to do logpri() for ppc, too.
65 *
66 * 17-July-97 Umesh Vaishampayan (umeshv@apple.com)
67 * Eliminated multiple definition of constty which is defined
68 * in bsd/dev/XXX/cons.c
69 *
70 * 26-MAR-1997 Umesh Vaishampayan (umeshv@NeXT.com
71 * Fixed tharshing format in many functions. Cleanup.
72 *
73 * 17-Jun-1995 Mac Gillon (mgillon) at NeXT
74 * Purged old history
75 * New version based on 4.4 and NS3.3
76 */
77
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/buf.h>
81 #include <sys/conf.h>
82 #include <sys/reboot.h>
83 #include <sys/msgbuf.h>
84 #include <sys/proc.h>
85 #include <sys/ioctl.h>
86 #include <sys/tty.h>
87 #include <sys/file.h>
88 #include <sys/tprintf.h>
89 #include <sys/syslog.h>
90 #include <stdarg.h>
91 #include <sys/malloc.h>
92 #include <sys/lock.h>
93 #include <kern/parallel.h>
94 #include <sys/subr_prf.h>
95
96 #include <kern/cpu_number.h> /* for cpu_number() */
97 #include <machine/spl.h>
98 #include <libkern/libkern.h>
99
100 struct snprintf_arg {
101 char *str;
102 size_t remain;
103 };
104
105
106 /*
107 * In case console is off,
108 * panicstr contains argument to last
109 * call to panic.
110 */
111 extern const char *panicstr;
112
113 extern cnputc(); /* standard console putc */
114 int (*v_putc)() = cnputc; /* routine to putc on virtual console */
115
116 extern struct tty cons; /* standard console tty */
117 extern struct tty *constty; /* pointer to console "window" tty */
118
119 /*
120 * Record cpu that panic'd and lock around panic data
121 */
122
123 static void puts(const char *s, int flags, struct tty *ttyp);
124 static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld_size);
125
126 /* MP printf stuff */
127 decl_simple_lock_data(,printf_lock)
128 #if NCPUS > 1
129 boolean_t new_printf_cpu_number; /* do we need to output who we are */
130 #endif
131
132 extern void logwakeup();
133 extern void halt_cpu();
134 extern boot();
135 int putchar();
136
137 static void
138 snprintf_func(int ch, void *arg);
139
140
141
142 /*
143 * Uprintf prints to the controlling terminal for the current process.
144 * It may block if the tty queue is overfull. No message is printed if
145 * the queue does not clear in a reasonable time.
146 */
147 void
148 uprintf(const char *fmt, ...)
149 {
150 register struct proc *p = current_proc();
151 va_list ap;
152
153 unix_master(); /* sessions, sigh */
154 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
155 va_start(ap, fmt);
156 prf(fmt, ap, TOTTY, (struct tty *)p->p_session->s_ttyvp);
157 va_end(ap);
158 }
159 unix_release();
160 }
161
162 tpr_t
163 tprintf_open(p)
164 register struct proc *p;
165 {
166 unix_master(); /* sessions, sigh */
167 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
168 SESSHOLD(p->p_session);
169 unix_release();
170 return ((tpr_t) p->p_session);
171 }
172 unix_release();
173 return ((tpr_t) NULL);
174 }
175
176 void
177 tprintf_close(sess)
178 tpr_t sess;
179 {
180 unix_master(); /* sessions, sigh */
181 if (sess)
182 SESSRELE((struct session *) sess);
183 unix_release();
184 }
185
186 /*
187 * tprintf prints on the controlling terminal associated
188 * with the given session.
189 */
190 void
191 tprintf(tpr_t tpr, const char *fmt, ...)
192 {
193 register struct session *sess = (struct session *)tpr;
194 struct tty *tp = NULL;
195 int flags = TOLOG;
196 va_list ap;
197
198 logpri(LOG_INFO);
199 unix_master(); /* sessions, sigh */
200 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
201 flags |= TOTTY;
202 tp = sess->s_ttyp;
203 }
204 if (tp != NULL) {
205 va_start(ap, fmt);
206 prf(fmt, ap, TOTTY, tp);
207 va_end(ap);
208 }
209 unix_release();
210 logwakeup();
211 }
212
213 /*
214 * Ttyprintf displays a message on a tty; it should be used only by
215 * the tty driver, or anything that knows the underlying tty will not
216 * be revoke(2)'d away. Other callers should use tprintf.
217 */
218 void
219 ttyprintf(struct tty *tp, const char *fmt, ...)
220 {
221 va_list ap;
222
223 if (tp != NULL) {
224 va_start(ap, fmt);
225 prf(fmt, ap, TOTTY, tp);
226 va_end(ap);
227 }
228 }
229
230 extern int log_open;
231
232
233 void
234 logpri(level)
235 int level;
236 {
237
238 putchar('<', TOLOG, (struct tty *)0);
239 printn((u_long)level, 10, TOLOG, (struct tty *)0, 0, 0);
240 putchar('>', TOLOG, (struct tty *)0);
241 }
242
243 void
244 addlog(const char *fmt, ...)
245 {
246 register s = splhigh();
247 va_list ap;
248
249 va_start(ap, fmt);
250 prf(fmt, ap, TOLOG, (struct tty *)0);
251 splx(s);
252 if (!log_open)
253 prf(fmt, ap, TOCONS, (struct tty *)0);
254 va_end(ap);
255 logwakeup();
256 }
257 void _printf(int flags, struct tty *ttyp, const char *format, ...)
258 {
259 va_list ap;
260
261 va_start(ap, format);
262 prf(format, ap, flags, ttyp);
263 va_end(ap);
264 }
265
266 int prf(const char *fmt, va_list ap, int flags, struct tty *ttyp)
267 {
268 register int b, c, i;
269 char *s;
270 int any;
271 int zf = 0, fld_size;
272
273 #if NCPUS > 1
274 int cpun = cpu_number();
275
276 if(ttyp == 0) {
277 simple_lock(&printf_lock);
278 } else
279 TTY_LOCK(ttyp);
280
281 if (cpun != master_cpu)
282 new_printf_cpu_number = TRUE;
283
284 if (new_printf_cpu_number) {
285 putchar('{', flags, ttyp);
286 printn((u_long)cpun, 10, flags, ttyp, 0, 0);
287 putchar('}', flags, ttyp);
288 }
289 #endif /* NCPUS > 1 */
290 loop:
291 while ((c = *fmt++) != '%') {
292 if (c == '\0') {
293 #if NCPUS > 1
294 if(ttyp == 0) {
295 simple_unlock(&printf_lock);
296 } else
297 TTY_UNLOCK(ttyp);
298 #endif
299 return 0;
300 }
301 putchar(c, flags, ttyp);
302 }
303 again:
304 zf = 0;
305 fld_size = 0;
306 c = *fmt++;
307 if (c == '0')
308 zf = '0';
309 fld_size = 0;
310 for (;c <= '9' && c >= '0'; c = *fmt++)
311 fld_size = fld_size * 10 + c - '0';
312
313 /* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */
314 switch (c) {
315
316 case 'l':
317 goto again;
318 case 'x': case 'X':
319 b = 16;
320 goto number;
321 case 'd': case 'D':
322 case 'u': /* what a joke */
323 b = 10;
324 goto number;
325 case 'o': case 'O':
326 b = 8;
327 number:
328 printn(va_arg(ap, unsigned), b, flags, ttyp, zf, fld_size);
329 break;
330 case 'c':
331 b = va_arg(ap, unsigned);
332 #if BYTE_ORDER == LITTLE_ENDIAN
333 for (i = 24; i >= 0; i -= 8)
334 if (c = (b >> i) & 0x7f)
335 putchar(c, flags, ttyp);
336 #endif
337 #if BYTE_ORDER == BIG_ENDIAN
338 if ((c = (b & 0x7f)))
339 putchar(c, flags, ttyp);
340 #endif
341 break;
342 case 'b':
343 b = va_arg(ap, unsigned);
344 s = va_arg(ap, char *);
345 printn((u_long)b, *s++, flags, ttyp, 0, 0);
346 any = 0;
347 if (b) {
348 while ((i = *s++)) {
349 if (*s <= 32) {
350 register int j;
351
352 if (any++)
353 putchar(',', flags, ttyp);
354 j = *s++ ;
355 for (; (c = *s) > 32 ; s++)
356 putchar(c, flags, ttyp);
357 printn( (u_long)( (b >> (j-1)) &
358 ( (2 << (i-j)) -1)),
359 8, flags, ttyp, 0, 0);
360 } else if (b & (1 << (i-1))) {
361 putchar(any? ',' : '<', flags, ttyp);
362 any = 1;
363 for (; (c = *s) > 32; s++)
364 putchar(c, flags, ttyp);
365 } else
366 for (; *s > 32; s++)
367 ;
368 }
369 putchar('>', flags, ttyp);
370 }
371 break;
372
373 case 's':
374 s = va_arg(ap, char *);
375 #ifdef DEBUG
376 if (fld_size) {
377 while (fld_size-- > 0)
378 putchar((c = *s++)? c : '_', flags, ttyp);
379 } else {
380 while ((c = *s++))
381 putchar(c, flags, ttyp);
382 }
383 #else
384 while (c = *s++)
385 putchar(c, flags, ttyp);
386 #endif
387 break;
388
389 case '%':
390 putchar('%', flags, ttyp);
391 goto loop;
392 case 'C':
393 b = va_arg(ap, unsigned);
394 #if BYTE_ORDER == LITTLE_ENDIAN
395 for (i = 24; i >= 0; i -= 8)
396 if (c = (b >> i) & 0x7f)
397 putchar(c, flags, ttyp);
398 #endif
399 #if BYTE_ORDER == BIG_ENDIAN
400 if ((c = (b & 0x7f)))
401 putchar(c, flags, ttyp);
402 #endif
403
404 case 'r':
405 case 'R':
406 b = va_arg(ap, unsigned);
407 s = va_arg(ap, char *);
408 if (c == 'R') {
409 puts("0x", flags, ttyp);
410 printn((u_long)b, 16, flags, ttyp, 0, 0);
411 }
412 any = 0;
413 if (c == 'r' || b) {
414 register struct reg_desc *rd;
415 register struct reg_values *rv;
416 unsigned field;
417
418 putchar('<', flags, ttyp);
419 for (rd = (struct reg_desc *)s; rd->rd_mask; rd++) {
420 field = b & rd->rd_mask;
421 field = (rd->rd_shift > 0)
422 ? field << rd->rd_shift
423 : field >> -rd->rd_shift;
424 if (any &&
425 (rd->rd_format || rd->rd_values
426 || (rd->rd_name && field)
427 )
428 )
429 putchar(',', flags, ttyp);
430 if (rd->rd_name) {
431 if (rd->rd_format || rd->rd_values
432 || field) {
433 puts(rd->rd_name, flags, ttyp);
434 any = 1;
435 }
436 if (rd->rd_format || rd->rd_values) {
437 putchar('=', flags, ttyp);
438 any = 1;
439 }
440 }
441 if (rd->rd_format) {
442 _printf(flags, ttyp, rd->rd_format,
443 field);
444 any = 1;
445 if (rd->rd_values)
446 putchar(':', flags, ttyp);
447 }
448 if (rd->rd_values) {
449 any = 1;
450 for (rv = rd->rd_values;
451 rv->rv_name;
452 rv++) {
453 if (field == rv->rv_value) {
454 puts(rv->rv_name, flags,
455 ttyp);
456 break;
457 }
458 }
459 if (rv->rv_name == NULL)
460 puts("???", flags, ttyp);
461 }
462 }
463 putchar('>', flags, ttyp);
464 }
465 break;
466
467 case 'n':
468 case 'N':
469 {
470 register struct reg_values *rv;
471
472 b = va_arg(ap, unsigned);
473 s = va_arg(ap,char *);
474 for (rv = (struct reg_values *)s; rv->rv_name; rv++) {
475 if (b == rv->rv_value) {
476 puts(rv->rv_name, flags, ttyp);
477 break;
478 }
479 }
480 if (rv->rv_name == NULL)
481 puts("???", flags, ttyp);
482 if (c == 'N' || rv->rv_name == NULL) {
483 putchar(':', flags, ttyp);
484 printn((u_long)b, 10, flags, ttyp, 0, 0);
485 }
486 }
487 break;
488 }
489 goto loop;
490 }
491
492 static void puts(const char *s, int flags, struct tty *ttyp)
493 {
494 register char c;
495
496 while ((c = *s++))
497 putchar(c, flags, ttyp);
498 }
499
500 /*
501 * Printn prints a number n in base b.
502 * We don't use recursion to avoid deep kernel stacks.
503 */
504 static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld_size)
505 {
506 char prbuf[11];
507 register char *cp;
508
509 if (b == 10 && (int)n < 0) {
510 putchar('-', flags, ttyp);
511 n = (unsigned)(-(int)n);
512 }
513 cp = prbuf;
514 do {
515 *cp++ = "0123456789abcdef"[n%b];
516 n /= b;
517 } while (n);
518 if (fld_size) {
519 for (fld_size -= cp - prbuf; fld_size > 0; fld_size--)
520 if (zf)
521 putchar('0', flags, ttyp);
522 else
523 putchar(' ', flags, ttyp);
524 }
525 do
526 putchar(*--cp, flags, ttyp);
527 while (cp > prbuf);
528 }
529
530
531
532 /*
533 * Warn that a system table is full.
534 */
535 void tablefull(const char *tab)
536 {
537 log(LOG_ERR, "%s: table is full\n", tab);
538 }
539
540 /*
541 * Print a character on console or users terminal.
542 * If destination is console then the last MSGBUFS characters
543 * are saved in msgbuf for inspection later.
544 */
545 /*ARGSUSED*/
546 int
547 putchar(c, flags, tp)
548 register int c;
549 struct tty *tp;
550 {
551 register struct msgbuf *mbp;
552 char **sp = (char**) tp;
553
554 if (panicstr)
555 constty = 0;
556 if ((flags & TOCONS) && tp == NULL && constty) {
557 tp = constty;
558 flags |= TOTTY;
559 }
560 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
561 (flags & TOCONS) && tp == constty)
562 constty = 0;
563 if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177)
564 log_putc(c);
565 if ((flags & TOCONS) && constty == 0 && c != '\0')
566 (*v_putc)(c);
567 if (flags & TOSTR) {
568 **sp = c;
569 (*sp)++;
570 }
571 return 0;
572 }
573
574
575
576 /*
577 * Scaled down version of vsprintf(3).
578 */
579 int
580 vsprintf(char *buf, const char *cfmt, va_list ap)
581 {
582 int retval;
583
584 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
585 buf[retval] = '\0';
586 return retval;
587 }
588
589 /*
590 * Scaled down version of snprintf(3).
591 */
592 int
593 snprintf(char *str, size_t size, const char *format, ...)
594 {
595 int retval;
596 va_list ap;
597
598 va_start(ap, format);
599 retval = vsnprintf(str, size, format, ap);
600 va_end(ap);
601 return(retval);
602 }
603
604 /*
605 * Scaled down version of vsnprintf(3).
606 */
607 int
608 vsnprintf(char *str, size_t size, const char *format, va_list ap)
609 {
610 struct snprintf_arg info;
611 int retval;
612
613 info.str = str;
614 info.remain = size;
615 retval = kvprintf(format, snprintf_func, &info, 10, ap);
616 if (info.remain >= 1)
617 *info.str++ = '\0';
618 return retval;
619 }
620
621 static void
622 snprintf_func(int ch, void *arg)
623 {
624 struct snprintf_arg *const info = arg;
625
626 if (info->remain >= 2) {
627 *info->str++ = ch;
628 info->remain--;
629 }
630 }
631
632 /*
633 * Put a number (base <= 16) in a buffer in reverse order; return an
634 * optional length and a pointer to the NULL terminated (preceded?)
635 * buffer.
636 */
637 static char *
638 ksprintn(ul, base, lenp)
639 register u_long ul;
640 register int base, *lenp;
641 { /* A long in base 8, plus NULL. */
642 static char buf[sizeof(long) * NBBY / 3 + 2];
643 register char *p;
644
645 p = buf;
646 do {
647 *++p = hex2ascii(ul % base);
648 } while (ul /= base);
649 if (lenp)
650 *lenp = p - buf;
651 return (p);
652 }
653
654 /*
655 * Scaled down version of printf(3).
656 *
657 * Two additional formats:
658 *
659 * The format %b is supported to decode error registers.
660 * Its usage is:
661 *
662 * printf("reg=%b\n", regval, "<base><arg>*");
663 *
664 * where <base> is the output base expressed as a control character, e.g.
665 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
666 * the first of which gives the bit number to be inspected (origin 1), and
667 * the next characters (up to a control character, i.e. a character <= 32),
668 * give the name of the register. Thus:
669 *
670 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
671 *
672 * would produce output:
673 *
674 * reg=3<BITTWO,BITONE>
675 *
676 * XXX: %D -- Hexdump, takes pointer and separator string:
677 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
678 * ("%*D", len, ptr, " " -> XX XX XX XX ...
679 */
680 int
681 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
682 {
683 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
684 char *p, *q, *d;
685 u_char *up;
686 int ch, n;
687 u_long ul;
688 int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
689 int dwidth;
690 char padc;
691 int retval = 0;
692
693 if (!func)
694 d = (char *) arg;
695 else
696 d = NULL;
697
698 if (fmt == NULL)
699 fmt = "(fmt null)\n";
700
701 if (radix < 2 || radix > 36)
702 radix = 10;
703
704 for (;;) {
705 padc = ' ';
706 width = 0;
707 while ((ch = (u_char)*fmt++) != '%') {
708 if (ch == '\0')
709 return retval;
710 PCHAR(ch);
711 }
712 lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
713 sign = 0; dot = 0; dwidth = 0;
714 reswitch: switch (ch = (u_char)*fmt++) {
715 case '.':
716 dot = 1;
717 goto reswitch;
718 case '#':
719 sharpflag = 1;
720 goto reswitch;
721 case '+':
722 sign = 1;
723 goto reswitch;
724 case '-':
725 ladjust = 1;
726 goto reswitch;
727 case '%':
728 PCHAR(ch);
729 break;
730 case '*':
731 if (!dot) {
732 width = va_arg(ap, int);
733 if (width < 0) {
734 ladjust = !ladjust;
735 width = -width;
736 }
737 } else {
738 dwidth = va_arg(ap, int);
739 }
740 goto reswitch;
741 case '0':
742 if (!dot) {
743 padc = '0';
744 goto reswitch;
745 }
746 case '1': case '2': case '3': case '4':
747 case '5': case '6': case '7': case '8': case '9':
748 for (n = 0;; ++fmt) {
749 n = n * 10 + ch - '0';
750 ch = *fmt;
751 if (ch < '0' || ch > '9')
752 break;
753 }
754 if (dot)
755 dwidth = n;
756 else
757 width = n;
758 goto reswitch;
759 case 'b':
760 ul = va_arg(ap, int);
761 p = va_arg(ap, char *);
762 for (q = ksprintn(ul, *p++, NULL); *q;)
763 PCHAR(*q--);
764
765 if (!ul)
766 break;
767
768 for (tmp = 0; *p;) {
769 n = *p++;
770 if (ul & (1 << (n - 1))) {
771 PCHAR(tmp ? ',' : '<');
772 for (; (n = *p) > ' '; ++p)
773 PCHAR(n);
774 tmp = 1;
775 } else
776 for (; *p > ' '; ++p)
777 continue;
778 }
779 if (tmp)
780 PCHAR('>');
781 break;
782 case 'c':
783 PCHAR(va_arg(ap, int));
784 break;
785 case 'D':
786 up = va_arg(ap, u_char *);
787 p = va_arg(ap, char *);
788 if (!width)
789 width = 16;
790 while(width--) {
791 PCHAR(hex2ascii(*up >> 4));
792 PCHAR(hex2ascii(*up & 0x0f));
793 up++;
794 if (width)
795 for (q=p;*q;q++)
796 PCHAR(*q);
797 }
798 break;
799 case 'd':
800 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
801 sign = 1;
802 base = 10;
803 goto number;
804 case 'l':
805 lflag = 1;
806 goto reswitch;
807 case 'o':
808 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
809 base = 8;
810 goto nosign;
811 case 'p':
812 ul = (uintptr_t)va_arg(ap, void *);
813 base = 16;
814 sharpflag = (width == 0);
815 goto nosign;
816 case 'n':
817 case 'r':
818 ul = lflag ? va_arg(ap, u_long) :
819 sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int);
820 base = radix;
821 goto number;
822 case 's':
823 p = va_arg(ap, char *);
824 if (p == NULL)
825 p = "(null)";
826 if (!dot)
827 n = strlen (p);
828 else
829 for (n = 0; n < dwidth && p[n]; n++)
830 continue;
831
832 width -= n;
833
834 if (!ladjust && width > 0)
835 while (width--)
836 PCHAR(padc);
837 while (n--)
838 PCHAR(*p++);
839 if (ladjust && width > 0)
840 while (width--)
841 PCHAR(padc);
842 break;
843 case 'u':
844 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
845 base = 10;
846 goto nosign;
847 case 'x':
848 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
849 base = 16;
850 goto nosign;
851 case 'z':
852 ul = lflag ? va_arg(ap, u_long) :
853 sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int);
854 base = 16;
855 goto number;
856 nosign: sign = 0;
857 number: if (sign && (long)ul < 0L) {
858 neg = 1;
859 ul = -(long)ul;
860 }
861 p = ksprintn(ul, base, &tmp);
862 if (sharpflag && ul != 0) {
863 if (base == 8)
864 tmp++;
865 else if (base == 16)
866 tmp += 2;
867 }
868 if (neg)
869 tmp++;
870
871 if (!ladjust && width && (width -= tmp) > 0)
872 while (width--)
873 PCHAR(padc);
874 if (neg)
875 PCHAR('-');
876 if (sharpflag && ul != 0) {
877 if (base == 8) {
878 PCHAR('0');
879 } else if (base == 16) {
880 PCHAR('0');
881 PCHAR('x');
882 }
883 }
884
885 while (*p)
886 PCHAR(*p--);
887
888 if (ladjust && width && (width -= tmp) > 0)
889 while (width--)
890 PCHAR(padc);
891
892 break;
893 default:
894 PCHAR('%');
895 if (lflag)
896 PCHAR('l');
897 PCHAR(ch);
898 break;
899 }
900 }
901 #undef PCHAR
902 }