]> Joshua Wise's Git repositories - netwatch.git/blame_incremental - lib/doprnt.c
Merge nyus.joshuawise.com:/storage/git/netwatch
[netwatch.git] / lib / doprnt.c
... / ...
CommitLineData
1/*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 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 Software.Distribution@CS.CMU.EDU
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#include <stdarg.h>
28#include <minilib.h>
29#include "doprnt.h"
30
31/* How irritating -- this boolean crap. */
32#define FALSE 0
33#define TRUE 1
34typedef int boolean_t;
35
36/*
37 * Common code for printf et al.
38 *
39 * The calling routine typically takes a variable number of arguments,
40 * and passes the address of the first one. This implementation
41 * assumes a straightforward, stack implementation, aligned to the
42 * machine's wordsize. Increasing addresses are assumed to point to
43 * successive arguments (left-to-right), as is the case for a machine
44 * with a downward-growing stack with arguments pushed right-to-left.
45 *
46 * To write, for example, fprintf() using this routine, the code
47 *
48 * fprintf(fd, format, args)
49 * FILE *fd;
50 * char *format;
51 * {
52 * _doprnt(format, &args, fd);
53 * }
54 *
55 * would suffice. (This example does not handle the fprintf's "return
56 * value" correctly, but who looks at the return value of fprintf
57 * anyway?)
58 *
59 * This version implements the following printf features:
60 *
61 * %d decimal conversion
62 * %u unsigned conversion
63 * %x hexadecimal conversion
64 * %X hexadecimal conversion with capital letters
65 * %o octal conversion
66 * %c character
67 * %s string
68 * %m.n field width, precision
69 * %-m.n left adjustment
70 * %0m.n zero-padding
71 * %*.* width and precision taken from arguments
72 *
73 * This version does not implement %f, %e, or %g. It accepts, but
74 * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
75 * work correctly on machines for which sizeof(long) != sizeof(int).
76 * It does not even parse %D, %O, or %U; you should be using %ld, %o and
77 * %lu if you mean long conversion.
78 *
79 * As mentioned, this version does not return any reasonable value.
80 *
81 * Permission is granted to use, modify, or propagate this code as
82 * long as this notice is incorporated.
83 *
84 * Steve Summit 3/25/87
85 */
86
87/*
88 * Added formats for decoding device registers:
89 *
90 * printf("reg = %b", regval, "<base><arg>*")
91 *
92 * where <base> is the output base expressed as a control character:
93 * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of
94 * characters, the first of which gives the bit number to be inspected
95 * (origin 1), and the rest (up to a control character (<= 32)) give the
96 * name of the register. Thus
97 * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
98 * would produce
99 * reg = 3<BITTWO,BITONE>
100 *
101 * If the second character in <arg> is also a control character, it
102 * indicates the last bit of a bit field. In this case, printf will extract
103 * bits <1> to <2> and print it. Characters following the second control
104 * character are printed before the bit field.
105 * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
106 * would produce
107 * reg = b<FIELD1=2,BITONE>
108 */
109/*
110 * Added for general use:
111 * # prefix for alternate format:
112 * 0x (0X) for hex
113 * leading 0 for octal
114 * + print '+' if positive
115 * blank print ' ' if positive
116 *
117 * z signed hexadecimal
118 * r signed, 'radix'
119 * n unsigned, 'radix'
120 *
121 * D,U,O,Z same as corresponding lower-case versions
122 * (compatibility)
123 */
124/*
125 * Added ANSI %p for pointers. Output looks like 0x%08x.
126 */
127/*
128 *
129 * Added special for L4-use: %t format
130 *
131 * prints L4-threadids. standard format is "task.thread". Field-width
132 * may be specified with width-modifier. Padding begins with threadid,
133 * up to 2 chars, task-part follows.
134 *
135 * modifiers:
136 * # surrounds output with square brackets []
137 * l prints the high and low part of a threadid
138 * fixed length for the dwords: 8 chars
139 * 0 as usual, padding after optional '['
140 * - as usual
141 *
142 * Jork Loeser 9/20/99
143 */
144
145#define isdigit(d) ((d) >= '0' && (d) <= '9')
146#define Ctod(c) ((c) - '0')
147
148#define MAXBUF (sizeof(long int) * 8) /* enough for binary */
149
150static char digs[] = "0123456789abcdef";
151
152static void
153printnum(u, base, putc, putc_arg)
154 register unsigned long u; /* number to print */
155 register int base;
156 void (*putc)();
157 char *putc_arg;
158{
159 char buf[MAXBUF]; /* build number here */
160 register char * p = &buf[MAXBUF-1];
161
162 do {
163 *p-- = digs[u % base];
164 u /= base;
165 } while (u != 0);
166
167 while (++p != &buf[MAXBUF])
168 (*putc)(putc_arg, *p);
169}
170
171boolean_t _doprnt_truncates = FALSE;
172
173void _doprnt(fmt, args, radix, putc, putc_arg)
174 register const char *fmt;
175 va_list args;
176 int radix; /* default radix - for '%r' */
177 void (*putc)(); /* character output */
178 char *putc_arg; /* argument for putc */
179{
180 int length;
181 int prec;
182 boolean_t ladjust;
183 char padc;
184 long n;
185 unsigned long u;
186 int plus_sign;
187 int sign_char;
188 boolean_t altfmt, truncate;
189 int base;
190 char c;
191 int longopt;
192
193 while (*fmt != '\0') {
194 if (*fmt != '%') {
195 (*putc)(putc_arg, *fmt++);
196 continue;
197 }
198
199 fmt++;
200
201 length = 0;
202 prec = -1;
203 ladjust = FALSE;
204 padc = ' ';
205 plus_sign = 0;
206 sign_char = 0;
207 altfmt = FALSE;
208 longopt = 0;
209
210 while (TRUE) {
211 if (*fmt == '#') {
212 altfmt = TRUE;
213 fmt++;
214 }
215 else if (*fmt == '-') {
216 ladjust = TRUE;
217 fmt++;
218 }
219 else if (*fmt == '+') {
220 plus_sign = '+';
221 fmt++;
222 }
223 else if (*fmt == ' ') {
224 if (plus_sign == 0)
225 plus_sign = ' ';
226 fmt++;
227 }
228 else
229 break;
230 }
231
232 if (*fmt == '0') {
233 padc = '0';
234 fmt++;
235 }
236
237 if (isdigit(*fmt)) {
238 while(isdigit(*fmt))
239 length = 10 * length + Ctod(*fmt++);
240 }
241 else if (*fmt == '*') {
242 length = va_arg(args, int);
243 fmt++;
244 if (length < 0) {
245 ladjust = !ladjust;
246 length = -length;
247 }
248 }
249
250 if (*fmt == '.') {
251 fmt++;
252 if (isdigit(*fmt)) {
253 prec = 0;
254 while(isdigit(*fmt))
255 prec = 10 * prec + Ctod(*fmt++);
256 }
257 else if (*fmt == '*') {
258 prec = va_arg(args, int);
259 fmt++;
260 }
261 }
262
263 while (*fmt == 'l'){
264 longopt++;
265 fmt++;
266 }
267
268 truncate = FALSE;
269
270 switch(*fmt) {
271 case 'b':
272 case 'B':
273 {
274 register char *p;
275 boolean_t any;
276 register int i;
277
278 u = va_arg(args, unsigned long);
279 p = va_arg(args, char *);
280 base = *p++;
281 printnum(u, base, putc, putc_arg);
282
283 if (u == 0)
284 break;
285
286 any = FALSE;
287 while ((i = *p++) != 0) {
288 /* NOTE: The '32' here is because ascii space */
289 if (*p <= 32) {
290 /*
291 * Bit field
292 */
293 register int j;
294 if (any)
295 (*putc)(putc_arg, ',');
296 else {
297 (*putc)(putc_arg, '<');
298 any = TRUE;
299 }
300 j = *p++;
301 for (; (c = *p) > 32; p++)
302 (*putc)(putc_arg, c);
303 printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
304 base, putc, putc_arg);
305 }
306 else if (u & (1<<(i-1))) {
307 if (any)
308 (*putc)(putc_arg, ',');
309 else {
310 (*putc)(putc_arg, '<');
311 any = TRUE;
312 }
313 for (; (c = *p) > 32; p++)
314 (*putc)(putc_arg, c);
315 }
316 else {
317 for (; *p > 32; p++)
318 continue;
319 }
320 }
321 if (any)
322 (*putc)(putc_arg, '>');
323 break;
324 }
325
326 case 'c':
327 c = va_arg(args, int);
328 (*putc)(putc_arg, c);
329 break;
330
331 case 's':
332 {
333 register char *p;
334 register char *p2;
335
336 if (prec == -1)
337 prec = 0x7fffffff; /* MAXINT */
338
339 p = va_arg(args, char *);
340
341 if (p == (char *)0)
342 p = "";
343
344 if (length > 0 && !ladjust) {
345 n = 0;
346 p2 = p;
347
348 for (; *p != '\0' && n < prec; p++)
349 n++;
350
351 p = p2;
352
353 while (n < length) {
354 (*putc)(putc_arg, ' ');
355 n++;
356 }
357 }
358
359 n = 0;
360
361 while (*p != '\0') {
362 if (++n > prec)
363 break;
364
365 (*putc)(putc_arg, *p++);
366 }
367
368 if (n < length && ladjust) {
369 while (n < length) {
370 (*putc)(putc_arg, ' ');
371 n++;
372 }
373 }
374
375 break;
376 }
377
378
379 case 'o':
380 truncate = _doprnt_truncates;
381 case 'O':
382 base = 8;
383 goto print_unsigned;
384
385 case 'd':
386 truncate = _doprnt_truncates;
387 case 'D':
388 base = 10;
389 goto print_signed;
390
391 case 'u':
392 truncate = _doprnt_truncates;
393 case 'U':
394 base = 10;
395 goto print_unsigned;
396
397 case 'p':
398 padc = '0';
399 length = 8;
400 /*
401 * We do this instead of just setting altfmt to TRUE
402 * because we want 0 to have a 0x in front, and we want
403 * eight digits after the 0x -- not just 6.
404 */
405 (*putc)(putc_arg, '0');
406 (*putc)(putc_arg, 'x');
407 case 'x':
408 truncate = _doprnt_truncates;
409 case 'X':
410 base = 16;
411 goto print_unsigned;
412
413 case 'z':
414 truncate = _doprnt_truncates;
415 case 'Z':
416 base = 16;
417 goto print_signed;
418
419 case 'r':
420 truncate = _doprnt_truncates;
421 case 'R':
422 base = radix;
423 goto print_signed;
424
425 case 'n':
426 truncate = _doprnt_truncates;
427 case 'N':
428 base = radix;
429 goto print_unsigned;
430
431 print_signed:
432 if (longopt>1)
433 n = va_arg(args, long long);
434 else
435 n = va_arg(args, long);
436 if (n >= 0) {
437 u = n;
438 sign_char = plus_sign;
439 }
440 else {
441 u = -n;
442 sign_char = '-';
443 }
444 goto print_num;
445
446 print_unsigned:
447 if (longopt>1)
448 u = va_arg(args, unsigned long long);
449 else
450 u = va_arg(args, unsigned long);
451 goto print_num;
452
453 print_num:
454 {
455 char buf[MAXBUF]; /* build number here */
456 register char * p = &buf[MAXBUF-1];
457 static char digits[] = "0123456789abcdef";
458 char *prefix = 0;
459
460 if (truncate) u = (long)((int)(u));
461
462 if (u != 0 && altfmt) {
463 if (base == 8)
464 prefix = "0";
465 else if (base == 16)
466 prefix = "0x";
467 }
468
469 do {
470 *p-- = digits[u % base];
471 u /= base;
472 } while (u != 0);
473
474 length -= (&buf[MAXBUF-1] - p);
475 if (sign_char)
476 length--;
477 if (prefix)
478 length -= strlen(prefix);
479
480 if (padc == ' ' && !ladjust) {
481 /* blank padding goes before prefix */
482 while (--length >= 0)
483 (*putc)(putc_arg, ' ');
484 }
485 if (sign_char)
486 (*putc)(putc_arg, sign_char);
487 if (prefix)
488 while (*prefix)
489 (*putc)(putc_arg, *prefix++);
490 if (padc == '0') {
491 /* zero padding goes after sign and prefix */
492 while (--length >= 0)
493 (*putc)(putc_arg, '0');
494 }
495 while (++p != &buf[MAXBUF])
496 (*putc)(putc_arg, *p);
497
498 if (ladjust) {
499 while (--length >= 0)
500 (*putc)(putc_arg, ' ');
501 }
502 break;
503 }
504
505 case '\0':
506 fmt--;
507 break;
508
509 default:
510 (*putc)(putc_arg, *fmt);
511 }
512 fmt++;
513 }
514}
This page took 0.030924 seconds and 4 git commands to generate.