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