unix-options (C) 2009-2010 Andrew Stine This software is distributed under the terms of the Lisp Lesser GNU Public License (http://opensource.franz.com/preamble.html), also known as the LLGPL. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------- Unix-options is a small Common Lisp library for parsing unix-style command line options. This library is very new and not widely tested so suggestions, bug-reports and patches (including changes to this document) are welcome. Please send any feedback to: unix dot options (at) librelist dot com ---------------------------------------------------------------------- Usage: The library can be loaded through ASDF and used through the package 'unix-options.' Exported symbols are: =| cli-options - variable =| ¶meters - symbol =| &free - symbol =| free - symbol =| map-parsed-options - function =| getopt - function =| with-cli-options - macro An example of usage: (with-cli-options () (print ¶meters in-file out-file) (when print (with-open-file (in in-file :direction :input) (with-open-file (out out-file :direction :output) (while (peek-char in) (write-char (read-char in) out)))))) $ sample-program -p -i input.txt -o output.txt => write input.txt to output.txt --------------------------------------------------------------------- API: getopt - An imitation of the Unix 'getopt' command line program prototype: (getopt cli-options shortopts longopts) details: Getopt accepts three arguments: a list of tokens passed in on the CLI, a string detailing available short-form options and a list detailing long-form options. Getopt breaks the tokens up and sorts them so that they can be handled by the calling program more easily. Cli-options can be any list of strings. Each string begging with a single '-' is interpreted as a series of short options and any beginning with '--' is interpreted as a long option. Others are either free tokens or parameters. Any tokens appearing after a token that is soley a '--', are interpreted as free tokens. Shortopts takes the form: "abf:" where each letter is the name of a permissable short option and a ':' following a letter signifies that it takes a parameter. Longopts takes the form: '("option1" "file=") where each string is the name of a long option and a '=' signifies that the option takes a parameter. Return three values which are all lists: (1) parsed command line arguments with "--" separating valid options and free arguments, (2) only the valid options and (3) only the free arguments. example: (getopt '("-ab" "--file" "file.txt" "free") "ab" '("file=")) => ("a" "b" "file" "file.txt" "--" "free") ("a" "b" "file" "file.txt") ("free") make-option-spec - A function which create an option-spec object prototype: (make-option-spec tokens &optional parameter description) details: Make-option-spec generates an option-spec object from the the details provided. Tokens can either be a symbol, or a list of characters, strings, and symbols. Parameter is either nil, t, or a string. Description is always a string. An option spec contains a list of short-tokens, as characters and a list of long-tokens as strings. Short-tokens are drawn from any characters passed under tokens and the first letter of the name of any symbols passed. Long-tokens are drawn from any strings passed likewise and from the complete names of any symbols passed. Parameter signifies whether an option takes a parameter. If parameter is nil, then the option does not. Otherwise, the option does. The parameter can be described briefly by passing a string as parameter rather than simply t. Description is a description of the option and it's purpose in general. Option-specs are used as parameters to several functions in unix-options. Generally, anywhere an option-spec is required, one may substitute a list of the parameters one would pass to make-option-spec. Thus one might be able to type: (function '(foo nil "foo option")) instead of: (function (make-option-spec 'foo nil "foo option")) example: (make-option-spec '(#\A foo) "integer" "A number to be passed in") => <option-spec {12f9sj39}> with-cli-options - A macro that binds values passed in from the command line to local variables prototype: (with-cli-options (&optional (cli-options '(cli-options)) enable-usage-summary) option-variables &body body) details: With-cli-options takes a list of symbols and attempts to bind values passed in on the command line to them according to a set of rules. For every symbol named in option-variables, with-cli-options creates a variable to which it binds any long option of the same name. With-cli-options also take the first letter of any symbol and bind short options of that letter to that symbol. If multiple symbols begin with the same letter, only the first in option-variables is bound the short option of the same letter; the second is bound to the uppercase version and any more must use a long option. Optionally, each entry in option-variables can be a short list. The first item is symbol to be used. The second is either a documentation string, or a full option-spec allowing greater detail as to how that particular entry is to be formed. In addition, symbols in option-variables are boolean by default; that is, they bound to either t or nil depending on whether they are passed in on the cli. Symbols listed after ¶meters, if it is present, are are considered parameter options, that is, they are bound to the next token on the cli if the are long options or the same or the rest of the current short option group, if they are short options. If nothing is passed for this options (ie. if it is the last token) it is bound to nil. Any tokens that aren't options or parameters to options are saved into a list of free tokens. This list is bound to 'free' unless a different symbol is provided in option-variables after &free. If enable-usage-summary is set, then with-cli-options will be able to print out a usage summary (using print-usage-summary) based on the options bound in option-varibles. The summary will be printed either when an invalid option is specified or the user uses '-h' or '--help' as an option. If enable-usage-summary is set to a string, that string is passed as control string to print-usage-summary. Else, a generic string is used. example: (with-cli-options ('("-pi" "in" "--out-file" "out" "another")) (print ¶meters in-file out-file) (print print) (print in-file) (print out-file) (print free)) T "in" "out" ("another") => NIL cli-options - returns the list of whitespace separated tokens passed on the command line. print-usage-summary - Prints a usage description of the current program prototype: (print-usage-summary description option-specs) details: Print-usage-summary print a usage summary of options specified by options-specs. The function takes each option-spec and generates a string describing in detail each option. The resulting strings are passed as arguments to a call to format. Description is used as the control string. The option-spec descriptions are auto- aligned. example: (print-usage-summary "Usage:~%~@{~A~%~}~%end summary" '(((#\a "alpha") nil "A simple option") ((#\f "file") "FILENAME" "A filename") ((#\b #\d "beta") nil "Another option"))) Usage: -a, --alpha A simple option -f, --file=FILENAME A filename -b, -d, --beta Another option end summary =>NIL map-parsed-options - Function that does the actual parsing of cli tokens prototype: (map-parsed-options cli-options bool-options param-options opt-val-func free-val-func) details: Map-parsed-options is the backend function that does most of the actual work in parsing cli functions. It is exposed to allow more front ends in addition to getopt and with-cli-options. Map-parsed-options receives a list of cli tokens, as well as two list of options, boolean options and options with parameters, respectively. The final two arguments are functions, one to handle found options and there values, and one to handle free tokens. example: (map-parsed-options '("-ab" "value" "free") '("a") '("b") (lambda (option value) (format t "option: ~A; value: ~A~%" option value)) (lambda (free-val) (format t "free: ~A~%" free-val))) option: a; value T option: b; value value free: free => NIL With thanks to folks who've reported bugs and provided patches.