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