📄 printf.c
字号:
#include "stdarg.h"#include "stdlib.h"void printf(const char* templ, ...);void vprintf(const char* templ, va_list ap);static void put_oct(unsigned long x, int padding, int width, int nice);static void put_dec(unsigned long x, int padding, int width, int is_signed, int sign);static void put_hex(unsigned long x, int padding, int width, int nice, int hex_case);static void put_chr(int c, int width, int nice);static void put_str(const char* str, int width, int nice);/* printf(template, ...) vprintf(template, ap) -------------------------------------------------------------- printf() is a simplified printf-like function that writes up the output string to the console using putchar(). The following formatting fields are recognised and have the usual meaning: %%, %c, %d, %i, %o, %s, %u, %x, and %X. Further, the "l" option may be inserted before the format characters "d", "i", "o", "u", "x" and "X" to indicate that the corresponding argument is an long or unsigned long. If "l" is ommited, the argument is interpreted as an int or unsigned int. Also, the "#" flag may be inserted after "%" is the %c, %s, %o, %x and %X fields. In the %o, %x and %X field, it has the usual effect of printing the number as a C constant. In a %c field, it indicates that non-printable characters should be converted to the ^X (if possible) or \xxx escape sequence (this includes \t and \v.) In a %s field, it escapes all non-printable characters except for spaces which are compressed to a single space. The '0', '+', '-' and ' ' flags and the field width specifier may also preceed the format character. Note that the %p format specifier, the precision field, the '*' syntax and the XPG4 '`' flag and '$' syntax are not supported. All that said, printf() wouldn't be worth the bother if the code had to be written from scratch ;) It's been taken directly from libsulima.*/void printf(const char* templ, ...){ va_list ap; va_start(ap, templ); vprintf(templ, ap); va_end(ap);}void vprintf(const char* templ, va_list ap){ const char* p; unsigned long x; /* Process the template. */ for (p = templ; *p != '\0'; ++p) { if (*p != '%' || *++p == '%') putchar(*p); else { int left = 0; /* the - flag */ int nice = 0; /* the # flag */ int padding = ' '; /* the 0 flag */ int sign = 0; /* the + and ' ' flags */ int width = 0; /* the - flag and the field width */ int lflag; /* the l modifier */ int digit; /* Process a format specifier flags. */ for (;;) { int flag =* p++; if (flag == '-') left = 1; else if (flag == '+') sign = '+'; else if (flag == ' ') sign = (sign != '\0') ? sign : ' '; else if (flag == '#') nice = 1; else if (flag == '0') padding = '0'; else { --p; break; } } /* Process the field width. */ digit = *p++; while (digit >= '0' && digit <= '9') { width = width * 10 + digit - '0'; digit = *p++; } --p; if (left) width = -width; /* Process the "l" format modifier. */ if (*p != 'l') lflag = 0; else { lflag = 1; ++p; } /* Process the format specifier. */ switch (*p) { case 'c': put_chr(va_arg(ap, int), width, nice); break; case 'd': case 'i': x = (lflag) ? va_arg(ap, long) : (long)va_arg(ap, int); put_dec(x, padding, width, 1, sign); break; case 'o': x = (lflag) ? va_arg(ap, long) : (long)va_arg(ap, int); put_oct(x, padding, width, nice); break; case 's': put_str(va_arg(ap, const char*), width, nice); break; case 'u': x = (lflag) ? va_arg(ap, long) : (long)va_arg(ap, int); put_dec(x, padding, width, 0, sign); break; case 'x': x = (lflag) ? va_arg(ap, long) : (long)va_arg(ap, int); put_hex(x, padding, width, nice, 'a'); break; case 'X': x = (lflag) ? va_arg(ap, long) : (long)va_arg(ap, int); put_hex(x, padding, width, nice, 'A'); break; case 'p': x = va_arg(ap, long); put_str("0x", 0, 0); put_hex(x, '0', 16, 0, 'A'); break; } } }}/* put_oct(x, padding, width, nice) put_dec(x, padding, width, is_signed, sign) put_hex(x, padding, width, nice, hex_case) -------------------------------------------------------------- Echo an octal, decimal or hexadecimal number. "hex_case" is either 'a' or 'A'. "nice" is 1 if the '#' flag is specified. "padding" is the left-padding character. "sign" is set to the prevailing '+' or ' ' flag, or is 0. "is_signed" is 1 for signed conversions "width" is the field width, negated for the '-' flag.*/void put_oct( unsigned long x, int padding, int width, int nice){ int flush_left; char buffer[(sizeof(x) * 8 + 2) / 3 + 2]; char* p = buffer; /* Don't print the initial '0' in front of a 0. */ if (x == 0) nice = 0; /* Align left if width is negative. */ if (width >= 0) flush_left = 0; else { flush_left = 1; width = -width; } /* Generate the digits (least-signficant one first.) */ do { *p++ = (x & 7) + '0'; } while (x >>= 3); /* Print the 'nice' zero. */ if (nice) *p++ = '0'; /* Adjust the width by the number of already-generated characters. */ width -= (p - buffer); /* Print the left padding. */ if (!flush_left) for (; width > 0; --width) putchar(padding); /* Print the generated digits in a reversed order. */ do { putchar(*--p); } while (p > buffer); /* Print the right padding. */ for (; width > 0; --width) putchar(' ');}void put_dec( unsigned long x, int padding, int width, int is_signed, int sign){ /* The buffer size uses log10(2) == 0.30103. */ char buffer[sizeof(x) * 8 * 30103L / 100000L + 2]; int flush_left; char* p = buffer; /* For signed conversions, grab the absolute value of the number. */ if (!is_signed) sign = 0; else { /* Process the sign and distard it from x. */ if ((long)x < 0) { sign = '-'; x = -x; } } /* Align left if width is negative. */ if (width >= 0) flush_left = 0; else { flush_left = 1; width = -width; } /* Generate the digits (least-signficant one first.) */ do { *p++ = (x % 10) + '0'; x /= 10; } while (x); /* Print the sign character. */ if (sign) *p++ = sign; /* Adjust the width by the number of already-generated characters. */ width -= (p - buffer); /* Print the left padding. */ if (!flush_left) for (; width > 0; --width) putchar(padding); /* Print the generated digits in a reversed order. */ do { putchar(*--p); } while (p > buffer); /* Print the right padding. */ for (; width > 0; --width) putchar(' ');}void put_hex( unsigned long x, int padding, int width, int nice, int hex_case){ int flush_left; char buffer[sizeof(x) * 8 / 4 + 2]; char* p = buffer; /* Align left if width is negative. */ if (width >= 0) flush_left = 0; else { flush_left = 1; width = -width; } /* Generate the digits (least-signficant one first.) */ do { int digit = x & 15; *p++ = digit + ((digit < 10) ? '0' : hex_case - 10); } while (x >>= 4); /* Print the 'nice' 0x. */ if (nice) { *p++ = 'x' - 'a' + hex_case; *p++ = '0'; } /* Adjust the width by the number of already-generated characters. */ width -= (p - buffer); /* Print the left padding. */ if (!flush_left) { for (; width > 0; --width) putchar(padding); } /* Print the generated digits in a reversed order. */ do { putchar(*--p); } while (p > buffer); /* Print the right padding. */ for (; width > 0; --width) putchar(' ');}/* put_chr(c, width, nice) put_str(s, width, nice) -------------------------------------------------------------- Print a character or a string.*/void put_chr( int c, int width, int nice){ unsigned char x = c; if (!nice || (x >= ' ' && x < '\177')) { while (width > 1) { /* Pad on the left. */ putchar(' '); --width; } putchar(x); while (width < -1) { /* Pad on the right. */ putchar(' '); ++width; } } else if (x > '\177') { while (width > 4) { /* Pad on the left. */ putchar(' '); --width; } putchar('\\'); putchar((x >> 6) & 7); putchar((x >> 3) & 7); putchar((x >> 0) & 7); while (width < -4) { /* Pad on the right. */ putchar(' '); ++width; } } else { while (width > 2) { /* Pad on the left. */ putchar(' '); --width; } putchar('^'); putchar((x + '@') & 127); width -= 2; while (width < -2) { /* Pad on the right. */ putchar(' '); ++width; } }}void put_str( const char* str, int width, int nice){ const char* p; int length = 0; if (width) { if (!nice) length = strlen(str); else { for (p = str; *p; ++p) { unsigned char x = *p; if ((x >= ' ' && x < '\177') || isspace(x)) ++length; else if (x > '\177') length += 4; else length += 2; } } } while (width > length) { /* Pad on the left. */ putchar(' '); --width; } if (!nice) { while (*str) putchar(*str++); } else { while (*str) { unsigned char x = *str++; if ((x >= ' ' && x < '\177') || isspace(x)) putchar(x); else if (x > '\177') { putchar('\\'); putchar((x >> 6) & 7); putchar((x >> 3) & 7); putchar((x >> 0) & 7); } else { putchar('^'); putchar((x + '@') & 127); } } } while (width < -length) { /* Pad on the right. */ putchar(' '); ++width; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -