1 ;;; esh-opt.el --- command options processing
3 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
6 ;; Author: John Wiegley <johnw@gnu.org>
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 3, or (at your option)
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
29 (eval-when-compile (require 'esh-ext
))
31 (defgroup eshell-opt nil
32 "The options processing code handles command argument parsing for
33 Eshell commands implemented in Lisp."
34 :tag
"Command options processing"
39 (defmacro eshell-eval-using-options
(name macro-args
40 options
&rest body-forms
)
41 "Process NAME's MACRO-ARGS using a set of command line OPTIONS.
42 After doing so, settings will be stored in local symbols as declared
43 by OPTIONS; FORMS will then be evaluated -- assuming all was OK.
45 The syntax of OPTIONS is:
47 '((?C nil nil multi-column \"multi-column display\")
48 (nil \"help\" nil nil \"show this usage display\")
49 (?r \"reverse\" nil reverse-list \"reverse order while sorting\")
51 :usage \"[OPTION]... [FILE]...
52 List information about the FILEs (the current directory by default).
53 Sort entries alphabetically across.\")
55 `eshell-eval-using-options' returns the value of the last form in
56 BODY-FORMS. If instead an external command is run, the tag
57 `eshell-external' will be thrown with the new process for its value.
59 Lastly, any remaining arguments will be available in a locally
60 interned variable `args' (created using a `let' form)."
61 (declare (debug (form form sexp body
)))
63 ,(if (memq ':preserve-args
(cadr options
))
65 (list 'eshell-stringify-list
66 (list 'eshell-flatten-list macro-args
)))))
67 (let ,(append (mapcar (function
69 (or (and (listp opt
) (nth 3 opt
))
70 'eshell-option-stub
)))
72 '(usage-msg last-value ext-command args
))
73 (eshell-do-opt ,name
,options
(quote ,body-forms
)))))
75 ;;; Internal Functions:
84 (defun eshell-do-opt (name options body-forms
)
85 "Helper function for `eshell-eval-using-options'.
86 This code doesn't really need to be macro expanded everywhere."
90 (catch 'eshell-ext-command
95 (if (and (= (length args
) 0)
96 (memq ':show-usage options
))
98 (eshell-show-usage name options
)))
99 (setq args
(eshell-process-args name args options
)
100 last-value
(eval (append (list 'progn
)
103 (error "%s" usage-msg
))))
104 (throw 'eshell-external
105 (eshell-external-command ext-command args
))
108 (defun eshell-show-usage (name options
)
109 "Display the usage message for NAME, using OPTIONS."
110 (let ((usage (format "usage: %s %s\n\n" name
111 (cadr (memq ':usage options
))))
112 (extcmd (memq ':external options
))
113 (post-usage (memq ':post-usage options
))
116 (when (listp (car options
))
117 (let ((opt (car options
)))
119 (cond ((and (nth 0 opt
)
123 (format " %-20s %s\n"
124 (format "-%c, --%s" (nth 0 opt
)
130 (format " %-20s %s\n"
131 (format "-%c" (nth 0 opt
))
136 (format " %-20s %s\n"
137 (format " --%s" (nth 1 opt
))
139 (t (setq had-option nil
)))))
140 (setq options
(cdr options
)))
142 (setq usage
(concat usage
(and had-option
"\n")
145 (setq extcmd
(eshell-search-path (cadr extcmd
)))
150 This command is implemented in Lisp. If an unrecognized option is
151 passed to this command, the external version '%s'
152 will be called instead." extcmd
)))))
153 (throw 'eshell-usage usage
)))
155 (defun eshell-set-option (name ai opt options
)
156 "Using NAME's remaining args (index AI), set the OPT within OPTIONS.
157 If the option consumes an argument for its value, the argument list
159 (if (not (nth 3 opt
))
160 (eshell-show-usage name options
)
161 (if (eq (nth 2 opt
) t
)
162 (if (> ai
(length args
))
163 (error "%s: missing option argument" name
)
164 (set (nth 3 opt
) (nth ai args
))
166 (setcdr (nthcdr (1- ai
) args
) (nthcdr (1+ ai
) args
))
167 (setq args
(cdr args
))))
168 (set (nth 3 opt
) (or (nth 2 opt
) t
)))))
170 (defun eshell-process-option (name switch kind ai options
)
171 "For NAME, process SWITCH (of type KIND), from args at index AI.
172 The SWITCH will be looked up in the set of OPTIONS.
174 SWITCH should be either a string or character. KIND should be the
175 integer 0 if it's a character, or 1 if it's a string.
177 The SWITCH is then be matched against OPTIONS. If no matching handler
178 is found, and an :external command is defined (and available), it will
179 be called; otherwise, an error will be triggered to say that the
180 switch is unrecognized."
181 (let* ((opts options
)
184 (if (and (listp (car opts
))
185 (nth kind
(car opts
))
187 (eq switch
(nth kind
(car opts
)))
188 (string= switch
(nth kind
(car opts
)))))
190 (eshell-set-option name ai
(car opts
) options
)
191 (setq found t opts nil
))
192 (setq opts
(cdr opts
))))
194 (let ((extcmd (memq ':external options
)))
196 (setq extcmd
(eshell-search-path (cadr extcmd
)))
198 (throw 'eshell-ext-command extcmd
)
199 (if (char-valid-p switch
)
200 (error "%s: unrecognized option -%c" name switch
)
201 (error "%s: unrecognized option --%s" name switch
))))))))
203 (defun eshell-process-args (name args options
)
204 "Process the given ARGS using OPTIONS.
205 This assumes that symbols have been intern'd by `eshell-with-options'."
207 (while (< ai
(length args
))
208 (setq arg
(nth ai args
))
209 (if (not (and (stringp arg
)
210 (string-match "^-\\(-\\)?\\(.*\\)" arg
)))
212 (let* ((dash (match-string 1 arg
))
213 (switch (match-string 2 arg
)))
215 (setq args
(cdr args
))
216 (setcdr (nthcdr (1- ai
) args
) (nthcdr (1+ ai
) args
)))
218 (if (> (length switch
) 0)
219 (eshell-process-option name switch
1 ai options
)
220 (setq ai
(length args
)))
221 (let ((len (length switch
))
224 (eshell-process-option name
(aref switch index
) 0 ai options
)
225 (setq index
(1+ index
)))))))))
230 ;;; arch-tag: 45c6c2d0-8091-46a1-a205-2f4bafd8230c
231 ;;; esh-opt.el ends here