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
skip_and_atoi(const char ** s)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 */
__do_vsprintf(char * buf,const char * fmt,int buf_size,va_list args)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 */
vsprintf(char * buf,const char * fmt,va_list args)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 */
vsnprintf(char * buf,const char * fmt,int buf_size,va_list args)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
write_num(char * str,ul num,int base,int field_width,int precision,int flags)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
write_float_point_num(char * str,double num,int field_width,int precision,int flags)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 */
printk_color(unsigned int FRcolor,unsigned int BKcolor,const char * fmt,...)594 int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...)
595 {
596 uint64_t rflags;
597 io_mfence();
598 spin_lock_irqsave(&__printk_lock, rflags);
599 io_mfence();
600 va_list args;
601 va_start(args, fmt);
602 char buf[4096]; // vsprintf()的缓冲区
603 int len = vsprintf(buf, fmt, args);
604
605 va_end(args);
606 unsigned char current;
607
608 int i; // 总共输出的字符数
609 for (i = 0; i < len; ++i)
610 {
611 current = *(buf + i);
612 // 输出
613 textui_putchar(current, FRcolor, BKcolor);
614 }
615 io_mfence();
616 spin_unlock_irqrestore(&__printk_lock, rflags);
617 io_mfence();
618 return i;
619 }
620
sprintk(char * buf,const char * fmt,...)621 int sprintk(char *buf, const char *fmt, ...)
622 {
623 int count = 0;
624 va_list args;
625
626 va_start(args, fmt);
627 count = vsprintf(buf, fmt, args);
628 va_end(args);
629
630 return count;
631 }
632