printf.c 13 KB

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