]> Joshua Wise's Git repositories - netwatch.git/blob - lib/doprnt.c
Add a todo list entry.
[netwatch.git] / lib / doprnt.c
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
34 typedef 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
150 static char digs[] = "0123456789abcdef";
151
152 static void
153 printnum(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
171 boolean_t       _doprnt_truncates = FALSE;
172
173 void _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.051239 seconds and 4 git commands to generate.