(FILECREATED "30-Sep-86 16:09:50" {ERIS}<LISPCORE>SOURCES>CMLFORMAT.;3 96980        changes to:  (FUNCTIONS FORMAT-DO-ITERATION FORMAT-FRESHLINE FORMAT-STRINGIFY-OUTPUT)      previous date: " 9-Sep-86 23:45:48" {ERIS}<LISPCORE>SOURCES>CMLFORMAT.;2)(* "Copyright (c) 1986 by Xerox Corporation.  All rights reserved.")(PRETTYCOMPRINT CMLFORMATCOMS)(RPAQQ CMLFORMATCOMS        ((* ;; "The FORMAT facility")                (STRUCTURES FORMAT-ERROR)        (FUNCTIONS MAKE-DISPATCH-VECTOR SCALE-EXPONENT SCALE-EXPT-AUX)        (FUNCTIONS FORMAT-ERROR)        (VARIABLES *DIGIT-STRING* *DIGITS*)        (FUNCTIONS FLONUM-TO-STRING FLOAT-STRING FORMAT-WITH-CONTROL-STRING FORMAT-STRINGIFY-OUTPUT                POP-FORMAT-ARG WITH-FORMAT-PARAMETERS NEXTCHAR FORMAT-PEEK FORMAT-FIND-CHAR)        (FUNCTIONS FORMAT-GET-PARAMETER PARSE-FORMAT-OPERATION FORMAT-FIND-COMMAND FORMAT SUB-FORMAT                FORMAT-CAPITALIZATION FORMAT-ESCAPE FORMAT-SEMICOLON-ERROR FORMAT-UNTAGGED-CONDITION                FORMAT-FUNNY-CONDITION FORMAT-BOOLEAN-CONDITION FORMAT-CONDITION FORMAT-ITERATION                FORMAT-DO-ITERATION FORMAT-GET-TRAILING-SEGMENTS FORMAT-GET-SEGMENTS MAKE-PAD-SEGS                FORMAT-ROUND-COLUMNS FORMAT-JUSTIFICATION FORMAT-TERPRI FORMAT-FRESHLINE FORMAT-PAGE                FORMAT-TILDE FORMAT-EAT-WHITESPACE FORMAT-NEWLINE FORMAT-PLURAL FORMAT-SKIP-ARGUMENTS                FORMAT-INDIRECTION FORMAT-TAB FORMAT-PRINC FORMAT-PRIN1 FORMAT-PRINT-CHARACTER                FORMAT-PRINT-NAMED-CHARACTER FORMAT-ADD-COMMAS FORMAT-WRITE-FIELD FORMAT-PRINT-NUMBER                FORMAT-PRINT-SMALL-CARDINAL FORMAT-PRINT-CARDINAL FORMAT-PRINT-CARDINAL-AUX                FORMAT-PRINT-ORDINAL FORMAT-PRINT-OLD-ROMAN FORMAT-PRINT-ROMAN FORMAT-PRINT-DECIMAL                FORMAT-PRINT-BINARY FORMAT-PRINT-OCTAL FORMAT-PRINT-HEXADECIMAL FORMAT-PRINT-RADIX                FORMAT-FIXED FORMAT-FIXED-AUX FORMAT-EXPONENTIAL FORMAT-EXPONENT-MARKER FORMAT-EXP-AUX                FORMAT-GENERAL-FLOAT FORMAT-GENERAL-AUX FORMAT-DOLLARS)        (FUNCTIONS CHARPOS WHITESPACE-CHAR-P)        (FUNCTIONS NAME-ARRAY)        (VARIABLES *FORMAT-ARGUMENTS* *FORMAT-CONTROL-STRING* *FORMAT-DISPATCH-TABLE* *FORMAT-INDEX*                *FORMAT-LENGTH* *FORMAT-ORIGINAL-ARGUMENTS* CARDINAL-ONES CARDINAL-TENS CARDINAL-TEENS                CARDINAL-PERIODS ORDINAL-ONES ORDINAL-TENS)        (DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS (ADDVARS (NLAMA)                                                                            (NLAML)                                                                            (LAMA)))        (* ;; "Arrange to use the correct compiler.")        (PROP FILETYPE CMLFORMAT)))(* ;; "The FORMAT facility")(DECLARE: EVAL@COMPILE DONTCOPY (FILESLOAD (LOADCOMP)       FILEIO))(DEFINE-CONDITION FORMAT-ERROR CL:ERROR :REPORT-FUNCTION (CL:LAMBDA (CONDITION *STANDARD-OUTPUT*)                                                                (DECLARE (SPECVARS *STANDARD-OUTPUT*)                                                                       )                                                                (FORMAT T "~%%~:{~@?~%%~}"                                                                       (FORMAT-ERROR-ARGS CONDITION))                                                                )                                     ARGS)(DEFMACRO MAKE-DISPATCH-VECTOR (&BODY ENTRIES)    (* ;; "Hairy dispatch-table initialization macro. Takes a list of two-element lists (<character> <function-object>) and returns a vector char-code-limit elements in length, where the Ith element is the function associated with the character with char-code I. If the character is case-convertible, it must be given in only one case however, an entry in the vector will be made for both.")   (LET ((ENTRIES (MAPCAN (CL:FUNCTION (CL:LAMBDA (X)                                              (LET ((LOWER (CHAR-DOWNCASE (CAR X)))                                                    (UPPER (CHAR-UPCASE (CAR X))))                                                   (CL:IF (CHAR= LOWER UPPER)                                                          (LIST X)                                                          (LIST (CONS UPPER (CDR X))                                                                (CONS LOWER (CDR X)))))))                         ENTRIES)))        (CL:DO ((ENTRIES (SORT ENTRIES (CL:FUNCTION (CL:LAMBDA (X Y)                                                           (CHAR< (CAR X)                                                                  (CAR Y))))))                (CHARIDX 0 (1+ CHARIDX))                (COMTAB NIL (CONS (CL:IF ENTRIES (CL:IF (= (CHAR-CODE (CAAR ENTRIES))                                                           CHARIDX)                                                        (CADR (pop ENTRIES))                                                        NIL)                                         NIL)                                  COMTAB)))               ((= CHARIDX 256)                (CL:IF ENTRIES (CL:ERROR "Garbage in dispatch vector - ~S" ENTRIES))                (BQUOTE (MAKE-ARRAY (QUOTE (256))                               :ELEMENT-TYPE T :INITIAL-CONTENTS (QUOTE (\, (NREVERSE COMTAB)))))))))(DEFUN SCALE-EXPONENT (X)                     (* OLD CODE -          (CL:IF (TYPEP X (QUOTE SHORT-FLOAT)) (SCALE-EXPT-AUX X 0.0S0 1.0S0 1.0S1 1.0S-1           SHORT-LOG10-OF-2) (SCALE-EXPT-AUX X (%%SP-L-FLOAT 0)          (%%SP-L-FLOAT 1) %%LONG-FLOAT-TEN %%LONG-FLOAT-ONE-TENTH LONG-LOG10-OF-2))) (SCALE-EXPT-AUX X 0.0 1.0 10.0 .1 (CONSTANT (CL:LOG 2.0 10.0))))(DEFUN SCALE-EXPT-AUX (X ZERO ONE TEN ONE-TENTH LOG10-OF-2)   (MULTIPLE-VALUE-BIND (SIG EXPONENT)          (DECODE-FLOAT X)          (DECLARE (IGNORE SIG))          (CL:IF (= X ZERO)                 (VALUES ZERO 1)                 (LET* ((E (ROUND (CL:* EXPONENT LOG10-OF-2)))                        (X (CL:IF (MINUSP E)                                  (CL:* X TEN (CL:EXPT TEN (- -1 E)))                                  (/ X TEN (CL:EXPT TEN (1- E))))))                       (CL:DO ((D TEN (CL:* D TEN))                               (Y X (/ X D))                               (E E (1+ E)))                              ((< Y ONE)                               (CL:DO ((M TEN (CL:* M TEN))                                       (Z Y (CL:* Z M))                                       (E E (1- E)))                                      ((>= Z ONE-TENTH)                                       (VALUES Z E)))))))))(DEFUN FORMAT-ERROR (COMPLAINT &REST FORMAT-ARGS)            (* amd " 2-May-86 17:13")   (CL:ERROR (QUOTE FORMAT-ERROR)          :ARGS          (LIST (LIST "~?~%%~S~%%~V@T^" COMPLAINT FORMAT-ARGS *FORMAT-CONTROL-STRING* (1+                                                                                        *FORMAT-INDEX*                                                                                          )))))(DEFVAR *DIGIT-STRING* (MAKE-ARRAY 50 :ELEMENT-TYPE (QUOTE STRING-CHAR)                              :FILL-POINTER 0 :ADJUSTABLE T) )(DEFVAR *DIGITS* "0123456789" )(DEFUN FLONUM-TO-STRING (X &OPTIONAL WIDTH FDIGITS SCALE FMIN)   (COND      ((CL:ZEROP X)       (VALUES "." 1 T T))      (T (SETF (FILL-POINTER *DIGIT-STRING*)               0)         (MULTIPLE-VALUE-BIND (SIG EXP)                (INTEGER-DECODE-FLOAT X)                (CL:IF (TYPEP X (QUOTE SHORT-FLOAT))                       (FLOAT-STRING SIG EXP 20 WIDTH FDIGITS SCALE FMIN)                       (FLOAT-STRING SIG EXP 53 WIDTH FDIGITS SCALE FMIN))))))(DEFUN FLOAT-STRING (FRACTION EXPONENT PRECISION WIDTH FDIGITS SCALE FMIN)   (LET ((R FRACTION)         (S 1)         (M- 1)         (M+ 1)         (K 0)         (DIGITS 0)         (DECPNT 0)         (CUTOFF NIL)         (ROUNDUP NIL)         U LOW HIGH)        (COND           ((> EXPONENT 0)            (CL:SETQ R (ASH FRACTION EXPONENT))            (CL:SETQ M- (ASH 1 EXPONENT))            (CL:SETQ M+ M-))           ((< EXPONENT 0)            (CL:SETQ S (ASH 1 (- EXPONENT)))))        (CL:WHEN (= FRACTION (ASH 1 PRECISION))               (CL:SETQ M+ (ASH M+ 1))               (CL:SETQ R (ASH R 1))               (CL:SETQ S (ASH S 1)))        (CL:WHEN SCALE (CL:IF (MINUSP SCALE)                              (LET ((SCALE-FACTOR (EXPT 10 (- SCALE))))                                   (CL:SETQ S (CL:* S SCALE-FACTOR)))                              (LET ((SCALE-FACTOR (EXPT 10 SCALE)))                                   (CL:SETQ R (CL:* R SCALE-FACTOR))                                   (CL:SETQ M+ (CL:* M+ SCALE-FACTOR))                                   (CL:SETQ M- (CL:* M- SCALE-FACTOR)))))        (CL:DO NIL ((>= R (CEILING S 10)))               (DECF K)               (CL:SETQ R (CL:* R 10))               (CL:SETQ M- (CL:* M- 10))               (CL:SETQ M+ (CL:* M+ 10)))        (CL:DO NIL (NIL)               (CL:DO NIL ((< (+ (ASH R 1)                                 M+)                            (ASH S 1)))                      (CL:SETQ S (CL:* S 10))                      (INCF K))               (COND                  (FDIGITS (CL:SETQ CUTOFF (- FDIGITS))                         (CL:IF (AND FMIN (> CUTOFF (- FMIN)))                                (CL:SETQ CUTOFF (- FMIN))))                  (WIDTH (CL:IF (< K 0)                                (CL:SETQ CUTOFF (- 1 WIDTH))                                (CL:SETQ CUTOFF (1+ (- K WIDTH))))                         (CL:IF (AND FMIN (> CUTOFF (- FMIN)))                                (CL:SETQ CUTOFF (- FMIN)))))               (CL:WHEN (OR FDIGITS WIDTH)                      (LET ((A (- CUTOFF K))                            (Y S))                           (CL:IF (>= A 0)                                  (DOTIMES (I A)                                         (CL:SETQ Y (CL:* Y 10)))                                  (DOTIMES (I (- A))                                         (CL:SETQ Y (CEILING Y 10))))                           (CL:SETQ M- (MAX Y M-))                           (CL:SETQ M+ (MAX Y M+))                           (CL:WHEN (= M+ Y)                                  (CL:SETQ ROUNDUP T))))               (CL:WHEN (< (+ (ASH R 1)                              M+)                         (ASH S 1))                      (RETURN)))        (CL:WHEN (< K 0)               (CL:SETQ DECPNT DIGITS)               (VECTOR-PUSH-EXTEND |\. *DIGIT-STRING*)               (DOTIMES (I (- K))                      (INCF DIGITS)                      (VECTOR-PUSH-EXTEND |\0 *DIGIT-STRING*)))        (CL:DO NIL (NIL)               (DECF K)               (CL:WHEN (= K -1)                      (VECTOR-PUSH-EXTEND |\. *DIGIT-STRING*)                      (CL:SETQ DECPNT DIGITS))               (MULTIPLE-VALUE-SETQ (U R)                      (TRUNCATE (CL:* R 10)                             S))               (CL:SETQ M- (CL:* M- 10))               (CL:SETQ M+ (CL:* M+ 10))               (CL:SETQ LOW (< (ASH R 1)                             M-))               (CL:IF ROUNDUP (CL:SETQ HIGH (>= (ASH R 1)                                                (- (ASH S 1)                                                   M+)))                      (CL:SETQ HIGH (> (ASH R 1)                                       (- (ASH S 1)                                          M+))))               (CL:WHEN (OR LOW HIGH (AND CUTOFF (<= K CUTOFF)))                      (RETURN))               (VECTOR-PUSH-EXTEND (CHAR *DIGITS* U)                      *DIGIT-STRING*)               (INCF DIGITS))        (CL:WHEN (OR (NOT CUTOFF)                     (>= K CUTOFF))               (VECTOR-PUSH-EXTEND (CHAR *DIGITS* (COND                                                     ((AND LOW (NOT HIGH))                                                      U)                                                     ((AND HIGH (NOT LOW))                                                      (1+ U))                                                     (T (CL:IF (<= (ASH R 1)                                                                S)                                                               U                                                               (1+ U)))))                      *DIGIT-STRING*)               (INCF DIGITS))        (CL:WHEN (>= K 0)               (DOTIMES (I K)                      (INCF DIGITS)                      (VECTOR-PUSH-EXTEND |\0 *DIGIT-STRING*))               (VECTOR-PUSH-EXTEND |\. *DIGIT-STRING*)               (CL:SETQ DECPNT DIGITS))        (CL:WHEN FDIGITS (DOTIMES (I (- FDIGITS (- DIGITS DECPNT)))                                (INCF DIGITS)                                (VECTOR-PUSH-EXTEND |\0 *DIGIT-STRING*)))        (VALUES *DIGIT-STRING* (1+ DIGITS)               (= DECPNT 0)               (= DECPNT DIGITS)               DECPNT)))(DEFMACRO FORMAT-WITH-CONTROL-STRING (CONTROL-STRING &BODY FORMS)                                                   (* ;; "This macro establishes the correct environment for processing an indirect control string. CONTROL-STRING is the string to process, and FORMS are the forms to do the processing. They invariably will involve a call to SUB-FORMAT.  CONTROL-STRING is guaranteed to be evaluated exactly once.")   (BQUOTE (LET ((STRING (\, CONTROL-STRING)))                (LET ((STRING (CL:IF (SIMPLE-STRING-P STRING)                                     STRING                                     (COERCE STRING (QUOTE SIMPLE-STRING)))))                     (DECLARE (TYPE SIMPLE-STRING STRING))                     (CONDITION-CASE (LET ((*FORMAT-CONTROL-STRING* STRING)                                           (*FORMAT-LENGTH* (CL:LENGTH STRING))                                           (*FORMAT-INDEX* 0))                                          (\,@ FORMS))                            (FORMAT-ERROR (C)                                   (CL:ERROR (QUOTE FORMAT-ERROR)                                          :ARGS                                          (CONS (LIST                                               "While processing indirect control string~%%~S~%%~V@T^"                                                       *FORMAT-CONTROL-STRING* (1+ *FORMAT-INDEX*))                                                (FORMAT-ERROR-ARGS C)))))))))(DEFMACRO FORMAT-STRINGIFY-OUTPUT (&BODY FORMS)                     (* This macro rebinds collects output to the standard output stream in a           string. For efficiency, we avoid consing a new stream on every call.          A stack of string streams is maintained in order to guarantee re-entrancy.          *) (BQUOTE (LET ((*STANDARD-OUTPUT* (MAKE-STRING-OUTPUT-STREAM)))              (\,@ FORMS)              (COERCE (GET-OUTPUT-STREAM-STRING *STANDARD-OUTPUT*)                     (QUOTE SIMPLE-STRING)))))(DEFMACRO POP-FORMAT-ARG NIL                     (* Pops an argument from the current argument list.          This is either the list of arguments given to the top-level call to FORMAT, or           the argument list for the current iteration in a ~{~} construct.          An error is signalled if the argument list is empty.          *)                             (QUOTE (CL:IF *FORMAT-ARGUMENTS* (CL:POP *FORMAT-ARGUMENTS*)                                           (FORMAT-ERROR "Missing argument"))))(DEFMACRO WITH-FORMAT-PARAMETERS (PARMVAR PARMDEFS &BODY FORMS)                                                   (* ;; "This macro decomposes the argument list returned by PARSE-FORMAT-OPERATION. PARMVAR is the list of parameters. PARMDEFS is a list of lists of the form (<var> <default>) . The FORMS are evaluated in an environment where each <var> is bound to either the value of the parameter supplied in the parameter list, or to its <default> value if the parameter was omitted or explicitly defaulted.")   (CL:DO ((PARMDEFS PARMDEFS (CDR PARMDEFS))           (BINDINGS NIL (CONS (BQUOTE ((\, (CAAR PARMDEFS))                                        (OR (CL:IF (\, PARMVAR)                                                   (POP (\, PARMVAR)))                                            (\, (CADAR PARMDEFS)))))                               BINDINGS)))          ((NULL PARMDEFS)           (BQUOTE (LET (\, (NREVERSE BINDINGS))                        (CL:WHEN (\, PARMVAR)                               (FORMAT-ERROR "Too many parameters"))                        (\,@ FORMS))))))(DEFMACRO NEXTCHAR NIL                     (* Gets the next character from the current control string.          It is an error if there is none. Leave *format-index* pointing to the character           returned. *)                       (QUOTE (CL:IF (< (INCF *FORMAT-INDEX*)                                      *FORMAT-LENGTH*)                                     (SCHAR *FORMAT-CONTROL-STRING* *FORMAT-INDEX*)                                     (FORMAT-ERROR "Syntax error"))))(DEFMACRO FORMAT-PEEK NIL                                    (* Returns the current character, i.e.                                                             the one pointed to by *format-index*.                                                             *)                          (QUOTE (SCHAR *FORMAT-CONTROL-STRING* *FORMAT-INDEX*)))(DEFMACRO FORMAT-FIND-CHAR (CHAR START END)                     (* Returns the index of the first occurrence of the specified character between           indices START (inclusive) and END (exclusive) in the control string.          *) (BQUOTE (CL:POSITION (\, CHAR)                (THE SIMPLE-STRING *FORMAT-CONTROL-STRING*)                :START                (\, START)                :END                (\, END)                :TEST                (FUNCTION CHAR=))))(DEFUN FORMAT-GET-PARAMETER NIL                              (* amd "25-Apr-86 18:44")                    (* Attempts to parse a parameter, starting at the current index.          Returns the value of the parameter, or NIL if none is found.          On exit, *format-index* points to the first character which is not a part of           the recognized parameter. *)                                (LET ((NUMSIGN (CASE (FORMAT-PEEK)                                                     (|\+ (NEXTCHAR)                                                          NIL)                                                     (|\- (NEXTCHAR)                                                          T)                                                     (T NIL))))                                     (CASE (FORMAT-PEEK)                                           (|\# (NEXTCHAR)                                                (CL:LENGTH *FORMAT-ARGUMENTS*))                                           ((|\V |\v)                                            (PROG1 (POP-FORMAT-ARG)                                                   (NEXTCHAR)))                                           (|\' (PROG1 (NEXTCHAR)                                                       (NEXTCHAR)))                                           ((|\0 |\1 |\2 |\3 |\4 |\5 |\6 |\7 |\8 |\9)                                            (CL:DO* ((NUMBER (DIGIT-CHAR-P (FORMAT-PEEK))                                                            (+ (CL:* 10 NUMBER)                                                               (DIGIT-CHAR-P (FORMAT-PEEK)))))                                                   ((NOT (DIGIT-CHAR-P (NEXTCHAR)))                                                    (CL:IF NUMSIGN (- NUMBER)                                                           NUMBER))))                                           (T NIL))))(DEFUN PARSE-FORMAT-OPERATION NIL                            (* amd " 1-May-86 14:33")                    (* Parses a format directive, including flags and parameters.          On entry, *format-index* should point to the "~" preceding the command.          On exit, *format-index* points to the command character itself.          Returns the list of parameters, the ":" flag, the "@" flag, and the command           character as multiple values. Explicitly defaulted parameters appear in the           list of parameters as NIL. Omitted parameters are simply not included in the           list at all. *)                                  (LET ((CH (NEXTCHAR)))                                       (VALUES (CL:IF (OR (DIGIT-CHAR-P CH)                                                          (CL:MEMBER CH                                                                 (QUOTE (|\, |\# |\V |\v |\'))                                                                 :TEST                                                                 (FUNCTION CHAR=)))                                                      (CL:DO ((PARMS (LIST (FORMAT-GET-PARAMETER))                                                                     (CONS (FORMAT-GET-PARAMETER)                                                                           PARMS)))                                                             ((CHAR/= (FORMAT-PEEK)                                                                     |\,)                                                              (NREVERSE PARMS))                                                             (NEXTCHAR))                                                      (QUOTE NIL))                                              (CL:IF (CHAR= (FORMAT-PEEK)                                                            |\:)                                                     (NEXTCHAR)                                                     NIL)                                              (CL:IF (CHAR= (FORMAT-PEEK)                                                            |\@)                                                     (NEXTCHAR)                                                     NIL)                                              (FORMAT-PEEK))))(DEFUN FORMAT-FIND-COMMAND (COMMAND-LIST)                    (* jrb: "15-May-86 14:53")                    (* Starting at the current value of *format-index*, finds the first occurrence           of one of the specified directives. Embedded constructs, i.e.          those inside ~ (~) %%, ~%[~%], ~{~}, or ~<~>, are ignored.          And error is signalled if no satisfactory command is found.          Otherwise, the following are returned as multiple values: The value of           *format-index* at the start of the search The index of the "~" character           preceding the command The parameter list of the command The ":" flag The "@"           flag The command character Implementation note: The present implementation is           not particulary careful with storage allocation.          It would be a good idea to have a separate function for skipping embedded           constructs which did not bother to cons parameter lists and then throw them           away. We go to some trouble here to use CL:POSITION for most of the searching.          *)   (LET ((START *FORMAT-INDEX*))        (CL:DO ((PLACE START *FORMAT-INDEX*)                (TILDE (FORMAT-FIND-CHAR |\~ START *FORMAT-LENGTH*)                       (FORMAT-FIND-CHAR |\~ PLACE *FORMAT-LENGTH*)))               ((NOT TILDE)                (FORMAT-ERROR "Expecting one of ~S" COMMAND-LIST))               (SETQ *FORMAT-INDEX* TILDE)               (MULTIPLE-VALUE-BIND (PARMS COLON ATSIGN COMMAND)                      (PARSE-FORMAT-OPERATION)                      (CL:WHEN (MEMBER COMMAND COMMAND-LIST :TEST (FUNCTION CHAR=))                             (RETURN (VALUES START TILDE PARMS COLON ATSIGN COMMAND)))                      NIL                      (CASE COMMAND (|\{ (NEXTCHAR)                                         (FORMAT-FIND-COMMAND (QUOTE (|\}))))                            (|\< (NEXTCHAR)                                 (FORMAT-FIND-COMMAND (QUOTE (|\>))))                            (|\( (NEXTCHAR)                                 (FORMAT-FIND-COMMAND (QUOTE (|\)))))                            (|\[ (NEXTCHAR)                                 (FORMAT-FIND-COMMAND (QUOTE (|\]))))                            ((|\} |\> |\) |\])                             (FORMAT-ERROR "No matching bracket")))))))(DEFUN FORMAT (DESTINATION CONTROL-STRING &REST FORMAT-ARGUMENTS)                                                              (* amd " 5-May-86 20:03")   (LET ((*FORMAT-ORIGINAL-ARGUMENTS* FORMAT-ARGUMENTS)         (*FORMAT-ARGUMENTS* FORMAT-ARGUMENTS)         (*FORMAT-CONTROL-STRING* (CL:IF (SIMPLE-STRING-P CONTROL-STRING)                                         CONTROL-STRING                                         (COERCE CONTROL-STRING (QUOTE SIMPLE-STRING)))))        (COND           ((NOT DESTINATION)            (FORMAT-STRINGIFY-OUTPUT (CATCH (QUOTE FORMAT-ESCAPE)                                            (CATCH (QUOTE FORMAT-COLON-ESCAPE)                                                   (SUB-FORMAT 0 (CL:LENGTH CONTROL-STRING))))))           ((AND (CL:STRINGP DESTINATION)                 (ARRAY-HAS-FILL-POINTER-P DESTINATION))            (WITH-OUTPUT-TO-STRING (*STANDARD-OUTPUT* DESTINATION)                   (CATCH (QUOTE FORMAT-ESCAPE)                          (CATCH (QUOTE FORMAT-COLON-ESCAPE)                                 (SUB-FORMAT 0 (CL:LENGTH CONTROL-STRING)))))            NIL)           (T (LET ((*STANDARD-OUTPUT* (CL:IF (EQ DESTINATION T)                                              *STANDARD-OUTPUT* DESTINATION)))                   (CATCH (QUOTE FORMAT-ESCAPE)                          (CATCH (QUOTE FORMAT-COLON-ESCAPE)                                 (SUB-FORMAT 0 (CL:LENGTH CONTROL-STRING))))                   NIL)))))(DEFUN SUB-FORMAT (START END)                                (* amd " 2-May-86 16:39")                    (* This function does the real work of format.          The segment of the control string between indiced START          (inclusive) and END (exclusive) is processed as follows: Text not part of a           directive is output without further processing.          Directives are parsed along with their parameters and flags, and the           appropriate handlers invoked with the arguments COLON, ATSIGN, and PARMS.          Implementation Note: FORMAT-FIND-CHAR uses the CL:POSITION stream operation for           speed. This is potentially faster than character-at-a-time searching.          *)   (LET ((*FORMAT-INDEX* START)         (*FORMAT-LENGTH* END))        (DECLARE (SPECVARS *FORMAT-INDEX* *FORMAT-LENGTH*))        (CL:DO* ((PLACE START *FORMAT-INDEX*)                 (TILDE (FORMAT-FIND-CHAR |\~ START END)                        (FORMAT-FIND-CHAR |\~ PLACE END)))               ((NOT TILDE)                (WRITE-STRING *FORMAT-CONTROL-STRING* *STANDARD-OUTPUT* :START PLACE :END END))               (CL:WHEN (> TILDE PLACE)                      (WRITE-STRING *FORMAT-CONTROL-STRING* *STANDARD-OUTPUT* :START PLACE :END TILDE                             ))               (SETQ *FORMAT-INDEX* TILDE)               (MULTIPLE-VALUE-BIND (PARMS COLON ATSIGN COMMAND)                      (PARSE-FORMAT-OPERATION)                      (LET ((CMDFUN (SVREF *FORMAT-DISPATCH-TABLE* (CHAR-CODE COMMAND))))                           (CL:IF CMDFUN (FUNCALL CMDFUN COLON ATSIGN PARMS)                                  (FORMAT-ERROR "Illegal FORMAT command ~~~C" COMMAND))))               (CL:UNLESS (< (INCF *FORMAT-INDEX*)                           END)                      (RETURN)))))(DEFUN FORMAT-CAPITALIZATION (COLON ATSIGN PARMS)            (* amd " 2-May-86 18:53")   (CL:WHEN PARMS (FORMAT-ERROR "No parameters allowed to ~~("))   (NEXTCHAR)   (MULTIPLE-VALUE-BIND (PREV TILDE END-PARMS END-COLON END-ATSIGN)          (FORMAT-FIND-COMMAND (QUOTE (|\))))          (CL:WHEN (OR END-PARMS END-COLON END-ATSIGN)                 (FORMAT-ERROR "Flags or parameters not allowed"))          (LET* ((ESCAPE NIL)                 (STRING (FORMAT-STRINGIFY-OUTPUT (SETQ ESCAPE (QUOTE FORMAT-COLON-ESCAPE))                                (CATCH (QUOTE FORMAT-COLON-ESCAPE)                                       (LET ((SUB-ESCAPE (QUOTE FORMAT-ESCAPE)))                                            (CATCH (QUOTE FORMAT-ESCAPE)                                                   (SUB-FORMAT PREV TILDE)                                                   (SETQ SUB-ESCAPE NIL))                                            (CL:SETQ ESCAPE SUB-ESCAPE))))))                (WRITE-STRING (COND                                 ((AND ATSIGN COLON)                                  (NSTRING-UPCASE STRING))                                 (COLON (NSTRING-CAPITALIZE STRING))                                 (ATSIGN (LET ((STRLEN (CL:LENGTH STRING)))                                                             (* Capitalize the first word only *)                                              (NSTRING-DOWNCASE STRING)                                              (CL:DO ((I 0 (1+ I)))                                                     ((OR (<= STRLEN I)                                                          (ALPHA-CHAR-P (CHAR STRING I)))                                                      (SETF (CHAR STRING I)                                                            (CHAR-UPCASE (CHAR STRING I)))                                                      STRING))))                                 (T (NSTRING-DOWNCASE STRING))))                (AND ESCAPE (THROW ESCAPE NIL)))))(DEFUN FORMAT-ESCAPE (COLON ATSIGN PARMS)                    (* Up and Out (Escape) ~^ *)   (CL:WHEN ATSIGN (FORMAT-ERROR "FORMAT command ~~~:[~;:~]@^ is undefined" COLON))   (CL:WHEN (CL:IF (CL:FIRST PARMS)                   (CL:IF (SECOND PARMS)                          (CL:IF (THIRD PARMS)                                 (TYPECASE (SECOND PARMS)                                        (INTEGER (<= (CL:FIRST PARMS)                                                  (SECOND PARMS)                                                  (THIRD PARMS)))                                        (CL:CHARACTER (CHAR< (CL:FIRST PARMS)                                                          (SECOND PARMS)                                                          (THIRD PARMS)))                                        (T NIL))                                 (EQUAL (CL:FIRST PARMS)                                        (SECOND PARMS)))                          (ZEROP (CL:FIRST PARMS)))                   (NOT *FORMAT-ARGUMENTS*))          (THROW (CL:IF COLON (QUOTE FORMAT-COLON-ESCAPE)                        (QUOTE FORMAT-ESCAPE))                 NIL)))(DEFUN FORMAT-SEMICOLON-ERROR (COLON ATSIGN PARAMS)          (* amd " 2-May-86 17:32")   (DECLARE (IGNORE COLON ATSIGN PARAMS))   (FORMAT-ERROR "Unexpected semicolon (probably a missing ~~ somewhere)."))(DEFUN FORMAT-UNTAGGED-CONDITION NIL                         (* jrb: "19-May-86 21:53")                                                             (* ~%[ *)                                     (LET ((TEST (POP-FORMAT-ARG)))                                          (CL:UNLESS (INTEGERP TEST)                                                 (FORMAT-ERROR "Argument to ~~[ must be integer - ~S"                                                         TEST))                                          (CL:DO ((CL:COUNT 0 (1+ CL:COUNT)))                                                 ((= CL:COUNT TEST)                                                  (MULTIPLE-VALUE-BIND (PREV TILDE PARMS COLON ATSIGN                                                                              CMD)                                                         (FORMAT-FIND-COMMAND (QUOTE (|\; |\])))                                                         (DECLARE (IGNORE COLON))                                                         (CL:WHEN ATSIGN (FORMAT-ERROR                                                                             "Atsign flag not allowed"                                                                                ))                                                         (CL:WHEN PARMS (FORMAT-ERROR                                                                               "No parameters allowed"                                                                               ))                                                         (SUB-FORMAT PREV TILDE)                                                         (CL:UNLESS (CHAR= CMD |\])                                                                (FORMAT-FIND-COMMAND (QUOTE (|\])))))                                                  )                                                 (MULTIPLE-VALUE-BIND                                                  (PREV TILDE PARMS COLON ATSIGN CMD)                                                  (FORMAT-FIND-COMMAND (QUOTE (|\; |\])))                                                  (DECLARE (IGNORE PREV TILDE))                                                  (CL:WHEN ATSIGN (FORMAT-ERROR                                                                          "Atsign flag not allowed"))                                                  (CL:WHEN PARMS (FORMAT-ERROR                                                                         "Parameters not allowed"))                                                  (CL:WHEN (CHAR= CMD |\])                                                         (RETURN))                                                  (CL:WHEN COLON (NEXTCHAR)                                                         (MULTIPLE-VALUE-BIND                                                          (PREV TILDE PARMS COLON ATSIGN CMD)                                                          (FORMAT-FIND-COMMAND (QUOTE (|\; |\])))                                                          (DECLARE (IGNORE PARMS COLON ATSIGN))                                                          (SUB-FORMAT PREV TILDE)                                                          (CL:UNLESS (CHAR= CMD |\])                                                                 (FORMAT-FIND-COMMAND (QUOTE (|\]))))                                                          )                                                         (RETURN))                                                  (NEXTCHAR)))))(DEFUN FORMAT-FUNNY-CONDITION NIL                            (* jrb: "19-May-86 21:51")                                                             (* ~@%[ *)                                  (MULTIPLE-VALUE-BIND (PREV TILDE PARMS COLON ATSIGN)                                         (FORMAT-FIND-COMMAND (QUOTE (|\])))                                         (CL:WHEN (OR COLON ATSIGN PARMS)                                                (FORMAT-ERROR "Flags or arguments not allowed"))                                         (CL:IF *FORMAT-ARGUMENTS* (CL:IF (CAR *FORMAT-ARGUMENTS*)                                                                          (SUB-FORMAT PREV TILDE)                                                                          (CL:POP *FORMAT-ARGUMENTS*)                                                                          )                                                (FORMAT-ERROR "Missing argument"))))(DEFUN FORMAT-BOOLEAN-CONDITION NIL                          (* amd " 1-May-86 16:48")                                                             (* ~:%[ *)                                    (MULTIPLE-VALUE-BIND (PREV TILDE PARMS COLON ATSIGN)                                           (FORMAT-FIND-COMMAND (QUOTE (|\;)))                                           (CL:WHEN (OR PARMS COLON ATSIGN)                                                  (FORMAT-ERROR "Flags or parameters not allowed"))                                           (NEXTCHAR)                                           (CL:IF (POP-FORMAT-ARG)                                                  (MULTIPLE-VALUE-BIND (PREV TILDE PARMS COLON ATSIGN                                                                             )                                                         (FORMAT-FIND-COMMAND (QUOTE (|\])))                                                         (CL:WHEN (OR COLON ATSIGN PARMS)                                                                (FORMAT-ERROR                                                                     "Flags or parameters not allowed"                                                                       ))                                                         (SUB-FORMAT PREV TILDE))                                                  (PROGN (SUB-FORMAT PREV TILDE)                                                         (FORMAT-FIND-COMMAND (QUOTE (|\])))))))(DEFUN FORMAT-CONDITION (COLON ATSIGN PARMS) (CL:WHEN PARMS (CL:PUSH (POP PARMS)                                                                   *FORMAT-ARGUMENTS*)                                                    (CL:UNLESS (NULL PARMS)                                                           (FORMAT-ERROR "Too many parameters to ~[")                                                           ))                                             (NEXTCHAR)                                             (COND                                                (COLON (CL:WHEN ATSIGN (FORMAT-ERROR                                                                               "~~:@[ undefined"))                                                       (FORMAT-BOOLEAN-CONDITION))                                                (ATSIGN (FORMAT-FUNNY-CONDITION))                                                (T (FORMAT-UNTAGGED-CONDITION))))(DEFUN FORMAT-ITERATION (COLON ATSIGN PARMS)                 (* ;; "Iteration ~{ ... ~}")   (WITH-FORMAT-PARAMETERS PARMS ((MAX-ITER -1))          (NEXTCHAR)          (MULTIPLE-VALUE-BIND (PREV TILDE END-PARMS END-COLON END-ATSIGN)                 (FORMAT-FIND-COMMAND (QUOTE (|\})))                 (CL:WHEN (OR END-ATSIGN END-PARMS)                        (FORMAT-ERROR "Illegal terminator for ~~{"))                 (CL:IF (= PREV TILDE)                        (LET ((STRING (POP-FORMAT-ARG)))                                                  (* ;;                                              "Use an argument as the control string if ~{~} is empty")                             (CL:UNLESS (CL:STRINGP STRING)                                    (FORMAT-ERROR "Control string is not a string"))                             (FORMAT-WITH-CONTROL-STRING STRING (FORMAT-DO-ITERATION 0                                                                        *FORMAT-LENGTH* MAX-ITER COLON                                                                        ATSIGN END-COLON)))                        (FORMAT-DO-ITERATION PREV TILDE MAX-ITER COLON ATSIGN END-COLON)))))(DEFUN FORMAT-DO-ITERATION (START END MAX-ITER COLON ATSIGN AT-LEAST-ONCE-P)                                                              (* jrb: "19-May-86 22:14")                    (* The two catch tags FORMAT-ESCAPE and FORMAT-COLON-ESCAPE are needed here to           correctly implement ~^ and ~:^. The former aborts only the current iteration,           but the latter aborts the entire iteration process.          *)   (CATCH (QUOTE FORMAT-COLON-ESCAPE)          (CATCH (QUOTE FORMAT-ESCAPE)                 (CL:IF ATSIGN (CL:DO ((CL:COUNT 0 (1+ CL:COUNT)))                                      ((OR (= CL:COUNT MAX-ITER)                                           (AND (NULL *FORMAT-ARGUMENTS*)                                                (CL:IF (= CL:COUNT 0)                                                       (NOT AT-LEAST-ONCE-P)                                                       T))))                                      (CATCH (QUOTE FORMAT-ESCAPE)                                             (CL:IF COLON (LET* ((*ORIGINAL-ARGUMENTS* (                                                                                       POP-FORMAT-ARG                                                                                        ))                                                                 (*FORMAT-ARGUMENTS*                                                                         *ORIGINAL-ARGUMENTS*))                                                                (CL:UNLESS (CL:LISTP                                                                                   *FORMAT-ARGUMENTS*)                                                                       (FORMAT-ERROR                                                                             "Argument must be a list"                                                                              ))                                                                (SUB-FORMAT START END))                                                    (SUB-FORMAT START END))))                        (LET* ((*ORIGINAL-ARGUMENTS* (POP-FORMAT-ARG))                               (*FORMAT-ARGUMENTS* *ORIGINAL-ARGUMENTS*))                              (CL:UNLESS (CL:LISTP *FORMAT-ARGUMENTS*)                                     (FORMAT-ERROR "Argument must be a list"))                              (CL:DO ((CL:COUNT 0 (1+ CL:COUNT)))                                     ((OR (= CL:COUNT MAX-ITER)                                          (AND (NULL *FORMAT-ARGUMENTS*)                                               (CL:IF (= CL:COUNT 0)                                                      (NOT AT-LEAST-ONCE-P)                                                      T))))                                     (CATCH (QUOTE FORMAT-ESCAPE)                                            (CL:IF COLON (LET* ((*ORIGINAL-ARGUMENTS* (POP-FORMAT-ARG                                                                                       ))                                                                (*FORMAT-ARGUMENTS*                                                                        *ORIGINAL-ARGUMENTS*))                                                               (CL:UNLESS (CL:LISTP                                                                                  *FORMAT-ARGUMENTS*)                                                                      (FORMAT-ERROR                                                                    "Argument must be a list of lists"                                                                             ))                                                               (SUB-FORMAT START END))                                                   (SUB-FORMAT START END)))))))))(DEFUN FORMAT-GET-TRAILING-SEGMENTS NIL                     (* Parses a list of clauses delimited by ~ and terminated by ~>.          Recursively invoke SUB-FORMAT to process them, and return a list of the           results, the length of this list, and the total number of characters in the           strings composing the list. *)                                        (NEXTCHAR)                                        (MULTIPLE-VALUE-BIND                                         (PREV TILDE COLON ATSIGN PARMS CMD)                                         (FORMAT-FIND-COMMAND (QUOTE (|\; |\>)))                                         (CL:WHEN COLON (FORMAT-ERROR                                                        "~~:; allowed only after first segment in ~~<"                                                               ))                                         (CL:WHEN (OR ATSIGN PARMS)                                                (FORMAT-ERROR "Flags and parameters not allowed"))                                         (LET ((STR (CATCH (QUOTE FORMAT-ESCAPE)                                                           (FORMAT-STRINGIFY-OUTPUT (SUB-FORMAT                                                                                     PREV TILDE)))))                                              (CL:IF STR (CL:IF (CHAR= CMD |\;)                                                                (MULTIPLE-VALUE-BIND                                                                 (SEGMENTS NUMSEGS NUMCHARS)                                                                 (FORMAT-GET-TRAILING-SEGMENTS)                                                                 (VALUES (CONS STR SEGMENTS)                                                                        (1+ NUMSEGS)                                                                        (+ NUMCHARS (CL:LENGTH STR)))                                                                 )                                                                (VALUES (LIST STR)                                                                       1                                                                       (CL:LENGTH STR)))                                                     (VALUES NIL 0 0)))))(DEFUN FORMAT-GET-SEGMENTS NIL                               (* Gets the first segment, which is                                                              treated specially. Call                                                              FORMAT-GET-TRAILING-SEGMENTS to get                                                              the rest. *)                               (MULTIPLE-VALUE-BIND                                (PREV TILDE PARMS COLON ATSIGN CMD)                                (FORMAT-FIND-COMMAND (QUOTE (|\; |\>)))                                (CL:WHEN ATSIGN (FORMAT-ERROR "Atsign flag not allowed"))                                (LET ((FIRST-SEG (FORMAT-STRINGIFY-OUTPUT (SUB-FORMAT PREV TILDE))))                                     (CL:IF (CHAR= CMD |\;)                                            (MULTIPLE-VALUE-BIND (SEGMENTS NUMSEGS NUMCHARS)                                                   (FORMAT-GET-TRAILING-SEGMENTS)                                                   (CL:IF COLON (VALUES FIRST-SEG PARMS SEGMENTS                                                                        NUMSEGS NUMCHARS)                                                          (VALUES NIL NIL (CONS FIRST-SEG SEGMENTS)                                                                 (1+ NUMSEGS)                                                                 (+ (CL:LENGTH FIRST-SEG)                                                                    NUMCHARS))))                                            (VALUES NIL NIL (LIST FIRST-SEG)                                                   1                                                   (CL:LENGTH FIRST-SEG))))))(DEFUN MAKE-PAD-SEGS (SPACES PADDINGS)                       (* amd " 1-May-86 16:30")                    (* Given the total number of SPACES needed for padding, and the number of           padding segments needed (PADDINGS) %%, returns a list of such segments.          We try to allocate the spaces equally to each segment.          When this is not possible, we allocate the left-over spaces randomly, to           improve the appearance of many successive lines of justified text.          Query: Is this right? Perhaps consistency might be better for the kind of           applications ~<~> is used for. *)   (CL:DO* ((EXTRA-SPACE NIL (AND (PLUSP EXTRA-SPACES)                                  (< (RAND 0 (FLOAT 1))                                   (/ SEGS EXTRA-SPACES))))            (RESULT NIL (CONS (CL:IF EXTRA-SPACE (1+ MIN-SPACE)                                     MIN-SPACE)                              RESULT))            (MIN-SPACE (TRUNCATE SPACES PADDINGS))            (EXTRA-SPACES (- SPACES (CL:* PADDINGS MIN-SPACE))                   (CL:IF EXTRA-SPACE (1- EXTRA-SPACES)                          EXTRA-SPACES))            (SEGS PADDINGS (1- SEGS)))          ((ZEROP SEGS)           RESULT)))(DEFUN FORMAT-ROUND-COLUMNS (WIDTH MINCOL COLINC)            (* jrb: "15-May-86 17:56")                    (* Determine the actual width to be used for a field requiring WIDTH characters           according to the following rule: If WIDTH is less than or equal to MINCOL, use           WIDTH as the actual width. Otherwise, round up to MINCOL + k CL:* COLINC for           the smallest possible positive integer k.          *)   (CL:IF (> WIDTH MINCOL)          WIDTH          (+ WIDTH (CL:* COLINC (CEILING (- MINCOL WIDTH)                                       COLINC)))))(DEFUN FORMAT-JUSTIFICATION (COLON ATSIGN PARMS)   (WITH-FORMAT-PARAMETERS PARMS ((MINCOL 0)                                  (COLINC 1)                                  (MINPAD 0)                                  (PADCHAR |\Space))          (CL:UNLESS (AND (INTEGERP MINCOL)                          (NOT (MINUSP MINCOL)))                 (FORMAT-ERROR "Mincol must be a non-negative integer - ~S" MINCOL))          (CL:UNLESS (AND (INTEGERP COLINC)                          (PLUSP COLINC))                 (FORMAT-ERROR "Colinc must be a positive integer - ~S" COLINC))          (CL:UNLESS (AND (INTEGERP MINPAD)                          (NOT (MINUSP MINPAD)))                 (FORMAT-ERROR "Minpad must be a non-negative integer - ~S" MINPAD))          (CL:UNLESS (CHARACTERP PADCHAR)                 (FORMAT-ERROR "Padchar must be a character - ~S" PADCHAR))          (NEXTCHAR)          (MULTIPLE-VALUE-BIND (SPECIAL-ARG SPECIAL-PARMS SEGMENTS NUMSEGS NUMCHARS)                 (FORMAT-GET-SEGMENTS)                 (LET* ((PADSEGS (+ (CL:IF (OR COLON (= NUMSEGS 1))                                           1 0)                                    (1- NUMSEGS)                                    (CL:IF ATSIGN 1 0)))                        (WIDTH (FORMAT-ROUND-COLUMNS (+ NUMCHARS (CL:* MINPAD PADSEGS))                                      MINCOL COLINC))                        (SPACES (APPEND (CL:IF (OR COLON (= NUMSEGS 1))                                               NIL                                               (QUOTE (0)))                                       (MAKE-PAD-SEGS (- WIDTH NUMCHARS)                                              PADSEGS)                                       (CL:IF ATSIGN NIL (QUOTE (0))))))                       (CL:WHEN SPECIAL-ARG (WITH-FORMAT-PARAMETERS                                             SPECIAL-PARMS                                             ((SPARE 0)                                              (LINEL (OR (LINE-LENGTH)                                                         72)))                                             (LET ((POS (OR (CHARPOS *STANDARD-OUTPUT*)                                                            0)))                                                  (CL:WHEN (> (+ POS WIDTH SPARE)                                                              LINEL)                                                         (WRITE-STRING SPECIAL-ARG)))))                       (CL:DO ((SEGS SEGMENTS (CDR SEGS))                               (SPCS SPACES (CDR SPCS)))                              ((NULL SEGS)                               (DOTIMES (I (CAR SPCS))                                      (WRITE-CHAR PADCHAR)))                              (DOTIMES (I (CAR SPCS))                                     (WRITE-CHAR PADCHAR))                              (WRITE-STRING (CAR SEGS)))))))(DEFUN FORMAT-TERPRI (COLON ATSIGN PARMS)                    (* amd " 1-May-86 16:20")                                                             (* Newline ~& *)   (CL:WHEN (OR COLON ATSIGN)          (FORMAT-ERROR "Flags not allowed"))   (WITH-FORMAT-PARAMETERS PARMS ((REPEAT-COUNT 1))          (DOTIMES (I REPEAT-COUNT)                 (TERPRI *STANDARD-OUTPUT*))))(DEFUN FORMAT-FRESHLINE (COLON ATSIGN PARMS)                 (* amd " 5-May-86 19:28")                                                             (* Fresh-line ~%% *)   (CL:WHEN (OR COLON ATSIGN)          (FORMAT-ERROR "Flags not allowed"))   (WITH-FORMAT-PARAMETERS PARMS ((REPEAT-COUNT 1))          (FRESH-LINE *STANDARD-OUTPUT*)          (DOTIMES (I (1- REPEAT-COUNT))                 (TERPRI *STANDARD-OUTPUT*))))(DEFUN FORMAT-PAGE (COLON ATSIGN PARMS)                      (* " Page  ~|" *)   (CL:WHEN (OR COLON ATSIGN)          (FORMAT-ERROR "Flags not allowed"))   (WITH-FORMAT-PARAMETERS PARMS ((REPEAT-COUNT 1))          (DOTIMES (I REPEAT-COUNT)                 (WRITE-CHAR |\Page))))(DEFUN FORMAT-TILDE (COLON ATSIGN PARMS)                     (* Print a tilde ~~ *)   (CL:WHEN (OR COLON ATSIGN)          (FORMAT-ERROR "Flags not allowed"))   (WITH-FORMAT-PARAMETERS PARMS ((REPEAT-COUNT 1))          (DOTIMES (I REPEAT-COUNT)                 (WRITE-CHAR |\~))))(DEFUN FORMAT-EAT-WHITESPACE NIL                             (* jrb: "19-May-86 11:11")                                                             (* Continue control string on next                                                              line ~<newline> *)                                 (NEXTCHAR)                                 (SETQ *FORMAT-INDEX* (LET ((NEXT-NON-WHITE (POSITION-IF-NOT                                                                             (CL:FUNCTION                                                                                     WHITESPACE-CHAR-P                                                                                    )                                                                             *FORMAT-CONTROL-STRING*                                                                              :START *FORMAT-INDEX*)))                                                           (CL:IF NEXT-NON-WHITE (1- NEXT-NON-WHITE)                                                                  (CL:LENGTH *FORMAT-CONTROL-STRING*)                                                                  ))))(DEFUN FORMAT-NEWLINE (COLON ATSIGN PARMS)                   (* jrb: "19-May-86 15:08")   (CL:WHEN PARMS (FORMAT-ERROR "Parameters not allowed"))   (COND      (COLON (CL:WHEN ATSIGN (FORMAT-ERROR "~:@<newline> is undefined")))      (ATSIGN (TERPRI *STANDARD-OUTPUT*)                    (* * "The *standard-output* should go away when TERPRI is fixed")             (FORMAT-EAT-WHITESPACE))      (T (FORMAT-EAT-WHITESPACE))))(DEFUN FORMAT-PLURAL (COLON ATSIGN PARMS)                    (* Pluralize word ~P *)   (CL:WHEN PARMS (FORMAT-ERROR "Parameters not allowed"))   (CL:WHEN COLON                                            (* Back up one argument first *)          (LET ((CDRS (- (CL:LENGTH *FORMAT-ORIGINAL-ARGUMENTS*)                         (CL:LENGTH *FORMAT-ARGUMENTS*)                         1)))               (CL:IF (MINUSP CDRS)                      (FORMAT-ERROR "No previous argument")                      (SETQ *FORMAT-ARGUMENTS* (NTHCDR CDRS *FORMAT-ORIGINAL-ARGUMENTS*)))))   (CL:IF (EQL (POP-FORMAT-ARG)               1)          (WRITE-STRING (CL:IF ATSIGN "y" ""))          (WRITE-STRING (CL:IF ATSIGN "ies" "s"))))(DEFUN FORMAT-SKIP-ARGUMENTS (COLON ATSIGN PARMS)            (* jrb: "19-May-86 22:15")                                                             (* Skip arguments (relative goto) ~* *)   (WITH-FORMAT-PARAMETERS PARMS ((CL:COUNT 1))          (COND             (ATSIGN (CL:WHEN (OR (MINUSP CL:COUNT)                                  (> CL:COUNT (CL:LENGTH *FORMAT-ORIGINAL-ARGUMENTS*)))                            (FORMAT-ERROR "Illegal to go to non-existant argument"))                    (SETQ *FORMAT-ARGUMENTS* (NTHCDR CL:COUNT *FORMAT-ORIGINAL-ARGUMENTS*)))             (COLON (LET ((CDRS (- (CL:LENGTH *FORMAT-ORIGINAL-ARGUMENTS*)                                   (CL:LENGTH *FORMAT-ARGUMENTS*)                                   CL:COUNT)))                         (CL:IF (MINUSP CDRS)                                (FORMAT-ERROR "Skip to nonexistant argument")                                (SETQ *FORMAT-ARGUMENTS* (NTHCDR CDRS *FORMAT-ORIGINAL-ARGUMENTS*))))                    )             (T (CL:IF (> CL:COUNT (CL:LENGTH *FORMAT-ARGUMENTS*))                       (FORMAT-ERROR "Skip to nonexistant argument")                       (SETQ *FORMAT-ARGUMENTS* (NTHCDR CL:COUNT *FORMAT-ARGUMENTS*)))))))(DEFUN FORMAT-INDIRECTION (COLON ATSIGN PARMS)               (* ;; "Indirection ~?")   (CL:WHEN COLON (FORMAT-ERROR "Colon modifier not allowed"))   (CL:WHEN PARMS (FORMAT-ERROR "Parameters not allowed"))   (LET ((STRING (POP-FORMAT-ARG)))        (CL:UNLESS (CL:STRINGP STRING)               (FORMAT-ERROR "Indirected control string is not a string"))        (FORMAT-WITH-CONTROL-STRING STRING (CL:IF ATSIGN (SUB-FORMAT 0 *FORMAT-LENGTH*)                                                  (LET ((*FORMAT-ARGUMENTS* (POP-FORMAT-ARG)))                                                       (SUB-FORMAT 0 *FORMAT-LENGTH*))))))(DEFUN FORMAT-TAB (COLON ATSIGN PARMS)                       (* jrb: "19-May-86 15:33")                                                             (* Tabulation ~T *)   (WITH-FORMAT-PARAMETERS    PARMS    ((COLNUM 1)     (COLINC 1))    (CL:WHEN COLON (FORMAT-ERROR "Tab-to in pixel units not supported"))    (DOTIMES (X (1- (LET ((POSITION (POSITION *STANDARD-OUTPUT*)))                         (COND                            (POSITION (LET ((TABCOL (CL:* COLINC (CEILING (CL:IF ATSIGN                                                                                 (+ POSITION COLNUM)                                                                                 COLNUM)                                                                        COLINC))))                                           (CL:IF (> POSITION TABCOL)                                                  (- COLINC (REM (- POSITION TABCOL)                                                                 COLINC))                                                  (- TABCOL POSITION))))                            (ATSIGN COLNUM)                            (T 2)))))           (WRITE-CHAR |\Space *STANDARD-OUTPUT*))))(DEFUN FORMAT-PRINC (COLON ATSIGN PARMS)                     (* amd " 1-May-86 15:19")                                                             (* Ascii ~A *)   (LET ((ARG (POP-FORMAT-ARG)))        (CL:IF (NULL PARMS)               (CL:IF ARG (PRINC ARG)                      (CL:IF COLON (WRITE-STRING "()")                             (PRINC NIL)))               (WITH-FORMAT-PARAMETERS PARMS ((MINCOL 0)                                              (COLINC 1)                                              (MINPAD 0)                                              (PADCHAR |\Space))                      (FORMAT-WRITE-FIELD (CL:IF ARG (PRINC-TO-STRING ARG)                                                 (CL:IF COLON "()" (PRINC-TO-STRING NIL)))                             MINCOL COLINC MINPAD PADCHAR ATSIGN)))))(DEFUN FORMAT-PRIN1 (COLON ATSIGN PARMS)                     (* S-expression ~S *)   (LET ((ARG (POP-FORMAT-ARG)))        (CL:IF (NULL PARMS)               (CL:IF ARG (CL:PRIN1 ARG)                      (CL:IF COLON (WRITE-STRING "()")                             (CL:PRIN1 NIL)))               (WITH-FORMAT-PARAMETERS PARMS ((MINCOL 0)                                              (COLINC 1)                                              (MINPAD 0)                                              (PADCHAR |\Space))                      (FORMAT-WRITE-FIELD (CL:IF ARG (PRIN1-TO-STRING ARG)                                                 (CL:IF COLON "()" (PRIN1-TO-STRING NIL)))                             MINCOL COLINC MINPAD PADCHAR ATSIGN)))))(DEFUN FORMAT-PRINT-CHARACTER (COLON ATSIGN PARMS)           (* Character ~C *)   (WITH-FORMAT-PARAMETERS PARMS NIL (LET ((CHAR (POP-FORMAT-ARG)))                                          (CL:UNLESS (CHARACTERP CHAR)                                                 (FORMAT-ERROR "Argument must be a character"))                                          (COND                                             ((AND ATSIGN (NOT COLON))                                              (CL:PRIN1 CHAR))                                             (T (FORMAT-PRINT-NAMED-CHARACTER CHAR COLON))))))(DEFUN FORMAT-PRINT-NAMED-CHARACTER (CHAR LONGP)             (* jrb: "16-May-86 10:56")                    (* (WRITE-STRING (COND ((CHAR-BIT CHAR :CONTROL)          (CL:IF LONGP "Control-" "C-")) ((CHAR-BIT CHAR :META)          (CL:IF LONGP "Meta-" "M-")) ((CHAR-BIT CHAR :SUPER)          (CL:IF LONGP "Super-" "S-")) ((CHAR-BIT CHAR :HYPER)          (CL:IF LONGP "Hyper-" "H-")) (T ""))))   (LET* ((CH (CODE-CHAR (CHAR-CODE CHAR)))          (NAME (CHAR-NAME CH)))                             (* The calls to CODE-CHAR and                                                              CHAR-CODE strip funny bits *)         (COND            (NAME (WRITE-STRING (STRING-CAPITALIZE (PRINC-TO-STRING NAME))))            ((<= 0 (CHAR-CODE CHAR)              31)                                            (* Print control characters as "^"                                                              <char> *)             (WRITE-CHAR |\^)             (WRITE-CHAR (CODE-CHAR (+ 64 (CHAR-CODE CHAR)))))            (T (WRITE-CHAR CH)))))(DEFUN FORMAT-ADD-COMMAS (STRING COMMACHAR)                  (* jrb: "16-May-86 11:12")                                                             (* Insert commas after every third                                                              digit, scanning from right to left.)                    (* * Signs don't count in the final length)   (CL:DO* ((LENGTH (CL:LENGTH (THE STRING STRING)))            (NEW-LENGTH (+ LENGTH (CL:FLOOR (- LENGTH (CL:IF (OR (EQL (CHAR STRING 0)                                                                      |\+)                                                                 (EQL (CHAR STRING 0)                                                                      |\-))                                                             2 1))                                         3)))            (NEW-STRING (MAKE-STRING NEW-LENGTH :INITIAL-ELEMENT COMMACHAR)                   (CL:REPLACE (THE STRING NEW-STRING)                          (THE STRING STRING)                          :START1                          (MAX 0 (- NEW-POS 3))                          :END1 NEW-POS :START2 (MAX 0 (- POS 3))                          :END2 POS))            (POS LENGTH (- POS 3))            (NEW-POS NEW-LENGTH (- NEW-POS 4)))          ((NOT (PLUSP POS))                                 (* If there was a sign, put it back                                                              now)           (CL:IF (OR (EQL (CHAR STRING 0)                           |\+)                      (EQL (CHAR STRING 0)                           |\-))                  (SETF (CHAR NEW-STRING 0)                        (CHAR STRING 0)))           NEW-STRING)))(DEFUN FORMAT-WRITE-FIELD (STRING MINCOL COLINC MINPAD PADCHAR PADLEFT)                     (* Output a string in a field at MINCOL wide, padding with PADCHAR.          Pads on the left if PADLEFT is true, else on the right.          If the length of the string plus the minimum permissible padding, MINPAD, is           greater than MINCOL, the actual field size is rounded up to MINCOL + k CL:*           COLINC for the smallest possible positive integer k.          *) (CL:UNLESS (AND (INTEGERP MINCOL)                 (NOT (MINUSP MINCOL)))        (FORMAT-ERROR "Mincol must be a non-negative integer - ~S" MINCOL)) (CL:UNLESS (AND (INTEGERP COLINC)                 (PLUSP COLINC))        (FORMAT-ERROR "Colinc must be a positive integer - ~S" COLINC)) (CL:UNLESS (AND (INTEGERP MINPAD)                 (NOT (MINUSP MINPAD)))        (FORMAT-ERROR "Minpad must be a non-negative integer - ~S" MINPAD)) (CL:UNLESS (CHARACTERP PADCHAR)        (FORMAT-ERROR "Padchar must be a character - ~S" PADCHAR)) (LET* ((STRLEN (CL:LENGTH (THE STRING STRING)))        (WIDTH (FORMAT-ROUND-COLUMNS (+ STRLEN MINPAD)                      MINCOL COLINC)))       (COND          (PADLEFT (DOTIMES (I (- WIDTH STRLEN))                          (WRITE-CHAR PADCHAR))                 (WRITE-STRING STRING))          (T (WRITE-STRING STRING)             (DOTIMES (I (- WIDTH STRLEN))                    (WRITE-CHAR PADCHAR))))))(DEFUN FORMAT-PRINT-NUMBER (NUMBER RADIX PRINT-COMMAS-P PRINT-SIGN-P PARMS)                                                              (* This functions does most of the                                                              work for the numeric printing                                                              directives. The parameters are                                                              interpreted as defined for ~D.                                                             *)   (WITH-FORMAT-PARAMETERS PARMS ((MINCOL 0)                                  (PADCHAR |\Space)                                  (COMMACHAR |\,))          (LET* ((*PRINT-BASE* RADIX)                 (TEXT (PRINC-TO-STRING NUMBER)))                (CL:IF (INTEGERP NUMBER)                       (PROGN                                (* colinc = 1, minpad = 0, padleft = t                                                              *)                              (FORMAT-WRITE-FIELD (CL:IF (AND (PLUSP NUMBER)                                                              PRINT-SIGN-P)                                                         (CL:IF PRINT-COMMAS-P                                                                (CONCATENATE (QUOTE STRING)                                                                       "+"                                                                       (FORMAT-ADD-COMMAS TEXT                                                                               COMMACHAR))                                                                (CONCATENATE (QUOTE STRING)                                                                       "+" TEXT))                                                         (CL:IF PRINT-COMMAS-P (FORMAT-ADD-COMMAS                                                                                TEXT COMMACHAR)                                                                TEXT))                                     MINCOL 1 0 PADCHAR T))                       (WRITE-STRING TEXT)))))(DEFUN FORMAT-PRINT-SMALL-CARDINAL (N)                       (* amd "23-Apr-86 20:12")   (MULTIPLE-VALUE-BIND (HUNDREDS REM)          (TRUNCATE N 100)          (CL:WHEN (PLUSP HUNDREDS)                 (WRITE-STRING (SVREF CARDINAL-ONES HUNDREDS))                 (WRITE-STRING " hundred")                 (CL:WHEN (PLUSP REM)                        (WRITE-CHAR |\Space)))          (CL:WHEN (PLUSP REM)                 (MULTIPLE-VALUE-BIND (TENS ONES)                        (TRUNCATE REM 10)                        (COND                           ((< 1 TENS)                            (WRITE-STRING (SVREF CARDINAL-TENS TENS))                            (CL:WHEN (PLUSP ONES)                                   (WRITE-CHAR |\-)                                   (WRITE-STRING (SVREF CARDINAL-ONES ONES))))                           ((= TENS 1)                            (WRITE-STRING (SVREF CARDINAL-TEENS ONES)))                           ((PLUSP ONES)                            (WRITE-STRING (SVREF CARDINAL-ONES ONES))))))))(DEFUN FORMAT-PRINT-CARDINAL (N) (COND                                    ((MINUSP N)                                     (WRITE-STRING "negative ")                                     (FORMAT-PRINT-CARDINAL-AUX (- N)                                            0 N))                                    ((ZEROP N)                                     (WRITE-STRING "zero"))                                    (T (FORMAT-PRINT-CARDINAL-AUX N 0 N))))(DEFUN FORMAT-PRINT-CARDINAL-AUX (N PERIOD ERR) (MULTIPLE-VALUE-BIND (BEYOND HERE)                                                       (TRUNCATE N 1000)                                                       (CL:UNLESS (<= PERIOD 10)                                                              (FORMAT-ERROR                                                           "Number too large to print in English: ~:D"                                                                      ERR))                                                       (CL:UNLESS (ZEROP BEYOND)                                                              (FORMAT-PRINT-CARDINAL-AUX BEYOND                                                                     (1+ PERIOD)                                                                     ERR))                                                       (CL:UNLESS (ZEROP HERE)                                                              (CL:UNLESS (ZEROP BEYOND)                                                                     (WRITE-CHAR |\Space))                                                              (FORMAT-PRINT-SMALL-CARDINAL HERE)                                                              (WRITE-STRING (SVREF CARDINAL-PERIODS                                                                                    PERIOD)))))(DEFUN FORMAT-PRINT-ORDINAL (N)                              (* amd "23-Apr-86 20:14")   (CL:WHEN (MINUSP N)          (WRITE-STRING "negative "))   (LET ((NUMBER (ABS N)))        (MULTIPLE-VALUE-BIND (TOP BOT)               (TRUNCATE NUMBER 100)               (CL:UNLESS (ZEROP TOP)                      (FORMAT-PRINT-CARDINAL (- NUMBER BOT)))               (CL:WHEN (AND (PLUSP TOP)                             (PLUSP BOT))                      (WRITE-CHAR |\Space))               (MULTIPLE-VALUE-BIND (TENS ONES)                      (TRUNCATE BOT 10)                      (COND                         ((= BOT 12)                          (WRITE-STRING "twelfth"))                         ((= TENS 1)                          (WRITE-STRING (SVREF CARDINAL-TEENS ONES))                          (WRITE-STRING "th"))                         ((AND (ZEROP TENS)                               (PLUSP ONES))                          (WRITE-STRING (SVREF ORDINAL-ONES ONES)))                         ((AND (ZEROP ONES)                               (PLUSP TENS))                          (WRITE-STRING (SVREF ORDINAL-TENS TENS)))                         ((PLUSP BOT)                          (WRITE-STRING (SVREF CARDINAL-TENS TENS))                          (WRITE-CHAR |\-)                          (WRITE-STRING (SVREF ORDINAL-ONES ONES)))                         ((PLUSP NUMBER)                          (WRITE-STRING "th"))                         (T (WRITE-STRING "zeroeth")))))))(DEFUN FORMAT-PRINT-OLD-ROMAN (N)                            (* Print Roman numerals *)   (CL:UNLESS (< 0 N 5000)          (FORMAT-ERROR "Number too large to print in old Roman numerals: ~:D" N))   (CL:DO ((CHAR-LIST (QUOTE (|\D |\C |\L |\X |\V |\I))                  (CDR CHAR-LIST))           (VAL-LIST (QUOTE (500 100 50 10 5 1))                  (CDR VAL-LIST))           (CUR-CHAR |\M (CAR CHAR-LIST))           (CUR-VAL 1000 (CAR VAL-LIST))           (START N (CL:DO ((I START (PROGN (WRITE-CHAR CUR-CHAR)                                            (- I CUR-VAL))))                           ((< I CUR-VAL)                            I))))          ((ZEROP START))))(DEFUN FORMAT-PRINT-ROMAN (N) (CL:UNLESS (< 0 N 4000)                                     (FORMAT-ERROR "Number too large to print in Roman numerals: ~:D"                                             N))                              (CL:DO ((CHAR-LIST (QUOTE (|\D |\C |\L |\X |\V |\I))                                             (CDR CHAR-LIST))                                      (VAL-LIST (QUOTE (500 100 50 10 5 1))                                             (CDR VAL-LIST))                                      (SUB-CHARS (QUOTE (|\C |\X |\X |\I |\I))                                             (CDR SUB-CHARS))                                      (SUB-VAL (QUOTE (100 10 10 1 1 0))                                             (CDR SUB-VAL))                                      (CUR-CHAR |\M (CAR CHAR-LIST))                                      (CUR-VAL 1000 (CAR VAL-LIST))                                      (CUR-SUB-CHAR |\C (CAR SUB-CHARS))                                      (CUR-SUB-VAL 100 (CAR SUB-VAL))                                      (START N (CL:DO ((I START (PROGN (WRITE-CHAR CUR-CHAR)                                                                       (- I CUR-VAL))))                                                      ((< I CUR-VAL)                                                       (COND                                                          ((<= (- CUR-VAL CUR-SUB-VAL)                                                            I)                                                           (WRITE-CHAR CUR-SUB-CHAR)                                                           (WRITE-CHAR CUR-CHAR)                                                           (- I (- CUR-VAL CUR-SUB-VAL)))                                                          (T I))))))                                     ((ZEROP START))))(DEFUN FORMAT-PRINT-DECIMAL (COLON ATSIGN PARMS)             (* Decimal ~D *) (FORMAT-PRINT-NUMBER                                                                               (POP-FORMAT-ARG)                                                                               10 COLON ATSIGN PARMS))(DEFUN FORMAT-PRINT-BINARY (COLON ATSIGN PARMS)              (* Binary ~B *) (FORMAT-PRINT-NUMBER                                                                              (POP-FORMAT-ARG)                                                                              2 COLON ATSIGN PARMS))(DEFUN FORMAT-PRINT-OCTAL (COLON ATSIGN PARMS)               (* Octal ~O *) (FORMAT-PRINT-NUMBER                                                                             (POP-FORMAT-ARG)                                                                             8 COLON ATSIGN PARMS))(DEFUN FORMAT-PRINT-HEXADECIMAL (COLON ATSIGN PARMS)         (* Hexadecimal ~X *) (                                                                                  FORMAT-PRINT-NUMBER                                                                                   (POP-FORMAT-ARG)                                                                                   16 COLON ATSIGN                                                                                    PARMS))(DEFUN FORMAT-PRINT-RADIX (COLON ATSIGN PARMS)               (* Radix ~R *)   (LET ((NUMBER (POP-FORMAT-ARG)))        (CL:IF PARMS (FORMAT-PRINT-NUMBER NUMBER (pop PARMS)                            COLON ATSIGN PARMS)               (CL:IF ATSIGN (CL:IF COLON (FORMAT-PRINT-OLD-ROMAN NUMBER)                                    (FORMAT-PRINT-ROMAN NUMBER))                      (CL:IF COLON (FORMAT-PRINT-ORDINAL NUMBER)                             (FORMAT-PRINT-CARDINAL NUMBER))))))(DEFUN FORMAT-FIXED (COLON ATSIGN PARMS)                     (* Fixed-format floating point ~F *)   (CL:WHEN COLON (FORMAT-ERROR "Colon flag not allowed"))   (WITH-FORMAT-PARAMETERS PARMS ((W NIL)                                  (D NIL)                                  (K NIL)                                  (OVF NIL)                                  (PAD |\Space))             (* Note that the scale factor k                                                              defaults to nil. This is interpreted                                                              as *)                                                             (* zero by flonum-to-string, but more                                                              efficiently. *)          (LET ((NUMBER (POP-FORMAT-ARG)))               (CL:IF (FLOATP NUMBER)                      (FORMAT-FIXED-AUX NUMBER W D K OVF PAD ATSIGN)                      (CL:IF (RATIONALP NUMBER)                             (FORMAT-FIXED-AUX (COERCE NUMBER (QUOTE FLOAT))                                    W D K OVF PAD ATSIGN)                             (LET ((*PRINT-BASE* 10))                                  (FORMAT-WRITE-FIELD (PRINC-TO-STRING NUMBER)                                         W 1 0 |\Space T)))))))(DEFUN FORMAT-FIXED-AUX (NUMBER W D K OVF PAD ATSIGN)   (CL:IF (NOT (OR W D))          (PROGN                                             (* Code snarfed from Spice printer                                                              OUTPUT-FLOAT)                 (CL:WHEN (MINUSP NUMBER)                        (WRITE-CHAR |\-)                        (CL:SETQ NUMBER (- NUMBER)))         (*                   "When number is reasonable size, use FLONUM-TO-STRING, otherwise punt and PRINC it")                 (CL:IF (AND (>= NUMBER .001)                             (<= NUMBER 10000000.0))                        (MULTIPLE-VALUE-BIND (STR LEN LPOINT TPOINT)                               (FLONUM-TO-STRING NUMBER)                               (CL:WHEN LPOINT (WRITE-CHAR |\0))                               (WRITE-STRING STR)                               (CL:WHEN TPOINT (WRITE-CHAR |\0)))                        (PRINC NUMBER)))          (LET ((SPACELEFT W))               (CL:WHEN (AND W (OR ATSIGN (MINUSP NUMBER)))                      (DECF SPACELEFT))               (MULTIPLE-VALUE-BIND (STR LEN LPOINT TPOINT)                      (FLONUM-TO-STRING (ABS NUMBER)                             SPACELEFT D K)                  (* if caller specifically requested no                                                              fraction digits, suppress the *)                                                             (* optional trailing zero *)                      (CL:WHEN (AND D (ZEROP D))                             (SETQ TPOINT NIL))                      (CL:WHEN W (DECF SPACELEFT LEN)        (* optional leading zero *)                             (CL:WHEN LPOINT                 (* force at least one digit *)                                    (CL:IF (OR (> SPACELEFT 0)                                               TPOINT)                                           (DECF SPACELEFT)                                           (SETQ LPOINT NIL)))                                                             (* optional trailing zero *)                             (CL:WHEN TPOINT (CL:IF (> SPACELEFT 0)                                                    (DECF SPACELEFT)                                                    (SETQ TPOINT NIL))))                      (COND                         ((AND W (< SPACELEFT 0)                               OVF)                          (* field width overflow *)                          (DOTIMES (I W)                                 (WRITE-CHAR OVF)))                         (T (CL:WHEN W (DOTIMES (I SPACELEFT)                                              (WRITE-CHAR PAD)))                            (CL:IF (MINUSP NUMBER)                                   (WRITE-CHAR |\-)                                   (CL:IF ATSIGN (WRITE-CHAR |\+)))                            (CL:WHEN LPOINT (WRITE-CHAR |\0))                            (WRITE-STRING STR)                            (CL:WHEN TPOINT (WRITE-CHAR |\0))))))))(DEFUN FORMAT-EXPONENTIAL (COLON ATSIGN PARMS)               (* Exponential-format floating point                                                              ~E *)   (CL:WHEN COLON (FORMAT-ERROR "Colon flag not allowed"))   (WITH-FORMAT-PARAMETERS PARMS ((W NIL)                                  (D NIL)                                  (E NIL)                                  (K 1)                                  (OVF NIL)                                  (PAD |\Space)                                  (MARKER NIL))          (LET ((NUMBER (POP-FORMAT-ARG)))               (CL:IF (FLOATP NUMBER)                      (FORMAT-EXP-AUX NUMBER W D E K OVF PAD MARKER ATSIGN)                      (CL:IF (RATIONALP NUMBER)                             (FORMAT-EXP-AUX (COERCE NUMBER (QUOTE FLOAT))                                    W D E K OVF PAD MARKER ATSIGN)                             (LET ((*PRINT-BASE* 10))                                  (FORMAT-WRITE-FIELD (PRINC-TO-STRING NUMBER)                                         W 1 0 |\Space T)))))))(DEFUN FORMAT-EXPONENT-MARKER (NUMBER) (CL:IF (TYPEP NUMBER *READ-DEFAULT-FLOAT-FORMAT*)                                              |\E                                              (TYPECASE NUMBER (SHORT-FLOAT |\S)                                                     (SINGLE-FLOAT |\F)                                                     (DOUBLE-FLOAT |\D)                                                     (LONG-FLOAT |\L))))(DEFUN FORMAT-EXP-AUX (NUMBER W D E K OVF PAD MARKER ATSIGN)                     (* Here we prevent the scale factor from shifting all significance out of a           number to the right. We allow insignificant zeroes to be shifted in to the left           right, athough it is an error to specify k and d such that this occurs.          Perhaps we should detect both these condtions and flag them as errors.          As for now, we let the user get away with it, and merely guarantee that at           least one significant digit will appear.          *) (CL:IF (NOT (OR W D))        (CL:PRIN1 NUMBER)        (MULTIPLE-VALUE-BIND (NUM EXPT)               (SCALE-EXPONENT (ABS NUMBER))               (LET* ((EXPT (- EXPT K))                      (ESTR (PRINC-TO-STRING (ABS EXPT)))                      (ELEN (CL:IF E (MAX (CL:LENGTH ESTR)                                          E)                                   (CL:LENGTH ESTR)))                      (FDIG (CL:IF D (CL:IF (PLUSP K)                                            (1+ (- D K))                                            D)                                   NIL))                      (FMIN (CL:IF (MINUSP K)                                   (- 1 K)                                   NIL))                      (SPACELEFT (CL:IF W (- W 2 ELEN)                                        NIL)))                     (CL:WHEN (OR ATSIGN (MINUSP NUMBER))                            (DECF SPACELEFT))                     (CL:IF (AND W E OVF (> ELEN E))                            (PROGN                           (* exponent overflow *)                                   (DOTIMES (I W)                                          (WRITE-CHAR OVF)))                            (MULTIPLE-VALUE-BIND (FSTR FLEN LPOINT TPOINT)                                   (FLONUM-TO-STRING NUM SPACELEFT FDIG K FMIN)                                   (CL:WHEN W (DECF SPACELEFT FLEN)                                          (CL:WHEN TPOINT (DECF SPACELEFT))                                          (CL:WHEN LPOINT (CL:IF (> SPACELEFT 0)                                                                 (DECF SPACELEFT)                                                                 (SETQ LPOINT NIL))))                                   (COND                                      ((AND W (< SPACELEFT 0)                                            OVF)             (* significand overflow *)                                       (DOTIMES (I W)                                              (WRITE-CHAR OVF)))                                      (T (CL:WHEN W (DOTIMES (I SPACELEFT)                                                           (WRITE-CHAR PAD)))                                         (CL:IF (MINUSP NUMBER)                                                (WRITE-CHAR |\-)                                                (CL:IF ATSIGN (WRITE-CHAR |\+)))                                         (CL:WHEN LPOINT (WRITE-CHAR |\0))                                         (WRITE-STRING FSTR)                                         (CL:WHEN TPOINT (WRITE-CHAR |\0))                                         (WRITE-CHAR (CL:IF MARKER MARKER (FORMAT-EXPONENT-MARKER                                                                           NUMBER)))                                         (WRITE-CHAR (CL:IF (MINUSP EXPT)                                                            |\- |\+))                                         (CL:WHEN E          (* zero-fill before exponent if                                                              necessary *)                                                (DOTIMES (I (- E (CL:LENGTH ESTR)))                                                       (WRITE-CHAR |\0)))                                         (WRITE-STRING ESTR)))))))))(DEFUN FORMAT-GENERAL-FLOAT (COLON ATSIGN PARMS)             (* General Floating Point -                                                             ~G *)   (CL:WHEN COLON (FORMAT-ERROR "Colon flag not allowed"))   (WITH-FORMAT-PARAMETERS PARMS ((W NIL)                                  (D NIL)                                  (E NIL)                                  (K NIL)                                  (OVF |\*)                                  (PAD |\Space)                                  (MARKER NIL))          (LET ((NUMBER (POP-FORMAT-ARG)))                   (* The Excelsior edition does not say                                                              what to do if *)                                                             (* the argument is not a float.                                                             Here, we adopt the *)                                                             (* conventions used by ~F and ~E.                                                             *)               (CL:IF (FLOATP NUMBER)                      (FORMAT-GENERAL-AUX NUMBER W D E K OVF PAD MARKER ATSIGN)                      (CL:IF (RATIONALP NUMBER)                             (FORMAT-GENERAL-AUX (COERCE NUMBER (QUOTE FLOAT))                                    W D E K OVF PAD MARKER ATSIGN)                             (LET ((*PRINT-BASE* 10))                                  (FORMAT-WRITE-FIELD (PRINC-TO-STRING NUMBER)                                         W 1 0 |\Space T)))))))(DEFUN FORMAT-GENERAL-AUX (NUMBER W D E K OVF PAD MARKER ATSIGN)   (MULTIPLE-VALUE-BIND (IGNORE N)          (SCALE-EXPONENT (ABS NUMBER))          (DECLARE (IGNORE IGNORE))                          (* Default d if omitted.                                                             The procedure is taken directly *)                                                             (* from the definition given in the                                                              manual, and is not *)                                                             (* very efficient, since we generate                                                              the digits twice. *)                                                             (* Future maintainers are encouraged                                                              to improve on this. *)          (CL:UNLESS D (MULTIPLE-VALUE-BIND (STR LEN)                              (FLONUM-TO-STRING (ABS NUMBER))                              (DECLARE (IGNORE STR))                              (LET ((Q (CL:IF (= LEN 1)                                              1                                              (1- LEN))))                                   (SETQ D (MAX Q (MIN N 7))))))          (LET* ((EE (CL:IF E (+ E 2)                            4))                 (WW (CL:IF W (- W EE)                            NIL))                 (DD (- D N)))                (COND                   ((<= 0 DD D)                    (FORMAT-FIXED-AUX NUMBER WW DD NIL OVF PAD ATSIGN)                    (DOTIMES (I EE)                           (WRITE-CHAR |\Space)))                   (T (FORMAT-EXP-AUX NUMBER W D E (OR K 1)                             OVF PAD MARKER ATSIGN))))))(DEFUN FORMAT-DOLLARS (COLON ATSIGN PARMS)                   (* jrb: "19-May-86 09:52")                                                             (* Dollars floating-point format ~$ *)   (WITH-FORMAT-PARAMETERS PARMS ((D 2)                                  (N 1)                                  (FW 0)                                  (PAD |\Space))          (LET* ((NUMBER (POP-FORMAT-ARG))                 (SIGNSTR (CL:IF (MINUSP NUMBER)                                 "-"                                 (CL:IF ATSIGN "+" ""))))                (MULTIPLE-VALUE-BIND (STR NUMLENGTH IG2 IG3 POINTPLACE)                       (FLONUM-TO-STRING (ABS NUMBER)                              NIL D NIL)                       (DECLARE (IGNORE IG2 IG3))                       (CL:WHEN COLON (WRITE-STRING SIGNSTR))                       (DOTIMES (I (- FW NUMLENGTH (CL:LENGTH SIGNSTR)                                      (- N POINTPLACE)))                              (WRITE-CHAR PAD))                       (CL:UNLESS COLON (WRITE-STRING SIGNSTR))                       (DOTIMES (I (- N POINTPLACE))                              (WRITE-CHAR |\0))                       (WRITE-STRING STR)))))(DEFUN CHARPOS (STREAM) (CL:UNLESS (STREAMP STREAM)                               (CL:ERROR "CHARPOS: ~A isn't a stream" STREAM))                        (fetch (STREAM CHARPOSITION) of STREAM))(DEFUN WHITESPACE-CHAR-P (CH) (CL:MEMBER CH (QUOTE (|\Tab |\Page |\Space |\Backspace |\Newline                                                           |\Linefeed))                                     :TEST                                     (CL:FUNCTION EQL)))(DEFMACRO NAME-ARRAY (CONTENTS) (BQUOTE (MAKE-ARRAY (\, (LENGTH CONTENTS))                                               :ELEMENT-TYPE T :INITIAL-CONTENTS (QUOTE (\, CONTENTS)                                                                                        ))))(DEFVAR *FORMAT-ARGUMENTS* NIL "List of FORMAT args yet unprocessed")(DEFVAR *FORMAT-CONTROL-STRING* NIL "Bound to FORMAT control string")(DEFVAR *FORMAT-DISPATCH-TABLE* (MAKE-DISPATCH-VECTOR (|\B FORMAT-PRINT-BINARY)                                       (|\O FORMAT-PRINT-OCTAL)                                       (|\D FORMAT-PRINT-DECIMAL)                                       (|\X FORMAT-PRINT-HEXADECIMAL)                                       (|\R FORMAT-PRINT-RADIX)                                       (|\F FORMAT-FIXED)                                       (|\E FORMAT-EXPONENTIAL)                                       (|\G FORMAT-GENERAL-FLOAT)                                       (|\A FORMAT-PRINC)                                       (|\C FORMAT-PRINT-CHARACTER)                                       (|\P FORMAT-PLURAL)                                       (|\S FORMAT-PRIN1)                                       (|\T FORMAT-TAB)                                       (|\% FORMAT-TERPRI)                                       (|\& FORMAT-FRESHLINE)                                       (|\* FORMAT-SKIP-ARGUMENTS)                                       (|\| FORMAT-PAGE)                                       (|\~ FORMAT-TILDE)                                       (|\$ FORMAT-DOLLARS)                                       (|\? FORMAT-INDIRECTION)                                       (|\^ FORMAT-ESCAPE)                                       (|\; FORMAT-SEMICOLON-ERROR)                                       (|\[ FORMAT-CONDITION)                                       (|\{ FORMAT-ITERATION)                                       (|\< FORMAT-JUSTIFICATION)                                       (|\( FORMAT-CAPITALIZATION)                                       (|\Newline FORMAT-NEWLINE))                                       "Table of functions called by SUB-FORMAT to process ~foo stuff"   )(DEFVAR *FORMAT-INDEX* NIL "Index into current control string")(DEFVAR *FORMAT-LENGTH* NIL "Length of current control string")(DEFVAR *FORMAT-ORIGINAL-ARGUMENTS* NIL "List of original FORMAT arguments")(DEFVAR CARDINAL-ONES (NAME-ARRAY (NIL "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"                                       )) "Table of strings used by ~R" )(DEFVAR CARDINAL-TENS (NAME-ARRAY (NIL NIL "twenty" "thirty" "forty" "fifty" "sixty" "seventy"                                        "eighty" "ninety")) "Table of strings used by ~R" )(DEFVAR CARDINAL-TEENS (NAME-ARRAY ("ten" "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen"                                           "seventeen" "eighteen" "nineteen"))                                                                         "Table of strings used by ~R"   )(DEFVAR CARDINAL-PERIODS (NAME-ARRAY ("" " thousand" " million" " billion" " trillion" " quadrillion"                                          " quintillion" " sextillion" " septillion" " octillion"                                          " nonillion" " decillion")) "Table of strings used by ~R"   )(DEFVAR ORDINAL-ONES (NAME-ARRAY (NIL "first" "second" "third" "fourth" "fifth" "sixth" "seventh"                                       "eighth" "ninth")) "Table of strings used by ~R" )(DEFVAR ORDINAL-TENS (NAME-ARRAY (NIL "tenth" "twentieth" "thirtieth" "fourtieth" "fiftieth"                                       "sixtieth" "seventieth" "eightieth" "ninetieth"))                                                                         "Table of strings used by ~R"   )(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS (ADDTOVAR NLAMA )(ADDTOVAR NLAML )(ADDTOVAR LAMA ))(* ;; "Arrange to use the correct compiler.")(PUTPROPS CMLFORMAT FILETYPE COMPILE-FILE)(PUTPROPS CMLFORMAT COPYRIGHT ("Xerox Corporation" 1986))(DECLARE: DONTCOPY  (FILEMAP (NIL)))STOP