gencgc: More precise conservatism for pointers to boxed pages.
[sbcl.git] / src / code / print.lisp
index 7bb66a9..3aaaf74 100644 (file)
 
 (defvar *print-readably* nil
   #!+sb-doc
 
 (defvar *print-readably* nil
   #!+sb-doc
-  "If true, all objects will printed readably. If readable printing is
-  impossible, an error will be signalled. This overrides the value of
+  "If true, all objects will be printed readably. If readable printing
+  is impossible, an error will be signalled. This overrides the value of
   *PRINT-ESCAPE*.")
   *PRINT-ESCAPE*.")
-(defvar *print-escape* T
+(defvar *print-escape* t
   #!+sb-doc
   #!+sb-doc
-  "Flag which indicates that slashification is on. See the manual")
+  "Should we print in a reasonably machine-readable way? (possibly
+  overridden by *PRINT-READABLY*)")
 (defvar *print-pretty* nil ; (set later when pretty-printer is initialized)
   #!+sb-doc
 (defvar *print-pretty* nil ; (set later when pretty-printer is initialized)
   #!+sb-doc
-  "Flag which indicates that pretty printing is to be used")
+  "Should pretty printing be used?")
 (defvar *print-base* 10.
   #!+sb-doc
 (defvar *print-base* 10.
   #!+sb-doc
-  "The output base for integers and rationals.")
+  "The output base for RATIONALs (including integers).")
 (defvar *print-radix* nil
   #!+sb-doc
 (defvar *print-radix* nil
   #!+sb-doc
-  "This flag requests to verify base when printing rationals.")
+  "Should base be verified when printing RATIONALs?")
 (defvar *print-level* nil
   #!+sb-doc
 (defvar *print-level* nil
   #!+sb-doc
-  "How many levels deep to print. Unlimited if null.")
+  "How many levels should be printed before abbreviating with \"#\"?")
 (defvar *print-length* nil
   #!+sb-doc
 (defvar *print-length* nil
   #!+sb-doc
-  "How many elements to print on each level. Unlimited if null.")
+  "How many elements at any level should be printed before abbreviating
+  with \"...\"?")
 (defvar *print-circle* nil
   #!+sb-doc
 (defvar *print-circle* nil
   #!+sb-doc
-  "Whether to worry about circular list structures. See the manual.")
+  "Should we use #n= and #n# notation to preserve uniqueness in general (and
+  circularity in particular) when printing?")
 (defvar *print-case* :upcase
   #!+sb-doc
 (defvar *print-case* :upcase
   #!+sb-doc
-  "What kind of case the printer should use by default")
+  "What case should the printer should use default?")
 (defvar *print-array* t
   #!+sb-doc
 (defvar *print-array* t
   #!+sb-doc
-  "Whether the array should print its guts out")
+  "Should the contents of arrays be printed?")
 (defvar *print-gensym* t
   #!+sb-doc
 (defvar *print-gensym* t
   #!+sb-doc
-  "If true, symbols with no home package are printed with a #: prefix.
-  If false, no prefix is printed.")
+  "Should #: prefixes be used when printing symbols with null SYMBOL-PACKAGE?")
 (defvar *print-lines* nil
   #!+sb-doc
 (defvar *print-lines* nil
   #!+sb-doc
-  "The maximum number of lines to print. If NIL, unlimited.")
+  "The maximum number of lines to print per object.")
 (defvar *print-right-margin* nil
   #!+sb-doc
 (defvar *print-right-margin* nil
   #!+sb-doc
-  "The position of the right margin in ems. If NIL, try to determine this
-   from the stream in use.")
+  "The position of the right margin in ems (for pretty-printing).")
 (defvar *print-miser-width* nil
   #!+sb-doc
   "If the remaining space between the current column and the right margin
    is less than this, then print using ``miser-style'' output. Miser
    style conditional newlines are turned on, and all indentations are
    turned off. If NIL, never use miser mode.")
 (defvar *print-miser-width* nil
   #!+sb-doc
   "If the remaining space between the current column and the right margin
    is less than this, then print using ``miser-style'' output. Miser
    style conditional newlines are turned on, and all indentations are
    turned off. If NIL, never use miser mode.")
-(defvar *print-pprint-dispatch* nil
+(defvar *print-pprint-dispatch*)
+#!+sb-doc
+(setf (fdocumentation '*print-pprint-dispatch* 'variable)
+      "The pprint-dispatch-table that controls how to pretty-print objects.")
+(defvar *suppress-print-errors* nil
   #!+sb-doc
   #!+sb-doc
-  "The pprint-dispatch-table that controls how to pretty print objects. See
-   COPY-PPRINT-DISPATH, PPRINT-DISPATCH, and SET-PPRINT-DISPATCH.")
+  "Suppress printer errors when the condition is of the type designated by this
+variable: an unreadable object representing the error is printed instead.")
 
 (defmacro with-standard-io-syntax (&body body)
   #!+sb-doc
   "Bind the reader and printer control variables to values that enable READ
    to reliably read the results of PRINT. These values are:
 
 (defmacro with-standard-io-syntax (&body body)
   #!+sb-doc
   "Bind the reader and printer control variables to values that enable READ
    to reliably read the results of PRINT. These values are:
-       *PACKAGE*                       the COMMON-LISP-USER package
-       *PRINT-ARRAY*                   T
-       *PRINT-BASE*                    10
-       *PRINT-CASE*                    :UPCASE
-       *PRINT-CIRCLE*                  NIL
-       *PRINT-ESCAPE*                  T
-       *PRINT-GENSYM*                  T
-       *PRINT-LENGTH*                  NIL
-       *PRINT-LEVEL*                   NIL
-       *PRINT-LINES*                   NIL
-       *PRINT-MISER-WIDTH*             NIL
-       *PRINT-PRETTY*                  NIL
-       *PRINT-RADIX*                   NIL
-       *PRINT-READABLY*                        T
-       *PRINT-RIGHT-MARGIN*            NIL
-       *READ-BASE*                     10
-       *READ-DEFAULT-FLOAT-FORMAT*     SINGLE-FLOAT
-       *READ-EVAL*                     T
-       *READ-SUPPRESS*                 NIL
-       *READTABLE*                     the standard readtable."
-  `(%with-standard-io-syntax #'(lambda () ,@body)))
+
+         *PACKAGE*                        the COMMON-LISP-USER package
+         *PRINT-ARRAY*                    T
+         *PRINT-BASE*                     10
+         *PRINT-CASE*                     :UPCASE
+         *PRINT-CIRCLE*                   NIL
+         *PRINT-ESCAPE*                   T
+         *PRINT-GENSYM*                   T
+         *PRINT-LENGTH*                   NIL
+         *PRINT-LEVEL*                    NIL
+         *PRINT-LINES*                    NIL
+         *PRINT-MISER-WIDTH*              NIL
+         *PRINT-PPRINT-DISPATCH*          the standard pprint dispatch table
+         *PRINT-PRETTY*                   NIL
+         *PRINT-RADIX*                    NIL
+         *PRINT-READABLY*                 T
+         *PRINT-RIGHT-MARGIN*             NIL
+         *READ-BASE*                      10
+         *READ-DEFAULT-FLOAT-FORMAT*      SINGLE-FLOAT
+         *READ-EVAL*                      T
+         *READ-SUPPRESS*                  NIL
+         *READTABLE*                      the standard readtable
+  SB-EXT:*SUPPRESS-PRINT-ERRORS*          NIL
+"
+  `(%with-standard-io-syntax (lambda () ,@body)))
 
 (defun %with-standard-io-syntax (function)
 
 (defun %with-standard-io-syntax (function)
+  (declare (type function function))
   (let ((*package* (find-package "COMMON-LISP-USER"))
   (let ((*package* (find-package "COMMON-LISP-USER"))
-       (*print-array* t)
-       (*print-base* 10)
-       (*print-case* :upcase)
-       (*print-circle* nil)
-       (*print-escape* t)
-       (*print-gensym* t)
-       (*print-length* nil)
-       (*print-level* nil)
-       (*print-lines* nil)
-       (*print-miser-width* nil)
-       (*print-pretty* nil)
-       (*print-radix* nil)
-       (*print-readably* t)
-       (*print-right-margin* nil)
-       (*read-base* 10)
-       (*read-default-float-format* 'single-float)
-       (*read-eval* t)
-       (*read-suppress* nil)
-       ;; FIXME: It doesn't seem like a good idea to expose our
-       ;; disaster-recovery *STANDARD-READTABLE* here. What if some
-       ;; enterprising user corrupts the disaster-recovery readtable
-       ;; by doing destructive readtable operations within
-       ;; WITH-STANDARD-IO-SYNTAX? Perhaps we should do a
-       ;; COPY-READTABLE? The consing would be unfortunate, though.
-       (*readtable* *standard-readtable*))
+        (*print-array* t)
+        (*print-base* 10)
+        (*print-case* :upcase)
+        (*print-circle* nil)
+        (*print-escape* t)
+        (*print-gensym* t)
+        (*print-length* nil)
+        (*print-level* nil)
+        (*print-lines* nil)
+        (*print-miser-width* nil)
+        (*print-pprint-dispatch* sb!pretty::*standard-pprint-dispatch-table*)
+        (*print-pretty* nil)
+        (*print-radix* nil)
+        (*print-readably* t)
+        (*print-right-margin* nil)
+        (*read-base* 10)
+        (*read-default-float-format* 'single-float)
+        (*read-eval* t)
+        (*read-suppress* nil)
+        (*readtable* *standard-readtable*)
+        (*suppress-print-errors* nil))
     (funcall function)))
 \f
 ;;;; routines to print objects
 
     (funcall function)))
 \f
 ;;;; routines to print objects
 
+\f
+;;; keyword variables shared by WRITE and WRITE-TO-STRING, and
+;;; the bindings they map to.
+(eval-when (:compile-toplevel :load-toplevel)
+  (defvar *printer-keyword-variables*
+    '(:escape *print-escape*
+      :radix *print-radix*
+      :base *print-base*
+      :circle *print-circle*
+      :pretty *print-pretty*
+      :level *print-level*
+      :length *print-length*
+      :case *print-case*
+      :array *print-array*
+      :gensym *print-gensym*
+      :readably *print-readably*
+      :right-margin *print-right-margin*
+      :miser-width *print-miser-width*
+      :lines *print-lines*
+      :pprint-dispatch *print-pprint-dispatch*
+      :suppress-errors *suppress-print-errors*)))
+
 (defun write (object &key
 (defun write (object &key
-                    ((:stream stream) *standard-output*)
-                    ((:escape *print-escape*) *print-escape*)
-                    ((:radix *print-radix*) *print-radix*)
-                    ((:base *print-base*) *print-base*)
-                    ((:circle *print-circle*) *print-circle*)
-                    ((:pretty *print-pretty*) *print-pretty*)
-                    ((:level *print-level*) *print-level*)
-                    ((:length *print-length*) *print-length*)
-                    ((:case *print-case*) *print-case*)
-                    ((:array *print-array*) *print-array*)
-                    ((:gensym *print-gensym*) *print-gensym*)
-                    ((:readably *print-readably*) *print-readably*)
-                    ((:right-margin *print-right-margin*)
-                     *print-right-margin*)
-                    ((:miser-width *print-miser-width*)
-                     *print-miser-width*)
-                    ((:lines *print-lines*) *print-lines*)
-                    ((:pprint-dispatch *print-pprint-dispatch*)
-                     *print-pprint-dispatch*))
+                     ((:stream stream) *standard-output*)
+                     ((:escape *print-escape*) *print-escape*)
+                     ((:radix *print-radix*) *print-radix*)
+                     ((:base *print-base*) *print-base*)
+                     ((:circle *print-circle*) *print-circle*)
+                     ((:pretty *print-pretty*) *print-pretty*)
+                     ((:level *print-level*) *print-level*)
+                     ((:length *print-length*) *print-length*)
+                     ((:case *print-case*) *print-case*)
+                     ((:array *print-array*) *print-array*)
+                     ((:gensym *print-gensym*) *print-gensym*)
+                     ((:readably *print-readably*) *print-readably*)
+                     ((:right-margin *print-right-margin*)
+                      *print-right-margin*)
+                     ((:miser-width *print-miser-width*)
+                      *print-miser-width*)
+                     ((:lines *print-lines*) *print-lines*)
+                     ((:pprint-dispatch *print-pprint-dispatch*)
+                      *print-pprint-dispatch*)
+                     ((:suppress-errors *suppress-print-errors*)
+                      *suppress-print-errors*))
   #!+sb-doc
   #!+sb-doc
-  "Outputs OBJECT to the specified stream, defaulting to *STANDARD-OUTPUT*"
+  "Output OBJECT to the specified stream, defaulting to *STANDARD-OUTPUT*."
   (output-object object (out-synonym-of stream))
   object)
 
   (output-object object (out-synonym-of stream))
   object)
 
+;;; Optimize common case of constant keyword arguments
+(define-compiler-macro write (&whole form object &rest keys)
+  (let (bind ignore)
+    (do ()
+        ((not (cdr keys))
+         ;; Odd number of keys, punt
+         (when keys
+           (return-from write form)))
+      (let* ((key (pop keys))
+             (value (pop keys))
+             (variable (or (getf *printer-keyword-variables* key)
+                           (when (eq :stream key)
+                             'stream)
+                           (return-from write form))))
+        (when (assoc variable bind)
+          ;; First key has precedence, but we still need to execute the
+          ;; argument, and in the right order.
+          (setf variable (gensym "IGNORE"))
+          (push variable ignore))
+        (push (list variable value) bind)))
+    (unless (assoc 'stream bind)
+      (push (list 'stream '*standard-output*) bind))
+    (once-only ((object object))
+      `(let ,(nreverse bind)
+         ,@(when ignore `((declare (ignore ,@ignore))))
+         (output-object ,object (out-synonym-of stream))
+         ,object))))
+
 (defun prin1 (object &optional stream)
   #!+sb-doc
 (defun prin1 (object &optional stream)
   #!+sb-doc
-  "Outputs a mostly READable printed representation of OBJECT on the specified
+  "Output a mostly READable printed representation of OBJECT on the specified
   STREAM."
   STREAM."
-  (let ((*print-escape* T))
+  (let ((*print-escape* t))
     (output-object object (out-synonym-of stream)))
   object)
 
 (defun princ (object &optional stream)
   #!+sb-doc
     (output-object object (out-synonym-of stream)))
   object)
 
 (defun princ (object &optional stream)
   #!+sb-doc
-  "Outputs an aesthetic but not necessarily READable printed representation
+  "Output an aesthetic but not necessarily READable printed representation
   of OBJECT on the specified STREAM."
   of OBJECT on the specified STREAM."
-  (let ((*print-escape* NIL)
-       (*print-readably* NIL))
+  (let ((*print-escape* nil)
+        (*print-readably* nil))
     (output-object object (out-synonym-of stream)))
   object)
 
 (defun print (object &optional stream)
   #!+sb-doc
     (output-object object (out-synonym-of stream)))
   object)
 
 (defun print (object &optional stream)
   #!+sb-doc
-  "Outputs a terpri, the mostly READable printed represenation of OBJECT, and
+  "Output a newline, the mostly READable printed representation of OBJECT, and
   space to the specified STREAM."
   (let ((stream (out-synonym-of stream)))
     (terpri stream)
   space to the specified STREAM."
   (let ((stream (out-synonym-of stream)))
     (terpri stream)
 
 (defun pprint (object &optional stream)
   #!+sb-doc
 
 (defun pprint (object &optional stream)
   #!+sb-doc
-  "Prettily outputs OBJECT preceded by a newline."
+  "Prettily output OBJECT preceded by a newline."
   (let ((*print-pretty* t)
   (let ((*print-pretty* t)
-       (*print-escape* t)
-       (stream (out-synonym-of stream)))
+        (*print-escape* t)
+        (stream (out-synonym-of stream)))
     (terpri stream)
     (output-object object stream))
   (values))
 
 (defun write-to-string
     (terpri stream)
     (output-object object stream))
   (values))
 
 (defun write-to-string
-       (object &key
-              ((:escape *print-escape*) *print-escape*)
-              ((:radix *print-radix*) *print-radix*)
-              ((:base *print-base*) *print-base*)
-              ((:circle *print-circle*) *print-circle*)
-              ((:pretty *print-pretty*) *print-pretty*)
-              ((:level *print-level*) *print-level*)
-              ((:length *print-length*) *print-length*)
-              ((:case *print-case*) *print-case*)
-              ((:array *print-array*) *print-array*)
-              ((:gensym *print-gensym*) *print-gensym*)
-              ((:readably *print-readably*) *print-readably*)
-              ((:right-margin *print-right-margin*) *print-right-margin*)
-              ((:miser-width *print-miser-width*) *print-miser-width*)
-              ((:lines *print-lines*) *print-lines*)
-              ((:pprint-dispatch *print-pprint-dispatch*)
-               *print-pprint-dispatch*))
+    (object &key
+            ((:escape *print-escape*) *print-escape*)
+            ((:radix *print-radix*) *print-radix*)
+            ((:base *print-base*) *print-base*)
+            ((:circle *print-circle*) *print-circle*)
+            ((:pretty *print-pretty*) *print-pretty*)
+            ((:level *print-level*) *print-level*)
+            ((:length *print-length*) *print-length*)
+            ((:case *print-case*) *print-case*)
+            ((:array *print-array*) *print-array*)
+            ((:gensym *print-gensym*) *print-gensym*)
+            ((:readably *print-readably*) *print-readably*)
+            ((:right-margin *print-right-margin*) *print-right-margin*)
+            ((:miser-width *print-miser-width*) *print-miser-width*)
+            ((:lines *print-lines*) *print-lines*)
+            ((:pprint-dispatch *print-pprint-dispatch*)
+             *print-pprint-dispatch*)
+            ((:suppress-errors *suppress-print-errors*)
+             *suppress-print-errors*))
   #!+sb-doc
   #!+sb-doc
-  "Returns the printed representation of OBJECT as a string."
+  "Return the printed representation of OBJECT as a string."
   (stringify-object object))
 
   (stringify-object object))
 
+;;; Optimize common case of constant keyword arguments
+(define-compiler-macro write-to-string (&whole form object &rest keys)
+  (let (bind ignore)
+    (do ()
+        ((not (cdr keys))
+         ;; Odd number of keys, punt
+         (when keys
+           (return-from write-to-string form)))
+      (let* ((key (pop keys))
+             (value (pop keys))
+             (variable (or (getf *printer-keyword-variables* key)
+                           (return-from write-to-string form))))
+        (when (assoc variable bind)
+          ;; First key has precedence, but we still need to execute the
+          ;; argument, and in the right order.
+          (setf variable (gensym "IGNORE"))
+          (push variable ignore))
+        (push (list variable value) bind)))
+    (if bind
+        (once-only ((object object))
+          `(let ,(nreverse bind)
+             ,@(when ignore `((declare (ignore ,@ignore))))
+             (stringify-object ,object)))
+        `(stringify-object ,object))))
+
 (defun prin1-to-string (object)
   #!+sb-doc
 (defun prin1-to-string (object)
   #!+sb-doc
-  "Returns the printed representation of OBJECT as a string with
+  "Return the printed representation of OBJECT as a string with
    slashification on."
    slashification on."
-  (stringify-object object t))
+  (let ((*print-escape* t))
+    (stringify-object object)))
 
 (defun princ-to-string (object)
   #!+sb-doc
 
 (defun princ-to-string (object)
   #!+sb-doc
-  "Returns the printed representation of OBJECT as a string with
+  "Return the printed representation of OBJECT as a string with
   slashification off."
   slashification off."
-  (stringify-object object nil))
+  (let ((*print-escape* nil)
+        (*print-readably* nil))
+    (stringify-object object)))
 
 ;;; This produces the printed representation of an object as a string.
 ;;; The few ...-TO-STRING functions above call this.
 
 ;;; This produces the printed representation of an object as a string.
 ;;; The few ...-TO-STRING functions above call this.
-(defvar *string-output-streams* ())
-(defun stringify-object (object &optional (*print-escape* *print-escape*))
-  (let ((stream (if *string-output-streams*
-                   (pop *string-output-streams*)
-                   (make-string-output-stream))))
+(defun stringify-object (object)
+  (let ((stream (make-string-output-stream)))
     (setup-printer-state)
     (output-object object stream)
     (setup-printer-state)
     (output-object object stream)
-    (prog1
-       (get-output-stream-string stream)
-      (push stream *string-output-streams*))))
+    (get-output-stream-string stream)))
 \f
 ;;;; support for the PRINT-UNREADABLE-OBJECT macro
 
 \f
 ;;;; support for the PRINT-UNREADABLE-OBJECT macro
 
+(defun print-not-readable-error (object stream)
+  (restart-case
+      (error 'print-not-readable :object object)
+    (print-unreadably ()
+      :report "Print unreadably."
+      (let ((*print-readably* nil))
+        (output-object object stream)
+        object))
+    (use-value (o)
+      :report "Supply an object to be printed instead."
+      :interactive
+      (lambda ()
+        (read-evaluated-form "~@<Enter an object (evaluated): ~@:>"))
+      (output-object o stream)
+      o)))
+
 ;;; guts of PRINT-UNREADABLE-OBJECT
 (defun %print-unreadable-object (object stream type identity body)
 ;;; guts of PRINT-UNREADABLE-OBJECT
 (defun %print-unreadable-object (object stream type identity body)
-  (when *print-readably*
-    (error 'print-not-readable :object object))
-  (flet ((print-description ()
-          (when type
-            (write (type-of object) :stream stream :circle nil
-                   :level nil :length nil)
-            (when (or body identity)
-              (write-char #\space stream)
-              (pprint-newline :fill stream)))
-          (when body
-            (funcall body))
-          (when identity
-            (when body
-              (write-char #\space stream)
-              (pprint-newline :fill stream))
-            (write-char #\{ stream)
-            (write (get-lisp-obj-address object) :stream stream
-                   :radix nil :base 16)
-            (write-char #\} stream))))
-    (cond ((print-pretty-on-stream-p stream)
-          ;; Since we're printing prettily on STREAM, format the
-          ;; object within a logical block. PPRINT-LOGICAL-BLOCK does
-          ;; not rebind the stream when it is already a pretty stream,
-          ;; so output from the body will go to the same stream.
-          (pprint-logical-block (stream nil :prefix "#<" :suffix ">")
-            (print-description)))
-         (t
-            (write-string "#<" stream)
-            (print-description)
-            (write-char #\> stream))))
+  (declare (type (or null function) body))
+  (if *print-readably*
+      (print-not-readable-error object stream)
+      (flet ((print-description ()
+               (when type
+                 (write (type-of object) :stream stream :circle nil
+                                         :level nil :length nil)
+                 (write-char #\space stream)
+                 (pprint-newline :fill stream))
+               (when body
+                 (funcall body))
+               (when identity
+                 (when (or body (not type))
+                   (write-char #\space stream))
+                 (pprint-newline :fill stream)
+                 (write-char #\{ stream)
+                 (write (get-lisp-obj-address object) :stream stream
+                                                      :radix nil :base 16)
+                 (write-char #\} stream))))
+        (cond ((print-pretty-on-stream-p stream)
+               ;; Since we're printing prettily on STREAM, format the
+               ;; object within a logical block. PPRINT-LOGICAL-BLOCK does
+               ;; not rebind the stream when it is already a pretty stream,
+               ;; so output from the body will go to the same stream.
+               (pprint-logical-block (stream nil :prefix "#<" :suffix ">")
+                 (print-description)))
+              (t
+               (write-string "#<" stream)
+               (print-description)
+               (write-char #\> stream)))))
   nil)
 \f
   nil)
 \f
-;;;; circularity detection stuff
-
-;;; When *PRINT-CIRCLE* is T, this gets bound to a hash table that
-;;; (eventually) ends up with entries for every object printed. When
-;;; we are initially looking for circularities, we enter a T when we
-;;; find an object for the first time, and a 0 when we encounter an
-;;; object a second time around. When we are actually printing, the 0
-;;; entries get changed to the actual marker value when they are first
-;;; printed.
-(defvar *circularity-hash-table* nil)
-
-;;; When NIL, we are just looking for circularities. After we have
-;;; found them all, this gets bound to 0. Then whenever we need a new
-;;; marker, it is incremented.
-(defvar *circularity-counter* nil)
-
-(defun check-for-circularity (object &optional assign)
-  #!+sb-doc
-  "Check to see whether OBJECT is a circular reference, and return something
-   non-NIL if it is. If ASSIGN is T, then the number to use in the #n= and
-   #n# noise is assigned at this time. Note: CHECK-FOR-CIRCULARITY must
-   be called *EXACTLY* once with ASSIGN T, or the circularity detection noise
-   will get confused about when to use #n= and when to use #n#. If this
-   returns non-NIL when ASSIGN is T, then you must call HANDLE-CIRCULARITY
-   on it. If you are not using this inside a WITH-CIRCULARITY-DETECTION,
-   then you have to be prepared to handle a return value of :INITIATE which
-   means it needs to initiate the circularity detection noise. See the
-   source for info on how to do that."
-  (cond ((null *print-circle*)
-        ;; Don't bother, nobody cares.
-        nil)
-       ((null *circularity-hash-table*)
-        :initiate)
-       ((null *circularity-counter*)
-        (ecase (gethash object *circularity-hash-table*)
-          ((nil)
-           ;; First encounter.
-           (setf (gethash object *circularity-hash-table*) t)
-           ;; We need to keep looking.
-           nil)
-          ((t)
-           ;; Second encounter.
-           (setf (gethash object *circularity-hash-table*) 0)
-           ;; It's a circular reference.
-           t)
-          (0
-           ;; It's a circular reference.
-           t)))
-       (t
-        (let ((value (gethash object *circularity-hash-table*)))
-          (case value
-            ((nil t)
-             ;; If NIL, we found an object that wasn't there the first time
-             ;; around. If T, exactly one occurance of this object appears.
-             ;; Either way, just print the thing without any special
-             ;; processing. Note: you might argue that finding a new object
-             ;; means that something is broken, but this can happen. If
-             ;; someone uses the ~@<...~:> format directive, it conses a
-             ;; new list each time though format (i.e. the &REST list), so
-             ;; we will have different cdrs.
-             nil)
-            (0
-             (if assign
-                 (let ((value (incf *circularity-counter*)))
-                   ;; First occurance of this object. Set the counter.
-                   (setf (gethash object *circularity-hash-table*) value)
-                   value)
-                 t))
-            (t
-             ;; Second or later occurance.
-             (- value)))))))
-
-(defun handle-circularity (marker stream)
-  #!+sb-doc
-  "Handle the results of CHECK-FOR-CIRCULARITY. If this returns T then
-   you should go ahead and print the object. If it returns NIL, then
-   you should blow it off."
-  (case marker
-    (:initiate
-     ;; Someone forgot to initiate circularity detection.
-     (let ((*print-circle* nil))
-       (error "trying to use CHECK-FOR-CIRCULARITY when ~
-              circularity checking isn't initiated")))
-    ((t)
-     ;; It's a second (or later) reference to the object while we are
-     ;; just looking. So don't bother groveling it again.
-     nil)
-    (t
-     (write-char #\# stream)
-     (let ((*print-base* 10) (*print-radix* nil))
-       (cond ((minusp marker)
-             (output-integer (- marker) stream)
-             (write-char #\# stream)
-             nil)
-            (t
-             (output-integer marker stream)
-             (write-char #\= stream)
-             t))))))
-\f
 ;;;; OUTPUT-OBJECT -- the main entry point
 
 ;;;; OUTPUT-OBJECT -- the main entry point
 
-(defvar *pretty-printer* nil
-  #!+sb-doc
-  "The current pretty printer. Should be either a function that takes two
-   arguments (the object and the stream) or NIL to indicate that there is
-   no pretty printer installed.")
+;;; Objects whose print representation identifies them EQLly don't
+;;; need to be checked for circularity.
+(defun uniquely-identified-by-print-p (x)
+  (or (numberp x)
+      (characterp x)
+      (and (symbolp x)
+           (symbol-package x))))
 
 
+(defvar *in-print-error* nil)
+
+;;; Output OBJECT to STREAM observing all printer control variables.
 (defun output-object (object stream)
 (defun output-object (object stream)
-  #!+sb-doc
-  "Output OBJECT to STREAM observing all printer control variables."
   (labels ((print-it (stream)
   (labels ((print-it (stream)
-            (if *print-pretty*
-                (if *pretty-printer*
-                    (funcall *pretty-printer* object stream)
-                    (let ((*print-pretty* nil))
-                      (output-ugly-object object stream)))
-                (output-ugly-object object stream)))
-          (check-it (stream)
-            (let ((marker (check-for-circularity object t)))
-              (case marker
-                (:initiate
-                 (let ((*circularity-hash-table*
-                        (make-hash-table :test 'eq)))
-                   (check-it (make-broadcast-stream))
-                   (let ((*circularity-counter* 0))
-                     (check-it stream))))
-                ((nil)
-                 (print-it stream))
-                (t
-                 (when (handle-circularity marker stream)
-                   (print-it stream)))))))
-    (cond ((or (not *print-circle*)
-              (numberp object)
-              (characterp object)
-              (and (symbolp object) (symbol-package object) t))
-          ;; If it a number, character, or interned symbol, we do not
-          ;; want to check for circularity/sharing.
-          (print-it stream))
-         ((or *circularity-hash-table*
-              (consp object)
-              (typep object 'instance)
-              (typep object '(array t *)))
-          ;; If we have already started circularity detection, this
-          ;; object might be a sharded reference. If we have not,
-          ;; then if it is a cons, a instance, or an array of element
-          ;; type t it might contain a circular reference to itself
-          ;; or multiple shared references.
-          (check-it stream))
-         (t
-          (print-it stream)))))
+             (if *print-pretty*
+                 (sb!pretty:output-pretty-object object stream)
+                 (output-ugly-object object stream)))
+           (handle-it (stream)
+             (if *suppress-print-errors*
+                 (handler-bind ((condition
+                                  (lambda (condition) nil
+                                    (when (typep condition *suppress-print-errors*)
+                                      (cond (*in-print-error*
+                                             (write-string "(error printing " stream)
+                                             (write-string *in-print-error* stream)
+                                             (write-string ")" stream))
+                                            (t
+                                             ;; Give outer handlers a chance.
+                                             (with-simple-restart
+                                                 (continue "Suppress the error.")
+                                               (signal condition))
+                                             (let ((*print-readably* nil)
+                                                   (*print-escape* t))
+                                               (write-string
+                                                "#<error printing a " stream)
+                                               (let ((*in-print-error* "type"))
+                                                 (output-object (type-of object) stream))
+                                               (write-string ": " stream)
+                                               (let ((*in-print-error* "condition"))
+                                                 (output-object condition stream))
+                                               (write-string ">" stream))))
+                                      (return-from handle-it object)))))
+                   (print-it stream))
+                 (print-it stream)))
+           (check-it (stream)
+             (multiple-value-bind (marker initiate)
+                 (check-for-circularity object t)
+               (if (eq initiate :initiate)
+                   (let ((*circularity-hash-table*
+                          (make-hash-table :test 'eq)))
+                     (check-it (make-broadcast-stream))
+                     (let ((*circularity-counter* 0))
+                       (check-it stream)))
+                   ;; otherwise
+                   (if marker
+                       (when (handle-circularity marker stream)
+                         (handle-it stream))
+                       (handle-it stream))))))
+    (cond (;; Maybe we don't need to bother with circularity detection.
+           (or (not *print-circle*)
+               (uniquely-identified-by-print-p object))
+           (handle-it stream))
+          (;; If we have already started circularity detection, this
+           ;; object might be a shared reference. If we have not, then
+           ;; if it is a compound object it might contain a circular
+           ;; reference to itself or multiple shared references.
+           (or *circularity-hash-table*
+               (compound-object-p object))
+           (check-it stream))
+          (t
+           (handle-it stream)))))
+
+;;; a hack to work around recurring gotchas with printing while
+;;; DEFGENERIC PRINT-OBJECT is being built
+;;;
+;;; (hopefully will go away naturally when CLOS moves into cold init)
+(defvar *print-object-is-disabled-p*)
 
 
+;;; Output OBJECT to STREAM observing all printer control variables
+;;; except for *PRINT-PRETTY*. Note: if *PRINT-PRETTY* is non-NIL,
+;;; then the pretty printer will be used for any components of OBJECT,
+;;; just not for OBJECT itself.
 (defun output-ugly-object (object stream)
 (defun output-ugly-object (object stream)
-  #!+sb-doc
-  "Output OBJECT to STREAM observing all printer control variables except
-   for *PRINT-PRETTY*. Note: if *PRINT-PRETTY* is non-NIL, then the pretty
-   printer will be used for any components of OBJECT, just not for OBJECT
-   itself."
   (typecase object
     ;; KLUDGE: The TYPECASE approach here is non-ANSI; the ANSI definition of
     ;; PRINT-OBJECT says it provides printing and we're supposed to provide
   (typecase object
     ;; KLUDGE: The TYPECASE approach here is non-ANSI; the ANSI definition of
     ;; PRINT-OBJECT says it provides printing and we're supposed to provide
     ;;       a method on an external symbol in the CL package which is
     ;;       applicable to arg lists containing only direct instances of
     ;;       standardized classes.
     ;;       a method on an external symbol in the CL package which is
     ;;       applicable to arg lists containing only direct instances of
     ;;       standardized classes.
-    ;; Thus, in order for the user to detect our sleaziness, he has to do
-    ;; something relatively obscure like
+    ;; Thus, in order for the user to detect our sleaziness in conforming
+    ;; code, he has to do something relatively obscure like
     ;;   (1) actually use tools like FIND-METHOD to look for PRINT-OBJECT
     ;;       methods, or
     ;;   (2) define a PRINT-OBJECT method which is specialized on the stream
     ;;       value (e.g. a Gray stream object).
     ;; As long as no one comes up with a non-obscure way of detecting this
     ;; sleaziness, fixing this nonconformity will probably have a low
     ;;   (1) actually use tools like FIND-METHOD to look for PRINT-OBJECT
     ;;       methods, or
     ;;   (2) define a PRINT-OBJECT method which is specialized on the stream
     ;;       value (e.g. a Gray stream object).
     ;; As long as no one comes up with a non-obscure way of detecting this
     ;; sleaziness, fixing this nonconformity will probably have a low
-    ;; priority. -- WHN 20000121
-    (fixnum
-     (output-integer object stream))
+    ;; priority. -- WHN 2001-11-25
     (list
      (if (null object)
     (list
      (if (null object)
-        (output-symbol object stream)
-        (output-list object stream)))
+         (output-symbol object stream)
+         (output-list object stream)))
     (instance
     (instance
-     (print-object object stream))
+     (cond ((not (and (boundp '*print-object-is-disabled-p*)
+                      *print-object-is-disabled-p*))
+            (print-object object stream))
+           ((typep object 'structure-object)
+            (default-structure-print object stream *current-level-in-print*))
+           (t
+            (write-string "#<INSTANCE but not STRUCTURE-OBJECT>" stream))))
+    (funcallable-instance
+     (cond
+       ((not (and (boundp '*print-object-is-disabled-p*)
+                  *print-object-is-disabled-p*))
+        (print-object object stream))
+       (t (output-fun object stream))))
     (function
     (function
-     (unless (and (funcallable-instance-p object)
-                 (printed-as-funcallable-standard-class object stream))
-       (output-function object stream)))
+     (output-fun object stream))
     (symbol
      (output-symbol object stream))
     (number
      (etypecase object
        (integer
     (symbol
      (output-symbol object stream))
     (number
      (etypecase object
        (integer
-       (output-integer object stream))
+        (output-integer object stream))
        (float
        (float
-       (output-float object stream))
+        (output-float object stream))
        (ratio
        (ratio
-       (output-ratio object stream))
-       (ratio
-       (output-ratio object stream))
+        (output-ratio object stream))
        (complex
        (complex
-       (output-complex object stream))))
+        (output-complex object stream))))
     (character
      (output-character object stream))
     (vector
     (character
      (output-character object stream))
     (vector
      (output-code-component object stream))
     (fdefn
      (output-fdefn object stream))
      (output-code-component object stream))
     (fdefn
      (output-fdefn object stream))
+    #!+sb-simd-pack
+    (simd-pack
+     (output-simd-pack object stream))
     (t
      (output-random object stream))))
 \f
 ;;;; symbols
 
     (t
      (output-random object stream))))
 \f
 ;;;; symbols
 
-;;; Values of *PRINT-CASE* and (READTABLE-CASE *READTABLE*) the last
-;;; time the printer was called.
+;;; values of *PRINT-CASE* and (READTABLE-CASE *READTABLE*) the last
+;;; time the printer was called
 (defvar *previous-case* nil)
 (defvar *previous-readtable-case* nil)
 
 ;;; This variable contains the current definition of one of three
 ;;; symbol printers. SETUP-PRINTER-STATE sets this variable.
 (defvar *previous-case* nil)
 (defvar *previous-readtable-case* nil)
 
 ;;; This variable contains the current definition of one of three
 ;;; symbol printers. SETUP-PRINTER-STATE sets this variable.
-(defvar *internal-symbol-output-function* nil)
+(defvar *internal-symbol-output-fun* nil)
 
 ;;; This function sets the internal global symbol
 
 ;;; This function sets the internal global symbol
-;;; *INTERNAL-SYMBOL-OUTPUT-FUNCTION* to the right function depending
-;;; on the value of *PRINT-CASE*. See the manual for details. The
-;;; print buffer stream is also reset.
+;;; *INTERNAL-SYMBOL-OUTPUT-FUN* to the right function depending on
+;;; the value of *PRINT-CASE*. See the manual for details. The print
+;;; buffer stream is also reset.
 (defun setup-printer-state ()
   (unless (and (eq *print-case* *previous-case*)
 (defun setup-printer-state ()
   (unless (and (eq *print-case* *previous-case*)
-              (eq (readtable-case *readtable*) *previous-readtable-case*))
+               (eq (readtable-case *readtable*) *previous-readtable-case*))
     (setq *previous-case* *print-case*)
     (setq *previous-readtable-case* (readtable-case *readtable*))
     (unless (member *print-case* '(:upcase :downcase :capitalize))
       (setq *print-case* :upcase)
       (error "invalid *PRINT-CASE* value: ~S" *previous-case*))
     (unless (member *previous-readtable-case*
     (setq *previous-case* *print-case*)
     (setq *previous-readtable-case* (readtable-case *readtable*))
     (unless (member *print-case* '(:upcase :downcase :capitalize))
       (setq *print-case* :upcase)
       (error "invalid *PRINT-CASE* value: ~S" *previous-case*))
     (unless (member *previous-readtable-case*
-                   '(:upcase :downcase :invert :preserve))
+                    '(:upcase :downcase :invert :preserve))
       (setf (readtable-case *readtable*) :upcase)
       (error "invalid READTABLE-CASE value: ~S" *previous-readtable-case*))
 
       (setf (readtable-case *readtable*) :upcase)
       (error "invalid READTABLE-CASE value: ~S" *previous-readtable-case*))
 
-    (setq *internal-symbol-output-function*
-         (case *previous-readtable-case*
-           (:upcase
-            (case *print-case*
-              (:upcase #'output-preserve-symbol)
-              (:downcase #'output-lowercase-symbol)
-              (:capitalize #'output-capitalize-symbol)))
-           (:downcase
-            (case *print-case*
-              (:upcase #'output-uppercase-symbol)
-              (:downcase #'output-preserve-symbol)
-              (:capitalize #'output-capitalize-symbol)))
-           (:preserve #'output-preserve-symbol)
-           (:invert #'output-invert-symbol)))))
+    (setq *internal-symbol-output-fun*
+          (case *previous-readtable-case*
+            (:upcase
+             (case *print-case*
+               (:upcase #'output-preserve-symbol)
+               (:downcase #'output-lowercase-symbol)
+               (:capitalize #'output-capitalize-symbol)))
+            (:downcase
+             (case *print-case*
+               (:upcase #'output-uppercase-symbol)
+               (:downcase #'output-preserve-symbol)
+               (:capitalize #'output-capitalize-symbol)))
+            (:preserve #'output-preserve-symbol)
+            (:invert #'output-invert-symbol)))))
 
 ;;; Output PNAME (a symbol-name or package-name) surrounded with |'s,
 ;;; and with any embedded |'s or \'s escaped.
 
 ;;; Output PNAME (a symbol-name or package-name) surrounded with |'s,
 ;;; and with any embedded |'s or \'s escaped.
   (dotimes (index (length pname))
     (let ((char (schar pname index)))
       (when (or (char= char #\\) (char= char #\|))
   (dotimes (index (length pname))
     (let ((char (schar pname index)))
       (when (or (char= char #\\) (char= char #\|))
-       (write-char #\\ stream))
+        (write-char #\\ stream))
       (write-char char stream)))
   (write-char #\| stream))
 
 (defun output-symbol (object stream)
   (if (or *print-escape* *print-readably*)
       (let ((package (symbol-package object))
       (write-char char stream)))
   (write-char #\| stream))
 
 (defun output-symbol (object stream)
   (if (or *print-escape* *print-readably*)
       (let ((package (symbol-package object))
-           (name (symbol-name object)))
-       (cond
-        ;; The ANSI spec "22.1.3.3.1 Package Prefixes for Symbols"
-        ;; requires that keywords be printed with preceding colons
-        ;; always, regardless of the value of *PACKAGE*.
-        ((eq package *keyword-package*)
-         (write-char #\: stream))
-        ;; Otherwise, if the symbol's home package is the current
-        ;; one, then a prefix is never necessary.
-        ((eq package (sane-package)))
-        ;; Uninterned symbols print with a leading #:.
-        ((null package)
-         (when (or *print-gensym* *print-readably*)
-           (write-string "#:" stream)))
-        (t
-         (multiple-value-bind (symbol accessible)
-             (find-symbol name (sane-package))
-           ;; If we can find the symbol by looking it up, it need not
-           ;; be qualified. This can happen if the symbol has been
-           ;; inherited from a package other than its home package.
-           (unless (and accessible (eq symbol object))
-             (output-symbol-name (package-name package) stream)
-             (multiple-value-bind (symbol externalp)
-                 (find-external-symbol name package)
-               (declare (ignore symbol))
-               (if externalp
-                   (write-char #\: stream)
-                   (write-string "::" stream)))))))
-       (output-symbol-name name stream))
+            (name (symbol-name object))
+            (current (sane-package)))
+        (cond
+         ;; The ANSI spec "22.1.3.3.1 Package Prefixes for Symbols"
+         ;; requires that keywords be printed with preceding colons
+         ;; always, regardless of the value of *PACKAGE*.
+         ((eq package *keyword-package*)
+          (write-char #\: stream))
+         ;; Otherwise, if the symbol's home package is the current
+         ;; one, then a prefix is never necessary.
+         ((eq package current))
+         ;; Uninterned symbols print with a leading #:.
+         ((null package)
+          (when (or *print-gensym* *print-readably*)
+            (write-string "#:" stream)))
+         (t
+          (multiple-value-bind (symbol accessible)
+              (find-symbol name current)
+            ;; If we can find the symbol by looking it up, it need not
+            ;; be qualified. This can happen if the symbol has been
+            ;; inherited from a package other than its home package.
+            ;;
+            ;; To preserve print-read consistency, use the local nickname if
+            ;; one exists.
+            (unless (and accessible (eq symbol object))
+              (let ((prefix (or (car (rassoc package (package-%local-nicknames current)))
+                                (package-name package))))
+                (output-symbol-name prefix stream))
+              (multiple-value-bind (symbol externalp)
+                  (find-external-symbol name package)
+                (declare (ignore symbol))
+                (if externalp
+                    (write-char #\: stream)
+                    (write-string "::" stream)))))))
+        (output-symbol-name name stream))
       (output-symbol-name (symbol-name object) stream nil)))
 
 ;;; Output the string NAME as if it were a symbol name. In other
 ;;; words, diddle its case according to *PRINT-CASE* and
 ;;; READTABLE-CASE.
 (defun output-symbol-name (name stream &optional (maybe-quote t))
       (output-symbol-name (symbol-name object) stream nil)))
 
 ;;; Output the string NAME as if it were a symbol name. In other
 ;;; words, diddle its case according to *PRINT-CASE* and
 ;;; READTABLE-CASE.
 (defun output-symbol-name (name stream &optional (maybe-quote t))
-  (declare (type simple-base-string name))
-  (setup-printer-state)
-  (if (and maybe-quote (symbol-quotep name))
-      (output-quoted-symbol-name name stream)
-      (funcall *internal-symbol-output-function* name stream)))
+  (declare (type simple-string name))
+  (let ((*readtable* (if *print-readably* *standard-readtable* *readtable*)))
+    (setup-printer-state)
+    (if (and maybe-quote (symbol-quotep name))
+        (output-quoted-symbol-name name stream)
+        (funcall *internal-symbol-output-fun* name stream))))
 \f
 ;;;; escaping symbols
 
 \f
 ;;;; escaping symbols
 
 ;;; character has. At characters have at least one bit set, so we can
 ;;; search for any character with a positive test.
 (defvar *character-attributes*
 ;;; character has. At characters have at least one bit set, so we can
 ;;; search for any character with a positive test.
 (defvar *character-attributes*
-  (make-array char-code-limit
-             :element-type '(unsigned-byte 16)
-             :initial-element 0))
-(declaim (type (simple-array (unsigned-byte 16) (#.char-code-limit))
-              *character-attributes*))
-
-;;; Constants which are a bit-mask for each interesting character attribute.
-(defconstant other-attribute           (ash 1 0)) ; Anything else legal.
-(defconstant number-attribute          (ash 1 1)) ; A numeric digit.
-(defconstant uppercase-attribute       (ash 1 2)) ; An uppercase letter.
-(defconstant lowercase-attribute       (ash 1 3)) ; A lowercase letter.
-(defconstant sign-attribute            (ash 1 4)) ; +-
-(defconstant extension-attribute       (ash 1 5)) ; ^_
-(defconstant dot-attribute             (ash 1 6)) ; .
-(defconstant slash-attribute           (ash 1 7)) ; /
-(defconstant funny-attribute           (ash 1 8)) ; Anything illegal.
+  (make-array 160 ; FIXME
+              :element-type '(unsigned-byte 16)
+              :initial-element 0))
+(declaim (type (simple-array (unsigned-byte 16) (#.160)) ; FIXME
+               *character-attributes*))
+
+;;; constants which are a bit-mask for each interesting character attribute
+(defconstant other-attribute            (ash 1 0)) ; Anything else legal.
+(defconstant number-attribute           (ash 1 1)) ; A numeric digit.
+(defconstant uppercase-attribute        (ash 1 2)) ; An uppercase letter.
+(defconstant lowercase-attribute        (ash 1 3)) ; A lowercase letter.
+(defconstant sign-attribute             (ash 1 4)) ; +-
+(defconstant extension-attribute        (ash 1 5)) ; ^_
+(defconstant dot-attribute              (ash 1 6)) ; .
+(defconstant slash-attribute            (ash 1 7)) ; /
+(defconstant funny-attribute            (ash 1 8)) ; Anything illegal.
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
 
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
 
 ) ; EVAL-WHEN
 
 (flet ((set-bit (char bit)
 ) ; EVAL-WHEN
 
 (flet ((set-bit (char bit)
-        (let ((code (char-code char)))
-          (setf (aref *character-attributes* code)
-                (logior bit (aref *character-attributes* code))))))
+         (let ((code (char-code char)))
+           (setf (aref *character-attributes* code)
+                 (logior bit (aref *character-attributes* code))))))
 
   (dolist (char '(#\! #\@ #\$ #\% #\& #\* #\= #\~ #\[ #\] #\{ #\}
 
   (dolist (char '(#\! #\@ #\$ #\% #\& #\* #\= #\~ #\[ #\] #\{ #\}
-                 #\? #\< #\>))
+                  #\? #\< #\>))
     (set-bit char other-attribute))
 
   (dotimes (i 10)
     (set-bit char other-attribute))
 
   (dotimes (i 10)
   (set-bit #\/ slash-attribute)
 
   ;; Mark anything not explicitly allowed as funny.
   (set-bit #\/ slash-attribute)
 
   ;; Mark anything not explicitly allowed as funny.
-  (dotimes (i char-code-limit)
+  (dotimes (i 160) ; FIXME
     (when (zerop (aref *character-attributes* i))
       (setf (aref *character-attributes* i) funny-attribute))))
 
 ;;; For each character, the value of the corresponding element is the
 ;;; lowest base in which that character is a digit.
 (defvar *digit-bases*
     (when (zerop (aref *character-attributes* i))
       (setf (aref *character-attributes* i) funny-attribute))))
 
 ;;; For each character, the value of the corresponding element is the
 ;;; lowest base in which that character is a digit.
 (defvar *digit-bases*
-  (make-array char-code-limit
-             :element-type '(unsigned-byte 8)
-             :initial-element 36))
-(declaim (type (simple-array (unsigned-byte 8) (#.char-code-limit))
-              *digit-bases*))
-
+  (make-array 128 ; FIXME
+              :element-type '(unsigned-byte 8)
+              :initial-element 36))
+(declaim (type (simple-array (unsigned-byte 8) (#.128)) ; FIXME
+               *digit-bases*))
 (dotimes (i 36)
   (let ((char (digit-char i 36)))
     (setf (aref *digit-bases* (char-code char)) i)))
 (dotimes (i 36)
   (let ((char (digit-char i 36)))
     (setf (aref *digit-bases* (char-code char)) i)))
 (defun symbol-quotep (name)
   (declare (simple-string name))
   (macrolet ((advance (tag &optional (at-end t))
 (defun symbol-quotep (name)
   (declare (simple-string name))
   (macrolet ((advance (tag &optional (at-end t))
-              `(progn
-                (when (= index len)
-                  ,(if at-end '(go TEST-SIGN) '(return nil)))
-                (setq current (schar name index)
-                      code (char-code current)
-                      bits (aref attributes code))
-                (incf index)
-                (go ,tag)))
-            (test (&rest attributes)
-               `(not (zerop
-                      (the fixnum
-                           (logand
-                            (logior ,@(mapcar
-                                       (lambda (x)
-                                         (or (cdr (assoc x
-                                                         *attribute-names*))
-                                             (error "Blast!")))
-                                       attributes))
-                            bits)))))
-            (digitp ()
-              `(< (the fixnum (aref bases code)) base)))
+               `(progn
+                 (when (= index len)
+                   ,(if at-end '(go TEST-SIGN) '(return nil)))
+                 (setq current (schar name index)
+                       code (char-code current)
+                       bits (cond ; FIXME
+                              ((< code 160) (aref attributes code))
+                              ((upper-case-p current) uppercase-attribute)
+                              ((lower-case-p current) lowercase-attribute)
+                              (t other-attribute)))
+                 (incf index)
+                 (go ,tag)))
+             (test (&rest attributes)
+                `(not (zerop
+                       (the fixnum
+                            (logand
+                             (logior ,@(mapcar
+                                        (lambda (x)
+                                          (or (cdr (assoc x
+                                                          *attribute-names*))
+                                              (error "Blast!")))
+                                        attributes))
+                             bits)))))
+             (digitp ()
+               `(and (< code 128) ; FIXME
+                     (< (the fixnum (aref bases code)) base))))
 
     (prog ((len (length name))
 
     (prog ((len (length name))
-          (attributes *character-attributes*)
-          (bases *digit-bases*)
-          (base *print-base*)
-          (letter-attribute
-           (case (readtable-case *readtable*)
-             (:upcase uppercase-attribute)
-             (:downcase lowercase-attribute)
-             (t (logior lowercase-attribute uppercase-attribute))))
-          (index 0)
-          (bits 0)
-          (code 0)
-          current)
+           (attributes *character-attributes*)
+           (bases *digit-bases*)
+           (base *print-base*)
+           (letter-attribute
+            (case (readtable-case *readtable*)
+              (:upcase uppercase-attribute)
+              (:downcase lowercase-attribute)
+              (t (logior lowercase-attribute uppercase-attribute))))
+           (index 0)
+           (bits 0)
+           (code 0)
+           current)
       (declare (fixnum len base index bits code))
       (advance START t)
 
       (declare (fixnum len base index bits code))
       (advance START t)
 
 
      OTHER ; not potential number, see whether funny chars...
       (let ((mask (logxor (logior lowercase-attribute uppercase-attribute
 
      OTHER ; not potential number, see whether funny chars...
       (let ((mask (logxor (logior lowercase-attribute uppercase-attribute
-                                 funny-attribute)
-                         letter-attribute)))
-       (do ((i (1- index) (1+ i)))
-           ((= i len) (return-from symbol-quotep nil))
-         (unless (zerop (logand (aref attributes (char-code (schar name i)))
-                                mask))
-           (return-from symbol-quotep t))))
+                                  funny-attribute)
+                          letter-attribute)))
+        (do ((i (1- index) (1+ i)))
+            ((= i len) (return-from symbol-quotep nil))
+          (unless (zerop (logand (let* ((char (schar name i))
+                                        (code (char-code char)))
+                                   (cond
+                                     ((< code 160) (aref attributes code))
+                                     ((upper-case-p char) uppercase-attribute)
+                                     ((lower-case-p char) lowercase-attribute)
+                                     (t other-attribute)))
+                                 mask))
+            (return-from symbol-quotep t))))
 
      START
       (when (digitp)
 
      START
       (when (digitp)
-       (if (test letter)
-           (advance LAST-DIGIT-ALPHA)
-           (advance DIGIT)))
+        (if (test letter)
+            (advance LAST-DIGIT-ALPHA)
+            (advance DIGIT)))
       (when (test letter number other slash) (advance OTHER nil))
       (when (char= current #\.) (advance DOT-FOUND))
       (when (test sign extension) (advance START-STUFF nil))
       (when (test letter number other slash) (advance OTHER nil))
       (when (char= current #\.) (advance DOT-FOUND))
       (when (test sign extension) (advance START-STUFF nil))
 
      START-STUFF ; leading stuff before any dot or digit
       (when (digitp)
 
      START-STUFF ; leading stuff before any dot or digit
       (when (digitp)
-       (if (test letter)
-           (advance LAST-DIGIT-ALPHA)
-           (advance DIGIT)))
+        (if (test letter)
+            (advance LAST-DIGIT-ALPHA)
+            (advance DIGIT)))
       (when (test number other) (advance OTHER nil))
       (when (test letter) (advance START-MARKER nil))
       (when (char= current #\.) (advance START-DOT-STUFF nil))
       (when (test number other) (advance OTHER nil))
       (when (test letter) (advance START-MARKER nil))
       (when (char= current #\.) (advance START-DOT-STUFF nil))
       (when (test letter) (advance OTHER nil))
       (go START-STUFF)
 
       (when (test letter) (advance OTHER nil))
       (go START-STUFF)
 
-     START-DOT-STUFF ; leading stuff containing dot w/o digit...
+     START-DOT-STUFF ; leading stuff containing dot without digit...
       (when (test letter) (advance START-DOT-STUFF nil))
       (when (digitp) (advance DOT-DIGIT))
       (when (test sign extension dot slash) (advance START-DOT-STUFF nil))
       (when (test number other) (advance OTHER nil))
       (return t)
 
       (when (test letter) (advance START-DOT-STUFF nil))
       (when (digitp) (advance DOT-DIGIT))
       (when (test sign extension dot slash) (advance START-DOT-STUFF nil))
       (when (test number other) (advance OTHER nil))
       (return t)
 
-     START-DOT-MARKER ; number marker in leading stuff w/ dot..
-      ;; leading stuff containing dot w/o digit followed by letter...
+     START-DOT-MARKER ; number marker in leading stuff with dot..
+      ;; leading stuff containing dot without digit followed by letter...
       (when (test letter) (advance OTHER nil))
       (go START-DOT-STUFF)
 
       (when (test letter) (advance OTHER nil))
       (go START-DOT-STUFF)
 
 
      LAST-DIGIT-ALPHA ; previous char is a letter digit...
       (when (or (digitp) (test sign slash))
 
      LAST-DIGIT-ALPHA ; previous char is a letter digit...
       (when (or (digitp) (test sign slash))
-       (advance ALPHA-DIGIT))
+        (advance ALPHA-DIGIT))
       (when (test letter number other dot) (advance OTHER nil))
       (return t)
 
      ALPHA-DIGIT ; seen a digit which is a letter...
       (when (or (digitp) (test sign slash))
       (when (test letter number other dot) (advance OTHER nil))
       (return t)
 
      ALPHA-DIGIT ; seen a digit which is a letter...
       (when (or (digitp) (test sign slash))
-       (if (test letter)
-           (advance LAST-DIGIT-ALPHA)
-           (advance ALPHA-DIGIT)))
+        (if (test letter)
+            (advance LAST-DIGIT-ALPHA)
+            (advance ALPHA-DIGIT)))
       (when (test letter) (advance ALPHA-MARKER))
       (when (test number other dot) (advance OTHER nil))
       (return t)
       (when (test letter) (advance ALPHA-MARKER))
       (when (test number other dot) (advance OTHER nil))
       (return t)
 
      DIGIT ; seen only ordinary (non-alphabetic) numeric digits...
       (when (digitp)
 
      DIGIT ; seen only ordinary (non-alphabetic) numeric digits...
       (when (digitp)
-       (if (test letter)
-           (advance ALPHA-DIGIT)
-           (advance DIGIT)))
+        (if (test letter)
+            (advance ALPHA-DIGIT)
+            (advance DIGIT)))
       (when (test number other) (advance OTHER nil))
       (when (test letter) (advance MARKER))
       (when (test extension slash sign) (advance DIGIT))
       (when (test number other) (advance OTHER nil))
       (when (test letter) (advance MARKER))
       (when (test extension slash sign) (advance DIGIT))
       (return t)
 
      MARKER ; number marker in a numeric number...
       (return t)
 
      MARKER ; number marker in a numeric number...
+      ;; ("What," you may ask, "is a 'number marker'?" It's something
+      ;; that a conforming implementation might use in number syntax.
+      ;; See ANSI 2.3.1.1 "Potential Numbers as Tokens".)
       (when (test letter) (advance OTHER nil))
       (go DIGIT))))
 \f
       (when (test letter) (advance OTHER nil))
       (go DIGIT))))
 \f
-;;;; *INTERNAL-SYMBOL-OUTPUT-FUNCTION*
+;;;; *INTERNAL-SYMBOL-OUTPUT-FUN*
 ;;;;
 ;;;;
-;;;; Case hackery. These functions are stored in
-;;;; *INTERNAL-SYMBOL-OUTPUT-FUNCTION* according to the values of
+;;;; case hackery: These functions are stored in
+;;;; *INTERNAL-SYMBOL-OUTPUT-FUN* according to the values of
 ;;;; *PRINT-CASE* and READTABLE-CASE.
 
 ;;; called when:
 ;;;; *PRINT-CASE* and READTABLE-CASE.
 
 ;;; called when:
-;;; READTABLE-CASE     *PRINT-CASE*
-;;; :UPCASE            :UPCASE
-;;; :DOWNCASE          :DOWNCASE
-;;; :PRESERVE          any
+;;; READTABLE-CASE      *PRINT-CASE*
+;;; :UPCASE             :UPCASE
+;;; :DOWNCASE           :DOWNCASE
+;;; :PRESERVE           any
 (defun output-preserve-symbol (pname stream)
   (declare (simple-string pname))
   (write-string pname stream))
 
 ;;; called when:
 (defun output-preserve-symbol (pname stream)
   (declare (simple-string pname))
   (write-string pname stream))
 
 ;;; called when:
-;;; READTABLE-CASE     *PRINT-CASE*
-;;; :UPCASE            :DOWNCASE
+;;; READTABLE-CASE      *PRINT-CASE*
+;;; :UPCASE             :DOWNCASE
 (defun output-lowercase-symbol (pname stream)
   (declare (simple-string pname))
   (dotimes (index (length pname))
 (defun output-lowercase-symbol (pname stream)
   (declare (simple-string pname))
   (dotimes (index (length pname))
       (write-char (char-downcase char) stream))))
 
 ;;; called when:
       (write-char (char-downcase char) stream))))
 
 ;;; called when:
-;;; READTABLE-CASE     *PRINT-CASE*
-;;; :DOWNCASE          :UPCASE
+;;; READTABLE-CASE      *PRINT-CASE*
+;;; :DOWNCASE           :UPCASE
 (defun output-uppercase-symbol (pname stream)
   (declare (simple-string pname))
   (dotimes (index (length pname))
 (defun output-uppercase-symbol (pname stream)
   (declare (simple-string pname))
   (dotimes (index (length pname))
       (write-char (char-upcase char) stream))))
 
 ;;; called when:
       (write-char (char-upcase char) stream))))
 
 ;;; called when:
-;;; READTABLE-CASE     *PRINT-CASE*
-;;; :UPCASE            :CAPITALIZE
-;;; :DOWNCASE          :CAPITALIZE
+;;; READTABLE-CASE      *PRINT-CASE*
+;;; :UPCASE             :CAPITALIZE
+;;; :DOWNCASE           :CAPITALIZE
 (defun output-capitalize-symbol (pname stream)
   (declare (simple-string pname))
 (defun output-capitalize-symbol (pname stream)
   (declare (simple-string pname))
-  (let ((prev-not-alpha t)
-       (up (eq (readtable-case *readtable*) :upcase)))
+  (let ((prev-not-alphanum t)
+        (up (eq (readtable-case *readtable*) :upcase)))
     (dotimes (i (length pname))
       (let ((char (char pname i)))
     (dotimes (i (length pname))
       (let ((char (char pname i)))
-       (write-char (if up
-                       (if (or prev-not-alpha (lower-case-p char))
-                           char
-                           (char-downcase char))
-                       (if prev-not-alpha
-                           (char-upcase char)
-                           char))
-                   stream)
-       (setq prev-not-alpha (not (alpha-char-p char)))))))
+        (write-char (if up
+                        (if (or prev-not-alphanum (lower-case-p char))
+                            char
+                            (char-downcase char))
+                        (if prev-not-alphanum
+                            (char-upcase char)
+                            char))
+                    stream)
+        (setq prev-not-alphanum (not (alphanumericp char)))))))
 
 ;;; called when:
 
 ;;; called when:
-;;; READTABLE-CASE     *PRINT-CASE*
-;;; :INVERT            any
+;;; READTABLE-CASE      *PRINT-CASE*
+;;; :INVERT             any
 (defun output-invert-symbol (pname stream)
   (declare (simple-string pname))
   (let ((all-upper t)
 (defun output-invert-symbol (pname stream)
   (declare (simple-string pname))
   (let ((all-upper t)
-       (all-lower t))
+        (all-lower t))
     (dotimes (i (length pname))
       (let ((ch (schar pname i)))
     (dotimes (i (length pname))
       (let ((ch (schar pname i)))
-       (when (both-case-p ch)
-         (if (upper-case-p ch)
-             (setq all-lower nil)
-             (setq all-upper nil)))))
+        (when (both-case-p ch)
+          (if (upper-case-p ch)
+              (setq all-lower nil)
+              (setq all-upper nil)))))
     (cond (all-upper (output-lowercase-symbol pname stream))
     (cond (all-upper (output-lowercase-symbol pname stream))
-         (all-lower (output-uppercase-symbol pname stream))
-         (t
-          (write-string pname stream)))))
+          (all-lower (output-uppercase-symbol pname stream))
+          (t
+           (write-string pname stream)))))
 
 #|
 (defun test1 ()
   (let ((*readtable* (copy-readtable nil)))
     (format t "READTABLE-CASE  Input   Symbol-name~@
 
 #|
 (defun test1 ()
   (let ((*readtable* (copy-readtable nil)))
     (format t "READTABLE-CASE  Input   Symbol-name~@
-              ----------------------------------~%")
+               ----------------------------------~%")
     (dolist (readtable-case '(:upcase :downcase :preserve :invert))
       (setf (readtable-case *readtable*) readtable-case)
       (dolist (input '("ZEBRA" "Zebra" "zebra"))
     (dolist (readtable-case '(:upcase :downcase :preserve :invert))
       (setf (readtable-case *readtable*) readtable-case)
       (dolist (input '("ZEBRA" "Zebra" "zebra"))
-       (format t "~&:~A~16T~A~24T~A"
-               (string-upcase readtable-case)
-               input
-               (symbol-name (read-from-string input)))))))
+        (format t "~&:~A~16T~A~24T~A"
+                (string-upcase readtable-case)
+                input
+                (symbol-name (read-from-string input)))))))
 
 (defun test2 ()
   (let ((*readtable* (copy-readtable nil)))
     (format t "READTABLE-CASE  *PRINT-CASE*  Symbol-name  Output  Princ~@
 
 (defun test2 ()
   (let ((*readtable* (copy-readtable nil)))
     (format t "READTABLE-CASE  *PRINT-CASE*  Symbol-name  Output  Princ~@
-              --------------------------------------------------------~%")
+               --------------------------------------------------------~%")
     (dolist (readtable-case '(:upcase :downcase :preserve :invert))
       (setf (readtable-case *readtable*) readtable-case)
       (dolist (*print-case* '(:upcase :downcase :capitalize))
     (dolist (readtable-case '(:upcase :downcase :preserve :invert))
       (setf (readtable-case *readtable*) readtable-case)
       (dolist (*print-case* '(:upcase :downcase :capitalize))
-       (dolist (symbol '(|ZEBRA| |Zebra| |zebra|))
-         (format t "~&:~A~15T:~A~29T~A~42T~A~50T~A"
-                 (string-upcase readtable-case)
-                 (string-upcase *print-case*)
-                 (symbol-name symbol)
-                 (prin1-to-string symbol)
-                 (princ-to-string symbol)))))))
+        (dolist (symbol '(|ZEBRA| |Zebra| |zebra|))
+          (format t "~&:~A~15T:~A~29T~A~42T~A~50T~A"
+                  (string-upcase readtable-case)
+                  (string-upcase *print-case*)
+                  (symbol-name symbol)
+                  (prin1-to-string symbol)
+                  (princ-to-string symbol)))))))
 |#
 \f
 ;;;; recursive objects
 |#
 \f
 ;;;; recursive objects
   (descend-into (stream)
     (write-char #\( stream)
     (let ((length 0)
   (descend-into (stream)
     (write-char #\( stream)
     (let ((length 0)
-         (list list))
+          (list list))
       (loop
       (loop
-       (punt-print-if-too-long length stream)
-       (output-object (pop list) stream)
-       (unless list
-         (return))
-       (when (or (atom list) (check-for-circularity list))
-         (write-string " . " stream)
-         (output-object list stream)
-         (return))
-       (write-char #\space stream)
-       (incf length)))
+        (punt-print-if-too-long length stream)
+        (output-object (pop list) stream)
+        (unless list
+          (return))
+        (when (or (atom list)
+                  (check-for-circularity list))
+          (write-string " . " stream)
+          (output-object list stream)
+          (return))
+        (write-char #\space stream)
+        (incf length)))
     (write-char #\) stream)))
 
     (write-char #\) stream)))
 
+(defun output-unreadable-vector-readably (vector stream)
+  (declare (vector vector))
+  (write-string "#." stream)
+  (write `(coerce ,(coerce vector '(vector t))
+                  '(simple-array ,(array-element-type vector) (*)))
+         :stream stream))
+
 (defun output-vector (vector stream)
   (declare (vector vector))
   (cond ((stringp vector)
 (defun output-vector (vector stream)
   (declare (vector vector))
   (cond ((stringp vector)
-        (cond ((or *print-escape* *print-readably*)
-               (write-char #\" stream)
-               (quote-string vector stream)
-               (write-char #\" stream))
-              (t
-               (write-string vector stream))))
-       ((not (or *print-array* *print-readably*))
-        (output-terse-array vector stream))
-       ((bit-vector-p vector)
-        (write-string "#*" stream)
-        (dotimes (i (length vector))
-          (output-object (aref vector i) stream)))
-       (t
-        (when (and *print-readably*
-                   (not (eq (array-element-type vector) t)))
-          (error 'print-not-readable :object vector))
-        (descend-into (stream)
-                      (write-string "#(" stream)
-                      (dotimes (i (length vector))
-                        (unless (zerop i)
-                          (write-char #\space stream))
-                        (punt-print-if-too-long i stream)
-                        (output-object (aref vector i) stream))
-                      (write-string ")" stream)))))
+         (cond ((and *print-readably*
+                     (not (eq (array-element-type vector)
+                              (load-time-value
+                               (array-element-type
+                                (make-array 0 :element-type 'character))))))
+                (print-not-readable-error vector stream))
+               ((or *print-escape* *print-readably*)
+                (write-char #\" stream)
+                (quote-string vector stream)
+                (write-char #\" stream))
+               (t
+                (write-string vector stream))))
+        ((not (or *print-array* *print-readably*))
+         (output-terse-array vector stream))
+        ((bit-vector-p vector)
+         (write-string "#*" stream)
+         (dovector (bit vector)
+           ;; (Don't use OUTPUT-OBJECT here, since this code
+           ;; has to work for all possible *PRINT-BASE* values.)
+           (write-char (if (zerop bit) #\0 #\1) stream)))
+        ((or (not *print-readably*)
+             (array-readably-printable-p vector))
+         (descend-into (stream)
+                       (write-string "#(" stream)
+                       (dotimes (i (length vector))
+                         (unless (zerop i)
+                           (write-char #\space stream))
+                         (punt-print-if-too-long i stream)
+                         (output-object (aref vector i) stream))
+                       (write-string ")" stream)))
+        (*read-eval*
+         (output-unreadable-vector-readably vector stream))
+        (t
+         (print-not-readable-error vector stream))))
 
 ;;; This function outputs a string quoting characters sufficiently
 
 ;;; This function outputs a string quoting characters sufficiently
-;;; that so someone can read it in again. Basically, put a slash in
+;;; so that someone can read it in again. Basically, put a slash in
 ;;; front of an character satisfying NEEDS-SLASH-P.
 (defun quote-string (string stream)
   (macrolet ((needs-slash-p (char)
 ;;; front of an character satisfying NEEDS-SLASH-P.
 (defun quote-string (string stream)
   (macrolet ((needs-slash-p (char)
-              ;; KLUDGE: We probably should look at the readtable, but just do
-              ;; this for now. [noted by anonymous long ago] -- WHN 19991130
-              `(or (char= ,char #\\)
+               ;; KLUDGE: We probably should look at the readtable, but just do
+               ;; this for now. [noted by anonymous long ago] -- WHN 19991130
+               `(or (char= ,char #\\)
                  (char= ,char #\"))))
                  (char= ,char #\"))))
-    (with-array-data ((data string) (start) (end (length string)))
+    (with-array-data ((data string) (start) (end)
+                      :check-fill-pointer t)
       (do ((index start (1+ index)))
       (do ((index start (1+ index)))
-         ((>= index end))
-       (let ((char (schar data index)))
-         (when (needs-slash-p char) (write-char #\\ stream))
-         (write-char char stream))))))
-
+          ((>= index end))
+        (let ((char (schar data index)))
+          (when (needs-slash-p char) (write-char #\\ stream))
+          (write-char char stream))))))
+
+(defun array-readably-printable-p (array)
+  (and (eq (array-element-type array) t)
+       (let ((zero (position 0 (array-dimensions array)))
+             (number (position 0 (array-dimensions array)
+                               :test (complement #'eql)
+                               :from-end t)))
+         (or (null zero) (null number) (> zero number)))))
+
+;;; Output the printed representation of any array in either the #< or #A
+;;; form.
 (defun output-array (array stream)
 (defun output-array (array stream)
-  #!+sb-doc
-  "Outputs the printed representation of any array in either the #< or #A
-   form."
   (if (or *print-array* *print-readably*)
       (output-array-guts array stream)
       (output-terse-array array stream)))
 
   (if (or *print-array* *print-readably*)
       (output-array-guts array stream)
       (output-terse-array array stream)))
 
-;;; to output the abbreviated #< form of an array
+;;; Output the abbreviated #< form of an array.
 (defun output-terse-array (array stream)
   (let ((*print-level* nil)
 (defun output-terse-array (array stream)
   (let ((*print-level* nil)
-       (*print-length* nil))
+        (*print-length* nil))
     (print-unreadable-object (array stream :type t :identity t))))
 
     (print-unreadable-object (array stream :type t :identity t))))
 
-;;; to output the readable #A form of an array
-(defun output-array-guts (array stream)
-  (when (and *print-readably*
-            (not (eq (array-element-type array) t)))
-    (error 'print-not-readable :object array))
-  (write-char #\# stream)
-  (let ((*print-base* 10))
-    (output-integer (array-rank array) stream))
-  (write-char #\A stream)
+;;; Convert an array into a list that can be used with MAKE-ARRAY's
+;;; :INITIAL-CONTENTS keyword argument.
+(defun listify-array (array)
   (with-array-data ((data array) (start) (end))
     (declare (ignore end))
   (with-array-data ((data array) (start) (end))
     (declare (ignore end))
-    (sub-output-array-guts data (array-dimensions array) stream start)))
+    (labels ((listify (dimensions index)
+               (if (null dimensions)
+                   (aref data index)
+                   (let* ((dimension (car dimensions))
+                          (dimensions (cdr dimensions))
+                          (count (reduce #'* dimensions)))
+                     (loop for i below dimension
+                           collect (listify dimensions index)
+                           do (incf index count))))))
+      (listify (array-dimensions array) start))))
+
+(defun output-unreadable-array-readably (array stream)
+  (write-string "#." stream)
+  (write `(make-array ',(array-dimensions array)
+                      :element-type ',(array-element-type array)
+                      :initial-contents ',(listify-array array))
+         :stream stream))
+
+;;; Output the readable #A form of an array.
+(defun output-array-guts (array stream)
+  (cond ((or (not *print-readably*)
+             (array-readably-printable-p array))
+         (write-char #\# stream)
+         (let ((*print-base* 10)
+               (*print-radix* nil))
+           (output-integer (array-rank array) stream))
+         (write-char #\A stream)
+         (with-array-data ((data array) (start) (end))
+           (declare (ignore end))
+           (sub-output-array-guts data (array-dimensions array) stream start)))
+        (*read-eval*
+         (output-unreadable-array-readably array stream))
+        (t
+         (print-not-readable-error array stream))))
 
 (defun sub-output-array-guts (array dimensions stream index)
   (declare (type (simple-array * (*)) array) (fixnum index))
   (cond ((null dimensions)
 
 (defun sub-output-array-guts (array dimensions stream index)
   (declare (type (simple-array * (*)) array) (fixnum index))
   (cond ((null dimensions)
-        (output-object (aref array index) stream))
-       (t
-        (descend-into (stream)
-          (write-char #\( stream)
-          (let* ((dimension (car dimensions))
-                 (dimensions (cdr dimensions))
-                 (count (reduce #'* dimensions)))
-            (dotimes (i dimension)
-              (unless (zerop i)
-                (write-char #\space stream))
-              (punt-print-if-too-long i stream)
-              (sub-output-array-guts array dimensions stream index)
-              (incf index count)))
-          (write-char #\) stream)))))
+         (output-object (aref array index) stream))
+        (t
+         (descend-into (stream)
+           (write-char #\( stream)
+           (let* ((dimension (car dimensions))
+                  (dimensions (cdr dimensions))
+                  (count (reduce #'* dimensions)))
+             (dotimes (i dimension)
+               (unless (zerop i)
+                 (write-char #\space stream))
+               (punt-print-if-too-long i stream)
+               (sub-output-array-guts array dimensions stream index)
+               (incf index count)))
+           (write-char #\) stream)))))
 
 ;;; a trivial non-generic-function placeholder for PRINT-OBJECT, for
 ;;; use until CLOS is set up (at which time it will be replaced with
 ;;; the real generic function implementation)
 (defun print-object (instance stream)
 
 ;;; a trivial non-generic-function placeholder for PRINT-OBJECT, for
 ;;; use until CLOS is set up (at which time it will be replaced with
 ;;; the real generic function implementation)
 (defun print-object (instance stream)
-  (default-structure-print instance stream *current-level*))
+  (default-structure-print instance stream *current-level-in-print*))
 \f
 ;;;; integer, ratio, and complex printing (i.e. everything but floats)
 
 \f
 ;;;; integer, ratio, and complex printing (i.e. everything but floats)
 
+(defun %output-radix (base stream)
+  (write-char #\# stream)
+  (write-char (case base
+                (2 #\b)
+                (8 #\o)
+                (16 #\x)
+                (t (%output-reasonable-integer-in-base base 10 stream)
+                   #\r))
+              stream))
+
+(defun %output-reasonable-integer-in-base (n base stream)
+  (multiple-value-bind (q r)
+      (truncate n base)
+    ;; Recurse until you have all the digits pushed on
+    ;; the stack.
+    (unless (zerop q)
+      (%output-reasonable-integer-in-base q base stream))
+    ;; Then as each recursive call unwinds, turn the
+    ;; digit (in remainder) into a character and output
+    ;; the character.
+    (write-char
+     (schar "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" r)
+     stream)))
+
+;;; *POWER-CACHE* is an alist mapping bases to power-vectors. It is
+;;; filled and probed by POWERS-FOR-BASE. SCRUB-POWER-CACHE is called
+;;; always prior a GC to drop overly large bignums from the cache.
+;;;
+;;; It doesn't need a lock, but if you work on SCRUB-POWER-CACHE or
+;;; POWERS-FOR-BASE, see that you don't break the assumptions!
+(defvar *power-cache* nil)
+
+(defconstant +power-cache-integer-length-limit+ 2048)
+
+(defun scrub-power-cache ()
+  (let ((cache *power-cache*))
+    (dolist (cell cache)
+      (let ((powers (cdr cell)))
+        (declare (simple-vector powers))
+        (let ((too-big (position-if
+                        (lambda (x)
+                          (>= (integer-length x)
+                              +power-cache-integer-length-limit+))
+                        powers)))
+          (when too-big
+            (setf (cdr cell) (subseq powers 0 too-big))))))
+    ;; Since base 10 is overwhelmingly common, make sure it's at head.
+    ;; Try to keep other bases in a hopefully sensible order as well.
+    (if (eql 10 (caar cache))
+        (setf *power-cache* cache)
+        ;; If we modify the list destructively we need to copy it, otherwise
+        ;; an alist lookup in progress might be screwed.
+        (setf *power-cache* (sort (copy-list cache)
+                                  (lambda (a b)
+                                    (declare (fixnum a b))
+                                    (cond ((= 10 a) t)
+                                          ((= 10 b) nil)
+                                          ((= 16 a) t)
+                                          ((= 16 b) nil)
+                                          ((= 2 a) t)
+                                          ((= 2 b) nil)
+                                          (t (< a b))))
+                                  :key #'car)))))
+
+;;; Compute (and cache) a power vector for a BASE and LIMIT:
+;;; the vector holds integers for which
+;;;    (aref powers k) == (expt base (expt 2 k))
+;;; holds.
+(defun powers-for-base (base limit)
+  (flet ((compute-powers (from)
+           (let (powers)
+             (do ((p from (* p p)))
+                 ((> p limit)
+                  ;; We don't actually need this, but we also
+                  ;; prefer not to cons it up a second time...
+                  (push p powers))
+               (push p powers))
+             (nreverse powers))))
+    ;; Grab a local reference so that we won't stuff consed at the
+    ;; head by other threads -- or sorting by SCRUB-POWER-CACHE.
+    (let ((cache *power-cache*))
+      (let ((cell (assoc base cache)))
+        (if cell
+            (let* ((powers (cdr cell))
+                   (len (length powers))
+                   (max (svref powers (1- len))))
+              (if (> max limit)
+                  powers
+                  (let ((new
+                         (concatenate 'vector powers
+                                      (compute-powers (* max max)))))
+                    (setf (cdr cell) new)
+                    new)))
+            (let ((powers (coerce (compute-powers base) 'vector)))
+              ;; Add new base to head: SCRUB-POWER-CACHE will later
+              ;; put it to a better place.
+              (setf *power-cache* (acons base powers cache))
+              powers))))))
+
+;; Algorithm by Harald Hanche-Olsen, sbcl-devel 2005-02-05
+(defun %output-huge-integer-in-base (n base stream)
+  (declare (type bignum n) (type fixnum base))
+  ;; POWER is a vector for which the following holds:
+  ;;   (aref power k) == (expt base (expt 2 k))
+  (let* ((power (powers-for-base base n))
+         (k-start (or (position-if (lambda (x) (> x n)) power)
+                      (bug "power-vector too short"))))
+    (labels ((bisect (n k exactp)
+               (declare (fixnum k))
+               ;; N is the number to bisect
+               ;; K on initial entry BASE^(2^K) > N
+               ;; EXACTP is true if 2^K is the exact number of digits
+               (cond ((zerop n)
+                      (when exactp
+                        (loop repeat (ash 1 k) do (write-char #\0 stream))))
+                     ((zerop k)
+                      (write-char
+                       (schar "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" n)
+                       stream))
+                     (t
+                      (setf k (1- k))
+                      (multiple-value-bind (q r) (truncate n (aref power k))
+                        ;; EXACTP is NIL only at the head of the
+                        ;; initial number, as we don't know the number
+                        ;; of digits there, but we do know that it
+                        ;; doesn't get any leading zeros.
+                        (bisect q k exactp)
+                        (bisect r k (or exactp (plusp q))))))))
+      (bisect n k-start nil))))
+
+(defun %output-integer-in-base (integer base stream)
+  (when (minusp integer)
+    (write-char #\- stream)
+    (setf integer (- integer)))
+  ;; The ideal cutoff point between these two algorithms is almost
+  ;; certainly quite platform dependent: this gives 87 for 32 bit
+  ;; SBCL, which is about right at least for x86/Darwin.
+  (if (or (fixnump integer)
+          (< (integer-length integer) (* 3 sb!vm:n-positive-fixnum-bits)))
+      (%output-reasonable-integer-in-base integer base stream)
+      (%output-huge-integer-in-base integer base stream)))
+
 (defun output-integer (integer stream)
 (defun output-integer (integer stream)
-  ;; FIXME: This UNLESS form should be pulled out into something like
-  ;; (SANE-PRINT-BASE), along the lines of (SANE-PACKAGE) for the
-  ;; *PACKAGE* variable.
-  (unless (and (fixnump *print-base*)
-              (< 1 *print-base* 37))
-    (let ((obase *print-base*))
-      (setq *print-base* 10.)
-      (error "~A is not a reasonable value for *PRINT-BASE*." obase)))
-  (when (and (not (= *print-base* 10.))
-            *print-radix*)
-    ;; First print leading base information, if any.
-    (write-char #\# stream)
-    (write-char (case *print-base*
-                 (2. #\b)
-                 (8. #\o)
-                 (16. #\x)
-                 (T (let ((fixbase *print-base*)
-                          (*print-base* 10.)
-                          (*print-radix* ()))
-                      (sub-output-integer fixbase stream))
-                    #\r))
-               stream))
-  ;; Then output a minus sign if the number is negative, then output
-  ;; the absolute value of the number.
-  (cond ((bignump integer) (print-bignum integer stream))
-       ((< integer 0)
-        (write-char #\- stream)
-        (sub-output-integer (- integer) stream))
-       (t
-        (sub-output-integer integer stream)))
-  ;; Print any trailing base information, if any.
-  (if (and (= *print-base* 10.) *print-radix*)
-      (write-char #\. stream)))
-
-(defun sub-output-integer (integer stream)
-  (let ((quotient ())
-       (remainder ()))
-    ;; Recurse until you have all the digits pushed on the stack.
-    (if (not (zerop (multiple-value-setq (quotient remainder)
-                     (truncate integer *print-base*))))
-       (sub-output-integer quotient stream))
-    ;; Then as each recursive call unwinds, turn the digit (in remainder)
-    ;; into a character and output the character.
-    (write-char (code-char (if (and (> remainder 9.)
-                                   (> *print-base* 10.))
-                              (+ (char-code #\A) (- remainder 10.))
-                              (+ (char-code #\0) remainder)))
-               stream)))
-\f
-;;;; bignum printing
-
-;;; *BASE-POWER* holds the number that we keep dividing into the
-;;; bignum for each *print-base*. We want this number as close to
-;;; *most-positive-fixnum* as possible, i.e. (floor (log
-;;; most-positive-fixnum *print-base*)).
-(defparameter *base-power* (make-array 37 :initial-element nil))
-
-;;; *FIXNUM-POWER--1* holds the number of digits for each *PRINT-BASE*
-;;; that fit in the corresponding *base-power*.
-(defparameter *fixnum-power--1* (make-array 37 :initial-element nil))
-
-;;; Print the bignum to the stream. We first generate the correct
-;;; value for *base-power* and *fixnum-power--1* if we have not
-;;; already. Then we call bignum-print-aux to do the printing.
-(defun print-bignum (big stream)
-  (unless (aref *base-power* *print-base*)
-    (do ((power-1 -1 (1+ power-1))
-        (new-divisor *print-base* (* new-divisor *print-base*))
-        (divisor 1 new-divisor))
-       ((not (fixnump new-divisor))
-        (setf (aref *base-power* *print-base*) divisor)
-        (setf (aref *fixnum-power--1* *print-base*) power-1))))
-  (bignum-print-aux (cond ((minusp big)
-                          (write-char #\- stream)
-                          (- big))
-                         (t big))
-                   (aref *base-power* *print-base*)
-                   (aref *fixnum-power--1* *print-base*)
-                   stream)
-  big)
-
-(defun bignum-print-aux (big divisor power-1 stream)
-  (multiple-value-bind (newbig fix) (truncate big divisor)
-    (if (fixnump newbig)
-       (sub-output-integer newbig stream)
-       (bignum-print-aux newbig divisor power-1 stream))
-    (do ((zeros power-1 (1- zeros))
-        (base-power *print-base* (* base-power *print-base*)))
-       ((> base-power fix)
-        (dotimes (i zeros) (write-char #\0 stream))
-        (sub-output-integer fix stream)))))
+  (let ((base *print-base*))
+    (when (and (/= base 10) *print-radix*)
+      (%output-radix base stream))
+    (%output-integer-in-base integer base stream)
+    (when (and *print-radix* (= base 10))
+      (write-char #\. stream))))
 
 (defun output-ratio (ratio stream)
 
 (defun output-ratio (ratio stream)
-  (when *print-radix*
-    (write-char #\# stream)
-    (case *print-base*
-      (2 (write-char #\b stream))
-      (8 (write-char #\o stream))
-      (16 (write-char #\x stream))
-      (t (write *print-base* :stream stream :radix nil :base 10)))
-    (write-char #\r stream))
-  (let ((*print-radix* nil))
-    (output-integer (numerator ratio) stream)
+  (let ((base *print-base*))
+    (when *print-radix*
+      (%output-radix base stream))
+    (%output-integer-in-base (numerator ratio) base stream)
     (write-char #\/ stream)
     (write-char #\/ stream)
-    (output-integer (denominator ratio) stream)))
+    (%output-integer-in-base (denominator ratio) base stream)))
 
 (defun output-complex (complex stream)
   (write-string "#C(" stream)
 
 (defun output-complex (complex stream)
   (write-string "#C(" stream)
+  ;; FIXME: Could this just be OUTPUT-NUMBER?
   (output-object (realpart complex) stream)
   (write-char #\space stream)
   (output-object (imagpart complex) stream)
   (output-object (realpart complex) stream)
   (write-char #\space stream)
   (output-object (imagpart complex) stream)
 ;;;; float printing
 
 ;;; FLONUM-TO-STRING (and its subsidiary function FLOAT-STRING) does
 ;;;; float printing
 
 ;;; FLONUM-TO-STRING (and its subsidiary function FLOAT-STRING) does
-;;; most of the work for all printing of floating point numbers in the
-;;; printer and in FORMAT. It converts a floating point number to a
-;;; string in a free or fixed format with no exponent. The
-;;; interpretation of the arguments is as follows:
+;;; most of the work for all printing of floating point numbers in
+;;; FORMAT.  It converts a floating point number to a string in a free
+;;; or fixed format with no exponent. The interpretation of the
+;;; arguments is as follows:
 ;;;
 ;;;
-;;;     X      - The floating point number to convert, which must not be
-;;;            negative.
+;;;     X       - The floating point number to convert, which must not be
+;;;             negative.
 ;;;     WIDTH    - The preferred field width, used to determine the number
 ;;;     WIDTH    - The preferred field width, used to determine the number
-;;;            of fraction digits to produce if the FDIGITS parameter
-;;;            is unspecified or NIL. If the non-fraction digits and the
-;;;            decimal point alone exceed this width, no fraction digits
-;;;            will be produced unless a non-NIL value of FDIGITS has been
-;;;            specified. Field overflow is not considerd an error at this
-;;;            level.
+;;;             of fraction digits to produce if the FDIGITS parameter
+;;;             is unspecified or NIL. If the non-fraction digits and the
+;;;             decimal point alone exceed this width, no fraction digits
+;;;             will be produced unless a non-NIL value of FDIGITS has been
+;;;             specified. Field overflow is not considerd an error at this
+;;;             level.
 ;;;     FDIGITS  - The number of fractional digits to produce. Insignificant
 ;;;     FDIGITS  - The number of fractional digits to produce. Insignificant
-;;;            trailing zeroes may be introduced as needed. May be
-;;;            unspecified or NIL, in which case as many digits as possible
-;;;            are generated, subject to the constraint that there are no
-;;;            trailing zeroes.
+;;;             trailing zeroes may be introduced as needed. May be
+;;;             unspecified or NIL, in which case as many digits as possible
+;;;             are generated, subject to the constraint that there are no
+;;;             trailing zeroes.
 ;;;     SCALE    - If this parameter is specified or non-NIL, then the number
 ;;;     SCALE    - If this parameter is specified or non-NIL, then the number
-;;;            printed is (* x (expt 10 scale)). This scaling is exact,
-;;;            and cannot lose precision.
+;;;             printed is (* x (expt 10 scale)). This scaling is exact,
+;;;             and cannot lose precision.
 ;;;     FMIN     - This parameter, if specified or non-NIL, is the minimum
 ;;;     FMIN     - This parameter, if specified or non-NIL, is the minimum
-;;;            number of fraction digits which will be produced, regardless
-;;;            of the value of WIDTH or FDIGITS. This feature is used by
-;;;            the ~E format directive to prevent complete loss of
-;;;            significance in the printed value due to a bogus choice of
-;;;            scale factor.
-;;;
-;;; Most of the optional arguments are for the benefit for FORMAT and are not
-;;; used by the printer.
+;;;             number of fraction digits which will be produced, regardless
+;;;             of the value of WIDTH or FDIGITS. This feature is used by
+;;;             the ~E format directive to prevent complete loss of
+;;;             significance in the printed value due to a bogus choice of
+;;;             scale factor.
 ;;;
 ;;; Returns:
 ;;; (VALUES DIGIT-STRING DIGIT-LENGTH LEADING-POINT TRAILING-POINT DECPNT)
 ;;;
 ;;; Returns:
 ;;; (VALUES DIGIT-STRING DIGIT-LENGTH LEADING-POINT TRAILING-POINT DECPNT)
 ;;;     DIGIT-STRING    - The decimal representation of X, with decimal point.
 ;;;     DIGIT-LENGTH    - The length of the string DIGIT-STRING.
 ;;;     LEADING-POINT   - True if the first character of DIGIT-STRING is the
 ;;;     DIGIT-STRING    - The decimal representation of X, with decimal point.
 ;;;     DIGIT-LENGTH    - The length of the string DIGIT-STRING.
 ;;;     LEADING-POINT   - True if the first character of DIGIT-STRING is the
-;;;                   decimal point.
+;;;                    decimal point.
 ;;;     TRAILING-POINT  - True if the last character of DIGIT-STRING is the
 ;;;     TRAILING-POINT  - True if the last character of DIGIT-STRING is the
-;;;                   decimal point.
+;;;                    decimal point.
 ;;;     POINT-POS       - The position of the digit preceding the decimal
 ;;;     POINT-POS       - The position of the digit preceding the decimal
-;;;                   point. Zero indicates point before first digit.
+;;;                    point. Zero indicates point before first digit.
 ;;;
 ;;; NOTE: FLONUM-TO-STRING goes to a lot of trouble to guarantee
 ;;; accuracy. Specifically, the decimal number printed is the closest
 ;;;
 ;;; NOTE: FLONUM-TO-STRING goes to a lot of trouble to guarantee
 ;;; accuracy. Specifically, the decimal number printed is the closest
 ;;; representation. Furthermore, only as many digits as necessary to
 ;;; satisfy this condition will be printed.
 ;;;
 ;;; representation. Furthermore, only as many digits as necessary to
 ;;; satisfy this condition will be printed.
 ;;;
-;;; FLOAT-STRING actually generates the digits for positive numbers.
-;;; The algorithm is essentially that of algorithm Dragon4 in "How to
-;;; Print Floating-Point Numbers Accurately" by Steele and White. The
-;;; current (draft) version of this paper may be found in
-;;; [CMUC]<steele>tradix.press. DO NOT EVEN THINK OF ATTEMPTING TO
-;;; UNDERSTAND THIS CODE WITHOUT READING THE PAPER!
-
-(defvar *digits* "0123456789")
+;;; FLOAT-DIGITS actually generates the digits for positive numbers;
+;;; see below for comments.
 
 (defun flonum-to-string (x &optional width fdigits scale fmin)
 
 (defun flonum-to-string (x &optional width fdigits scale fmin)
-  (cond ((zerop x)
-        ;; Zero is a special case which FLOAT-STRING cannot handle.
-        (if fdigits
-            (let ((s (make-string (1+ fdigits) :initial-element #\0)))
-              (setf (schar s 0) #\.)
-              (values s (length s) t (zerop fdigits) 0))
-            (values "." 1 t t 0)))
-       (t
-        (multiple-value-bind (sig exp) (integer-decode-float x)
-          (let* ((precision (float-precision x))
-                 (digits (float-digits x))
-                 (fudge (- digits precision))
-                 (width (if width (max width 1) nil)))
-          (float-string (ash sig (- fudge)) (+ exp fudge) precision width
-                        fdigits scale fmin))))))
-
-(defun float-string (fraction exponent precision width fdigits scale fmin)
-  (let ((r fraction) (s 1) (m- 1) (m+ 1) (k 0)
-       (digits 0) (decpnt 0) (cutoff nil) (roundup nil) u low high
-       (digit-string (make-array 50
-                                 :element-type 'base-char
-                                 :fill-pointer 0
-                                 :adjustable t)))
-    ;; Represent fraction as r/s, error bounds as m+/s and m-/s.
-    ;; Rational arithmetic avoids loss of precision in subsequent
-    ;; calculations.
-    (cond ((> exponent 0)
-          (setq r (ash fraction exponent))
-          (setq m- (ash 1 exponent))
-          (setq m+ m-))
-         ((< exponent 0)
-          (setq s (ash 1 (- exponent)))))
-    ;; Adjust the error bounds m+ and m- for unequal gaps.
-    (when (= fraction (ash 1 precision))
-      (setq m+ (ash m+ 1))
-      (setq r (ash r 1))
-      (setq s (ash s 1)))
-    ;; Scale value by requested amount, and update error bounds.
-    (when scale
-      (if (minusp scale)
-         (let ((scale-factor (expt 10 (- scale))))
-           (setq s (* s scale-factor)))
-         (let ((scale-factor (expt 10 scale)))
-           (setq r (* r scale-factor))
-           (setq m+ (* m+ scale-factor))
-           (setq m- (* m- scale-factor)))))
-    ;; Scale r and s and compute initial k, the base 10 logarithm of r.
-    (do ()
-       ((>= r (ceiling s 10)))
-      (decf k)
-      (setq r (* r 10))
-      (setq m- (* m- 10))
-      (setq m+ (* m+ 10)))
-    (do ()(nil)
-      (do ()
-         ((< (+ (ash r 1) m+) (ash s 1)))
-       (setq s (* s 10))
-       (incf k))
-      ;; Determine number of fraction digits to generate.
-      (cond (fdigits
-            ;; Use specified number of fraction digits.
-            (setq cutoff (- fdigits))
-            ;;don't allow less than fmin fraction digits
-            (if (and fmin (> cutoff (- fmin))) (setq cutoff (- fmin))))
-           (width
-            ;; Use as many fraction digits as width will permit but
-            ;; force at least fmin digits even if width will be
-            ;; exceeded.
-            (if (< k 0)
-                (setq cutoff (- 1 width))
-                (setq cutoff (1+ (- k width))))
-            (if (and fmin (> cutoff (- fmin))) (setq cutoff (- fmin)))))
-      ;; If we decided to cut off digit generation before precision
-      ;; has been exhausted, rounding the last digit may cause a carry
-      ;; propagation. We can prevent this, preserving left-to-right
-      ;; digit generation, with a few magical adjustments to m- and
-      ;; m+. Of course, correct rounding is also preserved.
-      (when (or fdigits width)
-       (let ((a (- cutoff k))
-             (y s))
-         (if (>= a 0)
-             (dotimes (i a) (setq y (* y 10)))
-             (dotimes (i (- a)) (setq y (ceiling y 10))))
-         (setq m- (max y m-))
-         (setq m+ (max y m+))
-         (when (= m+ y) (setq roundup t))))
-      (when (< (+ (ash r 1) m+) (ash s 1)) (return)))
-    ;; Zero-fill before fraction if no integer part.
-    (when (< k 0)
-      (setq decpnt digits)
-      (vector-push-extend #\. digit-string)
-      (dotimes (i (- k))
-       (incf digits) (vector-push-extend #\0 digit-string)))
-    ;; Generate the significant digits.
-    (do ()(nil)
-      (decf k)
-      (when (= k -1)
-       (vector-push-extend #\. digit-string)
-       (setq decpnt digits))
-      (multiple-value-setq (u r) (truncate (* r 10) s))
-      (setq m- (* m- 10))
-      (setq m+ (* m+ 10))
-      (setq low (< (ash r 1) m-))
-      (if roundup
-         (setq high (>= (ash r 1) (- (ash s 1) m+)))
-         (setq high (> (ash r 1) (- (ash s 1) m+))))
-      ;; Stop when either precision is exhausted or we have printed as
-      ;; many fraction digits as permitted.
-      (when (or low high (and cutoff (<= k cutoff))) (return))
-      (vector-push-extend (char *digits* u) digit-string)
-      (incf digits))
-    ;; If cutoff occurred before first digit, then no digits are
-    ;; generated at all.
-    (when (or (not cutoff) (>= k cutoff))
-      ;; Last digit may need rounding
-      (vector-push-extend (char *digits*
-                               (cond ((and low (not high)) u)
-                                     ((and high (not low)) (1+ u))
-                                     (t (if (<= (ash r 1) s) u (1+ u)))))
-                         digit-string)
-      (incf digits))
-    ;; Zero-fill after integer part if no fraction.
-    (when (>= k 0)
-      (dotimes (i k) (incf digits) (vector-push-extend #\0 digit-string))
-      (vector-push-extend #\. digit-string)
-      (setq decpnt digits))
-    ;; Add trailing zeroes to pad fraction if fdigits specified.
-    (when fdigits
-      (dotimes (i (- fdigits (- digits decpnt)))
-       (incf digits)
-       (vector-push-extend #\0 digit-string)))
-    ;; all done
-    (values digit-string (1+ digits) (= decpnt 0) (= decpnt digits) decpnt)))
-
+  (declare (type float x))
+  ;; FIXME: I think only FORMAT-DOLLARS calls FLONUM-TO-STRING with
+  ;; possibly-negative X.
+  (setf x (abs x))
+  (multiple-value-bind (e string)
+      (if fdigits
+          (flonum-to-digits x (min (- (+ fdigits (or scale 0)))
+                                   (- (or fmin 0))))
+          (if (and width (> width 1))
+              (let ((w (multiple-value-list
+                        (flonum-to-digits x
+                                          (max 1
+                                               (+ (1- width)
+                                                  (if (and scale (minusp scale))
+                                                      scale 0)))
+                                          t)))
+                    (f (multiple-value-list
+                        (flonum-to-digits x (- (+ (or fmin 0)
+                                                  (if scale scale 0)))))))
+                (cond
+                  ((>= (length (cadr w)) (length (cadr f)))
+                   (values-list w))
+                  (t (values-list f))))
+              (flonum-to-digits x)))
+    (let ((e (if (zerop x)
+                 e
+                 (+ e (or scale 0))))
+          (stream (make-string-output-stream)))
+      (if (plusp e)
+          (progn
+            (write-string string stream :end (min (length string) e))
+            (dotimes (i (- e (length string)))
+              (write-char #\0 stream))
+            (write-char #\. stream)
+            (write-string string stream :start (min (length string) e))
+            (when fdigits
+              (dotimes (i (- fdigits
+                             (- (length string)
+                                (min (length string) e))))
+                (write-char #\0 stream))))
+          (progn
+            (write-string "." stream)
+            (dotimes (i (- e))
+              (write-char #\0 stream))
+            (write-string string stream :end (when fdigits
+                                               (min (length string)
+                                                    (max (or fmin 0)
+                                                         (+ fdigits e)))))
+            (when fdigits
+              (dotimes (i (+ fdigits e (- (length string))))
+                (write-char #\0 stream)))))
+      (let ((string (get-output-stream-string stream)))
+        (values string (length string)
+                (char= (char string 0) #\.)
+                (char= (char string (1- (length string))) #\.)
+                (position #\. string))))))
+
+;;; implementation of figure 1 from Burger and Dybvig, 1996. It is
+;;; extended in order to handle rounding.
+;;;
+;;; As the implementation of the Dragon from Classic CMUCL (and
+;;; previously in SBCL above FLONUM-TO-STRING) says: "DO NOT EVEN
+;;; THINK OF ATTEMPTING TO UNDERSTAND THIS CODE WITHOUT READING THE
+;;; PAPER!", and in this case we have to add that even reading the
+;;; paper might not bring immediate illumination as CSR has attempted
+;;; to turn idiomatic Scheme into idiomatic Lisp.
+;;;
+;;; FIXME: figure 1 from Burger and Dybvig is the unoptimized
+;;; algorithm, noticeably slow at finding the exponent.  Figure 2 has
+;;; an improved algorithm, but CSR ran out of energy.
+;;;
+;;; possible extension for the enthusiastic: printing floats in bases
+;;; other than base 10.
+(defconstant single-float-min-e
+  (- 2 sb!vm:single-float-bias sb!vm:single-float-digits))
+(defconstant double-float-min-e
+  (- 2 sb!vm:double-float-bias sb!vm:double-float-digits))
+#!+long-float
+(defconstant long-float-min-e
+  (nth-value 1 (decode-float least-positive-long-float)))
+
+(defun flonum-to-digits (v &optional position relativep)
+  (let ((print-base 10) ; B
+        (float-radix 2) ; b
+        (float-digits (float-digits v)) ; p
+        (digit-characters "0123456789")
+        (min-e
+         (etypecase v
+           (single-float single-float-min-e)
+           (double-float double-float-min-e)
+           #!+long-float
+           (long-float long-float-min-e))))
+    (multiple-value-bind (f e)
+        (integer-decode-float v)
+      (let (;; FIXME: these even tests assume normal IEEE rounding
+            ;; mode.  I wonder if we should cater for non-normal?
+            (high-ok (evenp f))
+            (low-ok (evenp f)))
+        (with-push-char (:element-type base-char)
+          (labels ((scale (r s m+ m-)
+                     (do ((k 0 (1+ k))
+                          (s s (* s print-base)))
+                         ((not (or (> (+ r m+) s)
+                                   (and high-ok (= (+ r m+) s))))
+                          (do ((k k (1- k))
+                               (r r (* r print-base))
+                               (m+ m+ (* m+ print-base))
+                               (m- m- (* m- print-base)))
+                              ((not (and (plusp (- r m-)) ; Extension to handle zero
+                                         (or (< (* (+ r m+) print-base) s)
+                                             (and (not high-ok)
+                                                  (= (* (+ r m+) print-base) s)))))
+                               (values k (generate r s m+ m-)))))))
+                   (generate (r s m+ m-)
+                     (let (d tc1 tc2)
+                       (tagbody
+                        loop
+                          (setf (values d r) (truncate (* r print-base) s))
+                          (setf m+ (* m+ print-base))
+                          (setf m- (* m- print-base))
+                          (setf tc1 (or (< r m-) (and low-ok (= r m-))))
+                          (setf tc2 (or (> (+ r m+) s)
+                                        (and high-ok (= (+ r m+) s))))
+                          (when (or tc1 tc2)
+                            (go end))
+                          (push-char (char digit-characters d))
+                          (go loop)
+                        end
+                          (let ((d (cond
+                                     ((and (not tc1) tc2) (1+ d))
+                                     ((and tc1 (not tc2)) d)
+                                     (t ; (and tc1 tc2)
+                                      (if (< (* r 2) s) d (1+ d))))))
+                            (push-char (char digit-characters d))
+                            (return-from generate (get-pushed-string))))))
+                   (initialize ()
+                     (let (r s m+ m-)
+                       (if (>= e 0)
+                           (let* ((be (expt float-radix e))
+                                  (be1 (* be float-radix)))
+                             (if (/= f (expt float-radix (1- float-digits)))
+                                 (setf r (* f be 2)
+                                       s 2
+                                       m+ be
+                                       m- be)
+                                 (setf r (* f be1 2)
+                                       s (* float-radix 2)
+                                       m+ be1
+                                       m- be)))
+                           (if (or (= e min-e)
+                                   (/= f (expt float-radix (1- float-digits))))
+                               (setf r (* f 2)
+                                     s (* (expt float-radix (- e)) 2)
+                                     m+ 1
+                                     m- 1)
+                               (setf r (* f float-radix 2)
+                                     s (* (expt float-radix (- 1 e)) 2)
+                                     m+ float-radix
+                                     m- 1)))
+                       (when position
+                         (when relativep
+                           (aver (> position 0))
+                           (do ((k 0 (1+ k))
+                                ;; running out of letters here
+                                (l 1 (* l print-base)))
+                               ((>= (* s l) (+ r m+))
+                                ;; k is now \hat{k}
+                                (if (< (+ r (* s (/ (expt print-base (- k position)) 2)))
+                                       (* s (expt print-base k)))
+                                    (setf position (- k position))
+                                    (setf position (- k position 1))))))
+                         (let ((low (max m- (/ (* s (expt print-base position)) 2)))
+                               (high (max m+ (/ (* s (expt print-base position)) 2))))
+                           (when (<= m- low)
+                             (setf m- low)
+                             (setf low-ok t))
+                           (when (<= m+ high)
+                             (setf m+ high)
+                             (setf high-ok t))))
+                       (values r s m+ m-))))
+            (multiple-value-bind (r s m+ m-) (initialize)
+              (scale r s m+ m-))))))))
+\f
 ;;; Given a non-negative floating point number, SCALE-EXPONENT returns
 ;;; a new floating point number Z in the range (0.1, 1.0] and an
 ;;; exponent E such that Z * 10^E is (approximately) equal to the
 ;;; Given a non-negative floating point number, SCALE-EXPONENT returns
 ;;; a new floating point number Z in the range (0.1, 1.0] and an
 ;;; exponent E such that Z * 10^E is (approximately) equal to the
 ;;; part of the computation to avoid over/under flow. When
 ;;; denormalized, we must pull out a large factor, since there is more
 ;;; negative exponent range than positive range.
 ;;; part of the computation to avoid over/under flow. When
 ;;; denormalized, we must pull out a large factor, since there is more
 ;;; negative exponent range than positive range.
+
+(eval-when (:compile-toplevel :execute)
+  (setf *read-default-float-format*
+        #!+long-float 'long-float #!-long-float 'double-float))
 (defun scale-exponent (original-x)
   (let* ((x (coerce original-x 'long-float)))
     (multiple-value-bind (sig exponent) (decode-float x)
       (declare (ignore sig))
 (defun scale-exponent (original-x)
   (let* ((x (coerce original-x 'long-float)))
     (multiple-value-bind (sig exponent) (decode-float x)
       (declare (ignore sig))
-      (if (= x 0.0l0)
-         (values (float 0.0l0 original-x) 1)
-         (let* ((ex (round (* exponent (log 2l0 10))))
-                (x (if (minusp ex)
-                       (if (float-denormalized-p x)
-                           #!-long-float
-                           (* x 1.0l16 (expt 10.0l0 (- (- ex) 16)))
-                           #!+long-float
-                           (* x 1.0l18 (expt 10.0l0 (- (- ex) 18)))
-                           (* x 10.0l0 (expt 10.0l0 (- (- ex) 1))))
-                       (/ x 10.0l0 (expt 10.0l0 (1- ex))))))
-           (do ((d 10.0l0 (* d 10.0l0))
-                (y x (/ x d))
-                (ex ex (1+ ex)))
-               ((< y 1.0l0)
-                (do ((m 10.0l0 (* m 10.0l0))
-                     (z y (* y m))
-                     (ex ex (1- ex)))
-                    ((>= z 0.1l0)
-                     (values (float z original-x) ex))))))))))
+      (if (= x 0.0e0)
+          (values (float 0.0e0 original-x) 1)
+          (let* ((ex (locally (declare (optimize (safety 0)))
+                       (the fixnum
+                         (round (* exponent
+                                   ;; this is the closest double float
+                                   ;; to (log 2 10), but expressed so
+                                   ;; that we're not vulnerable to the
+                                   ;; host lisp's interpretation of
+                                   ;; arithmetic.  (FIXME: it turns
+                                   ;; out that sbcl itself is off by 1
+                                   ;; ulp in this value, which is a
+                                   ;; little unfortunate.)
+                                   (load-time-value
+                                    #!-long-float
+                                    (sb!kernel:make-double-float 1070810131 1352628735)
+                                    #!+long-float
+                                    (error "(log 2 10) not computed")))))))
+                 (x (if (minusp ex)
+                        (if (float-denormalized-p x)
+                            #!-long-float
+                            (* x 1.0e16 (expt 10.0e0 (- (- ex) 16)))
+                            #!+long-float
+                            (* x 1.0e18 (expt 10.0e0 (- (- ex) 18)))
+                            (* x 10.0e0 (expt 10.0e0 (- (- ex) 1))))
+                        (/ x 10.0e0 (expt 10.0e0 (1- ex))))))
+            (do ((d 10.0e0 (* d 10.0e0))
+                 (y x (/ x d))
+                 (ex ex (1+ ex)))
+                ((< y 1.0e0)
+                 (do ((m 10.0e0 (* m 10.0e0))
+                      (z y (* y m))
+                      (ex ex (1- ex)))
+                     ((>= z 0.1e0)
+                      (values (float z original-x) ex))
+                   (declare (long-float m) (integer ex))))
+              (declare (long-float d))))))))
+(eval-when (:compile-toplevel :execute)
+  (setf *read-default-float-format* 'single-float))
 \f
 ;;;; entry point for the float printer
 
 \f
 ;;;; entry point for the float printer
 
 ;;; attractive to handle exponential notation with the same accuracy
 ;;; as non-exponential notation, using the method described in the
 ;;; Steele and White paper.
 ;;; attractive to handle exponential notation with the same accuracy
 ;;; as non-exponential notation, using the method described in the
 ;;; Steele and White paper.
+;;;
+;;; NOTE II: this has been bypassed slightly by implementing Burger
+;;; and Dybvig, 1996.  When someone has time (KLUDGE) they can
+;;; probably (a) implement the optimizations suggested by Burger and
+;;; Dyvbig, and (b) remove all vestiges of Dragon4, including from
+;;; fixed-format printing.
 
 ;;; Print the appropriate exponent marker for X and the specified exponent.
 (defun print-float-exponent (x exp stream)
   (declare (type float x) (type integer exp) (type stream stream))
 
 ;;; Print the appropriate exponent marker for X and the specified exponent.
 (defun print-float-exponent (x exp stream)
   (declare (type float x) (type integer exp) (type stream stream))
-  (let ((*print-radix* nil)
-       (plusp (plusp exp)))
+  (let ((*print-radix* nil))
     (if (typep x *read-default-float-format*)
     (if (typep x *read-default-float-format*)
-       (unless (eql exp 0)
-         (format stream "e~:[~;+~]~D" plusp exp))
-       (format stream "~C~:[~;+~]~D"
-               (etypecase x
-                 (single-float #\f)
-                 (double-float #\d)
-                 (short-float #\s)
-                 (long-float #\L))
-               plusp exp))))
+        (unless (eql exp 0)
+          (format stream "e~D" exp))
+        (format stream "~C~D"
+                (etypecase x
+                  (single-float #\f)
+                  (double-float #\d)
+                  (short-float #\s)
+                  (long-float #\L))
+                exp))))
 
 (defun output-float-infinity (x stream)
   (declare (float x) (stream stream))
   (cond (*read-eval*
          (write-string "#." stream))
         (*print-readably*
 
 (defun output-float-infinity (x stream)
   (declare (float x) (stream stream))
   (cond (*read-eval*
          (write-string "#." stream))
         (*print-readably*
-         (error 'print-not-readable :object x))
+         (return-from output-float-infinity
+           (print-not-readable-error x stream)))
         (t
          (write-string "#<" stream)))
   (write-string "SB-EXT:" stream)
         (t
          (write-string "#<" stream)))
   (write-string "SB-EXT:" stream)
     (output-float-nan x stream))
    (t
     (let ((x (cond ((minusp (float-sign x))
     (output-float-nan x stream))
    (t
     (let ((x (cond ((minusp (float-sign x))
-                   (write-char #\- stream)
-                   (- x))
-                  (t
-                   x))))
+                    (write-char #\- stream)
+                    (- x))
+                   (t
+                    x))))
       (cond
        ((zerop x)
       (cond
        ((zerop x)
-       (write-string "0.0" stream)
-       (print-float-exponent x 0 stream))
+        (write-string "0.0" stream)
+        (print-float-exponent x 0 stream))
        (t
        (t
-       (output-float-aux x stream (float 1/1000 x) (float 10000000 x))))))))
+        (output-float-aux x stream -3 8)))))))
+
 (defun output-float-aux (x stream e-min e-max)
 (defun output-float-aux (x stream e-min e-max)
-  (if (and (>= x e-min) (< x e-max))
-      ;; free format
-      (multiple-value-bind (str len lpoint tpoint) (flonum-to-string x)
-       (declare (ignore len))
-       (when lpoint (write-char #\0 stream))
-       (write-string str stream)
-       (when tpoint (write-char #\0 stream))
-       (print-float-exponent x 0 stream))
-      ;; exponential format
-      (multiple-value-bind (f ex) (scale-exponent x)
-       (multiple-value-bind (str len lpoint tpoint)
-           (flonum-to-string f nil nil 1)
-         (declare (ignore len))
-         (when lpoint (write-char #\0 stream))
-         (write-string str stream)
-         (when tpoint (write-char #\0 stream))
-         ;; Subtract out scale factor of 1 passed to FLONUM-TO-STRING.
-         (print-float-exponent x (1- ex) stream)))))
+  (multiple-value-bind (e string)
+      (flonum-to-digits x)
+    (cond
+      ((< e-min e e-max)
+       (if (plusp e)
+           (progn
+             (write-string string stream :end (min (length string) e))
+             (dotimes (i (- e (length string)))
+               (write-char #\0 stream))
+             (write-char #\. stream)
+             (write-string string stream :start (min (length string) e))
+             (when (<= (length string) e)
+               (write-char #\0 stream))
+             (print-float-exponent x 0 stream))
+           (progn
+             (write-string "0." stream)
+             (dotimes (i (- e))
+               (write-char #\0 stream))
+             (write-string string stream)
+             (print-float-exponent x 0 stream))))
+      (t (write-string string stream :end 1)
+         (write-char #\. stream)
+         (write-string string stream :start 1)
+         (print-float-exponent x (1- e) stream)))))
 \f
 ;;;; other leaf objects
 
 \f
 ;;;; other leaf objects
 
 ;;; the character name or the character in the #\char format.
 (defun output-character (char stream)
   (if (or *print-escape* *print-readably*)
 ;;; the character name or the character in the #\char format.
 (defun output-character (char stream)
   (if (or *print-escape* *print-readably*)
-      (let ((name (char-name char)))
-       (write-string "#\\" stream)
-       (if name
-           (quote-string name stream)
-           (write-char char stream)))
+      (let ((graphicp (and (graphic-char-p char)
+                           (standard-char-p char)))
+            (name (char-name char)))
+        (write-string "#\\" stream)
+        (if (and name (not graphicp))
+            (quote-string name stream)
+            (write-char char stream)))
       (write-char char stream)))
 
 (defun output-sap (sap stream)
   (declare (type system-area-pointer sap))
   (cond (*read-eval*
       (write-char char stream)))
 
 (defun output-sap (sap stream)
   (declare (type system-area-pointer sap))
   (cond (*read-eval*
-        (format stream "#.(~S #X~8,'0X)" 'int-sap (sap-int sap)))
-       (t
-        (print-unreadable-object (sap stream)
-          (format stream "system area pointer: #X~8,'0X" (sap-int sap))))))
+         (format stream "#.(~S #X~8,'0X)" 'int-sap (sap-int sap)))
+        (t
+         (print-unreadable-object (sap stream)
+           (format stream "system area pointer: #X~8,'0X" (sap-int sap))))))
 
 (defun output-weak-pointer (weak-pointer stream)
   (declare (type weak-pointer weak-pointer))
   (print-unreadable-object (weak-pointer stream)
     (multiple-value-bind (value validp) (weak-pointer-value weak-pointer)
       (cond (validp
 
 (defun output-weak-pointer (weak-pointer stream)
   (declare (type weak-pointer weak-pointer))
   (print-unreadable-object (weak-pointer stream)
     (multiple-value-bind (value validp) (weak-pointer-value weak-pointer)
       (cond (validp
-            (write-string "weak pointer: " stream)
-            (write value :stream stream))
-           (t
-            (write-string "broken weak pointer" stream))))))
+             (write-string "weak pointer: " stream)
+             (write value :stream stream))
+            (t
+             (write-string "broken weak pointer" stream))))))
 
 (defun output-code-component (component stream)
   (print-unreadable-object (component stream :identity t)
     (let ((dinfo (%code-debug-info component)))
       (cond ((eq dinfo :bogus-lra)
 
 (defun output-code-component (component stream)
   (print-unreadable-object (component stream :identity t)
     (let ((dinfo (%code-debug-info component)))
       (cond ((eq dinfo :bogus-lra)
-            (write-string "bogus code object" stream))
-           (t
-            (write-string "code object" stream)
-            (when dinfo
-              (write-char #\space stream)
-              (output-object (sb!c::debug-info-name dinfo) stream)))))))
+             (write-string "bogus code object" stream))
+            (t
+             (write-string "code object" stream)
+             (when dinfo
+               (write-char #\space stream)
+               (output-object (sb!c::debug-info-name dinfo) stream)))))))
 
 (defun output-lra (lra stream)
   (print-unreadable-object (lra stream :identity t)
 
 (defun output-lra (lra stream)
   (print-unreadable-object (lra stream :identity t)
   (print-unreadable-object (fdefn stream)
     (write-string "FDEFINITION object for " stream)
     (output-object (fdefn-name fdefn) stream)))
   (print-unreadable-object (fdefn stream)
     (write-string "FDEFINITION object for " stream)
     (output-object (fdefn-name fdefn) stream)))
+
+#!+sb-simd-pack
+(defun output-simd-pack (pack stream)
+  (declare (type simd-pack pack))
+  (cond ((and *print-readably* *read-eval*)
+         (etypecase pack
+           ((simd-pack double-float)
+            (multiple-value-call #'format stream
+              "#.(~S ~S ~S)"
+              '%make-simd-pack-double
+              (%simd-pack-doubles pack)))
+           ((simd-pack single-float)
+            (multiple-value-call #'format stream
+              "#.(~S ~S ~S ~S ~S)"
+              '%make-simd-pack-single
+              (%simd-pack-singles pack)))
+           (t
+            (multiple-value-call #'format stream
+              "#.(~S #X~16,'0X #X~16,'0X)"
+              '%make-simd-pack-ub64
+              (%simd-pack-ub64s pack)))))
+        (t
+         (print-unreadable-object (pack stream)
+           (flet ((all-ones-p (value start end &aux (mask (- (ash 1 end) (ash 1 start))))
+                      (= (logand value mask) mask))
+                    (split-num (value start)
+                      (loop
+                         for i from 0 to 3
+                         and v = (ash value (- start)) then (ash v -8)
+                         collect (logand v #xFF))))
+             (multiple-value-bind (low high)
+                 (%simd-pack-ub64s pack)
+               (etypecase pack
+                 ((simd-pack double-float)
+                  (multiple-value-bind (v0 v1) (%simd-pack-doubles pack)
+                    (format stream "~S~@{ ~:[~,13E~;~*TRUE~]~}"
+                            'simd-pack
+                            (all-ones-p low 0 64) v0
+                            (all-ones-p high 0 64) v1)))
+                 ((simd-pack single-float)
+                  (multiple-value-bind (v0 v1 v2 v3) (%simd-pack-singles pack)
+                    (format stream "~S~@{ ~:[~,7E~;~*TRUE~]~}"
+                            'simd-pack
+                            (all-ones-p low 0 32) v0
+                            (all-ones-p low 32 64) v1
+                            (all-ones-p high 0 32) v2
+                            (all-ones-p high 32 64) v3)))
+                 (t
+                  (format stream "~S~@{ ~{ ~2,'0X~}~}"
+                          'simd-pack
+                          (split-num low 0) (split-num low 32)
+                          (split-num high 0) (split-num high 32))))))))))
 \f
 ;;;; functions
 
 \f
 ;;;; functions
 
 ;;; The definition here is a simple temporary placeholder. It will be
 ;;; overwritten by a smarter version (capable of calling generic
 ;;; PRINT-OBJECT when appropriate) when CLOS is installed.
 ;;; The definition here is a simple temporary placeholder. It will be
 ;;; overwritten by a smarter version (capable of calling generic
 ;;; PRINT-OBJECT when appropriate) when CLOS is installed.
-(defun printed-as-clos-funcallable-standard-class (object stream)
+(defun printed-as-funcallable-standard-class (object stream)
   (declare (ignore object stream))
   nil)
 
   (declare (ignore object stream))
   nil)
 
-(defun output-function (object stream)
-  (let* ((*print-length* 3) ; in case we have to..
-        (*print-level* 3)  ; ..print an interpreted function definition
-        (name (cond ((find (function-subtype object)
-                           #(#.sb!vm:closure-header-type
-                             #.sb!vm:byte-code-closure-type))
-                     "CLOSURE")
-                    ((sb!eval::interpreted-function-p object)
-                     (or (sb!eval::interpreted-function-%name object)
-                         (sb!eval:interpreted-function-lambda-expression
-                          object)))
-                    ((find (function-subtype object)
-                           #(#.sb!vm:function-header-type
-                             #.sb!vm:closure-function-header-type))
-                     (%function-name object))
-                    (t 'no-name-available)))
-        (identified-by-name-p (and (symbolp name)
-                                   (fboundp name)
-                                   (eq (fdefinition name) object))))
-      (print-unreadable-object (object
-                               stream
-                               :identity (not identified-by-name-p))
-       (prin1 'function stream)
-       (unless (eq name 'no-name-available)
-         (format stream " ~S" name)))))
+(defun output-fun (object stream)
+  (let* ((*print-length* 4)  ; in case we have to..
+         (*print-level* 3)  ; ..print an interpreted function definition
+         (name (%fun-name object))
+         (proper-name-p (and (legal-fun-name-p name) (fboundp name)
+                             (eq (fdefinition name) object))))
+    (print-unreadable-object (object stream :identity (not proper-name-p))
+      (format stream "~:[FUNCTION~;CLOSURE~]~@[ ~S~]"
+              (closurep object)
+              name))))
 \f
 ;;;; catch-all for unknown things
 
 (defun output-random (object stream)
   (print-unreadable-object (object stream :identity t)
 \f
 ;;;; catch-all for unknown things
 
 (defun output-random (object stream)
   (print-unreadable-object (object stream :identity t)
-    (let ((lowtag (get-lowtag object)))
+    (let ((lowtag (lowtag-of object)))
       (case lowtag
       (case lowtag
-       (#.sb!vm:other-pointer-type
-         (let ((type (get-type object)))
-           (case type
-             (#.sb!vm:value-cell-header-type
-              (write-string "value cell " stream)
-              (output-object (sb!c:value-cell-ref object) stream))
-             (t
-              (write-string "unknown pointer object, type=" stream)
-              (let ((*print-base* 16) (*print-radix* t))
-                (output-integer type stream))))))
-       ((#.sb!vm:function-pointer-type
-         #.sb!vm:instance-pointer-type
-         #.sb!vm:list-pointer-type)
-        (write-string "unknown pointer object, type=" stream))
-       (t
-        (case (get-type object)
-          (#.sb!vm:unbound-marker-type
-           (write-string "unbound marker" stream))
-          (t
-           (write-string "unknown immediate object, lowtag=" stream)
-           (let ((*print-base* 2) (*print-radix* t))
-             (output-integer lowtag stream))
-           (write-string ", type=" stream)
-           (let ((*print-base* 16) (*print-radix* t))
-             (output-integer (get-type object) stream)))))))))
+        (#.sb!vm:other-pointer-lowtag
+          (let ((widetag (widetag-of object)))
+            (case widetag
+              (#.sb!vm:value-cell-header-widetag
+               (write-string "value cell " stream)
+               (output-object (value-cell-ref object) stream))
+              (t
+               (write-string "unknown pointer object, widetag=" stream)
+               (let ((*print-base* 16) (*print-radix* t))
+                 (output-integer widetag stream))))))
+        ((#.sb!vm:fun-pointer-lowtag
+          #.sb!vm:instance-pointer-lowtag
+          #.sb!vm:list-pointer-lowtag)
+         (write-string "unknown pointer object, lowtag=" stream)
+         (let ((*print-base* 16) (*print-radix* t))
+           (output-integer lowtag stream)))
+        (t
+         (case (widetag-of object)
+           (#.sb!vm:unbound-marker-widetag
+            (write-string "unbound marker" stream))
+           (t
+            (write-string "unknown immediate object, lowtag=" stream)
+            (let ((*print-base* 2) (*print-radix* t))
+              (output-integer lowtag stream))
+            (write-string ", widetag=" stream)
+            (let ((*print-base* 16) (*print-radix* t))
+              (output-integer (widetag-of object) stream)))))))))