Finally got KFS stuff sorted out on the new setup
[akaros.git] / user / parlib / debugfmt.c
1 #include <ros/common.h>
2 #include <ros/errno.h>
3 #include <debug.h>
4
5 /*
6  * Print a number (base <= 16) in reverse order,
7  * using specified putch function and associated pointer putdat.
8  */
9 #ifdef __DEPUTY__
10 static void printnum(void (*putch)(int, TV(t)), TV(t) putdat,
11                          unsigned long long num, unsigned base, int width, int padc)
12 #else
13 static void printnum(void (*putch)(int, void**), void **putdat,
14                          unsigned long long num, unsigned base, int width, int padc)
15 #endif
16 {
17         // first recursively print all preceding (more significant) digits
18         if (num >= base) {
19                 printnum(putch, putdat, num / base, base, width - 1, padc);
20         } else {
21                 // print any needed pad characters before first digit
22                 while (--width > 0)
23                         putch(padc, putdat);
24         }
25
26         // then print this (the least significant) digit
27         putch("0123456789abcdef"[num % base], putdat);
28 }
29
30 // Get an unsigned int of various possible sizes from a varargs list,
31 // depending on the lflag parameter.
32 static unsigned long long getuint(va_list *ap, int lflag)
33 {
34         if (lflag >= 2)
35                 return va_arg(*ap, unsigned long long);
36         else if (lflag)
37                 return va_arg(*ap, unsigned long);
38         else
39                 return va_arg(*ap, unsigned int);
40 }
41
42 // Same as getuint but signed - can't use getuint
43 // because of sign extension
44 static long long getint(va_list *ap, int lflag)
45 {
46         if (lflag >= 2)
47                 return va_arg(*ap, long long);
48         else if (lflag)
49                 return va_arg(*ap, long);
50         else
51                 return va_arg(*ap, int);
52 }
53
54
55 // Main function to format and print a string.
56 #ifdef __DEPUTY__
57 void debugfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *fmt, ...);
58 void vdebugfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *fmt, va_list ap)
59 #else
60 void debugfmt(void (*putch)(int, void**), void **putdat, const char *fmt, ...);
61 void vdebugfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap)
62 #endif
63 {
64         register const char *NTS p;
65         const char *NTS last_fmt;
66         register int ch, err;
67         unsigned long long num;
68         int base, lflag, width, precision, altflag;
69         char padc;
70
71         while (1) {
72                 while ((ch = *(unsigned char *) fmt) != '%') {
73                         if (ch == '\0')
74                                 return;
75                         fmt++;
76                         putch(ch, putdat);
77                 }
78                 fmt++;
79
80                 // Process a %-escape sequence
81                 last_fmt = fmt;
82                 padc = ' ';
83                 width = -1;
84                 precision = -1;
85                 lflag = 0;
86                 altflag = 0;
87         reswitch:
88                 switch (ch = *(unsigned char *) fmt++) {
89
90                 // flag to pad on the right
91                 case '-':
92                         padc = '-';
93                         goto reswitch;
94                         
95                 // flag to pad with 0's instead of spaces
96                 case '0':
97                         padc = '0';
98                         goto reswitch;
99
100                 // width field
101                 case '1':
102                 case '2':
103                 case '3':
104                 case '4':
105                 case '5':
106                 case '6':
107                 case '7':
108                 case '8':
109                 case '9':
110                         for (precision = 0; ; ++fmt) {
111                                 precision = precision * 10 + ch - '0';
112                                 ch = *fmt;
113                                 if (ch < '0' || ch > '9')
114                                         break;
115                         }
116                         goto process_precision;
117
118                 case '*':
119                         precision = va_arg(ap, int);
120                         goto process_precision;
121
122                 case '.':
123                         if (width < 0)
124                                 width = 0;
125                         goto reswitch;
126
127                 case '#':
128                         altflag = 1;
129                         goto reswitch;
130
131                 process_precision:
132                         if (width < 0)
133                                 width = precision, precision = -1;
134                         goto reswitch;
135
136                 // long flag (doubled for long long)
137                 case 'l':
138                         lflag++;
139                         goto reswitch;
140
141                 // character
142                 case 'c':
143                         putch(va_arg(ap, int), putdat);
144                         break;
145
146                 // string
147                 case 's':
148                         if ((p = va_arg(ap, char *NT)) == NULL)
149                                 p = "(null)";
150                         if (width > 0 && padc != '-')
151                                 for (width -= strnlen(p, precision); width > 0; width--)
152                                         putch(padc, putdat);
153                         for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) {
154                                 if (altflag && (ch < ' ' || ch > '~'))
155                                         putch('?', putdat);
156                                 else
157                                         putch(ch, putdat);
158                                 // zra: make sure *p isn't '\0' before inc'ing
159                                 p++;
160                         }
161                         for (; width > 0; width--)
162                                 putch(' ', putdat);
163                         break;
164
165                 // (signed) decimal
166                 case 'd':
167                         num = getint(&ap, lflag);
168                         if ((long long) num < 0) {
169                                 putch('-', putdat);
170                                 num = -(long long) num;
171                         }
172                         base = 10;
173                         goto number;
174
175                 // unsigned decimal
176                 case 'u':
177                         num = getuint(&ap, lflag);
178                         base = 10;
179                         goto number;
180
181                 // (unsigned) octal
182                 case 'o':
183                         // should do something with padding so it's always 3 octits
184                         num = getuint(&ap, lflag);
185                         base = 8;
186                         goto number;
187
188                 // pointer
189                 case 'p':
190                         putch('0', putdat);
191                         putch('x', putdat);
192                         num = (unsigned long long)
193                                 (uintptr_t) va_arg(ap, void *);
194                         base = 16;
195                         goto number;
196
197                 // (unsigned) hexadecimal
198                 case 'x':
199                         num = getuint(&ap, lflag);
200                         base = 16;
201                 number:
202                         printnum(putch, putdat, num, base, width, padc);
203                         break;
204
205                 // escaped '%' character
206                 case '%':
207                         putch(ch, putdat);
208                         break;
209                         
210                 // unrecognized escape sequence - just print it literally
211                 default:
212                         putch('%', putdat);
213                         fmt = last_fmt;
214                         //for (fmt--; fmt[-1] != '%'; fmt--)
215                                 /* do nothing */;
216                         break;
217                 }
218         }
219 }
220
221 #ifdef __DEPUTY__
222 void debugfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *fmt, ...)
223 #else
224 void debugfmt(void (*putch)(int, void**), void **putdat, const char *fmt, ...)
225 #endif
226 {
227         va_list ap;
228
229         va_start(ap, fmt);
230         vdebugfmt(putch, putdat, fmt, ap);
231         va_end(ap);
232 }
233