4 ;; utils used throughout the code
6 (defmacro with-gensyms
((&rest names
) &body body
)
7 `(let ,(loop for n in names collect
`(,n
(gensym)))
10 (defmacro once-only
((&rest names
) &body body
)
11 (let ((gensyms (loop for n in names collect
(gensym))))
12 `(let (,@(loop for g in gensyms collect
`(,g
(gensym))))
13 `(let (,,@(loop for g in gensyms for n in names collect
``(,,g
,,n
)))
14 ,(let (,@(loop for n in names for g in gensyms collect
`(,n
,g
)))
17 (defun make-extensible-string (dimensions &key
(initial-element #\Space
))
18 "Create an ajustable string"
19 (make-array dimensions
20 :element-type
'character
21 :initial-element initial-element
23 :fill-pointer dimensions
))
25 (defmacro indefinitely
((var form
) &body body
)
26 "Expand to a form that repeatedly binds var to form and evaluates body until
27 something goes wrong (like a condition being signalled)"
28 `(do ((,var
,form
,form
))
33 (defun extend-string (elements string
)
34 "Add the elements to the end of the extensitble string."
35 (assert (adjustable-array-p string
))
37 ((extend-string-with-string (chars string
)
39 (for char in-vector chars
)
40 (vector-push-extend char string
))
43 (character (vector-push-extend elements string
))
44 (symbol (extend-string-with-string (string elements
) string
))
45 (string (extend-string-with-string elements string
))
46 (number (extend-string-with-string (format nil
"~D" elements
) string
))
47 (list (mapcar #'(lambda (x)
48 (extend-string x string
))
52 (defun collapse-string (stringlist)
53 "Given a list of strings collapse it to a single string."
54 (let ((result (make-extensible-string 0)))
56 (for string in stringlist
)
58 (for char in-vector string
)
59 (vector-push-extend char result
)))
63 (defmacro formatting
(stream initial-string
&rest args
)
64 "Format replacement using keywords rather than a control string."
66 ((add-numeric-control (control-char control-keys format-string
)
67 (extend-string #\~ format-string
)
69 (&key width fillchar form
)
71 (declare (ignore form
))
73 (extend-string width format-string
)
75 (extend-string #\
, format-string
)
76 (extend-string #\' format-string
)
77 (extend-string fillchar format-string
)))
78 (extend-string control-char format-string
)))
79 (process-control-item (control)
80 (let ((format-string (make-extensible-string 0)))
83 (extend-string control format-string
))
87 (:tab
(extend-string "~T" format-string
))
88 (:binary
(extend-string "~B" format-string
))
89 (:octal
(extend-string "~O" format-string
))
90 (:decimal
(extend-string "~D" format-string
))
91 (:hex
(extend-string "~X" format-string
))
92 (:newline
(extend-string "~%" format-string
))
93 (:freshline
(extend-string "~&" format-string
))
94 (:page
(extend-string "~|" format-string
))
95 (:pretty
(extend-string "~A" format-string
))
96 (:readable
(extend-string "~S" format-string
))
97 (:write
(extend-string "~W" format-string
))))
99 ;; handle complex forms
100 (case (first control
)
101 (:binary
(add-numeric-control #\B
(rest control
) format-string
))
102 (:octal
(add-numeric-control #\O
(rest control
) format-string
))
103 (:decimal
(add-numeric-control #\D
(rest control
) format-string
))
104 (:hex
(add-numeric-control #\X
(rest control
) format-string
))))
106 (extend-string control format-string
))
109 (process-argument-item (control)
111 (symbol (when (not (keywordp control
)) control
))
112 (list (car (last control
)))
115 ,(collapse-string (cons initial-string
(mapcar #'process-control-item args
)))
116 ,@(remove-if #'null
(mapcar #'process-argument-item args
)))))