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