Annotation of 43BSD/ucb/lisp/lisplib/format.l, revision 1.1.1.1

1.1       root        1: (setq rcs-format-
                      2:    "$Header")
                      3: 
                      4: ;;
                      5: ;;  format.l                           -[Fri Mar  4 12:20:16 1983 by jkf]-
                      6: ;;
                      7: ;;   This is a function for printing or creating nicely formatted strings.
                      8: ;; This file is a modified version of the format program which runs in
                      9: ;; the mit lisps.  When converting to franz, compatibility was the
                     10: ;; major goal, thus we still use the \ character as a string delimiter
                     11: ;; within a command string, even though it must be doubled in Franz.
                     12: ;;
                     13: ;; The file contains the user callable functions:
                     14: ;;   format    - lexpr for doing formated printed output or creating
                     15: ;;               strings
                     16: ;;   defformat  - macro for adding a format directive
                     17: ;;
                     18: 
                     19: ; FORMAT prints several arguments according to a control argument.
                     20: ; The control argument is either a string or a list of strings and lists.
                     21: ; The strings and lists are interpreted consecutively.
                     22: ; Strings are for the most part just printed, except that the character ~
                     23: ; starts an escape sequence which directs other actions.
                     24: ; A ~ escape sequence has an (optional) numeric parameter followed by a
                     25: ; mode character.
                     26: ; These escape actions can use up one or more of the non-control arguments.
                     27: ; A list in the control-argument list is also interpreted as an escape.
                     28: ; Its first element is the mode, a symbol which may be any length,
                     29: ; and its remaining elements are parameters.  The list (D 5) is equivalent
                     30: ; to the ~ escape "~5D";  similarly, each ~ escape has an equivalent list.
                     31: ; However, there are list escapes which have no ~ equivalent.
                     32: 
                     33: ; Any undefined list escape is simply evaluated.
                     34: 
                     35: ;These are the escape modes which are defined:
                     36: ; ~nD Takes any number and prints as a decimal integer.  If no arg,
                     37: ;     print without leading spaces.  If arg and it fits in, put in leading
                     38: ;     spaces; if it doesnt fit just print it.  If second arg, use that
                     39: ;     (or first char of STRING of it if not a number) instead of space
                     40: ;     as a pad char.
                     41: ; ~nF Floating point
                     42: ; ~nE Exponential notation
                     43: ; ~nO Like D but octal
                     44: ; ~nA Character string.  If there is an n then pad the string with spaces 
                     45: ;     on the right to make it n long.  If it doesn't fit, ignore n.
                     46: ; ~n,m,minpad,padcharA  Pad on the right to occupy at least
                     47: ;     n columns, or if longer than that to begin with, pad to occupy
                     48: ;     n+p*m columns for some nonnegative integer p.
                     49: ;     at least minpad pad characters are produced in any case
                     50: ;     (default if not supplied = 0).
                     51: ;     padchar is used for padding purposes (default if not supplied = space).
                     52: ;      if padchar is not a number, the first character in STRING of it is used.
                     53: 
                     54: ;     A mode can actually be used to PRINC anything, not just a string.
                     55: ; ~S  Prin1 an object.  Just like ~A (including parameters) but uses PRIN1.
                     56: ; ~C  One character, in any acceptable form.
                     57: ;      Control and meta bits print as alpha, beta, epsilon.
                     58: ; ~n* Ignore the next n args.  n defaults to 1.
                     59: ; ~n% Insert n newlines.  n defaults to 1.
                     60: ; ~n| Insert n formfeeds.  n defaults to 1.
                     61: ; ~nX Insert n spaces.  n defaults to 1.
                     62: ; ~n~ Insert n tildes.  n defaults to 1.
                     63: ; ~&  Perform the :FRESH-LINE operation on the stream.
                     64: ; ~n,mT  Tab to column n+pm, for p an integer >= 0.
                     65: ; ~Q  Apply the next arg to no arguments.
                     66: ; (Q ...) Apply the next arg to the (unevaluated) parameters following the Q.
                     67: ; ~P  Insert an "s", unless its argument is a 1
                     68: ; ~nG  Goto the nth argument (zero based).  The next command will get that
                     69: ;      argument, etc.
                     70: ; ~E and ~F are not implemented.  ~T is not implemented.
                     71: 
                     72: ; (FORMAT <stream> <control arg> <args>)
                     73: ; If <stream> is NIL, cons up and return a symbol.
                     74: ; If <stream> is T, use STANDARD-OUTPUT (saves typing).
                     75: 
                     76: ;; defformat:
                     77: ;;  to add a format handler, the defformat macro is used.
                     78: ;; the form is (defformat code args type . body)
                     79: ;;   where
                     80: ;;   code is the code this will handle.  the code can be a multi
                     81: ;;    character symbol, however it will have to be called with \\code\\.
                     82: ;;   args is either a one or two symbol list, depending on type
                     83: ;;   type is either: none, one, or many.
                     84: ;;    none means that type handler will not use any argument (it may use
                     85: ;;      use parameters however)
                     86: ;;    one means that it takes exactly one argument
                     87: ;;    many means that it may take from zero to ?? arguments.
                     88: ;;   body is the body of the function.  Its return value is only important
                     89: ;;    in the case of 'many' handlers since these handlers must return the
                     90: ;;    list of the arguments they didn't use.
                     91: ;;
                     92: ;;  'none' handlers get passes a hunk which contains the parameters provide
                     93: ;;     for this format directive.
                     94: ;;  'one' handlers are passed the argument and the parameters.
                     95: ;;  'many' handlers are passed the list of remaining arguments and the
                     96: ;;     parameters. they return the arguments they don't use.
                     97: 
                     98: ;to do:
                     99: ;  3) make sure the semantics follows the lisp machine defs
                    100: ;  6) do exponential (~e) floating point formats correctly.
                    101: ;  7) move ferror elsewhere (near error would be a good place).
                    102: ;  8) document it.
                    103: ;  11) fix ~a to left justify if given correct flag
                    104: ;  13) make sure that multi character directives are lower cased
                    105: ;  14) make the 'x parameter work correctly
                    106: ;  15) fix the english printer (wrt stream arg) and add ordinal
                    107: 
                    108: 
                    109: ;;; Kludges to make MacLISP like some of the LISPM functions
                    110: 
                    111: (declare (special Format-Standard-Output roman-old 
                    112:                  format-params-supplied format format-handlers
                    113:                  format-sharpsign-vars))
                    114: 
                    115: (setq format-sharpsign-vars 'franz-symbolic-character-names)
                    116: 
                    117: ;; format-params-supplied : numbers of parameters to format parameter
                    118: ;; roman-old when t, the roman printer will print IIII instead of IV
                    119: 
                    120: (or (boundp 'roman-old) (setq roman-old nil))
                    121: 
                    122: (declare (setq defmacro-for-compiling nil defmacro-displace-call nil ))
                    123:   (defmacro nsubstring (&rest w) `(format\:nsubstring ,.w))
                    124:   (defmacro string-search-char (&rest w) `(format\:string-search-char ,.w))
                    125:   (defmacro ar-1 (ar ind) `(cxr ,ind ,ar))
                    126:   (defmacro as-1 (val ar ind) `(rplacx ,ind ,ar ,val))
                    127:   (defmacro >= (x y) `(not (< ,x ,y)))
                    128:   (defmacro <= (x y) `(not (> ,x ,y)))
                    129:   (defmacro neq (x y) `(not (= ,x ,y)))
                    130:   (defmacro pop (stack) `(prog1 (car ,stack) (setq ,stack (cdr ,stack))))
                    131: (declare (setq defmacro-for-compiling 't defmacro-displace-call 't))
                    132: 
                    133: 
                    134: (declare
                    135:  (special ctl-string            ;The control string.
                    136:          ctl-length             ;string-length of ctl-string.
                    137:          ctl-index              ;Our current index into the control string.
                    138:                                 ; Used by the conditional command. (NYI)
                    139:          atsign-flag            ;Modifier
                    140:          colon-flag             ;Modifier
                    141:          format-temporary-area  ;For temporary consing
                    142:          format-arglist         ;The original arg list, for ~G.
                    143:          arglist-index          ;How far we are in the current arglist
                    144:          float-format           ; format used when printing floats
                    145:          poport                ; franz's standard output
                    146:          ))
                    147: 
                    148: (defun format (stream ctl-string &rest args)
                    149:   (let (format-string Format-Standard-Output
                    150:        (format-arglist args)
                    151:        (arglist-index 0))
                    152:     (setq stream (cond ((eq stream 't) poport )
                    153:                       ((null stream)
                    154:                        (setq format-string 't)
                    155:                        (list nil))
                    156:                       (t stream)))
                    157:     (setq Format-Standard-Output stream)
                    158:     (cond ((symbolp ctl-string)
                    159:           (setq ctl-string (get_pname ctl-string))))
                    160:     (cond ((stringp ctl-string)
                    161:           (format-ctl-string args ctl-string))
                    162:          (t (do ((ctl-string ctl-string (cdr ctl-string)))
                    163:               ((null ctl-string))
                    164:               (setq args
                    165:                     (cond ((symbolp (car ctl-string))
                    166:                            (format-ctl-string args (car ctl-string)))
                    167:                           (t (format-ctl-list args (car ctl-string))))))))
                    168:     (and format-string
                    169:         (setq format-string (maknam (nreverse (cdr stream)))))
                    170:     format-string))
                    171: 
                    172: (defun format-ctl-list (args ctl-list)
                    173:        (format-ctl-op (car ctl-list) args (cdr ctl-list)))
                    174: 
                    175: (defun format-ctl-string (args ctl-string)
                    176:     (declare (fixnum ctl-index ctl-length))
                    177:     (do   ((ctl-index 0) (ch) (tem) (str) (sym)
                    178:           (ctl-length (flatc ctl-string)))
                    179:          ((>= ctl-index ctl-length) args)
                    180:        (setq tem (cond ((string-search-char #/~ ctl-string ctl-index))
                    181:                        (t ctl-length)))
                    182:        (cond ((neq tem ctl-index)              ;Put out some literal string
                    183:               (setq str (nsubstring ctl-string ctl-index tem))
                    184:               (format:patom str)
                    185:               (and (>= (setq ctl-index tem) ctl-length)
                    186:                    (return args))))
                    187:        ;; (ar-1 ch ctl-index) is a tilde.
                    188:        (do ((atsign-flag nil)  ;Modifier
                    189:             (colon-flag nil)   ;Modifier
                    190:             (params (makhunk 10))
                    191:             (param-leader -1)
                    192:                                ;PARAMS contains the list of numeric parameters
                    193:             (param-flag nil)   ;If T, a parameter has been started in PARAM
                    194:             (param))           ;PARAM is the parameter currently
                    195:                                ; being constructed
                    196:            ((>= (setq ctl-index (1+ ctl-index)) ctl-length))
                    197:          (setq ch (getcharn ctl-string (1+ ctl-index)))
                    198:          (cond ((and (>= ch #/0) (<= ch #/9))                   ; 
                    199:                 (setq param (+ (* (or param 0) 10.) (- ch #/0)) ; 
                    200:                     param-flag t))
                    201:                ((= ch #/@)                                      ;ascii @
                    202:                 (setq atsign-flag t))
                    203:                ((= ch #/:)                                      ;ascii :
                    204:                 (setq colon-flag t))
                    205:                ((or (= ch #/v) (= ch #/V))                     ;ascii v, v
                    206:                 (as-1 (pop args) params
                    207:                       (setq param-leader (1+ param-leader)))
                    208:                 (setq arglist-index (1+ arglist-index))
                    209:                 (setq param nil param-flag nil))
                    210:                ((= ch #/#)
                    211:                 (as-1 (length args) params
                    212:                       (setq param-leader (1+ param-leader))))
                    213:                ((= ch #/,)
                    214:                   ;comma, begin another parameter, ascii ,
                    215:                 (and param-flag (as-1 param params (setq param-leader
                    216:                                                          (1+ param-leader))))
                    217:                 (setq param nil param-flag t))
                    218:                  ;omitted arguments made manifest by the
                    219:                  ;presence of a comma come through as nil
                    220:                (t              ;must be a command character
                    221:                    ;upper case to lower 
                    222:                  (and (>= ch #/A) (<= ch #/Z) (setq ch (+ ch (- #/a #/A))))
                    223:                  (setq ctl-index (1+ ctl-index)) ;advance past command char
                    224:                  (and param-flag (as-1 param params (setq param-leader
                    225:                                                           (1+ param-leader))))
                    226:                  (setq param-flag nil param nil tem nil)
                    227:                   ;str gets a string which is the name of the operation to do
                    228:                  (setq
                    229:                    str (cond ((= ch #/\ )                       ;ascii \
                    230:                               (let ((i (string-search-char
                    231:                                           #/\
                    232:                                           ctl-string
                    233:                                           (1+ ctl-index))))
                    234:                                  (and (null i)
                    235:                                       (ferror nil
                    236:                                          '|Unmatched \\ in control string.|))
                    237:                                  (prog1 ; don't uppercase! we are a two
                    238:                                     ; case system
                    239:                                     (setq tem
                    240:                                           (nsubstring ctl-string
                    241:                                                       (1+ ctl-index)
                    242:                                                       i))
                    243:                                     (setq ctl-index i))))
                    244:                              ; makes ~<newline> work!  ;SMH@EMS
                    245:                              ((= ch #\newline) (concat "ch" ch))  ;SMH@EMS
                    246:                              (t (ascii ch))))
                    247:                   ;; SYM gets the symbol corresponding to STR
                    248:                  (cond ((setq sym str)
                    249:                         (setq format-params-supplied param-leader)
                    250:                         (setq args (format-ctl-op sym args params)))
                    251:                        (t (ferror nil '|~C is an unknown FORMAT op in \"~A\"|
                    252:                                   tem ctl-string)))
                    253:                  (return nil))))))
                    254: 
                    255: ;Perform a single formatted output operation on specified args.
                    256: ;Return the remaining args not used up by the operation.
                    257: (defun format-ctl-op (op args params &aux tem)
                    258:    (cond ((stringp op) (setq op (concat op))))  ; make into a symbol
                    259:    (cond ((setq tem (assq op format-handlers))
                    260:          (cond ((eq 'one (cadr tem))
                    261:                 (or args
                    262:                     (ferror nil "arg required for ~a, but no more args" op))
                    263:                 (funcall (caddr tem) (car args) params)
                    264:                 (setq arglist-index (1+ arglist-index))
                    265:                 (cdr args))
                    266:                ((eq 'none (cadr tem))
                    267:                 (funcall (caddr tem) params)
                    268:                 args)
                    269:                ((eq 'many (cadr tem))
                    270:                 (funcall (caddr tem) args params))
                    271:                (t (ferror nil "Illegal format handler: ~s" tem))))
                    272:         (t (ferror nil '|\"~S\" is not defined as a FORMAT command.| op)
                    273:            args)))
                    274: 
                    275: (setq format-handlers nil)
                    276: ;; Format handlers
                    277: ;;
                    278: (defmacro defformat (name arglist type &rest body)
                    279:    (let (newname)
                    280:       ;; allow the name to be the fixnum rep of a character too.
                    281:       (cond ((fixp name) (setq name (concat "ch" name))))
                    282:       
                    283:       (cond ((not (memq type '(none one many)))
                    284:             (ferror nil "The format type, \"~a\" is not: none, one or many"
                    285:                     type)))
                    286:       (cond ((or (not (symbolp name))
                    287:                 (not (dtpr arglist)))
                    288:             (ferror nil "Bad form for name and/or arglist: ~a ~a"
                    289:                     name arglist)))
                    290:       (cond ((memq type '(one many))
                    291:             (cond ((not (= (length arglist) 2))
                    292:                    (ferror nil "There should be 2 arguments to ~a" name))))
                    293:            (t (cond ((not (= (length arglist) 1))
                    294:                      (ferror nil "There should be 1 argument to ~a" name)))))
                    295:       (setq newname (concat name ":format-handler"))
                    296:       `(progn 'compile
                    297:              (defun ,newname ,arglist ,@body)
                    298:              (let ((handler (assq ',name format-handlers)))
                    299:                 (cond (handler (rplaca (cddr handler) ',newname))
                    300:                       (t (setq format-handlers (cons (list ',name
                    301:                                                            ',type
                    302:                                                            ',newname)
                    303:                                                      format-handlers))))))))
                    304: 
                    305: 
                    306: 
                    307: (defformat d (arg params) one
                    308:    (let ((width (cxr 0 params))
                    309:         (padchar (cxr 1 params)))
                    310:     (cond ((and colon-flag (< arg 4000.) (> arg 0))
                    311:           (roman-step arg 0))
                    312:          (atsign-flag (english-print arg 'cardinal))
                    313:          ((let ((base 10.) (*nopoint t))
                    314:             (cond ((null padchar) (setq padchar 32.))
                    315:                   ((not (numberp padchar))
                    316:                    (setq padchar (getcharn padchar 1))))
                    317:             (and width (format-ctl-justify width (flatc arg) padchar))
                    318:             (format:patom arg))))))
                    319: 
                    320: (defformat f (arg params) one
                    321:    (cond ((not (floatp arg)) (format:patom arg))
                    322:         (t (let ((float-format "%.16g")
                    323:                  (prec (cxr 0 params)))
                    324:               (cond ((and prec (fixp prec) (> prec 0) (< prec 16))
                    325:                      (setq float-format (concat "%" prec "g"))))
                    326:               (format:patom arg)))))
                    327: 
                    328: ; r format
                    329: ; no params and flags: print as cardinal (four)
                    330: ; no params and colon: print as ordinal  (fourth)
                    331: ; no params and atsign: print as roman (IV)
                    332: ; no params and colon and atsign: print as old roman (IIII)
                    333: ; params:  radix,mincol[0],padchar[<space>]
                    334: ;              print in radix with at least mincol columns, padded on left
                    335: ;              with padchar
                    336: ;
                    337: (defformat r (arg params) one
                    338:    (format:anyradix-printer arg params nil))
                    339: 
                    340: ; o format - like ~8r, but params are like ~d.
                    341: ;
                    342: (defformat o (arg params) one
                    343:    (format:anyradix-printer arg params 8.))
                    344: 
                    345: (defun format:anyradix-printer (arg params radix)
                    346:    ; this is called by ~r and ~o.  for ~r, the mincol parameter starts at
                    347:    ; cxr 1, for ~o the mincol parameter starts at cxr 0.  We compute
                    348:    ; paramstart as either 0 or 1
                    349:    ; radix is given as third argument iff this is ~o
                    350:    (let ((paramstart (cond (radix 0)
                    351:                           (t 1))))
                    352:       (cond ((null radix) (setq radix (cxr 0 params))))
                    353:       (cond ((null radix)      ; if not to any given base
                    354:             (cond ((and (null colon-flag) (null atsign-flag))
                    355:                    (english-print arg 'cardinal))
                    356:                   ((and colon-flag (null atsign-flag))
                    357:                    (english-print arg 'ordinal))
                    358:                   ((and (null colon-flag) atsign-flag)
                    359:                    (roman-step arg 0))
                    360:                   ((and colon-flag atsign-flag)
                    361:                    (let ((roman-old t))
                    362:                       (roman-step arg 0)))))
                    363:            (t (let ((mincol (cxr paramstart params))
                    364:                     (padchr (or (cxr (+ 1 paramstart) params) #\space))
                    365:                     (res))
                    366:                  (cond (mincol         ;; if mincol specified
                    367:                           (let ((Format-Standard-Output (list nil)))
                    368:                              (format-binpr arg radix)
                    369:                              (setq res (cdr Format-Standard-Output)))
                    370:                           (format-ctl-justify mincol (length res) padchr)
                    371:                           (mapc 'format:tyo (nreverse res)))
                    372:                        (t (format-binpr arg radix))))))))
                    373:               
                    374: 
                    375: (defun format-binpr (x base)
                    376:    (cond ((equal x 0)(format:patom 0))
                    377:         ((or (> base 36.) (< base 2))
                    378:          (ferror nil "\"~s\" is not a base between 2 and 36" base))
                    379:         ((lessp x 0)
                    380:          (format:patom '-)
                    381:          (format-binpr1 (minus x) base))
                    382:         (t (format-binpr1 x base)))
                    383:    x)
                    384: 
                    385: 
                    386: 
                    387: (defun format-binpr1 (x base)
                    388:    (cond ((equal x 0))
                    389:         (t (format-binpr1 (quotient x base) base)
                    390:            (format-prc (remainder x base)))))
                    391: 
                    392: (defun format-prc (x)
                    393:    (cond ((< x 10.) (format:patom x))
                    394:         (t (format:tyo (plus (- #/a 10.) x)))))
                    395:                        ; works for 10.=A, 35.=Z.
                    396: 
                    397: ;; must get the width stuff to work!!
                    398: (defun format-ctl-octal (arg params)
                    399:    (let ((width (cxr 0 params)) (padchar (cxr 1 params)))
                    400:       (let ((base 8))
                    401:         (cond ((null padchar)
                    402:                (setq padchar 32.))
                    403:               ((not (numberp padchar))
                    404:                (setq padchar (getcharn padchar 1))))
                    405:         (and width (format-ctl-justify width (flatc arg) padchar))
                    406:         (format:patom arg))))
                    407: 
                    408: (defformat a (arg params) one
                    409:    (format-ctl-ascii arg params nil))
                    410: 
                    411: (defun format-ctl-ascii (arg params prin1p)
                    412:     (let ((edge (cxr 0 params))
                    413:          (period (cxr 1 params))
                    414:           (min (cxr 2 params))
                    415:          (padchar (cxr 3 params)))
                    416:         (cond ((null padchar)
                    417:                (setq padchar #\space))
                    418:               ((not (numberp padchar))
                    419:                (setq padchar (getcharn padchar 1))))
                    420:          (cond (prin1p (format:print arg))
                    421:                (t (format:patom arg)))
                    422:         (cond ((not (null edge))
                    423:                (let ((width (cond (prin1p (flatsize arg)) ((flatc arg)))))
                    424:                  (cond ((not (null min))
                    425:                         (format-ctl-repeat-char min padchar)
                    426:                         (setq width (+ width min))))
                    427:                  (cond (period
                    428:                         (format-ctl-repeat-char
                    429:                          (- (+ edge (* (\\ (+ (- (max edge width) edge 1)
                    430:                                               period)
                    431:                                            period)
                    432:                                        period))
                    433:                             width)
                    434:                          padchar))
                    435:                        (t (format-ctl-justify edge width padchar))))))))
                    436: 
                    437: (defformat s (arg params) one
                    438:     (format-ctl-ascii arg params t))
                    439: 
                    440: (defformat c (arg params) one
                    441:    (cond ((or (not (fixp arg))
                    442:              (< arg 0)
                    443:              (> arg 127))
                    444:          (ferror nil "~s is not a legal character value" arg)))
                    445:    (cond ((and (not colon-flag) (not atsign-flag))
                    446:          ; just print out the character after converting to ascii
                    447:          (format:patom (ascii arg)))
                    448:         (t ; it may have an extended name, check for that first
                    449:            (let (name)
                    450:               (cond ((setq name (car
                    451:                                    (rassq arg (symeval format-sharpsign-vars))))
                    452:                      ; it has an extended name.
                    453:                      ; if : flag, then print in human readable
                    454:                      (cond (colon-flag (format:patom name))
                    455:                            (atsign-flag (format:patom "#\\")
                    456:                                         (format:patom name))))
                    457:                     ((< arg #\space)
                    458:                      ; convert from control to upper case
                    459:                      (setq arg (+ arg #/@))
                    460:                      (cond (colon-flag (format:patom "^")
                    461:                                        (format:patom (ascii arg)))
                    462:                            (atsign-flag (format:patom "#^")
                    463:                                         (format:patom (ascii arg)))))
                    464:                     (t (cond (colon-flag (format:patom (ascii arg)))
                    465:                              (atsign-flag (format:patom "#/")
                    466:                                           (format:patom (ascii arg))))))))))
                    467: 
                    468: (defformat p (args params) many
                    469:   (let (arg)
                    470:     (cond (colon-flag
                    471:           (setq arg (nth (1- arglist-index) format-arglist)))
                    472:          ((null args)
                    473:           (ferror () "Argument required for p, but no more arguments"))
                    474:          (t (setq arg (pop args)
                    475:                   arglist-index (1+ arglist-index))))
                    476:     (if (= arg 1)
                    477:        (if atsign-flag (format:tyo #/y))
                    478:        (cond (atsign-flag
                    479:               (format:tyo #/i)
                    480:               (format:tyo #/e)
                    481:               (format:tyo #/s))
                    482:              (t (format:tyo #/s))))
                    483:     args))
                    484: 
                    485: (defformat *  (args params) many
                    486:   (let ((count (or (cxr 0 params) 1)))
                    487:     (if colon-flag (setq count (minus count)))
                    488:     (setq arglist-index (+ arglist-index count))
                    489: ;;  (nthcdr count format-arglist)              ;; ??? SMH@EMS
                    490:     (nthcdr arglist-index format-arglist)))    ;; SMH@EMS
                    491: 
                    492: (defformat g (arg params) many
                    493:        (let ((count (or (cxr 0 params) 1)))
                    494:            (nthcdr count format-arglist)))
                    495: 
                    496: (defformat % (params) none
                    497:        (declare (fixnum i))
                    498:        (let ((count (or (cxr 0 params) 1)))
                    499:            (do i 0 (1+ i) (= i count)
                    500:                (format:terpr))))
                    501: 
                    502: ;  ~ at the end of the line
                    503: ;  no params: ignore newline and following whitespace
                    504: ;  @ flag: leave the newline in the string but ignore whitespace
                    505: ;  : flag: ignore newline but leave the whitespace
                    506: ;  :@ flags: leave both newline and whitespace
                    507: ;
                    508: (defformat #\newline (params) none
                    509:    (cond (atsign-flag
                    510:            (format:tyo #\newline)))
                    511:    (cond ((not colon-flag)
                    512:          (setq ctl-index (1+ ctl-index))
                    513:          (do ()
                    514:              ((>= ctl-index ctl-length))
                    515:              (cond ((memq (getcharn ctl-string ctl-index)
                    516:                           '(#\space #\tab))
                    517:                     (setq ctl-index (1+ ctl-index)))
                    518:                    (t (setq ctl-index (1- ctl-index))
                    519:                       (return)))))))
                    520: 
                    521:                 
                    522: (defformat & (params) none
                    523:     (format:fresh-line))
                    524: 
                    525: (defformat x (params) none
                    526:    (format-ctl-repeat-char (cxr 0 params) #\space))
                    527: 
                    528: (defformat \| (params) none
                    529:    (format-ctl-repeat-char (cxr 0 params) #\ff))
                    530:    
                    531: (defformat ~ (params) none
                    532:    (format-ctl-repeat-char (cxr 0 params) #/~))
                    533: 
                    534: (defun format-ctl-repeat-char (count char)
                    535:     (declare (fixnum i))
                    536:     (cond ((null count) (setq count 1)))
                    537:     (do i 0 (1+ i) (=& i count)
                    538:        (format:tyo char)))
                    539: 
                    540: ;; Several commands have a SIZE long object which they must print
                    541: ;; in a WIDTH wide field.  If WIDTH is specified and is greater than
                    542: ;; the SIZE of the thing to be printed, this put out the right
                    543: ;; number of  CHARs to fill the field.  You can call this before
                    544: ;; or after printing the thing, to get leading or trailing padding.
                    545: (defun format-ctl-justify (width size &optional (char #\space))
                    546:     (and width (> width size) (format-ctl-repeat-char (- width size) char)))
                    547: 
                    548: (defformat q (arg params) one
                    549:    ;; convert params given to a list
                    550:    (do ((ii format-params-supplied (1- ii))
                    551:        (params-given nil))
                    552:        ((< ii 0) (apply arg params-given))
                    553:        (setq params-given (cons (cxr ii params) params-given))))
                    554: 
                    555: ;; Fixed nested ~[ ~] parser to handle ~:[ ~] and ~@:[ ~] as well.  SMH@EMS
                    556: (defun case-scan (goal &optional (lim ctl-length) (times 1))
                    557:   (declare (fixnum cnt lim times ctl-index))
                    558:   (*catch 'case-scan
                    559:     (do ((cnt 0 (1+ cnt)))
                    560:        ((>= cnt times) t)
                    561:       (do ((ch))
                    562:          ((>= ctl-index lim)
                    563:           (*throw 'case-scan nil))
                    564:        (setq ch (getcharn ctl-string (1+ ctl-index))
                    565:              ctl-index (1+ ctl-index))
                    566:        (cond ((= ch #/~)
                    567:               (setq ch (getcharn ctl-string (1+ ctl-index))
                    568:                     ctl-index (1+ ctl-index))
                    569:               (cond ((= ch goal)
                    570:                      (return t))
                    571:                     ((or (= ch #/[)            ;; SMH@EMS
                    572:                          (and (or (= ch #/:) (= ch #/@))
                    573:                               (= (getcharn ctl-string
                    574:                                            (setq ctl-index (1+ ctl-index)))
                    575:                                  #/[)))        ;; #/] fakeout emacs
                    576:                      (case-scan #/] lim)))))))))
                    577: 
                    578: ; [ format
                    579: ;  the case selector is the first parameter given, and if no  parameter
                    580: ;  is given, then it is the next argument
                    581: ;
                    582: (defformat \[ (args params) many
                    583:    (let ((start ctl-index)
                    584:         (num (cond ((> format-params-supplied -1)
                    585:                     (cxr 0 params))
                    586:                    (t (cond ((null args)
                    587:                              (error "the [ format requires an argument")))
                    588:                       (prog1 (car args)
                    589:                              (setq args (cdr args))
                    590:                              (setq arglist-index (1+ arglist-index)))))))
                    591:       (and colon-flag (setq num (cond (num 1) (t 0))))
                    592:       (and (null num)
                    593:           (ferror nil
                    594:               "The FORMAT \"[\" command must be given a numeric parameter"))
                    595:       (cond ((>= num 0)
                    596:             (or (case-scan #/])
                    597:                 (ferror nil "Unbalanced conditional in FORMAT control string"))
                    598:             (let ((i ctl-index))
                    599:                (setq ctl-index start)
                    600:                (case-scan #/; i num))))
                    601:       args))
                    602: 
                    603: (defformat \] (params) none nil)
                    604: 
                    605: (defformat \; (params) none
                    606:    (case-scan #/]))
                    607: 
                    608: ;; FIXTHIS:
                    609: ;; The following doesn't bind format-arglist and arglist-index properly.
                    610: ;; Added return-* stuff, also fixing above(?).  SMH@EMS
                    611: (defformat \{ (args params) many
                    612:   (let ((loop-times (or (cxr 0 params) -1))
                    613:        (loop-string)
                    614:        (at-least-once nil)
                    615:        (return-args)                   ;; SMH@EMS
                    616:        (return-format-arglist)         ;; SMH@EMS
                    617:        (return-arglist-index))         ;; SMH@EMS
                    618:     (do ((i (format\:string-search-char #/~ ctl-string ctl-index)
                    619:            (format\:string-search-char #/~ ctl-string (1+ i))))
                    620:         ((or (null i) (= (1+ i) ctl-length))
                    621:         (ferror () "No matching \"}\" for \"{\" in format"))
                    622:       (cond ((= #/} (getcharn ctl-string (+ 2 i)))
                    623:             (setq loop-string
                    624:                   (format\:nsubstring ctl-string ctl-index i)
                    625:                   ctl-index (+ 2 i))
                    626:             (return t))
                    627:            ((and (= #/: (getcharn ctl-string (+ 2 i)))
                    628:                  (= #/} (getcharn ctl-string (+ 3 i))))
                    629:             (setq loop-string
                    630:                   (format\:nsubstring ctl-string ctl-index i)
                    631:                   ctl-index (+ 3 i)
                    632:                   at-least-once t)
                    633:             (return t))))
                    634:     (if (= 0 (flatc loop-string))
                    635:        (setq loop-string (pop args)
                    636:              arglist-index (1+ arglist-index)))
                    637:     (if (null atsign-flag)
                    638:        (setq return-args (cdr args)                    ;; SMH@EMS
                    639:              return-arglist-index arglist-index        ;; SMH@EMS
                    640:              arglist-index 0                           ;; SMH@EMS
                    641:              return-format-arglist format-arglist      ;; SMH@EMS
                    642:              format-arglist (car args)                 ;; SMH@EMS
                    643:              args format-arglist))
                    644:     (*catch '(loop-stop loop-abort)
                    645:       (do ((i loop-times (1- i)))
                    646:          ((and (null at-least-once)
                    647:                (or (null args) (= i 0))))
                    648:        (setq at-least-once nil)
                    649:        (cond ((null colon-flag)
                    650:               (setq args (format-ctl-string args loop-string)))
                    651:              (t (*catch 'loop-stop
                    652:                    (format-ctl-string (car args) loop-string))
                    653:                 (setq args (cdr args)
                    654:                       arglist-index (1+ arglist-index))))))
                    655:     (cond (return-arglist-index                                        ;; SMH@EMS
                    656:           (setq args return-args                               ;; SMH@EMS
                    657:                 arglist-index (1+ return-arglist-index)        ;; SMH@EMS
                    658:                 format-arglist return-format-arglist)))        ;; SMH@EMS
                    659:     args))
                    660: 
                    661: (defformat \} (params) none nil)
                    662: 
                    663: (defformat \^ (args params) many
                    664:   (let ((terminate nil))
                    665:     (cond ((null (cxr 0 params))
                    666:           (setq terminate (null args)))
                    667:          ((null (cxr 1 params))
                    668:           (setq terminate (zerop (cxr 0 params))))
                    669:          ((null (cxr 2 params))
                    670:           (setq terminate (equal (cxr 1 params) (cxr 0 params))))
                    671:          (t (setq terminate (and (< (cxr 0 params) (cxr 1 params))
                    672:                                  (< (cxr 1 params) (cxr 2 params))))))
                    673:     (if terminate
                    674:        (if colon-flag (*throw 'loop-abort t) (*throw 'loop-stop t))
                    675:        args))) 
                    676: 
                    677: 
                    678: (declare (special english-small english-medium english-large))
                    679: 
                    680: (defun make-list-array (list)
                    681:    (let ((a (makhunk (length list))))
                    682:       (do ((i 0 (1+ i))
                    683:           (ll list (cdr ll)))
                    684:          ((null ll))
                    685:          (rplacx i a (car ll)))
                    686:       a))
                    687: 
                    688: (setq english-small
                    689:    (make-list-array '(|one| |two| |three| |four| |five| |six|
                    690:                            |seven| |eight| |nine| |ten| |eleven| |twelve|
                    691:                            |thirteen| |fourteen| |fifteen| |sixteen|
                    692:                            |seventeen| |eighteen| |nineteen|)))
                    693: 
                    694: (setq english-medium
                    695:    (make-list-array '(|twenty| |thirty| |forty| |fifty| |sixty| |seventy|
                    696:                               |eighty| |ninty|)))
                    697: 
                    698: (setq english-large
                    699:    (make-list-array '(|thousand| |million| |billion| |trillion| |quadrillion|
                    700:                                 |quintillion|)))
                    701: 
                    702: 
                    703: (defun english-print (n type)
                    704:        (declare (fixnum i n limit))
                    705:        (cond ((zerop n)
                    706:              (cond ((eq type 'cardinal) (format:patom "zero"))
                    707:                    (t (format:patom "zeroth"))))
                    708:             ((< n 0)
                    709:              (format:patom '|minus|)
                    710:              (format:tyo #\space)
                    711:              (english-print (minus n) type))
                    712:             (t
                    713:              (do ((n n)
                    714:                    (p)
                    715:                   (flag)
                    716:                   (limit 1000000.
                    717:                          (quotient limit 1000.))
                    718:                   (i 1 (1- i)))
                    719:                  ((< i 0)
                    720:                   (cond ((> n 0)
                    721:                          (and flag (format:tyo #\space))
                    722:                          (english-print-thousand n))))
                    723:                  (cond ((not (< n limit))
                    724:                         (setq p (quotient n limit)
                    725:                               n (remainder n limit))
                    726:                         (cond (flag (format:tyo #\space))
                    727:                               (t (setq flag t)))
                    728:                         (english-print-thousand p)
                    729:                         (format:tyo #\space)
                    730:                         (format:patom (ar-1 english-large i))))))))
                    731: 
                    732: (defun english-print-thousand (n)
                    733:        (declare (fixnum i n limit))
                    734:        (let ((n (remainder n 100.))
                    735:             (h (quotient n 100.)))
                    736:            (cond ((> h 0)
                    737:                   (format:patom (ar-1 english-small (1- h)))
                    738:                   (format:tyo #\space)
                    739:                   (format:patom '|hundred|)
                    740:                   (and (> n 0) (format:tyo #\space))))
                    741:            (cond ((= n 0))
                    742:                  ((< n 20.)
                    743:                   (format:patom (ar-1 english-small (1- n))))
                    744:                  (t
                    745:                   (format:patom (ar-1 english-medium
                    746:                                                   (- (quotient n 10.) 2)))
                    747:                   (cond ((zerop (setq h (remainder n 10.))))
                    748:                         (t
                    749:                          (format:tyo #/-) ;ascii -
                    750:                          (format:patom (ar-1 english-small (1- h)))))))))
                    751: 
                    752: (defun roman-step (x n)
                    753:     (cond ((> x 9.)
                    754:           (roman-step (quotient x 10.) (1+ n))
                    755:           (setq x (remainder  x 10.))))
                    756:     (cond ((and (= x 9) (not roman-old))
                    757:           (roman-char 0 n)
                    758:           (roman-char 0 (1+ n)))
                    759:          ((= x 5)
                    760:           (roman-char 1 n))
                    761:          ((and (= x 4) (not roman-old))
                    762:           (roman-char 0 n)
                    763:           (roman-char 1 n))
                    764:          (t (cond ((> x 5)
                    765:                    (roman-char 1 n)
                    766:                    (setq x (- x 5))))
                    767:             (do i 0 (1+ i) (>= i x)
                    768:               (roman-char 0 n)))))
                    769: 
                    770: (defun roman-char (i x)
                    771:     (format:tyo (car (nthcdr (+ i x x) '(#/I #/V #/X #/L #/C #/D #/M)))
                    772:                         ;  i   v   x   l   c   d   m
                    773: ))
                    774: 
                    775: ;;; Kludges to make MacLISP like some of the LISPM functions
                    776: 
                    777: 
                    778: (defun format:tyo (char)
                    779:    (cond ((dtpr Format-Standard-Output)
                    780:          (rplacd Format-Standard-Output
                    781:                  (cons char (cdr Format-Standard-Output))))
                    782:         (t (tyo char Format-Standard-Output))))
                    783: 
                    784: (defun format:patom (arg)
                    785:    (format:printorpatom arg nil))
                    786: 
                    787: (defun format:print (arg)
                    788:    (format:printorpatom arg t))
                    789: 
                    790: (defun format:printorpatom (argument slashify)
                    791:    (cond ((dtpr Format-Standard-Output)
                    792:          (rplacd Format-Standard-Output
                    793:                  (nreconc (cond (slashify
                    794:                                         (mapcar '(lambda (x)
                    795:                                                     (getcharn x 1))
                    796:                                                 (explode argument)))
                    797:                                        ((exploden argument)))
                    798:                                  (cdr Format-Standard-Output))))
                    799:         (t (cond (slashify (print argument Format-Standard-Output))
                    800:                  (t (patom argument Format-Standard-Output))))))
                    801: 
                    802: (defun format:terpr nil
                    803:    (cond ((dtpr Format-Standard-Output)
                    804:          (rplacd Format-Standard-Output
                    805:                  (cons #\newline (cdr Format-Standard-Output))))
                    806:         (t (terpr Format-Standard-Output))))
                    807: 
                    808: (defun format:fresh-line nil
                    809:    (cond ((dtpr Format-Standard-Output)
                    810:          (cond ((and (cdr Format-Standard-Output)
                    811:                      (not (= (cadr Format-Standard-Output) #\newline)))
                    812:                 (rplacd Format-Standard-Output
                    813:                         (cons #\newline (cdr Format-Standard-Output))))))
                    814:         (t (and (not (= 0 (nwritn Format-Standard-Output)))
                    815:                 (terpr Format-Standard-Output)))))
                    816:    
                    817:          
                    818: 
                    819: 
                    820: (defun format\:string-search-char (char str start-pos)
                    821:        (declare (fixnum i start-pos str-len))
                    822:        (do ((i start-pos (1+ i))
                    823:            (str-len (flatc str)))
                    824:           ((>& i str-len) nil)
                    825:           (and (=& char (getcharn str (1+ i))) (return i))))
                    826: 
                    827: (defun format\:nsubstring (str from to)
                    828:        (declare (fixnum i from to))
                    829:        (substring str (+ 1 from) (- to from)))  ;substring is 1 based
                    830: 
                    831: (defun ferror (&rest args)
                    832:    (let (str)
                    833:       ; if the first arg to ferror is a string we assume that it is the
                    834:       ; format control string, otherwise we assume that it is a port
                    835:       ; specification, and we ignore it since we want to build a string.
                    836:       (if (stringp (car args))
                    837:         then (setq str (lexpr-funcall 'format nil args))
                    838:         else (setq str (lexpr-funcall 'format nil (cdr args))))
                    839:       (error str)))
                    840: 
                    841: 
                    842: (defun format-test nil
                    843:    (format t "Start test, newline:~%freshline:~&")
                    844:    (format t "decimal:~d, width=5:~5d~%" 10 10)
                    845:    (format t "decimal pad with period:~10,vd~%" #/.  12)
                    846:    (format t "char normal:~c, as # would read:~@c, human read:~:c~%"
                    847:           #\space #\space #\space)
                    848:    (format t "cardinal:~r, roman new:~@r, roman-old:~:@r~
                    849:                <same line I hope>~@
                    850:                new line but at beginning~:
                    851:    same line, but spaced out~:@
                    852:        new line and over two tabs~%" 4 4 4))
                    853: 
                    854: (putprop 'format t 'version)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.