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