X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=blobdiff_plain;f=src%2Flib%2Fstdio.c;h=8927c50555d9993ae1ac952e21bc3fe7deb93f7e;hp=4b0ba1967f2698bbce124fd4cad9bfb3ac17ff95;hb=a03618133f7df0954802a470a4bee7674f7aed45;hpb=372d49062a54fb5b1741cd828b0266a67196a8e3 diff --git a/src/lib/stdio.c b/src/lib/stdio.c index 4b0ba19..8927c50 100644 --- a/src/lib/stdio.c +++ b/src/lib/stdio.c @@ -74,8 +74,7 @@ snprintf (char *buffer, size_t buf_size, const char *format, ...) /* Writes formatted output to the console. In the kernel, the console is both the video display and first serial port. - In userspace, the console is file descriptor 1. -*/ + In userspace, the console is file descriptor 1. */ int printf (const char *format, ...) { @@ -132,25 +131,25 @@ struct integer_base { int base; /* Base. */ const char *digits; /* Collection of digits. */ - const char *signifier; /* Prefix used with # flag. */ + int x; /* `x' character to use, for base 16 only. */ int group; /* Number of digits to group with ' flag. */ }; -static const struct integer_base base_d = {10, "0123456789", "", 3}; -static const struct integer_base base_o = {8, "01234567", "0", 3}; -static const struct integer_base base_x = {16, "0123456789abcdef", "0x", 4}; -static const struct integer_base base_X = {16, "0123456789ABCDEF", "0X", 4}; +static const struct integer_base base_d = {10, "0123456789", 0, 3}; +static const struct integer_base base_o = {8, "01234567", 0, 3}; +static const struct integer_base base_x = {16, "0123456789abcdef", 'x', 4}; +static const struct integer_base base_X = {16, "0123456789ABCDEF", 'X', 4}; static const char *parse_conversion (const char *format, struct printf_conversion *, va_list *); -static void format_integer (uintmax_t value, bool negative, +static void format_integer (uintmax_t value, bool is_signed, bool negative, const struct integer_base *, const struct printf_conversion *, void (*output) (char, void *), void *aux); static void output_dup (char ch, size_t cnt, void (*output) (char, void *), void *aux); -static void format_string (const char *string, size_t length, +static void format_string (const char *string, int length, struct printf_conversion *, void (*output) (char, void *), void *aux); @@ -214,13 +213,15 @@ __vprintf (const char *format, va_list args, break; case SIZET: value = va_arg (args, size_t); + if (value > SIZE_MAX / 2) + value = value - SIZE_MAX - 1; break; default: NOT_REACHED (); } format_integer (value < 0 ? -value : value, - value < 0, &base_d, &c, output, aux); + true, value < 0, &base_d, &c, output, aux); } break; @@ -255,6 +256,9 @@ __vprintf (const char *format, va_list args, break; case PTRDIFFT: value = va_arg (args, ptrdiff_t); +#if UINTMAX_MAX != PTRDIFF_MAX + value &= ((uintmax_t) PTRDIFF_MAX << 1) | 1; +#endif break; case SIZET: value = va_arg (args, size_t); @@ -271,8 +275,8 @@ __vprintf (const char *format, va_list args, case 'X': b = &base_X; break; default: NOT_REACHED (); } - - format_integer (value, false, b, &c, output, aux); + + format_integer (value, false, false, b, &c, output, aux); } break; @@ -305,7 +309,8 @@ __vprintf (const char *format, va_list args, void *p = va_arg (args, void *); c.flags = POUND; - format_integer ((uintptr_t) p, false, &base_x, &c, output, aux); + format_integer ((uintptr_t) p, false, false, + &base_x, &c, output, aux); } break; @@ -456,66 +461,83 @@ parse_conversion (const char *format, struct printf_conversion *c, /* Performs an integer conversion, writing output to OUTPUT with auxiliary data AUX. The integer converted has absolute value - VALUE. If NEGATIVE is true the value is negative, otherwise - positive. The output will use the given DIGITS, with - strlen(DIGITS) indicating the output base. Details of the - conversion are in C. */ + VALUE. If IS_SIGNED is true, does a signed conversion with + NEGATIVE indicating a negative value; otherwise does an + unsigned conversion and ignores NEGATIVE. The output is done + according to the provided base B. Details of the conversion + are in C. */ static void -format_integer (uintmax_t value, bool negative, const struct integer_base *b, +format_integer (uintmax_t value, bool is_signed, bool negative, + const struct integer_base *b, const struct printf_conversion *c, void (*output) (char, void *), void *aux) { char buf[64], *cp; /* Buffer and current position. */ - const char *signifier; /* b->signifier or "". */ + int x; /* `x' character to use or 0 if none. */ + int sign; /* Sign character or 0 if none. */ int precision; /* Rendered precision. */ int pad_cnt; /* # of pad characters to fill field width. */ - int group_cnt; /* # of digits grouped so far. */ + int digit_cnt; /* # of digits output so far. */ + + /* Determine sign character, if any. + An unsigned conversion will never have a sign character, + even if one of the flags requests one. */ + sign = 0; + if (is_signed) + { + if (c->flags & PLUS) + sign = negative ? '-' : '+'; + else if (c->flags & SPACE) + sign = negative ? '-' : ' '; + else if (negative) + sign = '-'; + } + + /* Determine whether to include `0x' or `0X'. + It will only be included with a hexadecimal conversion of a + nonzero value with the # flag. */ + x = (c->flags & POUND) && value ? b->x : 0; /* Accumulate digits into buffer. This algorithm produces digits in reverse order, so later we - will output the buffer's content in reverse. This is also - the reason that later we append zeros and the sign. */ + will output the buffer's content in reverse. */ cp = buf; - group_cnt = 0; + digit_cnt = 0; while (value > 0) { - if ((c->flags & GROUP) && group_cnt++ == b->group) - { - *cp++ = ','; - group_cnt = 0; - } + if ((c->flags & GROUP) && digit_cnt > 0 && digit_cnt % b->group == 0) + *cp++ = ','; *cp++ = b->digits[value % b->base]; value /= b->base; + digit_cnt++; } /* Append enough zeros to match precision. If requested precision is 0, then a value of zero is - rendered as a null string, otherwise as "0". */ + rendered as a null string, otherwise as "0". + If the # flag is used with base 8, the result must always + begin with a zero. */ precision = c->precision < 0 ? 1 : c->precision; - if (precision < 0) - precision = 1; - while (cp - buf < precision && cp - buf < (int) sizeof buf - 8) + while (cp - buf < precision && cp < buf + sizeof buf - 1) + *cp++ = '0'; + if ((c->flags & POUND) && b->base == 8 && (cp == buf || cp[-1] != '0')) *cp++ = '0'; - - /* Append sign. */ - if (c->flags & PLUS) - *cp++ = negative ? '-' : '+'; - else if (c->flags & SPACE) - *cp++ = negative ? '-' : ' '; - else if (negative) - *cp++ = '-'; /* Calculate number of pad characters to fill field width. */ - signifier = c->flags & POUND ? b->signifier : ""; - pad_cnt = c->width - (cp - buf) - strlen (signifier); + pad_cnt = c->width - (cp - buf) - (x ? 2 : 0) - (sign != 0); if (pad_cnt < 0) pad_cnt = 0; /* Do output. */ if ((c->flags & (MINUS | ZERO)) == 0) output_dup (' ', pad_cnt, output, aux); - while (*signifier != '\0') - output (*signifier++, aux); + if (sign) + output (sign, aux); + if (x) + { + output ('0', aux); + output (x, aux); + } if (c->flags & ZERO) output_dup ('0', pad_cnt, output, aux); while (cp > buf) @@ -536,16 +558,17 @@ output_dup (char ch, size_t cnt, void (*output) (char, void *), void *aux) the conversion specified in C. Writes output to OUTPUT with auxiliary data AUX. */ static void -format_string (const char *string, size_t length, +format_string (const char *string, int length, struct printf_conversion *c, void (*output) (char, void *), void *aux) { - if (c->width > 1 && (c->flags & MINUS) == 0) - output_dup (' ', c->width - 1, output, aux); - while (length-- > 0) - output (*string++, aux); - if (c->width > 1 && (c->flags & MINUS) != 0) - output_dup (' ', c->width - 1, output, aux); + int i; + if (c->width > length && (c->flags & MINUS) == 0) + output_dup (' ', c->width - length, output, aux); + for (i = 0; i < length; i++) + output (string[i], aux); + if (c->width > length && (c->flags & MINUS) != 0) + output_dup (' ', c->width - length, output, aux); } /* Wrapper for __vprintf() that converts varargs into a @@ -612,3 +635,21 @@ hex_dump (uintptr_t ofs, const void *buf_, size_t size, bool ascii) size -= n; } } + +/* Prints SIZE, which represents a number of bytes, in a + human-readable format, e.g. "256 kB". */ +void +print_human_readable_size (uint64_t size) +{ + if (size == 1) + printf ("1 byte"); + else + { + static const char *factors[] = {"bytes", "kB", "MB", "GB", "TB", NULL}; + const char **fp; + + for (fp = factors; size >= 1024 && fp[1] != NULL; fp++) + size /= 1024; + printf ("%"PRIu64" %s", size, *fp); + } +}