Skip to content

Latest commit

 

History

History
321 lines (222 loc) · 12.1 KB

fanion.markdown

File metadata and controls

321 lines (222 loc) · 12.1 KB

Fanion Manual

Table of Contents

[in package FANION/DOCUMENTATION]

1 The fanion ASDF System

2 Introduction

Fanion is a Common Lisp library for parsing command-line options. It parses them in the same way as OpenBSD getopt(3), but additionally supports long options, though currently with limitations (see Current issues). In particular, short options may take optional arguments, and options and non-option arguments cannot be mixed. This makes parsing subcommands and their arguments trivial with the existing API.

This library is intentionally spartan in its functionality. It can parse options and nothing else; it cannot parse non-option arguments or subcommands, because the comparative ease with which they can be manually parsed, e.g., via pattern matching or even DESTRUCTURING-BIND, makes further complexifying the API unjustified, especially when considering the myriad ways non-option arguments can be arranged.

Also, Fanion does not automatically generate usage or help messages, operating under the assumption that there will always be someone (usually me) unhappy with the formatting. Furthermore, I believe that a good help message, just like a good manual page, is best manually written.

However, Fanion's option parsing should be flexible enough to cater to many use-cases thanks to its option-value reduction (see the REDUCE argument to FANION:MAKE-OPTION), which is modeled after Adopt's.

Fanion is currently under active development and its API is unstable, but it follows Semantic Versioning so breaking changes will be indicated by an appropriate bump in version number.

2.1 Background

Why yet another command-line option parsing library, when there are already twenty? (See Similar libraries.) I first started with unix-opts, then migrated to clingon when I saw that it handled subcommands and seemed well-designed, but I was unhappy with the automatic formatting of their help messages and also that they allow options to follow non-option arguments, like GNU getopt_long(3). The catalyst for my decision to write my own library was that I found no way to make clingon options take optional arguments.

The name Fanion comes from the French term for flag in this context.

3 Installing

Fanion is not available on Quicklisp, so you will need to clone it to a location known to ASDF or Quicklisp:

git clone https://git.sr.ht/~paulapatience/fanion

Fanion has no dependencies beyond ASDF/UIOP. It is developed on SBCL, but should be compatible with any conventional Common Lisp implementation.

4 Examples

The Common Lisp files located in Fanion's scripts directory are good examples of Fanion being used in practice. The following is an extract of scripts/build-documentation.lisp:

(defparameter +options+
  (list
   (fanion:make-option 'format #\f nil
                       :value #'parse-format)
   (fanion:make-option 'help nil "help")
   (fanion:make-option 'output #\o nil
                       :value #'parse-output
                       :initial-value uiop:*stdout*)))

(fanion:parse +options+ (uiop:command-line-arguments))

See FANION:MAKE-OPTION for further examples of its capabilities.

5 API reference

[in package FANION]

PARSE is the main entrypoint to the library. It takes a list of OPTIONs and the command-line arguments to be parsed, and returns as multiple values a hashtable of parsed options and the remaining non-option arguments.

Options are parsed in the same way as OpenBSD getopt(3), except that long options — though currently only boolean long options — are also supported. Short options start with one hyphen (-a), long options with two (--abc). Multiple short options may be joined or separate (-ab -a -b); their arguments may be joined or separate (-c1 -c 2); and they may take optional arguments, though these if provided must be joined (-d -d1). Option parsing ends upon reaching the end of the argument list, the argument ‘-’, an argument not starting with ‘-’, or the argument ‘--’, which is dropped. In particular, options and non-option arguments cannot be mixed.

  • [function] PARSE OPTIONS ARGUMENTS

    Parse command-line ARGUMENTS according to OPTIONS. Return as multiple values the parsed options as a hashtable whose keys are the options' names, and the list of remaining non-option arguments.

    OPTIONS must be a list of OPTIONs, ARGUMENTS a list of strings. The list of remaining non-option arguments may share structure with ARGUMENTS.

  • [function] MAKE-OPTION NAME SHORT LONG &KEY (VALUE NIL VALUE-P) OPTIONAL-VALUE INITIAL-VALUE REDUCE FINALLY

    Make an OPTION named NAME identified by at least one of SHORT and LONG. SHORT may not be #\-, and LONG may not contain #\=.

    If VALUE is non-NIL, the option takes an argument; if VALUE is a function, it is called with the option's argument to produce the option's value. If OPTIONAL-VALUE is non-NIL, the option takes an optional argument.

    The option's value is initially set to INITIAL-VALUE, and each time the option appears in the argument list, REDUCE is called with, and its result replaces, the option's current value. If the option takes an argument, it is passed as REDUCE's second argument. The value of boolean options and missing optional arguments is T. When the options are exhausted, FINALLY is called with, and its result replaces, the option's value.

    If REDUCE and VALUE are NIL, REDUCE is initialized to (CONSTANTLY T). If REDUCE is NIL and VALUE is not, REDUCE is initialized to a function which returns its second argument. If FINALLY is NIL, it is initialized to IDENTITY.

    Some examples of conventional option styles follow:

    (make-option 'verbose #\v nil)    ; Boolean short option
    (make-option 'help nil "help")    ; Boolean long option
    (make-option 'output #\o nil      ; Pathname option
                 :value #'uiop:parse-native-namestring
                 :initial-value uiop:*stdout*)
    (make-option 'formats #\f nil     ; List option (in order)
                 :value t
                 :reduce (lambda (a b) (cons b a))
                 :finally #'nreverse)

  • [class] OPTION STRUCTURE-OBJECT

    Command-line option.

    This type is exported only for use in type declarations. Its internal representation may change at any time.

6 Current issues

Long options are supported, but only as booleans. This will be corrected.

Also, no dedicated FANION-ERROR class exists for such errors as unrecognized options and missing arguments. An error class hierarchy may be added in the future.

7 Similar libraries

In alphabetical order:

Other lists:

8 Acknowledgments

Fanion's option-value reduction, consisting of the VALUE, REDUCE and FINALLY arguments to FANION:MAKE-OPTION, is modeled after Adopt's, though in Adopt VALUE is named KEY and REDUCE is required.