Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/lib/printk.c 3 * 4 * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/kernel.h> 9 #include <fiwix/tty.h> 10 #include <fiwix/stdio.h> 11 #include <fiwix/string.h> 12 #include <fiwix/stdarg.h> 13 14 #define LOG_BUF_LEN 4096 15 #define MAX_BUF 1024 /* printk() and sprintk() size limit */ 16 17 static char log_buf[LOG_BUF_LEN]; 18 static unsigned int log_count; 19 20 static void puts(char *buffer) 21 { 22 struct tty *tty; 23 unsigned short int count; 24 char *b; 25 26 tty = get_tty(_syscondev); 27 count = strlen(buffer); 28 b = buffer; 29 30 while(count--) { 31 if(!tty) { 32 if(log_count < LOG_BUF_LEN) { 33 log_buf[log_count++] = *(b++); 34 } 35 } else { 36 tty_queue_putchar(tty, &tty->write_q, *(b++)); 37 38 /* kernel messages must be shown immediately */ 39 tty->output(tty); 40 } 41 } 42 } 43 44 /* 45 * format identifiers 46 * -------------------------------------------------------- 47 * %d decimal conversion 48 * %u unsigned decimal conversion 49 * %x hexadecimal conversion (lower case) 50 * %X hexadecimal conversion (upper case) 51 * %b binary conversion 52 * %o octal conversion 53 * %c character 54 * %s string 55 * 56 * flags 57 * -------------------------------------------------------- 58 * 0 result is padded with zeros (e.g.: '%06d') 59 * (maximum value is 32) 60 * blank result is padded with spaces (e.g.: '% 6d') 61 * (maximum value is 32) 62 * - the numeric result is left-justified 63 * (default is right-justified) 64 */ 65 static void do_printk(char *buffer, const char *format, va_list args) 66 { 67 char sw_neg, in_identifier, n_pad, lf; 68 char ch_pad, basecase, c; 69 char str[] = { 70 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 71 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 72 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 73 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 74 NULL 75 }; 76 char nullstr[7] = { '<', 'N', 'U', 'L', 'L', '>', '\0' }; 77 char *ptr_s, *p; 78 int num, count; 79 char simplechar; 80 unsigned int unum, digit; 81 82 sw_neg = in_identifier = n_pad = lf = 0; 83 count = 0; 84 basecase = 'A'; 85 ch_pad = ' '; 86 p = NULL; 87 88 /* assumes buffer has a maximum size of MAX_BUF */ 89 while((c = *(format++)) && count < MAX_BUF) { 90 if((c != '%') && !in_identifier) { 91 *(buffer++) = c; 92 memset_b(str, NULL, 32); 93 } else { 94 in_identifier = 1; 95 switch(c = *(format)) { 96 case 'd': 97 num = va_arg(args, int); 98 if(num < 0) { 99 num *= -1; 100 sw_neg = 1; 101 } 102 ptr_s = str; 103 do { 104 *(ptr_s++) = '0' + (num % 10); 105 } while(num /= 10); 106 if(lf) { 107 p = ptr_s; 108 } else { 109 while(*ptr_s) { 110 ptr_s++; 111 } 112 } 113 if(sw_neg) { 114 sw_neg = 0; 115 *(ptr_s++) = '-'; 116 } 117 do { 118 *(buffer++) = *(--ptr_s); 119 count++; 120 } while(ptr_s != str && count < MAX_BUF); 121 if(lf) { 122 while(*p && count < MAX_BUF) { 123 *(buffer++) = *(p++); 124 count++; 125 } 126 } 127 format++; 128 ch_pad = ' '; 129 n_pad = 0; 130 in_identifier = 0; 131 lf = 0; 132 break; 133 134 case 'u': 135 unum = va_arg(args, unsigned int); 136 ptr_s = str; 137 do { 138 *(ptr_s++) = '0' + (unum % 10); 139 } while(unum /= 10); 140 if(lf) { 141 p = ptr_s; 142 } else { 143 while(*ptr_s) { 144 ptr_s++; 145 } 146 } 147 do { 148 *(buffer++) = *(--ptr_s); 149 count++; 150 } while(ptr_s != str && count < MAX_BUF); 151 if(lf) { 152 while(*p && count < MAX_BUF) { 153 *(buffer++) = *(p++); 154 count++; 155 } 156 } 157 format++; 158 ch_pad = ' '; 159 n_pad = 0; 160 in_identifier = 0; 161 lf = 0; 162 break; 163 164 case 'x': 165 basecase = 'a'; 166 case 'X': 167 unum = va_arg(args, unsigned int); 168 ptr_s = str; 169 do { 170 *(ptr_s++) = (digit = (unum & 0x0F)) > 9 ? basecase + digit - 10 : '0' + digit; 171 } while(unum /= 16); 172 if(lf) { 173 p = ptr_s; 174 } else { 175 while(*ptr_s) { 176 ptr_s++; 177 } 178 } 179 do { 180 *(buffer++) = *(--ptr_s); 181 count++; 182 } while(ptr_s != str && count < MAX_BUF); 183 if(lf) { 184 while(*p && count < MAX_BUF) { 185 *(buffer++) = *(p++); 186 count++; 187 } 188 } 189 format++; 190 ch_pad = ' '; 191 n_pad = 0; 192 in_identifier = 0; 193 lf = 0; 194 break; 195 196 case 'b': 197 num = va_arg(args, unsigned int); 198 if(num < 0) { 199 num *= -1; 200 } 201 ptr_s = str; 202 do { 203 *(ptr_s++) = '0' + (num % 2); 204 } while(num /= 2); 205 if(lf) { 206 p = ptr_s; 207 } else { 208 while(*ptr_s) { 209 ptr_s++; 210 } 211 } 212 do { 213 *(buffer++) = *(--ptr_s); 214 count++; 215 } while(ptr_s != str && count < MAX_BUF); 216 if(lf) { 217 while(*p && count < MAX_BUF) { 218 *(buffer++) = *(p++); 219 count++; 220 } 221 } 222 format++; 223 ch_pad = ' '; 224 n_pad = 0; 225 in_identifier = 0; 226 lf = 0; 227 break; 228 229 case 'o': 230 num = va_arg(args, unsigned int); 231 if(num < 0) { 232 num *= -1; 233 } 234 ptr_s = str; 235 do { 236 *(ptr_s++) = '0' + (num % 8); 237 } while(num /= 8); 238 if(lf) { 239 p = ptr_s; 240 } else { 241 while(*ptr_s) { 242 ptr_s++; 243 } 244 } 245 do { 246 *(buffer++) = *(--ptr_s); 247 count++; 248 } while(ptr_s != str && count < MAX_BUF); 249 if(lf) { 250 while(*p && count < MAX_BUF) { 251 *(buffer++) = *(p++); 252 count++; 253 } 254 } 255 format++; 256 ch_pad = ' '; 257 n_pad = 0; 258 in_identifier = 0; 259 lf = 0; 260 break; 261 262 case 'c': 263 simplechar = va_arg(args, int); 264 *(buffer++) = simplechar; 265 format++; 266 in_identifier = 0; 267 lf = 0; 268 break; 269 270 case 's': 271 num = 0; 272 ptr_s = va_arg(args, char *); 273 if(n_pad) { 274 num = n_pad - strlen(ptr_s); 275 if(num < 0) { 276 num *= -1; 277 } 278 } 279 /* if it's a NULL then show "<NULL>" */ 280 if(ptr_s == NULL) { 281 ptr_s = (char *)nullstr; 282 } 283 while((c = *(ptr_s++)) && count < MAX_BUF) { 284 *(buffer++) = c; 285 count++; 286 } 287 while(num-- && count < MAX_BUF) { 288 *(buffer++) = ' '; 289 count++; 290 } 291 format++; 292 n_pad = 0; 293 in_identifier = 0; 294 lf = 0; 295 break; 296 297 case ' ': 298 ch_pad = ' '; 299 break; 300 301 case '0': 302 if(!n_pad) { 303 ch_pad = '0'; 304 } 305 case '1': 306 case '2': 307 case '3': 308 case '4': 309 case '5': 310 case '6': 311 case '7': 312 case '8': 313 case '9': 314 n_pad = !n_pad ? c - '0': ((n_pad * 10) + (c - '0')); 315 n_pad = n_pad > 32 ? 32 : n_pad; 316 for(unum = 0; unum < n_pad; unum++) { 317 str[unum] = ch_pad; 318 } 319 break; 320 321 case '-': 322 lf = 1; 323 break; 324 case '%': 325 *(buffer++) = c; 326 format++; 327 in_identifier = 0; 328 break; 329 } 330 } 331 count++; 332 } 333 *buffer = NULL; 334 } 335 336 void register_console(void (*fn)(char *, unsigned int)) 337 { 338 (*fn)(log_buf, log_count); 339 } 340 341 void printk(const char *format, ...) 342 { 343 va_list args; 344 char buffer[MAX_BUF]; 345 346 va_start(args, format); 347 do_printk(buffer, format, args); 348 puts(buffer); 349 va_end(args); 350 } 351 352 int sprintk(char *buffer, const char *format, ...) 353 { 354 va_list args; 355 356 va_start(args, format); 357 do_printk(buffer, format, args); 358 va_end(args); 359 return strlen(buffer); 360 }