Next: , Previous: Programs and Arguments, Up: Programs and Arguments


4.4.1 Getopt

(require 'getopt) This routine implements Posix command line argument parsing. Notice that returning values through global variables means that getopt is not reentrant.

Obedience to Posix format for the getopt calls sows confusion. Passing argc and argv as arguments while referencing optind as a global variable leads to strange behavior, especially when the calls to getopt are buried in other procedures.

Even in C, argc can be derived from argv; what purpose does it serve beyond providing an opportunity for argv/argc mismatch? Just such a mismatch existed for years in a SLIB getopt-- example.

I have removed the argc and argv arguments to getopt procedures; and replaced them with a global variable:

— Variable: *argv*

Define *argv* with a list of arguments before calling getopt procedures. If you don't want the first (0th) element to be ignored, set *optind* to 0 (after requiring getopt).

— Variable: *optind*

Is the index of the current element of the command line. It is initially one. In order to parse a new command line or reparse an old one, *optind* must be reset.

— Variable: *optarg*

Is set by getopt to the (string) option-argument of the current option.

— Function: getopt optstring

Returns the next option letter in *argv* (starting from (vector-ref argv *optind*)) that matches a letter in optstring. *argv* is a vector or list of strings, the 0th of which getopt usually ignores. optstring is a string of recognized option characters; if a character is followed by a colon, the option takes an argument which may be immediately following it in the string or in the next element of *argv*.

*optind* is the index of the next element of the *argv* vector to be processed. It is initialized to 1 by getopt.scm, and getopt updates it when it finishes with each element of *argv*.

getopt returns the next option character from *argv* that matches a character in optstring, if there is one that matches. If the option takes an argument, getopt sets the variable *optarg* to the option-argument as follows:

If, when getopt is called, the string (vector-ref argv *optind*) either does not begin with the character #\- or is just "-", getopt returns #f without changing *optind*. If (vector-ref argv *optind*) is the string "--", getopt returns #f after incrementing *optind*.

If getopt encounters an option character that is not contained in optstring, it returns the question-mark #\? character. If it detects a missing option argument, it returns the colon character #\: if the first character of optstring was a colon, or a question-mark character otherwise. In either case, getopt sets the variable getopt:opt to the option character that caused the error.

The special option "--" can be used to delimit the end of the options; #f is returned, and "--" is skipped.

RETURN VALUE

getopt returns the next option character specified on the command line. A colon #\: is returned if getopt detects a missing argument and the first character of optstring was a colon #\:.

A question-mark #\? is returned if getopt encounters an option character not in optstring or detects a missing argument and the first character of optstring was not a colon #\:.

Otherwise, getopt returns #f when all command line options have been parsed.

Example:

          #! /usr/local/bin/scm
          (require 'program-arguments)
          (require 'getopt)
          (define argv (program-arguments))
          
          (define opts ":a:b:cd")
          (let loop ((opt (getopt (length argv) argv opts)))
            (case opt
              ((#\a) (print "option a: " *optarg*))
              ((#\b) (print "option b: " *optarg*))
              ((#\c) (print "option c"))
              ((#\d) (print "option d"))
              ((#\?) (print "error" getopt:opt))
              ((#\:) (print "missing arg" getopt:opt))
              ((#f) (if (< *optind* (length argv))
                        (print "argv[" *optind* "]="
                               (list-ref argv *optind*)))
                    (set! *optind* (+ *optind* 1))))
            (if (< *optind* (length argv))
                (loop (getopt (length argv) argv opts))))
          
          (slib:exit)

4.4.2 Getopt—

— Function: getopt-- optstring

The procedure getopt-- is an extended version of getopt which parses long option names of the form ‘--hold-the-onions’ and ‘--verbosity-level=extreme’. Getopt-- behaves as getopt except for non-empty options beginning with ‘--’.

Options beginning with ‘--’ are returned as strings rather than characters. If a value is assigned (using ‘=’) to a long option, *optarg* is set to the value. The ‘=’ and value are not returned as part of the option string.

No information is passed to getopt-- concerning which long options should be accepted or whether such options can take arguments. If a long option did not have an argument, *optarg* will be set to #f. The caller is responsible for detecting and reporting errors.

          (define opts ":-:b:")
          (define *argv* '("foo" "-b9" "--f1" "--2=" "--g3=35234.342" "--"))
          (define *optind* 1)
          (define *optarg* #f)
          (require 'qp)
          (do ((i 5 (+ -1 i)))
              ((zero? i))
            (let ((opt (getopt-- opts)))
              (print *optind* opt *optarg*)))
          -|
          2 #\b "9"
          3 "f1" #f
          4 "2" ""
          5 "g3" "35234.342"
          5 #f "35234.342"