1 /*
2  * Copyright (c) 2006-2023 Ali Mashtizadeh
3  * All rights reserved.
4  */
5 
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdarg.h>
9 #include <string.h>
10 
11 #include <sys/kassert.h>
12 
13 #include "../dev/console.h"
14 
15 // static unsigned long getuint(va_list *ap, int lflag)
16 #define getuint(ap, lflag) \
17     (lflag == 8) ? va_arg(ap, uint64_t) : \
18     (lflag == 4) ? va_arg(ap, uint32_t) : \
19     (lflag == 2) ? va_arg(ap, uint32_t) : \
20     (lflag == 1) ? va_arg(ap, uint32_t) : 0
21 
22 // static long getint(va_list *ap, int lflag)
23 #define getint(ap, lflag) \
24     (lflag == 8) ? va_arg(ap, int64_t) : \
25     (lflag == 4) ? va_arg(ap, int32_t) : \
26     (lflag == 2) ? va_arg(ap, int32_t) : \
27     (lflag == 1) ? va_arg(ap, int32_t) : 0
28 
29 static const char *numberstring_lower = "0123456789abcdef";
30 static const char *numberstring_upper = "0123456789ABCDEF";
31 
printnum(void (* func)(int,void *),void * handle,uint64_t num,int base,int width,int padc)32 static void printnum(void (*func)(int, void*),void *handle,
33                      uint64_t num,int base,int width,int padc)
34 {
35     char buf[64];
36     char *p = buf;
37     int spaces;
38     if (base < 0)
39     {
40         base = -base;
41         do {
42             *p = numberstring_upper[num % base];
43             p++;
44         } while (num /= base);
45     } else {
46         do {
47             *p = numberstring_lower[num % base];
48             p++;
49         } while (num /= base);
50     }
51 
52     // Print spacers (pre-number)
53     spaces = width - (p - buf);
54     if (padc == ' ' || padc == '0') {
55 	while (spaces > 0)
56 	{
57 	    func(padc, handle);
58 	    spaces--;
59 	}
60     }
61 
62     // Print Number
63     while (p != buf) {
64         p--;
65         func((int)*p, handle);
66     }
67 
68     // Print spacers (post-number)
69     if (padc == '-') {
70 	while (spaces > 0)
71 	{
72 	    func(' ', handle);
73 	    spaces--;
74 	}
75     }
76 }
77 
kvprintf(char const * fmt,void (* func)(int,void *),void * handle,va_list ap)78 int kvprintf(char const *fmt, void (*func)(int,void *), void *handle, va_list ap)
79 {
80     const char *p;
81     int ch;
82     uint64_t unum;
83     int64_t num;
84     int lflag, width, padc;
85 
86     while (1) {
87         while ((ch = *(unsigned char *)fmt++) != '%') {
88             if (ch == '\0') return -1;
89             func(ch, handle);
90         }
91 
92         width = -1;
93         lflag = 4;
94         padc = ' ';
95 again:
96         switch (ch = *(unsigned char *)fmt++) {
97             case '-':
98                 padc = '-';
99                 goto again;
100             case '0':
101                 padc = '0';
102                 goto again;
103             case '1':
104             case '2':
105             case '3':
106             case '4':
107             case '5':
108             case '6':
109             case '7':
110             case '8':
111             case '9':
112                 width = 0;
113                 while (1) {
114                     width = 10 * width + ch - '0';
115                     ch = *fmt;
116                     if (ch < '0' || ch > '9')
117                     {
118                         break;
119                     }
120                     fmt++;
121                     if (ch == '\0')
122                     {
123                         fmt--;
124                         goto again;
125                     }
126                 }
127                 goto again;
128             case 'c':
129                 func(va_arg(ap, int) & 0xff, handle);
130                 break;
131             case 's': {
132 		int spaces;
133 
134 		p = va_arg(ap, char *);
135 		ASSERT(p != 0);
136 		spaces = width - strlen(p);
137 
138 		if (padc == ' ') {
139 		    while (spaces > 0)
140 		    {
141 			func(' ', handle);
142 			spaces--;
143 		    }
144 		}
145 
146 		while (*p != '\0')
147 		{
148 		    func(*p++, handle);
149 		}
150 
151 		if (padc == '-') {
152 		    while (spaces > 0)
153 		    {
154 			func(' ', handle);
155 			spaces--;
156 		    }
157 		}
158 		break;
159             }
160             case 'd':
161                 num = getint(ap, lflag);
162                 if (num < 0) {
163                     func('-', handle);
164                     unum = -num;
165                 } else {
166                     unum = num;
167                 }
168                 printnum(func, handle, unum, 10, width, padc);
169                 break;
170             case 'u':
171                 unum = getuint(ap, lflag);
172                 printnum(func, handle, unum, 10, width, padc);
173                 break;
174             case 'o':
175                 unum = getuint(ap, lflag);
176                 printnum(func, handle, unum, 8, width, padc);
177                 break;
178             case 'p':
179                 unum = (unsigned long)va_arg(ap, void *);
180                 printnum(func, handle, unum, 8, width, padc);
181                 break;
182             case 'x':
183                 unum = getuint(ap, lflag);
184                 printnum(func, handle, unum, 16, width, padc);
185                 break;
186             case 'X':
187                 unum = getuint(ap, lflag);
188                 printnum(func, handle, unum, -16, width, padc);
189                 break;
190             case 'l':
191                 lflag = 8;
192                 goto again;
193             case '%':
194             default: // Print Literally
195                 func(ch, handle);
196                 break;
197         }
198     }
199     return 0;
200 }
201 
consoleputc(int c,void * handle)202 void consoleputc(int c,void* handle)
203 {
204     if (c == '\n') {
205 	Console_Putc('\r');
206     }
207     Console_Putc(c);
208 }
209 
kprintf(const char * fmt,...)210 int kprintf(const char *fmt, ...)
211 {
212     int ret;
213     va_list ap;
214 
215     va_start(ap, fmt);
216     ret = kvprintf(fmt, consoleputc, 0, ap);
217     va_end(ap);
218 
219     return ret;
220 }
221 
Debug_Assert(const char * fmt,...)222 void Debug_Assert(const char *fmt, ...)
223 {
224     va_list ap;
225 
226     va_start(ap, fmt);
227     kvprintf(fmt, consoleputc, 0, ap);
228     va_end(ap);
229 
230 #if 0
231     kprintf("PC %lx FP %lx\n", __builtin_return_address(0), __builtin_frame_address(0));
232     kprintf("PC %lx FP %lx\n", __builtin_return_address(1), __builtin_frame_address(1));
233     kprintf("PC %lx FP %lx\n", __builtin_return_address(2), __builtin_frame_address(2));
234     kprintf("PC %lx FP %lx\n", __builtin_return_address(3), __builtin_frame_address(3));
235     kprintf("PC %lx FP %lx\n", __builtin_return_address(4), __builtin_frame_address(4));
236     kprintf("PC %lx FP %lx\n", __builtin_return_address(5), __builtin_frame_address(5));
237 #endif
238 
239     Panic("");
240 }
241 
242