1 ;;; esh-opt.el --- command options processing
3 ;; Copyright (C) 1999, 2000 Free Software Foundation
5 ;; Author: John Wiegley <johnw@gnu.org>
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
26 (eval-when-compile (require 'esh-maint
))
28 (defgroup eshell-opt nil
29 "The options processing code handles command argument parsing for
30 Eshell commands implemented in Lisp."
31 :tag
"Command options processing"
38 (defmacro eshell-eval-using-options
(name macro-args
39 options
&rest body-forms
)
40 "Process NAME's MACRO-ARGS using a set of command line OPTIONS.
41 After doing so, settings will be stored in local symbols as declared
42 by OPTIONS; FORMS will then be evaluated -- assuming all was OK.
44 The syntax of OPTIONS is:
46 '((?C nil nil multi-column \"multi-column display\")
47 (nil \"help\" nil nil \"show this usage display\")
48 (?r \"reverse\" nil reverse-list \"reverse order while sorting\")
50 :usage \"[OPTION]... [FILE]...
51 List information about the FILEs (the current directory by default).
52 Sort entries alphabetically across.\")
54 `eshell-eval-using-options' returns the value of the last form in
55 BODY-FORMS. If instead an external command is run, the tag
56 `eshell-external' will be thrown with the new process for its value.
58 Lastly, any remaining arguments will be available in a locally
59 interned variable `args' (created using a `let' form)."
61 ,(if (memq ':preserve-args
(cadr options
))
63 (list 'eshell-stringify-list
64 (list 'eshell-flatten-list macro-args
)))))
65 (let ,(append (mapcar (function
67 (or (and (listp opt
) (nth 3 opt
))
68 'eshell-option-stub
)))
70 '(usage-msg last-value ext-command args
))
71 (eshell-do-opt ,name
,options
(quote ,body-forms
)))))
73 ;;; Internal Functions:
82 (defun eshell-do-opt (name options body-forms
)
83 "Helper function for `eshell-eval-using-options'.
84 This code doesn't really need to be macro expanded everywhere."
88 (catch 'eshell-ext-command
93 (if (and (= (length args
) 0)
94 (memq ':show-usage options
))
96 (eshell-show-usage name options
)))
97 (setq args
(eshell-process-args name args options
)
98 last-value
(eval (append (list 'progn
)
102 (throw 'eshell-external
103 (eshell-external-command ext-command args
))
106 (defun eshell-show-usage (name options
)
107 "Display the usage message for NAME, using OPTIONS."
108 (let ((usage (format "usage: %s %s\n\n" name
109 (cadr (memq ':usage options
))))
110 (extcmd (memq ':external options
))
111 (post-usage (memq ':post-usage options
))
114 (when (listp (car options
))
115 (let ((opt (car options
)))
117 (cond ((and (nth 0 opt
)
121 (format " %-20s %s\n"
122 (format "-%c, --%s" (nth 0 opt
)
128 (format " %-20s %s\n"
129 (format "-%c" (nth 0 opt
))
134 (format " %-20s %s\n"
135 (format " --%s" (nth 1 opt
))
137 (t (setq had-option nil
)))))
138 (setq options
(cdr options
)))
140 (setq usage
(concat usage
(and had-option
"\n")
143 (setq extcmd
(eshell-search-path (cadr extcmd
)))
148 This command is implemented in Lisp. If an unrecognized option is
149 passed to this command, the external version '%s'
150 will be called instead." extcmd
)))))
151 (throw 'eshell-usage usage
)))
153 (defun eshell-set-option (name ai opt options
)
154 "Using NAME's remaining args (index AI), set the OPT within OPTIONS.
155 If the option consumes an argument for its value, the argument list
157 (if (not (nth 3 opt
))
158 (eshell-show-usage name options
)
159 (if (eq (nth 2 opt
) t
)
160 (if (> ai
(length args
))
161 (error "%s: missing option argument" name
)
162 (set (nth 3 opt
) (nth ai args
))
164 (setcdr (nthcdr (1- ai
) args
) (nthcdr (1+ ai
) args
))
165 (setq args
(cdr args
))))
166 (set (nth 3 opt
) (or (nth 2 opt
) t
)))))
168 (defun eshell-process-option (name switch kind ai options
)
169 "For NAME, process SWITCH (of type KIND), from args at index AI.
170 The SWITCH will be looked up in the set of OPTIONS.
172 SWITCH should be either a string or character. KIND should be the
173 integer 0 if it's a character, or 1 if it's a string.
175 The SWITCH is then be matched against OPTIONS. If no matching handler
176 is found, and an :external command is defined (and available), it will
177 be called; otherwise, an error will be triggered to say that the
178 switch is unrecognized."
179 (let* ((opts options
)
182 (if (and (listp (car opts
))
183 (nth kind
(car opts
))
185 (eq switch
(nth kind
(car opts
)))
186 (string= switch
(nth kind
(car opts
)))))
188 (eshell-set-option name ai
(car opts
) options
)
189 (setq found t opts nil
))
190 (setq opts
(cdr opts
))))
192 (let ((extcmd (memq ':external options
)))
194 (setq extcmd
(eshell-search-path (cadr extcmd
)))
196 (throw 'eshell-ext-command extcmd
)
197 (if (char-valid-p switch
)
198 (error "%s: unrecognized option -%c" name switch
)
199 (error "%s: unrecognized option --%s" name switch
))))))))
201 (defun eshell-process-args (name args options
)
202 "Process the given ARGS using OPTIONS.
203 This assumes that symbols have been intern'd by `eshell-with-options'."
205 (while (< ai
(length args
))
206 (setq arg
(nth ai args
))
207 (if (not (and (stringp arg
)
208 (string-match "^-\\(-\\)?\\(.*\\)" arg
)))
210 (let* ((dash (match-string 1 arg
))
211 (switch (match-string 2 arg
)))
213 (setq args
(cdr args
))
214 (setcdr (nthcdr (1- ai
) args
) (nthcdr (1+ ai
) args
)))
216 (if (> (length switch
) 0)
217 (eshell-process-option name switch
1 ai options
)
218 (setq ai
(length args
)))
219 (let ((len (length switch
))
222 (eshell-process-option name
(aref switch index
) 0 ai options
)
223 (setq index
(1+ index
)))))))))
228 ;;; esh-opt.el ends here