diff options
Diffstat (limited to 'bin/cl')
-rwxr-xr-x | bin/cl | 315 |
1 files changed, 315 insertions, 0 deletions
@@ -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 |