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
)
35 (defun cl-option-description (name 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
)))
42 (defun list-cl-options (cl-option-list)
43 (format t
"options:~%")
44 (dolist (opt cl-option-list
)
45 (let ((help-string (cl-option-help-string opt
))
46 (names (cl-option-names opt
))
47 (arg (cl-option-argument opt
)))
48 (format t
" ~a" (cl-option-description (first names
) arg
))
49 (dolist (name (rest names
))
50 (format t
", ~a" (cl-option-description name arg
)))
53 (format t
" ~a" help-string
))
57 ;; Old argument processing. Leaving this here for now, but if getopts
58 ;; works well enough, then these should be removed.
61 (defun parse-args (args cl-option-list
)
64 (let ((arg (pop args
))
66 (dolist (opt cl-option-list
)
67 (when (member arg
(cl-option-names opt
) :test
#'equal
)
68 (cond ((and (cl-option-action opt
) (cl-option-argument opt
))
69 (funcall (cl-option-action opt
) (pop args
)))
70 ((cl-option-action opt
)
71 (funcall (cl-option-action opt
)))
72 ((cl-option-argument opt
)
76 (unless (or arg-matched
(equal arg
""))
77 (format t
"Warning: argument ~a not recognized~%" arg
))
78 (parse-args args cl-option-list
))))
80 (defun expand-compound-arg (arg)
81 (map 'list
#'(lambda (char) (concatenate 'string
"-" (string char
)))
84 (defun expand-equals-arg (arg)
85 (let ((equals-position (search "=" arg
)))
86 (list (subseq arg
0 equals-position
) (subseq arg
(+ 1 equals-position
)))))
88 (defun expand-args (args)
91 (let* ((arg (car args
))
92 (rest (expand-args (cdr args
)))
94 (cond ((< (length arg
) 2) nil
)
95 ((and (equal (subseq arg
0 2) "--") (search "=" arg
))
96 (setf listarg
(expand-equals-arg arg
)))
97 ((equal (subseq arg
0 2) "--") nil
)
98 ((equal (char arg
0) #\-
)
99 (if (> (length arg
) 2)
100 (setf listarg
(expand-compound-arg arg
)))))
101 (append listarg rest
))))
103 (defun process-args (args cl-option-list
)
104 (parse-args (expand-args args
) cl-option-list
))
107 (defun process-args (args cl-option-list
)
108 (flet ((fixup (options)
109 ;; Massage cl-option into the format wanted by getopt.
110 ;; Basically, remove any leading dashes, and if the
111 ;; cl-option includes an argument, treat it as a required
115 (dolist (name (cl-option-names o
))
116 (push (list (string-left-trim "-" name
)
117 (if (cl-option-argument o
)
123 (let ((options (fixup cl-option-list
)))
124 (multiple-value-bind (non-opts opts errors
)
125 (getopt:getopt args options
:allow-exact-match t
)
126 (declare (ignore non-opts
)) ;non-opts ignored for now
127 ;; Look over all of opts and run the action
128 #+nil
(format t
"opts = ~S~%" opts
)
130 ;; Try to find the corresponding cl-option.
131 (let ((cl-opt (find (car o
)
133 :test
#'(lambda (desired e
)
134 ;; Strip off any leading
135 ;; dashes from the option name
136 ;; and compare with the
138 (member desired
(cl-option-names e
)
141 (string-left-trim "-" e
)))))))
142 #+nil
(format t
"Processing ~S -> ~S~%" o cl-opt
)
144 (cond ((and (cl-option-action cl-opt
) (cl-option-argument cl-opt
))
145 (funcall (cl-option-action cl-opt
) (cdr o
)))
146 ((cl-option-action cl-opt
)
147 (funcall (cl-option-action cl-opt
))))
148 (warn "Could not find option ~S in cl-options: ~S.~%Please report this bug."
150 (format t
"~{Warning: argument ~A not recognized.~%~}" errors
)
151 ;; What do we do about non-option arguments? We just ignore them for now.
155 (defun get-application-args ()
156 ;; -- is used to distinguish between options for a lisp implementation
158 (flet ((remove-implementation-args (arglist)
159 (let ((dashes (member "--" arglist
:test
#'equal
)))
163 (remove-implementation-args
168 (rest (ext:command-args
))
171 (if (boundp 'ext
::*command-line-application-arguments
*)
172 ext
::*command-line-application-arguments
*
173 (rest ext
:*command-line-strings
*))
176 (rest ext
:*command-line-strings
*)
179 (rest sb-ext
:*posix-argv
*)
182 (rest si
:*command-args
*)
185 (rest (system:command-line-arguments
:application t
))
188 (rest system
:*line-arguments-list
*)
191 (rest ccl
:*command-line-argument-list
*)
194 ext
:*command-line-argument-list
*)))