127 is a control character.
[pintos-anon] / src / lib / stdio.c
index 95dfdbe66273b8c8557813e0064b9f60b08afd0f..5fb052159c70f480c854c0302e178f647410be70 100644 (file)
@@ -1,5 +1,7 @@
-#include <ctype.h>
 #include <stdio.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <round.h>
 #include <stdint.h>
 #include <string.h>
 
@@ -142,13 +144,13 @@ static const struct integer_base base_X = {16, "0123456789ABCDEF", "0X", 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);
 
@@ -198,6 +200,9 @@ __vprintf (const char *format, va_list args,
               case INT:
                 value = va_arg (args, int);
                 break;
+              case INTMAX:
+                value = va_arg (args, intmax_t);
+                break;
               case LONG:
                 value = va_arg (args, long);
                 break;
@@ -209,13 +214,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;
           
@@ -239,6 +246,9 @@ __vprintf (const char *format, va_list args,
               case INT:
                 value = va_arg (args, unsigned);
                 break;
+              case INTMAX:
+                value = va_arg (args, uintmax_t);
+                break;
               case LONG:
                 value = va_arg (args, unsigned long);
                 break;
@@ -247,6 +257,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);
@@ -263,8 +276,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;
 
@@ -297,7 +310,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;
       
@@ -448,12 +462,14 @@ 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 IS_SIGNED.  The output will
+   use the given DIGITS, with strlen(DIGITS) indicating the
+   output base.  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)
 {
@@ -461,42 +477,41 @@ format_integer (uintmax_t value, bool negative, const struct integer_base *b,
   const char *signifier;        /* b->signifier or "". */
   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. */
 
   /* 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. */
   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". */
   precision = c->precision < 0 ? 1 : c->precision;
-  if (precision < 0)
-    precision = 1;
   while (cp - buf < precision && cp - buf < (int) sizeof buf - 8)
     *cp++ = '0';
 
   /* Append sign. */
-  if (c->flags & PLUS)
-    *cp++ = negative ? '-' : '+';
-  else if (c->flags & SPACE)
-    *cp++ = negative ? '-' : ' ';
-  else if (negative)
-    *cp++ = '-';
-
+  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);
@@ -528,16 +543,16 @@ 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);
+  if (c->width > length && (c->flags & MINUS) == 0)
+    output_dup (' ', c->width - length, output, aux);
   while (length-- > 0)
     output (*string++, aux);
-  if (c->width > 1 && (c->flags & MINUS) != 0)
-    output_dup (' ', c->width - 1, output, aux);
+  if (c->width > length && (c->flags & MINUS) != 0)
+    output_dup (' ', c->width - length, output, aux);
 }
 
 /* Wrapper for __vprintf() that converts varargs into a
@@ -552,51 +567,55 @@ __printf (const char *format,
   __vprintf (format, args, output, aux);
   va_end (args);
 }
-
-/* Writes string S to the console, followed by a new-line
-   character. */
-int
-puts (const char *s) 
-{
-  while (*s != '\0')
-    putchar (*s++);
-  putchar ('\n');
-  return 0;
-}
 \f
-/* Dumps the SIZE bytes in BUFFER to the console as hex bytes
-   arranged 16 per line.  If ASCII is true then the corresponding
-   ASCII characters are also rendered alongside. */   
+/* Dumps the SIZE bytes in BUF to the console as hex bytes
+   arranged 16 per line.  Numeric offsets are also included,
+   starting at OFS for the first byte in BUF.  If ASCII is true
+   then the corresponding ASCII characters are also rendered
+   alongside. */   
 void
-hex_dump (const void *buffer, size_t size, bool ascii)
+hex_dump (uintptr_t ofs, const void *buf_, size_t size, bool ascii)
 {
-  const size_t n_per_line = 16; /* Maximum bytes per line. */
-  size_t n;                     /* Number of bytes in this line. */
-  const uint8_t *p;             /* Start of current line in buffer. */
+  const uint8_t *buf = buf_;
+  const size_t per_line = 16; /* Maximum bytes per line. */
 
-  for (p = buffer; p < (uint8_t *) buffer + size; p += n) 
+  while (size > 0)
     {
+      size_t start, end, n;
       size_t i;
-
+      
       /* Number of bytes on this line. */
-      n = (uint8_t *) (buffer + size) - p;
-      if (n > n_per_line)
-        n = n_per_line;
+      start = ofs % per_line;
+      end = per_line;
+      if (end - start > size)
+        end = start + size;
+      n = end - start;
 
       /* Print line. */
-      for (i = 0; i < n; i++) 
-        printf ("%c%02x", i == n_per_line / 2 ? '-' : ' ', (unsigned) p[i]);
+      printf ("%08jx  ", (uintmax_t) ROUND_DOWN (ofs, per_line));
+      for (i = 0; i < start; i++)
+        printf ("   ");
+      for (; i < end; i++) 
+        printf ("%02hhx%c",
+                buf[i - start], i == per_line / 2 - 1? '-' : ' ');
       if (ascii) 
         {
-          for (; i < n_per_line; i++)
+          for (; i < per_line; i++)
             printf ("   ");
-          printf (" |");
-          for (i = 0; i < n; i++)
-            printf ("%c", isprint (p[i]) ? p[i] : '.');
-          for (; i < n_per_line; i++)
+          printf ("|");
+          for (i = 0; i < start; i++)
+            printf (" ");
+          for (; i < end; i++)
+            printf ("%c",
+                    isprint (buf[i - start]) ? buf[i - start] : '.');
+          for (; i < per_line; i++)
             printf (" ");
           printf ("|");
         }
       printf ("\n");
+
+      ofs += n;
+      buf += n;
+      size -= n;
     }
 }