Subject: Re: CMUCL CGI scripting
From: (Rob Warnock)
Date: 17 May 2001 04:03:25 GMT
Newsgroups: comp.lang.lisp
Message-ID: <9dviid$8v856$>
Mike McDonald <> replied to:
| (Hannah Schroeter) writes:
| > #! /bin/sh
| > exec sbcl --noinform --noprint --noprogrammer			\
| >     --eval '(load "foo.lisp")' --eval '(quit)' --end-toplevel-options

And since most people who write scripts want to have the whole thing
inline -- not in a separate file -- he countered with:

| #! /bin/sh -f
| exec /usr/local/bin/cmucl -quiet -batch \
|      -eval '(setq *prompt* "")' -noinit <<\EOF
| (progn
|     ;; My code goes here
|     (print `hello-world)
|     (values))

But in my experience most people who write scripts want them
in-line *and* want to be able to access the normal inherited
standard-input when the script runs (say, to interact with the
user, or with a piped stdin), which Mike's approach precludes.

Here's the gross, ugly, smelly hack I've been using with CMUCL &
CLISP (with minor variations) to provide both at the same time:

	% cat ~/bin/hello_cmucl
	#!/bin/sh -f
	exec /usr/local/bin/cmucl -eval \ 
	"(progn		; double the backslashes for 'sh'
	   (set-dispatch-macro-character #\\# #\\!
	     (get-dispatch-macro-character #\\# #\\| ))
	   (defvar *script-name* \"$0\")     
	   (defvar *script-args* \"$*\")     
	   (load *script-name* :verbose nil))"    
	|# ; close the block comment [CLISP needs "!#" here]

	(format t "Hello world!~%Script = ~S~%Args = ~S~%"
		  *script-name* *script-args*)
	;(format t "~%Input a number: ")	; oops, not if piped
	(let ((x (read)))
	  (format t "~S squared = ~S~%" x (* x x)))

	% echo 23.45 | hello_cmucl foo bar "baz gorp"
	Hello world!
	Script = "/u/rpw3/bin/hello_cmucl"
	Args = "foo bar baz gorp"
	23.45 squared = 549.9025


p.s. The main problem remaining with the above is Unix command-line
arguments with spaces in them (e.g., "baz gorp"), since the "$*"
doesn't distinguish between inter- and intra-arg whitespace. The
usual Unix solution here would be to use "$@", e.g.:

	"(progn ...
	   (defvar *script-args* '#(\"$@\")) ; build a vector of strings

but that doesn't work because the inter-arg quotes [or more precisely,
the <quote><space><quote> sequences] that "$@" introduces don't get
backslash-quoted here, and thus break the string argument to "-eval"
in the middle, causing a premature EOF. (Oops!)

Rob Warnock, 31-2-510
SGI Network Engineering		<URL:>
1600 Amphitheatre Pkwy.		Phone: 650-933-1673
Mountain View, CA  94043	PP-ASEL-IA