📄 getopt-long.scm
字号:
;;; Copyright (C) 1998, 2001 Free Software Foundation, Inc.;;;;;; This program is free software; you can redistribute it and/or modify;;; it under the terms of the GNU General Public License as published by;;; the Free Software Foundation; either version 2 of the License, or;;; (at your option) any later version.;;;;;; This program is distributed in the hope that it will be useful,;;; but WITHOUT ANY WARRANTY; without even the implied warranty of;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the;;; GNU General Public License for more details.;;;;;; You should have received a copy of the GNU General Public License;;; along with this program; if not, write to the Free Software;;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA;;;;;; As a special exception, the Free Software Foundation gives permission;;; for additional uses of the text contained in its release of GUILE.;;;;;; The exception is that, if you link the GUILE library with other files;;; to produce an executable, this does not by itself cause the;;; resulting executable to be covered by the GNU General Public License.;;; Your use of that executable is in no way restricted on account of;;; linking the GUILE library code into it.;;;;;; This exception does not however invalidate any other reasons why;;; the executable file might be covered by the GNU General Public License.;;;;;; This exception applies only to the code released by the;;; Free Software Foundation under the name GUILE. If you copy;;; code from other Free Software Foundation releases into a copy of;;; GUILE, as the General Public License permits, the exception does;;; not apply to the code that you add in this way. To avoid misleading;;; anyone as to the status of such modified files, you must delete;;; this exception notice from them.;;;;;; If you write modifications of your own for GUILE, it is your choice;;; whether to permit this exception to apply to your modifications.;;; If you do not wish that, delete this exception notice.;;; Author: Russ McManus (rewritten by Thien-Thi Nguyen);;; Commentary:;;; This module implements some complex command line option parsing, in;;; the spirit of the GNU C library function `getopt_long'. Both long;;; and short options are supported.;;;;;; The theory is that people should be able to constrain the set of;;; options they want to process using a grammar, rather than some arbitrary;;; structure. The grammar makes the option descriptions easy to read.;;;;;; `getopt-long' is a procedure for parsing command-line arguments in a;;; manner consistent with other GNU programs. `option-ref' is a procedure;;; that facilitates processing of the `getopt-long' return value.;;; (getopt-long ARGS GRAMMAR);;; Parse the arguments ARGS according to the argument list grammar GRAMMAR.;;;;;; ARGS should be a list of strings. Its first element should be the;;; name of the program; subsequent elements should be the arguments;;; that were passed to the program on the command line. The;;; `program-arguments' procedure returns a list of this form.;;;;;; GRAMMAR is a list of the form:;;; ((OPTION (PROPERTY VALUE) ...) ...);;;;;; Each OPTION should be a symbol. `getopt-long' will accept a;;; command-line option named `--OPTION'.;;; Each option can have the following (PROPERTY VALUE) pairs:;;;;;; (single-char CHAR) --- Accept `-CHAR' as a single-character;;; equivalent to `--OPTION'. This is how to specify traditional;;; Unix-style flags.;;; (required? BOOL) --- If BOOL is true, the option is required.;;; getopt-long will raise an error if it is not found in ARGS.;;; (value BOOL) --- If BOOL is #t, the option accepts a value; if;;; it is #f, it does not; and if it is the symbol;;; `optional', the option may appear in ARGS with or;;; without a value.;;; (predicate FUNC) --- If the option accepts a value (i.e. you;;; specified `(value #t)' for this option), then getopt;;; will apply FUNC to the value, and throw an exception;;; if it returns #f. FUNC should be a procedure which;;; accepts a string and returns a boolean value; you may;;; need to use quasiquotes to get it into GRAMMAR.;;;;;; The (PROPERTY VALUE) pairs may occur in any order, but each;;; property may occur only once. By default, options do not have;;; single-character equivalents, are not required, and do not take;;; values.;;;;;; In ARGS, single-character options may be combined, in the usual;;; Unix fashion: ("-x" "-y") is equivalent to ("-xy"). If an option;;; accepts values, then it must be the last option in the;;; combination; the value is the next argument. So, for example, using;;; the following grammar:;;; ((apples (single-char #\a));;; (blimps (single-char #\b) (value #t));;; (catalexis (single-char #\c) (value #t)));;; the following argument lists would be acceptable:;;; ("-a" "-b" "bang" "-c" "couth") ("bang" and "couth" are the values;;; for "blimps" and "catalexis");;; ("-ab" "bang" "-c" "couth") (same);;; ("-ac" "couth" "-b" "bang") (same);;; ("-abc" "couth" "bang") (an error, since `-b' is not the;;; last option in its combination);;;;;; If an option's value is optional, then `getopt-long' decides;;; whether it has a value by looking at what follows it in ARGS. If;;; the next element is does not appear to be an option itself, then;;; that element is the option's value.;;;;;; The value of a long option can appear as the next element in ARGS,;;; or it can follow the option name, separated by an `=' character.;;; Thus, using the same grammar as above, the following argument lists;;; are equivalent:;;; ("--apples" "Braeburn" "--blimps" "Goodyear");;; ("--apples=Braeburn" "--blimps" "Goodyear");;; ("--blimps" "Goodyear" "--apples=Braeburn");;;;;; If the option "--" appears in ARGS, argument parsing stops there;;;; subsequent arguments are returned as ordinary arguments, even if;;; they resemble options. So, in the argument list:;;; ("--apples" "Granny Smith" "--" "--blimp" "Goodyear");;; `getopt-long' will recognize the `apples' option as having the;;; value "Granny Smith", but it will not recognize the `blimp';;; option; it will return the strings "--blimp" and "Goodyear" as;;; ordinary argument strings.;;;;;; The `getopt-long' function returns the parsed argument list as an;;; assocation list, mapping option names --- the symbols from GRAMMAR;;; --- onto their values, or #t if the option does not accept a value.;;; Unused options do not appear in the alist.;;;;;; All arguments that are not the value of any option are returned;;; as a list, associated with the empty list.;;;;;; `getopt-long' throws an exception if:;;; - it finds an unrecognized property in GRAMMAR;;; - the value of the `single-char' property is not a character;;; - it finds an unrecognized option in ARGS;;; - a required option is omitted;;; - an option that requires an argument doesn't get one;;; - an option that doesn't accept an argument does get one (this can;;; only happen using the long option `--opt=value' syntax);;; - an option predicate fails;;;;;; So, for example:;;;;;; (define grammar;;; `((lockfile-dir (required? #t);;; (value #t);;; (single-char #\k);;; (predicate ,file-is-directory?));;; (verbose (required? #f);;; (single-char #\v);;; (value #f));;; (x-includes (single-char #\x));;; (rnet-server (single-char #\y);;; (predicate ,string?))));;;;;; (getopt-long '("my-prog" "-vk" "/tmp" "foo1" "--x-includes=/usr/include";;; "--rnet-server=lamprod" "--" "-fred" "foo2" "foo3");;; grammar);;; => ((() "foo1" "-fred" "foo2" "foo3");;; (rnet-server . "lamprod");;; (x-includes . "/usr/include");;; (lockfile-dir . "/tmp");;; (verbose . #t));;; (option-ref OPTIONS KEY DEFAULT);;; Return value in alist OPTIONS using KEY, a symbol; or DEFAULT if not;;; found. The value is either a string or `#t'.;;;;;; For example, using the `getopt-long' return value from above:;;;;;; (option-ref (getopt-long ...) 'x-includes 42) => "/usr/include";;; (option-ref (getopt-long ...) 'not-a-key! 31) => 31;;; Code:(define-module (ice-9 getopt-long) :use-module ((ice-9 common-list) :select (some remove-if-not)) :export (getopt-long option-ref))(define option-spec-fields '(name value required? single-char predicate value-policy))(define option-spec (make-record-type 'option-spec option-spec-fields))(define make-option-spec (record-constructor option-spec option-spec-fields))(define (define-one-option-spec-field-accessor field) `(define ,(symbol-append 'option-spec-> field) ;;; name slib-compat (record-accessor option-spec ',field)))(define (define-one-option-spec-field-modifier field) `(define ,(symbol-append 'set-option-spec- field '!) ;;; name slib-compat (record-modifier option-spec ',field)))(defmacro define-all-option-spec-accessors/modifiers () `(begin ,@(map define-one-option-spec-field-accessor option-spec-fields) ,@(map define-one-option-spec-field-modifier option-spec-fields)))(define-all-option-spec-accessors/modifiers)(define make-option-spec (let ((ctor (record-constructor option-spec '(name)))) (lambda (name) (ctor name))))(define (parse-option-spec desc) (let ((spec (make-option-spec (symbol->string (car desc))))) (for-each (lambda (desc-elem) (let ((given (lambda () (cadr desc-elem)))) (case (car desc-elem) ((required?) (set-option-spec-required?! spec (given))) ((value) (set-option-spec-value-policy! spec (given)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -