Ignore boring files.
[lisp] / optparse.lisp
CommitLineData
861345b4 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(defpackage #:mdw.optparse
27 (:use #:common-lisp #:mdw.base #:mdw.sys-base #:mdw.str)
28 (:export #:exit #:*program-name* #:*command-line-strings*
29 #:moan #:die
30 #:option #:optionp #:make-option
31 #:opt-short-name #:opt-long-name #:opt-tag #:opt-negated-tag
32 #:opt-arg-name #:opt-arg-optional-p #:opt-documentation
33 #:option-parser #:make-option-parser #:option-parser-p
34 #:op-options #:op-non-option #:op-long-only-p #:op-numeric-p
35 #:op-negated-numeric-p #:op-negated-p
36 #:option-parse-error
37 #:option-parse-remainder #:option-parse-next #:option-parse-try
38 #:with-unix-error-reporting
39 #:defopthandler #:invoke-option-handler
40 #:set #:clear #:inc #:dec #:read #:int #:string
41 #:keyword #:list
42 #:parse-option-form #:options
43 #:simple-usage #:show-usage #:show-version #:show-help
44 #:sanity-check-option-list))
45
46(in-package #:mdw.optparse)
47
48;;; Standard error-reporting functions.
49
50(defun moan (msg &rest args)
51 "Report an error message in the usual way."
52 (format *error-output* "~&~A: ~?~%" *program-name* msg args))
53(defun die (&rest args)
54 "Report an error message and exit."
55 (apply #'moan args)
56 (exit 1))
57
58;;; The main option parser.
59
60(defstruct (option (:predicate optionp)
61 (:conc-name opt-)
62 (:print-function
63 (lambda (o s k)
64 (declare (ignore k))
65 (format s
66 "#<option~@[ -~C,~]~@[ --~A~]~:[~2*~;~:[=~A~;[=~A]~]~]~@[ ~S~]>"
67 (opt-short-name o)
68 (opt-long-name o)
69 (opt-arg-name o)
70 (opt-arg-optional-p o)
71 (opt-arg-name o)
72 (opt-documentation o))))
73 (:constructor %make-option)
74 (:constructor make-option
75 (long-name
76 short-name
77 &optional
78 arg-name
79 &key
80 (tag (intern (string-upcase long-name)
81 :keyword))
82 negated-tag
83 arg-optional-p
84 doc
85 (documentation doc))))
86 "Describes a command-line option. Slots:
87
88LONG-NAME The option's long name. If this is null, the `option' is
89 just a banner to be printed in the program's help text.
90
91TAG The value to be returned if this option is encountered. If
92 this is a function, instead, the function is called with the
93 option's argument or nil.
94
95NEGATED-TAG As for TAG, but used if the negated form of the option is
96 found. If this is nil (the default), the option cannot be
97 negated.
98
99SHORT-NAME The option's short name. This must be a single character, or
100 nil if the option has no short name.
101
102ARG-NAME The name of the option's argument, a string. If this is nil,
103 the option doesn't accept an argument. The name is shown in
104 the help text.
105
106ARG-OPTIONAL-P If non-nil, the option's argument is optional. This is
107 ignored unless ARG-NAME is non-null.
108
109DOCUMENTATION The help text for this option. It is automatically
110 line-wrapped. If nil, the option is omitted from the help
111 text.
112
113Usually, one won't use make-option, but use the option macro instead."
114 (long-name nil :type (or null string))
115 (tag nil :type t)
116 (negated-tag nil :type t)
117 (short-name nil :type (or null character))
118 (arg-name nil :type (or null string))
119 (arg-optional-p nil :type t)
120 (documentation nil :type (or null string)))
121
122(defstruct (option-parser (:conc-name op-)
123 (:constructor make-option-parser
124 (argstmp
125 options
126 &key
127 (non-option :skip)
128 ((:numericp numeric-p))
129 negated-numeric-p
130 long-only-p
131 &aux
132 (args (cons nil argstmp))
133 (next args)
134 (negated-p (or negated-numeric-p
135 (some
136 #'opt-negated-tag
137 options))))))
138 "An option parser object. Slots:
139
140ARGS The arguments to be parsed. Usually this will be
141 *command-line-strings*.
142
143OPTIONS List of option structures describing the acceptable options.
144
145NON-OPTION Behaviour when encountering a non-option argument. The
146 default is :skip. Allowable values are:
147 :skip -- pretend that it appeared after the option
148 arguments; this is the default behaviour of GNU getopt
149 :stop -- stop parsing options, leaving the remaining
150 command line unparsed
151 :return -- return :non-option and the argument word
152
153NUMERIC-P Non-nil tag (as for options) if numeric options (e.g., -43)
154 are to be allowed. The default is nil. (Anomaly: the
155 keyword for this argument is :numericp.)
156
157NEGATED-NUMERIC-P
158 Non-nil tag (as for options) if numeric options (e.g., -43)
159 can be negated. This is not the same thing as a negative
160 numeric option!
161
162LONG-ONLY-P A misnomer inherited from GNU getopt. Whether to allow
163 long options to begin with a single dash. Short options are
164 still allowed, and may be cuddled as usual. The default is
165 nil."
166 (args nil :type list)
167 (options nil :type list)
168 (non-option :skip :type (or function (member :skip :stop :return)))
169 (next nil :type list)
170 (short-opt nil :type (or null string))
171 (short-opt-index 0 :type fixnum)
172 (short-opt-neg-p nil :type t)
173 (long-only-p nil :type t)
174 (numeric-p nil :type t)
175 (negated-numeric-p nil :type t)
176 (negated-p nil :type t))
177
178(define-condition option-parse-error (error simple-condition)
179 ()
180 (:documentation "Indicates an error found while parsing options. Probably
181not that useful."))
182
183(defun option-parse-error (msg &rest args)
184 "Signal an option-parse-error with the given message and arguments."
185 (error (make-condition 'option-parse-error
186 :format-control msg
187 :format-arguments args)))
188
189(defun option-parse-remainder (op)
190 "Returns the unparsed remainder of the command line."
191 (cdr (op-args op)))
192
193(defun option-parse-next (op)
194 "The main option-parsing function. OP is an option-parser object,
195initialized appropriately. Returns two values, OPT and ARG: OPT is the tag
196of the next option read, and ARG is the argument attached to it, or nil if
197there was no argument. If there are no more options, returns nil twice.
198Options whose TAG is a function aren't returned; instead, the tag function is
199called, with the option argument (or nil) as the only argument. It is safe
200for tag functions to throw out of option-parse-next, if they desparately need
201to. (This is the only way to actually get option-parse-next to return a
202function value, should that be what you want.)
203
204While option-parse-next is running, there is a restart `skip-option' which
205moves on to the next option. Error handlers should use this to resume after
206parsing errors."
207 (loop
208 (labels ((ret (opt &optional arg)
209 (return-from option-parse-next (values opt arg)))
210 (finished ()
211 (setf (op-next op) nil)
212 (ret nil nil))
213 (peek-arg ()
214 (cadr (op-next op)))
215 (more-args-p ()
216 (and (op-next op)
217 (cdr (op-next op))))
218 (skip-arg ()
219 (setf (op-next op) (cdr (op-next op))))
220 (eat-arg ()
221 (setf (cdr (op-next op)) (cddr (op-next op))))
222 (get-arg ()
223 (prog1 (peek-arg) (eat-arg)))
224 (process-option (o name negp &key arg argfunc)
225 (cond ((not (opt-arg-name o))
226 (when arg
227 (option-parse-error
228 "Option `~A' does not accept arguments"
229 name)))
230 (arg)
231 (argfunc
232 (setf arg (funcall argfunc)))
233 ((opt-arg-optional-p o))
234 ((more-args-p)
235 (setf arg (get-arg)))
236 (t
237 (option-parse-error "Option `~A' requires an argument"
238 name)))
239 (let ((how (if negp (opt-negated-tag o) (opt-tag o))))
240 (if (functionp how)
241 (funcall how arg)
242 (ret how arg))))
243 (process-long-option (arg start negp)
244 (when (and (not negp)
245 (op-negated-p op)
246 (> (length arg) (+ start 3))
247 (string= arg "no-"
248 :start1 start :end1 (+ start 3)))
249 (incf start 3)
250 (setf negp t))
251 (let* ((matches nil)
252 (eqpos (position #\= arg :start start))
253 (len (or eqpos (length arg)))
254 (optname (subseq arg 0 len))
255 (len-2 (- len start)))
256 (dolist (o (op-options op))
257 (cond ((or (not (stringp (opt-long-name o)))
258 (and negp (not (opt-negated-tag o)))
259 (< (length (opt-long-name o)) len-2)
260 (string/= optname (opt-long-name o)
261 :start1 start :end2 len-2)))
262 ((= (length (opt-long-name o)) len-2)
263 (setf matches (list o))
264 (return))
265 (t
266 (push o matches))))
267 (cond ((null matches)
268 (option-parse-error "Unknown option `~A'" optname))
269 ((cdr matches)
270 (option-parse-error
271 "~
272Ambiguous long option `~A' -- could be any of:~{~% --~A~}"
273 optname
274 (mapcar #'opt-long-name matches))))
275 (process-option (car matches)
276 optname
277 negp
278 :arg (and eqpos
279 (subseq arg (1+ eqpos)))))))
280 (with-simple-restart (skip-option "Skip this bogus option.")
281 (cond
282 ;;
283 ;; We're embroiled in short options: handle them.
284 ((op-short-opt op)
285 (if (>= (op-short-opt-index op) (length (op-short-opt op)))
286 (setf (op-short-opt op) nil)
287 (let* ((str (op-short-opt op))
288 (i (op-short-opt-index op))
289 (ch (char str i))
290 (negp (op-short-opt-neg-p op))
291 (name (format nil "~C~A" (if negp #\+ #\-) ch))
292 (o (find ch (op-options op) :key #'opt-short-name)))
293 (incf i)
294 (setf (op-short-opt-index op) i)
295 (when (or (not o)
296 (and negp (not (opt-negated-tag o))))
297 (option-parse-error "Unknown option `~A'" name))
298 (process-option o
299 name
300 negp
301 :argfunc
302 (and (< i (length str))
303 (lambda ()
304 (prog1
305 (subseq str i)
306 (setf (op-short-opt op)
307 nil))))))))
308 ;;
309 ;; End of the list. Say we've finished.
310 ((not (more-args-p))
311 (finished))
312 ;;
313 ;; Process the next option.
314 (t
315 (let ((arg (peek-arg)))
316 (cond
317 ;;
318 ;; Non-option. Decide what to do.
319 ((or (<= (length arg) 1)
320 (and (char/= (char arg 0) #\-)
321 (or (char/= (char arg 0) #\+)
322 (not (op-negated-p op)))))
323 (case (op-non-option op)
324 (:skip (skip-arg))
325 (:stop (finished))
326 (:return (eat-arg)
327 (ret :non-option arg))
328 (t (eat-arg)
329 (funcall (op-non-option op) arg))))
330 ;;
331 ;; Double-hyphen. Stop right now.
332 ((string= arg "--")
333 (eat-arg)
334 (finished))
335 ;;
336 ;; Numbers. Check these before long options, since `--43' is
337 ;; not a long option.
338 ((and (op-numeric-p op)
339 (or (char= (char arg 0) #\-)
340 (op-negated-numeric-p op))
341 (or (and (digit-char-p (char arg 1))
342 (every #'digit-char-p (subseq arg 2)))
343 (and (or (char= (char arg 1) #\-)
344 (char= (char arg 1) #\+))
345 (>= (length arg) 3)
346 (digit-char-p (char arg 2))
347 (every #'digit-char-p (subseq arg 3)))))
348 (eat-arg)
349 (let ((negp (char= (char arg 0) #\+))
350 (num (parse-integer arg :start 1)))
351 (when (and negp (eq (op-negated-numeric-p op) :-))
352 (setf num (- num))
353 (setf negp nil))
354 (let ((how (if negp
355 (op-negated-numeric-p op)
356 (op-numeric-p op))))
357 (if (functionp how)
358 (funcall how num)
359 (ret (if negp :negated-numeric :numeric) num)))))
360 ;;
361 ;; Long option. Find the matching option-spec and process
362 ;; it.
363 ((and (char= (char arg 0) #\-)
364 (char= (char arg 1) #\-))
365 (eat-arg)
366 (process-long-option arg 2 nil))
367 ;;
368 ;; Short options. All that's left.
369 (t
370 (eat-arg)
371 (let ((negp (char= (char arg 0) #\+))
372 (ch (char arg 1)))
373 (cond ((and (op-long-only-p op)
374 (not (member ch (op-options op)
375 :key #'opt-short-name)))
376 (process-long-option arg 1 negp))
377 (t
378 (setf (op-short-opt op) arg
379 (op-short-opt-index op) 1
380 (op-short-opt-neg-p op) negp)))))))))))))
381
382(defmacro option-parse-try (&body body)
383 "Report errors encountered while parsing options, and continue struggling
384along. Also establishes a restart `stop-parsing'. Returns t if parsing
385completed successfully, or nil if errors occurred."
386 (with-gensyms (retcode)
387 `(let ((,retcode t))
388 (restart-case
389 (handler-bind
390 ((option-parse-error
391 (lambda (cond)
392 (setf ,retcode nil)
393 (moan "~A" cond)
394 (dolist (rn '(skip-option stop-parsing))
395 (let ((r (find-restart rn)))
396 (when r (invoke-restart r)))))))
397 ,@body)
398 (stop-parsing ()
399 :report "Give up parsing options."
400 (setf ,retcode nil)))
401 ,retcode)))
402
403(defmacro with-unix-error-reporting ((&key) &body body)
404 "Evaluate BODY with errors reported in the standard Unix fashion."
405 (with-gensyms (cond)
406 `(handler-case
407 (progn ,@body)
408 (simple-condition (,cond)
409 (die (simple-condition-format-control ,cond)
410 (simple-condition-format-arguments ,cond)))
411 (error (,cond)
412 (die "~A" ,cond)))))
413
414;;; Standard option handlers.
415
416(defmacro defopthandler (name (var &optional (arg (gensym)))
417 (&rest args)
418 &body body)
419 "Define an option handler function NAME. Option handlers update a
420generalized variable, which may be referred to as VAR in the BODY, based on
421some parameters (the ARGS) and the value of an option-argument named ARG."
422 (let ((func (intern (format nil "OPTHANDLER/~:@(~A~)" name))))
423 `(progn
424 (setf (get ',name 'opthandler) ',func)
425 (defun ,func (,var ,arg ,@args)
426 (with-locatives ,var
427 (declare (ignorable ,arg))
428 ,@body))
429 ',name)))
430
431(defun parse-c-integer (string &key radix (start 0) end)
432 "Parse STRING, or at least the parts of it between START and END, according
433to the standard C rules. Well, almost: the 0 and 0x prefixes are accepted,
434but so too are 0o (Haskell) and 0b (original); also RADIX_DIGITS is accepted,
435for any radix between 2 and 36. Prefixes are only accepted if RADIX is nil.
436Returns two values: the integer parsed (or nil if there wasn't enough for a
437sensible parse), and the index following the characters of the integer."
438 (unless end (setf end (length string)))
202c91a3
MW
439 (labels ((simple (i r goodp sgn)
440 (multiple-value-bind
441 (a i)
442 (if (and (< i end)
443 (digit-char-p (char string i) r))
444 (parse-integer string
445 :start i :end end
446 :radix r
447 :junk-allowed t)
448 (values nil i))
449 (values (if a (* sgn a) (and goodp 0)) i)))
861345b4 450 (get-radix (i r sgn)
202c91a3 451 (cond (r (simple i r nil sgn))
861345b4 452 ((>= i end) (values nil i))
453 ((and (char= (char string i) #\0)
454 (>= (- end i) 2))
455 (case (char string (1+ i))
202c91a3
MW
456 (#\x (simple (+ i 2) 16 nil sgn))
457 (#\o (simple (+ i 2) 8 nil sgn))
458 (#\b (simple (+ i 2) 2 nil sgn))
459 (t (simple (1+ i) 8 t sgn))))
861345b4 460 (t
461 (multiple-value-bind
202c91a3
MW
462 (r i)
463 (simple i 10 nil +1)
861345b4 464 (cond ((not r) (values nil i))
465 ((and (< i end)
466 (char= (char string i) #\_)
467 (<= 2 r 36))
202c91a3 468 (simple (1+ i) r nil sgn))
861345b4 469 (t
470 (values (* r sgn) i))))))))
471 (cond ((>= start end) (values nil start))
472 ((char= (char string start) #\-)
473 (get-radix (1+ start) radix -1))
474 ((char= (char string start) #\+)
475 (get-radix (1+ start) radix +1))
476 (t
477 (get-radix start radix +1)))))
478
479(defun invoke-option-handler (handler loc arg args)
480 "Call the HANDLER function, giving it LOC to update, the option-argument
481ARG, and the remaining ARGS."
482 (apply (if (functionp handler) handler
483 (fdefinition (get handler 'opthandler)))
484 loc
485 arg
486 args))
487
488(defopthandler set (var) (&optional (value t))
489 "Sets VAR to VALUE; defaults to t."
490 (setf var value))
491(defopthandler clear (var) (&optional (value nil))
492 "Sets VAR to VALUE; defaults to nil."
493 (setf var value))
494(defopthandler inc (var) (&optional max (step 1))
495 "Increments VAR by STEP (defaults to 1), but not greater than MAX (default
496nil for no maximum). No errors are signalled."
497 (incf var step)
498 (when (>= var max)
499 (setf var max)))
500(defopthandler dec (var) (&optional min (step 1))
501 "Decrements VAR by STEP (defaults to 1), but not less than MIN (default nil
502for no maximum). No errors are signalled."
503 (decf var step)
504 (when (<= var min)
505 (setf var min)))
506(defopthandler read (var arg) ()
507 "Stores in VAR the Lisp object found by reading the ARG. Evaluation is
508forbidden while reading ARG. If there is an error during reading, an error
509of type option-parse-error is signalled."
510 (handler-case
511 (let ((*read-eval* nil))
512 (multiple-value-bind (x end) (read-from-string arg t)
513 (unless (>= end (length arg))
514 (option-parse-error "Junk at end of argument `~A'" arg))
515 (setf var x)))
516 (error (cond)
517 (option-parse-error (format nil "~A" cond)))))
518(defopthandler int (var arg) (&key radix min max)
519 "Stores in VAR the integer read from the ARG. Integers are parsed
520according to C rules, which is normal in Unix; the RADIX may be nil to allow
521radix prefixes, or an integer between 2 and 36. An option-parse-error is
522signalled if the ARG is not a valid integer, or if it is not between MIN and
523MAX (either of which may be nil if no lower resp. upper bound is wanted)."
524 (multiple-value-bind (v end) (parse-c-integer arg :radix radix)
525 (unless (and v (>= end (length arg)))
526 (option-parse-error "Bad integer `~A'" arg))
527 (when (or (and min (< v min))
528 (and max (> v max)))
529 (option-parse-error
530 "Integer ~A out of range (must have ~@[~D <= ~]x~@[ <= ~D~])"
531 arg min max))
532 (setf var v)))
533(defopthandler string (var arg) ()
534 "Stores ARG in VAR, just as it is."
535 (setf var arg))
536(defopthandler keyword (var arg) (&rest valid)
537 (if (null valid)
538 (setf var (intern (string-upcase arg) :keyword))
539 (let ((matches nil)
540 (guess (string-upcase arg))
541 (len (length arg)))
542 (dolist (k valid)
543 (let* ((kn (symbol-name k))
544 (klen (length kn)))
545 (cond ((string= kn guess)
546 (setf matches (list k))
547 (return))
548 ((and (< len klen)
549 (string= guess kn :end2 len))
550 (push k matches)))))
551 (case (length matches)
552 (0 (option-parse-error "Argument `~A' invalid: must be one of:~
553 ~{~%~8T~(~A~)~}"
554 arg valid))
555 (1 (setf var (car matches)))
556 (t (option-parse-error "Argument `~A' ambiguous: may be any of:~
557 ~{~%~8T~(~A~)~}"
558 arg matches))))))
559(defopthandler list (var arg) (&optional handler &rest handler-args)
560 "Collect ARGs in a list at VAR. ARGs are translated by the HANDLER first,
561if specified. If not, it's as if you asked for `string'."
562 (when handler
563 (invoke-option-handler handler (locf arg) arg handler-args))
564 (setf var (nconc var (list arg))))
565
566(compile-time-defun parse-option-form (form)
567 "Does the heavy lifting for parsing an option form. See the docstring for
568the `option' macro for details of the syntax."
569 (flet ((doc (form)
570 (cond ((stringp form) form)
571 ((null (cdr form)) (car form))
572 (t `(format nil ,@form))))
573 (docp (form)
574 (or (stringp form)
575 (and (consp form)
576 (stringp (car form))))))
577 (if (and (docp (car form))
578 (null (cdr form)))
579 `(%make-option :documentation ,(doc (car form)))
580 (let (long-name short-name
581 arg-name arg-optional-p
582 tag negated-tag
583 doc)
584 (dolist (f form)
585 (cond ((and (or (not tag) (not negated-tag))
586 (or (keywordp f)
587 (and (consp f)
588 (member (car f) '(lambda function)))))
589 (if tag
590 (setf negated-tag f)
591 (setf tag f)))
592 ((and (not long-name)
593 (or (rationalp f)
594 (symbolp f)
595 (stringp f)))
596 (setf long-name (if (stringp f) f
597 (format nil "~(~A~)" f))))
598 ((and (not short-name)
599 (characterp f))
600 (setf short-name f))
601 ((and (not doc)
602 (docp f))
603 (setf doc (doc f)))
604 ((and (consp f) (symbolp (car f)))
605 (case (car f)
606 (:arg (setf arg-name (cadr f)))
607 (:opt-arg (setf arg-name (cadr f))
608 (setf arg-optional-p t))
609 (:doc (setf doc (doc (cdr f))))
610 (t (let ((handler (get (car f) 'opthandler)))
611 (unless handler
612 (error "No handler `~S' defined." (car f)))
613 (let* ((var (cadr f))
614 (arg (gensym))
615 (thunk `#'(lambda (,arg)
616 (,handler (locf ,var)
617 ,arg
618 ,@(cddr f)))))
619 (if tag
620 (setf negated-tag thunk)
621 (setf tag thunk)))))))
622 (t
623 (error "Unexpected thing ~S in option form." f))))
624 `(make-option ,long-name ,short-name ,arg-name
625 ,@(and arg-optional-p `(:arg-optional-p t))
626 ,@(and tag `(:tag ,tag))
627 ,@(and negated-tag `(:negated-tag ,negated-tag))
628 ,@(and doc `(:documentation ,doc)))))))
629
630(defmacro options (&rest optlist)
631 "More convenient way of initializing options. The OPTLIST is a list of
632OPTFORMS. Each OPTFORM is either a banner string, or a list of
633items. Acceptable items are interpreted as follows:
634
635 KEYWORD or FUNCTION
636 If no TAG is set yet, then as a TAG; otherwise as the NEGATED-TAG.
637
638 STRING (or SYMBOL or RATIONAL)
639 If no LONG-NAME seen yet, then the LONG-NAME. For symbols and rationals,
640 the item is converted to a string and squashed to lower-case.
641
642 CHARACTER
643 The SHORT-NAME.
644
645 STRING or (STRING STUFF...)
646 If no DOCUMENTATION set yet, then the DOCUMENTATION string. A string is
647 used as-is; a list is considered to be a `format' string and its
648 arguments. This is evaluated at standard evaluation time: the option
649 structure returned contains a simple documentation string.
650
651 (:ARG NAME)
652 Set the ARG-NAME.
653
654 (:OPT-ARG NAME)
655 Set the ARG-NAME, and also set ARG-OPTIONAL-P.
656
657 (HANDLER VAR ARGS...)
658 If no TAG is set yet, attach the HANDLER to this option, giving it ARGS.
659 Otherwise, set the NEGATED-TAG."
660 `(list ,@(mapcar (lambda (form)
661 (if (stringp form)
662 `(%make-option :documentation ,form)
663 (parse-option-form form)))
664 optlist)))
665
666;;; Support stuff for help and usage messages
667
668(defun print-text (string
669 &optional
670 (stream *standard-output*)
671 &key
672 (start 0)
673 (end nil))
674 "Prints STRING to a pretty-printed STREAM, breaking it at whitespace and
675newlines in the obvious way. Stuff between square brackets is not broken:
676this makes usage messages work better."
677 (let ((i start)
678 (nest 0)
679 (splitp nil))
680 (flet ((emit ()
681 (write-string string stream :start start :end i)
682 (setf start i)))
683 (unless end
684 (setf end (length string)))
685 (loop
686 (unless (< i end)
687 (emit)
688 (return))
689 (let ((ch (char string i)))
690 (cond ((char= ch #\newline)
691 (emit)
692 (incf start)
693 (pprint-newline :mandatory stream))
694 ((whitespace-char-p ch)
695 (when (zerop nest)
696 (setf splitp t)))
697 (t
698 (when splitp
699 (emit)
700 (pprint-newline :fill stream))
701 (setf splitp nil)
702 (case ch
703 (#\[ (incf nest))
704 (#\] (when (plusp nest) (decf nest))))))
705 (incf i))))))
706
707(defun simple-usage (opts &optional mandatory-args)
708 "Build a simple usage list from a list of options, and (optionally)
709mandatory argument names."
710 (let (short-simple long-simple short-arg long-arg)
711 (dolist (o opts)
712 (cond ((not (and (opt-documentation o)
713 (opt-long-name o))))
714 ((and (opt-short-name o) (opt-arg-name o))
715 (push o short-arg))
716 ((opt-short-name o)
717 (push o short-simple))
718 ((opt-arg-name o)
719 (push o long-arg))
720 (t
721 (push o long-simple))))
722 (list
723 (nconc (and short-simple
724 (list (format nil "[-~{~C~}]"
725 (sort (mapcar #'opt-short-name short-simple)
726 #'char<))))
727 (and long-simple
728 (mapcar (lambda (o)
729 (format nil "[--~A]" (opt-long-name o)))
730 (sort long-simple #'string< :key #'opt-long-name)))
731 (and short-arg
732 (mapcar (lambda (o)
733 (format nil "~:[[-~C ~A]~;[-~C[~A]]~]"
734 (opt-arg-optional-p o)
735 (opt-short-name o)
736 (opt-arg-name o)))
737 (sort short-arg #'char-lessp
738 :key #'opt-short-name)))
739 (and long-arg
740 (mapcar (lambda (o)
741 (format nil "~:[[--~A ~A]~;[--~A[=~A]]~]"
742 (opt-arg-optional-p o)
743 (opt-long-name o)
744 (opt-arg-name o)))
745 (sort long-arg #'string-lessp
746 :key #'opt-long-name)))
747 (listify mandatory-args)))))
748
749(defun show-usage (prog usage &optional (stream *standard-output*))
750 "Basic usage-showing function. PROG is the program name, probable from
751*command-line-strings*. USAGE is a list of possible usages of the program,
752each of which is a list of items to be supplied by the user. In simple
753cases, a single string is sufficient."
754 (pprint-logical-block (stream nil :prefix "Usage: ")
755 (dolist (u (listify usage))
756 (pprint-logical-block (stream nil :prefix (format nil "~A " prog))
757 (format stream "~{~A ~:_~}" (listify u)))
758 (pprint-newline :mandatory stream))))
759
760(defun show-help (prog ver usage opts &optional (stream *standard-output*))
761 "Basic help-showing function. PROG is the program name, probably from
762*command-line-strings*. VER is the program's version number. USAGE is a
763list of the possible usages of the program, each of which may be a list of
764items to be supplied. OPTS is the list of supported options, as provided to
765the options parser. STREAM is the stream to write on."
766 (format stream "~A, version ~A~2%" prog ver)
767 (show-usage prog usage stream)
768 (terpri stream)
769 (let (newlinep)
770 (dolist (o opts)
771 (let ((doc (opt-documentation o)))
772 (cond ((not o))
773 ((not (opt-long-name o))
774 (when newlinep
775 (terpri stream)
776 (setf newlinep nil))
777 (pprint-logical-block (stream nil)
778 (print-text doc stream))
779 (terpri stream))
780 (t
781 (setf newlinep t)
782 (pprint-logical-block (stream nil :prefix " ")
783 (pprint-indent :block 30 stream)
784 (format stream "~:[ ~;-~:*~C,~] --~A"
785 (opt-short-name o)
786 (opt-long-name o))
787 (when (opt-arg-name o)
788 (format stream "~:[=~A~;[=~A]~]"
789 (opt-arg-optional-p o)
790 (opt-arg-name o)))
791 (write-string " " stream)
792 (pprint-tab :line 30 1 stream)
793 (print-text doc stream))
794 (terpri stream)))))))
795
796(defun sanity-check-option-list (opts)
797 "Check the option list OPTS for basic sanity. Reused short and long option
798names are diagnosed. Maybe other problems will be reported later. Returns a
799list of warning strings."
800 (let ((problems nil)
801 (longs (make-hash-table :test #'equal))
802 (shorts (make-hash-table)))
803 (flet ((problem (msg &rest args)
804 (push (apply #'format nil msg args) problems)))
805 (dolist (o opts)
806 (push o (gethash (opt-long-name o) longs))
807 (push o (gethash (opt-short-name o) shorts)))
808 (maphash (lambda (k v)
809 (when (and k (cdr v))
810 (problem "Long name `--~A' reused in ~S" k v)))
811 longs)
812 (maphash (lambda (k v)
813 (when (and k (cdr v))
814 (problem "Short name `-~C' reused in ~S" k v)))
815 shorts)
816 problems)))
817
818;;;----- That's all, folks --------------------------------------------------