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 }