optparse.lisp: Move `ignorable' declaration into the right place.
[lisp] / optparse.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; $Id$
4 ;;;
5 ;;; Option parser, standard issue
6 ;;;
7 ;;; (c) 2005 Straylight/Edgeware
8 ;;;
9
10 ;;;----- Licensing notice ---------------------------------------------------
11 ;;;
12 ;;; This program is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2 of the License, or
15 ;;; (at your option) any later version.
16 ;;;
17 ;;; This program is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with this program; if not, write to the Free Software Foundation,
24 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 ;;;--------------------------------------------------------------------------
27 ;;; Packages.
28
29 (defpackage #:optparse
30 (:use #:common-lisp #:mdw.base #:mdw.sys-base)
31 (:export #:exit #:*program-name* #:*command-line*
32 #:moan #:die
33 #:option #:optionp #:make-option
34 #:opt-short-name #:opt-long-name #:opt-tag #:opt-negated-tag
35 #:opt-arg-name #:opt-arg-optional-p #:opt-documentation
36 #:option-parser #:make-option-parser #:option-parser-p
37 #:op-options #:op-non-option #:op-long-only-p #:op-numeric-p
38 #:op-negated-numeric-p #:op-negated-p
39 #:option-parse-error
40 #:option-parse-remainder #:option-parse-next #:option-parse-try
41 #:with-unix-error-reporting #:option-parse-return
42 #:defopthandler #:invoke-option-handler
43 #:set #:clear #:inc #:dec #:read #:int #:string
44 #:keyword #:list
45 #:parse-option-form #:options
46 #:simple-usage #:show-usage #:show-version #:show-help
47 #:sanity-check-option-list
48 #:*help* #:*version* #:*usage* #:*options*
49 #:do-options #:help-options
50 #:define-program #:do-usage #:die-usage))
51
52 (in-package #:optparse)
53
54 ;;;--------------------------------------------------------------------------
55 ;;; Standard error-reporting functions.
56
57 (defun moan (msg &rest args)
58 "Report an error message in the usual way."
59 (format *error-output* "~&~A: ~?~%" *program-name* msg args))
60
61 (defun die (&rest args)
62 "Report an error message and exit."
63 (apply #'moan args)
64 (exit 1))
65
66 ;;;--------------------------------------------------------------------------
67 ;;; The main option parser.
68
69 (defvar *options* nil)
70
71 (defstruct (option
72 (:predicate optionp)
73 (:conc-name opt-)
74 (:print-function
75 (lambda (o s k)
76 (declare (ignore k))
77 (print-unreadable-object (o s :type t)
78 (format s "~@[-~C, ~]~@[--~A~]~
79 ~*~@[~2:*~:[=~A~;[=~A]~]~]~
80 ~@[ ~S~]"
81 (opt-short-name o)
82 (opt-long-name o)
83 (opt-arg-optional-p o)
84 (opt-arg-name o)
85 (opt-documentation o)))))
86 (:constructor %make-option)
87 (:constructor make-option
88 (long-name short-name
89 &optional arg-name
90 &key (tag (intern (string-upcase long-name) :keyword))
91 negated-tag
92 arg-optional-p
93 doc (documentation doc))))
94 "Describes a command-line option. Slots:
95
96 LONG-NAME The option's long name. If this is null, the `option' is
97 just a banner to be printed in the program's help text.
98
99 TAG The value to be returned if this option is encountered. If
100 this is a function, instead, the function is called with the
101 option's argument or nil.
102
103 NEGATED-TAG As for TAG, but used if the negated form of the option is
104 found. If this is nil (the default), the option cannot be
105 negated.
106
107 SHORT-NAME The option's short name. This must be a single character, or
108 nil if the option has no short name.
109
110 ARG-NAME The name of the option's argument, a string. If this is nil,
111 the option doesn't accept an argument. The name is shown in
112 the help text.
113
114 ARG-OPTIONAL-P
115 If non-nil, the option's argument is optional. This is
116 ignored unless ARG-NAME is non-null.
117
118 DOCUMENTATION
119 The help text for this option. It is automatically line-
120 wrapped. If nil, the option is omitted from the help
121 text.
122
123 Usually, one won't use make-option, but use the option macro instead."
124 (long-name nil :type (or null string))
125 (tag nil :type t)
126 (negated-tag nil :type t)
127 (short-name nil :type (or null character))
128 (arg-name nil :type (or null string))
129 (arg-optional-p nil :type t)
130 (documentation nil :type (or null string)))
131
132 (defstruct (option-parser
133 (:conc-name op-)
134 (:constructor make-option-parser
135 (&key ((:args argstmp) (cdr *command-line*))
136 (options *options*)
137 (non-option :skip)
138 ((:numericp numeric-p))
139 negated-numeric-p
140 long-only-p
141 &aux (args (cons nil argstmp))
142 (next args)
143 (negated-p (or negated-numeric-p
144 (some #'opt-negated-tag
145 options))))))
146 "An option parser object. Slots:
147
148 ARGS The arguments to be parsed. Usually this will be
149 *command-line*.
150
151 OPTIONS List of option structures describing the acceptable options.
152
153 NON-OPTION Behaviour when encountering a non-option argument. The
154 default is :skip. Allowable values are:
155 :skip -- pretend that it appeared after the option
156 arguments; this is the default behaviour of GNU getopt
157 :stop -- stop parsing options, leaving the remaining
158 command line unparsed
159 :return -- return :non-option and the argument word
160
161 NUMERIC-P Non-nil tag (as for options) if numeric options (e.g., -43)
162 are to be allowed. The default is nil. (Anomaly: the
163 keyword for this argument is :numericp.)
164
165 NEGATED-NUMERIC-P
166 Non-nil tag (as for options) if numeric options (e.g., -43)
167 can be negated. This is not the same thing as a negative
168 numeric option!
169
170 LONG-ONLY-P A misnomer inherited from GNU getopt. Whether to allow
171 long options to begin with a single dash. Short options are
172 still allowed, and may be cuddled as usual. The default is
173 nil."
174 (args nil :type list)
175 (options nil :type list)
176 (non-option :skip :type (or function (member :skip :stop :return)))
177 (next nil :type list)
178 (short-opt nil :type (or null string))
179 (short-opt-index 0 :type fixnum)
180 (short-opt-neg-p nil :type t)
181 (long-only-p nil :type t)
182 (numeric-p nil :type t)
183 (negated-numeric-p nil :type t)
184 (negated-p nil :type t))
185
186 (define-condition option-parse-error (error simple-condition)
187 ()
188 (:documentation
189 "Indicates an error found while parsing options. Probably not that
190 useful."))
191
192 (defun option-parse-error (msg &rest args)
193 "Signal an option-parse-error with the given message and arguments."
194 (error (make-condition 'option-parse-error
195 :format-control msg
196 :format-arguments args)))
197
198 (defun option-parse-remainder (op)
199 "Returns the unparsed remainder of the command line."
200 (cdr (op-args op)))
201
202 (defun option-parse-return (tag &optional argument)
203 "Should be called from an option handler: forces a return from the
204 immediately enclosing `option-parse-next' with the given TAG and
205 ARGUMENT."
206 (throw 'option-parse-return (values tag argument)))
207
208 (defun option-parse-next (op)
209 "The main option-parsing function. OP is an option-parser object,
210 initialized appropriately. Returns two values, OPT and ARG: OPT is the
211 tag of the next option read, and ARG is the argument attached to it, or
212 nil if there was no argument. If there are no more options, returns nil
213 twice. Options whose TAG is a function aren't returned; instead, the tag
214 function is called, with the option argument (or nil) as the only
215 argument. It is safe for tag functions to throw out of option-parse-next,
216 if they desparately need to. (This is the only way to actually get
217 option-parse-next to return a function value, should that be what you
218 want. See `option-parse-return' for a way of doing this.)
219
220 While option-parse-next is running, there is a restart `skip-option' which
221 moves on to the next option. Error handlers should use this to resume
222 after parsing errors."
223 (labels ((ret (opt &optional arg)
224 (return-from option-parse-next (values opt arg)))
225 (finished ()
226 (setf (op-next op) nil)
227 (ret nil nil))
228 (peek-arg ()
229 (cadr (op-next op)))
230 (more-args-p ()
231 (and (op-next op)
232 (cdr (op-next op))))
233 (skip-arg ()
234 (setf (op-next op) (cdr (op-next op))))
235 (eat-arg ()
236 (setf (cdr (op-next op)) (cddr (op-next op))))
237 (get-arg ()
238 (prog1 (peek-arg) (eat-arg)))
239 (process-option (o name negp &key arg argfunc)
240 (cond ((not (opt-arg-name o))
241 (when arg
242 (option-parse-error
243 "Option `~A' does not accept arguments"
244 name)))
245 (arg)
246 (argfunc
247 (setf arg (funcall argfunc)))
248 ((opt-arg-optional-p o))
249 ((more-args-p)
250 (setf arg (get-arg)))
251 (t
252 (option-parse-error "Option `~A' requires an argument"
253 name)))
254 (let ((how (if negp (opt-negated-tag o) (opt-tag o))))
255 (if (functionp how)
256 (funcall how arg)
257 (ret how arg))))
258 (process-long-option (arg start negp)
259 (when (and (not negp)
260 (op-negated-p op)
261 (> (length arg) (+ start 3))
262 (string= arg "no-"
263 :start1 start :end1 (+ start 3)))
264 (incf start 3)
265 (setf negp t))
266 (let* ((matches nil)
267 (eqpos (position #\= arg :start start))
268 (len (or eqpos (length arg)))
269 (optname (subseq arg 0 len))
270 (len-2 (- len start)))
271 (dolist (o (op-options op))
272 (cond ((or (not (stringp (opt-long-name o)))
273 (and negp (not (opt-negated-tag o)))
274 (< (length (opt-long-name o)) len-2)
275 (string/= optname (opt-long-name o)
276 :start1 start :end2 len-2)))
277 ((= (length (opt-long-name o)) len-2)
278 (setf matches (list o))
279 (return))
280 (t
281 (push o matches))))
282 (cond ((null matches)
283 (option-parse-error "Unknown option `~A'" optname))
284 ((cdr matches)
285 (option-parse-error
286 #.(concatenate 'string
287 "Ambiguous long option `~A' -- "
288 "could be any of:"
289 "~{~%~8T--~A~}")
290 optname
291 (mapcar #'opt-long-name matches))))
292 (process-option (car matches)
293 optname
294 negp
295 :arg (and eqpos
296 (subseq arg (1+ eqpos)))))))
297 (catch 'option-parse-return
298 (loop
299 (with-simple-restart (skip-option "Skip this bogus option.")
300 (cond
301 ;;
302 ;; We're embroiled in short options: handle them.
303 ((op-short-opt op)
304 (if (>= (op-short-opt-index op) (length (op-short-opt op)))
305 (setf (op-short-opt op) nil)
306 (let* ((str (op-short-opt op))
307 (i (op-short-opt-index op))
308 (ch (char str i))
309 (negp (op-short-opt-neg-p op))
310 (name (format nil "~C~A" (if negp #\+ #\-) ch))
311 (o (find ch (op-options op) :key #'opt-short-name)))
312 (incf i)
313 (setf (op-short-opt-index op) i)
314 (when (or (not o)
315 (and negp (not (opt-negated-tag o))))
316 (option-parse-error "Unknown option `~A'" name))
317 (process-option o
318 name
319 negp
320 :argfunc
321 (and (< i (length str))
322 (lambda ()
323 (prog1
324 (subseq str i)
325 (setf (op-short-opt op)
326 nil))))))))
327 ;;
328 ;; End of the list. Say we've finished.
329 ((not (more-args-p))
330 (finished))
331 ;;
332 ;; Process the next option.
333 (t
334 (let ((arg (peek-arg)))
335 (cond
336 ;;
337 ;; Non-option. Decide what to do.
338 ((or (<= (length arg) 1)
339 (and (char/= (char arg 0) #\-)
340 (or (char/= (char arg 0) #\+)
341 (not (op-negated-p op)))))
342 (case (op-non-option op)
343 (:skip (skip-arg))
344 (:stop (finished))
345 (:return (eat-arg)
346 (ret :non-option arg))
347 (t (eat-arg)
348 (funcall (op-non-option op) arg))))
349 ;;
350 ;; Double-hyphen. Stop right now.
351 ((string= arg "--")
352 (eat-arg)
353 (finished))
354 ;;
355 ;; Numbers. Check these before long options, since `--43'
356 ;; is not a long option.
357 ((and (op-numeric-p op)
358 (or (char= (char arg 0) #\-)
359 (op-negated-numeric-p op))
360 (or (and (digit-char-p (char arg 1))
361 (every #'digit-char-p (subseq arg 2)))
362 (and (or (char= (char arg 1) #\-)
363 (char= (char arg 1) #\+))
364 (>= (length arg) 3)
365 (digit-char-p (char arg 2))
366 (every #'digit-char-p (subseq arg 3)))))
367 (eat-arg)
368 (let ((negp (char= (char arg 0) #\+))
369 (num (parse-integer arg :start 1)))
370 (when (and negp (eq (op-negated-numeric-p op) :-))
371 (setf num (- num))
372 (setf negp nil))
373 (let ((how (if negp
374 (op-negated-numeric-p op)
375 (op-numeric-p op))))
376 (if (functionp how)
377 (funcall how num)
378 (ret (if negp :negated-numeric :numeric) num)))))
379 ;;
380 ;; Long option. Find the matching option-spec and process
381 ;; it.
382 ((and (char= (char arg 0) #\-)
383 (char= (char arg 1) #\-))
384 (eat-arg)
385 (process-long-option arg 2 nil))
386 ;;
387 ;; Short options. All that's left.
388 (t
389 (eat-arg)
390 (let ((negp (char= (char arg 0) #\+))
391 (ch (char arg 1)))
392 (cond ((and (op-long-only-p op)
393 (not (member ch (op-options op)
394 :key #'opt-short-name)))
395 (process-long-option arg 1 negp))
396 (t
397 (setf (op-short-opt op) arg
398 (op-short-opt-index op) 1
399 (op-short-opt-neg-p op) negp))))))))))))))
400
401 (defmacro option-parse-try (&body body)
402 "Report errors encountered while parsing options, and continue struggling
403 along. Also establishes a restart `stop-parsing'. Returns t if parsing
404 completed successfully, or nil if errors occurred."
405 (with-gensyms (retcode)
406 `(let ((,retcode t))
407 (restart-case
408 (handler-bind
409 ((option-parse-error
410 (lambda (cond)
411 (setf ,retcode nil)
412 (moan "~A" cond)
413 (dolist (rn '(skip-option stop-parsing))
414 (let ((r (find-restart rn)))
415 (when r (invoke-restart r)))))))
416 ,@body)
417 (stop-parsing ()
418 :report "Give up parsing options."
419 (setf ,retcode nil)))
420 ,retcode)))
421
422 (defmacro with-unix-error-reporting ((&key) &body body)
423 "Evaluate BODY with errors reported in the standard Unix fashion."
424 (with-gensyms (cond)
425 `(handler-case
426 (progn ,@body)
427 (simple-condition (,cond)
428 (apply #'die
429 (simple-condition-format-control ,cond)
430 (simple-condition-format-arguments ,cond)))
431 (error (,cond)
432 (die "~A" ,cond)))))
433
434 ;;;--------------------------------------------------------------------------
435 ;;; Standard option handlers.
436
437 (defmacro defopthandler (name (var &optional (arg (gensym)))
438 (&rest args)
439 &body body)
440 "Define an option handler function NAME. Option handlers update a
441 generalized variable, which may be referred to as VAR in the BODY, based
442 on some parameters (the ARGS) and the value of an option-argument named
443 ARG."
444 (let ((func (intern (format nil "OPTHANDLER/~:@(~A~)" name))))
445 (with-parsed-body (body decls docs) body
446 `(progn
447 (setf (get ',name 'opthandler) ',func)
448 (defun ,func (,var ,arg ,@args)
449 ,@docs ,@decls
450 (declare (ignorable ,arg))
451 (with-locatives ,var
452 ,@body))
453 ',name))))
454
455 (defun parse-c-integer (string &key radix (start 0) end)
456 "Parse STRING, or at least the parts of it between START and END, according
457 to the standard C rules. Well, almost: the 0 and 0x prefixes are
458 accepted, but so too are 0o (Haskell) and 0b (original); also RADIX_DIGITS
459 is accepted, for any radix between 2 and 36. Prefixes are only accepted
460 if RADIX is nil. Returns two values: the integer parsed (or nil if there
461 wasn't enough for a sensible parse), and the index following the
462 characters of the integer."
463 (setf-default end (length string))
464 (labels ((simple (i r goodp sgn)
465 (multiple-value-bind
466 (a i)
467 (if (and (< i end)
468 (digit-char-p (char string i) r))
469 (parse-integer string
470 :start i :end end
471 :radix r
472 :junk-allowed t)
473 (values nil i))
474 (values (if a (* sgn a) (and goodp 0)) i)))
475 (get-radix (i r sgn)
476 (cond (r (simple i r nil sgn))
477 ((>= i end) (values nil i))
478 ((and (char= (char string i) #\0)
479 (>= (- end i) 2))
480 (case (char string (1+ i))
481 (#\x (simple (+ i 2) 16 nil sgn))
482 (#\o (simple (+ i 2) 8 nil sgn))
483 (#\b (simple (+ i 2) 2 nil sgn))
484 (t (simple (1+ i) 8 t sgn))))
485 (t
486 (multiple-value-bind
487 (r i)
488 (simple i 10 nil +1)
489 (cond ((not r) (values nil i))
490 ((and (< i end)
491 (char= (char string i) #\_)
492 (<= 2 r 36))
493 (simple (1+ i) r nil sgn))
494 (t
495 (values (* r sgn) i))))))))
496 (cond ((>= start end) (values nil start))
497 ((char= (char string start) #\-)
498 (get-radix (1+ start) radix -1))
499 ((char= (char string start) #\+)
500 (get-radix (1+ start) radix +1))
501 (t
502 (get-radix start radix +1)))))
503
504 (defun invoke-option-handler (handler loc arg args)
505 "Call the HANDLER function, giving it LOC to update, the option-argument
506 ARG, and the remaining ARGS."
507 (apply (if (functionp handler) handler
508 (fdefinition (get handler 'opthandler)))
509 loc
510 arg
511 args))
512
513 ;;;--------------------------------------------------------------------------
514 ;;; Built-in option handlers.
515
516 (defopthandler set (var) (&optional (value t))
517 "Sets VAR to VALUE; defaults to t."
518 (setf var value))
519
520 (defopthandler clear (var) (&optional (value nil))
521 "Sets VAR to VALUE; defaults to nil."
522 (setf var value))
523
524 (defopthandler inc (var) (&optional max (step 1))
525 "Increments VAR by STEP (defaults to 1), but not greater than MAX (default
526 nil for no maximum). No errors are signalled."
527 (incf var step)
528 (when (>= var max)
529 (setf var max)))
530
531 (defopthandler dec (var) (&optional min (step 1))
532 "Decrements VAR by STEP (defaults to 1), but not less than MIN (default nil
533 for no maximum). No errors are signalled."
534 (decf var step)
535 (when (<= var min)
536 (setf var min)))
537
538 (defopthandler read (var arg) ()
539 "Stores in VAR the Lisp object found by reading the ARG. Evaluation is
540 forbidden while reading ARG. If there is an error during reading, an
541 error of type option-parse-error is signalled."
542 (handler-case
543 (let ((*read-eval* nil))
544 (multiple-value-bind (x end) (read-from-string arg t)
545 (unless (>= end (length arg))
546 (option-parse-error "Junk at end of argument `~A'" arg))
547 (setf var x)))
548 (error (cond)
549 (option-parse-error (format nil "~A" cond)))))
550
551 (defopthandler int (var arg) (&key radix min max)
552 "Stores in VAR the integer read from the ARG. Integers are parsed
553 according to C rules, which is normal in Unix; the RADIX may be nil to
554 allow radix prefixes, or an integer between 2 and 36. An
555 option-parse-error is signalled if the ARG is not a valid integer, or if
556 it is not between MIN and MAX (either of which may be nil if no lower
557 resp. upper bound is wanted)."
558 (multiple-value-bind (v end) (parse-c-integer arg :radix radix)
559 (unless (and v (>= end (length arg)))
560 (option-parse-error "Bad integer `~A'" arg))
561 (when (or (and min (< v min))
562 (and max (> v max)))
563 (option-parse-error
564 #.(concatenate 'string
565 "Integer ~A out of range "
566 "(must have ~@[~D <= ~]x~@[ <= ~D~])")
567 arg min max))
568 (setf var v)))
569
570 (defopthandler string (var arg) ()
571 "Stores ARG in VAR, just as it is."
572 (setf var arg))
573
574 (defopthandler keyword (var arg) (&optional (valid t))
575 "Converts ARG into a keyword. If VALID is t, then any ARG string is
576 acceptable: the argument is uppercased and interned in the keyword
577 package. If VALID is a list, then we ensure that ARG matches one of the
578 elements of the list; unambigious abbreviations are allowed."
579 (etypecase valid
580 ((member t)
581 (setf var (intern (string-upcase arg) :keyword)))
582 (list
583 (let ((matches nil)
584 (guess (string-upcase arg))
585 (len (length arg)))
586 (dolist (k valid)
587 (let* ((kn (symbol-name k))
588 (klen (length kn)))
589 (cond ((string= kn guess)
590 (setf matches (list k))
591 (return))
592 ((and (< len klen)
593 (string= guess kn :end2 len))
594 (push k matches)))))
595 (cond
596 ((null matches)
597 (option-parse-error #.(concatenate 'string
598 "Argument `~A' invalid: "
599 "must be one of:"
600 "~{~%~8T~(~A~)~}")
601 arg valid))
602 ((null (cdr matches))
603 (setf var (car matches)))
604 (t
605 (option-parse-error #.(concatenate 'string
606 "Argument `~A' ambiguous: "
607 "may be any of:"
608 "~{~%~8T~(~A~)~}")
609 arg matches)))))))
610
611 (defopthandler list (var arg) (&optional handler &rest handler-args)
612 "Collect ARGs in a list at VAR. ARGs are translated by the HANDLER first,
613 if specified. If not, it's as if you asked for `string'."
614 (when handler
615 (invoke-option-handler handler (locf arg) arg handler-args))
616 (setf var (nconc var (list arg))))
617
618 ;;;--------------------------------------------------------------------------
619 ;;; Option descriptions.
620
621 (defmacro defoptmacro (name args &body body)
622 "Defines an option macro NAME. Option macros should produce a list of
623 expressions producing one option structure each."
624 `(progn
625 (setf (get ',name 'optmacro) (lambda ,args ,@body))
626 ',name))
627
628 (compile-time-defun parse-option-form (form)
629 "Does the heavy lifting for parsing an option form. See the docstring for
630 the `option' macro for details of the syntax."
631 (flet ((doc (form)
632 (cond ((stringp form) form)
633 ((null (cdr form)) (car form))
634 (t `(format nil ,@form))))
635 (docp (form)
636 (or (stringp form)
637 (and (consp form)
638 (stringp (car form))))))
639 (cond ((stringp form)
640 `(%make-option :documentation ,form))
641 ((not (listp form))
642 (error "option form must be string or list"))
643 ((and (docp (car form)) (null (cdr form)))
644 `(%make-option :documentation ,(doc (car form))))
645 (t
646 (let (long-name short-name
647 arg-name arg-optional-p
648 tag negated-tag
649 doc)
650 (dolist (f form)
651 (cond ((and (or (not tag) (not negated-tag))
652 (or (keywordp f)
653 (and (consp f)
654 (member (car f) '(lambda function)))))
655 (if tag
656 (setf negated-tag f)
657 (setf tag f)))
658 ((and (not long-name)
659 (or (rationalp f)
660 (symbolp f)
661 (stringp f)))
662 (setf long-name (if (stringp f) f
663 (format nil "~(~A~)" f))))
664 ((and (not short-name)
665 (characterp f))
666 (setf short-name f))
667 ((and (not doc)
668 (docp f))
669 (setf doc (doc f)))
670 ((and (consp f) (symbolp (car f)))
671 (case (car f)
672 (:short-name (setf short-name (cadr f)))
673 (:long-name (setf long-name (cadr f)))
674 (:tag (setf tag (cadr f)))
675 (:negated-tag (setf negated-tag (cadr f)))
676 (:arg (setf arg-name (cadr f)))
677 (:opt-arg (setf arg-name (cadr f))
678 (setf arg-optional-p t))
679 (:doc (setf doc (doc (cdr f))))
680 (t (let ((handler (get (car f) 'opthandler)))
681 (unless handler
682 (error "No handler `~S' defined." (car f)))
683 (let* ((var (cadr f))
684 (arg (gensym))
685 (thunk `#'(lambda (,arg)
686 (,handler (locf ,var)
687 ,arg
688 ,@(cddr f)))))
689 (if tag
690 (setf negated-tag thunk)
691 (setf tag thunk)))))))
692 (t
693 (error "Unexpected thing ~S in option form." f))))
694 `(make-option ,long-name ,short-name ,arg-name
695 ,@(and arg-optional-p `(:arg-optional-p t))
696 ,@(and tag `(:tag ,tag))
697 ,@(and negated-tag `(:negated-tag ,negated-tag))
698 ,@(and doc `(:documentation ,doc))))))))
699
700 (defmacro options (&rest optlist)
701 "More convenient way of initializing options. The OPTLIST is a list of
702 OPTFORMS. Each OPTFORM is one of the following:
703
704 STRING A banner to print.
705
706 SYMBOL or (SYMBOL STUFF...)
707 If SYMBOL is an optform macro, the result of invoking it.
708
709 (...) A full option-form. See below.
710
711 Full option-forms are a list of the following kinds of items.
712
713 (:short-name CHAR)
714 (:long-name STRING)
715 (:arg STRING)
716 (:tag TAG)
717 (:negated-tag TAG)
718 (:doc STRING)
719 Set the appropriate slot of the option to the given value.
720 The argument is evaluated.
721
722 (:doc FORMAT-CONTROL ARGUMENTS...)
723 As for (:doc (format nil FORMAT-CONTROL ARGUMENTS...)).
724
725 KEYWORD, (function ...), (lambda ...)
726 If no TAG is set yet, then as a TAG; otherwise as the
727 NEGATED-TAG.
728
729 STRING (or SYMBOL or RATIONAL)
730 If no LONG-NAME seen yet, then the LONG-NAME. For symbols
731 and rationals, the item is converted to a string and squashed
732 to lower-case.
733
734 CHARACTER If no SHORT-NAME, then the SHORT-NAME.
735
736 STRING or (STRING STUFF...)
737 If no DOCUMENTATION set yet, then the DOCUMENTATION string,
738 as for (:doc STRING STUFF...)
739
740 (:opt-arg NAME)
741 Set the ARG-NAME, and also set ARG-OPTIONAL-P.
742
743 (HANDLER VAR ARGS...)
744 If no TAG is set yet, attach the HANDLER to this option,
745 giving it ARGS. Otherwise, set the NEGATED-TAG."
746
747 `(list ,@(mapcan (lambda (form)
748 (multiple-value-bind
749 (sym args)
750 (cond ((symbolp form) (values form nil))
751 ((and (consp form) (symbolp (car form)))
752 (values (car form) (cdr form)))
753 (t (values nil nil)))
754 (let ((macro (and sym (get sym 'optmacro))))
755 (if macro
756 (apply macro args)
757 (list (parse-option-form form))))))
758 optlist)))
759
760 ;;;--------------------------------------------------------------------------
761 ;;; Support stuff for help and usage messages.
762
763 (defun print-text (string
764 &optional
765 (stream *standard-output*)
766 &key
767 (start 0)
768 (end nil))
769 "Prints STRING to a pretty-printed STREAM, breaking it at whitespace and
770 newlines in the obvious way. Stuff between square brackets is not broken:
771 this makes usage messages work better."
772 (let ((i start)
773 (nest 0)
774 (splitp nil))
775 (flet ((emit ()
776 (write-string string stream :start start :end i)
777 (setf start i)))
778 (setf-default end (length string))
779 (loop
780 (unless (< i end)
781 (emit)
782 (return))
783 (let ((ch (char string i)))
784 (cond ((char= ch #\newline)
785 (emit)
786 (incf start)
787 (pprint-newline :mandatory stream))
788 ((whitespace-char-p ch)
789 (when (zerop nest)
790 (setf splitp t)))
791 (t
792 (when splitp
793 (emit)
794 (pprint-newline :fill stream))
795 (setf splitp nil)
796 (case ch
797 (#\[ (incf nest))
798 (#\] (when (plusp nest) (decf nest))))))
799 (incf i))))))
800
801 (defun simple-usage (opts &optional mandatory-args)
802 "Build a simple usage list from a list of options, and (optionally)
803 mandatory argument names."
804 (let (short-simple long-simple short-arg long-arg)
805 (dolist (o opts)
806 (cond ((not (and (opt-documentation o)
807 (opt-long-name o))))
808 ((and (opt-short-name o) (opt-arg-name o))
809 (push o short-arg))
810 ((opt-short-name o)
811 (push o short-simple))
812 ((opt-arg-name o)
813 (push o long-arg))
814 (t
815 (push o long-simple))))
816 (list
817 (nconc (and short-simple
818 (list (format nil "[-~{~C~}]"
819 (sort (mapcar #'opt-short-name short-simple)
820 #'char<))))
821 (and long-simple
822 (mapcar (lambda (o)
823 (format nil "[--~A]" (opt-long-name o)))
824 (sort long-simple #'string< :key #'opt-long-name)))
825 (and short-arg
826 (mapcar (lambda (o)
827 (format nil "~:[[-~C ~A]~;[-~C[~A]]~]"
828 (opt-arg-optional-p o)
829 (opt-short-name o)
830 (opt-arg-name o)))
831 (sort short-arg #'char-lessp
832 :key #'opt-short-name)))
833 (and long-arg
834 (mapcar (lambda (o)
835 (format nil "~:[[--~A ~A]~;[--~A[=~A]]~]"
836 (opt-arg-optional-p o)
837 (opt-long-name o)
838 (opt-arg-name o)))
839 (sort long-arg #'string-lessp
840 :key #'opt-long-name)))
841 (listify mandatory-args)))))
842
843 (defun show-usage (prog usage &optional (stream *standard-output*))
844 "Basic usage-showing function. PROG is the program name, probably from
845 *command-line*. USAGE is a list of possible usages of the program, each
846 of which is a list of items to be supplied by the user. In simple cases,
847 a single string is sufficient."
848 (pprint-logical-block (stream nil :prefix "Usage: ")
849 (dolist (u (listify usage))
850 (pprint-logical-block (stream nil
851 :prefix (concatenate 'string prog " "))
852 (format stream "~{~A ~:_~}" (listify u)))
853 (pprint-newline :mandatory stream))))
854
855 (defun show-options-help (opts &optional (stream *standard-output*))
856 "Write help for OPTS to the STREAM. This is the core of the `show-help'
857 function."
858 (let (newlinep)
859 (dolist (o opts)
860 (let ((doc (opt-documentation o)))
861 (cond ((not o))
862 ((not (opt-long-name o))
863 (when newlinep
864 (terpri stream)
865 (setf newlinep nil))
866 (pprint-logical-block (stream nil)
867 (print-text doc stream))
868 (terpri stream))
869 (t
870 (setf newlinep t)
871 (pprint-logical-block (stream nil :prefix " ")
872 (format stream "~:[ ~;-~:*~C,~] --~A"
873 (opt-short-name o)
874 (opt-long-name o))
875 (when (opt-arg-name o)
876 (format stream "~:[=~A~;[=~A]~]"
877 (opt-arg-optional-p o)
878 (opt-arg-name o)))
879 (write-string " " stream)
880 (pprint-tab :line 30 1 stream)
881 (pprint-indent :block 30 stream)
882 (print-text doc stream))
883 (terpri stream)))))))
884
885 (defun show-help (prog ver usage opts &optional (stream *standard-output*))
886 "Basic help-showing function. PROG is the program name, probably from
887 *command-line*. VER is the program's version number. USAGE is a list of
888 the possible usages of the program, each of which may be a list of items
889 to be supplied. OPTS is the list of supported options, as provided to the
890 options parser. STREAM is the stream to write on."
891 (format stream "~A, version ~A~2%" prog ver)
892 (show-usage prog usage stream)
893 (terpri stream)
894 (show-options-help opts stream))
895
896 (defun sanity-check-option-list (opts)
897 "Check the option list OPTS for basic sanity. Reused short and long option
898 names are diagnosed. Maybe other problems will be reported later.
899 Returns a list of warning strings."
900 (let ((problems nil)
901 (longs (make-hash-table :test #'equal))
902 (shorts (make-hash-table)))
903 (flet ((problem (msg &rest args)
904 (push (apply #'format nil msg args) problems)))
905 (dolist (o opts)
906 (push o (gethash (opt-long-name o) longs))
907 (push o (gethash (opt-short-name o) shorts)))
908 (maphash (lambda (k v)
909 (when (and k (cdr v))
910 (problem "Long name `--~A' reused in ~S" k v)))
911 longs)
912 (maphash (lambda (k v)
913 (when (and k (cdr v))
914 (problem "Short name `-~C' reused in ~S" k v)))
915 shorts)
916 problems)))
917
918 ;;;--------------------------------------------------------------------------
919 ;;; Full program descriptions.
920
921 (defvar *help* nil)
922 (defvar *version* "<unreleased>")
923 (defvar *usage* nil)
924
925 (defun do-usage (&optional (stream *standard-output*))
926 (show-usage *program-name* *usage* stream))
927
928 (defun die-usage ()
929 (do-usage *error-output*)
930 (exit 1))
931
932 (defun opt-help (arg)
933 (declare (ignore arg))
934 (show-help *program-name* *version* *usage* *options*)
935 (typecase *help*
936 (string (terpri) (write-string *help*))
937 (null nil)
938 ((or function symbol) (terpri) (funcall *help*)))
939 (format t "~&")
940 (exit 0))
941 (defun opt-version (arg)
942 (declare (ignore arg))
943 (format t "~A, version ~A~%" *program-name* *version*)
944 (exit 0))
945 (defun opt-usage (arg)
946 (declare (ignore arg))
947 (do-usage)
948 (exit 0))
949
950 (defoptmacro help-options (&key (short-help #\h)
951 (short-version #\v)
952 (short-usage #\u))
953 "Inserts a standard help options collection in an options list."
954 (flet ((shortform (char)
955 (and char (list char))))
956 (mapcar
957 #'parse-option-form
958 `("Help options"
959 (,@(shortform short-help) "help" #'opt-help
960 "Show this help message.")
961 (,@(shortform short-version) "version" #'opt-version
962 ("Show ~A's version number." *program-name*))
963 (,@(shortform short-usage) "usage" #'opt-usage
964 ("Show a very brief usage summary for ~A." *program-name*))))))
965
966 (defun define-program (&key
967 (program-name nil progp)
968 (help nil helpp)
969 (version nil versionp)
970 (usage nil usagep)
971 (full-usage nil fullp)
972 (options nil optsp))
973 "Sets up all the required things a program needs to have to parse options
974 and respond to them properly."
975 (when progp (setf *program-name* program-name))
976 (when helpp (setf *help* help))
977 (when versionp (setf *version* version))
978 (when optsp (setf *options* options))
979 (cond ((and usagep fullp) (error "conflicting options"))
980 (usagep (setf *usage* (simple-usage *options* usage)))
981 (fullp (setf *usage* full-usage))))
982
983 (defmacro do-options ((&key (parser '(make-option-parser)))
984 &body clauses)
985 "Handy all-in-one options parser macro. PARSER defaults to a new options
986 parser using the preset default options structure. The CLAUSES are
987 `case2'-like clauses to match options, and must be exhaustive. If there
988 is a clause (nil (REST) FORMS...) then the FORMS are evaluated after
989 parsing is done with REST bound to the remaining command-line arguments."
990 (let*/gensyms (parser)
991 `(progn
992 (loop
993 (,(if (find t clauses :key #'car) 'case2 'ecase2)
994 (option-parse-next ,parser)
995 ((nil) () (return))
996 ,@(remove-if #'null clauses :key #'car)))
997 ,@(let ((tail (find nil clauses :key #'car)))
998 (and tail
999 (destructuring-bind ((&optional arg) &rest forms) (cdr tail)
1000 (if arg
1001 (list `(let ((,arg (option-parse-remainder ,parser)))
1002 ,@forms))
1003 forms)))))))
1004
1005 ;;;----- That's all, folks --------------------------------------------------