* minor incompatible change: --disable-debugger toplevel option now takes
effect before processing of initialization files and --eval or --load
options.
+ * new feature: new commandline argument: --script, which supports
+ shebang lines. See documentation for details. (based on work by
+ Kevin Reid)
* enhancement: inoccous calls to EVAL or generic functions dispatching
on subclasses of eg. STREAM no longer cause compiler notes to appear.
* enhancement: the system no longer resignals errors from --load and
@node Shebang Scripts
@comment node-name, next, previous, up
@subsection Shebang Scripts
+@vindex sb-ext:*posix-argv*
+@vindex *posix-argv*
+
+Standard Unix tools that are interpreters follow a common command line
+protocol that is necessary to work with ``shebang scripts''. SBCL supports
+this via the @code{--script} command line option.
+
+Example file (@file{hello.lisp}):
+
+@lisp
+#!/usr/local/bin/sbcl --script
+(write-line "Hello, World!")
+@end lisp
-SBCL doesn't come with built-in support for shebang-line execution,
-but this can be provided with a shell trampoline, or by dispatching
-from initialization files (@pxref{Unix-style Command Line Protocol} for
-an example.)
+Usage examples:
+
+@smallexample
+$ ./hello.lisp
+Hello, World!
+@end smallexample
+@smallexample
+$ sbcl --script hello.lisp
+Hello, World!
+@end smallexample
@node Stopping SBCL
@comment node-name, next, previous, up
cleanly in Unix pipelines. See also the @code{--noprint} and
@code{--disable-debugger} options.
+@item --script @var{filename}
+As a runtime option this is equivalent to @code{--noinform}
+@code{--end-runtime-options} @code{--script} @var{filename}. See the
+description of @code{--script} as a toplevel option below.
+
@item --help
Print some basic information about SBCL, then exit.
@code{--load} options. See @code{sb-ext:disable-debugger} for details.
@xref{Debugger Entry}.
+@item --script @var{filename}
+Implies @code{--no-userinit} @code{--no-sysinit}
+@code{--disable-debugger} @code{--end-toplevel-options}.
+
+Causes the system to load the specified file instead of entering the
+read-eval-print-loop, and exit afterwards. If the file begins with a
+shebang line, it is ignored.
+
@end table
files follow.
@menu
-* Unix-style Command Line Protocol::
* Automatic Recompilation of Stale Fasls::
@end menu
-@node Unix-style Command Line Protocol
-@comment node-name, next, previous, up
-@subsubsection Unix-style Command Line Protocol
-@vindex sb-ext:*posix-argv*
-@vindex *posix-argv*
-
-Standard Unix tools that are interpreters follow a common command line
-protocol that is necessary to work with ``shebang scripts''. SBCL
-doesn't do this by default, but adding the following snippet to an
-initialization file does the trick:
-
-@lisp
-;;; If the first user-processable command-line argument is a filename,
-;;; disable the debugger, load the file handling shebang-line and quit.
-(let ((script (and (second *posix-argv*)
- (probe-file (second *posix-argv*)))))
- (when script
- ;; Handle shebang-line
- (set-dispatch-macro-character #\# #\!
- (lambda (stream char arg)
- (declare (ignore char arg))
- (read-line stream)))
- ;; Disable debugger
- (setf *invoke-debugger-hook*
- (lambda (condition hook)
- (declare (ignore hook))
- ;; Uncomment to get backtraces on errors
- ;; (sb-debug:backtrace 20)
- (format *error-output* "Error: ~A~%" condition)
- (quit)))
- (load script)
- (quit)))
-@end lisp
-
-Example file (@file{hello.lisp}):
-
-@lisp
-#!/usr/local/bin/sbcl --noinform
-(write-line "Hello, World!")
-@end lisp
-
-Usage examples:
-
-@smallexample
-$ ./hello.lisp
-Hello, World!
-@end smallexample
-
-@smallexample
-$ sbcl hello.lisp
-This is SBCL 0.8.13.70, an implementation of ANSI Common Lisp.
-More information about SBCL is available at <http://www.sbcl.org/>.
-
-SBCL is free software, provided as is, with absolutely no warranty.
-It is mostly in the public domain; some portions are provided under
-BSD-style licenses. See the CREDITS and COPYING files in the
-distribution for more information.
-Hello, World!
-@end smallexample
-
-
@node Automatic Recompilation of Stale Fasls
@comment node-name, next, previous, up
@subsubsection Automatic Recompilation of Stale Fasls
cleanly in Unix pipelines. See also the "\-\-noprint" and
"\-\-disable\-debugger" options.)
.TP 3
+.B \-\-script <filename>
+As a runtime option equivalent to \-\-noinform
+\-\-end\-toplevel\-options \-\-script <filename>. See the description
+of \-\-script as a toplevel option below.
+.TP 3
.B \-\-help
Print some basic information about SBCL, then exit.
.TP 3
This option disables the debugger, causing errors to print a backtrace
and exit with status 1 instead -- which is a mode of operation better suited
for batch processing. See the user manual on \f(CRSB\-EXT:DISABLE\-DEBUGGER\fR for details.
+.B \-\-script <filename>
+Implies \-\-no-sysinit \-\-no-userinit \-\-disable-debugger
+\-\-end\-toplevel\-options.
+
+Causes the system to load the specified file and exit immediately
+afterwards, instead of entering the readl-eval-print loop. If the file
+begins with a shebang line, it is ignored.
.PP
Regardless of the order in which toplevel options appear on the command
\-\-eval and \-\-load options are processed in the order given.
.PP
-Finally, the read-eval-print loop is entered.
+Finally, either the read-eval-print loop is entered or the file
+specified with \-\-script option is loaded.
+
+When running in the read-eval-print loop the system exits on end of
+file. Similarly, the system exits immediately after processing the
+file specified with \-\-script.
Note that when running SBCL with the \-\-core option, using a core
file created by a user call to the
(dolist (option options)
(process-1 option)))))
+;;; Skips past the shebang line on stream, if any.
+(defun maybe-skip-shebang-line (stream)
+ (let ((p (file-position stream)))
+ (flet ((next () (read-byte stream nil)))
+ (unwind-protect
+ (when (and (eq (next) (char-code #\#))
+ (eq (next) (char-code #\!)))
+ (setf p nil)
+ (loop for x = (next)
+ until (or (not x) (eq x (char-code #\newline)))))
+ (when p
+ (file-position stream p))))
+ t))
+
+(defun process-script (script)
+ (let ((pathname (native-pathname script))
+ (ok nil))
+ (unwind-protect
+ (with-open-file (f pathname :element-type :default)
+ (maybe-skip-shebang-line f)
+ (load f :verbose nil :print nil)
+ (setf ok t))
+ (quit :unix-status (if ok 0 1)))))
+
;; Errors while processing the command line cause the system to QUIT,
;; instead of trying to go into the Lisp debugger, because trying to
;; go into the Lisp debugger would get into various annoying issues of
(reversed-options nil)
;; Has a --noprint option been seen?
(noprint nil)
+ ;; Has a --script option been seen?
+ (script nil)
;; everything in *POSIX-ARGV* except for argv[0]=programname
(options (rest *posix-argv*)))
(pop options)
(startup-error
"unexpected end of command line options"))))
- (cond ((string= option "--sysinit")
+ (cond ((string= option "--script")
+ (pop-option)
+ (setf disable-debugger t
+ no-userinit t
+ no-sysinit t
+ script (pop-option))
+ (return))
+ ((string= option "--sysinit")
(pop-option)
(if sysinit
(startup-error "multiple --sysinit options")
(process-init-file sysinit :system))
(unless no-userinit
(process-init-file userinit :user))
- (process-eval/load-options (nreverse reversed-options)))
+ (process-eval/load-options (nreverse reversed-options))
+ (when script
+ (process-script script)
+ (bug "PROCESS-SCRIPT returned")))
(abort ()
- :report "Skip to toplevel READ/EVAL/PRINT loop."
+ :report (lambda (s)
+ (write-string
+ (if script
+ ;; In case script calls (enable-debugger)!
+ "Abort script, exiting lisp."
+ "Skip to toplevel READ/EVAL/PRINT loop.")
+ s))
(/show0 "CONTINUEing from pre-REPL RESTART-CASE")
(values)) ; (no-op, just fall through)
(quit ()
:report "Quit SBCL (calling #'QUIT, killing the process)."
+ :test (lambda (c) (declare (ignore c)) (not script))
(/show0 "falling through to QUIT from pre-REPL RESTART-CASE")
(quit :unix-status 1))))
/* other command line options */
boolean noinform = 0;
+ char *script = 0;
boolean end_runtime_options = 0;
lispobj initial_function;
int argi = 1;
while (argi < argc) {
char *arg = argv[argi];
- if (0 == strcmp(arg, "--noinform")) {
+ if (0 == strcmp(arg, "--script")) {
+ /* This is both a runtime and a toplevel option. As a
+ * runtime option, it is equivalent to --noinform.
+ * This exits, and does not increment argi, so that
+ * TOPLEVEL-INIT sees the option. */
+ noinform = 1;
+ end_runtime_options = 1;
+ break;
+ } else if (0 == strcmp(arg, "--noinform")) {
noinform = 1;
++argi;
} else if (0 == strcmp(arg, "--core")) {
echo failed DEFPACKAGE-then-PRINT from --eval form
exit $EXIT_LOSE
fi
-exit $EXIT_TEST_WIN
\ No newline at end of file
+
+# --script
+run_sbcl --script script-test.lisp --eval foo \
+ < /dev/null > $TEST_FILESTEM
+if [ "`grep -c :SCRIPT-OK $TEST_FILESTEM`" != 1 ] ; then
+ echo "failed --script test"
+ exit $EXIT_LOSE
+fi
+exit $EXIT_TEST_WIN
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.21.16"
+"1.0.21.17"