1 // 2 // Created by longjin on 2022/1/22. 3 // 4 #include <common/kprint.h> 5 #include <common/printk.h> 6 7 #include <common/spinlock.h> 8 #include <libs/libUI/textui.h> 9 #include <mm/mm.h> 10 11 #include <common/math.h> 12 #include <common/string.h> 13 14 static spinlock_t __printk_lock = {1}; 15 /** 16 * @brief 将数字按照指定的要求转换成对应的字符串(2~36进制) 17 * 18 * @param str 要返回的字符串 19 * @param num 要打印的数值 20 * @param base 基数 21 * @param field_width 区域宽度 22 * @param precision 精度 23 * @param flags 标志位 24 */ 25 static char *write_num(char *str, ul num, int base, int field_width, int precision, int flags); 26 27 static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags); 28 29 static int skip_and_atoi(const char **s) 30 { 31 /** 32 * @brief 获取连续的一段字符对应整数的值 33 * @param:**s 指向 指向字符串的指针 的指针 34 */ 35 int ans = 0; 36 while (is_digit(**s)) 37 { 38 ans = ans * 10 + (**s) - '0'; 39 ++(*s); 40 } 41 return ans; 42 } 43 44 /** 45 * @brief 将字符串按照fmt和args中的内容进行格式化,当buf_size为-1时,字符串直接保存到buf中 46 * 否则将字符串前buf_size-1个字符放入,大小为buf_size的buf数组中 47 * 48 * @param buf 结果缓冲区 49 * @param fmt 格式化字符串 50 * @param args 内容 51 * @param buf_size buf_size为-1时,不指定buf的大小,否则buf大小为buf_size 52 * @return 最终字符串的长度 53 */ 54 static int __do_vsprintf(char *buf, const char *fmt, int buf_size, va_list args) 55 { 56 57 // 当需要输出的字符串的指针为空时,使用该字符填充目标字符串的指针 58 static const char __end_zero_char = '\0'; 59 60 char *str = NULL, *s = NULL, *end = NULL; 61 62 str = buf; 63 64 int flags; // 用来存储格式信息的bitmap 65 int field_width; //区域宽度 66 int precision; //精度 67 int qualifier; //数据显示的类型 68 int len; 69 70 if (buf_size != -1) 71 { 72 end = buf + buf_size; 73 } 74 //开始解析字符串 75 for (; *fmt; ++fmt) 76 { 77 //内容不涉及到格式化,直接输出 78 if (*fmt != '%') 79 { 80 *str = *fmt; 81 ++str; 82 continue; 83 } 84 85 //开始格式化字符串 86 87 //清空标志位和field宽度 88 field_width = flags = 0; 89 90 bool flag_tmp = true; 91 bool flag_break = false; 92 93 ++fmt; 94 while (flag_tmp) 95 { 96 switch (*fmt) 97 { 98 case '\0': 99 //结束解析 100 flag_break = true; 101 flag_tmp = false; 102 break; 103 104 case '-': 105 // 左对齐 106 flags |= LEFT; 107 ++fmt; 108 break; 109 case '+': 110 //在正数前面显示加号 111 flags |= PLUS; 112 ++fmt; 113 break; 114 case ' ': 115 flags |= SPACE; 116 ++fmt; 117 break; 118 case '#': 119 //在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X' 120 flags |= SPECIAL; 121 ++fmt; 122 break; 123 case '0': 124 //显示的数字之前填充‘0’来取代空格 125 flags |= PAD_ZERO; 126 ++fmt; 127 break; 128 default: 129 flag_tmp = false; 130 break; 131 } 132 } 133 if (flag_break) 134 break; 135 136 //获取区域宽度 137 field_width = -1; 138 if (*fmt == '*') 139 { 140 field_width = va_arg(args, int); 141 ++fmt; 142 } 143 else if (is_digit(*fmt)) 144 { 145 field_width = skip_and_atoi(&fmt); 146 if (field_width < 0) 147 { 148 field_width = -field_width; 149 flags |= LEFT; 150 } 151 } 152 153 //获取小数精度 154 precision = -1; 155 if (*fmt == '.') 156 { 157 ++fmt; 158 if (*fmt == '*') 159 { 160 precision = va_arg(args, int); 161 ++fmt; 162 } 163 else if (is_digit(*fmt)) 164 { 165 precision = skip_and_atoi(&fmt); 166 } 167 } 168 169 //获取要显示的数据的类型 170 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') 171 { 172 qualifier = *fmt; 173 ++fmt; 174 } 175 //为了支持lld 176 if (qualifier == 'l' && *fmt == 'l', *(fmt + 1) == 'd') 177 ++fmt; 178 179 //转化成字符串 180 long long *ip; 181 switch (*fmt) 182 { 183 //输出 % 184 case '%': 185 *str++ = '%'; 186 187 break; 188 // 显示一个字符 189 case 'c': 190 //靠右对齐 191 if (!(flags & LEFT)) 192 { 193 while (--field_width > 0) 194 { 195 *str = ' '; 196 ++str; 197 } 198 } 199 200 *str++ = (unsigned char)va_arg(args, int); 201 202 while (--field_width > 0) 203 { 204 *str = ' '; 205 ++str; 206 } 207 208 break; 209 210 //显示一个字符串 211 case 's': 212 s = va_arg(args, char *); 213 if (!s) 214 s = &__end_zero_char; 215 len = strlen(s); 216 if (precision < 0) 217 { 218 //未指定精度 219 precision = len; 220 } 221 222 else if (len > precision) 223 { 224 len = precision; 225 } 226 227 //靠右对齐 228 if (!(flags & LEFT)) 229 while (len < field_width--) 230 { 231 *str = ' '; 232 ++str; 233 } 234 235 for (int i = 0; i < len; i++) 236 { 237 *str = *s; 238 ++s; 239 ++str; 240 } 241 242 while (len < field_width--) 243 { 244 *str = ' '; 245 ++str; 246 } 247 248 break; 249 //以八进制显示字符串 250 case 'o': 251 flags |= SMALL; 252 case 'O': 253 flags |= SPECIAL; 254 if (qualifier == 'l') 255 str = write_num(str, va_arg(args, long long), 8, field_width, precision, flags); 256 else 257 str = write_num(str, va_arg(args, int), 8, field_width, precision, flags); 258 break; 259 260 //打印指针指向的地址 261 case 'p': 262 if (field_width == 0) 263 { 264 field_width = 2 * sizeof(void *); 265 flags |= PAD_ZERO; 266 } 267 268 str = write_num(str, (unsigned long)va_arg(args, void *), 16, field_width, precision, flags); 269 270 break; 271 272 //打印十六进制 273 case 'x': 274 flags |= SMALL; 275 case 'X': 276 // flags |= SPECIAL; 277 if (qualifier == 'l') 278 str = write_num(str, va_arg(args, ll), 16, field_width, precision, flags); 279 else 280 str = write_num(str, va_arg(args, int), 16, field_width, precision, flags); 281 break; 282 283 //打印十进制有符号整数 284 case 'i': 285 case 'd': 286 287 flags |= SIGN; 288 if (qualifier == 'l') 289 str = write_num(str, va_arg(args, long long), 10, field_width, precision, flags); 290 else 291 str = write_num(str, va_arg(args, int), 10, field_width, precision, flags); 292 break; 293 294 //打印十进制无符号整数 295 case 'u': 296 if (qualifier == 'l') 297 str = write_num(str, va_arg(args, unsigned long long), 10, field_width, precision, flags); 298 else 299 str = write_num(str, va_arg(args, unsigned int), 10, field_width, precision, flags); 300 break; 301 302 //输出有效字符数量到*ip对应的变量 303 case 'n': 304 305 if (qualifier == 'l') 306 ip = va_arg(args, long long *); 307 else 308 ip = (ll *)va_arg(args, int *); 309 310 *ip = str - buf; 311 break; 312 case 'f': 313 // 默认精度为3 314 // printk("1111\n"); 315 // va_arg(args, double); 316 // printk("222\n"); 317 318 if (precision < 0) 319 precision = 3; 320 321 str = write_float_point_num(str, va_arg(args, double), field_width, precision, flags); 322 323 break; 324 325 //对于不识别的控制符,直接输出 326 default: 327 *str++ = '%'; 328 if (*fmt) 329 *str++ = *fmt; 330 else 331 --fmt; 332 break; 333 } 334 } 335 //实现vsnprintf 的功能 336 if (buf_size > 0) 337 { 338 if (str < end) 339 { 340 *str = '\0'; 341 } 342 else 343 { 344 *(end-1) = '\0'; 345 } 346 return buf_size; 347 } 348 else 349 { 350 *str = '\0'; 351 } 352 353 //返回缓冲区已有字符串的长度。 354 return str - buf; 355 } 356 357 /** 358 * 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中 359 * @param buf 结果缓冲区 360 * @param fmt 格式化字符串 361 * @param args 内容 362 * @return 最终字符串的长度 363 */ 364 int vsprintf(char *buf, const char *fmt, va_list args) 365 { 366 return __do_vsprintf(buf, fmt, -1, args); 367 } 368 369 /** 370 * @brief 将字符串按照fmt和args中的内容进行格式化,截取字符串前buf_size-1,保存到buf中 371 * 372 * @param buf 结果缓冲区,大小为buf_size 373 * @param fmt 格式化字符串 374 * @param buf_size 缓冲区长度 375 * @param args 内容 376 * @return 最终字符串的长度 377 */ 378 int vsnprintf(char *buf, const char *fmt, int buf_size, va_list args) 379 { 380 return __do_vsprintf(buf, fmt, buf_size, args); 381 } 382 383 static char *write_num(char *str, ul num, int base, int field_width, int precision, int flags) 384 { 385 /** 386 * @brief 将数字按照指定的要求转换成对应的字符串 387 * 388 * @param str 要返回的字符串 389 * @param num 要打印的数值 390 * @param base 基数 391 * @param field_width 区域宽度 392 * @param precision 精度 393 * @param flags 标志位 394 */ 395 396 // 首先判断是否支持该进制 397 if (base < 2 || base > 36) 398 return 0; 399 char pad, sign, tmp_num[100]; 400 401 const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 402 // 显示小写字母 403 if (flags & SMALL) 404 digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 405 406 if (flags & LEFT) 407 flags &= ~PAD_ZERO; 408 // 设置填充元素 409 pad = (flags & PAD_ZERO) ? '0' : ' '; 410 411 sign = 0; 412 413 if (flags & SIGN) 414 { 415 int64_t signed_num = (int64_t)num; 416 if (signed_num < 0) 417 { 418 sign = '-'; 419 num = -signed_num; 420 } 421 else 422 num = signed_num; 423 } 424 else 425 { 426 // 设置符号 427 sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0); 428 } 429 430 // sign占用了一个宽度 431 if (sign) 432 --field_width; 433 434 if (flags & SPECIAL) 435 if (base == 16) // 0x占用2个位置 436 field_width -= 2; 437 else if (base == 8) // O占用一个位置 438 --field_width; 439 440 int js_num = 0; // 临时数字字符串tmp_num的长度 441 442 if (num == 0) 443 tmp_num[js_num++] = '0'; 444 else 445 { 446 num = ABS(num); 447 //进制转换 448 while (num > 0) 449 { 450 tmp_num[js_num++] = digits[num % base]; // 注意这里,输出的数字,是小端对齐的。低位存低位 451 num /= base; 452 } 453 } 454 455 if (js_num > precision) 456 precision = js_num; 457 458 field_width -= precision; 459 460 // 靠右对齐 461 if (!(flags & (LEFT + PAD_ZERO))) 462 while (field_width-- > 0) 463 *str++ = ' '; 464 465 if (sign) 466 *str++ = sign; 467 if (flags & SPECIAL) 468 if (base == 16) 469 { 470 *str++ = '0'; 471 *str++ = digits[33]; 472 } 473 else if (base == 8) 474 *str++ = digits[24]; //注意这里是英文字母O或者o 475 if (!(flags & LEFT)) 476 while (field_width-- > 0) 477 *str++ = pad; 478 while (js_num < precision) 479 { 480 --precision; 481 *str++ = '0'; 482 } 483 484 while (js_num-- > 0) 485 *str++ = tmp_num[js_num]; 486 487 while (field_width-- > 0) 488 *str++ = ' '; 489 490 return str; 491 } 492 493 static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags) 494 { 495 /** 496 * @brief 将浮点数按照指定的要求转换成对应的字符串 497 * 498 * @param str 要返回的字符串 499 * @param num 要打印的数值 500 * @param field_width 区域宽度 501 * @param precision 精度 502 * @param flags 标志位 503 */ 504 505 char pad, sign, tmp_num_z[100], tmp_num_d[350]; 506 507 const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 508 // 显示小写字母 509 if (flags & SMALL) 510 digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 511 512 // 设置填充元素 513 pad = (flags & PAD_ZERO) ? '0' : ' '; 514 sign = 0; 515 if (flags & SIGN && num < 0) 516 { 517 sign = '-'; 518 num = -num; 519 } 520 else 521 { 522 // 设置符号 523 sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0); 524 } 525 526 // sign占用了一个宽度 527 if (sign) 528 --field_width; 529 530 int js_num_z = 0, js_num_d = 0; // 临时数字字符串tmp_num_z tmp_num_d的长度 531 uint64_t num_z = (uint64_t)(num); // 获取整数部分 532 uint64_t num_decimal = (uint64_t)(round(1.0 * (num - num_z) * pow(10, precision))); // 获取小数部分 533 534 if (num == 0 || num_z == 0) 535 tmp_num_z[js_num_z++] = '0'; 536 else 537 { 538 //存储整数部分 539 while (num_z > 0) 540 { 541 tmp_num_z[js_num_z++] = digits[num_z % 10]; // 注意这里,输出的数字,是小端对齐的。低位存低位 542 num_z /= 10; 543 } 544 } 545 546 while (num_decimal > 0) 547 { 548 tmp_num_d[js_num_d++] = digits[num_decimal % 10]; 549 num_decimal /= 10; 550 } 551 552 field_width -= (precision + 1 + js_num_z); 553 554 // 靠右对齐 555 if (!(flags & LEFT)) 556 while (field_width-- > 0) 557 *str++ = pad; 558 559 if (sign) 560 *str++ = sign; 561 562 // 输出整数部分 563 while (js_num_z > 0) 564 { 565 *str++ = tmp_num_z[js_num_z - 1]; 566 --js_num_z; 567 } 568 *str++ = '.'; 569 570 // 输出小数部分 571 int total_dec_count = js_num_d; 572 for (int i = 0; i < precision && js_num_d-- > 0; ++i) 573 *str++ = tmp_num_d[js_num_d]; 574 575 while (total_dec_count < precision) 576 { 577 ++total_dec_count; 578 *str++ = '0'; 579 } 580 581 while (field_width-- > 0) 582 *str++ = ' '; 583 584 return str; 585 } 586 587 /** 588 * @brief 格式化打印字符串 589 * 590 * @param FRcolor 前景色 591 * @param BKcolor 背景色 592 * @param ... 格式化字符串 593 */ 594 int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...) 595 { 596 uint64_t rflags; 597 spin_lock_irqsave(&__printk_lock, rflags); 598 va_list args; 599 va_start(args, fmt); 600 char buf[4096]; // vsprintf()的缓冲区 601 int len = vsprintf(buf, fmt, args); 602 603 va_end(args); 604 unsigned char current; 605 606 int i; // 总共输出的字符数 607 for (i = 0; i < len; ++i) 608 { 609 current = *(buf + i); 610 // 输出 611 textui_putchar(current, FRcolor, BKcolor); 612 } 613 spin_unlock_irqrestore(&__printk_lock, rflags); 614 return i; 615 } 616 617 int sprintk(char *buf, const char *fmt, ...) 618 { 619 int count = 0; 620 va_list args; 621 622 va_start(args, fmt); 623 count = vsprintf(buf, fmt, args); 624 va_end(args); 625 626 return count; 627 } 628