CL-USER> (cffi:foreign-funcall "exit" :int 0)
...
Process inferior-lisp exited abnormally with code 0
--
Lars Rune Nøstdal || AJAX/Comet GUI type stuff for Common Lisp
http://nostdal.org/ || http://groups.google.com/group/symbolicweb
Such functionality is missing from ANSI CL, so any solution will
be more or less unportable. The following is a reasonable
approximation for free Lisp implementations, basically you
need special case for each implementation (if you know correct
code for other implementations I would appreciate such info).
Note: the code is intended to be used in a portablility
package, so called functionos use qualified names.
;;; How to exit Lisp process
#+:gcl
(defun quit() (lisp::quit))
#+:sbcl
(defun quit()
(sb-ext::quit))
#+:clisp
(defun quit() (ext::quit))
#+:openmcl
(defun quit() (ccl::quit))
#+:ecl
(defun quit ()
(SI:quit))
#+:poplog
(defun quit() (poplog::bye))
--
Waldek Hebisch
heb...@math.uni.wroc.pl
Presumably, you are starting that program somehow, which is already
implementation dependent. Do something like
sbcl --eval '(progn (load-what-I-need) (run-my-wonderful-program) (quit))'
for each implementation that your program is supposed to work with.
You can make run-my-wonderful-program portable and independent of the
implementation. When that function terminates, the program will quit.
Inside your program, define a condition that signals intention to quit.
Have run-my-wonderful-program handle it by returning.
HTH,
Tamas
Just came over this:
http://www.cliki.net/cl-launch
..search that page for cl-launch:quit .. might make sense; you'll have a
portable way to start stuff also then.
And so on...
A style that's less visually confusing (IMHO) puts all of the
feature tests[1] inside a single copy of the function in question,
documenting the common API in a single place. The following is
a merge of the set from <http://www.cliki.net/CLOCC-PORT>, the
set from Maxima, and yours:
(defun quit (&optional code)
;; This group from "clocc-port/ext.lisp"
#+allegro (excl:exit code)
#+clisp (#+lisp=cl ext:quit #-lisp=cl lisp:quit code)
#+cmu (ext:quit code)
#+cormanlisp (win32:exitprocess code)
#+gcl (lisp:bye code) ; XXX Or is it LISP::QUIT?
#+lispworks (lw:quit :status code)
#+lucid (lcl:quit code)
#+sbcl (sb-ext:quit
:unix-code (typecase code (number code) (null 0) (t 1)))
;; This group from Maxima
#+kcl (lisp::bye) ; XXX Does this take an arg?
#+scl (ext:quit code) ; XXX Pretty sure this *does*.
#+(or openmcl mcl) (ccl::quit)
#+abcl (cl-user::quit)
#+ecl (si:quit)
;; This group from <heb...@math.uni.wroc.pl>
#+poplog (poplog::bye) ; XXX Does this take an arg?
#-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbcl
kcl scl openmcl mcl abcl ecl)
(error 'not-implemented :proc (list 'quit code)))
-Rob
p.s. Note that you never need an explicit keyword package marker on
a symbol in a feature test, e.g. #+:FOO, since feature expressions
are read *in* the KEYWORD package, see CLHS "2.4.8.17 Sharpsign Plus",
"2.4.8.18 Sharpsign Minus", & "24.1.2.1 Feature Expressions".
-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
> Russell Wallace <russell...@gmail.com> wrote:
> > From within a portable Lisp program, how do you exit cleanly to the
> > operating system (as opposed to the debugger), i.e. the equivalent of
> > exit(0) in C? I can't find anything in the hyperspec or Google, but
> > maybe I'm overlooking something obvious.
>
> Such functionality is missing from ANSI CL, so any solution will
> be more or less unportable. The following is a reasonable
> approximation for free Lisp implementations, basically you
> need special case for each implementation (if you know correct
> code for other implementations I would appreciate such info).
> Note: the code is intended to be used in a portablility
> package, so called functionos use qualified names.
>
> ;;; How to exit Lisp process
Given the prevalence of the use of QUIT as the name of such a function,
I have sometimes resorted to the following outrageous hack. But it does
have a fair bit of portability, since it relies the implementations
making the quit symbol available from the CL-USER package.
Simple form:
(defun my-quit () (funcall (find-symbol "QUIT" "COMMON-LISP-USER")))
More robust:
(defun my-quit ()
(let ((quit-symbol (find-symbol "QUIT" "COMMON-LISP-USER"))
(exit-symbol (find-symbol "EXIT" "COMMON-LISP-USER")))
(when (and quit-symbol (fboundp quit-symbol))
(funcall quit-symbol))
(when (and exit-symbol (fboundp exit-symbol))
(funcall exit-symbol))
(warn "Don't know how to quit!")))
> #+:poplog
> (defun quit() (poplog::bye))
OK, it would miss this one, though...
--
Thomas A. Russ, USC/Information Sciences Institute
You could even skip the #-(...) in this case. :)
- Willem
Yes, that's true. But exiting the entire program is a very special
case and I didn't want to encourage sloppiness in the general case
where you *do* want to return a value, e.g., this function from the
"archive_0.7.0" package:
;;; stat field accessors
(defun stat-mode (stat)
#+sbcl (sb-posix::stat-mode stat)
#+lispworks (file-stat-mode stat)
#+clisp (posix:convert-mode (posix:file-stat-mode state))
#+cmucl (mode stat)
#-(or sbcl lispworks clisp cmucl) (error "Not implemented"))
So it's probably best to always include the #-(OR ...) list,
just to avoid mistakes by accident.
Although, now that you mention it, there *is* one other special case
that I can think of where the #-(OR ...) is unnecessary and, in fact,
unwanted, and that's where you're going to return a default value if
the implementation-specific value is NIL, e.g.:
;;; This version morphed very slightly from
;;; <http://cl-cookbook.sourceforge.net/os.html>
(defun getenv (name &optional default)
(or
#+cmu (cdr (assoc name ext:*environment-list* :test #'string=))
#+allegro (sys:getenv name)
#+clisp (ext:getenv name)
#+ecl (si:getenv name)
#+sbcl (sb-unix::posix-getenv name)
#+lispworks (lispworks:environment-variable name)
default))
-Rob
| Willem Broekema <meta...@gmail.com> wrote:
| +---------------
| | rp...@rpw3.org (Rob Warnock) wrote:
| | > (defun quit (&optional code)
| | > ;; This group from "clocc-port/ext.lisp"
| | > #+allegro (excl:exit code)
| | > #+clisp (#+lisp=cl ext:quit #-lisp=cl lisp:quit code)
| | > ...
| | > #-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbcl
| | > kcl scl openmcl mcl abcl ecl)
| | > (error 'not-implemented :proc (list 'quit code)))
| |
| | You could even skip the #-(...) in this case. :)
| +---------------
|
| Yes, that's true. But exiting the entire program is a very special
| case and I didn't want to encourage sloppiness in the general case
| where you *do* want to return a value, e.g., this function from the
| "archive_0.7.0" package:
|
| ;;; stat field accessors
| (defun stat-mode (stat)
| #+sbcl (sb-posix::stat-mode stat)
| #+lispworks (file-stat-mode stat)
| #+clisp (posix:convert-mode (posix:file-stat-mode state))
| #+cmucl (mode stat)
| #-(or sbcl lispworks clisp cmucl) (error "Not implemented"))
I don't like the double listing of features in the #-( ... ) forms. To
avoid them I'd suggest the following Pattern that I use myself:
(defun stat-mode (stat)
(or
#+sbcl (sb-posix::stat-mode stat)
#+lispworks (file-stat-mode stat)
#+clisp (posix:convert-mode (posix:file-stat-mode state))
#+cmucl (mode stat)
(error "Not implemented")))
Any drawbacks? (I don't think so...)
--
Madhu
Ruby:
exit
> Ruby:
>
> exit
Naturally, just as defined in the Ruby ANSI standard, I mean ISO standard...
Oh, wait...
Just a word of caution: do you really want to have NIL mean end-of-the-
world? If you ever end out throwing to nil on accident, you'll end out
not in the debugger but quietly exiting. It's probably not a big deal
(although the gun is pointed at your foot, the safety is on and the
chamber's empty) but I always call catch tags like yours above
something more like :goodbye-world or %exit or something.
What you're saying makes sense; I started off using nil to mean
basically "error parsing data file, so exit"; but then I added support
for processing several files in a batch, so I actually changed the
location of the catch, to mean "okay, ignore that file, but proceed to
the next one"; so I'll probably keep using nil to mean "done here, let
top-level decide what to do next".
This of course is an advantage of throw over explicit exit -- you can
change your mind about how to handle the situation, without having to
modify the low-level code.
Okay, that makes a lot of sense.
One last stylistic nit to pick: do you know about restarts, and
specifically ABORT? You've notice in your debugger that you often have
the option of invoking a restart called ABORT? There's a standard
function cl:abort that invokes it; there's also CONTINUE as a standard
name for a restart. If you have some concept of "the current
operation" in your application, it can be convenient to have ABORT,
well, abort it and return to the top-level loop, whatever that loop
may be. In Ltk, for example, we create an abort restart that aborts
handling the latest event (user input, button press, timeout, etc) and
returns to the main event loop. It interacts nicely with standard
debuggers.
The idiom is like this:
(loop while (keep-going-p)
do (restart-case
(do-one-iteration)
(abort ()
:report "Abort processing this file"
nil)))
Sometimes catch is better, sometimes restarts are more convenient,
just food for thought.
(OMG is that a pattern?! No, wait, it's an idiom. I guess I formatted
it differently?)
Thanks! I hadn't thought of that, but I'll keep it in mind.