aboutsummaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bin')
-rwxr-xr-xbin/cl296
1 files changed, 296 insertions, 0 deletions
diff --git a/bin/cl b/bin/cl
new file mode 100755
index 0000000..1b9a659
--- /dev/null
+++ b/bin/cl
@@ -0,0 +1,296 @@
+#!/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
+ccl
+clasp
+clisp
+cmucl
+ecl
+jscl
+mkcl
+sbcl
+'
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ cl [-e EXP] [-f FILE] [-p] [-M IMAGE] [-I IMPL] [-n] [-v] [FILE...]
+ cl -l
+ cl -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -e EXP an sexp to be evaluated (can be given more than once)
+ -f FILE FIXME
+ -p print the value of the last given expression
+ -M IMAGE load the given Lisp image
+ -m disable looking for the default image under $XDG_DATA_HOME
+ -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 FIXME
+
+
+ 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=''
+SKIP_DEFAULT_IMAGE=false
+IMPL="${LISP_CLI_IMPL:-}"
+while getopts 'e:f:pM:mI:nvlh' flag; do
+ case "$flag" in
+ e)
+ printf '%s\n' "$OPTARG" >> "$SCRIPT"
+ ;;
+ f)
+ escape_name "$OPTARG" >> "$SCRIPT"
+ ;;
+ M)
+ IMAGE="$OPTARG"
+ ;;
+ m)
+ SKIP_DEFAULT_IMAGE=true
+ ;;
+ I)
+ IMPL="$OPTARG"
+ ;;
+ n)
+ NO_RC=true
+ ;;
+ v)
+ VERBOSE=true
+ ;;
+ h)
+ usage
+ help
+ exit
+ ;;
+ *)
+ usage >&2
+ exit 2
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+INTERACTIVE=true
+for f in "$@"; do
+ INTERACTIVE=false
+ escape_name "$f" >> "$SCRIPT"
+done
+
+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
+
+DEFAULT_IMAGE="${XDG_DATA_HOME:-$HOME/.local/share}/lisp-cli/$IMPL.image"
+if [ "$SKIP_DEFAULT_IMAGE" = false ] && [ -z "$IMAGE" ] &&
+ [ -e "$DEFAULT_IMAGE" ]; then
+ IMAGE="$DEFAULT_IMAGE"
+fi
+
+case "$IMPL" in
+ abcl)
+ exit 4
+ ;;
+ allegro)
+ exit 4
+ ;;
+ ccl)
+ exit 4
+ ;;
+ clasp)
+ exit 4
+ ;;
+ clisp)
+ ARGS="-ansi -i $MAIN"
+ if [ -n "$IMAGE" ]; then
+ set -- -M "$IMAGE"
+ fi
+ if [ "$NO_RC" = true ]; then
+ ARGS="$ARGS -norc"
+ fi
+ if [ "$VERBOSE" = false ]; then
+ ARGS="$ARGS -q -q"
+ else
+ set -x
+ fi
+ exec clisp $ARGS "$@"
+ ;;
+ cmucl)
+ exit 4
+ ;;
+ ecl)
+ exit 4
+ ;;
+ jscl)
+ exit 4
+ ;;
+ mkcl)
+ exit 4
+ ;;
+ sbcl)
+ ARGS="--disable-debugger --script $MAIN"
+ if [ "$VERBOSE" = false ]; then
+ ARGS="$ARGS --noinform"
+ fi
+ if [ "$NO_RC" = true ]; then
+ ARGS="$ARGS --no-sysinit --no-userinit"
+ fi
+ if [ -n "$IMAGE" ]; then
+ set -- --core "$IMAGE"
+ fi
+ exec sbcl $ARGS "$@"
+ ;;
+ *)
+ printf 'Unsupported implementation: "%s".\n\n' "$IMPL" >&2
+ usage >&2
+ exit 2
+ ;;
+esac
+
+exit
+
+# https://www.cliki.net/cl-launch
+# buildapp
+# https://github.com/memleaks/clbuild
+# https://www.cliki.net/roswell
+# https://github.com/shinmera/cl-all
+# https://fare.livejournal.com/184127.html
+# https://github.com/rolpereira/trivial-dump-core
+# FIXME: enable readline from CL itself
+when competing with roswell, add completion
+FIXME: implement the example from help string