Implement a proper block layer with partition support.
[pintos-anon] / src / lib / stdio.c
index 5fb052159c70f480c854c0302e178f647410be70..8927c50555d9993ae1ac952e21bc3fe7deb93f7e 100644 (file)
@@ -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,14 +131,14 @@ 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 *,
@@ -464,9 +463,9 @@ parse_conversion (const char *format, struct printf_conversion *c,
    auxiliary data AUX.  The integer converted has absolute value
    VALUE.  If IS_SIGNED is true, does a signed conversion with
    NEGATIVE indicating a negative value; otherwise does an
-   unsigned conversion and ignores IS_SIGNED.  The output will
-   use the given DIGITS, with strlen(DIGITS) indicating the
-   output base.  Details of the conversion are in C. */
+   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 is_signed, bool negative, 
                 const struct integer_base *b,
@@ -474,15 +473,34 @@ format_integer (uintmax_t value, bool is_signed, bool negative,
                 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 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;
   digit_cnt = 0;
   while (value > 0) 
@@ -496,33 +514,30 @@ format_integer (uintmax_t value, bool is_signed, bool negative,
 
   /* 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;
-  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 (is_signed) 
-    {
-      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)
@@ -547,10 +562,11 @@ format_string (const char *string, int length,
                struct printf_conversion *c,
                void (*output) (char, void *), void *aux) 
 {
+  int i;
   if (c->width > length && (c->flags & MINUS) == 0)
     output_dup (' ', c->width - length, output, aux);
-  while (length-- > 0)
-    output (*string++, 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);
 }
@@ -619,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);
+    }
+}