home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / clisp / src / archive / clisp.faslsp.lha / format.lsp < prev    next >
Text File  |  1996-08-07  |  123KB  |  2,858 lines

  1. ; FORMAT - und was dazugehört.
  2. ; Bruno Haible 22.06.1988
  3. ; CLISP-Version 16.08.1988, 03.09.1988, 04.08.1989
  4. ; Groß umgearbeitet von Bruno Haible am 14.02.1990-15.02.1990
  5. ; Weiter umgearbeitet und FORMATTER geschrieben am 9.4.1995-11.4.1995
  6.  
  7. (in-package "SYSTEM")
  8.  
  9. ;-------------------------------------------------------------------------------
  10.  
  11. ; Datenstruktur der Kontrollstring-Direktive:
  12. (defstruct (control-string-directive
  13.              (:copier nil)
  14.              (:conc-name "CSD-")
  15.              (:predicate nil)
  16.              (:constructor make-csd ())
  17.            )
  18.   (type         0 :type fixnum)
  19.   (cs-index     0 :type fixnum)
  20.   (parm-list    nil :type list)
  21.   (v-or-#-p     nil :type symbol)
  22.   (colon-p      nil :type symbol)
  23.   (atsign-p     nil :type symbol)
  24.   (data         nil)
  25.   (clause-chain nil)
  26. )
  27. #+CLISP (remprop 'control-string-directive 'sys::defstruct-description)
  28. ; Erläuterung:
  29. ; type=0 : Direktive ~<Newline>, nichts auszugeben.
  30. ;          Weitere Komponenten bedeutungslos
  31. ; type=1 : String auszugeben,
  32. ;          von *FORMAT-CS* die Portion :START cs-index :END data.
  33. ;          Weitere Komponenten bedeutungslos
  34. ; type=2 : Formatier-Direktive auszuführen.
  35. ;          data = Name der Direktive (Symbol),
  36. ;          colon-p gibt an, ob ein ':' da war,
  37. ;          atsign-p gibt an, ob ein '@' da war,
  38. ;          parm-list = Parameterliste an die Direktive,
  39. ;          v-or-#-p gibt an, ob parm-list vor dem Aufruf noch zu behandeln ist.
  40. ;          clause-chain ist eine Verzeigerung: z.B. bei ~[...~;...~;...~]
  41. ;          von der ~[-Direktive auf die Liste ab der ersten ~;-Direktive,
  42. ;          von da auf die Liste ab der nächsten ~;-Direktive usw.
  43. ;          bis schließlich auf die Liste ab der ~]-Direktive.
  44.  
  45. ; Zeigt an, ob ein Character ein Whitespace-Character ist.
  46. (defun whitespacep (char)
  47.   (member char '(#\Space #\Newline #\Linefeed #\Tab #\Return #\Page))
  48. )
  49.  
  50. ; (FORMAT-PARSE-CS control-string startindex csdl stop-at)
  51. ; parst einen Kontrollstring (genauer: (subseq control-string startindex))
  52. ; und legt die sich ergebende Control-String-Directive-Liste in (cdr csdl) ab.
  53. ; Das Parsen muß mit der Direktive stop-at enden (ein Character, oder NIL
  54. ; für Stringende).
  55. ; Falls stop-at /= NIL, ist in (csd-clause-chain (car csdl)) ein Pointer auf
  56. ; die Teilliste ab dem nächsten Separator einzutragen. Diese Pointer bilden
  57. ; eine einfach verkettete Liste innerhalb csdl: von einem Separator zum
  58. ; nächsten, zum Schluß zum Ende der Clause.
  59. (defun format-parse-cs (control-string startindex csdl stop-at)
  60.   (declare (fixnum startindex))
  61.   (macrolet ((errorstring ()
  62.                #L{
  63.                DEUTSCH "Kontrollstring endet mitten in einer Direktive."
  64.                ENGLISH "The control string terminates within a directive."
  65.                FRANCAIS "La chaîne de contrôle se termine en plein milieu d'une directive."
  66.                }
  67.             ))
  68.     (prog* ((index startindex) ; cs-index des nächsten Zeichens
  69.             ch ; current character
  70.             intparam ; Integer-Parameter
  71.             newcsd ; aktuelle CSD
  72.             (last-separator-csd (car csdl))
  73.            )
  74.       (declare (type simple-string control-string) (type fixnum index))
  75.       (loop ; neue Direktive insgesamt
  76.         (tagbody
  77.           (when (>= index (length control-string))
  78.             (go string-ended)
  79.           )
  80.           (setq ch (schar control-string index))
  81.           (unless (eql ch #\~)
  82.             ; eventuell noch Stringstück zu einer eingenen Direktive machen
  83.             (setq csdl (setf (cdr csdl) (list (setq newcsd (make-csd)))))
  84.             (setf (csd-type     newcsd) 1)
  85.             (setf (csd-cs-index newcsd) index)
  86.             (setq index (position #\~ control-string :start index))
  87.             (unless index
  88.               (setf (csd-data newcsd) (setq index (length control-string)))
  89.               (go string-ended)
  90.             )
  91.             (setf (csd-data newcsd) index)
  92.           )
  93.           (setq csdl (setf (cdr csdl) (list (setq newcsd (make-csd)))))
  94.           (setf (csd-type         newcsd) 2)
  95.           (setf (csd-cs-index     newcsd) index)
  96.           (setf (csd-parm-list    newcsd) nil)
  97.           (setf (csd-v-or-#-p     newcsd) nil)
  98.           (setf (csd-colon-p      newcsd) nil)
  99.           (setf (csd-atsign-p     newcsd) nil)
  100.           (setf (csd-data         newcsd) nil)
  101.           (setf (csd-clause-chain newcsd) nil)
  102.  
  103.           param ; Parameter einer Direktive kann beginnen
  104.           (incf index)
  105.           (when (>= index (length control-string))
  106.             (format-error control-string index (errorstring))
  107.             (go string-ended)
  108.           )
  109.           (setq ch (schar control-string index))
  110.           (when (digit-char-p ch) (go num-param))
  111.           (case ch
  112.             ((#\+ #\-) (go num-param))
  113.             (#\' (go quote-param))
  114.             ((#\V #\v #\#)
  115.              (push (if (eql ch #\#) ':ARG-COUNT ':NEXT-ARG)
  116.                    (csd-parm-list newcsd)
  117.              )
  118.              (setf (csd-v-or-#-p newcsd) T)
  119.              (go param-ok-1)
  120.             )
  121.             (#\, (push nil (csd-parm-list newcsd)) (go param))
  122.             (#\: (go colon-modifier))
  123.             (#\@ (go atsign-modifier))
  124.             (T (go directive))
  125.           )
  126.  
  127.           num-param ; numerischer Parameter
  128.           (multiple-value-setq (intparam index)
  129.             (parse-integer control-string :start index :junk-allowed t)
  130.           )
  131.           (unless intparam
  132.             (format-error control-string index
  133.                           #L{
  134.                           DEUTSCH "~A muß eine Zahl einleiten."
  135.                           ENGLISH "~A must introduce a number."
  136.                           FRANCAIS "~A doit introduire un nombre."
  137.                           }
  138.                           ch
  139.           ) )
  140.           (push intparam (csd-parm-list newcsd))
  141.           (go param-ok-2)
  142.  
  143.           quote-param ; Quote-Parameter-Behandlung
  144.           (incf index)
  145.           (when (>= index (length control-string))
  146.             (format-error control-string index
  147.                           #L{
  148.                           DEUTSCH "Kontrollstring endet mitten in einem '-Parameter."
  149.                           ENGLISH "The control string terminates in the middle of a parameter."
  150.                           FRANCAIS "La chaîne de contrôle se termine au milieu d'un paramètre."
  151.                           }
  152.             )
  153.             (go string-ended)
  154.           )
  155.           (setq ch (schar control-string index))
  156.           (push ch (csd-parm-list newcsd))
  157.  
  158.           param-ok-1 ; Parameter OK
  159.           (incf index)
  160.           param-ok-2 ; Parameter OK
  161.           (when (>= index (length control-string))
  162.             (format-error control-string index (errorstring))
  163.             (go string-ended)
  164.           )
  165.           (setq ch (schar control-string index))
  166.           (case ch
  167.             (#\, (go param))
  168.             (#\: (go colon-modifier))
  169.             (#\@ (go atsign-modifier))
  170.             (T (go directive))
  171.           )
  172.  
  173.           colon-modifier ; nach :
  174.           (setf (csd-colon-p newcsd) T)
  175.           (go passed-modifier)
  176.  
  177.           atsign-modifier ; nach @
  178.           (setf (csd-atsign-p newcsd) T)
  179.           (go passed-modifier)
  180.  
  181.           passed-modifier ; nach : oder @
  182.           (incf index)
  183.           (when (>= index (length control-string))
  184.             (format-error control-string index (errorstring))
  185.             (go string-ended)
  186.           )
  187.           (setq ch (schar control-string index))
  188.           (case ch
  189.             (#\: (go colon-modifier))
  190.             (#\@ (go atsign-modifier))
  191.             (T (go directive))
  192.           )
  193.  
  194.           directive ; Direktive (ihr Name) erreicht
  195.           (setf (csd-parm-list newcsd) (nreverse (csd-parm-list newcsd)))
  196.           (let ((directive-name
  197.                   (cdr (assoc (char-upcase ch)
  198.                          '((#\A . FORMAT-ASCII)
  199.                            (#\S . FORMAT-S-EXPRESSION)
  200.                            (#\W . FORMAT-WRITE)
  201.                            (#\D . FORMAT-DECIMAL)
  202.                            (#\B . FORMAT-BINARY)
  203.                            (#\O . FORMAT-OCTAL)
  204.                            (#\X . FORMAT-HEXADECIMAL)
  205.                            (#\R . FORMAT-RADIX)
  206.                            (#\P . FORMAT-PLURAL)
  207.                            (#\C . FORMAT-CHARACTER)
  208.                            (#\F . FORMAT-FIXED-FLOAT)
  209.                            (#\E . FORMAT-EXPONENTIAL-FLOAT)
  210.                            (#\G . FORMAT-GENERAL-FLOAT)
  211.                            (#\$ . FORMAT-DOLLARS-FLOAT)
  212.                            (#\% . FORMAT-TERPRI)
  213.                            (#\& . FORMAT-FRESH-LINE)      (#\Newline . #\Newline)
  214.                            (#\| . FORMAT-PAGE)
  215.                            (#\~ . FORMAT-TILDE)
  216.                            (#\T . FORMAT-TABULATE)
  217.                            (#\* . FORMAT-GOTO)
  218.                            (#\? . FORMAT-INDIRECTION)
  219.                            (#\( . FORMAT-CASE-CONVERSION) (#\) . FORMAT-CASE-CONVERSION-END)
  220.                            (#\[ . FORMAT-CONDITIONAL)     (#\] . FORMAT-CONDITIONAL-END)
  221.                            (#\{ . FORMAT-ITERATION)       (#\} . FORMAT-ITERATION-END)
  222.                            (#\< . FORMAT-JUSTIFICATION)   (#\> . FORMAT-JUSTIFICATION-END)
  223.                            (#\^ . FORMAT-UP-AND-OUT)      (#\; . FORMAT-SEPARATOR)
  224.                            ; mit Funktionsdefinition      ; ohne Funktionsdefinition
  225.                )) )    )  )
  226.             (if directive-name
  227.               (setf (csd-data newcsd) directive-name)
  228.               (format-error control-string index
  229.                 #L{
  230.                 DEUTSCH "Diese Direktive gibt es nicht."
  231.                 ENGLISH "Non-existent directive"
  232.                 FRANCAIS "Directive non reconnue."
  233.                 }
  234.           ) ) )
  235.           (incf index)
  236.           (case ch
  237.             (( #\( #\[ #\{ #\< )
  238.              (multiple-value-setq (index csdl)
  239.                (format-parse-cs control-string index csdl
  240.                  (case ch (#\( #\)) (#\[ #\]) (#\{ #\}) (#\< #\>) )
  241.              ) )
  242.             )
  243.             (( #\) #\] #\} #\> )
  244.              (unless stop-at
  245.                (format-error control-string index
  246.                  #L{
  247.                  DEUTSCH "Schließende Klammer '~A' ohne vorherige öffnende Klammer"
  248.                  ENGLISH "The closing directive '~A' does not have a corresponding opening one."
  249.                  FRANCAIS "Parenthèse fermante '~A' sans parenthèse ouvrante correspondante."
  250.                  }
  251.                  ch
  252.              ) )
  253.              (unless (eql ch stop-at)
  254.                (format-error control-string index
  255.                  #L{
  256.                  DEUTSCH "Schließende Klammer '~A' paßt nicht; sollte '~A' lauten."
  257.                  ENGLISH "The closing directive '~A' does not match the corresponding opening one. It should read '~A'."
  258.                  FRANCAIS "La parenthèse fermante '~A' ne correspond pas à celle ouvrante. Il devrait y avoir '~A'."
  259.                  }
  260.                  ch stop-at
  261.              ) )
  262.              (setf (csd-clause-chain last-separator-csd) csdl)
  263.              (go end)
  264.             )
  265.             (#\;
  266.              (unless (or (eql stop-at #\]) (eql stop-at #\>))
  267.                (format-error control-string index
  268.                  #L{
  269.                  DEUTSCH "Hier ist keine ~~;-Direktive möglich."
  270.                  ENGLISH "The ~~; directive is not allowed at this point."
  271.                  FRANCAIS "La directive ~~; n'est pas permise ici."
  272.                  }
  273.              ) )
  274.              (setf (csd-clause-chain last-separator-csd) csdl)
  275.              (setq last-separator-csd newcsd)
  276.             )
  277.             (#\Newline
  278.              (setf (csd-type newcsd) 0)
  279.              (if (csd-colon-p newcsd)
  280.                (if (csd-atsign-p newcsd)
  281.                  (format-error control-string index
  282.                    #L{
  283.                    DEUTSCH "Die ~~Newline-Direktive ist mit : und @ sinnlos."
  284.                    ENGLISH "The ~~newline directive cannot take both modifiers."
  285.                    FRANCAIS "La directive ~~Newline est insensée avec les deux qualificateurs : et @."
  286.                    }
  287.                  )
  288.                  nil ; ~:<newline> -> Newline ignorieren, Whitespace dalassen
  289.                )
  290.                (progn
  291.                  (when (csd-atsign-p newcsd)
  292.                    ; ~@<newline> -> Stringstück mit Newline zum Ausgeben
  293.                    (setf (csd-type newcsd) 1)
  294.                    (setf (csd-cs-index newcsd) (1- index))
  295.                    (setf (csd-data newcsd) index)
  296.                  )
  297.                  (setq index
  298.                    (or (position-if-not #'whitespacep control-string :start index)
  299.                        (length control-string)
  300.           ) )) ) ) )
  301.         ) ; tagbody zu Ende
  302.       ) ; loop zu Ende
  303.  
  304.       string-ended
  305.       (when stop-at
  306.         (format-error control-string index
  307.           #L{
  308.           DEUTSCH "Schließende Klammer '~A' fehlt."
  309.           ENGLISH "An opening directive is never closed; expecting '~A'."
  310.           FRANCAIS "Il manque la borne fermante '~A'."
  311.           }
  312.           stop-at
  313.       ) )
  314.  
  315.       end
  316.       (return (values index csdl))
  317. ) ) )
  318.  
  319. ;-------------------------------------------------------------------------------
  320.  
  321. (defvar *FORMAT-CS*) ; control-string
  322. (defvar *FORMAT-CSDL*) ; control-string directive list
  323. (defvar *FORMAT-ARG-LIST*) ; argument-list
  324. (defvar *FORMAT-NEXT-ARG*) ; pointer to next argument in argument-list
  325. (defvar *FORMAT-NEXT-ARGLIST*) ; pointer to next sublist in ~:{ iteration
  326. (defvar *FORMAT-UP-AND-OUT* nil) ; reason for up-and-out
  327.  
  328. ; (format-error controlstring errorpos errorcode . arguments)
  329. ; signalisiert einen Error, der bei FORMAT aufgetreten ist. Die Stelle im
  330. ; Control-string wird mit einem Pfeil markiert.
  331. (defun format-error (controlstring errorpos errorstring &rest arguments)
  332.   (when controlstring
  333.     (unless errorpos (setq errorpos (csd-cs-index (car *FORMAT-CSDL*))))
  334.     (setq errorstring
  335.       (string-concat errorstring
  336.         #L{
  337.         DEUTSCH "~%Stelle im Kontrollstring:"
  338.         ENGLISH "~%Current point in control string:"
  339.         FRANCAIS "~%Position dans la chaîne de contrôle :"
  340.         }
  341.     ) )
  342.     (let ((pos1 0) (pos2 0))
  343.       (declare (simple-string errorstring) (fixnum pos1 pos2))
  344.       (loop
  345.         (setq pos2 (or (position #\Newline controlstring :start pos1)
  346.                        (length controlstring)
  347.         )          )
  348.         (setq errorstring (string-concat errorstring "~%  ~A"))
  349.         (setq arguments
  350.           (nconc arguments (list (substring controlstring pos1 pos2)))
  351.         )
  352.         (when (<= pos1 errorpos pos2)
  353.           (setq errorstring
  354.             (string-concat errorstring "~%~VT"
  355.                            #+(or DOS OS/2 WIN32-DOS) "" #-(or DOS OS/2 WIN32-DOS) "|"
  356.           ) )
  357.           (setq arguments (nconc arguments (list (+ (- errorpos pos1) 2))))
  358.         )
  359.         (when (= pos2 (length controlstring)) (return))
  360.         (setq pos1 (+ pos2 1))
  361.   ) ) )
  362.   (apply #'error-of-type 'error errorstring arguments)
  363. )
  364.  
  365. ;-------------------------------------------------------------------------------
  366.  
  367. (defun format (destination control-string &rest arguments)
  368.   (unless (or (stringp control-string) (functionp control-string))
  369.     (format-cs-error control-string)
  370.   )
  371.   (cond ((null destination)
  372.          (let ((stream (make-string-output-stream)))
  373.            (format-apply stream control-string arguments)
  374.            (get-output-stream-string stream)
  375.         ))
  376.         ((eq destination 'T)
  377.          (format-apply *standard-output* control-string arguments)
  378.          nil
  379.         )
  380.         ((streamp destination)
  381.          (format-apply destination control-string arguments)
  382.          nil
  383.         )
  384.         ((stringp destination)
  385.          (if (array-has-fill-pointer-p destination)
  386.            (let ((stream (sys::make-string-push-stream destination)))
  387.              (format-apply stream control-string arguments)
  388.            )
  389.            (error-of-type 'error
  390.              #L{
  391.              DEUTSCH "String zum Vollschreiben ~S hat keinen Fill-Pointer."
  392.              ENGLISH "The destination string ~S should have a fill pointer."
  393.              FRANCAIS "La chaîne destination n'a pas de pointeur de remplissage."
  394.              }
  395.              destination
  396.          ) )
  397.          nil
  398.         )
  399.         (t (error-of-type 'type-error
  400.              :datum destination :expected-type '(or (member nil t) stream string)
  401.              #L{
  402.              DEUTSCH "Das ist weder NIL noch T noch ein Stream noch ein String: ~S"
  403.              ENGLISH "The destination argument ~S is invalid (not NIL or T or a stream or a string)."
  404.              FRANCAIS "L'argument de destination n'est ni NIL, ni T, ni un «stream» ni une chaîne : ~S"
  405.              }
  406.              destination
  407.         )  )
  408. ) )
  409.  
  410. (defun format-apply (stream control-string arguments &optional (whole-arguments arguments))
  411.   (cond ((stringp control-string)
  412.          ; evtl. noch control-string zu einem Simple-String machen ??
  413.          (let ((node (list control-string)))
  414.            (format-parse-cs control-string 0 node nil)
  415.            (let* ((*FORMAT-CS*         (car node))
  416.                   (*FORMAT-CSDL*       (cdr node))
  417.                   (*FORMAT-ARG-LIST*   whole-arguments)
  418.                   (*FORMAT-NEXT-ARG*   arguments)
  419.                   (*FORMAT-NEXT-ARGLIST* nil)
  420.                   (*FORMAT-UP-AND-OUT* nil))
  421.              (format-interpret stream)
  422.              *FORMAT-NEXT-ARG*
  423.         )) )
  424.         ((functionp control-string)
  425.          (let ((*FORMAT-CS* nil)) ; format-error kann nicht mehr auf die Stelle zeigen
  426.            (apply control-string stream arguments)
  427.         ))
  428.         (t (format-cs-error control-string))
  429. ) )
  430.  
  431. (defun format-cs-error (control-string)
  432.   (error-of-type 'type-error
  433.     :datum control-string :expected-type '(or string function)
  434.     #L{
  435.     DEUTSCH "~S: Kontrollstring muß ein String sein, nicht ~S"
  436.     ENGLISH "~S: The control-string must be a string, not ~S"
  437.     FRANCAIS "~S : La chaîne de contrôle doit être une chaîne et non ~S"
  438.     }
  439.     'format control-string
  440. ) )
  441.  
  442. ;-------------------------------------------------------------------------------
  443.  
  444. ; (next-arg) liefert (und verbraucht) das nächste Argument aus der Argument-
  445. ; liste *FORMAT-NEXT-ARG*.
  446. (defun next-arg ()
  447.   (if (atom *FORMAT-NEXT-ARG*)
  448.     (format-error *FORMAT-CS* nil
  449.       #L{
  450.       DEUTSCH "Nicht genügend Argumente für diese Direktive übrig."
  451.       ENGLISH "There are not enough arguments left for this directive."
  452.       FRANCAIS "Il ne reste pas assez d'arguments pour cette directive."
  453.       }
  454.     )
  455.     (pop *FORMAT-NEXT-ARG*)
  456. ) )
  457.  
  458. ; (format-interpret stream [endmarker]) interpretiert *FORMAT-CSDL* ab.
  459. ; Fluid vars:
  460. ;   *FORMAT-ARG-LIST*
  461. ;   *FORMAT-NEXT-ARG*
  462. ;   *FORMAT-NEXT-ARGLIST*
  463. ;   *FORMAT-CS*
  464. ;   *FORMAT-CSDL*
  465. ;   *FORMAT-UP-AND-OUT*
  466. ; Abbruch des Interpretierens bei Antreffen der Direktive endmarker
  467. ; oder der Direktive ~; .
  468. (defun format-interpret (stream &optional (endmarker nil))
  469.   (loop
  470.     (when *FORMAT-UP-AND-OUT* (return))
  471.     (when (endp *FORMAT-CSDL*) (return))
  472.     (let ((csd (car *FORMAT-CSDL*)))
  473.       (case (csd-type csd)
  474.         (0 )
  475.         (1 (write-string *FORMAT-CS* stream
  476.              :start (csd-cs-index csd) :end (csd-data csd)
  477.         )  )
  478.         (2 (let ((directive-name (csd-data csd)))
  479.              (if (eq directive-name endmarker) (return))
  480.              (if (eq directive-name 'FORMAT-SEPARATOR) (return))
  481.              (apply directive-name
  482.                stream
  483.                (csd-colon-p csd)
  484.                (csd-atsign-p csd)
  485.                (format-resolve-parms csd)
  486.         )  ) )
  487.     ) )
  488.     (setq *FORMAT-CSDL* (cdr *FORMAT-CSDL*))
  489. ) )
  490.  
  491. ; liefert die korrekte Argumentliste einer CSD, evtl. mit eingesetzten
  492. ; Parametern: V (als :NEXT-ARG) und # (als :ARG-COUNT) werden aufgelöst.
  493. (defun format-resolve-parms (csd)
  494.   (let ((arglist (csd-parm-list csd)))
  495.     (if (csd-v-or-#-p csd)
  496.       (mapcar #'(lambda (arg)
  497.                   (case arg
  498.                     (:NEXT-ARG (next-arg))
  499.                     (:ARG-COUNT (list-length *FORMAT-NEXT-ARG*))
  500.                     (T arg)
  501.                 ) )
  502.               arglist
  503.       )
  504.       arglist
  505. ) ) )
  506.  
  507. ; Definiert eine einfache FORMAT-Unterfunktion, d.i. eine, die genau ein
  508. ; Argument verbraucht.
  509. (defmacro defformat-simple (name (stream colon atsign . optionals-with-defaults)
  510.                                  (arg) &body body
  511.                             &environment env)
  512.   (multiple-value-bind (body-rest declarations) (sys::parse-body body nil env)
  513.     (let ((name2 (concat-pnames "DO-" name)) ; in #<PACKAGE SYSTEM>
  514.           (optionals (mapcar #'(lambda (opt) (if (consp opt) (first opt) opt))
  515.                              optionals-with-defaults
  516.          ))          )
  517.       `(PROGN
  518.          (DEFUN ,name (,stream ,colon ,atsign &OPTIONAL ,@optionals)
  519.            (,name2 ,stream ,colon ,atsign ,@optionals (next-arg))
  520.          )
  521.          (DEFUN ,name2 (,stream ,colon ,atsign ,@optionals ,arg)
  522.            ,@(if declarations `((DECLARE ,@declarations)))
  523.            ,@(mapcap #'(lambda (opt)
  524.                          (if (and (consp opt) (not (null (second opt))))
  525.                            `((IF (NULL ,(first opt)) (SETQ ,(first opt) ,(second opt))))
  526.                            '()
  527.                        ) )
  528.                      optionals-with-defaults
  529.              )
  530.            ,@body-rest
  531.        ) )
  532. ) ) )
  533.  
  534. ; Bewegt den Stand des "Pointers in die Argumentliste" in eine Richtung.
  535. (defun format-goto-new-arg (backwardp index)
  536.   (if backwardp
  537.     ; rückwärts
  538.     (setq *FORMAT-NEXT-ARG*
  539.       (nthcdr
  540.         (max (- (list-length *FORMAT-ARG-LIST*) (list-length *FORMAT-NEXT-ARG*) index) 0)
  541.         *FORMAT-ARG-LIST*
  542.     ) )
  543.     ; vorwärts ist einfacher:
  544.     (setq *FORMAT-NEXT-ARG* (nthcdr index *FORMAT-NEXT-ARG*))
  545. ) )
  546.  
  547. ; gibt arg als römische Zahl auf stream aus, z.B. 4 als IIII.
  548. (defun format-old-roman (arg stream)
  549.   (unless (and (integerp arg) (<= 1 arg 4999))
  550.     (format-error *FORMAT-CS* nil
  551.       #L{
  552.       DEUTSCH "Die ~~:@R-Direktive erwartet ein Integer zwischen 1 und 4999, nicht ~S"
  553.       ENGLISH "The ~~:@R directive requires an integer in the range 1 - 4999, not ~S"
  554.       FRANCAIS "La directive ~~:@R requiert un entier compris entre 1 et 4999 et non ~S"
  555.       }
  556.       arg
  557.   ) )
  558.   (do ((charlistr  '(#\M  #\D #\C #\L #\X #\V #\I) (cdr charlistr))
  559.        (valuelistr '(1000 500 100 50  10   5   1) (cdr valuelistr))
  560.        (value arg (multiple-value-bind (multiplicity restvalue)
  561.                       (floor value (first valuelistr))
  562.                     (dotimes (i multiplicity)
  563.                       (write-char (first charlistr) stream)
  564.                     )
  565.                     restvalue
  566.       ))          )
  567.       ((zerop value))
  568. ) )
  569.  
  570. ; gibt arg als römische Zahl auf stream aus, z.B. 4 als IV.
  571. (defun format-new-roman (arg stream)
  572.   (unless (and (integerp arg) (<= 1 arg 3999))
  573.     (format-error *FORMAT-CS* nil
  574.       #L{
  575.       DEUTSCH "Die ~~@R-Direktive erwartet ein Integer zwischen 1 und 3999, nicht ~S"
  576.       ENGLISH "The ~~@R directive requires an integer in the range 1 - 3999, not ~S"
  577.       FRANCAIS "La directive ~~@R requiert un entier compris entre 1 et 3999 et non ~S"
  578.       }
  579.       arg
  580.   ) )
  581.   (do ((charlistr       '(#\M #\D #\C #\L #\X #\V #\I) (cdr charlistr))
  582.        (valuelistr     '(1000 500 100 50  10   5   1 ) (cdr valuelistr))
  583.        (lowercharlistr  '(#\C #\C #\X #\X #\I #\I    ) (cdr lowercharlistr))
  584.        (lowervaluelistr '(100 100 10  10   1   1   0 ) (cdr lowervaluelistr))
  585.        (value arg
  586.          (multiple-value-bind (multiplicity restvalue)
  587.              (floor value (first valuelistr))
  588.            (dotimes (i multiplicity) (write-char (first charlistr) stream))
  589.            (let ((loweredvalue (- (first valuelistr) (first lowervaluelistr))))
  590.              (if (>= restvalue loweredvalue)
  591.                (progn
  592.                  (write-char (first lowercharlistr) stream)
  593.                  (write-char (first charlistr) stream)
  594.                  (- restvalue loweredvalue)
  595.                )
  596.                restvalue
  597.       )) ) ) )
  598.       ((zerop value))
  599. ) )
  600.  
  601. (defconstant FORMAT-CARDINAL-ONES
  602.   '#(NIL "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"
  603.      "ten" "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen"
  604.      "seventeen" "eighteen" "nineteen"
  605. )   )
  606.  
  607. (defconstant FORMAT-CARDINAL-TENS
  608.   '#(NIL NIL "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety")
  609. )
  610.  
  611. ; (format-small-cardinal arg stream) gibt eine ganze Zahl >0, <1000 im
  612. ; Klartext auf englisch auf den stream aus. (arg=0 -> gibt nichts aus.)
  613. (defun format-small-cardinal (arg stream)
  614.   (multiple-value-bind (hundreds tens-and-ones) (truncate arg 100)
  615.     (when (> hundreds 0)
  616.       (write-string (svref FORMAT-CARDINAL-ONES hundreds) stream)
  617.       (write-string " hundred" stream)
  618.     )
  619.     (when (> tens-and-ones 0)
  620.       (when (> hundreds 0) (write-string " and " stream))
  621.       (multiple-value-bind (tens ones) (truncate tens-and-ones 10)
  622.         (if (< tens 2)
  623.           (write-string (svref FORMAT-CARDINAL-ONES tens-and-ones) stream)
  624.           (progn
  625.             (write-string (svref FORMAT-CARDINAL-TENS tens) stream)
  626.             (when (> ones 0)
  627.               (write-char #\- stream)
  628.               (write-string (svref FORMAT-CARDINAL-ONES ones) stream)
  629. ) ) ) ) ) ) )
  630.  
  631. ; (format-cardinal arg stream) gibt die ganze Zahl arg im Klartext auf englisch
  632. ; auf den Stream aus.
  633. (defun format-cardinal (arg stream) ; arg Integer
  634.   (if (zerop arg)
  635.     (write-string "zero" stream)
  636.     (progn
  637.       (when (minusp arg) (write-string "minus " stream) (setq arg (- arg)))
  638.       (labels
  639.         ((blocks1000 (illions-list arg) ; Zerlegung in 1000er-Blöcke
  640.            (when (null illions-list)
  641.              (format-error *FORMAT-CS* nil
  642.                #L{
  643.                DEUTSCH "Zu großes Argument für ~~R-Direktive."
  644.                ENGLISH "The argument for the ~~R directive is too large."
  645.                FRANCAIS "L'argument pour la directive ~~R est trop grand."
  646.                }
  647.            ) )
  648.            (multiple-value-bind (thousands small) (truncate arg 1000)
  649.              (when (> thousands 0) (blocks1000 (cdr illions-list) thousands))
  650.              (when (> small 0)
  651.                (when (> thousands 0) (write-string ", " stream))
  652.                (format-small-cardinal small stream)
  653.                (write-string (car illions-list) stream)
  654.         )) ) )
  655.         (blocks1000
  656.           ; amerikanisch (billion=10^9)
  657.           '("" " thousand" " million" " billion" " trillion" " quadrillion"
  658.             " quintillion" " sextillion" " septillion" " octillion" " nonillion"
  659.             " decillion" " undecillion" " duodecillion" " tredecillion"
  660.             " quattuordecillion" " quindecillion" " sexdecillion" " septendecillion"
  661.             " octodecillion" " novemdecillion" " vigintillion")
  662.           arg
  663. ) ) ) ) )
  664.  
  665. (defconstant FORMAT-ORDINAL-ONES
  666.   '#(NIL "first" "second" "third" "fourth" "fifth" "sixth" "seventh" "eighth"
  667.      "ninth" "tenth" "eleventh" "twelfth" "thirteenth" "fourteenth"
  668.      "fifteenth" "sixteenth" "seventeenth" "eighteenth" "nineteenth"
  669. )   )
  670.  
  671. ; (format-ordinal arg stream) gibt eine ganze Zahl arg als Abzählnummer im
  672. ; Klartext auf englisch auf den stream aus.
  673. (defun format-ordinal (arg stream) ; arg Integer
  674.   (if (zerop arg)
  675.     (write-string "zeroth" stream)
  676.     (progn
  677.       (when (minusp arg) (write-string "minus " stream) (setq arg (- arg)))
  678.       (multiple-value-bind (hundreds tens-and-ones) (floor arg 100)
  679.         (when (> hundreds 0) (format-cardinal (* hundreds 100) stream))
  680.         (if (zerop tens-and-ones)
  681.           (write-string "th" stream)
  682.           (multiple-value-bind (tens ones) (floor tens-and-ones 10)
  683.             (when (> hundreds 0) (write-char #\Space stream))
  684.             (cond ((< tens 2)
  685.                    (write-string (svref FORMAT-ORDINAL-ONES tens-and-ones) stream)
  686.                   )
  687.                   ((zerop ones)
  688.                    (write-string
  689.                      (svref '#(NIL "tenth" "twentieth" "thirtieth" "fortieth" "fiftieth"
  690.                                "sixtieth" "seventieth" "eightieth" "ninetieth")
  691.                             tens
  692.                      )
  693.                      stream
  694.                   ))
  695.                   (t (write-string (svref FORMAT-CARDINAL-TENS tens) stream)
  696.                      (write-char #\- stream)
  697.                      (write-string (svref FORMAT-ORDINAL-ONES ones) stream)
  698. ) ) ) ) ) ) )     )
  699.  
  700. ; (format-padding count char stream) gibt count (ein Fixnum >=0) Zeichen char
  701. ; auf stream aus.
  702. (defun format-padding (count char stream)
  703.   (dotimes (i count) (write-char char stream))
  704. )
  705.  
  706. ; gibt auf den Stream stream aus:
  707. ; den String str, eventuell aufgefüllt mit Padding characters padchar.
  708. ; Und zwar so, daß die Breite mindestens mincol ist. Um das zu erreichen,
  709. ; werden mindestens minpad Zeichen eingefügt, eventuelle weitere dann in
  710. ; Blöcken à colinc Zeichen. Falls padleftflag, werden sie links eingefügt,
  711. ; sonst rechts vom String.
  712. (defun format-padded-string
  713.        (mincol colinc minpad padchar padleftflag str stream)
  714.   (let* ((need (+ (length str) minpad)) ; so viele Zeichen mindestens
  715.          (auxpad (if (< need mincol)
  716.                    (* (ceiling (- mincol need) colinc) colinc)
  717.                    0
  718.         ))       ) ; so viele Zeichen zusätzlich
  719.     (unless padleftflag (write-string str stream))
  720.     (format-padding (+ minpad auxpad) padchar stream)
  721.     (when padleftflag (write-string str stream))
  722. ) )
  723.  
  724. ; gibt den Integer arg auf den Stream aus:
  725. ; in Zahlenbasis base, mit Vorzeichen (+ nur falls >0 und positive-sign-flag),
  726. ; bei commaflag alle drei Stellen unterbrochen durch ein Zeichen commachar.
  727. ; Das Ganze links aufgefüllt mit padchar's, so daß die Gesamtbreite mindestens
  728. ; mincol ist.
  729. (defun format-integer (base
  730.                        mincol
  731.                        padchar
  732.                        commachar
  733.                        commainterval
  734.                        commaflag
  735.                        positive-sign-flag
  736.                        arg
  737.                        stream
  738.                       )
  739.   (let* ((*print-base* base)
  740.          (*print-radix* nil)
  741.          (*print-readably* nil))
  742.     (if (and (zerop mincol) (not commaflag) (not positive-sign-flag))
  743.       (princ arg stream) ; normale Ausgabe tut's
  744.       (let* ((oldstring (princ-to-string arg))
  745.              (oldstring-length (length oldstring))
  746.              (number-of-digits
  747.                (if (minusp arg) (1- oldstring-length) oldstring-length) )
  748.              (number-of-commas
  749.                (if commaflag (floor (1- number-of-digits) commainterval) 0) )
  750.              (positive-sign (and positive-sign-flag (> arg 0)))
  751.              (newstring-length
  752.                (+ (if positive-sign 1 0) ; Vorzeichen
  753.                   oldstring-length number-of-commas ; Ziffern, Kommas
  754.              ) )
  755.              (newstring (make-string newstring-length)) )
  756.         ; Erst Vorzeichen +:
  757.         (when positive-sign (setf (schar newstring 0) #\+))
  758.         ; Dann oldstring in newstring übertragen, dabei Kommata überspringen:
  759.         (let ((oldpos oldstring-length) (newpos newstring-length))
  760.           (loop
  761.             (decf oldpos)
  762.             (when (minusp oldpos) (return))
  763.             (decf newpos)
  764.             (setf (schar newstring newpos) (schar oldstring oldpos))
  765.             (when (and (plusp number-of-commas)
  766.                        (zerop (mod (- oldstring-length oldpos) commainterval))
  767.                   ) ; noch ein Komma einzufügen?
  768.               (decf newpos)
  769.               (setf (schar newstring newpos) commachar)
  770.               (decf number-of-commas)
  771.         ) ) )
  772.         (if (zerop mincol)
  773.           (write-string newstring stream) ; schneller
  774.           (format-padded-string mincol 1 0 padchar t newstring stream)
  775. ) ) ) ) )
  776.  
  777. ; was ~D bei non-Integer-Argument tut: Argument mit ~A, aber dezimal ausgeben
  778. (defun format-ascii-decimal (arg stream)
  779.   (let ((*print-base* 10.)
  780.         (*print-radix* nil)
  781.         (*print-readably* nil))
  782.     (princ arg stream)
  783. ) )
  784.  
  785. ; Unterprogramm für ~D, ~B, ~O, ~X:
  786. (defun format-base (base stream colon-modifier atsign-modifier
  787.                     mincol padchar commachar commainterval
  788.                     arg)
  789.   (if (or (and (zerop mincol) (not colon-modifier) (not atsign-modifier))
  790.           (not (integerp arg))
  791.       )
  792.     (let ((*print-base* base)
  793.           (*print-radix* nil)
  794.           (*print-readably* nil))
  795.       (princ arg stream)
  796.     )
  797.     (format-integer base mincol padchar commachar commainterval
  798.                     colon-modifier atsign-modifier arg stream
  799. ) ) )
  800.  
  801. ; (format-scale-exponent-aux arg null eins zehn zehntel lg2)
  802. ; liefert zur Floating-Point-Zahl arg >= 0 und
  803. ; null = 0.0, eins = 1.0, zehn = 10.0, zehntel = 0.1, lg2 = log(2)/log(10)
  804. ; (erste vier in derselben Floating-Point-Precision wie arg)
  805. ; zwei Werte: mantissa und n, mit
  806. ; ganzem n und mantissa floating-point, 0.1 <= mantissa < 1,
  807. ; arg = mantissa * 10^n (also 10^(n-1) <= arg < 10^n ).
  808. ; (Bei arg=null: null und n=0.)
  809. (defun format-scale-exponent-aux (arg null eins zehn zehntel lg2)
  810.   (multiple-value-bind (significand expon) (decode-float arg)
  811.     (declare (ignore significand))
  812.     (if (zerop arg)
  813.       (values null 0)
  814.       (let* ((expon10a (truncate (* expon lg2))) ; nicht round, um Überlauf zu vermeiden
  815.              (signif10a (/ arg (expt zehn expon10a))))
  816.         (do ((zehnpot zehn (* zehnpot zehn))
  817.              (signif10b signif10a (/ signif10a zehnpot))
  818.              (expon10b expon10a (1+ expon10b)))
  819.             ((< signif10b eins)
  820.              (do ((zehnpot zehn (* zehnpot zehn))
  821.                   (signif10c signif10b (* signif10b zehnpot))
  822.                   (expon10c expon10b (1- expon10c)))
  823.                  ((>= signif10c zehntel)
  824.                   (values signif10c expon10c)
  825.              )   )
  826.         )   )
  827. ) ) ) )
  828.  
  829. ; (format-scale-exponent arg) liefert zur Floating-Point-Zahl arg >= 0
  830. ; zwei Werte: mantissa und n, mit
  831. ; ganzem n und mantissa floating-point, 0.1 <= mantissa < 1,
  832. ; arg = mantissa * 10^n (also 10^(n-1) <= arg < 10^n ).
  833. ; (Bei arg=null: 0.0 und n=0.)
  834. (defun format-scale-exponent (arg)
  835.   (cond ((short-float-p arg)
  836.          (format-scale-exponent-aux arg 0.0s0 1.0s0 10.0s0 0.1s0 0.30103s0)
  837.         )
  838.         ((single-float-p arg)
  839.          (format-scale-exponent-aux arg 0.0f0 1.0f0 10.0f0 0.1f0 0.30103s0)
  840.         )
  841.         ((double-float-p arg)
  842.          (format-scale-exponent-aux arg 0.0d0 1.0d0 10.0d0 0.1d0 0.30103s0)
  843.         )
  844.         ((long-float-p arg)
  845.          (format-scale-exponent-aux arg
  846.            (float 0 arg) (float 1 arg) (float 10 arg) (float 1/10 arg)
  847.            0.30102999566d0 ; lg2 wird mit 32 Bit Genauigkeit gebraucht
  848. ) )     ))
  849.  
  850. ; (format-float-to-string arg width d k dmin)
  851. ; ergibt einen String zum Floating-point arg:
  852. ; er hat den Wert von (* (abs arg) (expt 10 k)), dabei mind. d Nachkommastellen
  853. ; und höchstens die Länge width (width=nil -> keine Einschränkung).
  854. ; Trotzdem wird nicht auf weniger als dmin Stellen gerundet.
  855. (let ((digit-string
  856.         (make-array 20 :element-type 'string-char :adjustable t :fill-pointer t)
  857.      ))
  858. (defun format-float-to-string (arg width d k dmin)
  859.   (if (zerop arg)
  860.     (let ((places (max (or d 0) (or dmin 0))))
  861.       (when width ; width angegeben -> places := (min places (1- width))
  862.         (when (>= places width) (setq places (1- width)))
  863.       )
  864.       (values
  865.         (let ((str (make-string (1+ places) :initial-element #\0)))
  866.           (setf (schar str 0) #\.)
  867.           str          ; ein Punkt und places Nullen
  868.         )
  869.         (1+ places)    ; Stellenzahl
  870.         t              ; Punkt ganz vorne
  871.         (zerop places) ; Punkt ganz hinten ?
  872.         0              ; Position des Punktes
  873.     ) )
  874.     (multiple-value-bind (significand expon) (integer-decode-float arg)
  875. ; significand : Integer >0
  876. ; expon : Integer
  877. ; mantprec : Anzahl der echten Mantissenbits von significand
  878. ; (also 2^mantprec <= significand < 2^(mantprec+1))
  879. ; width : Anzahl Stellen, die die Zahl (inklusive Punkt) nicht überschreiten
  880. ;         soll, oder NIL
  881. ; d : Mindestanzahl Nachkommastellen oder NIL
  882. ; k : Skalierungsfaktor (siehe CLTL S.394)
  883. ; dmin : Mindestanzahl von Dezimaltellen, die (trotz Angabe von width oder d)
  884. ;        nicht gerundet werden dürfen.
  885. ;        (Nur interessant, falls d <= dmin <= (precision der Zahl).)
  886. ; wandelt die Zahl significand*2^expon um in einen Dezimalstring um.
  887. ; Es ist kein Exponent dabei.
  888.       (let* ((mantprec (1- (float-digits arg)))
  889.              (numerator significand)
  890.              (denominator 1)
  891.              (abrund-einh 1) ; Abrundungseinheit:
  892.                ; Abrunden um 1 in der letzten abrundbaren Stelle entspricht
  893.                ; einer Erniedrigung von numerator um abrund-einh.
  894.              (aufrund-einh 1) ; Aufrundungseinheit:
  895.                ; Aufrunden um 1 in der letzten aufrundbaren Stelle entspricht
  896.                ; einer Erhöhung von numerator um aufrund-einh.
  897.              ; Stellen: 0 = 1. Stelle vor dem Punkt, -1 = 1. Stelle nach dem Punkt.
  898.              (stelle 0) ; Stelle der als nächstes auszugebenden Ziffer
  899.              (digit-count 0) ; Zahl der bisher in digit-string ausgegebenen
  900.                              ; Ziffern (exklusive den Punkt)
  901.              (point-pos 0) ; Punkt-Position = Zahl führender Stellen
  902.                            ; = Zahl der Ziffern vor dem Punkt
  903.              (letzte-stelle nil) ; NIL oder (falls d oder width angegeben waren)
  904.                            ; Stelle der letzten signifikanten Ziffer
  905.              (halbzahlig nil) ; zeigt an, ob hinten genau ein 0.500000 wegfällt
  906.              digit ; die laufende Ziffer, >=0, <10
  907.              (abrunden nil) ; T falls letzte Ziffer abzurunden ist
  908.              (aufrunden nil) ; T falls letzte Ziffer aufzurunden ist
  909.             )
  910.         (setf (fill-pointer digit-string) 0) ; digit-string leeren
  911.         (cond
  912.           ((> expon 0)
  913.            (setq numerator (ash significand expon))
  914.            (setq aufrund-einh (setq abrund-einh (ash 1 expon)))
  915.           )
  916.           ((< expon 0)
  917.            (setq denominator (ash 1 (- expon))) ; aufrund-einh = abrund-einh = 1
  918.         ) )
  919.         ; Zahl = numerator/denominator
  920.         (when (= significand (ash 1 mantprec))
  921.           ; Ist der Significand=2^mantprec, so ist abrund-einh zu halbieren.
  922.           ; Man kann stattdessen auch alle 3 anderen Grössen verdoppeln:
  923.           (setq aufrund-einh (ash aufrund-einh 1))
  924.           (setq numerator (ash numerator 1))
  925.           (setq denominator (ash denominator 1))
  926.         )
  927.         ; Defaultmäßig: Auf-/Abrunde-Einheit = eine Einheit in der letzten
  928.         ; BINÄRstelle.
  929.         ; Zahl = numerator/denominator
  930.         ; Skalierungsfaktor k in die Zahl mit einbeziehen (vgl. CLTL S.394)
  931.         ; k<0 -> Mantisse durch 10^(abs k) dividieren
  932.         ; k>0 -> Mantisse mit 10^k multiplizieren
  933.         ; Dabei aufrund-einh, abrund-einh im Verhältnis zu numerator beibehalten.
  934.         (when k
  935.           (if (< k 0)
  936.             (let ((skal-faktor (expt 10 (- k))))
  937.               (setq denominator (* denominator skal-faktor))
  938.             )
  939.             (let ((skal-faktor (expt 10 k)))
  940.               (setq numerator (* numerator skal-faktor))
  941.               (setq aufrund-einh (* aufrund-einh skal-faktor))
  942.               (setq abrund-einh (* abrund-einh skal-faktor))
  943.             )
  944.         ) )
  945.         ; auf >= 1/10 adjustieren:
  946.         ; (jeweils numerator mit 10 multiplizieren, eine führende 0 mehr vorsehen)
  947.         (do ()
  948.             ((>= (* numerator 10) denominator))
  949.           (setq stelle (1- stelle))
  950.           (setq numerator (* numerator 10))
  951.           (setq abrund-einh (* abrund-einh 10))
  952.           (setq aufrund-einh (* aufrund-einh 10))
  953.         )
  954.         ; stelle = Stelle der letzten führenden 0
  955.         ;        = 1 + Stelle der 1. signifikanten Ziffer
  956.         ;        oder =0, falls k>=0
  957.         ; Ausführung der Rundung:
  958.         (loop
  959.           ; Solange das Ergebnis auch nach Aufrundung >= 1 bliebe,
  960.           ; eine Vorkommastelle mehr einplanen:
  961.           (do ()
  962.               ((< (+ (ash numerator 1) aufrund-einh) (ash denominator 1)))
  963.             (setq denominator (* denominator 10))
  964.             (setq stelle (1+ stelle))
  965.           )
  966.           ; Falls d oder width angegeben:
  967.           ; letzte-stelle ausrechnen
  968.           (if d
  969.             ; Falls dmin angegeben: (min (- d) (- dmin)) = (- (max d dmin)).
  970.             ; Sonst (- d).
  971.             (progn
  972.               (setq letzte-stelle (- d))
  973.               (when (and dmin (> letzte-stelle (- dmin)))
  974.                 (setq letzte-stelle (- dmin))
  975.             ) )
  976.             ; Falls nicht d, nur width angegeben:
  977.             (when width
  978.               (if (< stelle 0)
  979.                 ; Es kommen führende Nullen nach dem Punkt -> d:=(1- width)
  980.                 (setq letzte-stelle (- 1 width))
  981.                 ; Es kommen keine führenden Nullen nach dem Punkt ->
  982.                 ; Es wird stelle Vorkommaziffern geben, d:=(- (1- width) stelle)
  983.                 (setq letzte-stelle (1+ (- stelle width)))
  984.               )
  985.               ; also letzte-stelle = (- (- (1- width) (max stelle 0)))
  986.               ; wieder dmin berücksichtigen:
  987.               (when (and dmin (> letzte-stelle (- dmin)))
  988.                 (setq letzte-stelle (- dmin))
  989.           ) ) )
  990.           (when (or d width)
  991.             (let* ((ziffernzahl (- letzte-stelle stelle))
  992.                    ; ziffernzahl = - Zahl signifikanter Stellen oder >=0.
  993.                    (dezimal-einh denominator))
  994.               ; dezimal-einh := (ceiling (* dezimal-einh (expt 10 ziffernzahl)))
  995.               (if (>= ziffernzahl 0)
  996.                 (dotimes (i ziffernzahl)
  997.                   (setq dezimal-einh (* dezimal-einh 10))
  998.                 )
  999.                 (dotimes (i (- ziffernzahl))
  1000.                   (setq dezimal-einh (ceiling dezimal-einh 10))
  1001.                 )
  1002.               )
  1003.               ; dezimal-einh = Um wieviel numerator erhöht bzw. erniedigt werden
  1004.               ; müßte, damit sich die Dezimaldarstellung um genau 1 an der
  1005.               ; Position letzte-stelle verändert.
  1006.               (setq abrund-einh (max dezimal-einh abrund-einh))
  1007.               (setq aufrund-einh (max dezimal-einh aufrund-einh))
  1008.               ; Jetzt darf auch um eine (halbe) DEZIMAL-Einheit gerundet werden.
  1009.               (when (= aufrund-einh dezimal-einh) (setq halbzahlig T))
  1010.           ) )
  1011.           (when (< (+ (ash numerator 1) aufrund-einh) (ash denominator 1))
  1012.             (return)
  1013.         ) )
  1014.         ; stelle = Position der ersten signifikanten Stelle + 1
  1015.         ; Führenden Punkt und nachfolgende Nullen ausgeben:
  1016.         (when (< stelle 0)
  1017.           (setq point-pos digit-count)
  1018.           (vector-push-extend #\. digit-string)
  1019.           (dotimes (i (- stelle))
  1020.             (incf digit-count)
  1021.             (vector-push-extend #\0 digit-string)
  1022.         ) )
  1023.         ; Ziffern der Mantisse ausgeben:
  1024.         (loop
  1025.           (when (zerop stelle)
  1026.             (vector-push-extend #\. digit-string)
  1027.             (setq point-pos digit-count)
  1028.           )
  1029.           (decf stelle)
  1030.           (multiple-value-setq (digit numerator)
  1031.             (truncate (* numerator 10) denominator)
  1032.           )
  1033.           (setq abrund-einh (* abrund-einh 10))
  1034.           (setq aufrund-einh (* aufrund-einh 10))
  1035.           (setq abrunden (< (ash numerator 1) abrund-einh))
  1036.           (if halbzahlig
  1037.             (setq aufrunden
  1038.               (>= (ash numerator 1) (- (ash denominator 1) aufrund-einh))
  1039.             )
  1040.             (setq aufrunden
  1041.               (> (ash numerator 1) (- (ash denominator 1) aufrund-einh))
  1042.             )
  1043.           )
  1044.           (when (or abrunden aufrunden
  1045.                     (and letzte-stelle (<= stelle letzte-stelle))
  1046.                 )
  1047.             (return)
  1048.           )
  1049.           (vector-push-extend (schar "0123456789" digit) digit-string)
  1050.           (incf digit-count)
  1051.         )
  1052.         ; letzte signifikante Ziffer ausgeben:
  1053.         (when (or (null letzte-stelle) (>= stelle letzte-stelle))
  1054.           (vector-push-extend
  1055.             (schar "0123456789"
  1056.               (cond
  1057.                 ((and abrunden (not aufrunden)) digit)
  1058.                 ((and aufrunden (not abrunden)) (1+ digit))
  1059.                 ((<= (ash numerator 1) denominator) digit)
  1060.                 (t (1+ digit))
  1061.             ) )
  1062.             digit-string
  1063.           )
  1064.           (incf digit-count)
  1065.         )
  1066.         ; Nachfolgende Nullen und Punkt ausgeben
  1067.         (when (>= stelle 0)
  1068.           (dotimes (i stelle)
  1069.             (incf digit-count)
  1070.             (vector-push-extend #\0 digit-string)
  1071.           )
  1072.           (vector-push-extend #\. digit-string)
  1073.           (setq point-pos digit-count)
  1074.         )
  1075.         (when d
  1076.           (dotimes (i (- d (- digit-count point-pos)))
  1077.             (incf digit-count)
  1078.             (vector-push-extend #\0 digit-string)
  1079.         ) )
  1080.         (values
  1081.                   digit-string               ; Ziffern
  1082.                   (1+ digit-count)           ; Anzahl der Ziffern
  1083.                   (= point-pos 0)            ; Punkt ganz vorne?
  1084.                   (= point-pos digit-count)  ; Punkt ganz hinten?
  1085.                   point-pos                  ; Position des Punktes
  1086.         ) ; 5 Werte
  1087. ) ) ) )
  1088. )
  1089.  
  1090. ; (format-float-for-f w d k overflowchar padchar plus-sign-flag arg stream)
  1091. ; gibt die Floating-Point-Zahl arg in Festkommadarstellung auf stream aus.
  1092. (defun format-float-for-f (w d k overflowchar padchar plus-sign-flag arg stream)
  1093.   (let ((width (if w (if (or plus-sign-flag (minusp arg)) (1- w) w) nil)))
  1094.     ; width = zur Verfügung stehende Zeichen ohne Vorzeichen
  1095.     (multiple-value-bind (digits digitslength leadingpoint trailingpoint)
  1096.         (format-float-to-string arg width d k nil)
  1097.       (when (eql d 0) (setq trailingpoint nil)) ; d=0 -> keine Zusatz-Null hinten
  1098.       (when w
  1099.         (setq width (- width digitslength))
  1100.         (when leadingpoint ; evtl. Zusatz-Null vorne einplanen
  1101.           (if (> width 0) (setq width (1- width)) (setq leadingpoint nil))
  1102.         )
  1103.         (when trailingpoint ; evtl. Zusatz-Null hinten einplanen
  1104.           (if (> width 0) (setq width (1- width)) (setq trailingpoint nil))
  1105.         )
  1106.       )
  1107.       ; Es bleiben noch width Zeichen übrig.
  1108.       (if (and overflowchar w (minusp width))
  1109.         (format-padding w overflowchar stream) ; Zu wenig Platz -> overflow
  1110.         (progn
  1111.           (when (and w (> width 0)) (format-padding width padchar stream))
  1112.           (if (minusp arg)
  1113.             (write-char #\- stream)
  1114.             (if plus-sign-flag (write-char #\+ stream))
  1115.           )
  1116.           (when leadingpoint (write-char #\0 stream))
  1117.           (write-string digits stream)
  1118.           (when trailingpoint (write-char #\0 stream))
  1119.       ) )
  1120. ) ) )
  1121.  
  1122. ; (format-float-for-e w d e k overflowchar padchar exponentchar plus-sign-flag
  1123. ;                     arg stream)
  1124. ; gibt die Floating-point-Zahl arg in Exponentialdarstellung auf den stream aus.
  1125. ; (vgl. CLTL S.392-394)
  1126. ; Aufteilung der Mantisse:
  1127. ;   Falls k<=0, erst 1 Null (falls von der Breite her passend), dann der Punkt,
  1128. ;               dann |k| Nullen, dann d-|k| signifikante Stellen;
  1129. ;               zusammen also d Nachkommastellen.
  1130. ;   Falls k>0,  erst k signifikante Stellen, dann der Punkt,
  1131. ;               dann weitere d-k+1 signifikante Stellen;
  1132. ;               zusammen also d+1 signifikante Stellen. Keine Nullen vorne.
  1133. ;   (Der Defaultwert in FORMAT-EXPONENTIAL-FLOAT ist k=1.)
  1134. ; Vor der Mantisse das Vorzeichen (ein + nur falls arg>=0 und plus-sign-flag).
  1135. ; Dann der Exponent, eingeleitet durch exponentchar, dann Vorzeichen des
  1136. ; Exponenten (stets + oder -), dann e Stellen für den Exponenten.
  1137. ; Dann wird das Ganze mit padchars auf w Zeichen Breite aufgefüllt.
  1138. ; Sollte das (auch nach evtl. Unterdrückung einer führenden Null) mehr als
  1139. ; w Zeichen ergeben, so werden statt dessen w overflowchars ausgegeben, oder
  1140. ; (falls overflowchar = nil) die Zahl mit so vielen Stellen wie nötig
  1141. ; ausgegeben.
  1142. (defun format-float-for-e (w d e k
  1143.        overflowchar padchar exponentchar plus-sign-flag arg stream)
  1144.   (multiple-value-bind (mantissa oldexponent) (format-scale-exponent (abs arg))
  1145.     (let* ((exponent (if (zerop arg) 0 (- oldexponent k))) ; auszugebender Exponent
  1146.            (expdigits (write-to-string (abs exponent) :base 10. :radix nil :readably nil))
  1147.            (expdigitsneed (if e (max (length expdigits) e) (length expdigits)))
  1148.            ; expdigitsneed = Anzahl der Stellen, die für die Ziffern des
  1149.            ; Exponenten nötig sind.
  1150.            (mantd (if d (if (> k 0) (1+ (- d k)) d) nil))
  1151.            ; mantd = Anzahl der Mantissenstellen hinter dem Punkt
  1152.            (dmin (if (minusp k) (- 1 k) nil)) ; nachher: fordere, daß
  1153.            ; nicht in die ersten (+ 1 (abs k)) Stellen hineingerundet wird.
  1154.            (mantwidth (if w (- w 2 expdigitsneed) nil))
  1155.            ; mantwidth = Anzahl der für die Mantisse (inkl. Vorzeichen, Punkt)
  1156.            ; zur Verfügung stehenden Zeichen (oder nil)
  1157.           )
  1158.       (declare (simple-string expdigits) (fixnum exponent expdigitsneed))
  1159.       (if (and overflowchar w e (> expdigitsneed e))
  1160.         ; Falls Overflowchar und w und e angegeben, Exponent mehr braucht:
  1161.         (format-padding w overflowchar stream)
  1162.         (progn
  1163.           (if w
  1164.             (if (or plus-sign-flag (minusp arg)) (setq mantwidth (1- mantwidth)))
  1165.           )
  1166.           ; mantwidth = Anzahl der für die Mantisse (ohne Vorzeichen,
  1167.           ; inklusive Punkt) zur Verfügung stehenden Zeichen (oder nil)
  1168.           (multiple-value-bind (mantdigits mantdigitslength
  1169.                                 leadingpoint trailingpoint)
  1170.               (format-float-to-string mantissa mantwidth mantd k dmin)
  1171.             (when w
  1172.               (setq mantwidth (- mantwidth mantdigitslength))
  1173.               (if trailingpoint
  1174.                 (if (or (null mantd) (> mantd 0))
  1175.                   (setq mantwidth (- mantwidth 1))
  1176.                   (setq trailingpoint nil)
  1177.               ) )
  1178.               (if leadingpoint
  1179.                 (if (> mantwidth 0)
  1180.                   (setq mantwidth (- mantwidth 1))
  1181.                   (setq leadingpoint nil)
  1182.               ) )
  1183.             )
  1184.             ; Es bleiben noch mantwidth Zeichen übrig.
  1185.             (if (and overflowchar w (minusp mantwidth))
  1186.               (format-padding w overflowchar stream) ; Zu wenig Platz -> overflow
  1187.               (progn
  1188.                 (when (and w (> mantwidth 0))
  1189.                   (format-padding mantwidth padchar stream)
  1190.                 )
  1191.                 (if (minusp arg)
  1192.                   (write-char #\- stream)
  1193.                   (if plus-sign-flag (write-char #\+ stream))
  1194.                 )
  1195.                 (if leadingpoint (write-char #\0 stream))
  1196.                 (write-string mantdigits stream)
  1197.                 (if trailingpoint (write-char #\0 stream))
  1198.                 (write-char
  1199.                   (cond (exponentchar)
  1200.                         ((and (not *PRINT-READABLY*)
  1201.                               (typep arg *READ-DEFAULT-FLOAT-FORMAT*)
  1202.                          )
  1203.                          #\E
  1204.                         )
  1205.                         ((short-float-p arg) #\s)
  1206.                         ((single-float-p arg) #\f)
  1207.                         ((double-float-p arg) #\d)
  1208.                         ((long-float-p arg) #\L)
  1209.                   )
  1210.                   stream
  1211.                 )
  1212.                 (write-char (if (minusp exponent) #\- #\+) stream)
  1213.                 (when (and e (> e (length expdigits)))
  1214.                   (format-padding (- e (length expdigits)) #\0 stream)
  1215.                 )
  1216.                 (write-string expdigits stream)
  1217.           ) ) )
  1218.     ) ) )
  1219. ) )
  1220.  
  1221. ; Rückt *FORMAT-CSDL* vor bis zum Ende des momentanen ~[ bzw. ~{ bzw. ~< .
  1222. (defun format-skip-to-end ()
  1223.   (do ()
  1224.       ((null (csd-clause-chain (car *FORMAT-CSDL*))))
  1225.     (setq *FORMAT-CSDL* (csd-clause-chain (car *FORMAT-CSDL*)))
  1226. ) )
  1227.  
  1228. ; (format-justified-segments mincol colinc minpad justify-left justify-right
  1229. ;   piecelist) berechnet, an welchen Stellen zwischen den einzelnen Strings in
  1230. ; piecelist wieviele Leerstellen zu setzen sind.
  1231. ; Zwischen die einzelnen Strings aus piecelist (auch vorher, falls justify-left;
  1232. ; auch nachher, falls justify-right) werden mindestens minpad padding-characters
  1233. ; eingefügt. Dann werden nochmals weitere padding-characters dazugenommen,
  1234. ; damit die Gesamtbreite >= mincol wird. Ist die Breite > mincol, werden weitere
  1235. ; padding-characters dazugenommen, so daß die Breite von der Form
  1236. ; mincol + k * colinc wird. Diese padding-characters werden auf die einzelnen
  1237. ; Stellen gleichmäßig verteilt.
  1238. ; 1. Wert: Ein Vektor, der zu jeder Stelle angibt, wieviele padding-characters
  1239. ; einzufügen sind (NIL = keine).
  1240. ; Erstes Element: ganz links, zweites: nach 1. String, ..., letztes: rechts.
  1241. ; 2. Wert: Die sich ergebende Gesamtbreite.
  1242. (defun format-justified-segments
  1243.        (mincol colinc minpad justify-left justify-right piecelist)
  1244.   (declare (fixnum mincol colinc minpad))
  1245.   (let ((piecesnumber 0)
  1246.         (pieceswidth 0))
  1247.     (dolist (piece piecelist)
  1248.       (declare (simple-string piece))
  1249.       (incf piecesnumber)
  1250.       (incf pieceswidth (length piece))
  1251.     )
  1252.     (let* ((new-justify-left
  1253.              (or justify-left (and (= piecesnumber 1) (not justify-right))))
  1254.            (padblocks (+ piecesnumber -1       ; Anzahl der Einfüge-Stellen
  1255.                          (if new-justify-left 1 0) (if justify-right 1 0)
  1256.            )          )
  1257.            (width-need (+ pieceswidth (* padblocks minpad)))
  1258.            (width (+ mincol
  1259.                      (if (<= width-need mincol)
  1260.                          0
  1261.                          (* (ceiling (- width-need mincol) colinc) colinc)
  1262.           ))      )  )
  1263.       (declare (fixnum piecesnumber pieceswidth padblocks width-need width))
  1264.       (multiple-value-bind (padwidth rest) (floor (- width pieceswidth) padblocks)
  1265.         (let ((padblock-lengths
  1266.                 (make-array (1+ piecesnumber) :initial-element padwidth)
  1267.              ))
  1268.           (unless new-justify-left (setf (svref padblock-lengths 0) nil))
  1269.           (unless justify-right (setf (svref padblock-lengths piecesnumber) nil))
  1270.           (do ((i 0 (1+ i)))
  1271.               ((zerop rest))
  1272.             (when (svref padblock-lengths i)
  1273.               (incf (svref padblock-lengths i))
  1274.               (decf rest)
  1275.           ) )
  1276.           (values padblock-lengths width)
  1277. ) ) ) ) )
  1278.  
  1279. ;-------------------------------------------------------------------------------
  1280.  
  1281. ; ~A, CLTL S.387-388, CLtL2 S. 584
  1282. (defformat-simple format-ascii (stream colon-modifier atsign-modifier
  1283.                   (mincol 0) (colinc 1) (minpad 0) (padchar #\Space))
  1284.                   (arg)
  1285.   (when (and colon-modifier (null arg)) (setq arg "()"))
  1286.   (if (and (zerop mincol) (zerop minpad))
  1287.     (princ arg stream)
  1288.     (format-padded-string mincol colinc minpad padchar
  1289.       atsign-modifier ; =: padleftflag
  1290.       (princ-to-string arg)
  1291.       stream
  1292. ) ) )
  1293.  
  1294. ; ~S, CLTL S.388, CLtL2 S. 584
  1295. (defformat-simple format-s-expression (stream colon-modifier atsign-modifier
  1296.                   (mincol 0) (colinc 1) (minpad 0) (padchar #\Space))
  1297.                   (arg)
  1298.   (if (and (zerop mincol) (zerop minpad))
  1299.     (if (and colon-modifier (null arg))
  1300.       (write-string "()" stream)
  1301.       (prin1 arg stream)
  1302.     )
  1303.     (format-padded-string mincol colinc minpad padchar
  1304.       atsign-modifier ; =: padleftflag
  1305.       (if (and colon-modifier (null arg)) "()" (prin1-to-string arg))
  1306.       stream
  1307. ) ) )
  1308.  
  1309. ; ~W
  1310. (defformat-simple format-write (stream colon-modifier atsign-modifier
  1311.                   (mincol 0) (colinc 1) (minpad 0) (padchar #\Space))
  1312.                   (arg)
  1313.   (declare (ignore colon-modifier))
  1314.   (if (and (zerop mincol) (zerop minpad))
  1315.     (write arg :stream stream)
  1316.     (format-padded-string mincol colinc minpad padchar
  1317.       atsign-modifier ; =: padleftflag
  1318.       (write-to-string arg)
  1319.       stream
  1320. ) ) )
  1321.  
  1322. ; ~D, CLTL S.388, CLtL2 S. 585
  1323. (defformat-simple format-decimal (stream colon-modifier atsign-modifier
  1324.                   (mincol 0) (padchar #\Space) (commachar #\,) (commainterval 3))
  1325.                   (arg)
  1326.   (format-base 10 stream colon-modifier atsign-modifier mincol padchar commachar commainterval arg)
  1327. )
  1328.  
  1329. ; ~B, CLTL S.388, CLtL2 S. 585
  1330. (defformat-simple format-binary (stream colon-modifier atsign-modifier
  1331.                   (mincol 0) (padchar #\Space) (commachar #\,) (commainterval 3))
  1332.                   (arg)
  1333.   (format-base 2 stream colon-modifier atsign-modifier mincol padchar commachar commainterval arg)
  1334. )
  1335.  
  1336. ; ~O, CLTL S.388, CLtL2 S. 585
  1337. (defformat-simple format-octal (stream colon-modifier atsign-modifier
  1338.                   (mincol 0) (padchar #\Space) (commachar #\,) (commainterval 3))
  1339.                   (arg)
  1340.   (format-base 8 stream colon-modifier atsign-modifier mincol padchar commachar commainterval arg)
  1341. )
  1342.  
  1343. ; ~X, CLTL S.388-389, CLtL2 S. 586
  1344. (defformat-simple format-hexadecimal (stream colon-modifier atsign-modifier
  1345.                   (mincol 0) (padchar #\Space) (commachar #\,) (commainterval 3))
  1346.                   (arg)
  1347.   (format-base 16 stream colon-modifier atsign-modifier mincol padchar commachar commainterval arg)
  1348. )
  1349.  
  1350. ; ~R, CLTL S.389, CLtL2 S. 586-587
  1351. (defformat-simple format-radix (stream colon-modifier atsign-modifier
  1352.                   (radix nil) (mincol 0) (padchar #\Space) (commachar #\,) (commainterval 3))
  1353.                   (arg)
  1354.   (if radix
  1355.     (format-integer radix mincol padchar commachar commainterval
  1356.                     colon-modifier atsign-modifier
  1357.                     arg stream
  1358.     )
  1359.     (if atsign-modifier
  1360.       (if (integerp arg)
  1361.         (if colon-modifier
  1362.           (format-old-roman arg stream)
  1363.           (format-new-roman arg stream)
  1364.         )
  1365.         (format-error *FORMAT-CS* nil
  1366.           #L{
  1367.           DEUTSCH "Die ~~R- und ~~:R-Direktiven erwarten ein Integer als Argument, nicht ~S"
  1368.           ENGLISH "The ~~R and ~~:R directives require an integer argument, not ~S"
  1369.           FRANCAIS "Les directives ~~R et ~~:R nécessitent un argument de type entier et non ~S"
  1370.           }
  1371.           arg
  1372.       ) )
  1373.       (if colon-modifier
  1374.         (format-ordinal arg stream)
  1375.         (format-cardinal arg stream)
  1376. ) ) ) )
  1377.  
  1378. ; ~P, CLTL S. 389, CLtL2 S. 587-588
  1379. (defun format-plural (stream colon-modifier atsign-modifier)
  1380.   (when colon-modifier (format-goto-new-arg t 1))
  1381.   (let ((singular (eql (next-arg) 1)))
  1382.     (if atsign-modifier
  1383.       (write-string (if singular "y" "ies") stream)
  1384.       (unless singular (write-char #\s stream))
  1385. ) ) )
  1386.  
  1387. ; ~C, CLTL S.389-390, CLtL2 S. 588
  1388. (defformat-simple format-character (stream colon-modifier atsign-modifier)
  1389.                   (arg)
  1390.   (unless (characterp arg)
  1391.     (format-error *FORMAT-CS* nil
  1392.       #L{
  1393.       DEUTSCH "Die ~~C-Direktive erwartet ein Character, nicht ~S"
  1394.       ENGLISH "The ~~C directive requires a character argument, not ~S"
  1395.       FRANCAIS "La directive ~~C requiert un caractère et non ~S"
  1396.       }
  1397.       arg
  1398.   ) )
  1399.   (flet ((write-charname (arg)
  1400.            (let ((name (char-name arg)))
  1401.              (if name
  1402.                (write-string (string-capitalize name) stream)
  1403.                (write-char arg stream)
  1404.         )) ) )
  1405.     (if (not atsign-modifier)
  1406.       ; ~C oder ~:C
  1407.       (progn
  1408.         (dolist (name '(:CONTROL :META :SUPER :HYPER))
  1409.           (when (char-bit arg name)
  1410.             (write-string (string-capitalize (symbol-name name)) stream
  1411.                           :end (if colon-modifier nil 1)
  1412.             )
  1413.             (write-char #\- stream)
  1414.         ) )
  1415.         (if (not colon-modifier)
  1416.           ; ~C
  1417.           (write-char (make-char arg 0 (char-font arg)) stream)
  1418.           ; ~:C
  1419.           (write-charname (make-char arg))
  1420.       ) )
  1421.       (if (not colon-modifier)
  1422.         ; ~@C
  1423.         (prin1 arg stream)
  1424.         ; ~:@C -- hier NUR die Anweisung, wie's zu tippen ist.
  1425.         (progn
  1426.           (let ((keynames '("Shift-" "Control-" "Alternate-")))
  1427.             (dolist (name '(:SUPER :CONTROL :META))
  1428.               (when (char-bit arg name)
  1429.                 (write-string (car keynames) stream)
  1430.                 (setq arg (set-char-bit arg name nil))
  1431.               )
  1432.               (setq keynames (cdr keynames))
  1433.           ) )
  1434.           (let* ((hyperkey-alist
  1435.                    #+(or DOS OS/2 UNIX AMIGA WIN32-DOS WIN32-UNIX)
  1436.                    '(
  1437. #-(or UNIX AMIGA WIN32-UNIX) (#\Enter  . "Enter" )
  1438.               #-AMIGA (#\Insert . "Insert")
  1439.               #-AMIGA (#\End    . "End"   )
  1440.                       (#\Down   . "Down")
  1441.               #-AMIGA (#\PgDn   . "PgDn"  )
  1442.                       (#\Left   . "Left")
  1443.                #+UNIX (#\Center . "Center")
  1444.                       (#\Right  . "Right")
  1445.               #-AMIGA (#\Home   . "Home")
  1446.                       (#\Up     . "Up")
  1447.               #-AMIGA (#\PgUp   . "PgUp"  )
  1448.               #+AMIGA (#\Help   . "Help"  )
  1449.              #+(or DOS OS/2) (#\Prtscr . "PrtScr")
  1450.     #-(or UNIX AMIGA) (#\Delete . "Delete")
  1451.                       (#\F1     . "F1"    )
  1452.                       (#\F2     . "F2"    )
  1453.                       (#\F3     . "F3"    )
  1454.                       (#\F4     . "F4"    )
  1455.                       (#\F5     . "F5"    )
  1456.                       (#\F6     . "F6"    )
  1457.                       (#\F7     . "F7"    )
  1458.                       (#\F8     . "F8"    )
  1459.                       (#\F9     . "F9"    )
  1460.                       (#\F10    . "F10"   )
  1461.               #-AMIGA (#\F11    . "F11"   )
  1462.               #-AMIGA (#\F12    . "F12"   )
  1463.                     )
  1464.                    #-(or DOS OS/2 UNIX AMIGA WIN32-DOS WIN32-UNIX)
  1465.                    '()
  1466.                  )
  1467.                  (acons (assoc arg hyperkey-alist)))
  1468.             (if acons
  1469.               (write-string (cdr acons) stream)
  1470.               (progn
  1471.                 (when (char-bit arg ':HYPER)
  1472.                   (write-string
  1473.                    #L{
  1474.                    DEUTSCH "Ziffernblock-"
  1475.                    ENGLISH "Keypad-"
  1476.                    FRANCAIS "bloc numérique "
  1477.                    }
  1478.                    stream
  1479.                   )
  1480.                   (setq arg (set-char-bit arg :HYPER nil))
  1481.                 )
  1482.                 (write-charname arg)
  1483.         ) ) ) )
  1484. ) ) ) )
  1485.  
  1486. ; ~F, CLTL S.390-392, CLtL2 S. 588-590
  1487. (defformat-simple format-fixed-float (stream colon-modifier atsign-modifier
  1488.                   (w nil) (d nil) (k 0) (overflowchar nil) (padchar #\Space))
  1489.                   (arg)
  1490.   (declare (ignore colon-modifier))
  1491.   (when (rationalp arg) (setq arg (float arg)))
  1492.   (if (floatp arg)
  1493.     (format-float-for-f w d k overflowchar padchar atsign-modifier arg stream)
  1494.     (format-ascii-decimal arg stream)
  1495. ) )
  1496.  
  1497. ; ~E, CLTL S.392-395, CLtL2 S. 590-593
  1498. (defformat-simple format-exponential-float (stream colon-modifier atsign-modifier
  1499.                   (w nil) (d nil) (e nil) (k 1)
  1500.                   (overflowchar nil) (padchar #\Space) (exponentchar nil))
  1501.                   (arg)
  1502.   (declare (ignore colon-modifier))
  1503.   (when (rationalp arg) (setq arg (float arg)))
  1504.   (if (floatp arg)
  1505.     (format-float-for-e w d e k overflowchar padchar exponentchar
  1506.                         atsign-modifier arg stream
  1507.     )
  1508.     (format-ascii-decimal arg stream)
  1509. ) )
  1510.  
  1511. ; ~G, CLTL S.395-396, CLtL2 S. 594-595
  1512. (defformat-simple format-general-float (stream colon-modifier atsign-modifier
  1513.                   (w nil) (d nil) (e nil) (k 1)
  1514.                   (overflowchar nil) (padchar #\Space) (exponentchar nil))
  1515.                   (arg)
  1516.   (declare (ignore colon-modifier))
  1517.   (if (rationalp arg) (setq arg (float arg)))
  1518.   (if (floatp arg)
  1519.     (multiple-value-bind (mantissa n) (format-scale-exponent (abs arg))
  1520.       (declare (ignore mantissa))
  1521.       (if (null d)
  1522.         (setq d
  1523.           (multiple-value-bind (digits digitslength)
  1524.             (format-float-to-string (abs arg) nil nil nil nil)
  1525.             (declare (ignore digits))
  1526.             (max (max (1- digitslength) 1) (min n 7))
  1527.       ) ) )
  1528.       (let* ((ee (if e (+ 2 e) 4))
  1529.              (dd (- d n)))
  1530.         (if (<= 0 dd d)
  1531.           (progn
  1532.             (format-float-for-f
  1533.               (if w (- w ee) nil)
  1534.               dd 0
  1535.               overflowchar padchar atsign-modifier arg stream
  1536.             )
  1537.             (format-padding ee #\Space stream)
  1538.           )
  1539.           (format-float-for-e w d e k overflowchar padchar exponentchar
  1540.                               atsign-modifier arg stream
  1541.     ) ) ) )
  1542.     (format-ascii-decimal arg stream)
  1543. ) )
  1544.  
  1545. ; ~$, CLTL S.396-397, CLtL2 S. 595-596
  1546. (defformat-simple format-dollars-float (stream colon-modifier atsign-modifier
  1547.                   (d 2) (n 1) (w 0) (padchar #\Space))
  1548.                   (arg)
  1549.   (when (rationalp arg) (setq arg (float arg)))
  1550.   (if (floatp arg)
  1551.     (multiple-value-bind (digits digitslength
  1552.                           leadingpoint trailingpoint leadings)
  1553.       (format-float-to-string arg nil d 0 nil)
  1554.       (declare (ignore digitslength leadingpoint trailingpoint))
  1555.       (let* ((lefts (max leadings n))
  1556.              (totalwidth (+ (if (or atsign-modifier (minusp arg)) 1 0)
  1557.                             lefts 1 d
  1558.              )           )
  1559.              (padcount (max (- w totalwidth) 0)))
  1560.         (if (not colon-modifier) (format-padding padcount padchar stream))
  1561.         (if (minusp arg)
  1562.           (write-char #\- stream)
  1563.           (if atsign-modifier (write-char #\+ stream))
  1564.         )
  1565.         (if colon-modifier (format-padding padcount padchar stream))
  1566.         (format-padding (- lefts leadings) #\0 stream)
  1567.         (write-string digits stream)
  1568.     ) )
  1569.     (format-ascii-decimal arg stream)
  1570. ) )
  1571.  
  1572. ; ~%, CLTL S.397, CLtL2 S. 596
  1573. (defun format-terpri (stream colon-modifier atsign-modifier &optional (count 1))
  1574.   (declare (ignore colon-modifier atsign-modifier))
  1575.   (if (null count) (setq count 1))
  1576.   (dotimes (i count) (terpri stream))
  1577. )
  1578.  
  1579. ; ~&, CLTL S.397, CLtL2 S. 596
  1580. (defun format-fresh-line (stream colon-modifier atsign-modifier
  1581.                           &optional (count 1))
  1582.   (declare (ignore colon-modifier atsign-modifier))
  1583.   (if (null count) (setq count 1))
  1584.   (when (plusp count)
  1585.     (fresh-line stream)
  1586.     (dotimes (i (1- count)) (terpri stream))
  1587. ) )
  1588.  
  1589. ; ~|, CLTL S.397, CLtL2 S. 596
  1590. (defun format-page (stream colon-modifier atsign-modifier &optional (count 1))
  1591.   (declare (ignore colon-modifier atsign-modifier))
  1592.   (if (null count) (setq count 1))
  1593.   (dotimes (i count) (write-char #\Page stream))
  1594. )
  1595.  
  1596. ; ~~, CLTL S.397, CLtL2 S. 596
  1597. (defun format-tilde (stream colon-modifier atsign-modifier &optional (count 1))
  1598.   (declare (ignore colon-modifier atsign-modifier))
  1599.   (if (null count) (setq count 1))
  1600.   (dotimes (i count) (write-char #\~ stream))
  1601. )
  1602.  
  1603. ; ~T, CLTL S.398-399, CLtL2 S. 597-598
  1604. (defun format-tabulate (stream colon-modifier atsign-modifier
  1605.                         &optional (colnum 1) (colinc 1))
  1606.   (declare (ignore colon-modifier))
  1607.   (if (null colnum) (setq colnum 1))
  1608.   (if (null colinc) (setq colinc 1))
  1609.   (let* ((new-colnum (max colnum 0))
  1610.          (new-colinc (max colinc 1)) ; >0
  1611.          (pos (sys::line-position stream))) ; aktuelle Position, Fixnum >=0
  1612.     (if atsign-modifier
  1613.       (format-padding
  1614.         (+ new-colnum (mod (- (+ pos new-colnum)) new-colinc))
  1615.         #\Space stream
  1616.       )
  1617.       (if (< pos new-colnum)
  1618.         (format-padding (- new-colnum pos) #\Space stream)
  1619.         (unless (zerop colinc)
  1620.           (format-padding (+ colinc (mod (- new-colnum pos) (- colinc)))
  1621.                           #\Space stream
  1622. ) ) ) ) ) )
  1623.  
  1624. ; ~*, CLTL S.399, CLtL2 S. 598
  1625. (defun format-goto (stream colon-modifier atsign-modifier &optional (index nil))
  1626.   (declare (ignore stream))
  1627.   (if atsign-modifier
  1628.     (setq *FORMAT-NEXT-ARG* (nthcdr (or index 0) *FORMAT-ARG-LIST*))
  1629.     (format-goto-new-arg colon-modifier (or index 1))
  1630. ) )
  1631.  
  1632. ; ~?, CLTL S.399-401, CLtL2 S. 598-599
  1633. (defun format-indirection (stream colon-modifier atsign-modifier)
  1634.   (declare (ignore colon-modifier))
  1635.   (let* ((csarg (next-arg))
  1636.          (node (do-format-indirection-1 csarg)))
  1637.     (if atsign-modifier
  1638.       (if (consp node)
  1639.         (let ((*FORMAT-CS* (car node))
  1640.               (*FORMAT-CSDL* (cdr node))
  1641.              ;(*FORMAT-ARG-LIST* *FORMAT-NEXT-ARG*) ; ??
  1642.               (*FORMAT-UP-AND-OUT* nil))
  1643.           (format-interpret stream)
  1644.         )
  1645.         (setq *FORMAT-NEXT-ARG*
  1646.           (let ((*FORMAT-CS* nil))
  1647.             (apply node stream *FORMAT-NEXT-ARG*)
  1648.       ) ) )
  1649.       (let ((arglistarg (next-arg)))
  1650.         (do-format-indirection-2 stream node arglistarg arglistarg)
  1651. ) ) ) )
  1652. (defun do-format-indirection (stream csarg arguments)
  1653.   (unless (or (stringp csarg) (functionp csarg))
  1654.     (format-indirection-cserror csarg)
  1655.   )
  1656.   (unless (listp arguments) (format-indirection-lerror arguments))
  1657.   (format-apply stream csarg arguments)
  1658. )
  1659. (defun do-format-indirection-1 (csarg)
  1660.   (cond ((stringp csarg)
  1661.          (let ((node (list csarg)))
  1662.            (format-parse-cs csarg 0 node nil)
  1663.            node
  1664.         ))
  1665.         ((functionp csarg)
  1666.          csarg
  1667.         )
  1668.         (t (format-indirection-cserror csarg))
  1669. ) )
  1670. (defun do-format-indirection-2 (stream node arglistarg wholelistarg)
  1671.   (unless (listp arglistarg) (format-indirection-lerror arglistarg))
  1672.   (if (consp node)
  1673.     (let* ((*FORMAT-CS*         (car node))
  1674.            (*FORMAT-CSDL*       (cdr node))
  1675.            (*FORMAT-ARG-LIST*   wholelistarg)
  1676.            (*FORMAT-NEXT-ARG*   arglistarg)
  1677.            (*FORMAT-NEXT-ARGLIST* nil)
  1678.            (*FORMAT-UP-AND-OUT* nil))
  1679.       (format-interpret stream)
  1680.       *FORMAT-NEXT-ARG*
  1681.     )
  1682.     (let ((*FORMAT-CS* nil))
  1683.       (apply node stream arglistarg) ; wholelistarg??
  1684. ) ) )
  1685. (defun format-indirection-cserror (csarg)
  1686.   (format-error *FORMAT-CS* nil
  1687.     #L{
  1688.     DEUTSCH "Als Kontrollstring für ~~? ist das untauglich: ~S"
  1689.     ENGLISH "The control string argument for the ~~? directive is invalid: ~S"
  1690.     FRANCAIS "~S ne convient pas comme chaîne de contrôle pour ~~?."
  1691.     }
  1692.     csarg
  1693. ) )
  1694. (defun format-indirection-lerror (arguments)
  1695.   (format-error *FORMAT-CS* nil
  1696.     #L{
  1697.     DEUTSCH "Das ist keine passende Argumentliste für die ~~?-Direktive: ~S"
  1698.     ENGLISH "The argument list argument for the ~~? directive is invalid: ~S"
  1699.     FRANCAIS "Ceci n'est pas une liste d'arguments convenable pour la directive ~~? : ~S"
  1700.     }
  1701.     arguments
  1702. ) )
  1703.  
  1704. ; ~(, CLTL S.401, CLtL2 S. 600-601
  1705. (defun format-case-conversion (stream colon-modifier atsign-modifier)
  1706.   (setq *FORMAT-CSDL* (cdr *FORMAT-CSDL*))
  1707.   (let ((tempstr
  1708.           (let ((tempstream (make-string-output-stream (sys::line-position stream))))
  1709.             (format-interpret tempstream 'FORMAT-CASE-CONVERSION-END)
  1710.             ; Was bewirkt UP-AND-OUT in ~{...~(...~^...~)...~} ??
  1711.             (get-output-stream-string tempstream)
  1712.        )) )
  1713.     (if colon-modifier
  1714.       (if atsign-modifier
  1715.         (write-string (nstring-upcase tempstr) stream)
  1716.         (write-string (nstring-capitalize tempstr) stream)
  1717.       )
  1718.       (if atsign-modifier
  1719.         (write-string (nstring-capitalize1 tempstr) stream)
  1720.         (write-string (nstring-downcase tempstr) stream)
  1721. ) ) ) )
  1722. (defun nstring-capitalize1 (string)
  1723.   (setq string (nstring-downcase string))
  1724.   (dotimes (i (length string)) ; erstes Zeichen zum Upcase machen
  1725.     (when (both-case-p (schar string i))
  1726.       (setf (schar string i) (char-upcase (schar string i)))
  1727.       (return)
  1728.   ) )
  1729.   string
  1730. )
  1731.  
  1732. ; ~[, CLTL S.402-403, CLtL2 S. 601-602
  1733. (defun format-conditional (stream colon-modifier atsign-modifier
  1734.                            &optional (prefix nil))
  1735.   (if colon-modifier
  1736.     (if atsign-modifier
  1737.       (format-conditional-error)
  1738.       (progn
  1739.         (when (next-arg)
  1740.           (setq *FORMAT-CSDL* (csd-clause-chain (car *FORMAT-CSDL*)))
  1741.         )
  1742.         (setq *FORMAT-CSDL* (cdr *FORMAT-CSDL*))
  1743.         (format-interpret stream 'FORMAT-CONDITIONAL-END)
  1744.       )
  1745.     )
  1746.     (if atsign-modifier
  1747.       (when (next-arg)
  1748.         (format-goto-new-arg t 1)
  1749.         (setq *FORMAT-CSDL* (cdr *FORMAT-CSDL*))
  1750.         (format-interpret stream 'FORMAT-CONDITIONAL-END)
  1751.         (unless (null (csd-clause-chain (car *FORMAT-CSDL*)))
  1752.           (format-error *FORMAT-CS* nil
  1753.             #L{
  1754.             DEUTSCH "Hier ist keine ~~;-Direktive möglich."
  1755.             ENGLISH "The ~~; directive is not allowed at this point."
  1756.             FRANCAIS "La directive ~~; n'est pas permise ici."
  1757.             }
  1758.       ) ) )
  1759.       (let ((index (or prefix (next-arg))))
  1760.         (unless (integerp index)
  1761.           (format-error *FORMAT-CS* nil
  1762.             #L{
  1763.             DEUTSCH "Argument für ~~[ muß ein Integer sein, nicht ~S"
  1764.             ENGLISH "The ~~[ parameter must be an integer, not ~S"
  1765.             FRANCAIS "L'argument pour ~~[ doit être un entier et non ~S"
  1766.             }
  1767.             index
  1768.         ) )
  1769.         (dotimes (i (if (minusp index) most-positive-fixnum index))
  1770.           (when (eq (csd-data (car *FORMAT-CSDL*)) 'FORMAT-CONDITIONAL-END)
  1771.             (return)
  1772.           )
  1773.           (setq *FORMAT-CSDL* (csd-clause-chain (car *FORMAT-CSDL*)))
  1774.           (when (csd-colon-p (car *FORMAT-CSDL*)) (return))
  1775.         )
  1776.         (unless (eq (csd-data (car *FORMAT-CSDL*)) 'FORMAT-CONDITIONAL-END)
  1777.           (setq *FORMAT-CSDL* (cdr *FORMAT-CSDL*))
  1778.         )
  1779.         (format-interpret stream 'FORMAT-CONDITIONAL-END)
  1780.   ) ) )
  1781.   (format-skip-to-end) ; Weiterrücken bis ans Ende der ~[...~]-Direktive
  1782. )
  1783. (defun format-conditional-error ()
  1784.   (format-error *FORMAT-CS* nil
  1785.     #L{
  1786.     DEUTSCH "~~[ geht nicht mit : und @ gleichzeitig."
  1787.     ENGLISH "The ~~[ directive cannot take both modifiers."
  1788.     FRANCAIS "La directive ~~[ ne peut pas accepter les deux qualificateurs : et @ en même temps."
  1789.     }
  1790. ) )
  1791.  
  1792. ; ~{, CLTL S.403-404, CLtL2 S. 602-604
  1793. (defun format-iteration (stream colon-modifier atsign-modifier
  1794.                          &optional (prefix nil))
  1795.   (let* ((total-csdl *FORMAT-CSDL*)
  1796.          (max-iteration-count prefix))
  1797.     (format-skip-to-end) ; Weiterrücken bis ans Ende der ~{...~}-Direktive
  1798.     (let* ((min-1-iteration (csd-colon-p (car *FORMAT-CSDL*)))
  1799.            (inner-cs (if (eq (cdr total-csdl) *FORMAT-CSDL*)
  1800.                        (next-arg)
  1801.                        *FORMAT-CS*
  1802.            )         )
  1803.            (inner-csdl (if (stringp inner-cs)
  1804.                          (if (eq (cdr total-csdl) *FORMAT-CSDL*)
  1805.                            (let ((node (list inner-cs)))
  1806.                              (format-parse-cs inner-cs 0 node nil)
  1807.                              (cdr node)
  1808.                            )
  1809.                            (cdr total-csdl)
  1810.            )           ) )
  1811.            (arg-list-rest (if (not atsign-modifier)
  1812.                             (let ((arg (next-arg)))
  1813.                               (unless (listp arg)
  1814.                                 (format-error *FORMAT-CS* nil
  1815.                                   #L{
  1816.                                   DEUTSCH "Das Argument zu ~~{ muß eine Liste sein, nicht ~S"
  1817.                                   ENGLISH "The ~~{ directive requires a list argument, not ~S"
  1818.                                   FRANCAIS "L'argument de ~~{ doit être une liste et non ~S"
  1819.                                   }
  1820.                                   arg
  1821.                               ) )
  1822.                               arg
  1823.           ))              ) )
  1824.       (do* ((iteration-count 0 (1+ iteration-count)))
  1825.            ((or (and max-iteration-count
  1826.                      (>= iteration-count max-iteration-count)
  1827.                 )
  1828.                 (let ((remaining (if atsign-modifier
  1829.                                    *FORMAT-NEXT-ARG*
  1830.                                    arg-list-rest
  1831.                      ))          )
  1832.                   (if min-1-iteration
  1833.                     (and (plusp iteration-count) (null remaining))
  1834.                     (null remaining)
  1835.            ))   ) )
  1836.         (if (stringp inner-cs)
  1837.           (if colon-modifier
  1838.             (let* ((*FORMAT-ARG-LIST*
  1839.                      (if atsign-modifier (next-arg) (pop arg-list-rest))
  1840.                    )
  1841.                    (*FORMAT-NEXT-ARGLIST* ; für ~:^
  1842.                      (if atsign-modifier *FORMAT-NEXT-ARG* arg-list-rest)
  1843.                    )
  1844.                    (*FORMAT-NEXT-ARG* *FORMAT-ARG-LIST*)
  1845.                    (*FORMAT-CS* inner-cs)
  1846.                    (*FORMAT-CSDL* inner-csdl)
  1847.                    (*FORMAT-UP-AND-OUT* nil))
  1848.               (format-interpret stream 'FORMAT-ITERATION-END)
  1849.               (when (eq *FORMAT-UP-AND-OUT* ':TERMINATE-ALL) (return))
  1850.             )
  1851.             (if atsign-modifier
  1852.               (let* (; CLtL2 S. 598: "When within a ~{ construct, the "goto" is
  1853.                      ; relative to the list of arguments being processed by the
  1854.                      ; iteration." Soll das heißen, daß man bei ~@{ zu Beginn
  1855.                      ; jeder Iteration *FORMAT-ARG-LIST* neu binden muß ??
  1856.                      ; (*FORMAT-ARG-LIST* *FORMAT-NEXT-ARG*) ??
  1857.                      (*FORMAT-CS* inner-cs)
  1858.                      (*FORMAT-CSDL* inner-csdl)
  1859.                      (*FORMAT-UP-AND-OUT* nil))
  1860.                 (format-interpret stream 'FORMAT-ITERATION-END)
  1861.                 (when (eq *FORMAT-UP-AND-OUT* ':TERMINATE-ALL) (return))
  1862.               )
  1863.               (let* ((*FORMAT-ARG-LIST* arg-list-rest)
  1864.                      (*FORMAT-NEXT-ARG* *FORMAT-ARG-LIST*)
  1865.                      (*FORMAT-CS* inner-cs)
  1866.                      (*FORMAT-CSDL* inner-csdl)
  1867.                      (*FORMAT-UP-AND-OUT* nil))
  1868.                 (format-interpret stream 'FORMAT-ITERATION-END)
  1869.                 (setq arg-list-rest *FORMAT-NEXT-ARG*)
  1870.                 (when (eq *FORMAT-UP-AND-OUT* ':TERMINATE-ALL) (return))
  1871.           ) ) )
  1872.           ; inner-cs may be a function in the ~{~} case
  1873.           (if (functionp inner-cs)
  1874.             (if colon-modifier
  1875.               (let* ((arglist (if atsign-modifier (next-arg) (pop arg-list-rest)))
  1876.                      (*FORMAT-CS* nil))
  1877.                 (apply inner-cs stream arglist)
  1878.               )
  1879.               (if atsign-modifier
  1880.                 (setq *FORMAT-NEXT-ARG*
  1881.                   (let ((*FORMAT-CS* nil))
  1882.                     (apply inner-cs stream *FORMAT-NEXT-ARG*)
  1883.                 ) )
  1884.                 (setq arg-list-rest
  1885.                   (let ((*FORMAT-CS* nil))
  1886.                     (apply inner-cs stream arg-list-rest)
  1887.             ) ) ) )
  1888.             (format-indirection-cserror inner-cs)
  1889. ) ) ) ) ) )
  1890.  
  1891. ; ~<, CLTL S.404-406, CLtL2 S. 604-605
  1892. (defun format-justification (stream colon-modifier atsign-modifier
  1893.        &optional (mincol 0) (colinc 1) (minpad 0) (padchar #\Space))
  1894.   (let* ((saved-csdl *FORMAT-CSDL*)
  1895.          (pos (sys::line-position stream))
  1896.          (tempstream (make-string-output-stream pos))
  1897.          (check-on-line-overflow nil)
  1898.          supplementary-need
  1899.          line-length
  1900.          (old-piecelist
  1901.            (let ((pieces nil))
  1902.              (do ((first-piece-flag t nil))
  1903.                  ((eq (csd-data (car *FORMAT-CSDL*)) 'FORMAT-JUSTIFICATION-END))
  1904.                (setq *FORMAT-CSDL* (cdr *FORMAT-CSDL*))
  1905.                (let ((*FORMAT-UP-AND-OUT* nil))
  1906.                  (format-interpret tempstream 'FORMAT-JUSTIFICATION-END)
  1907.                  (when (and first-piece-flag (eq (csd-data (car *FORMAT-CSDL*)) 'FORMAT-SEPARATOR))
  1908.                    (when (setq check-on-line-overflow (csd-colon-p (car *FORMAT-CSDL*)))
  1909.                      (multiple-value-setq (supplementary-need line-length)
  1910.                        (values-list (format-resolve-parms (car *FORMAT-CSDL*)))
  1911.                  ) ) )
  1912.                  (when *FORMAT-UP-AND-OUT*
  1913.                    (setq *FORMAT-CSDL* saved-csdl)
  1914.                    (format-skip-to-end)
  1915.                    (return)
  1916.                  )
  1917.                  (push (get-output-stream-string tempstream) pieces)
  1918.              ) )
  1919.              (nreverse pieces)
  1920.         )) )
  1921.     (do-format-justification stream colon-modifier atsign-modifier
  1922.                              mincol colinc minpad padchar
  1923.                              pos check-on-line-overflow
  1924.                              (if check-on-line-overflow (car old-piecelist))
  1925.                              supplementary-need line-length
  1926.                              (if check-on-line-overflow (cdr old-piecelist) old-piecelist)
  1927. ) ) )
  1928. (defun do-format-justification (stream colon-modifier atsign-modifier
  1929.                                 mincol colinc minpad padchar
  1930.                                 pos check-on-line-overflow firstpiece
  1931.                                 supplementary-need line-length piecelist)
  1932.   (if (null mincol) (setq mincol 0))
  1933.   (if (null colinc) (setq colinc 1))
  1934.   (if (null minpad) (setq minpad 0))
  1935.   (if (null padchar) (setq padchar #\Space))
  1936.   (if piecelist
  1937.     (multiple-value-bind (padblocklengths width)
  1938.       (format-justified-segments mincol colinc minpad
  1939.         colon-modifier atsign-modifier piecelist)
  1940.       (when (and check-on-line-overflow
  1941.                  (> (+ pos width (or supplementary-need 0))
  1942.                     (or line-length #|(sys::line-length stream)|# 72)
  1943.             )    )
  1944.         (write-string firstpiece stream)
  1945.       )
  1946.       (do ((i 0 (1+ i)))
  1947.           (nil)
  1948.         (when (svref padblocklengths i)
  1949.           (format-padding (svref padblocklengths i) padchar stream)
  1950.         )
  1951.         (when (null piecelist) (return))
  1952.         (write-string (pop piecelist) stream)
  1953.     ) )
  1954.     (format-padding mincol padchar stream)
  1955. ) )
  1956.  
  1957. ; ~^, CLTL S.406-407, CLtL2 S. 605-606
  1958. (defun format-up-and-out (stream colon-modifier atsign-modifier
  1959.                           &optional (a nil) (b nil) (c nil))
  1960.   (declare (ignore stream atsign-modifier))
  1961.   (if (up-and-out-p a b c
  1962.         (if colon-modifier *FORMAT-NEXT-ARGLIST* *FORMAT-NEXT-ARG*)
  1963.       )
  1964.     (setq *FORMAT-UP-AND-OUT* (if colon-modifier ':TERMINATE-ALL ':TERMINATE))
  1965. ) )
  1966. (defun up-and-out-p (a b c &optional args)
  1967.   (cond ((and (null a) (null b) (null c)) ; keine Parameter
  1968.          (null args)
  1969.         )
  1970.         ((and (null b) (null c)) (eql a 0)) ; ein Parameter
  1971.         ((null c) (eql a b)) ; zwei Parameter
  1972.         ((and (integerp a) (integerp b) (integerp c)) (<= a b c))
  1973.         ((and (characterp a) (characterp b) (characterp c)) (char<= a b c))
  1974. ) )
  1975.  
  1976. ;-------------------------------------------------------------------------------
  1977.  
  1978. ;; FORMATTER - Compilation von FORMAT-Strings.
  1979.  
  1980.  
  1981. ; Fall-back function if control-string cannot be compiled.
  1982. (defun formatter-hairy (control-string)
  1983.   ; control-string is known to be a string
  1984.   #'(lambda (stream &rest args)
  1985.       (let ((node (list control-string)))
  1986.         (format-parse-cs control-string 0 node nil)
  1987.         (let* ((*FORMAT-CS*         (car node))
  1988.                (*FORMAT-CSDL*       (cdr node))
  1989.                (*FORMAT-ARG-LIST*   args)
  1990.                (*FORMAT-NEXT-ARG*   *FORMAT-ARG-LIST*)
  1991.                (*FORMAT-NEXT-ARGLIST* nil)
  1992.                (*FORMAT-UP-AND-OUT* nil))
  1993.           (format-interpret stream)
  1994.           *FORMAT-NEXT-ARG*
  1995.     ) ) )
  1996. )
  1997.  
  1998.  
  1999. ; Block für ~^
  2000. (defvar *format-terminate*)
  2001. ; Block für ~:^
  2002. (defvar *format-terminate-all*)
  2003.  
  2004. ; Der Block wird nur bei Bedarf bereitgestellt.
  2005. ; Um unnötige UNWIND-PROTECTs zu vermeiden, wird eine Liste der anhängigen
  2006. ; UNWIND-PROTECTs geführt. Jeder Blockname (ein Gensym) enthält einen Verweis
  2007. ; auf diese Liste zum Zeitpunkt seiner Bildung.
  2008.  
  2009. ; Liste der anhängigen UNWIND-PROTECTs
  2010. (defvar *format-uwps*)
  2011.  
  2012. (defun formatter-block (prefix)
  2013.   (let ((sym (gensym prefix)))
  2014.     (setf (get sym 'uwps) *format-uwps*)
  2015.     sym
  2016. ) )
  2017.  
  2018. (flet ((mark-used (blockname)
  2019.          ; Markiere den Block, so daß er nicht wegoptimiert wird.
  2020.          (setf (get blockname 'used) t)
  2021.          ; Markiere alle übersprungenen UNWIND-PROTECTs, so daß sie nicht
  2022.          ; wegoptimiert werden.
  2023.          (do ((L1 *format-uwps* (cdr L1))
  2024.               (L2 (get blockname 'uwps)))
  2025.              ((eq L1 L2))
  2026.            (setf (car L1) 'T)
  2027.          )
  2028.          blockname
  2029.       ))
  2030.   (defun formatter-terminate ()
  2031.     (mark-used *format-terminate*)
  2032.   )
  2033.   (defun formatter-terminate-all ()
  2034.     (mark-used *format-terminate-all*)
  2035.   )
  2036. )
  2037.  
  2038. (defmacro formatter-bind-terminator (&body body)
  2039.   `(let ((*format-terminate* (formatter-block "TERMINATE-")))
  2040.      (formatter-bind-terminator-1 (progn ,@body))
  2041.    )
  2042. )
  2043. (defun formatter-bind-terminator-1 (forms)
  2044.   (when (get *format-terminate* 'used)
  2045.     (setq forms `((BLOCK ,*format-terminate* ,@forms)))
  2046.   )
  2047.   forms
  2048. )
  2049.  
  2050. (defmacro formatter-bind-terminators (&body body)
  2051.   `(let ((*format-terminate* (formatter-block "TERMINATE-"))
  2052.          (*format-terminate-all* (formatter-block "TERMINATE-ALL-")))
  2053.      (formatter-bind-terminators-1 (progn ,@body))
  2054.    )
  2055. )
  2056. (defun formatter-bind-terminators-1 (forms)
  2057.   (when (get *format-terminate* 'used)
  2058.     (setq forms `((BLOCK ,*format-terminate* ,@forms)))
  2059.   )
  2060.   (when (get *format-terminate-all* 'used)
  2061.     (setq forms `((BLOCK ,*format-terminate-all* ,@forms)))
  2062.   )
  2063.   forms
  2064. )
  2065.  
  2066.  
  2067. ; Flag, ob innerhalb von ~(...~)
  2068. (defvar *format-case*)
  2069.  
  2070.  
  2071. ; Wegen ~:^ kann die Argumentliste nicht immer denselben Namen ARGS haben.
  2072. ; Ihr Name.
  2073. (defvar *args*)
  2074.  
  2075. ; Name der Argumentliste der umschließenden ~:{ Iteration.
  2076. (defvar *iterargs*)
  2077.  
  2078.  
  2079. ; Zugriff auf die normale Argumentliste:
  2080. ; Normalfall:
  2081. ;   Argumentliste &REST ARGS,
  2082. ;   Zugriff auf das nächste Element ist (POP ARGS),
  2083. ;   ~# ist (LENGTH ARGS),
  2084. ;   Gesamtliste für ~:* ist WHOLE-ARGS.
  2085. ; Optimiert, falls kein (LENGTH ARGS) und kein WHOLE-ARGS nötig ist:
  2086. ;   Argumentliste #:ARG1 #:ARG2 ... &REST ARGS
  2087. ;   Zugriff auf das nächste Element ist #:ARGi oder (POP ARGS).
  2088.  
  2089. ; Flag, das anzeigt, ob man sich noch in der linearen Abarbeitungsphase der
  2090. ; Argumente befindet (jedes genau einmal, bekannte Position).
  2091. (defvar *formatter-linear-args*)
  2092.  
  2093. ; Anzahl der Argumente, die bisher zur linearen Abarbeitungsphase gehören.
  2094. ; Wichtig: Diese kann hinterher erniedrigt werden!!
  2095. (defvar *formatter-linear-argcount*)
  2096.  
  2097. ; Position in der Argumentliste während der linearen Abarbeitungsphase.
  2098. ; Stets <= *formatter-linear-argcount*.
  2099. (defvar *formatter-linear-position*)
  2100.  
  2101. ; Flag, ob WHOLE-ARGS gebunden werden soll.
  2102. (defvar *formatter-whole-args*)
  2103.  
  2104. ; Beginnt eine Iteration, die ARGS und evtl. WHOLE-ARGS bindet.
  2105. (defmacro formatter-bind-args (&body body)
  2106.   `(let ((*args* (gensym "ARGS"))
  2107.          (*formatter-linear-args* t)
  2108.          (*formatter-linear-argcount* 0)
  2109.          (*formatter-linear-position* 0)
  2110.          (*formatter-whole-args* nil))
  2111.      (formatter-bind-args-1 (progn ,@body))
  2112.    )
  2113. )
  2114. (defun formatter-bind-args-1 (forms)
  2115.   (when *formatter-whole-args*
  2116.     (subst-if-then #'(lambda (x) ; x = `(WHOLE-ARGS ,i)
  2117.                        (setq *formatter-linear-argcount*
  2118.                              (min *formatter-linear-argcount* (second x))
  2119.                      ) )
  2120.                    #'(lambda (x) ; x = `(WHOLE-ARGS ,i) ?
  2121.                        (and (consp x) (eq (car x) 'WHOLE-ARGS)
  2122.                             (consp (cdr x)) (numberp (cadr x)) (null (cddr x))
  2123.                      ) )
  2124.                    forms
  2125.   ) )
  2126.   (let ((argsyms nil))
  2127.     (dotimes (i *formatter-linear-argcount*) (push (gensym "ARG") argsyms))
  2128.     (setq argsyms (nreverse argsyms))
  2129.     (setq forms
  2130.       (subst-if-then #'(lambda (x) ; x = `(ARG ,i)
  2131.                          (if (< (second x) *formatter-linear-argcount*)
  2132.                            (nth (second x) argsyms)
  2133.                            `(POP ,*args*)
  2134.                        ) )
  2135.                      #'(lambda (x) ; x = `(ARG ,i) ?
  2136.                          (and (consp x) (eq (car x) 'ARG) (consp (cdr x)) (null (cddr x)))
  2137.                        )
  2138.                      forms
  2139.     ) )
  2140.     (setq forms
  2141.       (subst-if-then #'(lambda (x) ; x = `(SETQ-ARGS-WHOLE-ARGS ,old-pos ,new-pos)
  2142.                          (let ((old-pos (second x)) (new-pos (third x)))
  2143.                            (if (<= old-pos *formatter-linear-argcount*)
  2144.                              ; no need for WHOLE-ARGS since ARGS = WHOLE-ARGS at this point
  2145.                              (if (<= new-pos *formatter-linear-argcount*)
  2146.                                `(PROGN)
  2147.                                `(SETQ ,*args* (NTHCDR ,(- new-pos *formatter-linear-argcount*) ,*args*))
  2148.                              )
  2149.                              (progn
  2150.                                (setq *formatter-whole-args* t)
  2151.                                `(SETQ ,*args* (WHOLE-ARGS ,(max new-pos *formatter-linear-argcount*)))
  2152.                        ) ) ) )
  2153.                      #'(lambda (x) ; x = `(SETQ-ARGS-WHOLE-ARGS ,i ,j) ?
  2154.                          (and (consp x) (eq (car x) 'SETQ-ARGS-WHOLE-ARGS)
  2155.                               (consp (cdr x)) (consp (cddr x)) (null (cdddr x)))
  2156.                        )
  2157.                      forms
  2158.     ) )
  2159.     (when *formatter-whole-args*
  2160.       (setq forms
  2161.         (subst-if-then #'(lambda (x) ; x = `(WHOLE-ARGS ,i)
  2162.                            (let ((i (- (second x) *formatter-linear-argcount*)))
  2163.                              (if (zerop i)
  2164.                                `WHOLE-ARGS
  2165.                                `(NTHCDR ,i WHOLE-ARGS)
  2166.                          ) ) )
  2167.                        #'(lambda (x) ; x = `(WHOLE-ARGS ,i) ?
  2168.                            (and (consp x) (eq (car x) 'WHOLE-ARGS)
  2169.                                 (consp (cdr x)) (numberp (cadr x)) (null (cddr x))
  2170.                          ) )
  2171.                        forms
  2172.       ) )
  2173.       (setq forms `((LET ((WHOLE-ARGS ,*args*)) ,@forms)))
  2174.     )
  2175.     (values `(,@argsyms &REST ,*args*)
  2176.             `((DECLARE (IGNORABLE ,@argsyms ,*args*)) ,@forms)
  2177. ) ) )
  2178.  
  2179. ; Beendet den linearen Modus. Ab jetzt kann auf die Argumentliste
  2180. ; als ARGS zugegriffen werden.
  2181. (defun formatter-stop-linear ()
  2182.   (when *formatter-linear-args*
  2183.     (setq *formatter-linear-argcount*
  2184.           (min *formatter-linear-argcount* *formatter-linear-position*)
  2185.     )
  2186.     ; Jetzt ist *formatter-linear-argcount* = *formatter-linear-position*.
  2187.     (setq *formatter-linear-args* nil)
  2188. ) )
  2189.  
  2190. ; Holt eine Form, die die Länge der Argumentliste liefert.
  2191. (defun formatter-length-args ()
  2192.   (formatter-stop-linear)
  2193.   `(LENGTH ,*args*)
  2194. )
  2195.  
  2196. ; Holt eine Form für das nächste Argument.
  2197. ; Diese Form muß nachher mit SUBST ersetzt werden.
  2198. (defun formatter-next-arg ()
  2199.   (if *formatter-linear-args*
  2200.     (prog1
  2201.       `(ARG ,*formatter-linear-position*)
  2202.       (incf *formatter-linear-position*)
  2203.       (setq *formatter-linear-argcount*
  2204.             (max *formatter-linear-argcount* *formatter-linear-position*)
  2205.     ) )
  2206.     `(POP ,*args*)
  2207. ) )
  2208.  
  2209. ; Holt eine Form, die ein nthcdr der ganzen Argumentliste liefert.
  2210. ; Diese Form muß nachher mit SUBST ersetzt werden.
  2211. (defun formatter-whole-args (n)
  2212.   (formatter-stop-linear)
  2213.   (setq *formatter-whole-args* t)
  2214.   `(WHOLE-ARGS ,n)
  2215. )
  2216.  
  2217. ; Holt eine Formenliste zum Überspringen (vor/zurück) von Argumenten.
  2218. (defun formatter-goto-arg (absolute-p backward-p n)
  2219.   (if absolute-p
  2220.     ; im einfachsten Fall: (setq args (nthcdr n whole-args))
  2221.     (if (numberp n)
  2222.       (progn
  2223.         (setq n (max n 0))
  2224.         (if *formatter-linear-args*
  2225.           (if (< n *formatter-linear-position*)
  2226.             (prog1
  2227.               `((SETQ-ARGS-WHOLE-ARGS ,*formatter-linear-position* ,n))
  2228.               (setq *formatter-linear-position* n)
  2229.             )
  2230.             ; n >= *formatter-linear-position*
  2231.             (formatter-goto-arg nil nil (- n *formatter-linear-position*))
  2232.           )
  2233.           (progn
  2234.             (formatter-stop-linear)
  2235.             `((SETQ ,*args* ,(formatter-whole-args n)))
  2236.       ) ) )
  2237.       (progn
  2238.         (formatter-stop-linear)
  2239.         `((SETQ ,*args* (NTHCDR ,n ,(formatter-whole-args 0))))
  2240.     ) )
  2241.     (if backward-p
  2242.       ; im einfachsten Fall:
  2243.       ; (setq args (nthcdr (max (- (length whole-args) (length args) n) 0) whole-args))
  2244.       (if (and (numberp n) *formatter-linear-args*)
  2245.         (formatter-goto-arg t nil (- *formatter-linear-position* n))
  2246.         (progn
  2247.           (formatter-stop-linear)
  2248.           `((SETQ ,*args* ,(if *formatter-linear-args*
  2249.                              `(NTHCDR (MAX (- ,*formatter-linear-position* ,n) 0) ,(formatter-whole-args 0))
  2250.                              `(LIST-BACKWARD ,n ; n zuerst auswerten, da es (POP ARGS) enthalten kann
  2251.                                 ,(formatter-whole-args 0) ,*args*
  2252.                               )
  2253.                            )
  2254.            ))
  2255.       ) )
  2256.       ; im einfachsten Fall: (setq args (nthcdr n args))
  2257.       (if (and (numberp n) (<= n 100) *formatter-linear-args*)
  2258.         (do ((l '() (cons (formatter-next-arg) l)) (i 0 (1+ i)))
  2259.             ((>= i n) (nreverse l))
  2260.         )
  2261.         (progn
  2262.           (formatter-stop-linear)
  2263.           `((SETQ ,*args* (NTHCDR ,n ,*args*)))
  2264.       ) )
  2265. ) ) )
  2266. (defun list-backward (n whole-list list)
  2267.   (nthcdr (max (- (length whole-list) (length list) n) 0) whole-list)
  2268. )
  2269.  
  2270. ; Holt eine Form, der ein Direktiven-Argument liefert.
  2271. (defun formatter-arg (arg)
  2272.   (case arg
  2273.     (:NEXT-ARG (formatter-next-arg))
  2274.     (:ARG-COUNT (formatter-length-args))
  2275.     (T ; arg ist NIL oder Integer oder Character, braucht nicht quotiert zu werden.
  2276.        arg
  2277. ) ) )
  2278.  
  2279.  
  2280. ; Haupt-Compilier-Funktion. Liefert eine Formenliste.
  2281. ; Fluid übergeben: *format-cs* und *format-csdl* (wird weitergerückt).
  2282. (defun formatter-main-1 (&optional (endmarker nil))
  2283.   (let ((forms '()))
  2284.     (loop
  2285.       (when (endp *format-csdl*) (return))
  2286.       (let ((csd (car *format-csdl*)))
  2287.         (case (csd-type csd)
  2288.           (0 )
  2289.           (1 (push (subseq *format-cs* (csd-cs-index csd) (csd-data csd))
  2290.                    forms
  2291.           )  )
  2292.           (2 (let ((directive-name (csd-data csd)))
  2293.                (if (eq directive-name endmarker) (return))
  2294.                (if (eq directive-name 'FORMAT-SEPARATOR) (return))
  2295.                (let ((colon-p (csd-colon-p csd))
  2296.                      (atsign-p (csd-atsign-p csd))
  2297.                      (arglist (mapcar #'formatter-arg (csd-parm-list csd)))
  2298.                     )
  2299.                  (labels ((simple-arglist (n)
  2300.                             (unless (<= (length arglist) n)
  2301.                               (format-error *format-cs* nil
  2302.                                 #L{
  2303.                                 DEUTSCH "Zu viele Argumente für diese Direktive."
  2304.                                 ENGLISH "Too many arguments for this directive"
  2305.                                 FRANCAIS "Trop d'arguments pour cette directive."
  2306.                                 }
  2307.                             ) )
  2308.                             (setq arglist
  2309.                                   (append arglist
  2310.                                           (make-list (- n (length arglist))
  2311.                                                      :initial-element 'NIL
  2312.                           ) )     )       )
  2313.                           (trivial-call ()
  2314.                             (push `(,directive-name
  2315.                                     STREAM
  2316.                                     ,colon-p
  2317.                                     ,atsign-p
  2318.                                     ,@arglist
  2319.                                    )
  2320.                                   forms
  2321.                           ) )
  2322.                           (trivial (n)
  2323.                             (simple-arglist n)
  2324.                             (trivial-call)
  2325.                           )
  2326.                           (simple-call ()
  2327.                             (push `(,(intern (string-concat "DO-" (string directive-name))
  2328.                                              (find-package "SYSTEM")
  2329.                                      )
  2330.                                     STREAM
  2331.                                     ,colon-p
  2332.                                     ,atsign-p
  2333.                                     ,@arglist
  2334.                                     ; Pass the actual argument last because
  2335.                                     ; ,@arglist may contain `(POP ,*args*) as well.
  2336.                                     ,(formatter-next-arg)
  2337.                                    )
  2338.                                   forms
  2339.                           ) )
  2340.                           (simple (n)
  2341.                             (simple-arglist n)
  2342.                             (simple-call)
  2343.                          ))
  2344.                    (case directive-name
  2345.                      (FORMAT-ASCII                  ; #\A
  2346.                        (simple-arglist 4)
  2347.                        (if (and (member (first arglist) '(nil 0)) ; mincol
  2348.                                 (member (third arglist) '(nil 0)) ; minpad
  2349.                            )
  2350.                          (progn
  2351.                            (setq forms (revappend (remove 'NIL arglist) forms))
  2352.                            (push `(PRINC ,(if colon-p
  2353.                                             `(OR ,(formatter-next-arg) "()")
  2354.                                             (formatter-next-arg)
  2355.                                           )
  2356.                                          STREAM
  2357.                                   )
  2358.                                  forms
  2359.                          ) )
  2360.                          (simple-call)
  2361.                      ) )
  2362.                      (FORMAT-S-EXPRESSION           ; #\S
  2363.                        (simple-arglist 4)
  2364.                        (if (and (member (first arglist) '(nil 0)) ; mincol
  2365.                                 (member (third arglist) '(nil 0)) ; minpad
  2366.                                 (not colon-p)
  2367.                            )
  2368.                          (progn
  2369.                            (setq forms (revappend (remove 'NIL arglist) forms))
  2370.                            (push `(PRIN1 ,(formatter-next-arg) STREAM) forms)
  2371.                          )
  2372.                          (simple-call)
  2373.                      ) )
  2374.                      (FORMAT-WRITE                  ; #\W
  2375.                        (simple-arglist 4)
  2376.                        (if (and (member (first arglist) '(nil 0)) ; mincol
  2377.                                 (member (third arglist) '(nil 0)) ; minpad
  2378.                            )
  2379.                          (progn
  2380.                            (setq forms (revappend (remove 'NIL arglist) forms))
  2381.                            (push `(WRITE ,(formatter-next-arg) :STREAM STREAM) forms)
  2382.                          )
  2383.                          (simple-call)
  2384.                      ) )
  2385.                      (FORMAT-DECIMAL                ; #\D
  2386.                        (simple 4) )
  2387.                      (FORMAT-BINARY                 ; #\B
  2388.                        (simple 4) )
  2389.                      (FORMAT-OCTAL                  ; #\O
  2390.                        (simple 4) )
  2391.                      (FORMAT-HEXADECIMAL            ; #\X
  2392.                        (simple 4) )
  2393.                      (FORMAT-RADIX                  ; #\R
  2394.                        (simple-arglist 5)
  2395.                        (if (and (null (first arglist)) (not atsign-p))
  2396.                          (progn
  2397.                            (setq forms (revappend (remove 'NIL arglist) forms))
  2398.                            (push `(,(if colon-p 'FORMAT-ORDINAL 'FORMAT-CARDINAL)
  2399.                                    ,(formatter-next-arg) STREAM
  2400.                                   )
  2401.                                  forms
  2402.                          ) )
  2403.                          (simple-call)
  2404.                      ) )
  2405.                      (FORMAT-PLURAL                 ; #\P
  2406.                        (simple-arglist 0)
  2407.                        (when colon-p
  2408.                          (setq forms (revappend (formatter-goto-arg nil t 1) forms))
  2409.                        )
  2410.                        (push (if atsign-p
  2411.                                `(WRITE-STRING
  2412.                                   (IF (EQL ,(formatter-next-arg) 1) "y" "ies")
  2413.                                   STREAM
  2414.                                 )
  2415.                                `(UNLESS (EQL ,(formatter-next-arg) 1)
  2416.                                   (WRITE-CHAR #\s STREAM)
  2417.                                 )
  2418.                              )
  2419.                              forms
  2420.                      ) )
  2421.                      (FORMAT-CHARACTER              ; #\C
  2422.                        (simple 0) )
  2423.                      (FORMAT-FIXED-FLOAT            ; #\F
  2424.                        (simple 5) )
  2425.                      (FORMAT-EXPONENTIAL-FLOAT      ; #\E
  2426.                        (simple 7) )
  2427.                      (FORMAT-GENERAL-FLOAT          ; #\G
  2428.                        (simple 7) )
  2429.                      (FORMAT-DOLLARS-FLOAT          ; #\$
  2430.                        (simple 4) )
  2431.                      (FORMAT-TERPRI                 ; #\%
  2432.                        (simple-arglist 1)
  2433.                        (if (member (first arglist) '(nil 1))
  2434.                          (push #\Newline forms) ; equiv. to `(TERPRI STREAM)
  2435.                          (trivial-call)
  2436.                      ) )
  2437.                      (FORMAT-FRESH-LINE             ; #\&
  2438.                        (simple-arglist 1)
  2439.                        (if (member (first arglist) '(nil 1))
  2440.                          (push `(FRESH-LINE STREAM) forms)
  2441.                          (trivial-call)
  2442.                      ) )
  2443.                      (FORMAT-PAGE                   ; #\|
  2444.                        (simple-arglist 1)
  2445.                        (if (member (first arglist) '(nil 1))
  2446.                          (push #\Page forms)
  2447.                          (trivial-call)
  2448.                      ) )
  2449.                      (FORMAT-TILDE                  ; #\~
  2450.                        (simple-arglist 1)
  2451.                        (if (member (first arglist) '(nil 1))
  2452.                          (push #\~ forms)
  2453.                          (trivial-call)
  2454.                      ) )
  2455.                      (FORMAT-TABULATE               ; #\T
  2456.                        (trivial 2) )
  2457.                      (FORMAT-GOTO                   ; #\*
  2458.                        (simple-arglist 1)
  2459.                        (setq forms
  2460.                              (revappend
  2461.                                (formatter-goto-arg atsign-p colon-p
  2462.                                  (or (first arglist) (if atsign-p 0 1))
  2463.                                )
  2464.                                forms
  2465.                      ) )     )
  2466.                      (FORMAT-INDIRECTION            ; #\?
  2467.                        (simple-arglist 0)
  2468.                        (if atsign-p
  2469.                          (push `(SETQ ,*args*
  2470.                                   (DO-FORMAT-INDIRECTION STREAM
  2471.                                     ,(formatter-next-arg)
  2472.                                     ,(progn (formatter-stop-linear) `,*args*)
  2473.                                 ) )
  2474.                                forms
  2475.                          )
  2476.                          (push `(DO-FORMAT-INDIRECTION STREAM ,(formatter-next-arg) ,(formatter-next-arg))
  2477.                                forms
  2478.                      ) ) )
  2479.                      (FORMAT-CASE-CONVERSION        ; #\(
  2480.                        (simple-arglist 0)
  2481.                        (setq *format-csdl* (cdr *format-csdl*))
  2482.                        (if *format-case*
  2483.                          ; Richard Waters notes: It is possible for ~(...~) to
  2484.                          ; be nested in a format string, but note that inner
  2485.                          ; nested modes never have any effect. You can just
  2486.                          ; ignore them.
  2487.                          (let ((inner-forms
  2488.                                  ; no need to bind *format-case* to t here
  2489.                                  (formatter-main-1 'FORMAT-CASE-CONVERSION-END)
  2490.                               ))
  2491.                            (setq forms (revappend inner-forms forms))
  2492.                          )
  2493.                          (push `(LET ((ORIG-STREAM STREAM)
  2494.                                       (STREAM (MAKE-STRING-OUTPUT-STREAM (SYS::LINE-POSITION STREAM))))
  2495.                                   ,@(let* ((*format-uwps* (cons 'NIL *format-uwps*))
  2496.                                            (inner-forms
  2497.                                              (let ((*format-case* t))
  2498.                                                (formatter-main 'FORMAT-CASE-CONVERSION-END)
  2499.                                            ) )
  2500.                                            (cleanup-forms
  2501.                                              `((WRITE-STRING
  2502.                                                  (,(if colon-p
  2503.                                                      (if atsign-p
  2504.                                                        'NSTRING-UPCASE
  2505.                                                        'NSTRING-CAPITALIZE
  2506.                                                      )
  2507.                                                      (if atsign-p
  2508.                                                        'SYS::NSTRING-CAPITALIZE1
  2509.                                                        'NSTRING-DOWNCASE
  2510.                                                    ) )
  2511.                                                   (GET-OUTPUT-STREAM-STRING STREAM)
  2512.                                                  )
  2513.                                                  ORIG-STREAM
  2514.                                               ))
  2515.                                           ))
  2516.                                       (if (car *format-uwps*)
  2517.                                         `((UNWIND-PROTECT (PROGN ,@inner-forms) ,@cleanup-forms))
  2518.                                         `(,@inner-forms ,@cleanup-forms)
  2519.                                     ) )
  2520.                                 )
  2521.                                forms
  2522.                      ) ) )
  2523.                      (FORMAT-CONDITIONAL            ; #\[
  2524.                        (if colon-p
  2525.                          (if atsign-p
  2526.                            (format-conditional-error)
  2527.                            (progn
  2528.                              (simple-arglist 0)
  2529.                              (push `(IF (NOT ,(formatter-next-arg))
  2530.                                       (PROGN ,@(progn
  2531.                                                  (formatter-stop-linear)
  2532.                                                  (setq *format-csdl* (cdr *format-csdl*))
  2533.                                                  (formatter-main 'FORMAT-CONDITIONAL-END)
  2534.                                       )        )
  2535.                                       (PROGN ,@(progn
  2536.                                                  (formatter-stop-linear)
  2537.                                                  (setq *format-csdl* (cdr *format-csdl*))
  2538.                                                  (formatter-main 'FORMAT-CONDITIONAL-END)
  2539.                                     ) )        )
  2540.                                    forms
  2541.                          ) ) )
  2542.                          (if atsign-p
  2543.                            (progn
  2544.                              (simple-arglist 0)
  2545.                              (formatter-stop-linear)
  2546.                              (push `(IF (CAR ,*args*)
  2547.                                       (PROGN ,@(progn
  2548.                                                  (setq *format-csdl* (cdr *format-csdl*))
  2549.                                                  (formatter-main 'FORMAT-CONDITIONAL-END)
  2550.                                       )        )
  2551.                                       (SETQ ,*args* (CDR ,*args*))
  2552.                                     )
  2553.                                    forms
  2554.                              )
  2555.                              (unless (null (csd-clause-chain (car *format-csdl*)))
  2556.                                (format-error *format-cs* nil
  2557.                                  #L{
  2558.                                  DEUTSCH "Hier ist keine ~~;-Direktive möglich."
  2559.                                  ENGLISH "The ~~; directive is not allowed at this point."
  2560.                                  FRANCAIS "La directive ~~; n'est pas permise ici."
  2561.                                  }
  2562.                            ) ) )
  2563.                            (progn
  2564.                              (simple-arglist 1)
  2565.                              (push `(CASE ,(or (first arglist) (formatter-next-arg))
  2566.                                       ,@(let ((index 0) (cases '()))
  2567.                                           (formatter-stop-linear)
  2568.                                           (loop
  2569.                                             (when (null (csd-clause-chain (car *format-csdl*)))
  2570.                                               (return)
  2571.                                             )
  2572.                                             (when (csd-colon-p (car *format-csdl*))
  2573.                                               (setq index 'T)
  2574.                                             )
  2575.                                             (setq *format-csdl* (cdr *format-csdl*))
  2576.                                             (push `(,index ,@(formatter-main 'FORMAT-CONDITIONAL-END))
  2577.                                                   cases
  2578.                                             )
  2579.                                             (if (eq index 'T) (return) (incf index))
  2580.                                           )
  2581.                                           (nreverse cases)
  2582.                                         )
  2583.                                     )
  2584.                                    forms
  2585.                      ) ) ) ) )
  2586.                      (FORMAT-ITERATION              ; #\{
  2587.                        (simple-arglist 1)
  2588.                        (setq *format-csdl* (cdr *format-csdl*))
  2589.                        (let ((max-n-iterations (first arglist))
  2590.                              (min-1-iteration (csd-colon-p (car (csd-clause-chain csd))))
  2591.                              (indirect (eq (csd-clause-chain csd) *format-csdl*)))
  2592.                          (flet ((compute-innermost ()
  2593.                                   (if indirect
  2594.                                     (progn
  2595.                                       (formatter-stop-linear)
  2596.                                       `((SETQ ,*args*
  2597.                                           (DO-FORMAT-INDIRECTION-2 STREAM NODE
  2598.                                                                    ,*args* ,(formatter-whole-args 0)
  2599.                                        )) )
  2600.                                     )
  2601.                                     (formatter-main 'FORMAT-ITERATION-END)
  2602.                                )) )
  2603.                            (flet ((compute-inner ()
  2604.                                     (if colon-p
  2605.                                       (let ((*iterargs* *args*))
  2606.                                         (formatter-bind-terminator
  2607.                                           (multiple-value-bind (lambdalist innermost)
  2608.                                               (formatter-bind-args (compute-innermost))
  2609.                                             `((APPLY #'(LAMBDA ,lambdalist ,@innermost)
  2610.                                                ,(formatter-next-arg)
  2611.                                              ))
  2612.                                       ) ) )
  2613.                                       (let ((*iterargs* nil))
  2614.                                         ; CLtL2 S. 598: "When within a ~{ construct, the "goto" is
  2615.                                         ; relative to the list of arguments being processed by the
  2616.                                         ; iteration." Soll das heißen, daß man bei ~@{ zu Beginn
  2617.                                         ; jeder Iteration WHOLE-ARGS neu an ARGS binden muß ??
  2618.                                         ; (if atsign-p
  2619.                                         ;   (progn (formatter-stop-linear)
  2620.                                         ;     `((LET ((WHOLE-ARGS ,*args*)) ,@(compute-innermost)))
  2621.                                         ;   )
  2622.                                         ;   (compute-innermost)
  2623.                                         ; )
  2624.                                         (compute-innermost)
  2625.                                  )) ) )
  2626.                              (flet ((compute-middle ()
  2627.                                       (if (eql max-n-iterations 0)
  2628.                                         '()
  2629.                                         (progn
  2630.                                           (unless (and (eql max-n-iterations 1) min-1-iteration)
  2631.                                             (formatter-stop-linear)
  2632.                                           )
  2633.                                           (if (eql max-n-iterations 1)
  2634.                                             (if min-1-iteration
  2635.                                               (compute-inner)
  2636.                                               `((UNLESS (ENDP ,*args*) ,@(compute-inner)))
  2637.                                             )
  2638.                                             `((BLOCK NIL
  2639.                                                 (TAGBODY
  2640.                                                   L
  2641.                                                   ,@(if max-n-iterations
  2642.                                                       `((WHEN (>= I N) (RETURN)) (INCF I))
  2643.                                                     )
  2644.                                                   ,@(if (not min-1-iteration)
  2645.                                                       `((WHEN (ENDP ,*args*) (RETURN)))
  2646.                                                     )
  2647.                                                   ,@(compute-inner)
  2648.                                                   ,@(if min-1-iteration
  2649.                                                       `((WHEN (ENDP ,*args*) (RETURN)))
  2650.                                                     )
  2651.                                                   (GO L)
  2652.                                              )) )
  2653.                                    )) ) ) )
  2654.                                (flet ((compute-outer ()
  2655.                                         (formatter-bind-terminators
  2656.                                           ; *format-terminate-all* und *format-terminate* werden
  2657.                                           ; gebunden, aber falls colon-p, wird *format-terminate*
  2658.                                           ; weiter innen verschattet (s.o.).
  2659.                                           (if atsign-p
  2660.                                             (compute-middle)
  2661.                                             (multiple-value-bind (lambdalist inner-forms)
  2662.                                                 (formatter-bind-args (compute-middle))
  2663.                                               `((APPLY #'(LAMBDA ,lambdalist ,@inner-forms)
  2664.                                                  ,(formatter-next-arg)
  2665.                                                ))
  2666.                                      )) ) ) )
  2667.                                  (flet ((compute-outermost ()
  2668.                                           (if indirect
  2669.                                             `((LET ((NODE (DO-FORMAT-INDIRECTION-1 ,(formatter-next-arg))))
  2670.                                                 ,@(compute-outer)
  2671.                                              ))
  2672.                                             (compute-outer)
  2673.                                        )) )
  2674.                                    (let ((new-forms
  2675.                                            (if (and max-n-iterations (not (member max-n-iterations '(0 1))))
  2676.                                              `((LET ((N ,(first arglist)) (I 0))
  2677.                                                  ,@(compute-outermost)
  2678.                                               ))
  2679.                                               (compute-outermost)
  2680.                                         )) )
  2681.                                      (setq forms (revappend new-forms forms))
  2682.                      ) ) ) ) ) ) ) )
  2683.                      (FORMAT-JUSTIFICATION          ; #\<
  2684.                        (simple-arglist 4)
  2685.                        (let* ((firstseparator (car (csd-clause-chain csd)))
  2686.                               (check-on-line-overflow
  2687.                                 (and (eq (csd-data firstseparator) 'FORMAT-SEPARATOR)
  2688.                                      (csd-colon-p firstseparator)
  2689.                               ) )
  2690.                               (bindings
  2691.                                 `((POS (SYS::LINE-POSITION STREAM))
  2692.                                   (ORIG-STREAM STREAM)
  2693.                                   (STREAM (MAKE-STRING-OUTPUT-STREAM POS))
  2694.                                  )
  2695.                               )
  2696.                               (justify-args
  2697.                                 `(ORIG-STREAM
  2698.                                   ,colon-p
  2699.                                   ,atsign-p
  2700.                                   ,@arglist
  2701.                                   POS
  2702.                                   ,check-on-line-overflow
  2703.                                   ,(when check-on-line-overflow
  2704.                                      (setq *format-csdl* (cdr *format-csdl*))
  2705.                                      `(PROGN
  2706.                                         ,@(formatter-main 'FORMAT-JUSTIFICATION-END)
  2707.                                         (GET-OUTPUT-STREAM-STRING STREAM)
  2708.                                       )
  2709.                                    )
  2710.                                   ,(when check-on-line-overflow
  2711.                                      (formatter-arg (first (csd-parm-list firstseparator)))
  2712.                                    )
  2713.                                   ,(when check-on-line-overflow
  2714.                                      (formatter-arg (second (csd-parm-list firstseparator)))
  2715.                                    )
  2716.                                  )
  2717.                               )
  2718.                               (*format-uwps* (cons 'NIL *format-uwps*))
  2719.                               (pieces-forms '())
  2720.                              )
  2721.                          (loop
  2722.                            (when (null (csd-clause-chain (car *format-csdl*))) (return))
  2723.                            (setq *format-csdl* (cdr *format-csdl*))
  2724.                            (push (formatter-main 'FORMAT-JUSTIFICATION-END) pieces-forms)
  2725.                          )
  2726.                          (setq pieces-forms (nreverse pieces-forms))
  2727.                          (push
  2728.                            (if (car *format-uwps*)
  2729.                              `(LET* (,@bindings
  2730.                                      (JARGS (LIST ,@justify-args))
  2731.                                      (PIECES '()))
  2732.                                 (UNWIND-PROTECT
  2733.                                   (PROGN
  2734.                                     ,@(mapcap #'(lambda (piece-forms)
  2735.                                                   `(,@piece-forms
  2736.                                                     (PUSH (GET-OUTPUT-STREAM-STRING STREAM) PIECES)
  2737.                                                    )
  2738.                                                 )
  2739.                                               pieces-forms
  2740.                                       )
  2741.                                   )
  2742.                                   (APPLY #'DO-FORMAT-JUSTIFICATION
  2743.                                          (NCONC JARGS (LIST (SYS::LIST-NREVERSE PIECES)))
  2744.                               ) ) )
  2745.                              `(LET* (,@bindings)
  2746.                                 (DO-FORMAT-JUSTIFICATION
  2747.                                   ,@justify-args
  2748.                                   (LIST
  2749.                                     ,@(mapcar #'(lambda (piece-forms)
  2750.                                                   `(PROGN ,@piece-forms (GET-OUTPUT-STREAM-STRING STREAM))
  2751.                                                 )
  2752.                                               pieces-forms
  2753.                                       )
  2754.                               ) ) )
  2755.                            )
  2756.                            forms
  2757.                      ) ) )
  2758.                      (FORMAT-UP-AND-OUT             ; #\^
  2759.                        (simple-arglist 3)
  2760.                        (formatter-stop-linear)
  2761.                        (let ((argsvar (if colon-p *iterargs* *args*)))
  2762.                          (push `(IF ,(if (some #'(lambda (x) (and (constantp x) x)) arglist)
  2763.                                        `(UP-AND-OUT-P ,@arglist)
  2764.                                        (if (and (null (second arglist)) (null (third arglist)))
  2765.                                          (let ((first-arg (first arglist)))
  2766.                                            (if (null first-arg)
  2767.                                              `(ENDP ,argsvar)
  2768.                                              (if (and (consp first-arg) (eq (car first-arg) 'LENGTH))
  2769.                                                `(ENDP ,(second first-arg)) ; (EQL (LENGTH x) 0) == (ENDP x)
  2770.                                                `(CASE ,first-arg ((NIL) (ENDP ,argsvar)) ((0) T) (T NIL))
  2771.                                          ) ) )
  2772.                                          `(UP-AND-OUT-P ,@arglist ,argsvar)
  2773.                                      ) )
  2774.                                   (RETURN-FROM ,(if colon-p (formatter-terminate-all) (formatter-terminate)))
  2775.                                 )
  2776.                                forms
  2777.                      ) ) )
  2778.                      (t ; Huh? Someone implemented a new format directive,
  2779.                         ; but forgot it here! Bail out.
  2780.                         (throw 'formatter-hairy nil)
  2781.                      )
  2782.           )  ) ) ) )
  2783.       ) )
  2784.       (setq *format-csdl* (cdr *format-csdl*))
  2785.     )
  2786.     ; Combine adjacent strings:
  2787.     (let ((new-forms '()))
  2788.       (dolist (form forms)
  2789.         (when (characterp form) (setq form (string form)))
  2790.         (if (and (consp new-forms) (stringp (car new-forms)) (stringp form))
  2791.           (setf (car new-forms)
  2792.                 (string-concat form (car new-forms))
  2793.           )
  2794.           (push form new-forms)
  2795.       ) )
  2796.       new-forms
  2797. ) ) )
  2798. (defun formatter-main (&optional (endmarker nil))
  2799.   (let ((new-forms (formatter-main-1 endmarker)))
  2800.     ; Convert strings to WRITE-STRING forms:
  2801.     (mapcap #'(lambda (form)
  2802.                 (if (stringp form)
  2803.                   (case (length form)
  2804.                     (0 )
  2805.                     (1 (setq form (char form 0))
  2806.                        `(,(if (eq form #\Newline)
  2807.                             `(TERPRI STREAM)
  2808.                             `(WRITE-CHAR ,form STREAM)
  2809.                     )   ) )
  2810.                     (t `((WRITE-STRING ,form STREAM)))
  2811.                   )
  2812.                   (list form)
  2813.               ) )
  2814.             new-forms
  2815. ) ) )
  2816.  
  2817. ;; FORMATTER, CLtL2 S. 764
  2818. (defmacro formatter (control-string)
  2819.   (unless (stringp control-string)
  2820.     (error-of-type 'type-error
  2821.       :datum control-string :expected-type 'string
  2822.       #L{
  2823.       DEUTSCH "Kontrollstring muß ein String sein, nicht ~S"
  2824.       ENGLISH "The control-string must be a string, not ~S"
  2825.       FRANCAIS "La chaîne de contrôle doit être une chaîne et non ~S"
  2826.       }
  2827.       control-string
  2828.   ) )
  2829.   ; evtl. noch control-string zu einem Simple-String machen ??
  2830.   (or
  2831.     (catch 'formatter-hairy
  2832.       (let ((node (list control-string)))
  2833.         (format-parse-cs control-string 0 node nil)
  2834.         (let ((*FORMAT-CS* (car node))
  2835.               (*FORMAT-CSDL* (cdr node))
  2836.               (*format-case* nil)
  2837.               (*format-uwps* '())
  2838.               (*iterargs* nil))
  2839.           (multiple-value-bind (lambdalist forms)
  2840.               (formatter-bind-args
  2841.                 `(,@(formatter-bind-terminators
  2842.                       (formatter-main)
  2843.                     )
  2844.                   ,(progn (formatter-stop-linear) `,*args*)
  2845.                  )
  2846.               )
  2847.             `(FUNCTION
  2848.                (LAMBDA (STREAM ,@lambdalist)
  2849.                  (DECLARE (IGNORABLE STREAM))
  2850.                  ,@forms
  2851.              ) )
  2852.     ) ) ) )
  2853.     `(FORMATTER-HAIRY ,(coerce control-string 'simple-string))
  2854. ) )
  2855.  
  2856. ;-------------------------------------------------------------------------------
  2857.  
  2858.