0.8.7.47:
[sbcl.git] / src / code / target-format.lisp
index 3e62ac0..99cbb3f 100644 (file)
   generally expand into additional text to be output, usually consuming one
   or more of the FORMAT-ARGUMENTS in the process. A few useful directives
   are:
-       ~A or ~nA     Prints one argument as if by PRINC
-       ~S or ~nS     Prints one argument as if by PRIN1
-       ~D or ~nD     Prints one argument as a decimal integer
-       ~%          Does a TERPRI
-       ~&          Does a FRESH-LINE
-
-        where n is the width of the field in which the object is printed.
+        ~A or ~nA   Prints one argument as if by PRINC
+        ~S or ~nS   Prints one argument as if by PRIN1
+        ~D or ~nD   Prints one argument as a decimal integer
+        ~%          Does a TERPRI
+        ~&          Does a FRESH-LINE
+  where n is the width of the field in which the object is printed.
 
   DESTINATION controls where the result will go. If DESTINATION is T, then
   the output is sent to the standard output stream. If it is NIL, then the
           (interpret-directive-list stream (cdr directives) orig-args args))
          (format-directive
           (multiple-value-bind (new-directives new-args)
-              (let ((function
-                     (svref *format-directive-interpreters*
-                            (char-code (format-directive-character
-                                        directive))))
-                    (*default-format-error-offset*
-                     (1- (format-directive-end directive))))
+              (let* ((character (format-directive-character directive))
+                     (function
+                      (svref *format-directive-interpreters*
+                             (char-code character)))
+                     (*default-format-error-offset*
+                      (1- (format-directive-end directive))))
                 (unless function
                   (error 'format-error
-                         :complaint "unknown format directive"))
+                         :complaint "unknown format directive ~@[(character: ~A)~]"
+                         :args (list (char-name character))))
                 (multiple-value-bind (new-directives new-args)
                     (funcall function stream directive
                              (cdr directives) orig-args args)
         (when ,params
           (error 'format-error
                  :complaint
-                 "too many parameters, expected no more than ~D"
-                 :arguments (list ,(length specs))
+                 "too many parameters, expected no more than ~W"
+                 :args (list ,(length specs))
                  :offset (caar ,params)))
         ,@body))))
 
   (let* ((name (char-name char)))
     (cond (name
           (write-string (string-capitalize name) stream))
-         ((<= 0 (char-code char) 31)
-          ;; Print control characters as "^"<char>. (This seems to be
-          ;; old pre-ANSI behavior, but ANSI just says that the "#^"
-          ;; sequence is undefined and not reserved for the user, so
-          ;; this behavior should be ANSI-compliant.)
-          (write-char #\^ stream)
-          (write-char (code-char (+ 64 (char-code char))) stream))
          (t
           (write-char char stream)))))
 
 (def-format-interpreter #\W (colonp atsignp params)
   (interpret-bind-defaults () params
     (let ((*print-pretty* (or colonp *print-pretty*))
-         (*print-level* (and atsignp *print-level*))
-         (*print-length* (and atsignp *print-length*)))
+         (*print-level* (unless atsignp *print-level*))
+         (*print-length* (unless atsignp *print-length*)))
       (output-object (next-arg) stream))))
 \f
 ;;;; format interpreters and support functions for integer output
                             (t commaed))))
          ;; colinc = 1, minpad = 0, padleft = t
          (format-write-field stream signed mincol 1 0 padchar t))
-       (princ number))))
+       (princ number stream))))
 
 (defun format-add-commas (string commachar commainterval)
   (let ((length (length string)))
 ;;; errors. As for now, we let the user get away with it, and merely guarantee
 ;;; that at least one significant digit will appear.
 
-;;; toy@rtp.ericsson.se:  The Hyperspec seems to say that the exponent
+;;; Raymond Toy writes: The Hyperspec seems to say that the exponent
 ;;; marker is always printed. Make it so. Also, the original version
 ;;; causes errors when printing infinities or NaN's. The Hyperspec is
 ;;; silent here, so let's just print out infinities and NaN's instead
                                  w 1 0 #\space t)))
       (format-princ stream number nil nil w 1 0 pad)))
 
-;;; toy@rtp.ericsson.se:  Same change as for format-exp-aux.
+;;; Raymond Toy writes: same change as for format-exp-aux
 (defun format-general-aux (stream number w d e k ovf pad marker atsign)
   (if (and (floatp number)
           (or (float-infinity-p number)
     (format-dollars stream (next-arg) d n w pad colonp atsignp)))
 
 (defun format-dollars (stream number d n w pad colon atsign)
-  (if (rationalp number) (setq number (coerce number 'single-float)))
+  (when (rationalp number)
+    ;; This coercion to SINGLE-FLOAT seems as though it gratuitously
+    ;; loses precision (why not LONG-FLOAT?) but it's the default
+    ;; behavior in the ANSI spec, so in some sense it's the right
+    ;; thing, and at least the user shouldn't be surprised.
+    (setq number (coerce number 'single-float)))
   (if (floatp number)
       (let* ((signstr (if (minusp number) "-" (if atsign "+" "")))
             (signlen (length signstr)))
        (multiple-value-bind (str strlen ig2 ig3 pointplace)
-           (sb!impl::flonum-to-string number nil d nil)
-         (declare (ignore ig2 ig3))
-         (when colon (write-string signstr stream))
-         (dotimes (i (- w signlen (- n pointplace) strlen))
+            (sb!impl::flonum-to-string number nil d nil)
+         (declare (ignore ig2 ig3 strlen))
+         (when colon
+           (write-string signstr stream))
+         (dotimes (i (- w signlen (max n pointplace) 1 d))
            (write-char pad stream))
-         (unless colon (write-string signstr stream))
-         (dotimes (i (- n pointplace)) (write-char #\0 stream))
+         (unless colon
+           (write-string signstr stream))
+         (dotimes (i (- n pointplace))
+           (write-char #\0 stream))
          (write-string str stream)))
       (format-write-field stream
                          (decimal-string number)
                          w 1 0 #\space t)))
 \f
-;;;; format interpreters and support functions for line/page breaks etc.
+;;;; FORMAT interpreters and support functions for line/page breaks etc.
 
 (def-format-interpreter #\% (colonp atsignp params)
   (when (or colonp atsignp)
            (if (<= 0 posn (length orig-args))
                (setf args (nthcdr posn orig-args))
                (error 'format-error
-                      :complaint "Index ~D is out of bounds. (It should ~
-                                  have been between 0 and ~D.)"
-                      :arguments (list posn (length orig-args))))))
+                      :complaint "Index ~W is out of bounds. (It should ~
+                                  have been between 0 and ~W.)"
+                      :args (list posn (length orig-args))))))
       (if colonp
          (interpret-bind-defaults ((n 1)) params
            (do ((cur-posn 0 (1+ cur-posn))
                       (setf args (nthcdr new-posn orig-args))
                       (error 'format-error
                              :complaint
-                             "Index ~D is out of bounds. (It should 
-                              have been between 0 and ~D.)"
-                             :arguments
+                             "Index ~W is out of bounds. (It should 
+                              have been between 0 and ~W.)"
+                             :args
                              (list new-posn (length orig-args))))))))
          (interpret-bind-defaults ((n 1)) params
            (dotimes (i n)
   (interpret-bind-defaults () params
     (handler-bind
        ((format-error
-         #'(lambda (condition)
-             (error 'format-error
-                    :complaint
-                    "~A~%while processing indirect format string:"
-                    :arguments (list condition)
-                    :print-banner nil
-                    :control-string string
-                    :offset (1- end)))))
+         (lambda (condition)
+           (error 'format-error
+                  :complaint
+                  "~A~%while processing indirect format string:"
+                  :args (list condition)
+                  :print-banner nil
+                  :control-string string
+                  :offset (1- end)))))
       (if atsignp
          (setf args (%format stream (next-arg) orig-args args))
          (%format stream (next-arg) (next-arg))))))
               (if (zerop posn)
                   (handler-bind
                       ((format-error
-                        #'(lambda (condition)
-                            (error 'format-error
-                                   :complaint
+                        (lambda (condition)
+                          (error
+                           'format-error
+                           :complaint
                            "~A~%while processing indirect format string:"
-                                   :arguments (list condition)
-                                   :print-banner nil
-                                   :control-string string
-                                   :offset (1- end)))))
+                           :args (list condition)
+                           :print-banner nil
+                           :control-string string
+                           :offset (1- end)))))
                     (%format stream insides orig-args args))
                   (interpret-directive-list stream insides
                                             orig-args args)))
                (interpret-format-logical-block stream orig-args args
                                                prefix per-line-p insides
                                                suffix atsignp))
-             (interpret-format-justification stream orig-args args
-                                             segments colonp atsignp
-                                             first-semi params)))
+             (let ((count (reduce #'+ (mapcar (lambda (x) (count-if #'illegal-inside-justification-p x)) segments))))
+               (when (> count 0)
+                 ;; ANSI specifies that "an error is signalled" in this
+                 ;; situation.
+                 (error 'format-error
+                        :complaint "~D illegal directive~:P found inside justification block"
+                        :args (list count)))
+               (interpret-format-justification stream orig-args args
+                                               segments colonp atsignp
+                                               first-semi params))))
     remaining))
 
 (defun interpret-format-justification
     (if per-line-p
        (pprint-logical-block
            (stream arg :per-line-prefix prefix :suffix suffix)
-         (let ((*logical-block-popper* #'(lambda () (pprint-pop))))
+         (let ((*logical-block-popper* (lambda () (pprint-pop))))
            (catch 'up-and-out
              (interpret-directive-list stream insides
                                        (if atsignp orig-args arg)
                                        arg))))
        (pprint-logical-block (stream arg :prefix prefix :suffix suffix)
-         (let ((*logical-block-popper* #'(lambda () (pprint-pop))))
+         (let ((*logical-block-popper* (lambda () (pprint-pop))))
            (catch 'up-and-out
              (interpret-directive-list stream insides
                                        (if atsignp orig-args arg)
 ;;;; format interpreter and support functions for user-defined method
 
 (def-format-interpreter #\/ (string start end colonp atsignp params)
-  (let ((symbol (extract-user-function-name string start end)))
+  (let ((symbol (extract-user-fun-name string start end)))
     (collect ((args))
       (dolist (param-and-offset params)
        (let ((param (cdr param-and-offset)))