diff --git a/src/cmd/levee/Makefile.in b/src/cmd/levee/Makefile.in new file mode 100644 index 0000000..1cea29f --- /dev/null +++ b/src/cmd/levee/Makefile.in @@ -0,0 +1,56 @@ +# makefile for Levee + +exedir=@exedir@ +mandir=@mandir@ +CC=@CC@ + +CFLAGS=@CFLAGS@ +LDFLAGS=@LDFLAGS@ + +OBJS = blockio.o display.o editcor.o exec.o find.o \ + unixcall.o globals.o insert.o main.o misc.o \ + modify.o move.o ucsd.o undo.o wildargs.o \ + version.o + +lev: $(OBJS) + $(CC) $(LDFLAGS) -o lev $(OBJS) @LIBS@ + +version.o: version.c VERSION + $(CC) $(CFLAGS) -c -DVERSION=\"`cat VERSION`\" version.c + +clean: + rm -f *.o lev + +distclean spotless: clean + rm -f @GENERATED_FILES@ @CONFIGURE_FILES@ + +install: install.bin install.man + +install.bin: lev + @INSTALL_DIR@ $(PREFIX)$(exedir) + @INSTALL_PROGRAM@ lev $(PREFIX)$(exedir)/levee + @NOMK@@LN_S@ -f levee $(PREFIX)$(exedir)/lv + +install.man: + @INSTALL_DIR@ $(PREFIX)$(mandir)/man1 + @INSTALL_DATA@ lv.1 $(PREFIX)$(mandir)/man1/levee.1 + @NOMK@echo ".so man1/levee.1" > $(PREFIX)$(mandir)/man1/lv.1 + +# Dependencies + +blockio.o : levee.h extern.h blockio.c config.h +display.o : levee.h extern.h termcap.i display.c config.h +editcor.o : levee.h extern.h editcor.c config.h +exec.o : levee.h extern.h exec.c config.h +find.o : levee.h extern.h grep.h find.c config.h +globals.o : levee.h globals.c config.h +insert.o : levee.h extern.h insert.c config.h +main.o : levee.h extern.h main.c config.h +misc.o : levee.h extern.h misc.c config.h +modify.o : levee.h extern.h grep.h modify.c config.h +move.o : levee.h extern.h move.c config.h +rmxcall.o : levee.h rmxcall.c config.h +ucsd.o : levee.h extern.h ucsd.c config.h +undo.o : levee.h extern.h undo.c config.h +unixcall.o : levee.h extern.h unixcall.c config.h +wildargs.o : levee.h extern.h wildargs.c config.h diff --git a/src/cmd/levee/VERSION b/src/cmd/levee/VERSION new file mode 100644 index 0000000..4d2ab0b --- /dev/null +++ b/src/cmd/levee/VERSION @@ -0,0 +1 @@ +3.5a diff --git a/src/cmd/levee/beep.c b/src/cmd/levee/beep.c new file mode 100644 index 0000000..32c7fab --- /dev/null +++ b/src/cmd/levee/beep.c @@ -0,0 +1,48 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" + +#if OS_ATARI +#include + +char sound[] = { + 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00, + 0xF8,0x10,0x10,0x10,0x00,0x20,0x03 +}; + +#define SADDR 0xFF8800L + +typedef char srdef[4]; + +srdef *SOUND = (srdef *)SADDR; + +main() +{ + register i; + long ssp; + + ssp = Super(0L); + for (i=0; i/dev/null >/dev/null; then +__ac_dirname() { + dirname "$1" +} +else +__ac_dirname() { + echo "$1" | sed -e 's:/[^/]*$::' +} +fi + +ac_progname=$0 +ac_configure_command= +Q=\' +for x in "$@"; do + ac_configure_command="$ac_configure_command $Q$x$Q" +done +# ac_configure_command="$*" + +__d=`__ac_dirname "$ac_progname"` +if [ "$__d" = "$ac_progname" ]; then + AC_SRCDIR=`pwd` +else + AC_SRCDIR=`cd $__d;pwd` +fi + +__ac_dir() { + if test -d "$1"; then + (cd "$1";pwd) + else + echo "$1"; + fi +} + +while [ $# -gt 0 ]; do + unset matched + + case X"$1" in + X--src|X--srcdir) + AC_SRCDIR=`__ac_dir "$2"` + _set_srcdir=1 + shift 2;; + + X--src=*|X--srcdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_SRCDIR=`__ac_dir "$__d"` + _set_srcdir=1 + shift 1 ;; + + X--prefix) + AC_PREFIX=`__ac_dir "$2"` + _set_prefix=1 + shift 2;; + + X--prefix=*) + __d=`echo "$1"| sed -e 's/^[^=]*=//'` + AC_PREFIX=`__ac_dir "$__d"` + _set_prefix=1 + shift 1;; + + X--confdir) + AC_CONFDIR=`__ac_dir "$2"` + _set_confdir=1 + shift 2;; + + X--confdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_CONFDIR=`__ac_dir "$__d"` + _set_confdir=1 + shift 1;; + + X--libexec|X--libexecdir) + AC_LIBEXEC=`__ac_dir "$2"` + _set_libexec=1 + shift 2;; + + X--libexec=*|X--libexecdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_LIBEXEC=`__ac_dir "$__d"` + _set_libexec=1 + shift 1;; + + X--lib|X--libdir) + AC_LIBDIR=`__ac_dir "$2"` + _set_libdir=1 + shift 2;; + + X--lib=*|X--libdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_LIBDIR=`__ac_dir "$__d"` + _set_libdir=1 + shift 1;; + + X--exec|X--execdir) + AC_EXECDIR=`__ac_dir "$2"` + _set_execdir=1 + shift 2;; + + X--exec=*|X--execdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_EXECDIR=`__ac_dir "$__d"` + _set_execdir=1 + shift 1;; + + X--sbin|X--sbindir) + AC_SBINDIR=`__ac_dir "$2"` + _set_sbindir=1 + shift 2;; + + X--sbin=*|X--sbindir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_SBINDIR=`__ac_dir "$__d"` + _set_sbindir=1 + shift 1;; + + X--man|X--mandir) + AC_MANDIR=`__ac_dir "$2"` + _set_mandir=1 + shift 2;; + + X--man=*|X--mandir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_MANDIR=`__ac_dir "$__d"` + _set_mandir=1 + shift 1;; + + X--use-*=*) + _var=`echo "$1"| sed -n 's/^--use-\([A-Za-z][-A-Za-z0-9_]*\)=.*$/\1/p'` + if [ "$_var" ]; then + _val=`echo "$1" | sed -e 's/^--use-[^=]*=\(.*\)$/\1/'` + _v=`echo $_var | tr '[a-z]' '[A-Z]' | tr '-' '_'` + case X"$_val" in + X[Yy][Ee][Ss]|X[Tt][Rr][Uu][Ee]) eval USE_${_v}=T ;; + X[Nn][Oo]|X[Ff][Aa][Ll][Ss][Ee]) eval unset USE_${_v} ;; + *) echo "Bad value for --use-$_var ; must be yes or no" + exit 1 ;; + esac + else + echo "Bad option $1. Use --help to show options" 1>&2 + exit 1 + fi + shift 1 ;; + + X--use-*) + _var=`echo "$1"|sed -n 's/^--use-\([A-Za-z][-A-Za-z0-9_]*\)$/\1/p'` + _v=`echo $_var | tr '[a-z]' '[A-Z]' | tr '-' '_'` + eval USE_${_v}=T + shift 1;; + + X--with-*=*) + _var=`echo "$1"| sed -n 's/^--with-\([A-Za-z][-A-Za-z0-9_]*\)=.*$/\1/p'` + if [ "$_var" ]; then + _val=`echo "$1" | sed -e 's/^--with-[^=]*=\(.*\)$/\1/'` + _v=`echo $_var | tr '[a-z]' '[A-Z]' | tr '-' '_'` + eval WITH_${_v}=\"$_val\" + else + echo "Bad option $1. Use --help to show options" 1>&2 + exit 1 + fi + shift 1 ;; + + X--with-*) + _var=`echo "$1" | sed -n 's/^--with-\([A-Za-z][A-Za-z0-9_-]*\)$/\1/p'` + if [ "$_var" ]; then + _v=`echo $_var | tr '[a-z]' '[A-Z]' | tr '-' '_'` + eval WITH_${_v}=1 + else + echo "Bad option $1. Use --help to show options" 1>&2 + exit 1 + fi + shift 1 ;; + + X--help) + echo "$ac_standard" + test "$ac_help" && echo "$ac_help" + exit 0;; + + *) if [ "$LOCAL_AC_OPTIONS" ]; then + eval "$LOCAL_AC_OPTIONS" + else + ac_error=T + fi + if [ "$ac_error" ]; then + echo "Bad option $1. Use --help to show options" 1>&2 + exit 1 + fi ;; + esac +done + + +# +# echo w/o newline +# +echononl() +{ + ${ac_echo:-echo} "${@}$ac_echo_nonl" +} + +# +# log something to the terminal and to a logfile. +# +LOG () { + echo "$@" + echo "$@" 1>&5 +} + +# +# log something to the terminal without a newline, and to a logfile with +# a newline +# +LOGN () { + echononl "$@" 1>&5 + echo "$@" +} + +# +# log something to the terminal +# +TLOG () { + echo "$@" 1>&5 +} + +# +# log something to the terminal, no newline +# +TLOGN () { + echononl "$@" 1>&5 +} + + +# +# AC_CONTINUE tells configure not to bomb if something fails, but to +# continue blithely along +# +AC_CONTINUE () { + __fail="return" +} + +# +# Emulate gnu autoconf's AC_CHECK_HEADERS() function +# +AC_CHECK_HEADERS () { + AC_PROG_CC + + echo "/* AC_CHECK_HEADERS */" > /tmp/ngc$$.c + for hdr in $*; do + echo "#include <$hdr>" >> /tmp/ngc$$.c + done + echo "main() { }" >> /tmp/ngc$$.c + + LOGN "checking for header $hdr" + + if $AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c; then + AC_DEFINE 'HAVE_'`echo $hdr | tr 'a-z' 'A-Z' | tr './' '_'` 1 + TLOG " (found)" + rc=0 + else + TLOG " (not found)" + rc=1 + fi + rm -f /tmp/ngc$$.c /tmp/ngc$$ + return $rc +} + + +# +# emulate GNU autoconf's AC_CHECK_FUNCS function +# +AC_CHECK_FUNCS () { + AC_PROG_CC + +F=$1 +shift +rm -f /tmp/ngc$$.c + +while [ "$1" ]; do + echo "#include <$1>" >> /tmp/ngc$$.c + shift +done + + cat >> /tmp/ngc$$.c << EOF +main() +{ + $F(); +} +EOF + + LOGN "checking for the $F function" + + if $AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c $LIBS; then + AC_DEFINE `echo ${2:-HAVE_$F} | tr 'a-z' 'A-Z'` 1 + TLOG " (found)" + rc=0 + else + echo "offending command was:" + cat /tmp/ngc$$.c + echo "$AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c $LIBS" + TLOG " (not found)" + rc=1 + fi + rm -f /tmp/ngc$$.c /tmp/ngc$$ + return $rc +} + + +# +# check to see if some structure exists +# +# usage: AC_CHECK_STRUCT structure {include ...} +# +AC_CHECK_STRUCT () { + AC_PROG_CC + struct=$1 + shift + + rm -f /tmp/ngc$$.c + + for include in $*; do + echo "#include <$include>" >> /tmp/ngc$$.c + done + + cat >> /tmp/ngc$$.c << EOF +main() +{ + struct $struct foo; +} +EOF + + LOGN "checking for struct $struct" + + if $AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c $AC_LIBS 2>>config.log; then + AC_DEFINE HAVE_STRUCT_`echo ${struct} | tr 'a-z' 'A-Z'` + TLOG " (found)" + rc=0 + else + TLOG " (not found)" + rc=1 + fi + rm -f /tmp/ngc$$.c /tmp/ngc$$ + return $rc +} + + +# +# check to see if some structure contains a field +# +# usage: AC_CHECK_FIELD structure field {include ...} +# +AC_CHECK_FIELD () { + AC_PROG_CC + + struct=$1 + field=$2 + shift 2 + + rm -f /tmp/ngc$$.c + + for include in $*;do + echo "#include <$include>" >> /tmp/ngc$$.c + done + + cat >> /tmp/ngc$$.c << EOF +main() +{ + struct $struct foo; + + foo.$field; +} +EOF + + LOGN "checking that struct $struct has a $field field" + + if $AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c $AC_LIBS 2>>config.log; then + AC_DEFINE HAVE_`echo ${struct}_$field | tr 'a-z' 'A-Z'` + TLOG " (yes)" + rc=0 + else + TLOG " (no)" + rc=1 + fi + rm -f /tmp/ngc$$.c /tmp/ngc$$ + return $rc +} + + +# +# check that the C compiler works +# +AC_PROG_CC () { + test "$AC_CC" && return 0 + + cat > /tmp/ngc$$.c << \EOF +#include +main() +{ + puts("hello, sailor"); +} +EOF + + TLOGN "checking the C compiler" + + unset AC_CFLAGS AC_LDFLAGS + + if [ "$CC" ] ; then + AC_CC="$CC" + elif [ "$WITH_PATH" ]; then + AC_CC=`acLookFor cc` + elif [ "`acLookFor cc`" ]; then + # don't specify the full path if the user is looking in their $PATH + # for a C compiler. + AC_CC=cc + fi + + # finally check for POSIX c89 + test "$AC_CC" || AC_CC=`acLookFor c89` + + if [ ! "$AC_CC" ]; then + TLOG " (no C compiler found)" + $__fail 1 + fi + echo "checking out the C compiler" + + $AC_CC -c -o /tmp/ngc$$.o /tmp/ngc$$.c + $AC_CC -o /tmp/ngc$$ /tmp/ngc$$.o + status=$? + + TLOGN " ($AC_CC)" + if [ $status -eq 0 ]; then + TLOG " ok" + + # check that the CFLAGS and LDFLAGS aren't bogus + + unset AC_CFLAGS AC_LDFLAGS + + if [ "$CFLAGS" ]; then + test "$CFLAGS" && echo "validating CFLAGS=${CFLAGS}" + if $AC_CC $CFLAGS -c -o /tmp/ngc$$.o /tmp/ngc$$.c ; then + AC_CFLAGS=${CFLAGS:-"-g"} + test "$CFLAGS" && echo "CFLAGS=\"${CFLAGS}\" are okay" + elif [ "$CFLAGS" ]; then + echo "ignoring bogus CFLAGS=\"${CFLAGS}\"" + fi + else + AC_CFLAGS=-g + fi + if [ "$LDFLAGS" ]; then + echo "validating LDFLAGS=${LDFLAGS}" + if $AC_CC $LDFLAGS -o /tmp/ngc$$ /tmp/ngc$$.o; then + AC_LDFLAGS="$LDFLAGS" + TLOG "LDFLAGS=\"${AC_LDFLAGS}\" are okay" + else + TLOG "ignoring bogus LDFLAGS=\"${LDFLAGS}\"" + fi + else + AC_LDFLAGS=${CFLAGS:-"-g"} + fi + else + AC_FAIL " does not compile code properly" + fi + + AC_SUB 'CC' "$AC_CC" + + rm -f /tmp/ngc$$ /tmp/ngc$$.c /tmp/ngc$$.o + + return $status +} + + +# +# acLookFor actually looks for a program, without setting anything. +# +acLookFor () { + path=${AC_PATH:-$ac_default_path} + case "X$1" in + X-[rx]) __mode=$1 + shift + ;; + *) __mode=-x + ;; + esac + oldifs="$IFS" + for program in $*; do + IFS=":" + for x in $path; do + if [ $__mode $x/$program -a -f $x/$program ]; then + echo $x/$program + break 2 + fi + done + done + IFS="$oldifs" + unset __mode +} + + +# +# check that a program exists and set its path +# +MF_PATH_INCLUDE () { + SYM=$1; shift + + case X$1 in + X-[rx]) __mode=$1 + shift + ;; + *) unset __mode + ;; + esac + + TLOGN "looking for $1" + + DEST=`acLookFor $__mode $*` + + __sym=`echo "$SYM" | tr '[a-z]' '[A-Z]'` + if [ "$DEST" ]; then + TLOG " ($DEST)" + echo "$1 is $DEST" + AC_MAK $SYM + AC_DEFINE PATH_$__sym \""$DEST"\" + AC_SUB $__sym "$DEST" + eval CF_$SYM=$DEST + return 0 + else + #AC_SUB $__sym '' + echo "$1 is not found" + TLOG " (not found)" + return 1 + fi +} + + +# +# AC_INIT starts the ball rolling +# +# After AC_INIT, fd's 1 and 2 point to config.log +# and fd 5 points to what used to be fd 1 +# +AC_INIT () { + __config_files="config.cmd config.sub config.h config.mak config.log" + rm -f $__config_files + __cwd=`pwd` + exec 5>&1 1>$__cwd/config.log 2>&1 + AC_CONFIGURE_FOR=__AC_`echo $1 | sed -e 's/\..$//' | tr 'a-z' 'A-Z' | tr ' ' '_'`_D + + # check to see whether to use echo -n or echo ...\c + # + echo -n hello > $$ + echo world >> $$ + if grep "helloworld" $$ >/dev/null; then + ac_echo="echo -n" + echo "[echo -n] works" + else + ac_echo="echo" + echo 'hello\c' > $$ + echo 'world' >> $$ + if grep "helloworld" $$ >/dev/null; then + ac_echo_nonl='\c' + echo "[echo ...\\c] works" + fi + fi + rm -f $$ + + LOG "Configuring for [$1]" + + cat > $__cwd/config.h << EOF +/* + * configuration for $1${2:+" ($2)"}, generated `date` + * by ${LOGNAME:-`whoami`}@`hostname` + */ +#ifndef $AC_CONFIGURE_FOR +#define $AC_CONFIGURE_FOR 1 + + +EOF + + unset __share + if [ -d $AC_PREFIX/share/man ]; then + for t in 1 2 3 4 5 6 7 8 9; do + if [ -d $AC_PREFIX/share/man/man$t ]; then + __share=/share + elif [ -d $AC_PREFIX/share/man/cat$t ]; then + __share=/share + fi + done + else + __share= + fi + + if [ -d $AC_PREFIX/libexec ]; then + __libexec=libexec + else + __libexec=lib + fi + + + AC_PREFIX=${AC_PREFIX:-/usr/local} + AC_EXECDIR=${AC_EXECDIR:-$AC_PREFIX/bin} + AC_SBINDIR=${AC_SBINDIR:-$AC_PREFIX/sbin} + AC_LIBDIR=${AC_LIBDIR:-$AC_PREFIX/lib} + AC_MANDIR=${AC_MANDIR:-$AC_PREFIX$__share/man} + AC_LIBEXEC=${AC_LIBEXEC:-$AC_PREFIX/$__libexec} + AC_CONFDIR=${AC_CONFDIR:-/etc} + + AC_PATH=${WITH_PATH:-$PATH} + AC_PROG_CPP + AC_PROG_INSTALL + + if [ -z "$ac_os" ]; then + ac_os=`uname -s` + fi + _os=`echo $ac_os | tr '[a-z]' '[A-Z]'` + AC_DEFINE OS_$_os 1 + eval OS_${_os}=1 + unset _os +} + + +# +# AC_LIBRARY checks to see if a given library exists and contains the +# given function. +# usage: AC_LIBRARY function library [alternate ...] +# +AC_LIBRARY() { + SRC=$1 + shift + + # first see if the function can be found in any of the + # current libraries + AC_QUIET AC_CHECK_FUNCS $SRC && return 0 + + # then search through the list of libraries + __libs="$LIBS" + for x in $*; do + LIBS="$__libs $x" + if AC_QUIET AC_CHECK_FUNCS $SRC; then + AC_LIBS="$AC_LIBS $x" + return 0 + fi + done + return 1 +} + + +# +# AC_PROG_LEX checks to see if LEX exists, and if it's lex or flex. +# +AC_PROG_LEX() { + TLOGN "looking for lex " + + DEST=`acLookFor lex` + if [ "$DEST" ]; then + AC_MAK LEX + AC_DEFINE PATH_LEX \"$DEST\" + AC_SUB 'LEX' "$DEST" + echo "lex is $DEST" + else + DEST=`acLookFor flex` + if [ "$DEST" ]; then + AC_MAK FLEX + AC_DEFINE 'LEX' \"$DEST\" + AC_SUB 'LEX', "$DEST" + echo "lex is $DEST" + else + AC_SUB LEX '' + echo "neither lex or flex found" + TLOG " (not found)" + return 1 + fi + fi + + if AC_LIBRARY yywrap -ll -lfl; then + TLOG "($DEST)" + return 0 + fi + TLOG "(no lex library found)" + return 1 +} + + +# +# AC_PROG_YACC checks to see if YACC exists, and if it's bison or +# not. +# +AC_PROG_YACC () { + + TLOGN "looking for yacc " + + DEST=`acLookFor yacc` + if [ "$DEST" ]; then + AC_MAK YACC + AC_DEFINE PATH_YACC \"$DEST\" + AC_SUB 'YACC' "$DEST" + TLOG "($DEST)" + echo "yacc is $DEST" + else + DEST=`acLookFor bison` + if [ "$DEST" ]; then + AC_MAK BISON + AC_DEFINE 'YACC' \"$DEST\" + AC_SUB 'YACC' "$DEST -y" + echo "yacc is $DEST -y" + TLOG "($DEST -y)" + else + AC_SUB 'YACC' '' + echo "neither yacc or bison found" + TLOG " (not found)" + return 1 + fi + fi + return 0 +} + + +# +# AC_PROG_LN_S checks to see if ln exists, and, if so, if ln -s works +# +AC_PROG_LN_S () { + test "$AC_FIND_PROG" || AC_PROG_FIND + + test "$AC_FIND_PROG" || return 1 + + TLOGN "looking for \"ln -s\"" + DEST=`acLookFor ln` + + if [ "$DEST" ]; then + rm -f /tmp/b$$ + $DEST -s /tmp/a$$ /tmp/b$$ + if [ "`$AC_FIND_PROG /tmp/b$$ -type l -print`" ]; then + TLOG " ($DEST)" + echo "$DEST exists, and ln -s works" + AC_SUB 'LN_S' "$DEST -s" + rm -f /tmp/b$$ + else + AC_SUB 'LN_S' '' + TLOG " ($DEST exists, but -s does not seem to work)" + echo "$DEST exists, but ln -s doesn't seem to work" + rm -f /tmp/b$$ + return 1 + fi + else + AC_SUB 'LN_S' '' + echo "ln not found" + TLOG " (not found)" + return 1 + fi +} + + +# +# AC_PROG_FIND looks for the find program and sets the FIND environment +# variable +# +AC_PROG_FIND () { + if test -z "$AC_FIND_PROG"; then + MF_PATH_INCLUDE FIND find + rc=$? + AC_FIND_PROG=$DEST + return $rc + fi + return 0 +} + + +# +# AC_PROG_AWK looks for the awk program and sets the AWK environment +# variable +# +AC_PROG_AWK () { + if test -z "$AC_AWK_PROG"; then + MF_PATH_INCLUDE AWK awk + rc=$? + AC_AWK_PROG=$DEST + return $rc + fi + return 0 +} + + +# +# AC_PROG_SED looks for the sed program and sets the SED environment +# variable +# +AC_PROG_SED () { + if test -z "$AC_SED_PROG"; then + MF_PATH_INCLUDE SED sed + rc=$? + AC_SED_PROG=$DEST + return $rc + fi + return 0 +} + + +# +# AC_HEADER_SYS_WAIT looks for sys/wait.h +# +AC_HEADER_SYS_WAIT () { + AC_CHECK_HEADERS sys/wait.h || return 1 +} + +# +# AC_TYPE_PID_T checks to see if the pid_t type exists +# +AC_TYPE_PID_T () { + cat > /tmp/pd$$.c << EOF +#include +main() { pid_t me; } +EOF + + LOGN "checking for pid_t" + + if $AC_CC -c /tmp/pd$$.c -o /tmp/pd$$.o; then + TLOG " (found)" + rc=0 + else + echo "typedef int pid_t;" >> $__cwd/config.h + TLOG " (not found)" + rc=1 + fi + rm -f /tmp/pd$$.o /tmp/pd$$.c + return $rc +} + + +# +# AC_C_CONST checks to see if the compiler supports the const keyword +# +AC_C_CONST () { + cat > /tmp/pd$$.c << EOF +const char me=1; +EOF + LOGN "checking for \"const\" keyword" + + if $AC_CC -c /tmp/pd$$.c -o /tmp/pd$$.o; then + TLOG " (yes)" + rc=0 + else + AC_DEFINE 'const' '/**/' + TLOG " (no)" + rc=1 + fi + rm -f /tmp/pd$$.o /tmp/pd$$.c + return $rc +} + + +# +# AC_SCALAR_TYPES checks to see if the compiler can generate 2 and 4 byte ints. +# +AC_SCALAR_TYPES () { + cat > /tmp/pd$$.c << EOF +#include +main() +{ + unsigned long v_long; + unsigned int v_int; + unsigned short v_short; + + if (sizeof v_long == 4) + puts("#define DWORD unsigned long"); + else if (sizeof v_int == 4) + puts("#define DWORD unsigned int"); + else + exit(1); + + if (sizeof v_int == 2) + puts("#define WORD unsigned int"); + else if (sizeof v_short == 2) + puts("#define WORD unsigned short"); + else + exit(2); + puts("#define BYTE unsigned char"); + exit(0); +} +EOF + rc=1 + LOGN "defining WORD & DWORD scalar types" + if $AC_CC /tmp/pd$$.c -o /tmp/pd$$; then + if /tmp/pd$$ >> $__cwd/config.h; then + rc=0 + fi + fi + case "$rc" in + 0) TLOG "" ;; + *) TLOG " ** FAILED **" ;; + esac + rm -f /tmp/pd$$ /tmp/pd$$.c +} + + +# +# AC_OUTPUT generates makefiles from makefile.in's +# +AC_OUTPUT () { + cd $__cwd + AC_SUB 'LIBS' "$AC_LIBS" + AC_SUB 'CONFIGURE_FILES' "$__config_files" + AC_SUB 'GENERATED_FILES' "$*" + AC_SUB 'CFLAGS' "$AC_CFLAGS" + AC_SUB 'LDFLAGS' "$AC_LDFLAGS" + AC_SUB 'srcdir' "$AC_SRCDIR" + AC_SUB 'prefix' "$AC_PREFIX" + AC_SUB 'exedir' "$AC_EXECDIR" + AC_SUB 'sbindir' "$AC_SBINDIR" + AC_SUB 'libdir' "$AC_LIBDIR" + AC_SUB 'libexec' "$AC_LIBEXEC" + AC_SUB 'confdir' "$AC_CONFDIR" + AC_SUB 'mandir' "$AC_MANDIR" + + if [ -r config.sub ]; then + test "$AC_SED_PROG" || AC_PROG_SED + test "$AC_SED_PROG" || return 1 + + echo >> config.h + echo "#endif/* ${AC_CONFIGURE_FOR} */" >> config.h + + rm -f config.cmd + Q=\' + cat - > config.cmd << EOF +#! /bin/sh +${CC:+CC=${Q}${CC}${Q}}${CFLAGS:+ CFLAGS=${Q}${CFLAGS}${Q}}${LDFLAGS:+ LDFLAGS=${Q}${LDFLAGS}${Q}} $ac_progname $ac_configure_command +EOF + chmod +x config.cmd + + __d=$AC_SRCDIR + for makefile in $*;do + if test -r $__d/${makefile}.in; then + LOG "generating $makefile" + ./config.md `__ac_dirname ./$makefile` 2>/dev/null + $AC_SED_PROG -f config.sub < $__d/${makefile}.in > $makefile + __config_files="$__config_files $makefile" + else + LOG "WARNING: ${makefile}.in does not exist!" + fi + done + unset __d + + else + echo + fi +} + +# +# AC_CHECK_FLOCK checks to see if flock() exists and if the LOCK_NB argument +# works properly. +# +AC_CHECK_FLOCK() { + + AC_CHECK_HEADERS sys/types.h sys/file.h fcntl.h + + cat << EOF > $$.c +#include +#include +#include +#include + +main() +{ + int x = open("$$.c", O_RDWR, 0666); + int y = open("$$.c", O_RDWR, 0666); + + if (flock(x, LOCK_EX) != 0) + exit(1); + if (flock(y, LOCK_EX|LOCK_NB) == 0) + exit(1); + exit(0); +} +EOF + + LOGN "checking for flock()" + HAS_FLOCK=0 + if $AC_CC -o flock $$.c ; then + if ./flock ; then + LOG " (found)" + HAS_FLOCK=1 + AC_DEFINE HAS_FLOCK + else + LOG " (bad)" + fi + else + LOG " (no)" + fi + + rm -f flock $$.c + + case "$HAS_FLOCK" in + 0) return 1 ;; + *) return 0 ;; + esac +} + + +# +# AC_PROG_INSTALL finds the install program and guesses whether it's a +# Berkeley or GNU install program +# +AC_PROG_INSTALL () { + + DEST=`acLookFor install` + + LOGN "checking for install" + unset IS_BSD + if [ "$DEST" ]; then + # BSD install or GNU install? Let's find out... + touch /tmp/a$$ + + $DEST /tmp/a$$ /tmp/b$$ + + if test -r /tmp/a$$; then + LOG " ($DEST)" + else + IS_BSD=1 + LOG " ($DEST) bsd install" + fi + rm -f /tmp/a$$ /tmp/b$$ + else + DEST=`acLookFor ginstall` + if [ "$DEST" ]; then + LOG " ($DEST)" + else + DEST="false" + LOG " (not found)" + fi + fi + + if [ "$IS_BSD" ]; then + PROG_INSTALL="$DEST -c" + else + PROG_INSTALL="$DEST" + fi + + AC_SUB 'INSTALL' "$PROG_INSTALL" + AC_SUB 'INSTALL_PROGRAM' "$PROG_INSTALL -s -m 755" + AC_SUB 'INSTALL_DATA' "$PROG_INSTALL -m 444" + + # finally build a little directory installer + # if mkdir -p works, use that, otherwise use install -d, + # otherwise build a script to do it by hand. + # in every case, test to see if the directory exists before + # making it. + + if mkdir -p $$a/b; then + # I like this method best. + __mkdir="mkdir -p" + rmdir $$a/b + rmdir $$a + elif $PROG_INSTALL -d $$a/b; then + __mkdir="$PROG_INSTALL -d" + rmdir $$a/b + rmdir $$a + fi + + __config_files="$__config_files config.md" + AC_SUB 'INSTALL_DIR' "$__cwd/config.md" + echo "#! /bin/sh" > $__cwd/config.md + echo "# script generated" `date` "by configure.sh" >> $__cwd/config.md + echo >> $__cwd/config.md + if [ "$__mkdir" ]; then + echo "test -d \"\$1\" || $__mkdir \"\$1\"" >> $__cwd/config.md + echo "exit $?" >> $__cwd/config.md + else + cat - >> $__cwd/config.md << \EOD +pieces=`IFS=/; for x in $1; do echo $x; done` +dir= +for x in $pieces; do + dir="$dir$x" + mkdir $dir || exit 1 + dir="$dir/" +done +exit 0 +EOD + fi + chmod +x $__cwd/config.md +} + +# +# acCheckCPP is a local that runs a C preprocessor with a given set of +# compiler options +# +acCheckCPP () { + cat > /tmp/ngc$$.c << EOF +#define FOO BAR + +FOO +EOF + + if $1 $2 /tmp/ngc$$.c > /tmp/ngc$$.o; then + if grep -v '#define' /tmp/ngc$$.o | grep -s BAR >/dev/null; then + echo "CPP=[$1], CPPFLAGS=[$2]" + AC_SUB 'CPP' "$1" + AC_SUB 'CPPFLAGS' "$2" + rm /tmp/ngc$$.c /tmp/ngc$$.o + return 0 + fi + fi + rm /tmp/ngc$$.c /tmp/ngc$$.o + return 1 +} + + +# +# AC_PROG_CPP checks for cpp, then checks to see which CPPFLAGS are needed +# to run it as a filter. +# +AC_PROG_CPP () { + if [ "$AC_CPP_PROG" ]; then + DEST=$AC_CPP_PROG + else + __ac_path="$AC_PATH" + AC_PATH="/lib:/usr/lib:${__ac_path:-$ac_default_path}" + DEST=`acLookFor cpp` + AC_PATH="$__ac_path" + fi + + unset fail + LOGN "Looking for cpp" + if [ "$DEST" ]; then + TLOGN " ($DEST)" + acCheckCPP $DEST "$CPPFLAGS" || \ + acCheckCPP $DEST -traditional-cpp -E || \ + acCheckCPP $DEST -E || \ + acCheckCPP $DEST -traditional-cpp -pipe || \ + acCheckCPP $DEST -pipe || fail=1 + + if [ "$fail" ]; then + AC_FAIL " (can't run cpp as a pipeline)" + else + TLOG " ok" + return 0 + fi + fi + AC_FAIL " (not found)" +} + +# +# AC_FAIL spits out an error message, then __fail's +AC_FAIL() { + LOG "$*" + $__fail 1 +} + +# +# AC_SUB writes a substitution into config.sub +AC_SUB() { + ( _subst=`echo $2 | sed -e 's/;/\\;/g'` + echo "s;@$1@;$_subst;g" ) >> $__cwd/config.sub +} + +# +# AC_MAK writes a define into config.mak +AC_MAK() { + echo "HAVE_$1 = 1" >> $__cwd/config.mak +} + +# +# AC_DEFINE adds a #define to config.h +AC_DEFINE() { + echo "#define $1 ${2:-1}" >> $__cwd/config.h +} + +# +# AC_CONFIG adds a configuration setting to all the config files +AC_CONFIG() { + AC_DEFINE "PATH_$1" \""$2"\" + AC_MAK "$1" + AC_SUB "$1" "$2" +} + +# +# AC_QUIET does something quietly +AC_QUIET() { + eval $* 5>/dev/null +} diff --git a/src/cmd/levee/configure.sh b/src/cmd/levee/configure.sh new file mode 100755 index 0000000..9467d29 --- /dev/null +++ b/src/cmd/levee/configure.sh @@ -0,0 +1,112 @@ +#! /bin/sh + +# local options: ac_help is the help message that describes them +# and LOCAL_AC_OPTIONS is the script that interprets them. LOCAL_AC_OPTIONS +# is a script that's processed with eval, so you need to be very careful to +# make certain that what you quote is what you want to quote. + +ac_help=" +--use-termcap Link with termcap instead of curses, if possible +--partial-install Don\'t install the lv, lv(1) name links +--size=NNN Use a NNN-byte edit buffer +--dos compile for ms-dos or microsoft windows +--tos compile for the Atari ST +--rmx compile for RMX +--flexos compile for FlexOS" + +LOCAL_AC_OPTIONS=' +case Z$1 in +Z--partial-install) + missing_lv=1;; +Z--dos) ac_os=DOS;; +Z--tos) ac_os=ATARI=1;; +Z--flexos) ac_os=FLEXOS=1;; +Z--rmx) ac_os=RMX;; +Z--size=*) SIZE=$(echo Z$1 | sed -e 's/^Z--size=//') ;; +*) ac_error=1;; +esac;shift' + +# load in the configuration file +# +TARGET=levee +. ./configure.inc +AC_INIT $TARGET + +# validate --size= +# +case X"${SIZE}" in +X[0-9][0-9]*) ;; +X[0-9][0-9]*[Ll]);; +X) ;; +X*) AC_FAIL "--size=$SIZE is not a valid number" ;; +esac + +AC_PROG_CC + +if [ "$OS_DOS" ]; then + AC_DEFINE SIZE ${SIZE:-32000} + AC_DEFINE PROC _fastcall + AC_DEFINE TTY_ANSI 1 + AC_CHECK_FUNCS basename +elif [ "$OS_ATARI" ]; then + AC_DEFINE SIZE ${SIZE:-32000} + AC_DEFINE TTY_VT52 1 + AC_DEFINE HAVE_BLKFILL 1 + AC_CHECK_FUNCS basename +elif [ "$OS_FLEXOS" ]; then + AC_DEFINE SIZE ${SIZE:-256000} + AC_CHECK_FUNCS basename +else + AC_DEFINE SIZE ${SIZE:-256000} + AC_DEFINE OS_UNIX 1 + + if AC_CHECK_HEADERS string.h; then + # Assume a mainly ANSI-compliant world, where the + # existance of string.h implies a memset() and strchr() + AC_DEFINE HAVE_MEMSET 1 + AC_DEFINE HAVE_STRCHR 1 + else + AC_CHECK_FUNCS memset + AC_CHECK_FUNCS strchr + fi + + # for basename + if AC_CHECK_FUNCS basename; then + AC_CHECK_HEADERS libgen.h + fi + + if AC_CHECK_HEADERS signal.h; then + # Assume a mainly sane world where the existance + # of signal.h means that signal() exists + AC_DEFINE HAVE_SIGNAL 1 + fi + + if [ "$USE_TERMCAP" ]; then + LIBORDER="-ltermcap -lcurses -lncurses" + else + LIBORDER="-lcurses -lncurses -ltermcap" + fi + + if AC_LIBRARY tgetent $LIBORDER; then + AC_CHECK_HEADERS termcap.h || AC_FAIL "levee needs " + AC_DEFINE USE_TERMCAP 1 + # our -libtermcap might be (n)curses in disguise. If so, + # it might have a colliding mvcur() that we need to define + # ourselves out from. + AC_QUIET AC_CHECK_FUNCS mvcur && AC_DEFINE mvcur __mvcur + else + # have to use a local termcap + AC_DEFINE TERMCAP_EMULATION 1 + AC_DEFINE USE_TERMCAP 1 + fi + + AC_CHECK_HEADERS termios.h && AC_CHECK_FUNCS tcgetattr +fi + +if AC_PROG_LN_S && test -z "$missing_lv"; then + AC_SUB NOMK '' +else + AC_SUB NOMK '@#' +fi + +AC_OUTPUT Makefile diff --git a/src/cmd/levee/display.c b/src/cmd/levee/display.c new file mode 100644 index 0000000..eae948a --- /dev/null +++ b/src/cmd/levee/display.c @@ -0,0 +1,349 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" + +/* do a gotoXY -- allowing -1 for same row/column */ + +#if USE_TERMCAP | OS_ATARI + +#define MAXCOLS 160 + +#if USE_TERMCAP +#include "termcap.i" +#endif + +#else /*!(USE_TERMCAP | OS_ATARI)*/ + +#define MAXCOLS COLS + +#endif + +VOID PROC +mvcur(y,x) +int y,x; +{ +#if TERMCAP_EMULATION || TTY_ANSI + static char gt[30]; +#endif + + if (y == -1) + y = curpos.y; + else + curpos.y = y; + if (y >= LINES) + y = LINES-1; + if (x == -1) + x = curpos.x; + else + curpos.x = x; + if (x >= COLS) + x = COLS-1; + +#if TERMCAP_EMULATION + tgoto(gt,y,x); + strput(gt); +#elif USE_TERMCAP + strput( tgoto(CM, x, y) ); +#elif TTY_ZTERM + zgoto(x,y); +#elif TTY_ANSI + { register char *p = gt; /* make a ansi gotoXY string */ + *p++ = 033; + *p++ = '['; + numtoa(p,1+y); p += strlen(p); + *p++ = ';'; + numtoa(p,1+x); p += strlen(p); + *p++ = 'H'; + WRITE_TEXT(1, gt, (p-gt)); + } +#elif TTY_VT52 + CM[2] = y+32; + CM[3] = x+32; + strput(CM); +#endif +} + +VOID PROC +numtoa(str,num) +char *str; +int num; +{ + int i = 10; /* I sure hope that str is 10 bytes long... */ + bool neg = (num < 0); + + if (neg) + num = -num; + + str[--i] = 0; + do{ + str[--i] = (num%10)+'0'; + num /= 10; + }while (num > 0); + if (neg) + str[--i] = '-'; + moveleft(&str[i], str, 10-i); +} + +VOID PROC +printi(num) +int num; +{ + char nb[10]; + register int size; + + numtoa(nb,num); + size = min(strlen(nb),COLS-curpos.x); + if (size > 0) { + nb[size] = 0; + zwrite(nb, size); + curpos.x += size; + } +} + +VOID PROC +println() +{ + zwrite("\r\n", 2); + curpos.x = 0; + curpos.y = min(curpos.y+1, LINES-1); +} + +/* print a character out in a readable form -- + * ^ for control- + * spaces for + * normal for everything else + */ + +static char hexdig[] = "0123456789ABCDEF"; + +int PROC +format(out,c) +/* format: put a displayable version of c into out */ +register char *out; +register unsigned c; +{ + if (c >= ' ' && c < '') { + out[0] = c; + return 1; + } + else if (c == '\t' && !list) { + register int i; + int size; + + for (i = size = tabsize - (curpos.x % tabsize);i > 0;) + out[--i] = ' '; + return size; + } + else if (c < 128) { + out[0] = '^'; + out[1] = c^64; + return 2; + } + else { +#if OS_DOS + out[0] = c; + return 1; +#else + out[0] = '\\'; + out[1] = hexdig[(c>>4)&017]; + out[2] = hexdig[c&017]; + return 3; +#endif + } +} + +VOID PROC +printch(c) +char c; +{ + register int size; + char buf[MAXCOLS]; + + size = min(format(buf,c),COLS-curpos.x); + if (size > 0) { + buf[size] = 0; + zwrite(buf, size); + curpos.x += size; + } +} + +VOID PROC +prints(s) +char *s; +{ + int size,oxp = curpos.x; + char buf[MAXCOLS+1]; + register int bi = 0; + + while (*s && curpos.x < COLS) { + size = format(&buf[bi],*s++); + bi += size; + curpos.x += size; + } + size = min(bi,COLS-oxp); + if (size > 0) { + buf[size] = 0; + zwrite(buf, size); + } +} + +VOID PROC +writeline(y,x,start) +int y,x,start; +{ + int endd,oxp; + register int size; + char buf[MAXCOLS+1]; + register int bi = 0; + + endd = fseekeol(start); + if (start==0 || core[start-1] == EOL) + mvcur(y, 0); + else + mvcur(y, x); + oxp = curpos.x; + + while (start < endd && curpos.x < COLS) { + size = format(&buf[bi],core[start++]); + bi += size; + curpos.x += size; + } + if (list) { + buf[bi++] = '$'; + curpos.x++; + } + size = min(bi,COLS-oxp); + if (size > 0) { + buf[size] = 0; + zwrite(buf, size); + } + if (curpos.x < COLS) + strput(CE); +} + +/* redraw && refresh the screen */ + +VOID PROC +refresh(y,x,start,endd,rest) +int y,x,start,endd; +bool rest; +{ + int sp; + +#if OS_ATARI + /* turn the cursor off */ + asm(" clr.l -(sp) "); + asm(" move.w #21,-(sp) "); + asm(" trap #14 "); + asm(" addq.l #6,sp "); +#endif + sp = start; + while (sp <= endd) { + writeline(y, x, sp); + sp = 1+fseekeol(sp); + y++; + x = 0; + } + if (rest && sp >= bufmax) + while (y curr); + setend(); +} + +VOID PROC +scrollforward(curr) +int curr; +{ + do { + writeline(LINES-1, 0, pend+1); + zwrite("\n", 1); + pend = fseekeol(pend+1); + ptop = fseekeol(ptop)+1; + } while (pend < curr); +} + +/* find if the number of lines between top && bottom is less than dofscroll */ + +bool PROC +ok_to_scroll(top,bottom) +int top,bottom; +{ + int nl, i; + + nl = dofscroll; + i = top; + do + i += 1+scan(bufmax-i,'=',EOL, &core[i]); + while (--nl > 0 && i < bottom); + return(nl>0); +} + +VOID PROC +clrprompt() +{ + mvcur(LINES-1,0); + strput(CE); +} + +VOID PROC +prompt(toot,s) +bool toot; +char *s; +{ + if (toot) + error(); + clrprompt(); + prints(s); +} diff --git a/src/cmd/levee/dos.asm b/src/cmd/levee/dos.asm new file mode 100644 index 0000000..6a64ecf --- /dev/null +++ b/src/cmd/levee/dos.asm @@ -0,0 +1,50 @@ + name dos + page 55,80 + title 'DOS.ASM -- assembly routines for the teeny-shell under DOS' + +_TEXT segment byte public 'CODE' + + assume cs:_TEXT + +public _fail_criterr +; +; If we get a critical error, just fail it - dos 3.0 and up only, please! +; +_fail_criterr proc far + mov al, 3 + iret +_fail_criterr endp + +public _ignore_ctrlc +; +; If the user presses ^C, don't do any special handling of it. +; +_ignore_ctrlc proc far + iret +_ignore_ctrlc endp +_pexec endp + +public _intr_on_ctrlc +; +; If the user presses ^C, terminate the current process. +; +_intr_on_ctrlc proc far + mov ah, 4ch + mov al, 0ffh + int 21h +_intr_on_ctrlc endp + +public _crawcin +; +; get a character from standard input without any sort of magical +; processing. +; +_crawcin proc far + mov ah, 07h + int 21h + ret +_crawcin endp + +_TEXT ends + + end diff --git a/src/cmd/levee/doscall.c b/src/cmd/levee/doscall.c new file mode 100644 index 0000000..08f70a2 --- /dev/null +++ b/src/cmd/levee/doscall.c @@ -0,0 +1,200 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +/* + * dos interface for levee (Microsoft C) + */ +#include "levee.h" + +#if OS_DOS +#include +#include + +int PROC +min(a,b) +int a,b; +{ + return (a>b) ? b : a; +} + +int PROC +max(a,b) +int a,b; +{ + return (a s; --p) + if (p[-1] == '/' || p[-1] == '\\' || p[-1] == ':') + return p; + return s; +} /* basename */ + + +/* + * glob() expands a wildcard, via calls to _dos_findfirst/_next() + * and pathname retention. + */ +char * +glob(path, dta) +char *path; +struct glob_t *dta; +{ + static char path_bfr[256]; /* full pathname to return */ + static char *file_part; /* points at file - for filling */ + static char isdotpattern; /* looking for files starting with . */ + static char isdotordotdot; /* special case . or .. */ + static struct glob_t *dta_bfr; /* pointer to desired dta */ + static struct find_t dird; /* DOS dta */ + + register st; /* status from _dos_findxxx */ + + if (path) { + /* when we start searching, save the path part of the filename in + * a safe place. + */ + strcpy(path_bfr, path); + file_part = basename(path_bfr); + + /* set up initial parameters for DosFindFirst() + */ + dta_bfr = dta; + + if (isdotpattern = (*file_part == '.')) + /* _dos_findfirst() magically expands . and .. into their + * directory names. Admittedly, there are cases where + * this can be useful, but this is not one of them. So, + * if we find that we're matching . and .., we just + * special-case ourselves into oblivion to get around + * this particular bit of DOS silliness. + */ + isdotordotdot = (file_part[1] == 0 || file_part[1] == '.'); + else + isdotordotdot = 0; + + st = _dos_findfirst(path, 0x16, &dird); + } + else + st = _dos_findnext(&dird); + + while (st == 0) { + /* Unless the pattern has a leading ., don't include any file + * that starts with . + */ + if (dird.name[0] == '.' && !isdotpattern) + st = _dos_findnext(&dird); + else { + /* found a file - affix the path leading to it, then return + * a pointer to the (static) buffer holding the path+the name. + */ + strlwr(dird.name); /* DOS & OS/2 are case-insensitive */ + + if (dta_bfr) { + dta_bfr->wr_time = dird.wr_time; + dta_bfr->wr_date = dird.wr_date; + if (isdotordotdot) + strcpy(dta_bfr->name, file_part); + else { + strncpy(dta_bfr->name, dird.name, sizeof(dta_bfr->name)-1); + dta_bfr->name[sizeof(dta_bfr->name)-1] = 0; + } + dta_bfr->size = dird.size; + dta_bfr->attrib = dird.attrib; + } + if (!isdotordotdot) + strcpy(file_part, dird.name); + return path_bfr; + } + } + /* nothing matched + */ + if (path && isdotordotdot) { + /* must be at root, so statting dot will most likely fail. Fake a + * dta. + */ + if (dta_bfr) { + memset(dta_bfr, 0, sizeof *dta_bfr); + dta_bfr->attrib = 0x10; + dta_bfr->name[0] = '.'; + } + return path_bfr; + } + return (char*)0; +} /* glob */ +#endif /*OS_DOS*/ diff --git a/src/cmd/levee/editcor.c b/src/cmd/levee/editcor.c new file mode 100644 index 0000000..35aa626 --- /dev/null +++ b/src/cmd/levee/editcor.c @@ -0,0 +1,644 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2008 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" +#include + +/* do some undoable modification */ + +/* These variables make docommand nonrecursive */ + +bool ok; +int newend, /* end position after change */ + disp, /* start redisplay here */ + newc, /* new cursor position for wierd cmds */ + endY; /* final yp for endp */ + +/* move a line of text right || left */ + +VOID PROC +adjuster(sleft, endd, sw) +bool sleft; +int endd, sw; +{ + bool noerror; + int np, ts, + ip, + ss, adjp, + DLEnum; + + if (sw == -1) + sw = shiftwidth; + if (sleft) + sw = -sw; + curr = bseekeol(curr); + ip = curr; + noerror = TRUE; + do { + DLEnum = sw + findDLE(ip, &np, bufmax,0); + if (DLEnum >= 0 && DLEnum <= COLS && core[np] != EOL && np < bufmax) { + ts = DLEnum / tabsize; + ss = DLEnum % tabsize; + adjp = ts+ss+ip; + if (np-adjp < 0) { /* expand the buf */ + moveright(&core[np], &core[adjp], bufmax-np); + insert_to_undo(&undo, adjp, adjp - np); + } + else + delete_to_undo(&undo, adjp, np - adjp); + + endd += (adjp-np); + noerror = move_to_undo(&undo, ip, ts+ss); + fillchar(&core[ip], ts, TAB); + fillchar(&core[ip+ts], ss, 32); + } + else if (np > ip) { /* remove the indent code */ + noerror = delete_to_undo(&undo, ip, np-ip); + endd += (ip - np); + } + ip = 1 + fseekeol(ip); + } while (noerror && ip < endd); + if (!noerror) + error(); + newc = skipws(curr); + disp = curr; + newend = endd; + endY = setY(min(newend, pend)); +} + +/* join lines together */ + +VOID PROC +join(count) +int count; +{ + bool ok; + int lp, first; + + if (lend < bufmax) { /* are we in the buffer? */ + disp = lend; /* start redraw here */ + newc = lend; + do { /* join until.. */ + first = lend; + lp = skipws(1+first); + ok = delete_to_undo(&undo, 1+first, lp-(1+first)); + if (ok) { + ok = move_to_undo(&undo, first, 1); + core[first] = ' '; /* spaces between lines */ + } + count--; + lend = fseekeol(first); + } while (ok && count > 0); + endY = MAGICNUMBER; + newend = lend; + if (!ok) + error(); + } + else + error(); +} + +VOID PROC +squiggle(endp, c, dorepl) +int endp; +char c; +bool dorepl; +{ + int i; + + if (endp >= curr) { + ok = move_to_undo(&undo,curr,endp-curr+1); + if (ok) { + for (i = curr;i<=endp;i++) { + if (!dorepl) { /* squiggle it to uc - lc */ + if (core[i] >='A' && core[i] <='Z') + core[i] += 32; + else if (core[i]>='a' && core[i]<='z') + core[i] -= 32; + } + else + core[i] = c; + } + newend = min(endp+1,lend); + } + } +} + +VOID PROC +bigreplace() +{ + int len, tsiz; + + tsiz = lend-curr; + if (move_to_undo(&undo, curr, tsiz)) + if (SIZE - bufmax > tsiz) { /* enough room for temp copy? */ + moveleft(&core[curr], &core[bufmax],lend-curr); + if (line(core, curr, lend, &len) != ESC) + error(); + newend = curr+len; + moveright(&core[bufmax+len], &core[newend], lend-newend); + } +} + +bool PROC +put(before) +bool before; +{ + endY = setY(curr); + if (!before) + if (yank.lines) + curr = min(lend+1,bufmax); + else + curr = min(curr+1, lend); + else if (yank.lines) + curr = lstart; + newc = disp = curr; + return(putback(curr, &newend)); +} + +bool PROC +execute(start, end) +{ + int tf; + FILE *f; + char scratch[20]; + bool ret = FALSE; + int size; + + strcpy(scratch, "/tmp/lv.XXXXXX"); + + clrprompt(); + printch('!'); + if ( !getline(instring) ) + return FALSE; + + if ( (tf = mkstemp(scratch)) < 0 ) { + prints("[tempfile error]"); + return FALSE; + } + + strcat(instring, " 2>&1 <"); + strcat(instring, scratch); + + if ( (size = write(tf, core+start, end-start)) == (end-start) ) { + if ( (f=popen(instring, "r")) ) { + if ( deletion(start, end) && (insertfile(f, 1, start, &size) > 0) ) + ret = TRUE; + pclose(f); + } + else + error(); + } + + close(tf); + unlink(scratch); + + return ret; +} + +VOID PROC +gcount() +{ + do { + count = (count*10) + (ch-'0'); + readchar(); /* get a char to replace the one we dumped */ + } while ( count >= 0 && isdigit(ch) ); +} + +VOID PROC +docommand(cmd) +cmdtype cmd; +{ + cmdtype movecmd; /* movement command for y, d, c */ + char cmdch; + int oldc; /* old count */ + int endp; /* end position before change */ + extern bool s_wrapped; + + resetX(); /* un-derange the cursor */ + oldc = newc = -1; + endY = yp; + newend = disp = curr; + ok = TRUE; /* so far everything is working */ + cmdch = ch; + if (cmd != UNDO_C && cmd != YANK_C) { + if (macro<0) + zerostack(&undo); + if (redoing != TRUE) { + rcp = rcb; /* point at start of redo buffer */ + if (count > 1) { /* put in a count? */ + numtoa(rcb,count); + rcp += strlen(rcb); + } + *rcp++ = cmdch; /* the command char goes in... */ + xerox = TRUE; /* hoist the magical flags */ + } + } + + if (cmd <= YANK_C) { + readchar(); + if ( isdigit(ch) && ch != '0' ) { + oldc = count; + count = 0; + gcount(); /* get a new count */ + if (cmd == ADJUST_C) /* special for >>,<< wierdness */ + swap(&count, &oldc); /* reverse sw & count */ + else + count = count*max(oldc,1); /* combine them */ + } + if (ch == cmdch) { /* diddle lines */ + yank.lines = TRUE; + endp = nextline(TRUE, curr, count); + curr = bseekeol(curr); + disp = curr; + } + else { /* diddle 'things' */ + yank.lines = FALSE; + movecmd = movemap[(unsigned int)ch]; + + if ( (ok = (findCP(curr,&endp,movecmd) == LEGALMOVE)) ) { + if (curr > endp) { + swap(&curr,&endp); + ok = (cmd != CHANGE_C); + } + if (adjcurr[(unsigned int)movecmd]) + curr++; + if (adjendp[(unsigned int)movecmd]) + endp++; + } + if (!ok) { + if (ch != ESC) + error(); + goto killredo; + } + } + + endY = setY(endp); + newend = curr; + disp = curr; + switch (cmd) { + case EXEC_C: + ok = execute(curr, endp); + break; + case DELETE_C: + ok = deletion(curr, endp); + break; + case ADJUST_C: + adjuster((cmdch == '<'), endp-1, oldc); + break; + case CHANGE_C: + if (endp <= pend+1) { + mvcur(setY(endp-1), setX(endp-1)); + printch('$'); + mvcur(yp, xp); + } + if (deletion(curr, endp)) + ok = ((newend = insertion(1, 0, &disp, &endY, TRUE)) >= 0); + else + ok = FALSE; + break; + case YANK_C: + if (!doyank(curr, endp)) + error(); + return; /* xerox will not be true, nor will redoing */ + } + + } + else { + endp = curr; + endY = yp; + + switch (cmd) { + case I_AT_NONWHITE: + case A_AT_END: + case APPEND_C: + case INSERT_C: /* variations on insert */ + if (cmd != INSERT_C) { + if (cmd == APPEND_C) + curr = min(curr+1, lend); + else if (cmd == A_AT_END) + curr = lend; + else /* if (cmd == I_AT_NONWHITE) */ + curr = skipws(lstart); + xp = setX(curr); + mvcur(yp,xp); + } + newend = insertion(count, 0, &disp, &endY, TRUE); + ok = (newend >= 0); + break; + case OPEN_C: + case OPENUP_C: + newend = insertion(1,setstep[ (cmd==OPENUP_C)&1 ], + &disp,&endY,TRUE)-1; + ok = (newend >= 0); + break; + case REPLACE_C: + case TWIDDLE_C: + if (cmd == REPLACE_C) { + if ((cmdch = readchar()) == ESC) + goto killredo; + } + if (findCP(curr, &endp, GO_RIGHT) == LEGALMOVE) + squiggle(endp-1, cmdch, (cmd==REPLACE_C)); + break; + case PUT_BEFORE: + case PUT_AFTER: + ok = put(cmd==PUT_AFTER); + break; + case BIG_REPL_C: + bigreplace(); + break; + case RESUBST_C: + ok = FALSE; + if (dst[0] != 0) { + newend = chop(curr, &lend, TRUE, &ok); + if (newend >= 0) { + endY = setY(newend+strlen(dst)); + ok = TRUE; + } + } + break; + case JOIN_C: + join(count); /* join lines */ + break; + case UNDO_C: /* undo last modification */ + ok = fixcore(&newend) >= 0; + disp = newend; + endY = MAGICNUMBER; + break; + } + } + + if (ok) { + setpos((newc<0)?newend:newc); + setend(); + if (curr < ptop || curr > pend) { + yp = settop(12); + redisplay(TRUE); + } + else { + yp = setY(curr); + if (endY != setY(newend)) /* shuffled lines */ + refresh(setY(disp), setX(disp), disp, pend, TRUE); + else /* refresh to end position */ + refresh(setY(disp), setX(disp), disp, newend, FALSE); + } + if (curr >= bufmax && bufmax > 0) { /* adjust off end of buffer */ + setpos(bufmax-1); + yp = setY(curr); + } + if (s_wrapped) { + prompt(FALSE, "search wrapped around end of buffer"); + s_wrapped = 0; + } + else + clrprompt(); + modified = TRUE; + } + else { + error(); +killredo: + rcb[0] = 0; + } + mvcur(yp, xp); + if (xerox) + *rcp = 0; /* terminate the redo */ + redoing = FALSE; + xerox = FALSE; + core[bufmax] = EOL; +} + +/* Initialize && execute a macro */ + +VOID PROC +exmacro() +{ + int mp; + + mp = lookup(ch); + if (mp > 0) { + if (macro<0) + zerostack(&undo); + insertmacro(mbuffer[mp].m_text, count); + } + else + error(); +} + +/* redraw the screen w.r.t. the cursor */ + +VOID PROC +zdraw(code) +unsigned char code; +{ + int nl = ERR, + np = (count>0)?to_index(count):curr; + + if (movemap[code] == CR_FWD) + nl = 0; + else if (movemap[code] == CR_BACK) + nl = LINES-1; + else if (code == '.') + nl = LINES / 2; + if (nl >= 0) { + curr = np; + yp = settop(nl); + redisplay(TRUE); + mvcur(yp,xp); + } + else + error(); +} + +/* start up a built-in macro */ + +VOID PROC +macrocommand() +{ + if (count > 1) + numtoa(gcb,count); + else + gcb[0] = 0; + switch (ch) { /* which macro? */ + case 'x': /* x out characters */ + strcat(gcb,"dl"); break; + case 'X': /* ... backwards */ + strcat(gcb,"dh"); break; + case 's': /* substitute over chars */ + strcat(gcb,"cl"); break; + case 'D': /* delete to end of line */ + strcat(gcb,"d$"); break; + case 'C': /* change ... */ + strcat(gcb,"c$"); break; + case 'Y': /* yank ... */ + strcat(gcb,"y$"); break; + case '': /* scroll up one page */ + strcpy(gcb,"22"); break; + case '': /* ... down one page */ + strcpy(gcb,"22"); break; + case '': /* scroll up one line */ + strcpy(gcb,"1"); break; + case '': /* ... down one line */ + strcpy(gcb,"1"); break; + default: + error(); + return; + break; + } + if (macro<0) + zerostack(&undo); + insertmacro(gcb, 1); +} + +/* scroll the window up || down */ + +VOID PROC +scroll(down) +bool down; +{ + int i; + + if (count <= 0) + count = dofscroll; + strput(CURoff); + if (down) { + curr = min(bufmax-1, nextline(TRUE, curr, count)); + i = min(bufmax-1, nextline(TRUE, pend, count)); + if (i > pend) + scrollforward(i); + } + else { + curr = bseekeol(max(0,nextline(FALSE, curr, count))); + i = bseekeol(max(0,nextline(FALSE, ptop, count))); + if (i < ptop) { + if (canUPSCROLL) + scrollback(i); + else { + ptop = i; + setend(); + redisplay(TRUE); + } + } + } + strput(CURon); + setpos(skipws(curr)); /* initialize new position - first nonwhite */ + yp = setY(curr); + mvcur(yp, xp); /* go there */ +} + +exec_type PROC +editcore() +{ + cmdtype cmd; + extern bool s_wrapped; + + /* rcb[0] = 0; rcp = rcb; */ + + if (diddled) { + setpos(skipws(curr)); /* set cursor x position.. */ + yp = settop(LINES / 2); /* Y position */ + } + if (diddled || zotscreen) /* redisplay? */ + redisplay(FALSE); + mvcur(yp, xp); /* and move the cursor */ + + for (;;) { + s_wrapped = 0; + ch = readchar(); /* get a char */ + count = 0; + if (isdigit(ch) && ch != '0') + gcount(); /* ... a possible count */ + switch (cmd = movemap[(unsigned int)ch]) { + case FILE_C: + wr_stat(); /* write file stats */ + mvcur(yp, xp); + break; + + case WINDOW_UP: + case WINDOW_DOWN: + scroll(cmd==WINDOW_UP); /* scroll the window */ + break; + + case REDRAW_C: /* redraw the window */ + redisplay(TRUE); + mvcur(yp, xp); + break; + + case MARKER_C: /* set a marker */ + ch = tolower(readchar()); + if (ch >= 'a' && ch <= 'z') + contexts[ch-'`'] = curr; + else if (ch != ESC) + error(); + break; + + case REDO_C: + if (rcb[0] != 0) { + zerostack(&undo); + insertmacro(rcb, 1); + redoing = TRUE; + } + break; + + case REWINDOW: + zdraw(readchar()); /* shift the window */ + break; + + case DEBUG_C: /* debugging stuff -- unused */ + break; + + case ZZ_C: /* shortcut for :xit */ + ch = readchar(); + if (ch == 'Z') + insertmacro(":x\r", 1); + else if (ch != ESC) + error(); + break; + + case EDIT_C: /* drop into line mode */ + return E_EDIT; + + case COLIN_C: /* do one exec mode command */ + return E_VISUAL; + + case HARDMACRO: + macrocommand(); /* 'hard-wired' macros */ + break; + + case SOFTMACRO: + exmacro(); /* run a macro */ + break; + + case INSMACRO: /* macro for insert mode */ + case BAD_COMMAND: + error(); + break; + + default: + if (cmd < DELETE_C) + movearound(cmd); + else /*if (cmd < HARDMACRO)*/ + docommand(cmd); + break; + } + lastexec = 0; + } + /* never exits here */ +} diff --git a/src/cmd/levee/exec.c b/src/cmd/levee/exec.c new file mode 100644 index 0000000..71bd718 --- /dev/null +++ b/src/cmd/levee/exec.c @@ -0,0 +1,1114 @@ +#include "levee.h" +#include "extern.h" +#include +#include + +VOID PROC undefine(); +VOID PROC fixupline(); +VOID PROC doinput(); + +/* + * do a newline and set flags. + */ +#define exprintln() (zotscreen=YES),println() + +VOID PROC +plural(num,string) +int num; +char *string; +{ + printi(num); + prints(string); + if (num != 1) + printch('s'); +} /* plural */ + + +VOID PROC +clrmsg() +{ + mvcur(-1,0); + strput(CE); +} /* clrmsg */ + + +VOID PROC +errmsg(msg) +char *msg; +{ + mvcur(-1,0); + prints(msg); + strput(CE); +} /* errmsg */ + + +/* get a space-delimited token */ +char *execstr; /* if someone calls getarg in the */ + /* wrong place, death will come... */ +char *PROC +getarg() +{ + char *rv; + rv = execstr; + while (*execstr && !isspace(*execstr)) + ++execstr; + if (*execstr) { + *execstr++ = 0; + while (isspace(*execstr)) + ++execstr; + } + return (*rv) ? rv : NULL; +} /* getarg */ + + +VOID PROC +version() +/* version: print which version of levee we are... */ +{ + errmsg("levee (c)");prints(codeversion); +} /* version */ + + +VOID PROC +args() +/* args: print the argument list */ +{ + register int i; + mvcur(-1,0); + for (i=0; i < argc; i++) { + if (curpos.x+strlen(argv[i]) >= COLS) + exprintln(); + else if (i > 0) + printch(' '); + if (pc == i) { /* highlight the current filename.. */ +#if OS_ATARI|OS_FLEXOS + strput("\033p"); +#else + printch('['); +#endif + prints(argv[i]); +#if OS_ATARI|OS_FLEXOS + strput("\033q"); +#else + printch(']'); +#endif + } + else + prints(argv[i]); + } +} /* args */ + +VOID PROC +setcmd() +{ + bool no = NO,b; +#if 0 + int len,i; +#endif + char *arg, *num; + struct variable *vp; + + if ( (arg = getarg()) ) { + do { + if (*arg != 0) { + if ( (num = strchr(arg, '=')) ) { + b = NO; + *num++ = 0; + } + else { /* set [no]opt */ + b = YES; + if (arg[0]=='n' && arg[1]=='o') { + arg += 2; + no = NO; + } + else + no = YES; + } + for(vp=vars;vp->u && strcmp(arg,vp->v_name) + && strcmp(arg,vp->v_abbr); vp++) + ; + if (!vp->u || vp->v_flags & V_CONST) { + errmsg("Can't set "); + prints(arg); + } + else { + int j; + + if (b) + if (vp->v_tipe == VBOOL) + vp->u->valu = no; + else + goto badsettype; + else if (vp->v_tipe == VSTR) { + if (vp->u->strp) + free(vp->u->strp); + vp->u->strp = (*num) ? strdup(num) : NULL; + } + else + if (*num && (j=atoi(num)) >= 0) + vp->u->valu = j; + else { + badsettype: + errmsg("bad set type"); + continue; + } + diddled |= vp->v_flags & V_DISPLAY; + } + } + } while ( (arg = getarg()) ); + } + else { + version(); exprintln(); + for(vp=vars;vp->u;vp++) { + switch (vp->v_tipe) { + case VBOOL: + if (!vp->u->valu) + prints("no"); + prints(vp->v_name); + break; + case VSTR: + if (!vp->u->strp) + prints("no "); + prints(vp->v_name); + if (vp->u->strp) { + mvcur(-1,10); + prints("= "); + prints(vp->u->strp); + } + break; + default: + prints(vp->v_name); + mvcur(-1,10); + prints("= "); + printi(vp->u->valu); + break; + } + exprintln(); + } + } +} /* setcmd */ + + +/* print a macro */ +VOID PROC +printone(i) +int i; +{ + if (i >= 0) { + exprintln(); + printch(mbuffer[i].token); + mvcur(-1,3); + if (movemap[(unsigned int)(mbuffer[i].token)] == INSMACRO) + prints("!= "); + else + prints(" = "); + prints(mbuffer[i].m_text); + } +} /* printone */ + + +/* print all the macros */ +VOID PROC +printall() +{ + int i; + for (i = 0; i < MAXMACROS; i++) + if (mbuffer[i].token != 0) + printone(i); +} /* printall */ + + +/* :map ch text */ +VOID PROC +map(insert) +bool insert; +{ + char *macro, c; + int i; + /* get the macro */ + if ((macro=getarg()) == NULL) { + printall(); + return; + } + if (strlen(macro) > 1) { + errmsg("macros must be one character"); + return; + } + c = macro[0]; + if (*execstr == 0) + printone(lookup(c)); + else { + if ((i = lookup(0)) < 0) + errmsg("macro table full"); + else if (c == ESC || c == ':') { + errmsg("can't map "); + printch(c); + } + else if (*execstr != 0) { + undefine(lookup(c)); + mbuffer[i].token = c; + mbuffer[i].m_text = strdup(execstr); + mbuffer[i].oldmap = movemap[(unsigned int)c]; + if (insert) + movemap[(unsigned int)c] = INSMACRO; + else + movemap[(unsigned int)c] = SOFTMACRO; + } + } +} /* map */ + + +VOID PROC +undefine(i) +int i; +{ + char *p; + if (i >= 0) { + movemap[(unsigned int)(mbuffer[i].token)] = mbuffer[i].oldmap; + mbuffer[i].token = 0; + p = mbuffer[i].m_text; + free(p); + mbuffer[i].m_text = 0; + } +} /* undefine */ + + +int PROC +unmap() +{ + int i; + char *arg; + + if ( (arg=getarg()) ) { + if (strlen(arg) == 1) { + undefine(lookup(*arg)); + return YES; + } + if (strcmp(arg,"all") == 0) { + for (i = 0; i < MAXMACROS; i++) + if (mbuffer[i].token != 0) + undefine(i); + return YES; + } + } + return NO; +} /* unmap */ + + +/* return argument # of a filename */ +int PROC +findarg(name) +register char *name; +{ + int j; + for (j = 0; j < argc; j++) + if (strcmp(argv[j],name) == 0) + return j; + return -1; +} /* findarg */ + + +/* add a filename to the arglist */ +int PROC +addarg(name) +register char *name; +{ + int where; + if ((where = findarg(name)) < 0) + return doaddwork(name, &argc, &argv); + return where; +} /* addarg */ + + +/* get a file name argument (substitute alt file for #) */ +char * PROC +getname() +{ + extern int wilderr; +#if OS_ATARI + extern int mapslash; + register char *p; +#endif + register char *name; + + if ( (name = getarg()) ) { + if ( 0 == strcmp(name,"#") ) { + if (*altnm) + name = altnm; + else { + errmsg("no alt name"); + wilderr++; + return NULL; + } + } +#if OS_ATARI + if (mapslash) + for (p=name; *p; p++) + if (*p == '/') + *p = '\\'; +#endif + } + return name; +} /* getname */ + + +/* CAUTION: these make exec not quite recursive */ +int high,low; /* low && high end of command range */ +bool affirm; /* cmd! */ +/* s/[src]/dst[/options] */ +/* s& */ +VOID PROC +cutandpaste() +{ + bool askme = NO, + printme= NO, + glob = NO; + int newcurr = -1; + int oldcurr = curr; + int num; + char delim; + register char *ip; + register char *dp; + + zerostack(&undo); + ip = execstr; + if (*ip != '&') { + delim = *ip; + ip = makepat(1+ip,delim); /* get search */ + if (ip == NULL) + goto splat; + dp = dst; + while (*ip && *ip != delim) { + if (*ip == '\\' && ip[1] != 0) + *dp++ = *ip++; + *dp++ = *ip++; + } + *dp = 0; + if (*ip == delim) { + while (*++ip) + switch (*ip) { + case 'q': + case 'c': askme = YES; break; + case 'g': glob = YES; break; + case 'p': printme= YES; break; + } + } + } + if (*lastpatt == 0) { +splat: errmsg("bad substitute"); + return; + } + fixupline(bseekeol(curr)); + num = 0; + do { + low = chop(low, &high, NO, &askme); + if (low > -1) { + diddled = YES; + num++; + if (printme) { + exprintln(); + writeline(-1,-1,bseekeol(low)); + } + if (newcurr < 0) + newcurr = low; + if (!glob) + low = 1+fseekeol(low); + } + } while (low >= 0); + if (num > 0) { + exprintln(); + plural(num," substitution"); + } + fixupline((newcurr > -1) ? newcurr : oldcurr); +} /* cutandpaste */ + + +/* quietly read in a file (and mark it in the undo stack) + */ +int PROC +insertfile(FILE *f, int insert, int at, int *fsize) +{ + int high, + onright, + rc=0; + + onright = (bufmax-at); + high = SIZE-onright; + + if ( insert && (onright > 0) ) + moveright(&core[at], &core[high], onright); + + rc = addfile(f, at, high, fsize); + + if ( (rc == 0) && (*fsize < 0) ) { + rc = -1; + *fsize=0; + } + if ( insert ) { + if ( *fsize ) + insert_to_undo(&undo, at, *fsize); + modified = YES; + if (onright > 0) + moveleft(&core[high], &core[at+(*fsize)], onright); + } + diddled = YES; + return rc; +} /* insertfile */ + + + +VOID PROC +inputf(fname, newbuf) +register char *fname; +bool newbuf; +{ + FILE *f; + int fsize, /* bytes read in */ + rc; + + if (newbuf) + readonly = NO; + + zerostack(&undo); + + if ( newbuf ) { + modified = NO; + low = 0; + } + else { + fixupline(bseekeol(curr)); + } + + printch('"'); + prints(fname); + prints("\" "); + if ((f=fopen(fname, "r")) == NULL) { + prints("[No such file]"); + fsize = 0; + if (newbuf) + newfile = YES; + } + else { + rc = insertfile(f, !newbuf, low, &fsize); + fclose(f); + + if ( rc > 0 ) + plural(fsize, " byte"); + else if ( rc < 0 ) + prints("[read error]"); + else { + prints("[overflow]"); + readonly=1; + } + if (newbuf) newfile = NO; + } + if (newbuf) { + fillchar(contexts, sizeof(contexts), -1); + bufmax = fsize; + } + if (*startcmd) { + count = 1; + if (*findparse(startcmd,&curr,low) != 0 || curr < 0) + curr = low; + *startcmd = 0; + } + else + curr = low; +} /* inputf */ + + +/* Change a file's name (for autocopy). */ +VOID PROC +backup(name) +char *name; +{ + char back[80]; +#if !OS_UNIX + char *p; +#endif + + strcpy(back, name); +#if OS_UNIX + strcat(back, "~"); +#else + p = strrchr(basename(back), '.'); + if (p) + strcpy(1+p, ",bkp"); + else + strcat(back, ".bkp"); +#endif + + unlink(back); + rename(name, back); +} /* backup */ + + +bool PROC +outputf(fname) +char *fname; +{ + bool whole; + FILE *f; + int status; + zerostack(&undo); /* undo doesn't survive past write */ + if (high < 0) + high = (low < 0) ? bufmax : (1+fseekeol(low)); + if (low < 0) + low = 0; + printch('"'); + prints(fname); + prints("\" "); + whole = (low == 0 && high >= bufmax-1); + if (whole && autocopy) + backup(fname); + if ( (f=fopen(fname, "w")) ) { + status = putfile(f, low, high); + fclose(f); + if (status) { + plural(high-low," byte"); + if (whole) + modified = NO; + return(YES); + } + else { + prints("[write error]"); + unlink(fname); + } + } + else + prints(fisro); + return(NO); +} /* outputf */ + + +int PROC +oktoedit(writeold) +/* check and see if it is ok to edit a new file */ +int writeold; /* automatically write out changes? */ +{ + if (modified && !affirm) { + if (readonly) { + errmsg(fisro); + return NO; + } + else if (writeold && *filenm) { + if (!outputf(filenm)) + return NO; + printch(','); + } + else { + errmsg(fismod); + return NO; + } + } + return YES; +} /* oktoedit */ + + +/* write out all || part of a file */ +bool PROC +writefile() +{ + char *name; + + if ((name=getname()) == NULL) + name = filenm; + if (*name) { + if (outputf(name)) { + addarg(name); + return YES; + } + else + strcpy(altnm, name); + } + else + errmsg("no file to write"); + return NO; +} + + +VOID PROC +editfile() +{ + char *name = NULL; /* file to edit */ + char **myargv; + int myargc; + int i, newpc; + if ((name = getarg()) && *name == '+') { + strcpy(startcmd, (name[1])?(1+name):"$"); + name = getarg(); + } + myargc=0; + if (name) + do { + if (!expandargs(name, &myargc, &myargv)) + return; + } while ( (name=getarg()) ); + if (myargc == 0) { + if (*filenm) + name = filenm; + else + errmsg("no file to edit"); + } + else if ((newpc = addarg(myargv[0])) >= 0) { + name = argv[pc = newpc]; + for (i=1; i < myargc && doaddwork(myargv[i], &argc, &argv) >= 0; i++) + ; + } + killargs(&myargc, &myargv); + if (name && oktoedit(NO)) + doinput(name); +} + + +VOID PROC +doinput(name) +char *name; +{ + inputf(name, YES); + strcpy(altnm, filenm); + strcpy(filenm, name); +} + + +VOID PROC +toedit(count) +int count; +{ + if (count > 1) { + printi(count); + prints(" files to edit; "); + } +} + + +VOID PROC +readfile() +{ + char *name; + + if ( (name=getarg()) ) + inputf(name,NO); + else + errmsg("no file to read"); +} + + +VOID PROC +nextfile(prev) +bool prev; +{ + char *name = NULL; + int newpc=pc, + myargc=0; + char **myargv; + bool newlist = NO; + + if (prev == 0) + while ( (name=getarg()) ) + if (!expandargs(name, &myargc, &myargv)) + return; + + if (oktoedit(autowrite)) { + if (prev || (myargc == 1 && strcmp(myargv[0],"-") == 0)) { + if (pc > 0) { + newpc = pc-1; + } + else { + prints("(no prev files)"); + goto killem; + } + } + else if (myargc == 0) { + if (pc < argc-1) { + newpc = 1+pc; + } + else { + prints("(no more files)"); + goto killem; + } + } + else if (myargc > 1 || (newpc = findarg(myargv[0])) < 0) { + toedit(myargc); + newpc = 0; + newlist++; + } + doinput(newlist ? myargv[0] : argv[newpc]); + pc = newpc; + if (newlist) { + killargs(&argc, &argv); + argc = myargc; + argv = myargv; + } + else + killem: if (!prev) + killargs(&myargc, &myargv); + } +} + + +/* + * set up low, high; set dot to low + */ +VOID PROC +fixupline(dft) +int dft; +{ + if (low < 0) + low = dft; + if (high < 0) + high = fseekeol(low)+1; + else if (high < low) { /* flip high & low */ + int tmp; + tmp = high; + high = low; + low = tmp; + } + if (low >= ptop && low < pend) { + setpos(skipws(low)); + yp = setY(curr); + } + else { + curr = low; + diddled = YES; + } +} + + +VOID PROC +whatline() +{ + printi(to_line((low < 0) ? (bufmax-1) : low)); + if (high >= 0) { + printch(','); + printi(to_line(high)); + } +} + + +VOID PROC +print() +{ + do { + exprintln(); + writeline(-1, 0, low); + low = fseekeol(low) + 1; + } while (low < high); + exprintln(); +} + +/* move to different line */ +/* execute lines from a :sourced || .lvrc file */ + + +bool PROC +do_file(fname,mode,noquit) +char *fname; +exec_type *mode; +bool *noquit; +{ + char line[120]; + FILE *fp, *fopen(); + + if ((fp = fopen(fname,"r")) != NULL) { + indirect = YES; + while (fgets(line,120,fp) && indirect) { + strtok(line, "\n"); + if (*line != 0) + exec(line,mode,noquit); + } + indirect = YES; + fclose(fp); + return YES; + } + return NO; +} + + +VOID PROC +doins(flag) +bool flag; +{ + int i; + curr = low; + exprintln(); + low = insertion(1,setstep[flag],&i,&i,NO)-1; + if (low >= 0) + curr = low; + diddled = YES; +} + + +/* figure out a address range for a command */ +char * PROC +findbounds(ip) +char *ip; +{ + ip = findparse(ip, &low, curr); /* get the low address */ + if (low >= 0) { + low = bseekeol(low); /* at start of line */ + if (*ip == ',') { /* high address? */ + ip++; + count = 0; + ip = findparse(ip, &high, curr); + if (high >= 0) { + high = fseekeol(high); + return(ip); + } + } + else + return(ip); + } + return(0); +} + + +/* parse the command line for lineranges && a command */ +int PROC +parse(inp) +char *inp; +{ + int j,k; + char cmd[80]; + low = high = ERR; + affirm = 0; + if (*inp == '%') { + moveright(inp, 2+inp, 1+strlen(inp)); + inp[0]='1'; + inp[1]=','; + inp[2]='$'; + } + while (isspace(*inp)) + ++inp; + if (strchr(".$-+0123456789?/`'", *inp)) + if (!(inp=findbounds(inp))) { + errmsg("bad address"); + return ERR; + } + while (isspace(*inp)) + ++inp; + j = 0; + while (isalpha(*inp)) + cmd[j++] = *inp++; + if (*inp == '!') { + if (j == 0) + cmd[j++] = '!'; + else + affirm++; + inp++; + } + else if (*inp == '=' && j == 0) + cmd[j++] = '='; + while (isspace(*inp)) + ++inp; + execstr = inp; + if (j==0) + return EX_CR; + for (k=0; excmds[k]; k++) + if (strncmp(cmd, excmds[k], j) == 0) + return k; + return ERR; +} + + +/* inner loop of execmode */ +VOID PROC +exec(cmd, mode, noquit) +char *cmd; +exec_type *mode; +bool *noquit; +{ + int what; + bool ok; + + what = parse(cmd); + ok = YES; + if (diddled) { + lstart = bseekeol(curr); + lend = fseekeol(curr); + } + switch (what) { + case EX_QUIT: /* :quit */ + if (affirm || what == lastexec || !modified) + *noquit = NO; + else + errmsg(fismod); + break; + case EX_READ: /* :read */ + clrmsg(); + readfile(); + break; + case EX_EDIT: /* :read, :edit */ + clrmsg(); + editfile(); + break; + case EX_WRITE: + case EX_WQ : /* :write, :wq */ + clrmsg(); + if (readonly && !affirm) + prints(fisro); + else if (writefile() && what==EX_WQ) + *noquit = NO; + break; + case EX_PREV: + case EX_NEXT: /* :next */ + clrmsg(); + nextfile(what==EX_PREV); + break; + case EX_SUBS: /* :substitute */ + cutandpaste(); + break; + case EX_SOURCE: /* :source */ + if ((cmd = getarg()) && !do_file(cmd, mode, noquit)) { + errmsg("cannot open "); + prints(cmd); + } + break; + case EX_XIT: + clrmsg(); + if (modified) { + if (readonly) { + prints(fisro); + break; + } + else if (!writefile()) + break; + } + + if (!affirm && (argc-pc > 1)) { /* any more files to edit? */ + printch('('); + plural(argc-pc-1," more file"); + prints(" to edit)"); + } + else + *noquit = NO; + break; + case EX_MAP: + map(affirm); + break; + case EX_UNMAP: + ok = unmap(); + break; + case EX_FILE: /* :file */ + if ( (cmd=getarg()) ) { /* :file name */ + strcpy(altnm, filenm); + strcpy(filenm, cmd); + pc = addarg(filenm); + } + wr_stat(); + break; + case EX_SET: /* :set */ + setcmd(); + break; + case EX_CR: + case EX_PR: /* :print */ + fixupline(bseekeol(curr)); + if (what == EX_PR) + print(); + break; + case EX_LINE: /* := */ + whatline(); + break; + case EX_DELETE: + case EX_YANK: /* :delete, :yank */ + yank.lines = YES; + fixupline(lstart); + zerostack(&undo); + if (what == EX_DELETE) + ok = deletion(low,high); + else + ok = doyank(low,high); + diddled = YES; + break; + case EX_PUT: /* :put */ + fixupline(lstart); + zerostack(&undo); + ok = putback(low, &high); + diddled = YES; + break; + case EX_VI: /* :visual */ + *mode = E_VISUAL; + if (*execstr) { + clrmsg(); + nextfile(NO); + } + break; + case EX_EX: + *mode = E_EDIT; /* :execmode */ + break; + case EX_INSERT: + case EX_OPEN: /* :insert, :open */ + if (indirect) + ok = NO; /* kludge, kludge, kludge!!!!!!!!!! */ + else { + zerostack(&undo); + fixupline(lstart); + doins(what == EX_OPEN); + } + break; + case EX_CHANGE: /* :change */ + if (indirect) + ok = NO; /* kludge, kludge, kludge!!!!!!!!!! */ + else { + zerostack(&undo); + yank.lines = YES; + fixupline(lstart); + if (deletion(low,high)) + doins(YES); + else + ok = NO; + } + break; + case EX_UNDO: /* :undo */ + low = fixcore(&high); + if (low >= 0) { + diddled = YES; + curr = low; + } + else ok = NO; + break; + case EX_ARGS: /* :args */ + args(); + break; + case EX_VERSION: /* version */ + version(); + break; + case EX_ESCAPE: /* shell escape hack */ + zotscreen = YES; + exprintln(); + if (*execstr) { +#if TTY_ZTERM + zclose(); +#endif +#if OS_FLEXOS|OS_UNIX + fixcon(); +#else + allowintr(); +#endif + system(execstr); +#if OS_FLEXOS|OS_UNIX + initcon(); +#else + nointr(); +#endif + } + else + prints("incomplete shell escape."); + break; + case EX_REWIND: + clrmsg(); + if (argc > 0 && oktoedit(autowrite)) { + pc = 0; + doinput(argv[0]); + } + break; + default: + prints(":not an editor command."); + break; + } + lastexec = what; + if (!ok) { + errmsg(excmds[what]); + prints(" error"); + } +} diff --git a/src/cmd/levee/extern.h b/src/cmd/levee/extern.h new file mode 100644 index 0000000..0e505b1 --- /dev/null +++ b/src/cmd/levee/extern.h @@ -0,0 +1,237 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#ifndef GLOBALS_D +#define GLOBALS_D +extern +char lastchar, /* Last character read via peekc */ + ch; /* Global command char */ +extern +exec_type mode; /* editor init state */ +extern +int lastexec; /* last exec mode command */ + +extern +int contexts['z'-'`'+1]; /* Labels */ + /* C O N S T A N T S */ +extern +bool adjcurr[PARA_BACK+1], + adjendp[PARA_BACK+1]; + /* A R G U M E N T S */ +extern +char startcmd[]; /* initial command after read */ +extern +char **argv; /* Arguments */ +extern +int argc, /* # arguments */ + pc; /* Index into arguments */ + /* M A C R O S T U F F */ +extern +struct macrecord mbuffer[]; +extern +struct tmacro mcr[]; /* A place for executing macros */ + /* S E A R C H S T U F F */ +extern +char dst[], /* last replacement pattern */ + lastpatt[], /* last search pattern */ + pattern[]; +extern +int RE_start[9], /* start of substitute argument */ + RE_size [9], /* size of substitute argument */ + lastp; /* last character matched in search */ +extern +struct undostack undo; /* To undo a command */ + /* R A N D O M S T R I N G S */ + +extern +char instring[], /* Latest input */ + filenm[], /* Filename */ + altnm[], /* Alternate filename */ + gcb[]; /* Command buffer for mutations of insert */ + +extern +char undobuf[], + undotmp[], + yankbuf[]; +extern +int uread, /* reading from the undo stack */ + uwrite; /* writing to the undo stack */ + /* B U F F E R S */ +extern +char rcb[], *rcp, /* last modification command */ + core[]; /* data space */ + +extern +struct ybuf yank; /* last deleted/yanked text */ +/* STATIC INITIALIZATIONS: */ + +/* ttydef stuff */ +#if OS_ATARI | USE_TERMCAP +extern int LINES, COLS; +#endif + +#if USE_TERMCAP +extern bool CA, canUPSCROLL; +extern char FkL, + CurRT, + CurLT, + CurDN, + CurUP; +#endif /*USE_TERMCAP*/ + +extern char *TERMNAME, + *HO, + *UP, + *CE, + *CL, + *OL, + *BELL, + *CM, + *UpS, + *CURoff, + *CURon; + +extern +char Erasechar, + eraseline; + +extern +char codeversion[], /* Editor version */ + fismod[], /* File is modified message */ + fisro[]; /* permission denied message */ + +extern +char *excmds[], + wordset[], + spaces[]; +extern +struct variable vars[]; +extern +int autowrite, + autocopy, + overwrite, + beautify, + autoindent, + dofscroll, + shiftwidth, + tabsize, + list, + wrapscan, + bell, + magic; +/*extern +char *suffix; */ +/* For movement routines */ +extern +int setstep[]; +/* Where the last diddling left us */ +extern +struct coord curpos; + + /* initialize the buffer */ +extern +int curr, /* Global cursor pos */ + lstart, lend, /* Start & end of current line */ + count, /* Latest count */ + xp, yp, /* Cursor window position */ + bufmax, /* End of file here */ + ptop, pend; /* Top & bottom of CRT window */ +extern +bool modified, /* File has been modified */ + readonly, /* is this file readonly? */ + needchar, /* Peekc flag */ + deranged, /* Up-arrow || down-arrow left xpos in Oz. */ + indirect, /* Reading from an indirect file?? */ + redoing, /* doing a redo? */ + xerox, /* making a redo buffer? */ + newfile, /* Editing a new file? */ + newline, /* Last insert/delete included a EOL */ + lineonly, /* Dumb terminal? */ + zotscreen, /* do more after command in execmode */ + diddled; /* force redraw when I enter editcore */ + +extern +int macro; /* Index into MCR macro execution stack */ +extern +char lsearch; +/* movement, command codes */ +extern +cmdtype movemap[]; +#endif /*GLOBALS_D*/ +#ifndef EXTERN_D +#define EXTERN_D +#define wc(ch) (scan(65,'=',(ch),wordset)<65) + +#if HAVE_STRING_H +#include +#endif + +#if HAVE_MEMSET +#define fillchar(p,l,c) memset((p),(c),(l)) +#elif HAVE_BLKFILL +#define fillchar(p,l,c) blkfill((p),(c),(l)) +#endif +#if HAVE_STRCHR +#define index(s,c) strchr((s),(c)) +#endif + +extern findstates PROC findCP(); +extern exec_type PROC editcore(); + +extern char PROC line(), peekc(), readchar(); +extern char PROC *findparse(),*makepat(); + +extern bool PROC getline(); +extern bool PROC putfile(); +extern bool PROC doyank(), deletion(), putback(); +extern bool PROC pushb(),pushi(),pushmem(),uputcmd(), delete_to_undo(); +extern bool PROC ok_to_scroll(), move_to_undo(); + +extern int PROC min(), max(), fseekeol(), bseekeol(), settop(); +extern int PROC scan(), findDLE(), setY(), skipws(), nextline(), setX(); +extern int PROC insertion(), chop(), fixcore(), lookup(), to_index(); +extern int PROC doaddwork(), addfile(), expandargs(), to_line(); +extern int PROC findfwd(), findback(), getcontext(), getKey(); +extern int PROC cclass(); +extern int PROC insertfile(); + +extern VOID PROC strput(), numtoa(), clrprompt(), setend(), error(); +extern VOID PROC insert_to_undo(), resetX(), zerostack(), swap(); +extern VOID PROC mvcur(), printch(), prints(), writeline(), refresh(); +extern VOID PROC redisplay(), scrollback(), scrollforward(), prompt(); +extern VOID PROC setpos(), resetX(), insertmacro(), wr_stat(); +extern VOID PROC movearound(), printi(), println(), killargs(); +extern VOID PROC exec(), initcon(), fixcon(), version(), setcmd(); +extern VOID PROC toedit(), inputf(), fixmarkers(), errmsg(); + +#ifndef moveleft +extern VOID PROC moveleft(); +#endif +#ifndef moveright +extern VOID PROC moveright(); +#endif +#ifndef fillchar +extern VOID PROC fillchar(); +#endif + +#if USE_TERMCAP +extern void tc_init(); +#endif + +#endif /*EXTERN_D*/ diff --git a/src/cmd/levee/find.c b/src/cmd/levee/find.c new file mode 100644 index 0000000..966529a --- /dev/null +++ b/src/cmd/levee/find.c @@ -0,0 +1,514 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" +#include "grep.h" +#include + +int PROC amatch(); +int PROC locate(); +VOID PROC patsize(); + +static int arg; /* arguments inside of a RE */ + +int PROC +REmatch(pattern, start, end) +char *pattern; +int start,end; +{ + char *endp = &core[end]; + + if (!*pattern) + return -1; + arg = 0; + while (start <= end && !amatch(pattern, &core[start], endp)) + start++; + return start; +} + +int PROC +omatch(pattern, cp, endp) +char *pattern, **cp, *endp; +{ + register int flag; + extern int ignorecase; + + switch (*pattern) { + case LEND: + return (**cp == EOL); + case LSTART: + return (*cp == core) || (*(*cp-1) == EOL); + case TOKENB: + return (*cp == core) || !isalnum(*(*cp-1)); + case TOKENE: + return !isalnum(**cp); + case LITCHAR: + if (ignorecase) + flag = (toupper(**cp) == toupper(*(pattern+1))); + else + flag = (**cp == *(pattern+1)); + break; + case ANY: + flag = (**cp != EOL); + break; + case CCL: + flag = locate(pattern,*cp); + break; + case NCCL: + flag = !locate(pattern,*cp); + break; + case ARGSTART: + RE_start[arg] = (*cp)-core; + return TRUE; + case ARGEND: + RE_size[arg] = ((*cp)-core) - RE_start[arg]; + ++arg; + return TRUE; + default: + return TRUE; + } + + if (*cp <= endp && flag) { + (*cp)++; + return TRUE; + } + return FALSE; +} + +int PROC +amatch(pattern,start,endp) +char *pattern, *endp, *start; +{ + int sarg = arg; /* save old arg match count for errors */ + + while (*pattern) { + if (*pattern == CLOSURE) { + /* Find the longest closure possible and work backwards trying + * to match the rest of the pattern. + */ + char *oldstart = start; + + ++pattern; /* skip over the closure token */ + while (start <= endp && omatch(pattern,&start,endp)) + ; + /* start points at the character that failed the search. + * Try to match the rest of the pattern against it, working + * back down the line if failure + */ + patsize(&pattern); + while (start >= oldstart) + if (amatch(pattern,start--,endp)) + return TRUE; + arg = sarg; + return FALSE; + } + else { + if (!omatch(pattern,&start,endp)) { + arg = sarg; + return FALSE; + } + patsize(&pattern); + } + } + lastp = start-core; + return TRUE; +} + +/* increment pattern by the size of the token being scanned + */ +VOID PROC +patsize(pattern) +register char **pattern; +{ + register int count; + + switch (**pattern) { + case LITCHAR: + *pattern += 2; + break; + case CCL: + case NCCL: + count = *(++*pattern) & 0xff; + *pattern += 1+count; + break; + default: + (*pattern)++; + break; + } +} + +int PROC +locate(pattern,linep) +/* locate: find a character in a closure */ +char *pattern; +register char *linep; +{ + register char *p = 1+pattern; + register int count; + + if ((count = (*p++)&0xff) == 0) + return FALSE; + while (count--) + if (*p++ == *linep) + return TRUE; + return FALSE; +} +char *p; + +VOID PROC +concatch(c) +/* add a character to the pattern */ +char c; +{ + if (p < &pattern[MAXPAT-1]) + *p++ = c; +} + +char PROC +esc(s) +char **s; +{ + if (**s != ESCAPE || *(1+*s) == 0) + return **s; + ++(*s); + switch (**s) { + case 't': return TAB; + case 'n': return EOL; + } + return **s; +} + +char * PROC +dodash(src) +/* parse the innards of a [] */ +char *src; +{ + int k; + char *start = src; + char cs[128]; + + fillchar(cs,sizeof(cs),FALSE); + while (*src && *src != CCLEND) { + if (*src == DASH && src>start && src[1] != CCLEND && src[-1] pattern)) { + cp = oldcp; + if (strchr(badclose, *cp) || p >= &pattern[MAXPAT-1]) + return NULL; + moveright(cp,1+cp,(int)(p-cp)); + *cp = CLOSURE; + p++; + } + else if (*string == ESCAPE) { + if (string[1] == ARGSTART || string[1] == ARGEND) { + if (string[1] == ARGEND) + if (!inarg) + goto normal; + if (string[1] == ARGSTART) { + if (inarg) + goto normal; + if (++arg > 9) + return NULL; + } + inarg = !inarg; + } + else if (string[1] != TOKENB && string[1] != TOKENE) + goto normal; + ++string; + concatch(*string); + } + else { + normal:concatch(LITCHAR); + concatch(esc(&string)); + } + if (*string) + string++; + } + if (inarg) + concatch(ARGEND); + if (p > pattern) { /* new pattern was created */ + strncpy(lastpatt,start,(int)(string-start)); + lastpatt[string-start] = 0; + concatch(0); + if (p-pattern >= MAXPAT) + return NULL; + } + return (*string == delim)?(string+1):(string); +} + +int PROC +findfwd(pattern,start,endp) +/* look for a regular expression forward */ +char *pattern; +int start, endp; +{ + int ep; + + while (start < endp) { + ep = fseekeol(start); + if ((start = REmatch(pattern, start, ep)) <= ep) + return start; + } + return ERR; + } + +int PROC +findback(pattern,start,endp) +/* look for a regular expression backwards */ +char *pattern; +int start, endp; +{ + int ep,i; + + while (start > endp) { + ep = bseekeol(start); + if ((i = REmatch(pattern, ep, start)) <= start) + return i; + start = ep-1; + } + return ERR; + } + +bool s_wrapped = 0; + +char * PROC +search(pat, start) +/* get a token for find & find it in the buffer + */ +char *pat; +int *start; +{ + bool forwd; + int pos; + char *p; + + forwd = ((lsearch = *pat) == '/'); + if ((p=makepat(pat+1,*pat)) == NULL) { + *start = ERR; + return pat; + } + do { + if (forwd) { + pos = findfwd(pattern, (*start)+1, bufmax-1); + if ((pos == ERR) && wrapscan) { + s_wrapped = 1; + pos = findfwd(pattern, 0, (*start)-1); + } + } + else { + pos = findback(pattern, (*start)-1, 0); + if ((pos == ERR) && wrapscan) { + s_wrapped = 1; + pos = findback(pattern, bufmax-1, (*start)+1); + } + } + *start = pos; + } while (--count > 0 && *start != ERR); + return p; +} + +char * PROC +findparse(src,idx,start) /* driver for ?, /, && : lineranges */ +char *src; +int *idx,start; +{ + int addr = start; + char c; + + s_wrapped = 0; + + switch (*src) { + case '/': + case '?': + /* get a token for find & find it in the buffer */ + src = search(src,&addr); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* fabricate a count */ + count = 0; + while (*src >= '0' && *src <= '9') + count = (count*10) + *(src++) - '0'; + + addr = to_index(count); + break; + case '$': + addr = bufmax-1; + src++; + break; + case '.' : + src++; + break; + case '`': + case '\'': + addr = getcontext(*(src+1), (*src == '\'')); + src += 2; + break; + } + + while (addr>=0 && (*src =='+' || *src == '-')) { + c = *(src++); + /* skip delimiter */ + if (*src == '/' || *src == '?') { + count = 1; + if ((src = search(src,&addr)) == NULL) + break; + } + else { + if (*src >= '0' && *src <= '9') { + /* fabricate a count */ + count = 0; + while (*src >= '0' && *src <= '9') + count = (count*10) + *(src++) - '0'; + } + else + count = -1; /* for naked + & - */ + if (count == 0) /* +0 goes to beginning of line */ + addr = bseekeol(addr); + else { + addr = nextline((c=='+'), addr, count); + if (c=='-' && addr > 0) + addr = bseekeol(addr); + } + if (addr >= bufmax) + addr = -1; + } + } + *idx = addr; + return(src); +} + +int PROC +nextline(advance,dest,count) +bool advance; +int dest,count; +{ + if (advance) + do { + dest = fseekeol(dest) + 1; + count--; + } while (count>0 && dest0 && dest>=0); + return(dest); +} + +int PROC +fseekeol(origin) +int origin; +{ + return(origin + scan(bufmax-origin-1,'=',EOL,&core[origin])); +} + +int PROC +bseekeol(origin) +int origin; +{ + return(origin + scan(-origin,'=',EOL,&core[origin-1])); +} + +/* get something from the context table */ + +int PROC +getcontext(c,begline) +char c; +bool begline; +{ + int i; + + if (c == '\'') + c = '`'; + if (c >= '`' && c <= 'z') + i = contexts[c-'`']; + else + i = -1; + if (begline && i>=0) + return(bseekeol(i)); + return(i); +} diff --git a/src/cmd/levee/flexcall.c b/src/cmd/levee/flexcall.c new file mode 100644 index 0000000..4ee0a56 --- /dev/null +++ b/src/cmd/levee/flexcall.c @@ -0,0 +1,122 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +/* + * flexos interface for levee (Metaware C) + */ +#include "levee.h" + +#if OS_FLEXOS +#include +#include + +static int oldkmode; +static int oldsmode; + +int +min(a,b) +{ + return (a>b) ? b : a; +} + +int +max(a,b) +{ + return (a + +strput(s) +register char *s; +{ + write(1, s, strlen(s)); +} + + +zwrite(s,len) +char *s; +{ + write(1, s, len); +} + + +min(a,b) +register int a, b; +{ + return (ab)?a:b; +} + + +unsigned +getKey() +/* get input from the keyboard. All odd keys (function keys, et al) that + * do not produce a character have their scancode orred with $80 and returned. + */ +{ + unsigned c; + long key; + + c = (key = Crawcin()) & 0xff; + if (!c) + c = (((unsigned)(key>>16))|0x80) & 0xff; + return c; +} /* getKey */ +#endif /*OS_ATARI*/ diff --git a/src/cmd/levee/globals.c b/src/cmd/levee/globals.c new file mode 100644 index 0000000..7f1c3b0 --- /dev/null +++ b/src/cmd/levee/globals.c @@ -0,0 +1,547 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2008 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +/* global declarations */ + +#include "levee.h" +#define GLOBALS + +char lastchar, /* Last character read via peekc */ + ch; /* Global command char */ + +exec_type mode; /* editor init state */ +int lastexec = 0; /* last exec command */ + +int contexts['z'-'`'+1]; /* Labels */ + + /* C O N S T A N T S */ + +bool adjcurr[PARA_BACK+1], + adjendp[PARA_BACK+1]; + + /* A R G U M E N T S */ +char startcmd[80] = ""; /* initial command after read */ +char **argv; /* Arguments */ +int argc=0, /* # arguments */ + pc=0; /* Index into arguments */ +#if 0 +struct stat thisfile; /* status on current file, for writeout... */ +#endif + + /* M A C R O S T U F F */ +struct macrecord mbuffer[MAXMACROS]; +struct tmacro mcr[NMACROS]; /* A place for executing macros */ + + /* S E A R C H S T U F F */ +char dst[80] = "", /* last replacement pattern */ + lastpatt[80] = "", /* last search pattern */ + pattern[MAXPAT] = ""; /* encoded last pattern */ + +int RE_start[9], /* start of substitution arguments */ + RE_size [9], /* size of substitution arguments */ + lastp; /* end of last pattern */ + +struct undostack undo; /* To undo a command */ + + + /* R A N D O M S T R I N G S */ + +char instring[200], /* Latest input */ + filenm[80] = "", /* Filename */ + altnm[80] = ""; /* Alternate filename */ +char gcb[16]; /* Command buffer for mutations of insert */ + +char undobuf[40]; +char undotmp[40]; +char yankbuf[40]; + +HANDLE uread, /* reading from the undo stack */ + uwrite; /* writing to the undo stack */ + + /* B U F F E R S */ +char rcb[256]; /* last modification command */ +char *rcp; /* this points at the end of the redo */ +char core[SIZE+1]; /* data space */ + +struct ybuf yank; /* last deleted/yanked text */ + + +/* STATIC INITIALIZATIONS: */ + +/* ttydef stuff */ + +#if OS_ATARI | USE_TERMCAP +int LINES, COLS; +#endif + +#if TTY_ZTERM +char *TERMNAME = "zterm", + *HO = "\001", /* goto top of screen */ + *UP = "\002", /* move up 1 line? */ + *CE = "\003", /* clear to end of line */ + *CL = "\004", /* clearscreen */ + *OL = "\005", /* open current line down */ + *UpS = "\006", /* scroll up 1 line */ + *BELL= "\007", /* ring the bell */ + *CM = "yes", /* cursor movement exists */ + *CURoff, + *CURon; +#endif /*ZTERM*/ + +#if TTY_ANSI +#if OS_DOS +char *TERMNAME = "braindamaged ansi", +#else +char *TERMNAME = "hardwired ansi", +#endif + *HO = "\033[H", + *UP = "\033[A", + *CE = "\033[K", + *CL = "\033[H\033[J", +#if OS_DOS + *OL = NULL, + *UpS = NULL, +#else + *OL = "\033[L", + *UpS = "\033[L", +#endif + *BELL= "\007", + *CM = "\033[%d;%dH", + *CURoff, + *CURon; +#endif /*TTY_ANSI*/ + +#if TTY_VT52 +#if OS_ATARI +char *TERMNAME = "Atari ST", +#else +#if OS_FLEXOS +char *TERMNAME = "Flexos console", +#else +char *TERMNAME = "hardwired vt52", +#endif /*OS_FLEXOS*/ +#endif /*OS_ATARI*/ + *HO = "\033H", + *UP = "\033A", + *CE = "\033K", + *CL = "\033E", + *OL = "\033L", + *BELL= "\007", + *CM = "\033Y??", +#if OS_FLEXOS + *UpS = NULL, /* Reverse scrolling is painfully slow */ +#else + *UpS = "\033I", +#endif + *CURoff= "\033f", + *CURon = "\033e"; +#endif /*TTY_VT52*/ + +#if USE_TERMCAP +bool CA, canUPSCROLL; +char FkL, CurRT, CurLT, CurUP, CurDN; + +char *TERMNAME, /* will be set in termcap handling */ + *HO, + *UP, + *CE, + *CL, + *OL, + *BELL, + *CM, + *UpS, + *CURoff, + *CURon; +#endif /*USE_TERMCAP*/ + +char Erasechar = ERASE, /* our erase character */ + eraseline = 'X'-'@'; /* and line-kill character */ + +char fismod[] = "File is modified", /* File is modified message */ + fisro[] = "File is readonly"; /* when you can't write the file */ + +char *excmds[] = { + "print", /* lines to screen */ + "quit", /* quit editor */ + "read", /* add file to buffer */ + "edit", /* replace buffer with file */ + "write", /* write out file */ + "wq", /* write file and quit */ + "next", /* make new arglist or traverse this one */ + "substitute", /* pattern */ + "xit", /* write changes and quit */ + "file", /* show/set file name */ + "set", /* options */ + "rm", /* a file */ + "previous", /* back up in arglist */ + "delete", /* lines from buffer */ + "=", /* tell line number */ + "yank", /* lines from buffer */ + "put", /* back yanked lines */ + "visual", /* go to visual mode */ + "exec", /* go to exec mode */ + "insert", /* text below current line */ + "open", /* insert text above current line */ + "change", /* lines */ + "undo", /* last change */ + "!", /* shell escape */ + "map", /* keyboard macro */ + "unmap", /* keyboard macro */ + "source", /* read commands from file */ + "version", /* print version # */ + "args", /* print argument list */ + "rewind", /* rewind argument list */ + NULL +}; + +char wordset[] = "0123456789$_#ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +char spaces[] = { TAB,EOL,' ',0 }; + +int shiftwidth = 4, +#if USE_TERMCAP | OS_ATARI + dofscroll, +#else + dofscroll = LINES/2, +#endif + tabsize = 8; +int autoindent = YES, + autocopy = NO, + autowrite = YES, + wrapscan = YES, + overwrite = YES, + beautify = YES, + list = NO, + magic = YES, + bell = YES, +#if OS_ATARI + mapslash, +#endif + ignorecase = NO; + +struct variable vars[]={ + {"terminal", "", VSTR, V_CONST, (void*)&TERMNAME }, + {"shiftwidth","sw", VINT, 0, (void*)&shiftwidth }, + {"scroll", "", VINT, 0, (void*)&dofscroll }, + {"tabsize", "ts", VINT, V_DISPLAY, (void*)&tabsize }, + {"autoindent","ai", VBOOL, 0, (void*)&autoindent }, + {"autocopy", "ac", VBOOL, 0, (void*)&autocopy }, + {"autowrite", "aw", VBOOL, 0, (void*)&autowrite }, + {"wrapscan", "ws", VBOOL, 0, (void*)&wrapscan }, + {"overwrite", "ow", VBOOL, 0, (void*)&overwrite }, + {"beautify", "be", VBOOL, 0, (void*)&beautify }, + {"list", "", VBOOL, V_DISPLAY, (void*)&list }, + {"magic", "", VBOOL, 0, (void*)&magic }, + {"ignorecase","ic", VBOOL, 0, (void*)&ignorecase }, + {"bell", "", VBOOL, 0, (void*)&bell }, +#if OS_ATARI + {"mapslash", "ms", VBOOL, 0, (void*)&mapslash }, +#endif + {NULL} +}; + +/* For movement routines */ +int setstep[2] = {-1,1}; + +/* Where the last diddling left us */ +struct coord curpos={0, 0}; + + /* initialize the buffer */ +int bufmax = 0, /* End of file here */ + lstart = 0, lend = 0, /* Start & end of current line */ + ptop = 0, pend = 0, /* Top & bottom of CRT window */ + curr = 0, /* Global cursor pos */ + xp = 0, yp = 0, /* Cursor window position */ + count = 0; /* Latest count */ + +bool modified= NO, /* File has been modified */ + readonly= NO, /* is this file readonly? */ + needchar= YES, /* Peekc flag */ + deranged= NO, /* Up-arrow || down-arrow left xpos in Oz. */ + indirect= NO, /* Reading from an indirect file?? */ + redoing = NO, /* doing a redo? */ + xerox = NO, /* making a redo buffer? */ + newfile = YES, /* Editing a new file? */ + newline = NO, /* Last insert/delete included a EOL */ + lineonly= NO, /* Dumb terminal? */ + zotscreen=NO, /* ask for [more] in execmode */ + diddled = NO; /* force new window in editcore */ + +int macro = -1; /* Index into MCR */ +char lsearch = 0; /* for N and n'ing... */ + +/* movement, command codes */ + +cmdtype movemap[256]={ + /*^@*/ BAD_COMMAND, + /*^A*/ DEBUG_C, + /*^B*/ HARDMACRO, + /*^C*/ BAD_COMMAND, + /*^D*/ WINDOW_UP, + /*^E*/ HARDMACRO, + /*^F*/ HARDMACRO, + /*^G*/ FILE_C, + /*^H*/ GO_LEFT, /* also leftarrow */ + /*^I*/ REDRAW_C, + /*^J*/ GO_DOWN, /* also downarrow */ + /*^K*/ GO_UP, /* also uparrow */ + /*^L*/ GO_RIGHT, /* also rightarrow */ + /*^M*/ CR_FWD, + /*^N*/ BAD_COMMAND, + /*^O*/ BAD_COMMAND, + /*^P*/ BAD_COMMAND, + /*^Q*/ BAD_COMMAND, + /*^R*/ BAD_COMMAND, + /*^S*/ BAD_COMMAND, + /*^T*/ BAD_COMMAND, + /*^U*/ WINDOW_DOWN, + /*^V*/ BAD_COMMAND, + /*^W*/ BAD_COMMAND, + /*^X*/ BAD_COMMAND, + /*^Y*/ HARDMACRO, + /*^Z*/ BAD_COMMAND, + /*^[*/ BAD_COMMAND, + /*^\*/ BAD_COMMAND, + /*^]*/ BAD_COMMAND, + /*^^*/ BAD_COMMAND, + /*^_*/ BAD_COMMAND, + /* */ GO_RIGHT, + /*! */ EXEC_C, + /*" */ BAD_COMMAND, + /*# */ BAD_COMMAND, + /*$ */ TO_EOL, + /*% */ MATCHEXPR, + /*& */ RESUBST_C, + /*\ */ TO_MARK_LINE, + /*( */ SENT_BACK, + /*) */ SENT_FWD, + /** */ BAD_COMMAND, + /*+ */ CR_FWD, + /*, */ BAD_COMMAND, + /*- */ CR_BACK, + /*. */ REDO_C, + /*/ */ PATT_FWD, + /*0 */ TO_COL, + /*1 */ BAD_COMMAND, + /*2 */ BAD_COMMAND, + /*3 */ BAD_COMMAND, + /*4 */ BAD_COMMAND, + /*5 */ BAD_COMMAND, + /*6 */ BAD_COMMAND, + /*7 */ BAD_COMMAND, + /*8 */ BAD_COMMAND, + /*9 */ BAD_COMMAND, + /*: */ COLIN_C, + /*; */ BAD_COMMAND, + /*< */ ADJUST_C, + /*= */ BAD_COMMAND, + /*> */ ADJUST_C, + /*? */ PATT_BACK, + /*@ */ BAD_COMMAND, + /*A */ A_AT_END, + /*B */ BACK_WD, + /*C */ HARDMACRO, + /*D */ HARDMACRO, + /*E */ BAD_COMMAND, + /*F */ BACK_CHAR, + /*G */ GLOBAL_LINE, + /*H */ PAGE_BEGIN, + /*I */ I_AT_NONWHITE, + /*J */ JOIN_C, + /*K */ BAD_COMMAND, + /*L */ PAGE_END, + /*M */ PAGE_MIDDLE, + /*N */ BSEARCH, + /*O */ OPENUP_C, + /*P */ PUT_AFTER, + /*Q */ EDIT_C, + /*R */ BIG_REPL_C, + /*S */ BAD_COMMAND, + /*T */ BACKTO_CHAR, + /*U */ BAD_COMMAND, + /*V */ BAD_COMMAND, + /*W */ FORWD, + /*X */ HARDMACRO, + /*Y */ HARDMACRO, + /*Z */ ZZ_C, + /*[ */ BAD_COMMAND, + /*\ */ BAD_COMMAND, + /*] */ BAD_COMMAND, + /*^ */ NOTWHITE, + /*_ */ BAD_COMMAND, + /*` */ TO_MARK, + /*a */ APPEND_C, + /*b */ BACK_WD, + /*c */ CHANGE_C, + /*d */ DELETE_C, + /*e */ FORWD, + /*f */ TO_CHAR, + /*g */ BAD_COMMAND, + /*h */ GO_LEFT, + /*i */ INSERT_C, + /*j */ GO_DOWN, + /*k */ GO_UP, + /*l */ GO_RIGHT, + /*m */ MARKER_C, + /*n */ FSEARCH, + /*o */ OPEN_C, + /*p */ PUT_BEFORE, + /*q */ BAD_COMMAND, + /*r */ REPLACE_C, + /*s */ HARDMACRO, + /*t */ UPTO_CHAR, + /*u */ UNDO_C, + /*v */ BTO_WD, + /*w */ TO_WD, + /*x */ HARDMACRO, + /*y */ YANK_C, + /*z */ REWINDOW, + /*{ */ PARA_BACK, + /*| */ TO_COL, + /*} */ PARA_FWD, + /*~ */ TWIDDLE_C, + /*^?*/ BAD_COMMAND, + /*80*/ BAD_COMMAND, + /*81*/ BAD_COMMAND, + /*82*/ BAD_COMMAND, + /*83*/ BAD_COMMAND, + /*84*/ BAD_COMMAND, + /*85*/ BAD_COMMAND, + /*x6*/ BAD_COMMAND, + /*x7*/ BAD_COMMAND, + /*x8*/ BAD_COMMAND, + /*x9*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND, + /*xx*/ BAD_COMMAND + }; diff --git a/src/cmd/levee/grep.h b/src/cmd/levee/grep.h new file mode 100644 index 0000000..0c7a480 --- /dev/null +++ b/src/cmd/levee/grep.h @@ -0,0 +1,36 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#define LEND '$' +#define LSTART '^' +#define LITCHAR 'c' +#define ANY '.' +#define CCL '[' +#define NCCL '!' +#define DASH '-' +#define CCLEND ']' +#define NEGATE '^' +#define CLOSURE '*' +#define ESCAPE '\\' +#define TOKENB '<' +#define TOKENE '>' + +#define ARGSTART '(' +#define ARGEND ')' +#define AMPERSAND '&' diff --git a/src/cmd/levee/insert.c b/src/cmd/levee/insert.c new file mode 100644 index 0000000..bb90e42 --- /dev/null +++ b/src/cmd/levee/insert.c @@ -0,0 +1,156 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" + +int PROC +insertion(count, openflag, dp, yp, visual) +int count, openflag, *dp, *yp; +bool visual; +{ + char cmd, c; + int rp; /* number of spaces to diddle */ + int ts, ss; /* tabs && spaces to insert */ + register int cp; /* current position */ + int i; /* random index */ + int endd; /* last open place */ + register int rsize; /* size of upper buffer */ + int currDLE = 0; /* what DLE is now */ + int len; /* full insert size */ + bool Dflag; + + if (openflag != 0) { /* opening a line above || below */ + if (openflag<0 && bufmax>0 && curr 0) + moveright(&core[curr], &core[endd], rsize); + + cp = curr; + do { /* Insert loop */ + Dflag = (cp==0 || core[cp-1]==EOL); + do { + if (Dflag) + while ((cmd=peekc()) == '' || cmd == '') { + if (readchar() == '') + currDLE = min(COLS,currDLE+shiftwidth); + else + currDLE = max(0,currDLE-shiftwidth); + mvcur(-1, currDLE); + } + } while (!(c = line(core, cp, endd-1, &len))); + if (Dflag && (len > 0 || c == ESC)) { + /* makeDLE : optimize leading whitespace for insert */ + currDLE = findDLE(cp, &rp, cp+len, currDLE); + if (rp > cp) { + len -= (rp-cp); + moveleft(&core[rp], &core[cp], len); /* squash whitespace */ + } + if (currDLE > 0) { /* create DLE indent */ + ts = currDLE / tabsize; + ss = currDLE % tabsize; + moveright(&core[cp], &core[cp+ts+ss], len); + len += (ts+ss); + fillchar(&core[cp ], ts, TAB); + fillchar(&core[cp+ts], ss, 32); + } + } + cp += len; + if (c == EOL) { /* Diddle-Diddle */ + core[cp++] = EOL; /* add in a \n */ + strput(CE); /* clear this line */ + println(); + if (visual) { +#if OS_RMX + /* at OL at bottom kludge... */ + if (OL && (*yp) < LINES-2) { +#else + if (OL) { +#endif + strput(OL); + (*yp)++; + } + else + strput(CE); + } + if (!autoindent) /* reset currDLE? */ + currDLE = 0; + mvcur(-1, currDLE); + } + } while (c != ESC && cp <= endd-INSSIZE); + *dp = cp; /* start display here */ + + if (count > 1) { /* repeated insertion */ + len = cp-curr; + if ((count-1)*len < endd-cp) + for (i = 1;i curr && core[cp-1] != EOL)) + core[cp++] = EOL; + len = cp-curr; + + if (rsize > 0) /* if not at end of buffer, stitch things together */ + moveleft(&core[endd], &core[cp], rsize); + insert_to_undo(&undo, curr, len); + core[bufmax] = EOL; + return(cp); +} diff --git a/src/cmd/levee/levee.h b/src/cmd/levee/levee.h new file mode 100644 index 0000000..1e45476 --- /dev/null +++ b/src/cmd/levee/levee.h @@ -0,0 +1,386 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1980-2008 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + * + * Levee v3.C + * C version for Unix/Atari ST/MS-DOS/OS-2/FlexOs/iRMX/etc + * Pascal version for UCSD Pascal 4.X + * + * written fall 82' - now (approx) by David L. Parsons. + * + * many patches, suggestions, + * and impractical design goals by: + * Jim Bolland, + * John Plocher, + * John Tainter + */ +#ifndef LEVEE_D + +#define LEVEE_D + +#include "config.h" + +#ifndef TRUE +#define TRUE (1) /* Nobody defines TRUE & FALSE, so I will do */ +#define FALSE (0) /* it myself */ +#endif + +#define HANDLE int /* default file handle type */ + +#define PROC /* for magic function types (MSDOS) */ +#define VOID void /* ancient creaking C compilers won't understand void */ + +/* + * Compilation defines for different systems. + */ + +#if OS_ATARI + +#include + +#define void int /* Alcyon C don't know void */ + +/* extractions from osbind.h */ +#define OPEN_OLD(n) gemdos(0x3d,n,/*open mode*/0) +#define OPEN_NEW(n) gemdos(0x3c,n,/*permissions*/0) +#define CLOSE_FILE(f) gemdos(0x3e,f) +#define SEEK_POSITION(f,o,m) gemdos(0x42,(long)(o),f,m) +#define READ_TEXT(f,b,c) gemdos(0x3f,f,(long)(c),b) +#define WRITE_TEXT(f,b,c) gemdos(0x40,f,(long)(c),b) + +extern char *malloc(); +extern long gemdos(); + +#endif /*OS_ATARI*/ + +#if OS_RMX +#include <:inc:stdio.h> +#include <:inc:udi.h> + +#define OPEN_OLD(n) open(n, /*open mode*/0) +#define OPEN_NEW(n) creat(n,/*permissions*/0) +#define CLOSE_FILE(f) close(f) +#define SEEK_POSITION(f,o,m) lseek((f),(long)(o),(m)) +#define READ_TEXT(f,p,c) read((f),(p),(unsigned)(c)) +#define WRITE_TEXT(f,p,c) write((f),(p),(unsigned)(c)) + +#define zwrite(p,s) write(1,(p), (unsigned)(s)) + +#endif /*OS_RMX*/ + +#if OS_DOS + +#include +#include + +#define OPEN_OLD(n) open(n, O_RDONLY|O_BINARY) +#define OPEN_NEW(n) open(n, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666) +#define CLOSE_FILE(f) close(f) +#define SEEK_POSITION(f,o,m) lseek(f, (long)(o), (m)) +#define READ_TEXT(f,p,c) read(f, p, (int)(c)) +#define WRITE_TEXT(f,p,c) write(f, p, (int)(c)) + +#define zwrite(p,s) WRITE_TEXT(fileno(stdout), p, s) + +#undef PROC +#define PROC _fastcall + +#include "proto.h" + +#endif /*OS_DOS*/ + +#if OS_UNIX + +#include +#include +#include +#include +#include + +#define OPEN_OLD(n) open(n, O_RDONLY) +#define OPEN_NEW(n) open(n, O_WRONLY|O_CREAT|O_TRUNC, 0666) +#define CLOSE_FILE(f) close(f) +#define SEEK_POSITION(f,o,m) lseek(f, (long)(o), (m)) +#define READ_TEXT(f,p,c) read(f, p, (int)(c)) +#define WRITE_TEXT(f,p,c) write(f, p, (int)(c)) + +#define zwrite(p,s) fwrite(p, 1, s, stdout) + +#endif /*OS_UNIX*/ + +#if OS_FLEXOS + +#include + +#define OPEN_OLD(n) s_open(m,0x08) /* note reversed parameters! */ +#define OPEN_NEW(n) s_create(0,0,n,0,0/*mode*/,0) +#define CLOSE_FILE(f) s_close(0,f) /* Full close on handle */ +#define SEEK_POSITION(f,o,m) s_seek((m&03)<<9, f, o) +#define READ_TEXT(f,p,c) s_read(0x0100,(long)(f),p,(long)(c),0L) +#define WRITE_TEXT(f,p,c) s_write(0x0101,(long)(f),p,(long)(c),0L) + +#define zwrite(p,s) s_write(0x0101, 1L, p, (long)(s),0L) + +#define unlink(n) s_delete(0, n) +#define rename(a,b) s_rename(0, a, b) + +/* OPEN_OLD mode flags */ + +#undef HANDLE +#define HANDLE long + +#endif /*OS_FLEXOS*/ + +#define bool int + +/* ttydef stuff */ +#if !(OS_ATARI | USE_TERMCAP) + +#ifndef LINES +#define LINES 25 +#endif /*LINES*/ +#define COLS 79 + +#endif + +#define YES 1 +#define NO 0 + +#define UPARROW 11 +#define DNARROW 10 +#define LTARROW erase +#define RTARROW 12 + +#if !USE_TERMCAP +#define CA TRUE +#if !(OS_DOS||OS_FLEXOS) +#define canUPSCROLL 1 +#endif +#endif + +/* nospecific stuff */ +#define MAGICNUMBER 42 +#define hell_freezes_over FALSE +#define BUGS 7 /* sometime when you least expect it.. */ + +#define DW 23 /* Delete Word */ +#define EOL 10 /* End Of Line */ +#define DLE 16 /* Space compression lead-in */ +#define ESC 27 /* Escape */ + +/* hardwired line kill and erase character for non-unix machines */ +#define DEL 21 /* ^U */ +#if RMX +#define ERASE 127 +#else +#define ERASE 8 /* ^H */ +#endif + +#define TAB 9 + + /* variable types */ +#define VBOOL 0 +#define VINT 1 +#define VSTR 2 + +#define ERR (-1) + + /* Undostack commands */ +#define U_ADDC 'A' +#define U_MOVEC 'M' +#define U_DELC 'D' + + /* magic things for find */ +#define MAXPAT ((int)300) + + /* exec mode commands */ +#define EX_CR (ERR-1) +#define EX_PR 0 +#define EX_QUIT 1 +#define EX_READ 2 +#define EX_EDIT 3 +#define EX_WRITE 4 +#define EX_WQ 5 +#define EX_NEXT 6 +#define EX_SUBS 7 +#define EX_XIT 8 +#define EX_FILE 9 +#define EX_SET 10 +#define EX_RM 11 +#define EX_PREV 12 +#define EX_DELETE 13 +#define EX_LINE 14 +#define EX_YANK 15 +#define EX_PUT 16 +#define EX_VI 17 +#define EX_EX 18 +#define EX_INSERT 19 +#define EX_OPEN 20 +#define EX_CHANGE 21 +#define EX_UNDO 22 +#define EX_ESCAPE 23 +#define EX_MAP 24 +#define EX_UNMAP 25 +#define EX_SOURCE 26 +#define EX_VERSION 27 +#define EX_ARGS 28 +#define EX_REWIND 29 + + /* movement return states */ +#define LEGALMOVE 0 +#define BADMOVE 1 +#define ESCAPED 2 +#define findstates char + + /* command codes */ +#define BAD_COMMAND 0 + /*visual movement*/ +#define GO_RIGHT 1 +#define GO_LEFT 2 +#define GO_UP 3 +#define GO_DOWN 4 +#define FORWD 5 +#define TO_WD 6 +#define BACK_WD 7 +#define BTO_WD 8 +#define NOTWHITE 9 +#define TO_COL 10 +#define TO_EOL 11 +#define MATCHEXPR 12 +#define TO_CHAR 13 +#define UPTO_CHAR 14 +#define BACK_CHAR 15 +#define BACKTO_CHAR 16 +#define SENT_FWD 17 +#define SENT_BACK 18 +#define PAGE_BEGIN 19 +#define PAGE_END 20 +#define PAGE_MIDDLE 21 +#define CR_FWD 22 +#define CR_BACK 23 +#define PATT_FWD 24 +#define PATT_BACK 25 +#define FSEARCH 26 +#define BSEARCH 27 +#define GLOBAL_LINE 28 +#define TO_MARK 29 +#define TO_MARK_LINE 30 +#define PARA_FWD 31 +#define PARA_BACK 32 + /*modifications*/ +#define DELETE_C 39 +#define EXEC_C 40 +#define ADJUST_C 41 +#define CHANGE_C 42 +#define YANK_C 43 +#define INSERT_C 44 +#define APPEND_C 45 +#define I_AT_NONWHITE 46 +#define A_AT_END 47 +#define OPEN_C 48 +#define OPENUP_C 49 +#define REPLACE_C 50 +#define TWIDDLE_C 51 +#define RESUBST_C 52 +#define JOIN_C 53 +#define UNDO_C 54 +#define BIG_REPL_C 55 +#define PUT_BEFORE 56 +#define PUT_AFTER 57 + /*everything else*/ +#define HARDMACRO 70 +#define REWINDOW 71 +#define ZZ_C 72 +#define DEBUG_C 73 +#define FILE_C 74 +#define WINDOW_UP 75 +#define WINDOW_DOWN 76 +#define REDRAW_C 77 +#define MARKER_C 78 +#define REDO_C 79 +#define EDIT_C 80 +#define COLIN_C 81 + /*macros*/ +#define SOFTMACRO 100 +#define INSMACRO 101 +#define cmdtype char + + /* exec mode states */ +#define E_VISUAL 0 +#define E_INIT 1 +#define E_EDIT 2 +#define exec_type char + + /* various sizes */ +#define INSSIZE ((int)80) /* Insert string size */ +#define FSIZE ((int)39) /* File string size */ +#ifndef SIZE +# define SIZE ((int)32760) /* Edit buffer size */ +#endif + +#define SBUFSIZE ((int)4096) /* Incore yank buffer size */ +#define MAXMACROS 32 /* Maximum # of macros */ +#define NMACROS 9 /* Nexting level for macros */ + +#define PAGESIZE ((int)1024) /* Bytes per block */ + +struct coord { /* Screen Coordinate */ + int x,y; +}; + +struct ybuf { /* Yank Buffer */ + int size; /* Bytes yanked */ + bool lines, /* Yanked whole lines? */ + has_eol; /* Yanked a EOL? */ + char stuff[SBUFSIZE]; /* The stuff */ +}; + +struct undostack { /* Undo Stack Descriptor */ + int blockp, /* block address of core block */ + ptr; /* offset within coreblock */ + int coreblock[PAGESIZE]; /* core block */ +}; + +union optionrec { /* Black Magic Option Structure */ + int valu; /* if integer, the value */ + char *strp; /* or if string, a pointer to it */ +}; + +struct macrecord { /* Macro Descriptor */ + char token; /* Character mapped */ + cmdtype oldmap; /* Old value in movemap */ + char *m_text; /* Replacement text */ +}; + +struct tmacro { /* For running a macro */ + char *mtext, /* Pointer to macro text */ + *ip; /* Pointer into macro text */ + int m_iter; /* Number of times to execute */ +}; + +#define V_CONST 1 /* this option cannot be modified */ +#define V_DISPLAY 2 /* this option affects the display */ + +struct variable { /* Settable Variable Record */ + char *v_name; /* full name */ + char *v_abbr; /* abbreviated name */ + int v_tipe; /* what kind of variable */ + int v_flags; /* special attributes... */ + union optionrec *u; /* pointer to it */ +}; +#endif /*LEVEE_D*/ diff --git a/src/cmd/levee/lv.1 b/src/cmd/levee/lv.1 new file mode 100644 index 0000000..0024e6f --- /dev/null +++ b/src/cmd/levee/lv.1 @@ -0,0 +1,955 @@ +.TH LEVEE 1 "29 August 1998" "Mastodon Linux" +.SH NAME +.B levee +\- +A Screen Oriented Editor. +.SH SYNOPSIS +.B levee +[\fI+address\fR] [\fIfile \fB...\fR] +.SH DESCRIPTION +Levee is a screen oriented editor based on the Unix editor +"vi". It provides a terse, powerful way to enter and edit text +(however, if you want a word-processor, you're better off with +WordStar.) + +Levee is a moded editor. It operates in 3 modes -- visual, +command, and insert. Most of the editing work is done is visual +mode, file reading and writing is done in command mode, and +insert mode does what you would expect. +.PP +When you enter Levee, you may specify an address to start +editing at. These addresses are in the same format as command +mode addresses, except that a naked + will put you at the very +end of the file. +.PP +Levee is copyright (c) 1982-2008 by David L. Parsons. (see +the notice at the end of this document for distribution terms) + +.SH "COMMAND MODE COMMANDS" + +These commands are used for editing new files, writing +modified files, changing options, doing substitutions, and +a subset of the visual commands. They take as input whole +lines, terminated by return (to execute), or escape (to +abort.) + +Command mode is reached by typing ":" or "Q" from visual +mode. If you enter command mode by typing ":", Levee will +execute one command, then return to visual mode after +prompting you with "[more]". If you type anything except +a space or return, Levee will accept another command, and so +forth. If, however, you enter command mode via "Q", Levee +will remain in command mode until you enter the "visual" +command. + + +.SS "A NOTE ON COMMAND SYNTAX" +.PP +A command may be preceded by an optional line-range. If +you do not provide a line-range, Levee will use the default +line-range shown by the command. A line-range is one or two +address specifications in the following format: + +.RS +(\fB.\fR|\fB$\fR|\fB'x\fR|\fB#\fR) [ (\fB+\fR|\fB-\fR) (\fB/\fIpatt\fB\fB/\fR|\fB?\fIpatt\fB?\fR|\fB#\fR) ] +.TP +.B \. +current line. +.TP +.B $ +last line. +.TP +.B 'x +the line with mark x on it. +.TP +.B # +line #. +.RE + +.PP +For example, ".-5,.+5p" will print every line within ten +lines of the current line. "$-5" is the fifth line from the +end of the file, and "/end/+2" is the second line past the +next occurrence of the pattern "end". Patterns may be +regular expressions (see below.) + +Also, a naked line-range will set the current line to +the first line in the range and print all the lines in that +range. "1,10" sets the current line to 1, then prints lines +1 to 10. + +If you specify a non-existent line in a range, the command + will abort and Levee will tell you "bad address". + +.SS "Command mode commands" + +.TP +.B args +show the current argument list, if one exists. The file that you +are currently editing will be framed by '[' and ']'. + +.TP +.IB (.,.) change +delete lines, then enter insert mode. + +.TP +.IB (.,.) delete +delete lines. Deleted lines are stored in a Yank Buffer for +later putback with "put". + +.TP +.B "edit[!] [file]" +Discard the current file and start editing a new one. If +changes were made to the current file, you must enter "edit!" +to force Levee to discard the changes. If you do not specify +a filename, Levee will try to reedit the current filename. + +When Levee reads in a new file, it will tell you how many +bytes it read in, or [overflow] if the file is larger than the +internal buffer (256000 bytes on most platforms; 20k on USCD +Pascal.) + +.TP +.B execmode +Remain in command mode until you use the "visual" command. + +.TP +.BI file [name] +Echo what the current filename is, its status, and the current +line. If you provide it with a name, it will change the filename +to that. + +.TP +.IB (.) insert +Insert text above the current line. If you specify a line number, +Levee will make that the current line, then insert above it. + +.RS +.SS "Insert mode commands" +.TP +.B ^W +back over the last word you entered. +.TP +.B ^H +back over one character. +.TP +.B ^U +back over all input on this line. +.TP +.B ^V +escape the next character typed. (For example, +.B ^V^H +will put a ^H into the file.) +.TP +.B ESC +exit insert mode. +.TP +.B ^D +If at start of line, reduce indentation 'shiftwidth' columns. +.TP +.B ^T +If at start of line, increase indentation 'shiftwidth' columns. +.RE + +.PP + +When in insert mode, Levee will not allow you to enter any control +characters except return and tab. Return ends input on this line and +opens a new line for input. + +.TP +.BI map[!] [key [text]] +Define/list macros. There are 3 forms of map: +.TP +.I map. +This lists all the active macros. +.TP +.IR map (key). +This shows the macro associated with (key), if any. +.TP +.IR map "(key) (text)" +This maps (key) to (text). You may map any +key except ":" and escape. In the normal +form (map), the macro will be effective +in visual mode, but in the alternate form, +(map!), the macro will be effective in +insert and command modes. + +.PP +For example, if you map!ped return to "hello world", every time +you entered a return in command or visual mode, the string "hello +world" would pop up. + +.TP +.BI next [file ...] +Edit the next file in the arglist, or edit a new arglist. Levee +takes its initial arglist off the command line when you execute it. +If "autowrite" is set, Levee will write out the changes to the +current file before editing the next one. + +.TP +.IB (.) open +Insert below the current line. Otherwise just like insert. + +.TP +.B previous +Edit the previous file in the arglist. Otherwise, like next. + +.TP +.IB (.,.) print +Display lines without changing the current line. + +.TP +.IB (.) put +Put the contents of the yank buffer back on the line below +the current line. If you specify a line, it resets the current +line, then puts the yank buffer back. The yank buffer is filled +by the delete, change, or yank commands. Put does not destroy +the yank buffer, so you may put back text multiple times. + +.TP +.B quit[!] +Exit Levee. If you want to discard changes, use "quit!" + +.TP +.IB (.) read [file] +put the contents of 'file' after the current line. + +.TP +.BI rm file +Delete 'file' from disk. + +.TP +.BI set [option=value] +Set a tunable variable. Levee has a dozen or so user-definable +variables which you can twiddle via this command. There are boolean, +integer, and string variables that you can set. A string or integer +variable is set by 'set xxx=yyy', a boolean variable is set via +'set xxx' or 'set noxxx'. + +Here are the settable variables (and abbreviations): +.TP +.BI tabsize (ts) +tab stop. +.TP +.BI shiftwidth (sw) +columns to shift on ^D, ^T, >>, or << +.TP +.B scroll +number of lines to scroll on ^D, ^U +.TP +.BI autoindent (ai) +supply indentation during insert mode. +.TP +.BI autowrite (aw) +write out changes before :next, :prev +.TP +.BI autocopy (ac) +make backup copies before writing changes. +.TP +.B list +display tabs as ^I, end of line as $. +.TP +.B magic +use regular expressions in searches. +.TP +.B suffix +if the filename does not have a . in +it, supply the suffix. (this is the +only string variable.) +.TP +.BI overwrite (ow) +destroy old file first, then write. +.TP +.BI beautify (be) +When set, Levee will not allow insert +of any control character except tab +and return unless you escape it with +ctrl-V. +.TP +.B wrapscan +searches wrap around end of buffer. +.TP +.BI ignorecase (ic) +Ignore the case of alphabetic characters +during searches. +.TP +.B "mapslash" +(ST version only) Map '/' in filenames to +'\\'. If the environment contains `mapslash' +when levee is called, this variable will +default to true, otherwise it defaults to +false. (See the documentation for the +Teeny-shell on how the teeny-shell interprets +`mapslash') +.TP +.BI lines (li) +(ST version only) How many lines on the display. +This is primarily for running levee through +the serial port - put set li=xx into your +LVRC for a xx line terminal. +.TP +.BI cols (co) +(ST version only) How many columns on the +display. Like the lines variable, it's for +running levee through the serial port. + +.PP +You may set multiple variables on one line, as in 'set ws noai'. +To see the current settings of these variables, :set -- without any +arguments -- will show the current settings. + +At startup, Levee looks in the environment variable LVRC for +a list of variables to set (GEMDOS/MS-DOS). LVRC is one line +of the form 'option=value ...'. If you have a LVRC defined that +is 'ts=4 ow nows', Levee will set tabsize to 4, turn on overwrite, +and turn off wrapscan. + +If you are using RMX, Levee looks in the file ":home:r?lvrc" +for initialization. If you are using Osy/SWOs, Levee looks in the +file "*.lvrc". The format of these files are different from the +LVRC variable -- see "source" for more information. + +.TP +.BI source file +Take command mode commands from 'file'. These commands can be +any legal command, except "visual". If a error happens during +execution of 'file', Levee abandons that level of source'ing. + +In Osy/SWOs, there are a few differences in insert mode from +within a sourced file. No character has special meaning except a +line containing nothing but a period, which terminates insert mode. +For example: + +.RS +:commands +.br +. +.br +. +.br +:insert +.br +blah blah blah blah blah blah +.br +blah blah blah blah blah blah +.br +blah blah blah blah blah blah +.br +. +.br +:more commands +.RE + +If you are running Levee under any other operating system, +you cannot do a insert from a :source file. + +.TP +.B (.,.)substitute(delim)patt(delim)repl(delim)[qcpg] +.TP +.B (.,.)substitute& + +Search for patt and replace it with repl. Levee will look for +patt once on each line and replace it with repl. The delimiter +may be any ascii character. + +The pattern is a regular expression, just like a search pattern. + +You may include parts of the pattern in the replacement string; +A '&' in the replacement pattern copies in the whole source pattern, +so if you do a 'sub/this/& and that/g', every instance of 'this' +will be replaced with 'this and that'. Also, you may pull parts of +the pattern out by using the \\( and \\) argument meta-characters. +Arguments gotten by \\( & \\) are put into the replacement string +everywhere you do a \\1..\\9 [ \\1 is the first argument you set up +with \\( & \\) ]. So, if you want to reverse the order of two substrings, +you can do 'sub/\\(string1\\)\\(string2\\)/\\2\\1/'. + +substitute& redoes the last substitution. + +Options: +.TP +.B q,c +before doing the substitute, display the affected +line and wait for you to type a character. If you +type 'y', it will do the substitution. 'q' aborts +the substitute, 'a' does the rest of the change +without prompting, and 'n' does not do it. +.TP +.B p +print the affected lines after the change. +.TP +.B g +do the change globally. That is, do it for every +occurence of patt on a line, rather than just +once. +.PP + +.TP +.B undo +Undo the last modification to the file (except :edit, :next, :rm, +or :write.) You can only undo the last change to a file -- undo counts +as a change. :undo followed by :undo does nothing to the file. + +.TP +.BI unmap (key) +Undefine a macro (see map). + +.TP +.BI visual [list] +If you entered command mode by "Q" or "execmode", return to +visual mode. If you provide an argument list, it also does a +`:next' on that list. + +.TP +.B version +Show which version of levee this is. + +.TP +.IB (.,.) "write \fI[file]" +Write lines to a file. If you write the everything to 'file', +the filename is set to 'file', and if you do not specify a file, +Levee will write to the filename. + +.TP +.IB (.,.) "wq \fI[file]" + Write to a file, then quit. + +.TP +.IB (.,.) yank +Yank lines from the file into the yank buffer, for later +putback with "put". + +.TP +.B xit[!] +Write changes to the current file, then exit. If there are +more files in the arglist, use "xit!" + +.TP +.B ![command] +Execute command. + +Example: + +.RS +!ls => does a 'ls'. +.RE + +This command is available only under GEMDOS, MSDOS, RMX, and +Unix. + +.TP +.B ($)= +Give the line number of the addressed line. /end/= gives you +the line number of the next line with a 'end' on it. + + +.SH "VISUAL MODE COMMANDS" +Visual mode commands move you around and modify the file. +There are movement commands to move the cursor by a variety of +objects. + +In the description, a (#) means a optional count. If a +command has a optional count, it will tell you what the count +does in parenthesis. A (*) means that the command can be used +in the delete, yank, and change commands. + +Counts are made up by entering digits. If you type '45', +the count will be set to 45. To cancel a count, type ESC. + +This section discusses 'whitespace' occasionally. +Whitespace is tabs, spaces, and end of line. + +.SS "How the display works" + +Characters are displayed on the screen as you would +expect, except that nonprinting characters are shown as ^x, +and tabs expand to spaces ( unless you set the option list, +then they show as ^I.) When sitting on a control character or +tab, the cursor is placed on the FIRST character displayed. If +you move the cursor to any other part of them ( via j or k -- +see below), any changes will start at the next character. + +Levee does not display a end of file marker, but lines +past the end of the file are denoted by ~ lines. + +If list is set, tabs display as ^I, and the end of line +displays as $. + +If a line is too long for the screen, it will just disappear off the end of the screen. + +Levee will handle any screen resolution and any monospaced +font you hand it ( if you are running in low resolution, Levee +will give you a 25x40 window, for example.) + +.SS "Visual mode commands" +.TP +.B ^A +Show a debugging message at the bottom of the screen. This is not at +all useful unless you are debugging the editor. Ignore it. + +.TP +.B (#)^D +Scroll the screen down a half screen. If a count is specified, scroll +down the specified number of lines. + +.TP +.B ^E +Scroll down 1 line (shorthand for 1^D ) + +.TP +.B ^G +Show file statistics. Exactly like ':file'. + +.TP +.IB (*) (#)^H +Move the cursor left one (count) chars. + +.TP +.B ^I +Redraw the screen. + +.TP +.IB (*) (#)^J +Move down one (count) lines. When you use ^J and ^K (below) to move +up or down lines, the cursor will remain in the same column, even if +it is in the middle of a tabstop or past the end of a line. + +.TP +.IB (*) (#)^K +Move up one (count) lines. +.TP +.IB (*) (#)^L +Move right one (count) characters. +.TP +.IB (*) (#)^M +Move to the first nonwhite space on the next line. If a count is specified, +move to the first nonwhite count lines down. +.TP +.B (#)^U +Scroll the screen up a half page. If a count is specified, scroll up +count lines. + +.TP +.B ^Y +Scroll the screen up 1 line (shorthand for 1^U.) + +.TP +.B (#)a +Insert text AFTER the cursor. If you give a count, the insertion will +be repeated count times ( 40i-ESC will give you a line of 40 dashes). + +The commands in insert mode are the same for visual and command mode. + +.TP +.IB (*) (#)b +Move to the beginning of the last word (the count'th word back). +A word is a collection of alphanumeric characters (a-z0-9$_#) or +any other nonwhite character (i.e. anything but space, tab, eoln). + +.TP +.B c +Change a object. Change deletes an object, then enters insert mode without +redrawing the screen. When you tell it the object to be changed, Levee +puts a '$' on the last character of the object. You cannot change +backwards. + +The object may be any visual mode command marked with a '(*) '. For +example, 'c4l' will change the next 4 characters on the line to something +else. (4cl does the same thing -- 4c4l changes the next 16 characters on +this line.) + + 'cc' will change whole lines. + +When changing, deleting, or yanking a object, it will be placed into +a yank buffer, where it can be retrieved by the 'p' or 'P' commands. + +.TP +.B (#)d +Delete an object. Like 'cc', 'dd' affects whole lines. + +.TP +.IB (*) (#)e +Move to the end of the current word. + +.TP +.IB (*) (#)f(x) +Find the next (count'th) occurance of a character on the current line. +For example, if the cursor is sitting on the first character of the +line 'abcdef', typing "ff" will put the cursor on the 'f'. + +.TP +.IB (*) (#)h +Move left one (count) characters. Exactly like ^H. + +.TP +.B (#)i +Start inserting characters at the cursor. If you specify a count, +the insertion will be duplicated count times. + +.TP +.IB (*) (#)j +Move down one (count) lines. Exactly like ^J. + +.TP +.IB (*) (#)k +Move up one (count) lines. Exactly like ^K. + +.TP +,B (*) (#)l +Move right one (count) character. Exactly like ^L. + +.TP +.B m(x) +Set the marker (x). There are 26 markers available (a-z). You may +move to a marker by use of the ' or ` commands. + +.TP +.IB (*) n +Find the next occurance of a search pattern. When you do a search with +a / or ? command, Levee will remember the pattern and the direction you +searched in. 'n' will search in the same direction for the pattern, 'N' +searches in the opposite direction. + +.TP +.B o +Open a line below the current line for insertion. + +.TP +.B p +Put yanked/deleted text back after the cursor. Text is yanked +by the delete (d,x,X,D), change (c,C,s,S), and yank (y,Y) commands. + +.TP +.B (#)r(x) +Replace characters (up to end of line) with (x). '4ra' will change the +next 4 characters after the cursor into 'aaaa'. + +.TP +.B (#)s +change one (count) characters. Shorthand for (#)cl. + +.TP +.IB (*) (#)t(x) +Move up to a character on the current line. If you are on the first +character of the line 'abcdef' and you type 'tf', you will end up sitting +on the 'e'. + +.TP +.B u +Undo last modification. You can undo ANY modification command except +:edit, :next, :rm, or :write. (Just like :undo). + +.TP +.IB (*) (#)v +Move back to the very end of the previous (count'th) word. +See 'b' for the definition of a word. + +.TP +.IB (*) (#)w +Move up to the very beginning of the next (count'th) word. + +.TP +.B (#)x +Delete one (count) characters forward. Shorthand for (#)dl. + +.TP +.B y +Yank an object for later use by put. 'yy' yanks whole lines. + +.TP +.B A +Append text at the end of the line. Shorthand for $a. + +.TP +.IB (*) (#)B +Move to the beginning of the current word. Exactly like 'b'. + +.B NOTE: +this is incorrect. the capitalized word movement commands should, +and will in the future, be used for movement by space-delimited words. + +.TP +.B C +Change to the end of the line. Shorthand for c$. + +.TP +.B D +Delete to the end of the line. Shorthand for d$. + +.TP +.IB (*) (#)F(x) +Move to the first (count'th) previous occurance of a character on the +current line. If you are sitting at the end of the line 'abcdef', typing +"Fa" will move you back to the 'a' at the start of the line. + +.TP +.IB (*) (#)G +Goto line. If you specify a count, Levee will move to that line, and if +there is no count, Levee moves to the absolute end of the file. + +To get to the start of the file, type "1G". To the end, just "G". + +.TP +.IB (*) H +Move to the first nonwhite character at the top of the screen. + +.TP +.B I +Insert at the end of the current line. Shorthand for $i. + +.TP +.B (#)J +Join two (count+1) lines together. Joining appends the second line at +the end of the first, putting a space between them. If the first line +ends in whitespace, Levee will not put in a space. + +.TP +.IB (*) L +Move to the last nonwhite character on the last line of the screen. + +.TP +.IB (*) M +Move to the first nonwhite character in the middle of the screen. + +.TP +.B O +Open a line above the current line. Otherwise works just like 'o'. + +.TP +.B P +Put back the yank buffer at the cursor. Otherwise works just like 'p'. + +.TP +.B Q +Enter and remain in command mode. Just like the command :exec. To get +back to visual mode, you must enter the command ':visual'. + +.TP +.B R +Replace mode. A limited subset of insert mode that overwrites characters +up to end of line. All of the normal insert mode commands apply. +If you overwrite a character, then back over it with ^H,^U, or ^W, it +will reappear after you exit Replace mode. + +Escape exits replace mode. + +.B NOTE: +due to a bug, entering a in Replace mode will drop you +back into visual mode with an error. The replacements you have made +will remain. + +.TP +.B S +Change characters backwards. Shorthand for (#)ch. + +.TP +.IB (*) (#)T(x) +Move back to character on current line. If you are on the last character +of the line 'abcdef', typing "Ta" will move you back to the 'b'. + +.TP +.IB (*) (#)W +Move to end of word. Exactly like 'e'. + +.TP +.B (#)X +Delete characters backwards. Shorthand for (#)dh. + +.TP +.B Y +Yank to end of line. Shorthand for y$. + +.TP +.B ZZ +Write changes to current file and exit if last file in arglist. +Exactly like :xit. + +.TP +.IB (*) (#)$ +Move to end of line. If you give a count, move to the end of the (count-1) +line down (so 2$ moves you to the end of the next line.). + +.TP +.B 0 +Move to the beginning of the current line. Shorthand for 0|. + +.TP +.B (#)! +Pipe an object through an external program. Like 'cc', '!!' affects whole lines. + +.TP +.IB (*) % +Find matching bracket, parenthesis, or squiggly bracket. If you are not +sitting on a '[]{}()', Levee will search forward for one of them on the +current line, then match whatever it finds. + +.TP +.B [space] +Move to the first nonwhite character on the current line. + +.TP +.B & +Redo last substitution command. + +.TP +.IB (*) (#){ +Move to the beginning of the count'th paragraph back. A paragraph is +delimited by a blank line. + +.TP +.IB (*) (#)} +Move to the end of the count'th paragraph forward. + +.TP +.IB (*) (#)( +Move to the beginning of the count'th sentence back. A sentence is +delimited by a ., a !, or a ? followed by a space, a tab, or end of line. + +.TP +.IB (*) (#)) +Move to the end of the count'th sentence forward. + +.TP +.IB (*) (#)- +Move to the (count'th) previous line, first nonwhite. + +.TP +.IB (*) (#)+ +Move to the (count'th) next line, first nonwhite. + +.TP +.B (#)~ +Change the case of the next count characters. Upper case becomes lowercase, +lowercase becomes uppercase. + +.TP +.IB (*) `(x) +Move to the exact position of mark (x). There is a special mark for some +of the visual mode move ment commands -- '' will move you to where you +were before the last (,),',`,G,/,?,n,N command. + +.TP +.B : +Execute one command mode command. When the command is done, it will return +to visual mode if it produces one line of output, but if it scrolls the +screen, Levee will prompt [more] before returning to visual mode. If you +type a : in response to the [more] prompt, Levee will remain in command +mode for one more command. + +.TP +.B (#)<(#) +Shift one (count) objects left. If you specify a second count, Levee will +shift the object left that many columns -- if you do not, they will be sh +shifted shiftwidth columns. + +This is a nondestructive shift. If the shift would carry past the left +margin, the objects will be moved up to the left margin but no farther. + +Like the other object movement commands, '<<' will affect whole lines. + +.TP +.B (#)>(#) +Shift one (count) objects right. Just like <, except it will not shift +objects past the right margin of the screen. If you do shift an object +past the right margin of the screen, all of its indent will be removed +and it will end up by the left margin. + +.TP +.B \. +Repeat last modification command. (except undo) + +.TP +.IB (*) ? +Search for pattern backwards. Escape aborts the search pattern, and a +empty pattern means search for the last pattern again. + +.TP +.IB (*) / +Search for pattern forwards. Otherwise like ?. + +.TP +.B (#)| +Move to specified column. If you don't have a count, move to column 0. + +.SH "REGULAR EXPRESSIONS" + +Levee gives special meanings to some characters during +a pattern match. The character "." will match any one char, +the character "*" will match zero or more occurances of the +previous char ( so, a* will match 'a','aa','aaa', etc, or it +will match nothing at all). If a pattern begins with "^", it +will only match at the beginning of a line, and patterns +ending with a "$" will only match at the end of a line. + +Brackets ('[]') have special meaning as well. They mean +match any one of the characters inside the brackets. '[abc]' +will match 'a', 'b', or 'c'. You may specify a range of +characters inside brackets by using a dash (-). '[a-z]' will +match any lowercase alphabetic character. If ^ is the first +character in the bracket, it means match any character +except those in the brackets. '[^abc]' will match anything +except 'a','b', or 'c'. + +Backslash takes away special meaning for these chars, +but '\\t' specifies a tab, and \\( & \\) delimit arguments +inside a pattern (used only by :substitute.) The patterns +\\< and \\> have special meaning, too; they match the start +and end of alpha-numeric tokens. + +If you turn off the editor variable 'magic', none of +the above characters will have special meaning inside of +a pattern (see 'set'). + +Some example patterns: + +.TP +.B ^end$ +Find a line that is just 'end'. +.TP +.B [Ee][Nn][Dd] +Find a 'end', ignoring case. +.TP +.B [A-Za-z][A-Za-z0-9]* +Find the next identifier. +.TP +.B (\\*.*\\*) +Find the next one-line pascal comment. +.TP +.B \ +Find the next occurance of `the'. + + +.SH LIMITATIONS +Levee can only edit files up to 256000 characters long. ^M is used +as its internal line separator, so inserting ^M will have interesting +consequences. + +.SH BUGS +Probably infinite. + +.SH AUTHOR +.B "David L. Parsons" +.I (orc@pell.chi.il.us) +.br +Testing, suggestions, and impractical design goals by: +Jim Bolland. John Tainter. John Plocher. + +.SH COPYRIGHT +Copyright (c) 1982-2007 David L Parsons +.br +All rights reserved. +.br + +Redistribution and use in source and binary forms, without or +without modification, are permitted provided that the above +copyright notice and this paragraph are duplicated in all such +forms and that any documentation, advertising materials, and +other materials related to such distribution and use acknowledge +that the software was developed by David L Parsons (orc@pell.chi.il.us). +My name may not be used to endorse or promote products derived +from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR +PURPOSE. diff --git a/src/cmd/levee/lv.doc b/src/cmd/levee/lv.doc new file mode 100644 index 0000000..f8a5e2c --- /dev/null +++ b/src/cmd/levee/lv.doc @@ -0,0 +1,873 @@ + Levee. A Screen Oriented Editor. + + USAGE + lv [+address] [file ...] + + SYNOPSIS + Levee is a screen oriented editor based on the Unix editor + "vi". It provides a terse, powerful way to enter and edit text + (however, if you want a word-processor, you're better off with + WordStar.) + + DESCRIPTION + Levee is a moded editor. It operates in 3 modes -- visual, + command, and insert. Most of the editing work is done is visual + mode, file reading and writing is done in command mode, and + insert mode does what you would expect. + When you enter Levee, you may specify an address to start + editing at. These addresses are in the same format as command + mode addresses, except that a naked + will put you at the very + end of the file. + + Levee is copyright (c) 1982-1997 by David L. Parsons. (see + the notice at the end of this document for distribution terms) + + Levee. A Screen Oriented Editor. + COMMANDS + + Command mode commands: + + These commands are used for editing new files, writing + modified files, changing options, doing substitutions, and + a subset of the visual commands. They take as input whole + lines, terminated by return (to execute), or escape (to + abort.) + + Command mode is reached by typing ":" or "Q" from visual + mode. If you enter command mode by typing ":", Levee will + execute one command, then return to visual mode after + prompting you with "[more]". If you type anything except + a space or return, Levee will accept another command, and so + forth. If, however, you enter command mode via "Q", Levee + will remain in command mode until you enter the "visual" + command. + + A NOTE ON COMMAND SYNTAX + A command may be preceded by an optional line-range. If + you do not provide a line-range, Levee will use the default + line-range shown by the command. A line-range is one or two + address specifications in the following format: + + (.|$|'x|#) [ (+|-) (/patt/|?patt?|#) ] + + . => current line. + $ => last line. + 'x => the line with mark x on it. + # => line #. + + For example, ".-5,.+5p" will print every line within ten + lines of the current line. "$-5" is the fifth line from the + end of the file, and "/end/+2" is the second line past the + next occurrence of the pattern "end". Patterns may be + regular expressions (see below.) + + Also, a naked line-range will set the current line to + the first line in the range and print all the lines in that + range. "1,10" sets the current line to 1, then prints lines + 1 to 10. + + If you specify a non-existent line in a range, the comm- + and will abort and Levee will tell you "bad address". + + Regular expressions: + Levee gives special meanings to some characters during + a pattern match. The character "." will match any one char, + the character "*" will match zero or more occurances of the + previous char ( so, a* will match 'a','aa','aaa', etc, or it + will match nothing at all). If a pattern begins with "^", it + will only match at the beginning of a line, and patterns + ending with a "$" will only match at the end of a line. + + Levee. A Screen Oriented Editor. + Brackets ('[]') have special meaning as well. They mean + match any one of the characters inside the brackets. '[abc]' + will match 'a', 'b', or 'c'. You may specify a range of + characters inside brackets by using a dash (-). '[a-z]' will + match any lowercase alphabetic character. If ^ is the first + character in the bracket, it means match any character + except those in the brackets. '[^abc]' will match anything + except 'a','b', or 'c'. + + Backslash takes away special meaning for these chars, + but '\t' specifies a tab, and \( & \) delimit arguments + inside a pattern (used only by :substitute.) The patterns + \< and \> have special meaning, too; they match the start + and end of alpha-numeric tokens. + + If you turn off the editor variable 'magic', none of + the above characters will have special meaning inside of + a pattern (see 'set'). + + Some example patterns: + + ^end$ Find a line that is just 'end'. + [Ee][Nn][Dd] Find a 'end', ignoring case. + [A-Za-z][A-Za-z0-9]* Find the next identifier. + (\*.*\*) Find the next one-line pascal + comment. + \ Find the next occurance of `the'. + + Levee. A Screen Oriented Editor. + +--------------- + args + show the current argument list, if one exists. The file that you + are currently editing will be framed by '[' and ']'. + +--------------- + (.,.) change + delete lines, then enter insert mode. + +--------------- + (.,.) delete + delete lines. Deleted lines are stored in a Yank Buffer for + later putback with "put". + +--------------- + edit[!] [file] + Discard the current file and start editing a new one. If + changes were made to the current file, you must enter "edit!" + to force Levee to discard the changes. If you do not specify + a filename, Levee will try to reedit the current filename. + + When Levee reads in a new file, it will tell you how many + bytes it read in, or [overflow] if the file is larger than the + internal buffer (currently 32760 bytes.) + +--------------- + execmode + Remain in command mode until you use the "visual" command. + +--------------- + file [name] + Echo what the current filename is, its status, and the current + line. If you provide it with a name, it will change the filename + to that. + +--------------- + (.) insert + Insert text above the current line. If you specify a line number, + Levee will make that the current line, then insert above it. + + Commands within insert mode: + ^W => back over the last word you entered. + ^H => back over one character. + ^U => back over all input on this line. + ^V => escape the next character typed. + ^V^H will put a ^H into the file. + ESC => exit insert mode. + ^D => If at start of line, reduce indentation 'shiftwidth' + columns. + ^T => If at start of line, increase indentation + 'shiftwidth' columns. + + When in insert mode, Levee will not allow you to enter any control + characters except return and tab. Return ends input on this line and + opens a new line for input. + + Levee. A Screen Oriented Editor. +--------------- + map[!] [key [text]] + Define/list macros. There are 3 forms of map: + + 1) map. This lists all the active macros. + 2) map (key). This shows the macro associated with (key), + if any. + 3) map (key) (text) + This maps (key) to (text). You may map any + key except ":" and escape. In the normal + form (map), the macro will be effective + in visual mode, but in the alternate form, + (map!), the macro will be effective in + insert and command modes. + + For example, if you map!ped return to "hello world", every time + you entered a return in command or visual mode, the string "hello + world" would pop up. + +--------------- + next [file ...] + Edit the next file in the arglist, or edit a new arglist. Levee + takes its initial arglist off the command line when you execute it. + If "autowrite" is set, Levee will write out the changes to the + current file before editing the next one. + +--------------- + (.) open + Insert below the current line. Otherwise just like insert. + +--------------- + previous + Edit the previous file in the arglist. Otherwise, like next. + +--------------- + (.,.) print + Display lines without changing the current line. + +--------------- + (.) put + Put the contents of the yank buffer back on the line below + the current line. If you specify a line, it resets the current + line, then puts the yank buffer back. The yank buffer is filled + by the delete, change, or yank commands. Put does not destroy + the yank buffer, so you may put back text multiple times. + +--------------- + quit[!] + Exit Levee. If you want to discard changes, use "quit!" + +--------------- + (.) read [file] + put the contents of 'file' after the current line. + +--------------- + rm file + Delete 'file' from disk. + + Levee. A Screen Oriented Editor. +--------------- + set [option=value] + Set a tunable variable. Levee has a dozen or so user-definable + variables which you can twiddle via this command. There are boolean, + integer, and string variables that you can set. A string or integer + variable is set by 'set xxx=yyy', a boolean variable is set via + 'set xxx' or 'set noxxx'. + + Here are the settable variables (and abbreviations): + tabsize (ts) tab stop. + shiftwidth (sw) columns to shift on ^D, ^T, >>, or << + scroll number of lines to scroll on ^D, ^U + autoindent (ai) supply indentation during insert mode. + autowrite (aw) write out changes before :next, :prev + autocopy (ac) make backup copies of before writing. + list display tabs as ^I, end of line as $. + magic use regular expressions in searches. + suffix if the filename does not have a . in + it, supply the suffix. (this is the + only string variable.) + overwrite (ow) destroy old file first, then write. + beautify (be) When set, Levee will not allow insert + of any control character except tab + and return unless you escape it with + ctrl-V. + wrapscan searches wrap around end of buffer. + ignorecase (ic) Ignore the case of alphabetic characters + during searches. + mapslash (ST version only) Map '/' in filenames to + '\'. If the environment contains `mapslash' + when levee is called, this variable will + default to true, otherwise it defaults to + false. (See the documentation for the + Teeny-shell on how the teeny-shell interprets + `mapslash') + lines (li) (ST version only) How many lines on the display. + This is primarily for running levee through + the serial port - put set li=xx into your + LVRC for a xx line terminal. + cols (co) (ST version only) How many columns on the + display. Like the lines variable, it's for + running levee through the serial port. + + You may set multiple variables on one line, as in 'set ws noai'. + To see the current settings of these variables, :set -- without any + arguments -- will show the current settings. + + At startup, Levee looks in the environment variable LVRC for + a list of variables to set (GEMDOS/MS-DOS). LVRC is one line + of the form 'option=value ...'. If you have a LVRC defined that + is 'ts=4 ow nows', Levee will set tabsize to 4, turn on overwrite, + and turn off wrapscan. + + If you are using RMX, Levee looks in the file ":home:r?lvrc" + for initialization. If you are using Osy/SWOs, Levee looks in the + file "*.lvrc". The format of these files are different from the + LVRC variable -- see "source" for more information. + + Levee. A Screen Oriented Editor. +--------------- + source file + Take command mode commands from 'file'. These commands can be + any legal command, except "visual". If a error happens during + execution of 'file', Levee abandons that level of source'ing. + + In Osy/SWOs, there are a few differences in insert mode from + within a sourced file. No character has special meaning except a + line containing nothing but a period, which terminates insert mode. + For example: + + :commands + . + . + :insert + blah blah blah blah blah blah + blah blah blah blah blah blah + blah blah blah blah blah blah + . + :more commands + + If you are running Levee under any other operating system, + you cannot do a insert from a :source file. + +NOTE: If you are running Levee on RMX or Osy/SWOs, it will read + ":home:r?lvrc" or "*.lvrc" at startup. These can consist of any + legal command mode instruction, just like any other source file. + +--------------- + (.,.)substitute(delim)patt(delim)repl(delim)[qcpg] + (.,.)substitute& + Search for patt and replace it with repl. Levee will look for + patt once on each line and replace it with repl. The delimiter + may be any ascii character. + + The pattern is a regular expression, just like a search + pattern. + + You may include parts of the pattern in the replacement string; + A '&' in the replacement pattern copies in the whole source pattern, + so if you do a 'sub/this/& and that/g', every instance of 'this' + will be replaced with 'this and that'. Also, you may pull parts of + the pattern out by using the \( and \) argument meta-characters. + Arguments gotten by \( & \) are put into the replacement string + everywhere you do a \1..\9 [ \1 is the first argument you set up + with \( & \) ]. So, if you want to reverse the order of two substrings, + you can do 'sub/\(string1\)\(string2\)/\2\1/'. + + substitute& redoes the last substitution. + + Options: + q,c => before doing the substitute, display the affected + line and wait for you to type a character. If you + type 'y', it will do the substitution. 'q' aborts + the substitute, 'a' does the rest of the change + without prompting, and 'n' does not do it. + p => print the affected lines after the change. + g => do the change globally. That is, do it for every + occurence of patt on a line, rather than just + once. + + Levee. A Screen Oriented Editor. +--------------- + undo + Undo the last modification to the file (except :edit, :next, :rm, + or :write.) You can only undo the last change to a file -- undo counts + as a change. :undo followed by :undo does nothing to the file. + +--------------- + unmap (key) + Undefine a macro (see map). + +--------------- + visual [list] + If you entered command mode by "Q" or "execmode", return to + visual mode. If you provide an argument list, it also does a + `:next' on that list. + +--------------- + version + Show which version of levee this is. + +--------------- + (.,.) write [file] + Write lines to a file. If you write the everything to 'file', + the filename is set to 'file', and if you do not specify a file, + Levee will write to the filename. + +--------------- + (.,.) wq [file] + Write to a file, then quit. + +--------------- + (.,.) yank + Yank lines from the file into the yank buffer, for later + putback with "put". + +--------------- + xit[!] + Write changes to the current file, then exit. If there are + more files in the arglist, use "xit!" + +--------------- + ![command] + Execute command. + + Example: + !ls => does a 'ls'. + + This command is available only under GEMDOS, MSDOS, and RMX. + +--------------- + ($)= + Give the line number of the addressed line. /end/= gives you + the line number of the next line with a 'end' on it. + +--------------- + Levee. A Screen Oriented Editor. + Visual mode commands. + Visual mode commands move you around and modify the file. + There are movement commands to move the cursor by a variety of + objects. + + In the description, a (#) means a optional count. If a + command has a optional count, it will tell you what the count + does in parenthesis. A (*) means that the command can be used + in the delete, yank, and change commands. + + Counts are made up by entering digits. If you type '45', + the count will be set to 45. To cancel a count, type ESC. + + This section discusses 'whitespace' occasionally. + Whitespace is tabs, spaces, and end of line. + + How the display works. + + Characters are displayed on the screen as you would + expect, except that nonprinting characters are shown as ^x, + and tabs expand to spaces ( unless you set the option list, + then they show as ^I.) When sitting on a control character or + tab, the cursor is placed on the FIRST character displayed. If + you move the cursor to any other part of them ( via j or k -- + see below), any changes will start at the next character. + + Levee does not display a end of file marker, but lines + past the end of the file are denoted by ~ lines. + + If list is set, tabs display as ^I, and the end of line + displays as $. + + If a line is too long for the screen, it will just dis- + appear off the end of the screen. + + Levee will handle any screen resolution and any monospaced + font you hand it ( if you are running in low resolution, Levee + will give you a 25x40 window, for example.) + + Levee. A Screen Oriented Editor. +--------------- + ^A + Show a debugging message at the bottom of the screen. This is not at + all useful unless you are debugging the editor. Ignore it. + +--------------- + (#)^D + Scroll the screen down a half screen. If a count is specified, scroll + down the specified number of lines. + +--------------- + ^E + Scroll down 1 line (shorthand for 1^D ) + +--------------- + ^G + Show file statistics. Exactly like ':file'. + +(*)------------ + (#)^H + Move the cursor left one (count) chars. + +--------------- + ^I + Redraw the screen. + +(*)------------ + (#)^J + Move down one (count) lines. When you use ^J and ^K (below) to move + up or down lines, the cursor will remain in the same column, even if + it is in the middle of a tabstop or past the end of a line. + +(*)------------ + (#)^K + Move up one (count) lines. + +(*)------------ + (#)^L + Move right one (count) characters. + +(*)------------ + (#)^M + Move to the first nonwhite space on the next line. If a count is specified, + move to the first nonwhite count lines down. + + Levee. A Screen Oriented Editor. +--------------- + (#)^U + Scroll the screen up a half page. If a count is specified, scroll up + count lines. + +--------------- + ^Y + Scroll the screen up 1 line (shorthand for 1^U.) + +--------------- + (#)a + Insert text AFTER the cursor. If you give a count, the insertion will + be repeated count times ( 40i-ESC will give you a line of 40 dashes). + + The commands in insert mode are the same for visual and command mode. + +(*)------------ + (#)b + Move to the beginning of the last word (the count'th word back). + A word is a collection of alphanumeric characters (a-z0-9$_#) or + any other nonwhite character (i.e. anything but space, tab, eoln). + +--------------- + c + Change a object. Change deletes an object, then enters insert mode without + redrawing the screen. When you tell it the object to be changed, Levee + puts a '$' on the last character of the object. You cannot change + backwards. + + The object may be any visual mode command marked with a '(*)'. For + example, 'c4l' will change the next 4 characters on the line to something + else. (4cl does the same thing -- 4c4l changes the next 16 characters on + this line.) + + 'cc' will change whole lines. + + When changing, deleting, or yanking a object, it will be placed into + a yank buffer, where it can be retrieved by the 'p' or 'P' commands. + +--------------- + (#)d + Delete an object. Like 'cc', 'dd' effects whole lines. + +(*)------------ + (#)e + Move to the end of the current word. + +(*)------------ + (#)f(x) + Find the next (count'th) occurance of a character on the current line. + For example, if the cursor is sitting on the first character of the + line 'abcdef', typing "ff" will put the cursor on the 'f'. + +(*)------------ + (#)h + Move left one (count) characters. Exactly like ^H. + + Levee. A Screen Oriented Editor. +--------------- + (#)i + Start inserting characters at the cursor. If you specify a count, + the insertion will be duplicated count times. + +(*)------------ + (#)j + Move down one (count) lines. Exactly like ^J. + +(*)------------ + (#)k + Move up one (count) lines. Exactly like ^K. + +(*)------------ + (#)l + Move right one (count) character. Exactly like ^L. + +--------------- + m(x) + Set the marker (x). There are 26 markers available (a-z). You may + move to a marker by use of the ' or ` commands. + +(*)------------ + n + Find the next occurance of a search pattern. When you do a search with + a / or ? command, Levee will remember the pattern and the direction you + searched in. 'n' will search in the same direction for the pattern, 'N' + searches in the opposite direction. + +--------------- + o + Open a line below the current line for insertion. + +--------------- + p + Put yanked/deleted text back after the cursor. Text is yanked + by the delete (d,x,X,D), change (c,C,s,S), and yank (y,Y) commands. + +--------------- + (#)r(x) + Replace characters (up to end of line) with (x). '4ra' will change the + next 4 characters after the cursor into 'aaaa'. + +--------------- + (#)s + change one (count) characters. Shorthand for (#)cl. + +(*)------------ + (#)t(x) + Move up to a character on the current line. If you are on the first + character of the line 'abcdef' and you type 'tf', you will end up sitting + on the 'e'. + +--------------- + u + Undo last modification. You can undo ANY modification command except + :edit, :next, :rm, or :write. (Just like :undo). + + Levee. A Screen Oriented Editor. +(*)------------ + (#)v + Move back to the very end of the previous (count'th) word. + See 'b' for the definition of a word. + +(*)------------ + (#)w + Move up to the very beginning of the next (count'th) word. + +--------------- + (#)x + Delete one (count) characters forward. Shorthand for (#)dl. + +--------------- + y + Yank an object for later use by put. 'yy' yanks whole lines. + +--------------- + A + Append text at the end of the line. Shorthand for $a. + +(*)------------ + (#)B + Move to the beginning of the current word. Exactly like 'b'. + + NOTE: this is incorrect. the capitalized word movement commands should, + and will in the future, be used for movement by space-delimited words. + +--------------- + C + Change to the end of the line. Shorthand for c$. + +--------------- + D + Delete to the end of the line. Shorthand for d$. + +(*)------------ + (#)F(x) + Move to the first (count'th) previous occurance of a character on the + current line. If you are sitting at the end of the line 'abcdef', typing + "Fa" will move you back to the 'a' at the start of the line. + +(*)------------ + (#)G + Goto line. If you specify a count, Levee will move to that line, and if + there is no count, Levee moves to the absolute end of the file. + + To get to the start of the file, type "1G". To the end, just "G". + +(*)------------ + H + Move to the first nonwhite character at the top of the screen. + +--------------- + I + Insert at the end of the current line. Shorthand for $i. + + Levee. A Screen Oriented Editor. +--------------- + (#)J + Join two (count+1) lines together. Joining appends the second line at + the end of the first, putting a space between them. If the first line + ends in whitespace, Levee will not put in a space. + +(*)------------ + L + Move to the last nonwhite character on the last line of the screen. + +(*)------------ + M + Move to the first nonwhite character in the middle of the screen. + +--------------- + O + Open a line above the current line. Otherwise works just like 'o'. + +--------------- + P + Put back the yank buffer at the cursor. Otherwise works just like 'p'. + +--------------- + Q + Enter and remain in command mode. Just like the command :exec. To get + back to visual mode, you must enter the command ':visual'. + +--------------- + R + Replace mode. A limited subset of insert mode that overwrites characters + up to end of line. All of the normal insert mode commands apply. + If you overwrite a character, then back over it with ^H,^U, or ^W, it + will reappear after you exit Replace mode. + + Escape exits replace mode. + + NOTE: due to a bug, entering a in Replace mode will drop you + back into visual mode with an error. The replacements you have made + will remain. + +--------------- + S + Change characters backwards. Shorthand for (#)ch. + +(*)------------ + (#)T(x) + Move back to character on current line. If you are on the last character + of the line 'abcdef', typing "Ta" will move you back to the 'b'. + +(*)------------ + (#)W + Move to end of word. Exactly like 'e'. + +--------------- + (#)X + Delete characters backwards. Shorthand for (#)dh. + + Levee. A Screen Oriented Editor. +--------------- + Y + Yank to end of line. Shorthand for y$. + +--------------- + ZZ + Write changes to current file and exit if last file in arglist. + Exactly like :xit. + +(*)------------ + (#)$ + Move to end of line. If you give a count, move to the end of the (count-1) + line down (so 2$ moves you to the end of the next line.). + +(*)------------ + % + Find matching bracket, parenthesis, or squiggly bracket. If you are not + sitting on a '[]{}()', Levee will search forward for one of them on the + current line, then match whatever it finds. + +(*)------------ + ^ + Move to the first nonwhite character on the current line. + +(*)------------ + & + Redo last substitution command. + +(*)------------ + (#){ + Move to the beginning of the count'th paragraph back. A paragraph is + delimited by a blank line. + +(*)------------ + (#)} + Move to the end of the count'th paragraph forward. + +(*)------------ + (#)( + Move to the beginning of the count'th sentence back. A sentence is + delimited by a ., a !, or a ? followed by a space, a tab, or end of line. + +(*)------------ + (#)) + Move to the end of the count'th sentence forward. + +(*)------------ + (#)- + Move to the (count'th) previous line, first nonwhite. + +(*)------------ + (#)+ + Move to the (count'th) next line, first nonwhite. + +--------------- + (#)~ + Change the case of the next count characters. Upper case becomes lowercase, + lowercase becomes uppercase. + + Levee. A Screen Oriented Editor. +(*)------------ + `(x) + Move to the exact position of mark (x). There is a special mark for some + of the visual mode move ment commands -- '' will move you to where you + were before the last (,),',`,G,/,?,n,N command. + +--------------- + : + Execute one command mode command. When the command is done, it will return + to visual mode if it produces one line of output, but if it scrolls the + screen, Levee will prompt [more] before returning to visual mode. If you + type a : in response to the [more] prompt, Levee will remain in command + mode for one more command. + +--------------- + (#)<(#) + Shift one (count) objects left. If you specify a second count, Levee will + shift the object left that many columns -- if you do not, they will be sh + shifted shiftwidth columns. + + This is a nondestructive shift. If the shift would carry past the left + margin, the objects will be moved up to the left margin but no farther. + + Like the other object movement commands, '<<' will affect whole lines. + +--------------- + (#)>(#) + Shift one (count) objects right. Just like <, except it will not shift + objects past the right margin of the screen. If you do shift an object + past the right margin of the screen, all of its indent will be removed + and it will end up by the left margin. + +--------------- + . + Repeat last modification command. (except undo) + +(*)------------ + ? + Search for pattern backwards. Escape aborts the search pattern, and a + empty pattern means search for the last pattern again. + +(*)------------ + / + Search for pattern forwards. Otherwise like ?. + +(*)------------ + (#)| + Move to specified column. If you don't have a count, move to column 0. + + Levee. A Screen Oriented Editor. + + + LIMITATIONS + Levee can only edit files up to 256000 characters long. ^M is used + as its internal line separator, so inserting ^M will have interesting + consequences. + + BUGS + Probably infinite. + + AUTHOR + David L. Parsons (orc) + + Testing, suggestions, and impractical design goals by: + Jim Bolland. + John Tainter. + John Plocher. + + Levee. A Screen Oriented Editor. + + COPYRIGHT + + Copyright (c) 1982-2007 David L Parsons + All rights reserved. + + Redistribution and use in source and binary forms are permitted + provided that the above copyright notice and this paragraph are + duplicated in all such forms and that any documentation, + advertising materials, and other materials related to such + distribution and use acknowledge that the software was developed + by David L Parsons (orc@pell.chi.il.us). My name may not be used + to endorse or promote products derived from this software without + specific prior written permission. THIS SOFTWARE IS PROVIDED + AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND + FITNESS FOR A PARTICULAR PURPOSE. + + Levee. A Screen Oriented Editor. + I N D E X + Are you kidding? diff --git a/src/cmd/levee/main.c b/src/cmd/levee/main.c new file mode 100644 index 0000000..6e4b3d6 --- /dev/null +++ b/src/cmd/levee/main.c @@ -0,0 +1,313 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +#include "levee.h" +#include "extern.h" + +#include + +#if HAVE_SIGNAL_H +#include +#endif + +#if OS_RMX + extern alien token rq$get$task$tokens(); /* for unique files */ +#endif + +VOID PROC +stamp(s, template) +/* make a unique temporary file */ +char *s; +char *template; +{ +#if OS_RMX + token dummy; + + strcpy(s, ":work:"); + strcat(s, template); + numtoa(&s[strlen(s)], rq$get$task$tokens(0,&dummy)); +#else +#if OS_DOS || OS_ATARI + char *p; +#endif + +#if OS_UNIX + strcpy(s, "/tmp/"); +#endif + +#if OS_FLEXOS + s[0] = 0; +#endif + +#if OS_DOS + if (p=getenv("TMP")) { + strcpy(s, p); + if (s[strlen(s)-1] != '\\') + strcat(s, "\\"); + } + else + s[0] = 0; +#endif +#if OS_ATARI + if (p=getenv("_TMP")) { + strcpy(s, p); + if (s[strlen(s)-1] != '\\') + strcat(s, "\\"); + } + else + s[0] = 0; +#endif + strcat(s, template); + numtoa(&s[strlen(s)], getpid()); +#endif +} + +#if OS_RMX|OS_UNIX +PROC void +ctrlc() +/* ctrlc: RMX control-C handler */ +{ + count = 0; /* clear count, eh? */ +} +#endif + +#if OS_RMX +PROC +settty() +/* settty: set up the terminal for raw input */ +{ + unsigned dummy; + /* transparent mode? */ + dq$special(1,&fileno(stdin),&dummy); + + /* turn off control character assignments */ + strput("\033]T:C15=0,C18=0,C20=0,C21=0,C23=0\033\\"); +} +#endif + +VOID PROC +initialize(count, args) +int count; +char **args; +/* initialize: set up everything I can in levee */ +{ + int i; +#if OS_RMX + int xmode = E_INIT, xquit; +#else + char *getenv(); +#if OS_ATARI + extern int mapslash; +#endif +#endif + +#if OS_UNIX + signal(SIGINT, ctrlc); +#else + signal(SIGINT, SIG_IGN); +#endif + initcon(); + +#if OS_RMX + exception(0); + dq$trap$cc(ctrlc,&i); +#endif + +#if TTY_ZTERM + zconfig(); +#endif /*TTY_ZTERM*/ + +#if OS_ATARI + screensz(&LINES, &COLS); + dofscroll = LINES/2; +#endif + +#if OS_RMX +#if USE_TERMCAP + { FILE *tcf; + extern char termcap[]; + + if (tcf=fopen(":termcap:","rb")) { + fgets(termcap,200,tcf); /* get a line... */ + termcap[strlen(termcap)-1] = 0; /* erase \n at eof */ + fclose(tcf); /* close the file */ + } + } +#endif /*USE_TERMCAP*/ + settty(); +#endif /*OS_RMX*/ + +#if USE_TERMCAP + tc_init(); +#endif + + version(); strput(". Copyright (c) 1983-2007 by David Parsons"); + + if (!CA) { + lineonly = TRUE; + mvcur(0, 0); + strput(CE); + prints("(line mode)"); + } + else + lineonly = FALSE; + + /* initialize macro table */ + for (i = 0;i < MAXMACROS;i++) + mbuffer[i].token = 0; + core[0] = EOL; + + yank.size = ERR; /* no yanks yet */ + + undo.blockp = undo.ptr = 0; + + fillchar(adjcurr, sizeof(adjcurr), 0); + fillchar(adjendp, sizeof(adjendp), 0); + + adjcurr[BTO_WD] = /* more practical to just leave dynamic */ + adjcurr[SENT_BACK] = + adjendp[BTO_WD] = + adjendp[FORWD] = + adjendp[MATCHEXPR] = + adjendp[PATT_BACK] = + adjendp[TO_CHAR] = + adjendp[UPTO_CHAR] = + adjendp[PAGE_BEGIN] = + adjendp[PAGE_MIDDLE]= + adjendp[PAGE_END] = TRUE; + + fillchar(contexts, sizeof(contexts), -1); + + stamp(undobuf, "$un"); + stamp(yankbuf, "$ya"); + stamp(undotmp, "$tm"); + + mvcur(LINES-1,0); +#if OS_ATARI + mapslash = getenv("mapslash") != 0L; +#endif +#if OS_RMX + do_file(":lvrc:", &xmode, &xquit); +#else /*!OS_RMX system has a environment.. */ + { char *p; + extern char *execstr; /* [exec.c] */ + + if ( (p=getenv("LVRC")) ) { + strcpy(instring,p); + execstr = instring; + setcmd(); + } + } +#endif + + ++args, --count; + if (count > 0 && **args == '+') { + char *p = *args; + strcpy(startcmd, p[1] ? (1+p) : "$"); + ++args, --count; + } + argc = 0; + while (count-- > 0) + expandargs(*args++, &argc, &argv); + if (argc > 0) { + strcpy(filenm, argv[0]); + if (argc > 1) + toedit(argc); + inputf(filenm,TRUE); + } + else + filenm[0] = 0; +} + +bool PROC +execmode(emode) +exec_type emode; +{ + bool more, /* used [more] at end of line */ + noquit; /* quit flag for :q, :xit, :wq */ + exec_type mode; + + zotscreen = diddled = FALSE; + noquit = TRUE; + + if (lineonly) + println(); + + mode=emode; + do { + prompt(FALSE,":"); + if (getline(instring)) + exec(instring, &mode, &noquit); + indirect = FALSE; + if (mode == E_VISUAL && zotscreen && noquit) { /*ask for more*/ + prints(" [more]"); + if ((ch=peekc()) == 13 || ch == ' ' || ch == ':') + readchar(); + more = (ch != ' ' && ch != 13); + } + else + more = (mode == E_EDIT); + if (mode != E_VISUAL && curpos.x > 0) + println(); + else + mvcur(-1,0); + } while (more && noquit); + if (zotscreen) + clrprompt(); + return noquit; +} + +#if OS_ATARI +long _STKSIZ = 4096; +long _BLKSIZ = 4096; +#endif + +void /* should be union { void a; int b; float c; } to annoy the purists */ +main(argc,argv) +int argc; +char **argv; +{ + initialize(argc, argv); + + diddled = TRUE; /* force screen redraw when we enter editcore() */ + if (lineonly) + while (execmode(E_EDIT)) + prints("(no visual mode)"); + else + while (execmode(editcore())) + /* do nada */; + + unlink(undobuf); + unlink(yankbuf); + +#if TTY_ZTERM + zclose(); +#endif + + fixcon(); + +#if OS_RMX + strputs("\033]T:C15=3,C18=13,C20=5,C21=6,C23=4\033\\\n"); + dq$special(2,&fileno(stdin),&curr); +#else + println(); +#endif + exit(0); +} diff --git a/src/cmd/levee/misc.c b/src/cmd/levee/misc.c new file mode 100644 index 0000000..48197d2 --- /dev/null +++ b/src/cmd/levee/misc.c @@ -0,0 +1,479 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" + +bool PROC +getline(str) +char *str; +{ + int len; + char flag; + + flag = line(str, 0, COLS-curpos.x, &len); + str[len] = 0; + strput(CE); + return (flag == EOL); +} /* getline */ + + +char PROC +readchar() +{ + ch = peekc(); /* get the peeked character */ + needchar = TRUE; /* force a read on next readchar/peekc */ + if (xerox) { /* save this character for redo */ + if (rcp >= &rcb[256-1]) /* oops, buffer overflow */ + error(); + else /* concat it at the end of rcb^ */ + *rcp++ = ch; + } + return ch; +} /* readchar */ + + +/* look at next input character without actually using it */ +char PROC +peekc() +{ + if (needchar) { /* if buffer is empty, */ + if (macro >= 0) { /* if a macro */ + lastchar = *mcr[macro].ip; + mcr[macro].ip++; + if (*mcr[macro].ip == 0) { + if (--mcr[macro].m_iter > 0) + mcr[macro].ip = mcr[macro].mtext; + else + --macro; + } + } + else /* else get one from the keyboard */ + lastchar = getKey(); + needchar = FALSE; + } + return lastchar; +} /* peekc */ + + +/* find the amount of leading whitespace between start && limit. + endd is the last bit of whitespace found. +*/ +int PROC +findDLE(start, endd, limit, dle) +int start, *endd, limit, dle; +{ + while ((core[start] == '\t' || core[start] == ' ') && start < limit) { + if (core[start] == '\t') + dle = tabsize * (1+(dle/tabsize)); + else + dle++; + start++; + } + *endd = start; + return dle; +} /* findDLE */ + + +int PROC +skipws(loc) +int loc; +{ + while ((core[loc] == '\t' || core[loc] == ' ') && loc <= bufmax) + loc++; + return(loc); +} /* skipws */ + + +int PROC +setX(cp) +int cp; +{ + int top, xp; + + top = bseekeol(cp); + xp = 0; + while (top < cp) { + switch (cclass(core[top])) { + case 0 : xp++; break; + case 1 : xp += 2; break; + case 2 : xp = tabsize*(1+(xp/tabsize)); break; + case 3 : xp += 3; break; + } + top++; + } + return(xp); +} /* setX */ + + +int PROC +setY(cp) +int cp; +{ + int yp, ix; + + ix = ptop; + yp = -1; + cp = min(cp,bufmax-1); + do { + yp++; + ix = 1+fseekeol(ix); + } while (ix <= cp); + return(yp); +} /* setY */ + + +int PROC +to_line(cp) +int cp; +{ + int tdx,line; + tdx = 0; + line = 0; + while (tdx <= cp) { + tdx = 1+fseekeol(tdx); + line++; + } + return(line); +} /* to_line */ + + +int PROC +to_index(line) +int line; +{ + int cp = 0; + while (cp < bufmax && line > 1) { + cp = 1+fseekeol(cp); + line--; + } + return(cp); +} /* to_index */ + +VOID PROC +swap(a,b) +int *a,*b; +{ + int c; + + c = *a; + *a = *b; + *b = c; +} /* swap */ + + +int PROC +#if OS_ATARI +cclass(c) +register int c; +{ + if (c >= ' ' && c < '') + return 0; + if (c == '\t' && !list) + return 2; + if (c >= 0) + return 1; + return 3; +} /* cclass */ +#else +cclass(c) +register unsigned char c; +{ + if (c == '\t' && !list) + return 2; + if (c == '' || c < ' ') + return 1; +#if !OS_DOS + if (c & 0x80) + return 3; +#endif + return 0; +} /* cclass */ +#endif + +#if OS_ATARI +/* + * wildly machine-dependent code to make a beep + */ +#include + +static char sound[] = { + 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00, + 0xF8,0x10,0x10,0x10,0x00,0x20,0x03 +}; + +#define SADDR 0xFF8800L + +typedef char srdef[4]; + +static srdef *SOUND = (srdef *)SADDR; + +static +beeper() +{ + register i; + for (i=0; i= NMACROS) + error(); + else if (*cmdstr != 0) { + macro++; + mcr[macro].mtext = cmdstr; /* point at the text */ + mcr[macro].ip = cmdstr; /* starting index */ + mcr[macro].m_iter = count; /* # times to do the macro */ + } +} /* insertmacro */ + + +int PROC +lookup(c) +char c; +{ + int ix = MAXMACROS; + + while (--ix >= 0 && mbuffer[ix].token != c) + ; + return ix; +} /* lookup */ + + +VOID PROC +fixmarkers(base,offset) +int base,offset; +{ + unsigned char c; + + for (c = 0;c<'z'-'`';c++) + if (contexts[c] > base) { + if (contexts[c]+offset < base || contexts[c]+offset >= bufmax) + contexts[c] = -1; + else + contexts[c] += offset; + } +} /* fixmarkers */ + + +VOID PROC +wr_stat() +{ + clrprompt(); + if (filenm[0] != 0) { + printch('"'); + prints(filenm); + prints("\" "); + if (newfile) + prints(" "); + } + else + prints("No file"); + printch(' '); + if (readonly) + prints(" "); + else if (modified) + prints(" "); + if (bufmax > 0) { + prints(" line "); + printi(to_line(curr)); + prints(" -"); + printi((int)((long)(curr*100L)/(long)bufmax)); + prints("%-"); + } + else + prints("-empty-"); +} /* wr_stat */ + + +static int tabptr, + tabstack[20], + ixp; + +VOID PROC +back_up(c) +char c; +{ + switch (cclass(c)) { + case 0: ixp--; break; + case 1: ixp -= 2; break; + case 2: ixp = tabstack[--tabptr]; break; + case 3: ixp -= 3; break; + } + mvcur(-1,ixp); +} /* back_up */ + + +/* + * put input into buf[] || instring[]. + * return states are: + * 0 : backed over beginning + * ESC : ended with an ESC + * EOL : ended with an '\r' + */ +char PROC +line(s, start, endd, size) +char *s; +int start, endd, *size; +{ + int col0, + ip; + unsigned char c; + + col0 = ixp = curpos.x; + ip = start; + tabptr = 0; + while (1) { + c = readchar(); + if (movemap[c] == INSMACRO) /* map!ped macro */ + insertmacro(mbuffer[lookup(c)].m_text, 1); + else if (c == DW) { + while (!wc(s[ip-1]) && ip > start) + back_up(s[--ip]); + while (wc(s[ip-1]) && ip > start) + back_up(s[--ip]); + } + else if (c == eraseline) { + ip = start; + tabptr = 0; + mvcur(-1,ixp=col0); + } + else if (c==Erasechar) { + if (ip>start) + back_up(s[--ip]); + else { + *size = 0; + return(0); + } + } + else if (c=='\r' || c==ESC) { + *size = (ip-start); + return (c==ESC) ? ESC : EOL; + } + else if ((!beautify) || c == TAB || c == '' + || (c >= ' ' && c <= '~')) { + if (ip < endd) { + if (c == '') + c = readchar(); + switch (cclass(c)) { + case 0 : ixp++; break; + case 1 : ixp += 2; break; + case 2 : + tabstack[tabptr++] = ixp; + ixp = tabsize*(1+(ixp/tabsize)); + break; + case 3 : ixp += 3; break; + } + s[ip++] = c; + printch(c); + } + else + error(); + } + else + error(); + } +} /* line */ + + +/* move to core[loc] */ +VOID PROC +setpos(loc) +int loc; +{ + lstart = bseekeol(loc); + lend = fseekeol(loc); + xp = setX(loc); + curr = loc; +} /* setpos */ + + +VOID PROC +resetX() +{ + if (deranged) { + xp = setX(curr); + mvcur(-1, xp); + deranged = FALSE; + } +} /* resetX */ + + +/* set end of window */ +VOID PROC +setend() +{ + int bottom, count; + + bottom = ptop; + count = LINES-1; + while (bottom < bufmax && count > 0) { + bottom = 1+fseekeol(bottom); + count--; + } + pend = bottom-1; /* last char before eol || eof */ +} /* setend */ + + +/* set top of window + * return the number of lines actually between curr && ptop. + */ +int PROC +settop(lines) +int lines; +{ + int top, yp; + + top = curr; + yp = -1; + do { + yp++; + top = bseekeol(top) - 1; + lines--; + } while (top >= 0 && lines > 0); + ptop = top+1; /* tah-dah */ + setend(); + return(yp); +} /* settop */ diff --git a/src/cmd/levee/modify.c b/src/cmd/levee/modify.c new file mode 100644 index 0000000..65c8610 --- /dev/null +++ b/src/cmd/levee/modify.c @@ -0,0 +1,197 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" +#include "grep.h" + +/* modification commands that can be accessed by either editcore || execmode */ + +/* put stuff into the yank buffer */ + +bool PROC +doyank(low, high) +int low, high; +{ + HANDLE f; + register int sz; + + yank.size = high - low; + moveleft(&core[low], yank.stuff, min(yank.size, SBUFSIZE)); + if (yank.size > SBUFSIZE) { + if ((f=OPEN_NEW(yankbuf)) >= 0) { + low += SBUFSIZE; + sz = WRITE_TEXT(f, core+low, high-low); + CLOSE_FILE(f); + if (sz == high-low) + return TRUE; + } + yank.size = -1; + return FALSE; + } + return TRUE; +} + +bool PROC +deletion(low, high) +int low,high; +{ + if (doyank(low, high)) /* fill yank buffer */ + return delete_to_undo(&undo, low, high-low); + return FALSE; +} + +/* move stuff from the yank buffer into core */ + +bool PROC +putback(start, newend) +int start, *newend; +{ + int siz, st; + HANDLE f; + + if (yank.size+bufmax < SIZE && yank.size > 0) { + *newend = start + yank.size; + if (start < bufmax) + moveright(&core[start], &core[start+yank.size], bufmax-start); + moveleft(yank.stuff, &core[start], min(SBUFSIZE, yank.size)); + if (yank.size > SBUFSIZE) { + siz = yank.size - SBUFSIZE; + if ((f=OPEN_OLD(yankbuf)) >= 0) { + st = READ_TEXT(f, &core[start+SBUFSIZE], siz); + CLOSE_FILE(f); + if (st == siz) + goto succeed; + } + moveleft(&core[start+yank.size], &core[start], bufmax-start); + *newend = -1; + return FALSE; + } + succeed: + insert_to_undo(&undo, start, yank.size); + return TRUE; + } + return FALSE; +} + +#define DSIZE 1024 + +int PROC +makedest(str,start,ssize,size) +/* makedest: make the replacement string for an regular expression */ +char *str; +int start, ssize, size; +{ + char *fr = dst; + char *to = str; + int as, asize, c; + + while (*fr && size >= 0) { + if (*fr == AMPERSAND) { /* & copies in the pattern that we matched */ + if ((size -= ssize) < 0) + return -1; + moveleft(&core[start],to,ssize); + to += ssize; + fr++; + } + else if (*fr == ESCAPE) { /* \1 .. \9 do arguments */ + c = fr[1]; + fr += 2; + if (c >= '1' && c <= '9') { + if ((as = RE_start[c-'1']) < 0) + continue; + asize = RE_size [c-'1']; + if ((size -= asize) < 0) + return -1; + moveleft(&core[as],to,asize); + to += asize; + } + else + *to++ = c; + } + else { + *to++ = *fr++; + --size; + } + } + return to-str; +} + +int PROC +chop(start,endd,visual,query) +int start,*endd; +bool visual, *query; +{ + int i,retval; + char c; +/*>>>> + bool ok; + <<<<*/ + char dest[DSIZE]; + register int len, dlen; + + retval = -1; + /*dlen = strlen(dst);*/ +restart: + count = 1; + i = findfwd(pattern, start, *endd); + if (i != ERR) { + if (*query) { + /*>>>> don't delete -- keep for future use + if (visual) { + mvcur(yp,setX(i));puts("?"); + } + else { + <<<<*/ + println(); + writeline(-1,-1,bseekeol(i)); + println(); + mvcur(-1,setX(i)); + prints("^?"); + /*>>>> + } + <<<<*/ + do + c = tolower(readchar()); + while (c!='y'&&c!='n'&&c!='q'&&c!='a'); + if (c == 'n') { + start = i+1; + goto restart; + } + else if (c == 'q') + return retval; + else if (c == 'a') + *query = FALSE; + } + len = lastp-i; + dlen = makedest(dest, i, len, DSIZE); + if (dlen >= 0 && bufmax-(int)(len+dlen) < SIZE + && delete_to_undo(&undo, i, len)) { + modified = TRUE; + if (dlen > 0) { + moveright(&core[i], &core[i+dlen], bufmax-i); + insert_to_undo(&undo,i,dlen); + moveleft(dest,&core[i],dlen); + } + *endd += (dlen-len); + retval = i+dlen; + } + } + return retval; +} diff --git a/src/cmd/levee/move.c b/src/cmd/levee/move.c new file mode 100644 index 0000000..ecc1eee --- /dev/null +++ b/src/cmd/levee/move.c @@ -0,0 +1,444 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" + +int PROC findcol(); +int PROC moveword(); +int PROC sentence(); +int PROC match(); +int PROC fchar(), bchar(); + +/* driver for movement commands */ + +findstates PROC +findCP(curp,newpos,cmd) +int curp, *newpos; +cmdtype cmd; +{ + static char chars[2] = {'/','?'}; + char tsearch; + + *newpos = ERR; + switch (cmd) { /* move around */ + + case GO_LEFT: + *newpos = max(lstart, curp-max(count,1)); + break; + + case GO_RIGHT: + *newpos = min(lend, curp+max(count,1)); + break; + + case GO_UP: + case GO_DOWN: + *newpos = nextline(cmd==GO_DOWN, curp, count); + if (*newpos >= 0 && *newpos < bufmax) + *newpos = findcol(*newpos,xp); + break; + + case FORWD: + case TO_WD: + case BACK_WD: + case BTO_WD: + *newpos = moveword(curp,(cmd <= TO_WD),(cmd==TO_WD || cmd==BTO_WD)); + break; + + case NOTWHITE: + *newpos = skipws(bseekeol(curp)); + break; + + case TO_COL: + *newpos = findcol(curp, count); + break; + + case TO_EOL: + while ( (count-- > 1) && (curp < bufmax) ) + curp = 1+fseekeol(curp); + *newpos = fseekeol(curp); + break; + + case PARA_FWD: + do + curp = findfwd("^*[ \t$",curp+1,bufmax-1); + while (curp != ERR && --count > 0); + *newpos = (curp==ERR)?bufmax:curp; + break; + + case PARA_BACK: + do + curp = findback("^*[ \t$",curp-1,0); + while (curp != ERR && --count > 0); + *newpos = (curp==ERR)?0:curp; + break; + + case SENT_FWD: + case SENT_BACK: + *newpos = sentence(curp, cmd==SENT_FWD); + break; + + case MATCHEXPR: + *newpos = match(curp); + break; + + case TO_CHAR: + case UPTO_CHAR: + case BACK_CHAR: + case BACKTO_CHAR: + ch = readchar(); + if (ch == ESC) + return ESCAPED; + if (cmd<=UPTO_CHAR) { + *newpos = fchar(curp,*newpos); + if (cmd==UPTO_CHAR && *newpos>=0) + *newpos = max(curp, *newpos-1); + } + else { + *newpos = bchar(curp,*newpos); + if (cmd==BACKTO_CHAR && *newpos>=0) + *newpos = min(curp, *newpos+1); + } + break; + + case PAGE_BEGIN: + *newpos = ptop; + break; + + case PAGE_END: + *newpos = pend; + break; + + case PAGE_MIDDLE: + curp = ptop; + count = 12; + while (count-- > 0 && curp < bufmax) + curp = 1+fseekeol(curp); + *newpos = skipws(curp); + break; + + case GLOBAL_LINE: + if (count <= 0) + *newpos = bufmax-1; + else + *newpos = to_index(count); + break; + + case TO_MARK: + case TO_MARK_LINE: + *newpos = getcontext((char)tolower(readchar()), cmd==TO_MARK_LINE); + break; + + case CR_FWD: + case CR_BACK: + curp = nextline(cmd==CR_FWD, curp, count); + if (cmd==CR_BACK && curp > 0) + curp = bseekeol(curp); + *newpos = skipws(curp); + break; + + case PATT_FWD: + case PATT_BACK: /* search for pattern */ + case FSEARCH: + case BSEARCH: + clrprompt(); + if (cmd == PATT_FWD || cmd == PATT_BACK) { + printch(tsearch = instring[0] = chars[cmd-PATT_FWD]); + if (!getline(&instring[1])) + return ESCAPED; /* needs to skip later tests */ + } + else { + if (!lsearch) + return BADMOVE; + tsearch = lsearch; + printch(instring[0] = (cmd==FSEARCH)?lsearch:((lsearch=='?')?'/':'?') ); + prints(lastpatt); + instring[1] = 0; + } + if (*findparse(instring, newpos, curp)) { /* croaked patt */ + *newpos = ERR; + prompt(TRUE,"bad pattern"); + } + else if (*newpos == ERR) + prompt(FALSE,"no match"); + lsearch = tsearch; /* fixup for N, n */ + break; + } + if ( ((*newpos) >= 0) && ((*newpos) <= bufmax) ) + return LEGALMOVE; + return BADMOVE; +} + +/* this procedure handles all movement in visual mode */ + +VOID PROC +movearound(cmd) +cmdtype cmd; +{ + int cp; + + switch (findCP(curr, &cp, cmd)) { + case LEGALMOVE: + if (cp < bufmax) { + if (cmd >= PATT_FWD) /* absolute move */ + contexts[0] = curr; /* so save old position... */ + curr = cp; /* goto new position */ + if (cmd==GO_UP || cmd==GO_DOWN) /* reset Xpos */ + deranged = TRUE; + else + xp = setX(cp); /* just reset XP */ + if (cp < lstart || cp > lend) { + lstart = bseekeol(curr); + lend = fseekeol(curr); + if (curr < ptop) { + if (canUPSCROLL && ok_to_scroll(curr, ptop)) { + scrollback(curr); + yp = 0; + } + else { + yp = settop(LINES / 2); + redisplay(TRUE); + } + } + else if (curr > pend) { + if (ok_to_scroll(pend, curr)) { + scrollforward(curr); + yp = LINES-2; + } + else { + yp = settop(LINES / 2); + redisplay(TRUE); + } + } + else + yp = setY(curr); + } + } + else + error(); + break; + case BADMOVE: + error(); + break; + } + mvcur(yp, xp); +} + +int PROC +findcol(ip, col) +int ip, col; +{ + int tcol, endd; + + ip = bseekeol(ip); /* start search here */ + endd = fseekeol(ip); /* end search here */ + + tcol = 0; + while (tcol < col && ip < endd) + switch (cclass(core[ip++])) { + case 0: tcol++; break; + case 1: tcol += 2; break; + case 3: tcol += 3; break; + case 2: tcol = tabsize*(1+(tcol/tabsize)); break; + } + return(ip); +} + +char dstpatt[]="[](){}", srcpatt[]="][)(}{"; + +/* find matching [], (), {} */ + +int PROC +match(p) +int p; +{ + char srcchar, dstchar; + int lev, step; + + while((lev = scan(6,'=',core[p],srcpatt)) >= 6 && core[p] != EOL) + p++; + if (lev < 6) { + srcchar = srcpatt[lev]; + dstchar = dstpatt[lev]; + step = setstep[lev&1]; + lev = 0; + while (p >= 0 && p < bufmax) { + p += step; + if (core[p] == srcchar) + lev++; + else if (core[p] == dstchar) + if(--lev < 0) + return p; + } + } + return (-1); +} + +char * PROC +class(c) +/* find the character class of a char -- for word movement */ +char c; +{ + if (strchr(wordset,c)) + return wordset; + else if (strchr(spaces,c)) + return spaces; + else + return (char*)NULL; +} + +int PROC +skip(chars,cp,step) +/* skip past characters in a character class */ +char *chars; +register int cp; +int step; +{ + while (cp >= 0 && cp < bufmax && strchr(chars,core[cp])) + cp += step; + return cp; +} + +int PROC +tow(cp,step) +/* skip to the start of the next word */ +register int cp; +register int step; +{ + while (cp >= 0 && cp < bufmax + && !(strchr(wordset,core[cp]) || strchr(spaces,core[cp]))) + cp += step; + return cp; +} + +int PROC +moveword(cp,forwd,toword) +/* word movement */ +int cp; +bool forwd, toword; +{ + int step; + char *ccl; + + step = setstep[forwd]; /* set direction to move.. */ + if (!toword) + cp += step; /* advance one character */ + count = max(1,count); + ccl = class(core[cp]); + if (toword && ccl == spaces) { /* skip to start of word */ + count--; + cp = skip(spaces,cp,step); + ccl = class(core[cp]); + } + + while (cp >= 0 && cp < bufmax && count-- > 0) { + if (ccl == spaces) { + cp = skip(spaces,cp,step); + ccl = class(core[cp]); + } + cp = (ccl)?skip(ccl,cp,step):tow(cp,step); + ccl = class(core[cp]); + } + if (toword) { /* past whitespace? */ + if (ccl == spaces) + cp = skip(spaces,cp,step); + return cp; + } + return cp-step; /* sit on last character. */ +} + +/* find a character forward on current line */ + +int PROC +fchar(pos,npos) +int pos,npos; +{ + do + pos += scan(lend-pos-1,'=',ch, &core[pos+1]) + 1; + while (--count>0 && pos0 && pos>=lstart); + if (pos>=lstart) + return(pos); + return(npos); +} + +/* look for the end of a sentence forward */ + +int PROC +ahead(i) +int i; +{ + char c; + + do { + if ((c=core[i]) == '.' || c == '?' || c == '!') + if (i == bufmax-1 || (c=core[1+i]) == TAB || c == EOL || c == ' ') + return i; + + } while (++i < bufmax); + return -1; +} + +/* look for the end of a sentence backwards. */ + +int PROC +back(i) +int i; +{ + char c; + + do { + if ((c=core[i]) == '.' || c == '?' || c == '!') + if ((c=core[1+i]) == TAB || c == EOL || c == ' ') + return i; + + } while (--i >= 0); + return -1; +} + +/* find the end of the next/last sentence. + Sentences are delimited by ., !, or ? followed by a space. +*/ + +int PROC +sentence(start,forwd) +int start; +bool forwd; +{ + do { + if (forwd) + start = ahead(start+1); + else + start = back(start-1); + } while (--count > 0 && start >= 0); + return start; +} diff --git a/src/cmd/levee/os2call.c b/src/cmd/levee/os2call.c new file mode 100644 index 0000000..eebe169 --- /dev/null +++ b/src/cmd/levee/os2call.c @@ -0,0 +1,207 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +/* + * os2 (and bound) interface for levee (Microsoft C) + */ +#include "levee.h" + +#if OS2 + +#include +#include + +#define INCL_DOS +#include + +int PROC +min(a,b) +int a,b; +{ + return (a>b) ? b : a; +} + +int PROC +max(a,b) +int a,b; +{ + return (a s; --p) + if (p[-1] == '/' || p[-1] == '\\' || p[-1] == ':') + return p; + return s; +} /* basename */ + + +/* + * glob() expands a wildcard, via calls to DosFindFirst/Next() + * and pathname retention. + */ +char * +glob(path, dta) +char *path; +struct glob_t *dta; +{ + static char path_bfr[256]; /* full pathname to return */ + static char *file_part; /* points at file - for filling */ + static char isdotpattern; /* looking for files starting with . */ + static char isdotordotdot; /* special case . or .. */ + static struct glob_t *dta_bfr; /* pointer to desired dta */ + static FILEFINDBUF ffb; /* DOS & OS/2 dta */ + static int dir; /* directory handle */ + + register st; /* status from DosFindxxx */ + int count=1; /* how many files to find */ + + if (path) { + /* when we start searching, save the path part of the filename in + * a safe place. + */ + strcpy(path_bfr, path); + file_part = basename(path_bfr); + + /* set up initial parameters for DosFindFirst() + */ + dta_bfr = dta; + dir = HDIR_SYSTEM; + + if (isdotpattern = (*file_part == '.')) + /* DosFindFirst() magically expands . and .. into their + * directory names. Admittedly, there are cases where + * this can be useful, but this is not one of them. So, + * if we find that we're matching . and .., we just + * special-case ourselves into oblivion to get around + * this particular bit of DOS silliness. + */ + isdotordotdot = (file_part[1] == 0 || file_part[1] == '.'); + else + isdotordotdot = 0; + + st = DosFindFirst(path, &dir, 0x16, &ffb, sizeof ffb, &count, 0L); + } + else + st = DosFindNext(dir, &ffb, sizeof ffb, &count); + + while (st == 0 && count > 0) { + /* Unless the pattern has a leading ., don't include any file + * that starts with . + */ + if (ffb.achName[0] == '.' && !isdotpattern) { + count = 1; + st = DosFindNext(dir, &ffb, sizeof ffb, &count); + } + else { + /* found a file - affix the path leading to it, then return + * a pointer to the (static) buffer holding the path+the name. + */ + strlwr(ffb.achName); /* DOS & OS/2 are case-insensitive */ + + if (dta_bfr) { + memcpy(&dta_bfr->wr_date, &ffb.fdateLastWrite, sizeof(short)); + memcpy(&dta_bfr->wr_time, &ffb.ftimeLastWrite, sizeof(short)); + if (isdotordotdot) + strcpy(dta_bfr->name, file_part); + else { + strncpy(dta_bfr->name, + ffb.achName, sizeof(dta_bfr->name)-1); + dta_bfr->name[sizeof(dta_bfr->name)-1] = 0; + } + dta_bfr->size = ffb.cbFile; + dta_bfr->attrib = ffb.attrFile; + } + if (!isdotordotdot) + strcpy(file_part, ffb.achName); + return path_bfr; + } + } + /* nothing matched + */ + if (path && isdotordotdot) { + /* must be at root, so statting dot will most likely fail. Fake a + * dta. + */ + if (dta_bfr) { + memset(dta_bfr, 0, sizeof *dta_bfr); + dta_bfr->attrib = 0x10; + dta_bfr->name[0] = '.'; + } + return path_bfr; + } + return (char*)0; +} /* glob */ +#endif diff --git a/src/cmd/levee/proto.h b/src/cmd/levee/proto.h new file mode 100644 index 0000000..c362af3 --- /dev/null +++ b/src/cmd/levee/proto.h @@ -0,0 +1,162 @@ +/* +** levee function prototypes +** (generated by cl -Gms -Ox -nologo -I../tools -Zg) +*/ +#ifndef _PROTO_D +#define _PROTO_D +char *PROC badccl(char *src); +char *PROC class(char c); +char *PROC dodash(char *src); +char *PROC findbounds(char *ip); +char *PROC findparse(char *src,int *idx,int start); +char *PROC getarg(void); +char *PROC getname(void); +char *PROC makepat(char *string,char delim); +char *PROC search(char *pat,int *start); +char *basename(char *s); +char *glob(char *path,struct glob_t *dta); +char PROC editcore(void); +char PROC esc(char * *s); +char PROC findCP(int curp,int *newpos,char cmd); +char PROC line(char *s,int start,int endd,int *size); +char PROC peekc(void); +char PROC readchar(void); +int PROC REmatch(char *pattern,int start,int end); +int PROC addarg(char *name); +int PROC addfile(struct _iobuf *f,int start,int endd,int *size); +int PROC adjuster(int sleft,int endd,int sw); +int PROC ahead(int i); +int PROC allowintr(void); +int PROC amatch(char *pattern,char *start,char *endp); +int PROC args(void); +int PROC back(int i); +int PROC back_up(char c); +int PROC backup(char *name); +int PROC bchar(int pos,int npos); +int PROC bigreplace(void); +int PROC bseekeol(int origin); +int PROC cclass(unsigned char c); +int PROC chop(int start,int *endd,int visual,int *query); +int PROC clrmsg(void); +int PROC clrprompt(void); +int PROC concatch(char c); +int PROC copyover(struct undostack *save_undo,int *curp); +int PROC cutandpaste(void); +int PROC delete_to_undo(struct undostack *u,int start,int lump); +int PROC deletion(int low,int high); +int PROC do_file(char *fname,char *mode,int *noquit); +int PROC doaddwork(char *token,int *argcp,char * * *argvp); +int PROC docommand(char cmd); +int PROC doinput(char *name); +int PROC doins(int flag); +int PROC doyank(int low,int high); +int PROC editfile(void); +int PROC errmsg(char *msg); +int PROC error(void); +int PROC exec(char *cmd,char *mode,int *noquit); +int PROC execmode(char emode); +int PROC exmacro(void); +int PROC expandargs(char *name,int *argcp,char * * *argvp); +int PROC fchar(int pos,int npos); +int PROC findDLE(int start,int *endd,int limit,int dle); +int PROC findarg(char *name); +int PROC findback(char *pattern,int start,int endp); +int PROC findcol(int ip,int col); +int PROC findfwd(char *pattern,int start,int endp); +int PROC fixcore(int *topp); +int PROC fixmarkers(int base,int offset); +int PROC fixupline(int dft); +int PROC format(char *out,unsigned short c); +int PROC fseekeol(int origin); +int PROC gcount(void); +int PROC getKey(void); +int PROC getcontext(char c,int begline); +int PROC getline(char *str); +int PROC initialize(int count,char * *args); +int PROC inputf(char *fname,int newbuf); +int PROC insert_to_undo(struct undostack *u,int start,int size); +int PROC insertion(int count,int openflag,int *dp,int *yp,int visual); +int PROC insertmacro(char *cmdstr,int count); +int PROC join(int count); +int PROC killargs(int *argcp,char * * *argvp); +int PROC locate(char *pattern,char *linep); +int PROC lookup(char c); +int PROC macrocommand(void); +int PROC makedest(char *str,int start,int ssize,int size); +int PROC map(int insert); +int PROC match(int p); +int PROC max(int a,int b); +int PROC min(int a,int b); +int PROC move_to_undo(struct undostack *u,int start,int lump); +int PROC movearound(char cmd); +int PROC moveleft(char *src,char *dest,int length); +int PROC moveright(char *src,char *dest,int length); +int PROC moveword(int cp,int forwd,int toword); +int PROC mvcur(int y,int x); +int PROC nextfile(int prev); +int PROC nextline(int advance,int dest,int count); +int PROC nointr(void); +int PROC numtoa(char *str,int num); +int PROC ok_to_scroll(int top,int bottom); +int PROC oktoedit(int writeold); +int PROC omatch(char *pattern,char * *cp,char *endp); +int PROC outputf(char *fname); +int PROC parse(char *inp); +int PROC patsize(char * *pattern); +int PROC plural(int num,char *string); +int PROC popblock(struct undostack *u); +int PROC popmem(struct undostack *u,int start,int size); +int PROC popw(struct undostack *u,int *i); +int PROC print(void); +int PROC printall(void); +int PROC printch(char c); +int PROC printi(int num); +int PROC println(void); +int PROC printone(int i); +int PROC prints(char *s); +int PROC prompt(int toot,char *s); +int PROC pushblock(struct undostack *u); +int PROC pushmem(struct undostack *u,int start,int size); +int PROC pushw(struct undostack *u,int i); +int PROC put(int before); +int PROC putback(int start,int *newend); +int PROC putfile(struct _iobuf *f,int start,int endd); +int PROC putin(struct undostack *save_undo,int *curp); +int PROC readfile(void); +int PROC redisplay(int flag); +int PROC refresh(int y,int x,int start,int endd,int rest); +int PROC resetX(void); +int PROC scan(int length,char tst,char ch,char *src); +int PROC scroll(int down); +int PROC scrollback(int curr); +int PROC scrollforward(int curr); +int PROC sentence(int start,int forwd); +int PROC setX(int cp); +int PROC setY(int cp); +int PROC setcmd(void); +int PROC setend(void); +int PROC setpos(int loc); +int PROC settop(int lines); +int PROC skip(char *chars,int cp,int step); +int PROC skipws(int loc); +int PROC squiggle(int endp,char c,int dorepl); +int PROC stamp(char *s,char *template); +int PROC strput(char *s); +int PROC swap(int *a,int *b); +int PROC takeout(struct undostack *save_undo,int *curp); +int PROC to_index(int line); +int PROC to_line(int cp); +int PROC toedit(int count); +int PROC tow(int cp,int step); +int PROC undefine(int i); +int PROC unmap(void); +int PROC uputcmd(struct undostack *u,int size,int start,char cmd); +int PROC version(void); +int PROC whatline(void); +int PROC wr_stat(void); +int PROC writefile(void); +int PROC writeline(int y,int x,int start); +int PROC zdraw(char code); +int PROC zerostack(struct undostack *u); +int main(int argc,char * *argv); +#endif /*_PROTO_D*/ diff --git a/src/cmd/levee/readme.os2 b/src/cmd/levee/readme.os2 new file mode 100644 index 0000000..c1ec005 --- /dev/null +++ b/src/cmd/levee/readme.os2 @@ -0,0 +1,7 @@ +If you wish to have your copy of Levee as a family mode application, all +you need to do is bind it. It's already set up as a family mode application- +there are some small differences for input (dos lv sees ^C and treats it +like an ordinary character; os2 lv never sees ^C, because it's eaten by trap +handlers) and redirectability (os2 lv uses getch() - a microsoft library +function; dos vi uses dos function 0x07 - "get raw character from stdin, +whatever that may be") but these shouldn't be a problem. diff --git a/src/cmd/levee/rmxcall.c b/src/cmd/levee/rmxcall.c new file mode 100644 index 0000000..f3a62ca --- /dev/null +++ b/src/cmd/levee/rmxcall.c @@ -0,0 +1,101 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +/* + * iRMX interface for levee (Intel C) + */ +#include "levee.h" +#if OS_RMX + +extern char FkL, CurRT, CurLT, CurUP, CurDN; + +extern alien rq$s$write$move(); + +strput(s) +/* strput: write a string to stdout */ +char *s; +{ + int dummy; + + if (s) + rq$s$write$move(fileno(stdout), s, strlen(s), &dummy); +} + +char +getKey() +/* getKey: read a character from stdin */ +{ + char c,sw; + unsigned dummy; + + read(0,&c,1); + + if (c == FkL) { /* (single character) function key lead-in */ + dq$special(3,&fileno(stdin),&dummy); /* grab a raw-mode character */ + if (read(0,&sw,1) == 1) + if (sw == CurLT) + c = LTARROW; + else if (sw == CurRT) + c = RTARROW; + else if (sw == CurUP) + c = UPARROW; + else if (sw == CurDN) + c = DNARROW; + else + c = sw | 0x80; + dq$special(1,&fileno(stdin),&dummy); /* back into transparent mode */ + } +#if 0 + else if (c == 0x7f) /* good old dos kludge... */ + return erase; +#endif + return c; +} + +int max(a,b) +int a,b; +{ + return (a>b)?a:b; +} + +int min(a,b) +int a,b; +{ + return (a>b)?b:a; +} + +extern alien token rq$c$create$command$connection(), + rq$c$delete$command$connection(), + rq$c$send$command(); + +int system(s) +/* system: do a shell escape */ +char *s; +{ + char *string(); + unsigned cp, error, status, dummy; + + cp = rq$c$create$command$connection(fileno(stdin),fileno(stdout),0,&error); + if (!error) { + rq$c$send$command(cp,string(s),&status,&error); + rq$c$delete$command$connection(cp,&dummy); + } + return error?(error|0x8000):(status&0x7fff); +} +#endif diff --git a/src/cmd/levee/tc b/src/cmd/levee/tc new file mode 100644 index 0000000..770fbb9 --- /dev/null +++ b/src/cmd/levee/tc @@ -0,0 +1,32 @@ + if (!(ttytype = getenv("TERM"))) { + S1("TERM not set"); + exit(6); + } + if (tgetent(tc, ttytype) != 1) { + sprintf(Msg, "Can't load %s", ttytype); + S; + exit(7); + } + ospeed = newmode.c_cflag & CBAUD; + LI = tgetnum("li") - 1; + CO = tgetnum("co"); + if (!(s = Tgetstr("pc"))) + PC = '\0'; + else + PC = *s; + + CD = Tgetstr("cd"); + CE = Tgetstr("ce"); + CL = Tgetstr("cl"); + CM = Tgetstr("cm"); + SE = Tgetstr("se"); + SO = Tgetstr("so"); +#ifdef linux + CF = Tgetstr("vi"); + CN = Tgetstr("ve"); +#else + CF = Tgetstr("CF"); + CN = Tgetstr("CN"); +#endif + if (CF && !CN) + CN = Tgetstr("CO"); diff --git a/src/cmd/levee/termcap.i b/src/cmd/levee/termcap.i new file mode 100644 index 0000000..4e2ce9e --- /dev/null +++ b/src/cmd/levee/termcap.i @@ -0,0 +1,287 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +#if TERMCAP_EMULATION +/* + * Termcap handlers + * + * Routines included: + * tc_init() -- set up all the terminal stuff levee will need. + * *xtract() -- get a field out of the termcap entry. + * *parseit() -- parse a termcap field. + * tgoto() -- put a gotoXY string into a buffer. + * * -> internal routine. + */ + +#if OS_RMX | OS_DOS /* default to ANSI.SYS termcap */ +char termcap[200] = "Ansi subset:CM=\033[%d;%dH,Y,1,1:\ +CE=\033[K:CL=\033[H\033[J:LINES=24:COLS=79:HO=\033[H:FkL=\033:\ +CurR=C:CurL=D:CurU=A:CurD=B"; +#endif + +char * +parseit(ptr,savearea) +/* parse a termcap field */ +char *ptr; +char **savearea; +{ + char *p = *savearea; + char *op = *savearea; + int tmp; + + while (*ptr && *ptr != ':') { + if (*ptr == '\\' && ptr[1]) { + ++ptr; + switch (*ptr) { + case 'E': + *p++ = '\033'; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + tmp = 0; + while (*ptr >= '0' && *ptr <= '9') + tmp = (tmp*8)+(*ptr++ - '0'); + *p++ = tmp; + --ptr; + default: + *p++ = *ptr; + } + } + else *p++ = *ptr; + ++ptr; + } + *p++ = 0; + *savearea = p; + return op; +} /* parseit */ + +char * +xtract(ptr,name,savearea) +/* get something from the termcap + * + * arguments: tcentry -- the termcap entry + * what -- the field we want to get (NULL means first field) + * savearea-- pointer to static buffer for parsed fields. + */ +char *ptr; +char name[]; +char **savearea; +{ + int size; + + if (!ptr) + return NULL; + + if (!name) /* return first field of entry -- terminal name? */ + return parseit(ptr,savearea); + + size = strlen(name); + /* + * always skip the first (terminal name) field + */ + while (*ptr) { + while (*ptr && *ptr != ':') { + if (*ptr == '\\') + ptr++; + ptr++; + } + if (*ptr) + ptr++; + if (*ptr && strncmp(name,ptr,size) == 0 && ptr[size] == '=') + return parseit(&ptr[1+size],savearea); + puts("\r"); + } + return NULL; +} /* xtract */ + +char +charext(tc,what,savearea) +/* get a character field from the termcap */ +char *tc, *what, **savearea; +{ + char *p = xtract(tc,what,savearea); + if (p) + return *p; + return 0; +} /* charext */ + +/* internal variables just for termcap */ +static int _Xfirst, _xpad, _ypad; + +void +tc_init() +/* get the termcap stuff and go berserk parsing it */ +/* if anything horrid goes wrong, levee will crash */ +{ +#if OS_RMX + char *p = termcap; +#else + char *getenv(); + char *p = getenv("TERMCAP"); +#endif + char *lp, *ptr; + +#if OS_DOS + if (!p) + p = termcap; +#endif +#if !(OS_RMX|OS_DOS) + if (!p) { + puts("lv: no termcap\n"); + exit(1); + } +#endif + lp = Malloc(strlen(p)+1); + if (!lp) { + puts("lv: out of memory\n"); + exit(1); + } + + TERMNAME = xtract(p,NULL,&lp); + CM = xtract(p,"CM",&lp); + HO = xtract(p,"HO",&lp); + UP = xtract(p,"UP",&lp); + CE = xtract(p,"CE",&lp); + CL = xtract(p,"CL",&lp); + BELL = xtract(p,"BELL",&lp); + if (!BELL) + BELL = "\007"; + OL = xtract(p,"OL",&lp); + UpS = xtract(p,"UpS",&lp); + CURon= xtract(p,"CURon",&lp); + CURoff=xtract(p,"CURoff",&lp); + + FkL = charext(p,"FkL",&lp); + CurRT= charext(p,"CurR",&lp); + CurLT= charext(p,"CurL",&lp); + CurUP= charext(p,"CurU",&lp); + CurDN= charext(p,"CurD",&lp); + + canUPSCROLL = (UpS != NULL); + CA = (CM != NULL); + + if ((LINES=atoi(ptr=xtract(p,"LINES",&lp))) <= 0) { + puts("lv: bad termcap"); + exit(1); + } + dofscroll = LINES/2; + if ((COLS=atoi(ptr=xtract(p,"COLS",&lp))-1) <= 0 || COLS >= MAXCOLS) { + puts("lv: bad termcap"); + exit(1); + } + + _ypad = _xpad = 0; + _Xfirst = 1; + + p = CM; + + while (*p && *p != ',') + p++; + if (!*p) + return; + *p++ = 0; + if (*p != ',') + _Xfirst = (*p++ == 'X'); + if (!*p) + return; + ++p; + while (*p && *p != ',') + _xpad = (_xpad*10) + (*p++ - '0'); + if (!*p) + return; + ++p; + while (*p) + _ypad = (_ypad*10) + (*p++ - '0'); +} + +#define tgoto(s,y,x) (_Xfirst?sprintf(s,CM,x+_xpad,y+_ypad):\ + sprintf(s,CM,y+_ypad,x+_xpad)) +#else + +#include +#include +#include +#include + +void +tc_init() +/* read in the termcap entry for this terminal. + */ +{ + static char tcbuf[2048+1024]; + char *bufp; + char *term = getenv("TERM"); + + if (( term ? tgetent(tcbuf, term) : 0) != 0) { + TERMNAME = term; + bufp = tcbuf + 2048; + CM = tgetstr("cm", &bufp); + UP = tgetstr("up", &bufp); + HO = tgetstr("ho", &bufp); + if (!HO) { + char *goto0 = tgoto(CM, 0, 0); + + if (goto0) + HO = strdup(goto0); + } + + CL = tgetstr("cl", &bufp); + CE = tgetstr("ce", &bufp); + BELL = tgetstr("vb", &bufp); + if (!BELL) + BELL = "\007"; + OL = tgetstr("al", &bufp); + UpS = tgetstr("sr", &bufp); + CURon = tgetstr("ve", &bufp); + CURoff = tgetstr("vi", &bufp); + + LINES = tgetnum("li"); + COLS = tgetnum("co"); + + /* don't trust li & co, because we might actually + * be on a console or gui instead of the tinned + * tty that termcap expects + */ +#if defined(TIOCGSIZE) + { struct ttysize tty; + if (ioctl(0, TIOCGSIZE, &tty) == 0) { + if (tty.ts_lines) LINES=tty.ts_lines; + if (tty.ts_cols) COLS=tty.ts_cols; + } + } +#elif defined(TIOCGWINSZ) + { struct winsize tty; + if (ioctl(0, TIOCGWINSZ, &tty) == 0) { + if (tty.ws_row) LINES=tty.ws_row; + if (tty.ws_col) COLS=tty.ws_col; + } + } +#endif + + dofscroll = LINES/2; + + /* set cursor movement keys to zero for now */ + FkL = CurRT = CurLT = CurUP = CurDN = EOF; + + canUPSCROLL = (UpS != NULL); + CA = (CM != NULL); + } +} +#endif diff --git a/src/cmd/levee/ucsd.c b/src/cmd/levee/ucsd.c new file mode 100644 index 0000000..22063ca --- /dev/null +++ b/src/cmd/levee/ucsd.c @@ -0,0 +1,86 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" + +#ifndef moveleft + +VOID PROC +moveleft(src,dest,length) +register char *src,*dest; +register int length; +{ + while (--length >= 0) + *(dest++) = *(src++); +} + +#endif /*moveleft*/ + +#ifndef moveright + +VOID PROC +moveright(src,dest,length) +register char *src,*dest; +register int length; +{ + src = &src[length]; + dest = &dest[length]; + while (--length >= 0) + *(--dest) = *(--src); +} + +#endif /*moveright*/ + +#ifndef fillchar + +VOID PROC +fillchar(src,length,ch) +register char *src,ch; +register int length; +{ + while (--length >= 0) + *(src++) = ch; +} + +#endif + +int PROC +scan(length,tst,ch,src) +int length; +register char tst,ch,*src; +{ + register int inc,l; + + if (length < 0) + inc = -1; + else + inc = 1; + if (tst == '!') { + for(l = ((int)inc)*length; l > 0; l--,src += (long)inc) + if (*src != ch) + break; + } + else { + for(l = ((int)inc)*length; l > 0; l--,src += (long)inc) + if (*src == ch) + break; + } + return length-(inc*l); +} diff --git a/src/cmd/levee/undo.c b/src/cmd/levee/undo.c new file mode 100644 index 0000000..256ed3a --- /dev/null +++ b/src/cmd/levee/undo.c @@ -0,0 +1,272 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +#include "levee.h" +#include "extern.h" + +#define BUFSZ sizeof(undo.coreblock) +#define AVAIL(x) ((x)<<1) +#define INDEX(x) ((1+x)>>1) + +bool PROC +pushblock(u) +struct undostack *u; +{ + if (u->blockp == 0) + if ((uwrite = OPEN_NEW(undobuf)) < 0) + return FALSE; + if (BUFSZ == WRITE_TEXT(uwrite, u->coreblock, BUFSZ)) { + u->blockp++; + u->ptr = 0; + return TRUE; + } + return FALSE; +} + +bool PROC +pushw(u, i) +struct undostack *u; +int i; +{ + if (u->ptr >= PAGESIZE && !pushblock(u)) + return FALSE; + u->coreblock[u->ptr++] = i; + return TRUE; +} + +bool PROC +pushmem(u, start, size) +struct undostack *u; +int start,size; +{ + int chunk; + bool ok; + + ok = TRUE; + while (ok && size > 0) { + chunk = min(size, AVAIL(PAGESIZE-u->ptr)); + moveleft(&core[start], (char*)&u->coreblock[u->ptr], chunk); + size -= chunk; + start += chunk; + if (size > 0) + ok = pushblock(u); + else + u->ptr += INDEX(chunk); + } + return ok; +} + +VOID PROC +zerostack(u) +struct undostack *u; +{ + if (u->blockp > 0) + CLOSE_FILE(uwrite); + u->blockp = 0; /* initialize the stack */ + u->ptr = 0; +} + +bool PROC +uputcmd(u, size, start, cmd) +struct undostack *u; +int size,start; +char cmd; +{ + return(pushw(u, size) && pushw(u, start) && pushw(u, cmd)); +} + +VOID PROC +insert_to_undo(u, start, size) +struct undostack *u; +int start,size; +{ + if (uputcmd(u, size, start, U_DELC)) { + fixmarkers(start, size); + bufmax += size; + } + else + error(); +} + +/* delete stuff from the buffer && put it into the undo stack */ + +bool PROC +delete_to_undo(u, start, lump) +struct undostack *u; +int start, lump; +{ + if (lump <= 0) + return TRUE; + else if (pushmem(u,start,lump) && uputcmd(u,lump,start,U_ADDC)) { + moveleft(&core[start+lump], &core[start], bufmax-(start+lump)); + bufmax -= lump; + fixmarkers(start,-lump); + return TRUE; + } + else + return FALSE; +} + +/* copy stuff into the undo buffer */ + +bool PROC +move_to_undo(u, start, lump) +struct undostack *u; +int start,lump; +{ + return pushmem(u, start, lump) && uputcmd(u,lump,start,U_MOVEC); +} + +bool PROC +popblock(u) +struct undostack *u; +{ + if (u->blockp > 0) { + if (SEEK_POSITION(uread, (long)((--u->blockp)*BUFSZ), 0) < 0) + return FALSE; + if (BUFSZ == READ_TEXT(uread, u->coreblock, BUFSZ)) { + u->ptr = PAGESIZE; + return TRUE; + } + } + return FALSE; +} + +bool PROC +popw(u, i) +struct undostack *u; +int *i; +{ + if (u->ptr < 1 && !popblock(u)) + return FALSE; + *i = u->coreblock[--u->ptr]; + return TRUE; +} + +bool PROC +popmem(u, start, size) +struct undostack *u; +int start, size; +{ + int chunk, loc; + bool ok; + + loc = start+size; /* running backwards */ + ok = TRUE; + while (ok && size > 0) { + chunk = min(size, AVAIL(u->ptr)); + size -= chunk; + loc -= chunk; + moveleft((char*)&u->coreblock[u->ptr-INDEX(chunk)], &core[loc], chunk); + if (size > 0) + ok = popblock(u); + else + u->ptr -= INDEX(chunk); + } + return(ok); +} + +/* delete (I)nserted text */ + +bool PROC +takeout(save_undo,curp) +struct undostack *save_undo; +int *curp; +{ + int lump; + + return popw(&undo,curp) && popw(&undo,&lump) + && delete_to_undo(save_undo,*curp,lump); +} + +bool PROC +copyover(save_undo,curp) +struct undostack *save_undo; +int *curp; +{ + int lump; + + return popw(&undo, curp) && popw(&undo, &lump) + && move_to_undo(save_undo, *curp, lump) + && popmem(&undo, *curp, lump); +} + +bool PROC +putin(save_undo,curp) +struct undostack *save_undo; +int *curp; +{ + int lump; + + if (popw(&undo,curp) && popw(&undo,&lump) && (bufmax+lump < SIZE)) { + insert_to_undo(save_undo, *curp, lump); + moveright(&core[*curp], &core[*curp+lump], bufmax-*curp); + if (popmem(&undo, *curp, lump)) + return TRUE; + else + moveleft(&core[*curp+lump], &core[*curp], bufmax-*curp); + } + return FALSE; +} + +/* driver for undo -- returns last address modified || -1 if error */ + +int PROC +fixcore(topp) +int *topp; +{ + int curp; + static struct undostack save_undo; + bool closeio, ok; + int cch; + + if (undo.blockp > 0 || undo.ptr > 0) { + closeio = (undo.blockp > 0); + if (closeio) { /* save diskfile */ + CLOSE_FILE(uwrite); /* close current undo file */ + rename(undobuf,undotmp); + uread = OPEN_OLD(undotmp); /* reopen it for reading */ + if (uread < 0) + return -1; + } + *topp = SIZE+1; + curp = -MAGICNUMBER; + save_undo.blockp = save_undo.ptr = 0; + ok = TRUE; + while (ok && popw(&undo,&cch)) { + switch (cch) { + case U_ADDC : ok = putin(&save_undo, &curp); break; + case U_MOVEC: ok = copyover(&save_undo, &curp); break; + case U_DELC : ok = takeout(&save_undo, &curp); break; + } + if (curp < *topp) + *topp = curp; + } + if (curp >= 0) + undo = save_undo; + if (closeio) { + CLOSE_FILE(uread); /* Zap old buffer */ + unlink(undotmp); + } + if (!ok) + error(); + return(curp); + } + return ERR; +} diff --git a/src/cmd/levee/unixcall.c b/src/cmd/levee/unixcall.c new file mode 100644 index 0000000..26a2d77 --- /dev/null +++ b/src/cmd/levee/unixcall.c @@ -0,0 +1,147 @@ +/* + * LEVEE, or Captain Video; A vi clone + * + * Copyright (c) 1982-2007 David L Parsons + * All rights reserved. + * + * Redistribution and use in source and binary forms, without or + * without modification, are permitted provided that the above + * copyright notice and this paragraph are duplicated in all such + * forms and that any documentation, advertising materials, and + * other materials related to such distribution and use acknowledge + * that the software was developed by David L Parsons (orc@pell.chi.il.us). + * My name may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ +/* + * Unix interface for levee + */ +#include "levee.h" + +#ifdef OS_UNIX + +#include "extern.h" +#include +#include +#include +#include +#include +#include + +#if USE_TERMCAP +#include +#endif + +int +min(a,b) +int a, b; +{ + return (a>b) ? b : a; +} + +int +max(a,b) +int a, b; +{ + return (a +#elif !OS_RMX +# include +#endif + + +int wilderr, wildcard; + +int PROC +expandargs(name, argcp, argvp) +char *name; +int *argcp; +char ***argvp; +{ +#if OS_RMX|OS_UNIX + wilderr = doaddwork(name, argcp, argvp) < 0; +#else + register char *p; + + wilderr = 0; + + if (p=glob(name, (char*)0)) { + do { + if (doaddwork(p, argcp, argvp) < 0) { + wilderr++; + break; + } + } while (p=glob((char*)0, (char*)0)); + } + else if (doaddwork(name, argcp, argvp) < 0) + wilderr++; +#endif /*!OS_RMX*/ + if (wilderr) + killargs(argcp, argvp); + return !wilderr; +} + +#define QUANTUM 10 + +int PROC +doaddwork(token,argcp,argvp) +char *token; +int *argcp; +char ***argvp; +{ + char **ap = *argvp; + int ac = *argcp; + int size; + + if ( ac%QUANTUM == 0) { /* realloc more memory! */ + size = (QUANTUM+ac)*sizeof(char**); + ap = (ac == 0)?malloc(size):realloc(ap, size); + if (!ap) { + *argcp = 0; + goto memfail; + } + } + if ( (ap[ac] = strdup(token)) ) { +#if OS_ATARI|OS_RMX|OS_FLEXOS + strlwr(ap[ac]); /* monocase filesystem */ +#endif + *argvp = ap; + return (*argcp)++; + } +memfail: + errmsg("no memory"); + return -1; +} + +VOID PROC +killargs(argcp, argvp) +int *argcp; +char ***argvp; +{ + int i; + + for (i=(*argcp)-1; i >= 0; i--) + free((*argvp)[i]); + if (*argcp) + free(*argvp); + *argcp = 0; + *argvp = 0L; +}