|
|
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:
129: #define MAXBUF (sizeof(long int) * 8) /* enough for binary */
130:
131:
132: void printnum(
1.1.1.4 ! root 133: unsigned long u,
! 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: /* printf could be called at _any_ point during system initialization,
155: including before printf_init() gets called from the "normal" place
156: in kern/startup.c. */
157: boolean_t _doprnt_lock_initialized = FALSE;
158: decl_simple_lock_data(,_doprnt_lock)
159:
1.1.1.3 root 160: void printf_init(void)
1.1 root 161: {
162: if (!_doprnt_lock_initialized)
163: {
164: _doprnt_lock_initialized = TRUE;
165: simple_lock_init(&_doprnt_lock);
166: }
167: }
168:
169: void _doprnt(
1.1.1.4 ! root 170: const char *fmt,
1.1.1.3 root 171: va_list argp,
1.1 root 172: /* character output routine */
173: void (*putc)( char, vm_offset_t),
174: int radix, /* default radix - for '%r' */
175: vm_offset_t putc_arg)
176: {
177: int length;
178: int prec;
179: boolean_t ladjust;
180: char padc;
181: long n;
182: unsigned long u;
183: int plus_sign;
184: int sign_char;
185: boolean_t altfmt, truncate;
186: int base;
1.1.1.4 ! root 187: char c;
1.1 root 188:
189: printf_init();
190:
191: #if 0
192: /* Make sure that we get *some* printout, no matter what */
193: simple_lock(&_doprnt_lock);
194: #else
195: {
1.1.1.4 ! root 196: int i = 0;
1.1 root 197: while (i < 1*1024*1024) {
198: if (simple_lock_try(&_doprnt_lock))
199: break;
200: i++;
201: }
202: }
203: #endif
204:
205: while ((c = *fmt) != '\0') {
206: if (c != '%') {
207: (*putc)(c, putc_arg);
208: fmt++;
209: continue;
210: }
211:
212: fmt++;
213:
214: length = 0;
215: prec = -1;
216: ladjust = FALSE;
217: padc = ' ';
218: plus_sign = 0;
219: sign_char = 0;
220: altfmt = FALSE;
221:
222: while (TRUE) {
223: c = *fmt;
224: if (c == '#') {
225: altfmt = TRUE;
226: }
227: else if (c == '-') {
228: ladjust = TRUE;
229: }
230: else if (c == '+') {
231: plus_sign = '+';
232: }
233: else if (c == ' ') {
234: if (plus_sign == 0)
235: plus_sign = ' ';
236: }
237: else
238: break;
239: fmt++;
240: }
241:
242: if (c == '0') {
243: padc = '0';
244: c = *++fmt;
245: }
246:
247: if (isdigit(c)) {
248: while(isdigit(c)) {
249: length = 10 * length + Ctod(c);
250: c = *++fmt;
251: }
252: }
253: else if (c == '*') {
1.1.1.3 root 254: length = va_arg(argp, int);
1.1 root 255: c = *++fmt;
256: if (length < 0) {
257: ladjust = !ladjust;
258: length = -length;
259: }
260: }
261:
262: if (c == '.') {
263: c = *++fmt;
264: if (isdigit(c)) {
265: prec = 0;
266: while(isdigit(c)) {
267: prec = 10 * prec + Ctod(c);
268: c = *++fmt;
269: }
270: }
271: else if (c == '*') {
1.1.1.3 root 272: prec = va_arg(argp, int);
1.1 root 273: c = *++fmt;
274: }
275: }
276:
277: if (c == 'l')
278: c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
279:
280: truncate = FALSE;
281:
282: switch(c) {
283: case 'b':
284: case 'B':
285: {
1.1.1.4 ! root 286: char *p;
! 287: boolean_t any;
! 288: int i;
1.1 root 289:
1.1.1.3 root 290: u = va_arg(argp, unsigned long);
291: p = va_arg(argp, char *);
1.1 root 292: base = *p++;
293: printnum(u, base, putc, putc_arg);
294:
295: if (u == 0)
296: break;
297:
298: any = FALSE;
1.1.1.3 root 299: while ((i = *p++)) {
1.1 root 300: /* NOTE: The '32' here is because ascii space */
301: if (*p <= 32) {
302: /*
303: * Bit field
304: */
1.1.1.4 ! root 305: int j;
1.1 root 306: if (any)
307: (*putc)(',', putc_arg);
308: else {
309: (*putc)('<', putc_arg);
310: any = TRUE;
311: }
312: j = *p++;
313: for (; (c = *p) > 32; p++)
314: (*putc)(c, putc_arg);
315: printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
316: base, putc, putc_arg);
317: }
318: else if (u & (1<<(i-1))) {
319: if (any)
320: (*putc)(',', putc_arg);
321: else {
322: (*putc)('<', putc_arg);
323: any = TRUE;
324: }
325: for (; (c = *p) > 32; p++)
326: (*putc)(c, putc_arg);
327: }
328: else {
329: for (; *p > 32; p++)
330: continue;
331: }
332: }
333: if (any)
334: (*putc)('>', putc_arg);
335: break;
336: }
337:
338: case 'c':
1.1.1.3 root 339: c = va_arg(argp, int);
1.1 root 340: (*putc)(c, putc_arg);
341: break;
342:
343: case 's':
344: {
1.1.1.4 ! root 345: char *p;
! 346: char *p2;
1.1 root 347:
348: if (prec == -1)
349: prec = 0x7fffffff; /* MAXINT */
350:
1.1.1.3 root 351: p = va_arg(argp, char *);
1.1 root 352:
353: if (p == (char *)0)
354: p = "";
355:
356: if (length > 0 && !ladjust) {
357: n = 0;
358: p2 = p;
359:
360: for (; *p != '\0' && n < prec; p++)
361: n++;
362:
363: p = p2;
364:
365: while (n < length) {
366: (*putc)(' ', putc_arg);
367: n++;
368: }
369: }
370:
371: n = 0;
372:
373: while (*p != '\0') {
374: if (++n > prec)
375: break;
376:
377: (*putc)(*p++, putc_arg);
378: }
379:
380: if (n < length && ladjust) {
381: while (n < length) {
382: (*putc)(' ', putc_arg);
383: n++;
384: }
385: }
386:
387: break;
388: }
389:
390: case 'o':
391: truncate = _doprnt_truncates;
392: case 'O':
393: base = 8;
394: goto print_unsigned;
395:
396: case 'd':
397: truncate = _doprnt_truncates;
398: case 'D':
399: base = 10;
400: goto print_signed;
401:
402: case 'u':
403: truncate = _doprnt_truncates;
404: case 'U':
405: base = 10;
406: goto print_unsigned;
407:
1.1.1.3 root 408: case 'p':
1.1 root 409: case 'x':
410: truncate = _doprnt_truncates;
411: case 'X':
412: base = 16;
413: goto print_unsigned;
414:
415: case 'z':
416: truncate = _doprnt_truncates;
417: case 'Z':
418: base = 16;
419: goto print_signed;
420:
421: case 'r':
422: truncate = _doprnt_truncates;
423: case 'R':
424: base = radix;
425: goto print_signed;
426:
427: case 'n':
428: truncate = _doprnt_truncates;
429: case 'N':
430: base = radix;
431: goto print_unsigned;
432:
433: print_signed:
1.1.1.3 root 434: n = va_arg(argp, long);
1.1 root 435: if (n >= 0) {
436: u = n;
437: sign_char = plus_sign;
438: }
439: else {
440: u = -n;
441: sign_char = '-';
442: }
443: goto print_num;
444:
445: print_unsigned:
1.1.1.3 root 446: u = va_arg(argp, unsigned long);
1.1 root 447: goto print_num;
448:
449: print_num:
450: {
451: char buf[MAXBUF]; /* build number here */
1.1.1.4 ! root 452: char * p = &buf[MAXBUF-1];
1.1 root 453: static char digits[] = "0123456789abcdef";
454: char *prefix = 0;
455:
456: if (truncate) u = (long)((int)(u));
457:
458: if (u != 0 && altfmt) {
459: if (base == 8)
460: prefix = "0";
461: else if (base == 16)
462: prefix = "0x";
463: }
464:
465: do {
466: *p-- = digits[u % base];
467: u /= base;
468: } while (u != 0);
469:
470: length -= (&buf[MAXBUF-1] - p);
471: if (sign_char)
472: length--;
473: if (prefix)
474: length -= strlen(prefix);
475:
476: if (padc == ' ' && !ladjust) {
477: /* blank padding goes before prefix */
478: while (--length >= 0)
479: (*putc)(' ', putc_arg);
480: }
481: if (sign_char)
482: (*putc)(sign_char, putc_arg);
483: if (prefix)
484: while (*prefix)
485: (*putc)(*prefix++, putc_arg);
486: if (padc == '0') {
487: /* zero padding goes after sign and prefix */
488: while (--length >= 0)
489: (*putc)('0', putc_arg);
490: }
491: while (++p != &buf[MAXBUF])
492: (*putc)(*p, putc_arg);
493:
494: if (ladjust) {
495: while (--length >= 0)
496: (*putc)(' ', putc_arg);
497: }
498: break;
499: }
500:
501: case '\0':
502: fmt--;
503: break;
504:
505: default:
506: (*putc)(c, putc_arg);
507: }
508: fmt++;
509: }
510:
511: simple_unlock(&_doprnt_lock);
512: }
513:
514: /*
515: * Printing (to console)
516: */
517:
1.1.1.3 root 518: int vprintf(const char *fmt, va_list listp)
1.1 root 519: {
1.1.1.3 root 520: _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
521: return 0;
1.1 root 522: }
523:
524: /*VARARGS1*/
1.1.1.3 root 525: int printf(const char *fmt, ...)
1.1 root 526: {
527: va_list listp;
1.1.1.2 root 528: va_start(listp, fmt);
1.1 root 529: vprintf(fmt, listp);
530: va_end(listp);
1.1.1.3 root 531: return 0;
1.1 root 532: }
533:
534: int indent = 0;
535:
536: /*
537: * Printing (to console) with indentation.
538: */
539: /*VARARGS1*/
1.1.1.2 root 540: void iprintf(const char *fmt, ...)
1.1 root 541: {
542: va_list listp;
1.1.1.4 ! root 543: int i;
1.1 root 544:
545: for (i = indent; i > 0; ){
546: if (i >= 8) {
547: printf("\t");
548: i -= 8;
549: }
550: else {
551: printf(" ");
552: i--;
553: }
554: }
1.1.1.2 root 555: va_start(listp, fmt);
1.1.1.3 root 556: _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
1.1 root 557: va_end(listp);
558: }
559:
560: /*
561: * Printing to generic buffer
562: * Returns #bytes printed.
563: * Strings are zero-terminated.
564: */
565: static void
566: sputc(
567: char c,
568: vm_offset_t arg)
569: {
1.1.1.4 ! root 570: char **bufp = (char **) arg;
! 571: char *p = *bufp;
1.1 root 572: *p++ = c;
573: *bufp = p;
574: }
575:
576: int
1.1.1.2 root 577: sprintf(char *buf, const char *fmt, ...)
1.1 root 578: {
579: va_list listp;
580: char *start = buf;
581:
1.1.1.2 root 582: va_start(listp, fmt);
1.1.1.3 root 583: _doprnt(fmt, listp, sputc, 16, (vm_offset_t)&buf);
1.1 root 584: va_end(listp);
585:
586: *buf = 0;
587: return (buf - start);
588: }
589:
1.1.1.3 root 590: struct vsnprintf_cookie
591: {
592: char *buf;
593: int index;
594: int max_len;
595: };
596:
597: static void
598: snputc(char c, vm_offset_t arg)
599: {
600: struct vsnprintf_cookie *cookie = (void *) arg;
601:
602: if (cookie->index < cookie->max_len)
603: cookie->buf[cookie->index ++] = c;
604: }
605:
606: int
607: vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
608: {
609: struct vsnprintf_cookie cookie
610: = { .buf = buf, .index = 0, .max_len = size };
611:
612: _doprnt (fmt, args, snputc, 16, (vm_offset_t)&cookie);
613: cookie.buf[cookie.index] = '\0';
614:
615: return cookie.index;
616: }
617:
1.1.1.4 ! root 618: int
! 619: snprintf(char *buf, size_t size, const char *fmt, ...)
! 620: {
! 621: int written;
! 622: va_list listp;
! 623: va_start(listp, fmt);
! 624: written = vsnprintf(buf, size, fmt, listp);
! 625: va_end(listp);
! 626: return written;
! 627: }
1.1 root 628:
1.1.1.4 ! root 629: void safe_gets(
! 630: char *str,
! 631: int maxlen)
1.1 root 632: {
1.1.1.4 ! root 633: char *lp;
! 634: int c;
1.1 root 635: char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
636:
637: lp = str;
638: for (;;) {
639: c = cngetc();
640: switch (c) {
641: case '\n':
642: case '\r':
643: printf("\n");
644: *lp++ = 0;
645: return;
646:
647: case '\b':
648: case '#':
649: case '\177':
650: if (lp > str) {
651: printf("\b \b");
652: lp--;
653: }
654: continue;
655:
656: case '@':
657: case 'u'&037:
658: lp = str;
659: printf("\n\r");
660: continue;
661:
662: default:
663: if (c >= ' ' && c < '\177') {
664: if (lp < strmax) {
665: *lp++ = c;
666: printf("%c", c);
667: }
668: else {
669: printf("%c", '\007'); /* beep */
670: }
671: }
672: }
673: }
674: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.