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