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 }