|
|
1.1 root 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 [email protected]
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: * Common code for printf et al.
28: *
29: * The calling routine typically takes a variable number of arguments,
30: * and passes the address of the first one. This implementation
31: * assumes a straightforward, stack implementation, aligned to the
32: * machine's wordsize. Increasing addresses are assumed to point to
33: * successive arguments (left-to-right), as is the case for a machine
34: * with a downward-growing stack with arguments pushed right-to-left.
35: *
36: * To write, for example, fprintf() using this routine, the code
37: *
38: * fprintf(fd, format, args)
39: * FILE *fd;
40: * char *format;
41: * {
1.1.1.3 root 42: * va_list listp;
43: * va_start(listp, fmt);
1.1 root 44: * _doprnt(format, &args, fd);
1.1.1.3 root 45: * va_end(listp);
1.1 root 46: * }
47: *
48: * would suffice. (This example does not handle the fprintf's "return
49: * value" correctly, but who looks at the return value of fprintf
50: * anyway?)
51: *
52: * This version implements the following printf features:
53: *
54: * %d decimal conversion
55: * %u unsigned conversion
1.1.1.3 root 56: * %p pointer address
1.1 root 57: * %x hexadecimal conversion
58: * %X hexadecimal conversion with capital letters
59: * %o octal conversion
60: * %c character
61: * %s string
62: * %m.n field width, precision
63: * %-m.n left adjustment
64: * %0m.n zero-padding
65: * %*.* width and precision taken from arguments
66: *
67: * This version does not implement %f, %e, or %g. It accepts, but
68: * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
69: * work correctly on machines for which sizeof(long) != sizeof(int).
70: * It does not even parse %D, %O, or %U; you should be using %ld, %o and
71: * %lu if you mean long conversion.
72: *
73: * As mentioned, this version does not return any reasonable value.
74: *
75: * Permission is granted to use, modify, or propagate this code as
76: * long as this notice is incorporated.
77: *
78: * Steve Summit 3/25/87
79: */
80:
81: /*
82: * Added formats for decoding device registers:
83: *
84: * printf("reg = %b", regval, "<base><arg>*")
85: *
86: * where <base> is the output base expressed as a control character:
87: * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of
88: * characters, the first of which gives the bit number to be inspected
89: * (origin 1), and the rest (up to a control character (<= 32)) give the
90: * name of the register. Thus
91: * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
92: * would produce
93: * reg = 3<BITTWO,BITONE>
94: *
95: * If the second character in <arg> is also a control character, it
96: * indicates the last bit of a bit field. In this case, printf will extract
97: * bits <1> to <2> and print it. Characters following the second control
98: * character are printed before the bit field.
99: * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
100: * would produce
101: * reg = b<FIELD1=2,BITONE>
102: */
103: /*
104: * Added for general use:
105: * # prefix for alternate format:
106: * 0x (0X) for hex
107: * leading 0 for octal
108: * + print '+' if positive
109: * blank print ' ' if positive
110: *
111: * z signed hexadecimal
112: * r signed, 'radix'
113: * n unsigned, 'radix'
114: *
115: * D,U,O,Z same as corresponding lower-case versions
116: * (compatibility)
117: */
118:
1.1.1.3 root 119: #include <string.h>
120: #include <device/cons.h>
121: #include <kern/printf.h>
1.1 root 122: #include <mach/boolean.h>
123: #include <kern/lock.h>
1.1.1.2 root 124: #include <stdarg.h>
1.1 root 125:
126: #define isdigit(d) ((d) >= '0' && (d) <= '9')
127: #define Ctod(c) ((c) - '0')
128:
1.1.1.5 ! root 129: #define MAXBUF (sizeof(long long int) * 8) /* enough for binary */
1.1 root 130:
131:
132: void printnum(
1.1.1.5 ! root 133: unsigned long long u,
1.1.1.4 root 134: int base,
1.1 root 135: void (*putc)( char, vm_offset_t ),
136: vm_offset_t putc_arg)
137: {
138: char buf[MAXBUF]; /* build number here */
1.1.1.4 root 139: char * p = &buf[MAXBUF-1];
1.1 root 140: static char digs[] = "0123456789abcdef";
141:
142: do {
143: *p-- = digs[u % base];
144: u /= base;
145: } while (u != 0);
146:
147: while (++p != &buf[MAXBUF])
148: (*putc)(*p, putc_arg);
149:
150: }
151:
152: boolean_t _doprnt_truncates = FALSE;
153:
154: void _doprnt(
1.1.1.4 root 155: const char *fmt,
1.1.1.3 root 156: va_list argp,
1.1 root 157: /* character output routine */
158: void (*putc)( char, vm_offset_t),
159: int radix, /* default radix - for '%r' */
160: vm_offset_t putc_arg)
161: {
162: int length;
163: int prec;
164: boolean_t ladjust;
165: char padc;
1.1.1.5 ! root 166: long long n;
! 167: unsigned long long u;
! 168: int have_long_long;
1.1 root 169: int plus_sign;
170: int sign_char;
171: boolean_t altfmt, truncate;
172: int base;
1.1.1.4 root 173: char c;
1.1 root 174:
175: while ((c = *fmt) != '\0') {
176: if (c != '%') {
177: (*putc)(c, putc_arg);
178: fmt++;
179: continue;
180: }
181:
182: fmt++;
183:
184: length = 0;
185: prec = -1;
186: ladjust = FALSE;
187: padc = ' ';
188: plus_sign = 0;
189: sign_char = 0;
190: altfmt = FALSE;
1.1.1.5 ! root 191: have_long_long = FALSE;
1.1 root 192:
193: while (TRUE) {
194: c = *fmt;
195: if (c == '#') {
196: altfmt = TRUE;
197: }
198: else if (c == '-') {
199: ladjust = TRUE;
200: }
201: else if (c == '+') {
202: plus_sign = '+';
203: }
204: else if (c == ' ') {
205: if (plus_sign == 0)
206: plus_sign = ' ';
207: }
208: else
209: break;
210: fmt++;
211: }
212:
213: if (c == '0') {
214: padc = '0';
215: c = *++fmt;
216: }
217:
218: if (isdigit(c)) {
219: while(isdigit(c)) {
220: length = 10 * length + Ctod(c);
221: c = *++fmt;
222: }
223: }
224: else if (c == '*') {
1.1.1.3 root 225: length = va_arg(argp, int);
1.1 root 226: c = *++fmt;
227: if (length < 0) {
228: ladjust = !ladjust;
229: length = -length;
230: }
231: }
232:
233: if (c == '.') {
234: c = *++fmt;
235: if (isdigit(c)) {
236: prec = 0;
237: while(isdigit(c)) {
238: prec = 10 * prec + Ctod(c);
239: c = *++fmt;
240: }
241: }
242: else if (c == '*') {
1.1.1.3 root 243: prec = va_arg(argp, int);
1.1 root 244: c = *++fmt;
245: }
246: }
247:
248: if (c == 'l')
249: c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
1.1.1.5 ! root 250: if (c == 'l') {
! 251: c = *++fmt; /* handle `long long' */
! 252: have_long_long = TRUE;
! 253: }
1.1 root 254:
255: truncate = FALSE;
256:
257: switch(c) {
258: case 'b':
259: case 'B':
260: {
1.1.1.4 root 261: char *p;
262: boolean_t any;
263: int i;
1.1 root 264:
1.1.1.5 ! root 265: if (! have_long_long)
! 266: u = va_arg(argp, unsigned long);
! 267: else
! 268: u = va_arg(argp, unsigned long long);
1.1.1.3 root 269: p = va_arg(argp, char *);
1.1 root 270: base = *p++;
271: printnum(u, base, putc, putc_arg);
272:
273: if (u == 0)
274: break;
275:
276: any = FALSE;
1.1.1.3 root 277: while ((i = *p++)) {
1.1 root 278: /* NOTE: The '32' here is because ascii space */
279: if (*p <= 32) {
280: /*
281: * Bit field
282: */
1.1.1.4 root 283: int j;
1.1 root 284: if (any)
285: (*putc)(',', putc_arg);
286: else {
287: (*putc)('<', putc_arg);
288: any = TRUE;
289: }
290: j = *p++;
291: for (; (c = *p) > 32; p++)
292: (*putc)(c, putc_arg);
293: printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
294: base, putc, putc_arg);
295: }
296: else if (u & (1<<(i-1))) {
297: if (any)
298: (*putc)(',', putc_arg);
299: else {
300: (*putc)('<', putc_arg);
301: any = TRUE;
302: }
303: for (; (c = *p) > 32; p++)
304: (*putc)(c, putc_arg);
305: }
306: else {
307: for (; *p > 32; p++)
308: continue;
309: }
310: }
311: if (any)
312: (*putc)('>', putc_arg);
313: break;
314: }
315:
316: case 'c':
1.1.1.3 root 317: c = va_arg(argp, int);
1.1 root 318: (*putc)(c, putc_arg);
319: break;
320:
321: case 's':
322: {
1.1.1.4 root 323: char *p;
324: char *p2;
1.1 root 325:
326: if (prec == -1)
327: prec = 0x7fffffff; /* MAXINT */
328:
1.1.1.3 root 329: p = va_arg(argp, char *);
1.1 root 330:
331: if (p == (char *)0)
332: p = "";
333:
334: if (length > 0 && !ladjust) {
335: n = 0;
336: p2 = p;
337:
338: for (; *p != '\0' && n < prec; p++)
339: n++;
340:
341: p = p2;
342:
343: while (n < length) {
344: (*putc)(' ', putc_arg);
345: n++;
346: }
347: }
348:
349: n = 0;
350:
351: while (*p != '\0') {
352: if (++n > prec)
353: break;
354:
355: (*putc)(*p++, putc_arg);
356: }
357:
358: if (n < length && ladjust) {
359: while (n < length) {
360: (*putc)(' ', putc_arg);
361: n++;
362: }
363: }
364:
365: break;
366: }
367:
368: case 'o':
369: truncate = _doprnt_truncates;
370: case 'O':
371: base = 8;
372: goto print_unsigned;
373:
374: case 'd':
375: truncate = _doprnt_truncates;
376: case 'D':
377: base = 10;
378: goto print_signed;
379:
380: case 'u':
381: truncate = _doprnt_truncates;
382: case 'U':
383: base = 10;
384: goto print_unsigned;
385:
1.1.1.3 root 386: case 'p':
1.1 root 387: case 'x':
388: truncate = _doprnt_truncates;
389: case 'X':
390: base = 16;
391: goto print_unsigned;
392:
393: case 'z':
394: truncate = _doprnt_truncates;
395: case 'Z':
396: base = 16;
397: goto print_signed;
398:
399: case 'r':
400: truncate = _doprnt_truncates;
401: case 'R':
402: base = radix;
403: goto print_signed;
404:
405: case 'n':
406: truncate = _doprnt_truncates;
407: case 'N':
408: base = radix;
409: goto print_unsigned;
410:
411: print_signed:
1.1.1.5 ! root 412: if (! have_long_long)
! 413: n = va_arg(argp, long);
! 414: else
! 415: n = va_arg(argp, long long);
1.1 root 416: if (n >= 0) {
417: u = n;
418: sign_char = plus_sign;
419: }
420: else {
421: u = -n;
422: sign_char = '-';
423: }
424: goto print_num;
425:
426: print_unsigned:
1.1.1.5 ! root 427: if (! have_long_long)
! 428: u = va_arg(argp, unsigned long);
! 429: else
! 430: u = va_arg(argp, unsigned long long);
1.1 root 431: goto print_num;
432:
433: print_num:
434: {
435: char buf[MAXBUF]; /* build number here */
1.1.1.4 root 436: char * p = &buf[MAXBUF-1];
1.1 root 437: static char digits[] = "0123456789abcdef";
438: char *prefix = 0;
439:
440: if (truncate) u = (long)((int)(u));
441:
442: if (u != 0 && altfmt) {
443: if (base == 8)
444: prefix = "0";
445: else if (base == 16)
446: prefix = "0x";
447: }
448:
449: do {
450: *p-- = digits[u % base];
451: u /= base;
452: } while (u != 0);
453:
454: length -= (&buf[MAXBUF-1] - p);
455: if (sign_char)
456: length--;
457: if (prefix)
458: length -= strlen(prefix);
459:
460: if (padc == ' ' && !ladjust) {
461: /* blank padding goes before prefix */
462: while (--length >= 0)
463: (*putc)(' ', putc_arg);
464: }
465: if (sign_char)
466: (*putc)(sign_char, putc_arg);
467: if (prefix)
468: while (*prefix)
469: (*putc)(*prefix++, putc_arg);
470: if (padc == '0') {
471: /* zero padding goes after sign and prefix */
472: while (--length >= 0)
473: (*putc)('0', putc_arg);
474: }
475: while (++p != &buf[MAXBUF])
476: (*putc)(*p, putc_arg);
477:
478: if (ladjust) {
479: while (--length >= 0)
480: (*putc)(' ', putc_arg);
481: }
482: break;
483: }
484:
485: case '\0':
486: fmt--;
487: break;
488:
489: default:
490: (*putc)(c, putc_arg);
491: }
492: fmt++;
493: }
494: }
495:
496: /*
497: * Printing (to console)
498: */
499:
1.1.1.3 root 500: int vprintf(const char *fmt, va_list listp)
1.1 root 501: {
1.1.1.3 root 502: _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
503: return 0;
1.1 root 504: }
505:
506: /*VARARGS1*/
1.1.1.3 root 507: int printf(const char *fmt, ...)
1.1 root 508: {
509: va_list listp;
1.1.1.2 root 510: va_start(listp, fmt);
1.1 root 511: vprintf(fmt, listp);
512: va_end(listp);
1.1.1.3 root 513: return 0;
1.1 root 514: }
515:
516: int indent = 0;
517:
518: /*
519: * Printing (to console) with indentation.
520: */
521: /*VARARGS1*/
1.1.1.2 root 522: void iprintf(const char *fmt, ...)
1.1 root 523: {
524: va_list listp;
1.1.1.4 root 525: int i;
1.1 root 526:
527: for (i = indent; i > 0; ){
528: if (i >= 8) {
529: printf("\t");
530: i -= 8;
531: }
532: else {
533: printf(" ");
534: i--;
535: }
536: }
1.1.1.2 root 537: va_start(listp, fmt);
1.1.1.3 root 538: _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
1.1 root 539: va_end(listp);
540: }
541:
542: /*
543: * Printing to generic buffer
544: * Returns #bytes printed.
545: * Strings are zero-terminated.
546: */
547: static void
548: sputc(
549: char c,
550: vm_offset_t arg)
551: {
1.1.1.4 root 552: char **bufp = (char **) arg;
553: char *p = *bufp;
1.1 root 554: *p++ = c;
555: *bufp = p;
556: }
557:
558: int
1.1.1.2 root 559: sprintf(char *buf, const char *fmt, ...)
1.1 root 560: {
561: va_list listp;
562: char *start = buf;
563:
1.1.1.2 root 564: va_start(listp, fmt);
1.1.1.3 root 565: _doprnt(fmt, listp, sputc, 16, (vm_offset_t)&buf);
1.1 root 566: va_end(listp);
567:
568: *buf = 0;
569: return (buf - start);
570: }
571:
1.1.1.3 root 572: struct vsnprintf_cookie
573: {
574: char *buf;
575: int index;
576: int max_len;
577: };
578:
579: static void
580: snputc(char c, vm_offset_t arg)
581: {
582: struct vsnprintf_cookie *cookie = (void *) arg;
583:
584: if (cookie->index < cookie->max_len)
585: cookie->buf[cookie->index ++] = c;
586: }
587:
588: int
589: vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
590: {
591: struct vsnprintf_cookie cookie
592: = { .buf = buf, .index = 0, .max_len = size };
593:
594: _doprnt (fmt, args, snputc, 16, (vm_offset_t)&cookie);
595: cookie.buf[cookie.index] = '\0';
596:
597: return cookie.index;
598: }
599:
1.1.1.4 root 600: int
601: snprintf(char *buf, size_t size, const char *fmt, ...)
602: {
603: int written;
604: va_list listp;
605: va_start(listp, fmt);
606: written = vsnprintf(buf, size, fmt, listp);
607: va_end(listp);
608: return written;
609: }
1.1 root 610:
1.1.1.4 root 611: void safe_gets(
612: char *str,
613: int maxlen)
1.1 root 614: {
1.1.1.4 root 615: char *lp;
616: int c;
1.1 root 617: char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
618:
619: lp = str;
620: for (;;) {
621: c = cngetc();
622: switch (c) {
623: case '\n':
624: case '\r':
625: printf("\n");
626: *lp++ = 0;
627: return;
628:
629: case '\b':
630: case '#':
631: case '\177':
632: if (lp > str) {
633: printf("\b \b");
634: lp--;
635: }
636: continue;
637:
638: case '@':
639: case 'u'&037:
640: lp = str;
641: printf("\n\r");
642: continue;
643:
644: default:
645: if (c >= ' ' && c < '\177') {
646: if (lp < strmax) {
647: *lp++ = c;
648: printf("%c", c);
649: }
650: else {
651: printf("%c", '\007'); /* beep */
652: }
653: }
654: }
655: }
656: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.