summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-06-08 23:20:23 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-06-08 23:20:23 -0400
commit5f29a477f190b9f4c0d3835574dfbcbad19d827c (patch)
treea2eef90f0afd351c65edb7aae5c9dc45699dedd9
parent8c67cad1f2bbcaabe23586643d670ba08f3d2a05 (diff)
emacsterm: sane option parsing; create emacsterm-{xterm,rxvt} for insanity
-rw-r--r--.gitignore2
-rw-r--r--Makefile2
-rw-r--r--common.sh.in7
-rw-r--r--emacsterm-rxvt.sh.in100
-rw-r--r--emacsterm-xterm.sh.in108
-rw-r--r--emacsterm.sh.in163
6 files changed, 268 insertions, 114 deletions
diff --git a/.gitignore b/.gitignore
index af0a490..9a81e7b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
ediff
emacsmail
emacsterm
+emacsterm-rxvt
+emacsterm-xterm
*.sh
diff --git a/Makefile b/Makefile
index 96fcd9a..8fc2ada 100644
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ else
-include .srcfiles.mk
endif
-std.out_files = ediff emacsmail emacsterm
+std.out_files = ediff emacsmail emacsterm emacsterm-rxvt emacsterm-xterm
std.sys_files = $(addprefix $(bindir)/,$(std.out_files))
std.clean_files += *.sh
diff --git a/common.sh.in b/common.sh.in
index b2b4768..2488a69 100644
--- a/common.sh.in
+++ b/common.sh.in
@@ -37,7 +37,12 @@ flag() {
expand)
declare -gi _flag_indent=${#str}
fi
- printf -- "%- ${_flag_indent}s%s\n" "$1" "$(print "${@:2}")"
+ local flag=$1
+ if [[ ${#1} -ge $_flag_indent ]]; then
+ printf -- "%s\n" "$flag"
+ flag=''
+ fi
+ printf -- "%- ${_flag_indent}s%s\n" "$flag" "$(print "${@:2}")"
}
error() {
diff --git a/emacsterm-rxvt.sh.in b/emacsterm-rxvt.sh.in
new file mode 100644
index 0000000..8b3d3ef
--- /dev/null
+++ b/emacsterm-rxvt.sh.in
@@ -0,0 +1,100 @@
+#!@bash@
+
+# Copyright (C) 2011, 2013-2014, 2016 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# This file is not considered part of GNU Emacs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+m4_include(common.sh.in)
+
+usage() {
+ print "Usage: %q [OPTIONS] [-e PROGRAM [ARGS...]]" "$0"
+ print 'A wrapper around emacsterm that behaves like rxvt'
+ echo
+ print 'The "-e" option cannot be combined with other short options.'
+ echo
+ print 'If the "-e" option is not given, then "${SHELL:-/bin/sh}" is used.'
+ echo
+ print 'The following OPTIONS are accepted:'
+ emacs_usage
+ flag "-T $(_ FUNCTION)" 'Use Emacs Lisp FUNCTION instead of "term"'
+ flag "-e $(_ 'PROGRAM [ARGS...]')" 'Specify the command to execute'
+ echo
+ print 'Bugs:'
+ print \
+'The string "-e" cannot be used as an argument to flags that take
+arguments.'
+}
+
+
+main() {
+ # Run through and check for the -e flag
+ declare e=false
+ declare -a arg_ary=("$@")
+ declare -i i=0
+ while [[ $i -lt ${#arg_ary[@]} ]]; do
+ case "${arg_ary[$i]}" in
+ '-e') e=true; arg_ary[$i]='--'; break;;
+ '--') error 'bad command line option "--"'; next error; return $?;;
+ esac
+ i+=1
+ done
+
+ declare -a flags=()
+ declare -a prog=()
+ declare mode=normal
+
+ emacs_getopt_init
+ declare args
+ if ! args="$(emacs_getopt T: '' "${arg_ary[@]}")"; then
+ mode=error
+ else
+ # Pretty much identical option parsing to emacsterm
+ eval set -- "$args"
+ while true; do
+ case "$1" in
+ -V|--version) shift; mode=version;;
+ -H|--help) shift; mode=usage;;
+ -T) flags+=("$1" "$2"); shift 2;;
+ --) shift; break;;
+ *)
+ if [[ $1 =~ $emacs_getopt_2 ]]; then
+ flags+=("$1" "$2"); shift 2
+ else
+ flags+=("$1"); shift 1
+ fi
+ ;;
+ esac
+ done
+
+ # Now for the rxvt weirdness
+ if ! $e; then
+ case $# in
+ 0) prog=("${SHELL:-/bin/sh}");;
+ *) error 'Extra arguments: %s' "$*"; mode=error;;
+ esac
+ else
+ case $# in
+ 0) getopt -Q -n "$0" e: -e; mode=error;;
+ *) prog=("$@");;
+ esac
+ fi
+ fi
+
+ next "$mode" \
+ emacsterm "${flags[@]}" -- "${prog[@]}"
+}
+
+main "$@"
diff --git a/emacsterm-xterm.sh.in b/emacsterm-xterm.sh.in
new file mode 100644
index 0000000..32110e0
--- /dev/null
+++ b/emacsterm-xterm.sh.in
@@ -0,0 +1,108 @@
+#!@bash@
+
+# Copyright (C) 2011, 2013-2014, 2016 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# This file is not considered part of GNU Emacs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+m4_include(common.sh.in)
+
+usage() {
+ print "Usage: %q [OPTIONS] [PROGRAM]" "$0"
+ print " or: %q [OPTIONS] -e COMMAND" "$0"
+ print " or: %q [OPTIONS] -e PROGRAM [ARGS...]" "$0"
+ print 'A wrapper around emacsterm that behaves like xterm'
+ echo
+ print 'The "-e" option cannot be combined with other short options.'
+ echo
+ print \
+'This tool does not (yet?) do any of the mucking around with SHELL,
+XTERM_SHELL, /etc/shells, or the user database (/etc/passwd) that xterm
+does. The simplified behavior is that if the "-e" option is not given,
+then "${SHELL:-/bin/sh}" is used.'
+ echo
+ print 'The following OPTIONS are accepted:'
+ emacs_usage
+ flag "-T $(_ FUNCTION)" 'Use Emacs Lisp FUNCTION instead of "term"'
+ flag "-e $(_ 'COMMAND|<PROGRAM [ARGS...]>')" 'Specify the command to execute'
+ echo
+ print 'Bugs:'
+ print \
+'The string "-e" cannot be used as an argument to flags that take
+arguments.'
+}
+
+
+main() {
+ # Run through and check for the -e flag
+ declare e=false
+ declare -a arg_ary=("$@")
+ declare -i i=0
+ while [[ $i -lt ${#arg_ary[@]} ]]; do
+ case "${arg_ary[$i]}" in
+ '-e') e=true; arg_ary[$i]='--'; break;;
+ '--') error 'bad command line option "--"'; next error; return $?;;
+ esac
+ i+=1
+ done
+
+ declare -a flags=()
+ declare -a prog=()
+ declare mode=normal
+
+ emacs_getopt_init
+ declare args
+ if ! args="$(emacs_getopt T: '' "${arg_ary[@]}")"; then
+ mode=error
+ else
+ # Pretty much identical option parsing to emacsterm
+ eval set -- "$args"
+ while true; do
+ case "$1" in
+ -V|--version) shift; mode=version;;
+ -H|--help) shift; mode=usage;;
+ -T) flags+=("$1" "$2"); shift 2;;
+ --) shift; break;;
+ *)
+ if [[ $1 =~ $emacs_getopt_2 ]]; then
+ flags+=("$1" "$2"); shift 2
+ else
+ flags+=("$1"); shift 1
+ fi
+ ;;
+ esac
+ done
+
+ # Now for the xterm weirdness
+ if ! $e; then
+ case $# in
+ 0) prog=("${SHELL:-/bin/sh}");;
+ 1) prog=("$1");;
+ *) shift; error 'Extra arguments: %s' "$*"; mode=error;;
+ esac
+ else
+ case $# in
+ 0) getopt -Q -n "$0" e: -e; mode=error;;
+ 1) prog=(sh -c "$1");;
+ *) prog=("$@");;
+ esac
+ fi
+ fi
+
+ next "$mode" \
+ emacsterm "${flags[@]}" -- "${prog[@]}"
+}
+
+main "$@"
diff --git a/emacsterm.sh.in b/emacsterm.sh.in
index 6ecbed3..e850aad 100644
--- a/emacsterm.sh.in
+++ b/emacsterm.sh.in
@@ -20,135 +20,74 @@
m4_include(common.sh.in)
usage() {
- print "Usage: %q [OPTIONS] [SHELL]" "$0"
+ print "Usage: %q [OPTIONS] [--] [PROGRAM [ARGS...]]" "$0"
+ print 'Use Emacs as a terminal emulator'
echo
- print 'This utility does NOT support option combining.'
+ print \
+'If ARGS contains anything beginning with "-", then you will need to put
+"--" before PROGRAM so that it does not get treated as part of OPTIONS.'
+ echo
+ print 'If PROGRAM is not given, the default is "${SHELL:-/bin/sh}".'
echo
print 'The following OPTIONS are accepted:'
emacs_usage
- flag '-r' 'Use rxvt-style parsing of CMD for -e (~execve)'
- flag '-x' 'Use xterm-style parsing of CMD for -e (~system)'
- flag "-e $(_ CMD)" 'Execute CMD instead of ${SHELL:-/bin/sh}'
+ flag "-T $(_ FUNCTION)" 'Use Emacs Lisp FUNCTION instead of "term"'
}
main() {
- declare mode
- declare mimic
- declare cmd
- declare -a flags
- parse "$@"
-
- next \
- emacsclient "${flags[@]}" --eval \
- "(term $(emacs_quote "${cmd}"))"
-}
-
-# Sets the 'global' variables:
-# - mode
-# - mimic
-# - cmd
-# - flags (array)
-parse() {
- mode=normal
- mimic=rxvt
- cmd=
- flags=()
+ declare -a flags=()
+ declare fn=term
+ declare -a prog=("${SHELL:-/bin/sh}")
+ declare mode=normal
emacs_getopt_init
-
- while [[ $# -gt 0 ]] && [ "$mode" != error ]; do
- case "$1" in
- -V|--version) shift; mode=version;;
- -H|--help) shift; mode=usage;;
- -r) shift; mimic=rxvt;;
- -x) shift; mimic=xterm;;
- -e) shift; parse_cmd "$@"; set --;;
- --) shift; parse_shell "$@"; set --;;
- -*) parse_emacs_getopt "$@"; shift $?;;
- *) parse_shell "$@"; set --;;
- esac
- done
-
- # This matches rxvt's behavior.
- # This is simpler than xterm's behavior.
- cmd="${cmd:-${SHELL:-/bin/sh}}"
-}
-
-# Return status is the number of things to shift
-parse_emacs_getopt() {
- declare -a flag
- # Because we don't want options to get combined, we run getopt
- # with : stripped, so that we can check that it returned 2
- # arguments: the flag itself, and '--'. If there were
- # combined flags, then it will return more than 2 arguments.
- if eval "flag=($(getopt -a \
- -n "$0" \
- -o "${emacs_getopt_o//:/}" \
- -l "${emacs_getopt_l//:/}" \
- -- "$1" 2>/dev/null))" &&
- [[ ${#flag[@]} == 2 ]]
- then
- # getopt worked
- if [[ $flag =~ $emacs_getopt_2 ]]; then
- # flag takes an argument
- if [[ $# -gt 1 ]]; then
- flags+=("$flag" "$2")
- return 2
- else
- # Missing the required 2nd part
- getopt -Q -a \
- -n "$0" \
- -o "$emacs_getopt_o" \
- -l "$emacs_getopt_l" \
- -- "$flag"
- mode=error
- return 1
- fi
- else
- # pass the flag along to emacs
- flags+=("$flag")
- return 1
- fi
- else
- # getopt either didn't work, or did combined flags
- # Have getopt display its own error message:
- getopt -Q -a -n "$0" -o '' -l '' -- "$1"
+ declare args
+ if ! args="$(emacs_getopt T: '' "$@")"; then
mode=error
- return 1
+ else
+ eval set -- "$args"
+ while true; do
+ case "$1" in
+ -V|--version) shift; mode=version;;
+ -H|--help) shift; mode=usage;;
+ -T) fn="$2"; shift 2;;
+ --) shift; break;;
+ *)
+ if [[ $1 =~ $emacs_getopt_2 ]]; then
+ flags+=("$1" "$2"); shift 2
+ else
+ flags+=("$1"); shift 1
+ fi
+ ;;
+ esac
+ done
+ if [[ $# -gt 0 ]]; then
+ prog=("$@")
+ fi
fi
-}
-parse_cmd() {
- cmd="$(mktemp -t -- "${0##*/}.XXXXXXXXXX")"
- trap "$(printf 'rm -f -- %q' "$cmd")" EXIT
- {
- echo '#!/bin/sh'
- case "$mimic" in
- xterm)
- if [[ $# == 1 ]]; then
- printf '%s' "$1"
- else
- printf -- '%q ' exec "$@"
- fi
- ;;
- rxvt)
- printf -- '%q ' exec "$@"
- ;;
- esac
- echo
- } > "$cmd"
- chmod 755 "$cmd"
+ next "$mode" \
+ emacsclient "${flags[@]}" --eval \
+ "($fn $(emacs_quote "$(args2program "${prog[@]}")"))"
}
-parse_shell() {
- if [[ $# == 1 ]]; then
- cmd=$1
+args2program() {
+ local program
+ if [ $# = 1 ]; then
+ program="$1"
else
- shift
- error "extra arguments: %s" "$*"
- mode=error
+ program="$(mktemp -t -- "${0##*/}.XXXXXXXXXX")"
+ {
+ echo '#!@bash@'
+ echo '{'
+ echo 'rm -f -- "$0"'
+ printf '%q ' exec -- "$@"
+ echo '}'
+ } > "$program"
+ chmod 755 "$program"
fi
+ printf '%s\n' "$program"
}
main "$@"