Add ability to dump command line options in texi format
[maxima.git] / src / command-line.lisp
blob5e9fb4edcddaed5655c381962d0a96f2c379358e
1 ;;;; command-line.lisp -- Application command line argument retrieval
2 ;;;; and processing for Common Lisp.
4 ;;;; Copyright (C) 2003 James F. Amundson
6 ;;;; command-line.lisp is free software; you can redistribute it
7 ;;;; and/or modify it under the terms of the GNU General Public
8 ;;;; License as published by the Free Software Foundation; either
9 ;;;; version 2, or (at your option) any later version.
11 ;;;; command-line.lisp is distributed in the hope that it will be
12 ;;;; useful, but WITHOUT ANY WARRANTY; without even the implied
13 ;;;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 ;;;; See the GNU General Public License for more details.
16 ;;;; You should have received a copy of the GNU General Public License
17 ;;;; along with command-line.lisp; see the file COPYING. If not,
18 ;;;; write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20 ;; Defined in maxima-package.
21 ;; (defpackage "COMMAND-LINE"
22 ;; (:use "COMMON-LISP")
23 ;; (:nicknames "CMDLINE")
24 ;; (:export "CL-OPTION" "MAKE-CL-OPTION" "LIST-CL-OPTIONS" "PROCESS-ARGS"
25 ;; "GET-APPLICATION-ARGS"))
27 (in-package :command-line)
29 (defstruct cl-option
30 (names nil)
31 (argument nil)
32 (action nil)
33 (help-string nil))
35 (defun cl-option-description (name arg)
36 (if arg
37 (cond ((= (length name) 1) (format nil "~a ~a" name arg))
38 ((equal (subseq name 0 2) "--") (format nil "~a=~a" name arg))
39 (t (format nil "~a ~a" name arg)))
40 name))
42 #-gcl
43 (defun print-help-string (help-string)
44 "Print the help string neatly by breaking long lines as needed.
45 This assumes that the HELP-STRING doesn't have any kind of manually
46 inserted formatting."
47 ;; Break the string into a list of words, where any number of
48 ;; whitespace characters separates the words.
49 (let ((words (pregexp::pregexp-split "\\s+" help-string)))
50 ;; Print the list of words individually with a single space after,
51 ;; and inserting a newline as needed. Each line is prefixed by 8
52 ;; spaces. This bit of code is a slightly modified pprint-vector
53 ;; example from
54 ;; http://www.lispworks.com/documentation/HyperSpec/Body/22_bb.htm.
55 (let ((*print-right-margin* 80))
56 (pprint-logical-block (nil nil :prefix " ")
57 (let ((end (length words))
58 (k 0))
59 (when (plusp end)
60 (loop (pprint-pop)
61 (princ (elt words k))
62 (if (= (incf k) end) (return nil))
63 (write-char #\space)
64 (pprint-newline :fill))))))))
66 ;; Gcl doesn't have pprint-logical-block and friends and I (rtoy) am
67 ;; not going to try to implement it. Just print the whole string out
68 ;; as we used to do before.
69 #+gcl
70 (defun print-help-string (help-string)
71 (format t " ~a" help-string))
73 (defun list-cl-options (cl-option-list &key texi-table-form)
74 (if texi-table-form
75 (format t "@need 100
76 @table @code
78 (format t "options:~%"))
79 (dolist (opt cl-option-list)
80 (let ((help-string (cl-option-help-string opt))
81 (names (cl-option-names opt))
82 (arg (cl-option-argument opt)))
83 (when texi-table-form
84 (format t "@need 150~%@item "))
85 (format t " ~a" (cl-option-description (first names) arg))
86 (dolist (name (rest names))
87 (format t ", ~a" (cl-option-description name arg)))
88 (terpri)
89 (when help-string
90 (print-help-string help-string))
91 (when texi-table-form
92 (format t "~2%"))
93 (terpri)))
94 (when texi-table-form
95 (format t "@end table~%"))
96 (finish-output))
98 (defun process-args (args cl-option-list)
99 (flet ((fixup (options)
100 ;; Massage cl-option into the format wanted by getopt.
101 ;; Basically, remove any leading dashes, and if the
102 ;; cl-option includes an argument, treat it as a required
103 ;; argument.
104 (let ((opts nil))
105 (dolist (o options)
106 (dolist (name (cl-option-names o))
107 (push (list (string-left-trim "-" name)
108 (if (cl-option-argument o)
109 :required
110 :none)
111 nil)
112 opts)))
113 (nreverse opts))))
114 (let ((options (fixup cl-option-list)))
115 (multiple-value-bind (non-opts opts errors)
116 (getopt:getopt args options :allow-exact-match t)
117 (declare (ignore non-opts)) ;non-opts ignored for now
118 ;; Look over all of opts and run the action
119 #+nil (format t "opts = ~S~%" opts)
120 (dolist (o opts)
121 ;; Try to find the corresponding cl-option.
122 (let ((cl-opt (find (car o)
123 cl-option-list
124 :test #'(lambda (desired e)
125 ;; Strip off any leading
126 ;; dashes from the option name
127 ;; and compare with the
128 ;; desired option.
129 (member desired (cl-option-names e)
130 :test #'equal
131 :key #'(lambda (e)
132 (string-left-trim "-" e)))))))
133 #+nil (format t "Processing ~S -> ~S~%" o cl-opt)
134 (if cl-opt
135 (cond ((and (cl-option-action cl-opt) (cl-option-argument cl-opt))
136 (funcall (cl-option-action cl-opt) (cdr o)))
137 ((cl-option-action cl-opt)
138 (funcall (cl-option-action cl-opt))))
139 (warn "Could not find option ~S in cl-options: ~S.~%Please report this bug."
140 o cl-option-list))))
141 (format t "~{Warning: argument ~A not recognized.~%~}" errors)
142 ;; What do we do about non-option arguments? We just ignore them for now.
143 ))))
146 (defun get-application-args ()
147 ;; -- is used to distinguish between options for a lisp implementation
148 ;; and for Maxima.
149 (flet ((remove-implementation-args (arglist)
150 (let ((dashes (member "--" arglist :test #'equal)))
151 (if dashes
152 (cdr dashes)
153 arglist))))
154 (remove-implementation-args
155 #+clisp
156 (rest ext:*args*)
158 #+ecl
159 (rest (ext:command-args))
161 #+cmu
162 (if (boundp 'ext::*command-line-application-arguments*)
163 ext::*command-line-application-arguments*
164 (rest ext:*command-line-strings*))
166 #+scl
167 (rest ext:*command-line-strings*)
169 #+sbcl
170 (rest sb-ext:*posix-argv*)
172 #+gcl
173 (rest si:*command-args*)
175 #+allegro
176 (rest (system:command-line-arguments :application t))
178 #+lispworks
179 (rest system:*line-arguments-list*)
181 #+openmcl
182 (rest ccl:*command-line-argument-list*)
184 #+abcl
185 ext:*command-line-argument-list*)))