aboutsummaryrefslogtreecommitdiff
path: root/bin/cl
diff options
context:
space:
mode:
Diffstat (limited to 'bin/cl')
-rwxr-xr-xbin/cl315
1 files changed, 315 insertions, 0 deletions
diff --git a/bin/cl b/bin/cl
new file mode 100755
index 0000000..87d7c92
--- /dev/null
+++ b/bin/cl
@@ -0,0 +1,315 @@
+#!/bin/sh
+set -eu
+
+
+uuid() {
+ od -xN20 /dev/urandom |
+ head -n1 |
+ awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
+}
+
+tmpname() {
+ echo "${TMPDIR:-/tmp}/cl.tmpfile.$(uuid)"
+}
+
+mkstemp() {
+ name="$(tmpname)"
+ touch "$name"
+ echo "$name"
+}
+
+escape_name() {
+ printf '%s' "$1" |
+ sed 's|"|\\"|g' |
+ printf '(load "%s")\n' "$(cat -)"
+}
+
+
+IMPLEMENTATIONS='
+abcl
+allegro
+clasp
+clisp
+clozure
+cmucl
+ecl
+jscl
+mkcl
+sbcl
+'
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ cl [-e EXP] [-f FILE] [-p] [-M IMAGE] [-I IMPL] [-n] [-v] [FILE...] [-- LISP_OPTIONS]
+ cl -l
+ cl -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -e EXP an sexp to be evaluated (can be given more than once)
+ -E EXP an sexp to be executed as a script
+ -f FILE a file to be evaluated (can be given more than once)
+ -p print the value of the last given expression
+ -M IMAGE load the given Lisp image
+ -I IMPL use the given implementation (default: $LISP_CLI_IMPL)
+ -n skip loading the implementation's init file
+ -v verbose mode
+ -l list the known types of implementations
+ -h, --help show this message
+
+ FILE the file to be executed as a script
+ LISP_OPTIONS options to be forwarrded to the underlying Lisp command
+
+
+ Lauch the desired Lisp implementation, properly adapting the given
+ CLI options.
+
+ When the implementation is not explicited on the command line, and
+ the $LISP_CLI_IMPL environment variable in unset, implementations are
+ searched for alphabetically in $PATH, untill one is found, otherwise
+ an error is emitted.
+
+ The supported implementations are:
+ EOF
+
+
+ for i in $IMPLEMENTATIONS; do
+ printf -- '- %s\n' "$i"
+ done
+
+ cat <<-'EOF'
+
+
+ Examples:
+
+ Launch CLISP REPL, when $LISP_CLI_IMPL is set to 'clisp':
+
+ $ cl
+
+
+ Lauch SBCL REPL, with the given Lisp image loaded, skipping the
+ loading of the '.sbclrc' file:
+
+ $ cl -n -Isbcl sbcl.image
+
+
+ Run file1.lisp with ABCL:
+
+ $ cl -Iabcl file1.lisp
+
+
+ Process STDIN:
+
+ $ cat <<-EOS > process.lisp
+
+ EOS
+ $ cat f1.txt f2.txt | cl -p process.lisp
+
+
+ Print a value on all types of implementations:
+
+ $ for i in `cl -l`; do cl -I$i -pe 'call-arguments-list'; done
+ EOF
+}
+
+
+for flag in "$@"; do
+ case "$flag" in
+ --)
+ break
+ ;;
+ --help)
+ usage
+ help
+ exit
+ ;;
+ *)
+ ;;
+ esac
+done
+
+NO_RC=false
+SCRIPT="$(mkstemp)"
+LISP_CLI_RC="${XDG_CONFIG_HOME:-$HOME/.config}/lisp-cli/init.lisp"
+VERBOSE=false
+IMAGE=''
+IMPL="${LISP_CLI_IMPL:-}"
+INTERACTIVE=true
+while getopts 'e:E:f:pM:I:nvlh' flag; do
+ case "$flag" in
+ e)
+ printf '%s\n' "$OPTARG" >> "$SCRIPT"
+ ;;
+ E)
+ printf '%s\n' "$OPTARG" >> "$SCRIPT"
+ INTERACTIVE=false
+ ;;
+ f)
+ escape_name "$OPTARG" >> "$SCRIPT"
+ ;;
+ M)
+ IMAGE="$OPTARG"
+ ;;
+ I)
+ IMPL="$OPTARG"
+ ;;
+ n)
+ NO_RC=true
+ ;;
+ v)
+ VERBOSE=true
+ ;;
+ l)
+ for i in $IMPLEMENTATIONS; do
+ printf '%s\n' "$i"
+ done
+ exit
+ ;;
+ h)
+ usage
+ help
+ exit
+ ;;
+ *)
+ usage >&2
+ exit 2
+ ;;
+ esac
+done
+
+shift $((OPTIND - 2))
+if [ "$1" != '--' ]; then
+ shift
+fi
+
+PRESERVE_ARGS=false
+for f in "$@"; do
+ if [ "$f" = '--' ]; then
+ PRESERVE_ARGS=true
+ shift
+ break
+ fi
+ INTERACTIVE=false
+ escape_name "$f" >> "$SCRIPT"
+done
+
+if [ "$PRESERVE_ARGS" = false ]; then
+ set --
+fi
+
+MAIN="$(mkstemp)"
+if [ "$NO_RC" = false ] && [ -e "$LISP_CLI_RC" ]; then
+ escape_name "$LISP_CLI_RC" > "$MAIN"
+fi
+
+if [ "$INTERACTIVE" = true ]; then
+ escape_name "$SCRIPT" >> "$MAIN"
+else
+ cat <<-EOF >> "$MAIN"
+ (handler-case
+ (progn
+ (load "$SCRIPT"
+ :verbose nil
+ :print nil)
+ (uiop:quit 0))
+ (error (e)
+ (format *error-output* "~&~%error: ~a~%" e)
+ (uiop:quit 1)))
+ EOF
+fi
+
+if [ -z "$IMPL" ]; then
+ for i in $IMPLEMENTATIONS; do
+ if command -v "$i" > /dev/null; then
+ IMPL="$i"
+ break
+ fi
+ done
+ if [ -z "$IMPL" ]; then
+ printf "Could not find any implementation in \$PATH.\n" >&2
+ exit 2
+ fi
+fi
+
+
+case "$IMPL" in
+ abcl)
+ exit 4
+ ;;
+ allegro)
+ exit 4
+ ;;
+ clasp)
+ exit 4
+ ;;
+ clisp)
+ set -- -ansi -i "$MAIN" "$@"
+ if [ -n "$IMAGE" ]; then
+ set -- -M "$IMAGE" "$@"
+ fi
+ if [ "$NO_RC" = true ]; then
+ set -- -norc "$@"
+ fi
+ if [ "$VERBOSE" = false ]; then
+ set -- -q -q "$@"
+ else
+ set -x
+ fi
+ exec clisp "$@"
+ ;;
+ clozure)
+ set -- -l "$MAIN" "$@"
+ if [ -n "$IMAGE" ]; then
+ set -- -I "$IMAGE" "$@"
+ fi
+ if [ "$NO_RC" = true ]; then
+ set -- -n "$@"
+ fi
+ if [ "$VERBOSE" = false ]; then
+ set -- -Q "$@"
+ else
+ set -x
+ fi
+ exec ccl "$@"
+ ;;
+ cmucl)
+ exit 4
+ ;;
+ ecl)
+ exit 4
+ ;;
+ jscl)
+ exit 4
+ ;;
+ mkcl)
+ exit 4
+ ;;
+ sbcl)
+ set -- --load "$MAIN" "$@"
+ if [ -n "$IMAGE" ]; then
+ # The '--core' "C runtime option" must appear before the
+ # other "Lisp options", such as '--load'.
+ set -- --core "$IMAGE" "$@"
+ fi
+ if [ "$NO_RC" = true ]; then
+ set -- --no-sysinit --no-userinit "$@"
+ fi
+ if [ "$VERBOSE" = false ]; then
+ set -- --noinform "$@"
+ else
+ set -x
+ fi
+ exec sbcl "$@"
+ ;;
+ *)
+ printf 'Unsupported implementation: "%s".\n\n' "$IMPL" >&2
+ usage >&2
+ exit 2
+ ;;
+esac