Exit with status 1 on error
Add macros `with-error-status' and `with-error-and-help' that help to easily report errors to the user. The latter also calls the `help' command. All commands, when done, exit with `*exit-status*' being the status code used. The `with-error-status' macro let-binds this variable so that the command function exits with the given status code.
This commit is contained in:
parent
ce8cfd58f4
commit
c1cbf7d59a
1 changed files with 30 additions and 11 deletions
|
@ -35,24 +35,41 @@
|
||||||
(defvar *script* nil
|
(defvar *script* nil
|
||||||
"Whether or not to output in a machine-readable format.")
|
"Whether or not to output in a machine-readable format.")
|
||||||
|
|
||||||
|
(defvar *exit-status* 0
|
||||||
|
"The exit status to use on quit.")
|
||||||
|
|
||||||
(defmacro call-command (name &rest args)
|
(defmacro call-command (name &rest args)
|
||||||
(let ((command-name (make-command-name (symbol-name name))))
|
(let ((command-name (make-command-name (symbol-name name))))
|
||||||
`(,command-name ,@args)))
|
`(,command-name ,@args)))
|
||||||
|
|
||||||
(defmacro defcommand (name (&rest args) sdoc ldoc
|
(defmacro defcommand (name (&rest args) sdoc ldoc &body body)
|
||||||
&body body)
|
|
||||||
"Define a new command usable on the command-line."
|
"Define a new command usable on the command-line."
|
||||||
(let* ((sname (string-downcase (symbol-name name)))
|
(let* ((sname (string-downcase (symbol-name name)))
|
||||||
(command-name (make-command-name (symbol-name name))))
|
(command-name (make-command-name (symbol-name name))))
|
||||||
`(progn
|
`(progn
|
||||||
(defun ,command-name (,@args)
|
(defun ,command-name (,@args)
|
||||||
,sdoc
|
,sdoc
|
||||||
,@body)
|
,@body
|
||||||
|
(sb-ext:exit :code *exit-status*))
|
||||||
(setf *help-messages*
|
(setf *help-messages*
|
||||||
(nconc *help-messages* '((,sname ,sdoc ,ldoc)))
|
(nconc *help-messages* '((,sname ,sdoc ,ldoc)))
|
||||||
*max-command-name-length*
|
*max-command-name-length*
|
||||||
(max *max-command-name-length* (length ,sname))))))
|
(max *max-command-name-length* (length ,sname))))))
|
||||||
|
|
||||||
|
(defmacro with-error-and-help (code cmd fmt &rest args)
|
||||||
|
"Call `with-error-status' with CODE, format FMT with ARGS and call
|
||||||
|
the help command."
|
||||||
|
`(with-error-status ,code
|
||||||
|
(format t ,fmt ,@args)
|
||||||
|
(call-command help ,cmd)))
|
||||||
|
|
||||||
|
(defmacro with-error-status (code &body body)
|
||||||
|
"Bind `*exit-status*' to CODE, `*standard-output*' to
|
||||||
|
`*error-output*' and execute BODY."
|
||||||
|
`(let ((*standard-output* *error-output*)
|
||||||
|
(*exit-status* ,code))
|
||||||
|
,@body))
|
||||||
|
|
||||||
(defconstant *version* "0.1.0"
|
(defconstant *version* "0.1.0"
|
||||||
"Clark's version.")
|
"Clark's version.")
|
||||||
|
|
||||||
|
@ -191,7 +208,9 @@ The executable name should already have been removed."
|
||||||
(loop while (and args (char= (char (car args) 0) #\-))
|
(loop while (and args (char= (char (car args) 0) #\-))
|
||||||
do (case (intern (string-upcase (string-left-trim "-" (car args)))
|
do (case (intern (string-upcase (string-left-trim "-" (car args)))
|
||||||
:org.ryuslash.clark)
|
:org.ryuslash.clark)
|
||||||
(script (setf *script* t args (cdr args)))))
|
(script (setf *script* t args (cdr args)))
|
||||||
|
(t (with-error-and-help
|
||||||
|
1 "help" "Unknown option: ~a~%" (car args)))))
|
||||||
(if args
|
(if args
|
||||||
(let ((cmd-name (make-command-name (car args))))
|
(let ((cmd-name (make-command-name (car args))))
|
||||||
(if (fboundp cmd-name)
|
(if (fboundp cmd-name)
|
||||||
|
@ -199,13 +218,11 @@ The executable name should already have been removed."
|
||||||
(sb-int:simple-program-error (err)
|
(sb-int:simple-program-error (err)
|
||||||
(if (string-equal (format nil "~A" err)
|
(if (string-equal (format nil "~A" err)
|
||||||
"invalid number of arguments" :end1 27)
|
"invalid number of arguments" :end1 27)
|
||||||
(let ((*standard-output* *error-output*))
|
(with-error-and-help
|
||||||
(format t "Wrong number of arguments given.~%")
|
1 (car args) "Wrong number of arguments given.~%")
|
||||||
(call-command help (car args)))
|
|
||||||
(signal err))))
|
(signal err))))
|
||||||
(let ((*standard-output* *error-output*))
|
(with-error-and-help
|
||||||
(format t "Unknown command: ~A~%" (car args))
|
1 "help" "Unknown command: ~A~%" (car args))))
|
||||||
(call-command help "help"))))
|
|
||||||
(map nil #'print-bookmark (get-bookmarks))))
|
(map nil #'print-bookmark (get-bookmarks))))
|
||||||
|
|
||||||
(defun print-bookmark (bm)
|
(defun print-bookmark (bm)
|
||||||
|
@ -271,7 +288,9 @@ otherwise."
|
||||||
command *help-messages*
|
command *help-messages*
|
||||||
:test #'(lambda (x y) (equal x (car y))))))))
|
:test #'(lambda (x y) (equal x (car y))))))))
|
||||||
(cond
|
(cond
|
||||||
((null ldoc) (format t "Unkown command: ~A~%" command))
|
((null ldoc)
|
||||||
|
(with-error-and-help
|
||||||
|
1 "help" "Unknown command: ~a~%" command))
|
||||||
((and (symbolp ldoc) (fboundp ldoc)) (funcall ldoc))
|
((and (symbolp ldoc) (fboundp ldoc)) (funcall ldoc))
|
||||||
(t (format t "~A~%" ldoc))))
|
(t (format t "~A~%" ldoc))))
|
||||||
(call-command help "help")))
|
(call-command help "help")))
|
||||||
|
|
Loading…
Reference in a new issue