aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/vi
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/vi')
-rw-r--r--usr.bin/vi/Makefile80
-rw-r--r--usr.bin/vi/README152
-rw-r--r--usr.bin/vi/args.h4
-rw-r--r--usr.bin/vi/ascii.c93
-rw-r--r--usr.bin/vi/compat.h56
-rw-r--r--usr.bin/vi/cut.c323
-rw-r--r--usr.bin/vi/cut.h6
-rw-r--r--usr.bin/vi/delete.c30
-rw-r--r--usr.bin/vi/docs/README177
-rw-r--r--usr.bin/vi/docs/USD.doc/edit/Makefile18
-rw-r--r--usr.bin/vi/docs/USD.doc/edit/edit.vindex115
-rw-r--r--usr.bin/vi/docs/USD.doc/edit/edittut.ms2322
-rw-r--r--usr.bin/vi/docs/USD.doc/ex/Makefile14
-rw-r--r--usr.bin/vi/docs/USD.doc/ex/ex.rm2230
-rw-r--r--usr.bin/vi/docs/USD.doc/ex/ex.summary734
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/Makefile17
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/vi.apwh.ms1079
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/vi.chars644
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/vi.in2064
-rw-r--r--usr.bin/vi/docs/USD.doc/vi/vi.summary468
-rw-r--r--usr.bin/vi/docs/bugs.current48
-rw-r--r--usr.bin/vi/docs/changelog138
-rw-r--r--usr.bin/vi/docs/features47
-rw-r--r--usr.bin/vi/docs/internals/autowrite88
-rw-r--r--usr.bin/vi/docs/internals/gdb.script68
-rw-r--r--usr.bin/vi/docs/internals/input314
-rw-r--r--usr.bin/vi/docs/internals/quoting219
-rw-r--r--usr.bin/vi/docs/internals/structures61
-rw-r--r--usr.bin/vi/docs/set.opt.roff1065
-rw-r--r--usr.bin/vi/docs/spell.ok163
-rw-r--r--usr.bin/vi/docs/tutorial/vi.advanced1458
-rw-r--r--usr.bin/vi/docs/tutorial/vi.beginner741
-rw-r--r--usr.bin/vi/docs/tutorial/vi.tut.csh24
-rw-r--r--usr.bin/vi/docs/vi.1 (renamed from usr.bin/vi/vi.1)1
-rw-r--r--usr.bin/vi/docs/vi.ref523
-rw-r--r--usr.bin/vi/docs/vi.ref.txt634
-rw-r--r--usr.bin/vi/ex/ex.c (renamed from usr.bin/vi/nex/ex.c)223
-rw-r--r--usr.bin/vi/ex/ex_abbrev.c (renamed from usr.bin/vi/nex/ex_abbrev.c)16
-rw-r--r--usr.bin/vi/ex/ex_append.c (renamed from usr.bin/vi/nex/ex_append.c)27
-rw-r--r--usr.bin/vi/ex/ex_args.c (renamed from usr.bin/vi/nex/ex_args.c)22
-rw-r--r--usr.bin/vi/ex/ex_argv.c (renamed from usr.bin/vi/nex/ex_argv.c)68
-rw-r--r--usr.bin/vi/ex/ex_at.c (renamed from usr.bin/vi/nex/ex_at.c)16
-rw-r--r--usr.bin/vi/ex/ex_bang.c (renamed from usr.bin/vi/nex/ex_bang.c)15
-rw-r--r--usr.bin/vi/ex/ex_cd.c205
-rw-r--r--usr.bin/vi/ex/ex_delete.c (renamed from usr.bin/vi/nex/ex_delete.c)15
-rw-r--r--usr.bin/vi/ex/ex_digraph.c (renamed from usr.bin/vi/nex/ex_digraph.c)14
-rw-r--r--usr.bin/vi/ex/ex_display.c (renamed from usr.bin/vi/nex/ex_display.c)14
-rw-r--r--usr.bin/vi/ex/ex_edit.c (renamed from usr.bin/vi/nex/ex_edit.c)14
-rw-r--r--usr.bin/vi/ex/ex_equal.c (renamed from usr.bin/vi/nex/ex_equal.c)15
-rw-r--r--usr.bin/vi/ex/ex_exit.c (renamed from usr.bin/vi/nex/ex_exit.c)15
-rw-r--r--usr.bin/vi/ex/ex_file.c (renamed from usr.bin/vi/nex/ex_file.c)14
-rw-r--r--usr.bin/vi/ex/ex_global.c (renamed from usr.bin/vi/nex/ex_global.c)50
-rw-r--r--usr.bin/vi/ex/ex_init.c (renamed from usr.bin/vi/nex/ex_init.c)28
-rw-r--r--usr.bin/vi/ex/ex_join.c (renamed from usr.bin/vi/nex/ex_join.c)26
-rw-r--r--usr.bin/vi/ex/ex_map.c (renamed from usr.bin/vi/nex/ex_map.c)16
-rw-r--r--usr.bin/vi/ex/ex_mark.c (renamed from usr.bin/vi/nex/ex_mark.c)15
-rw-r--r--usr.bin/vi/ex/ex_mkexrc.c (renamed from usr.bin/vi/nex/ex_mkexrc.c)16
-rw-r--r--usr.bin/vi/ex/ex_move.c208
-rw-r--r--usr.bin/vi/ex/ex_open.c (renamed from usr.bin/vi/nex/ex_open.c)15
-rw-r--r--usr.bin/vi/ex/ex_preserve.c (renamed from usr.bin/vi/nex/ex_preserve.c)14
-rw-r--r--usr.bin/vi/ex/ex_print.c (renamed from usr.bin/vi/nex/ex_print.c)16
-rw-r--r--usr.bin/vi/ex/ex_put.c (renamed from usr.bin/vi/nex/ex_put.c)14
-rw-r--r--usr.bin/vi/ex/ex_read.c (renamed from usr.bin/vi/nex/ex_read.c)50
-rw-r--r--usr.bin/vi/ex/ex_screen.c (renamed from usr.bin/vi/nex/ex_screen.c)32
-rw-r--r--usr.bin/vi/ex/ex_script.c (renamed from usr.bin/vi/nex/ex_script.c)18
-rw-r--r--usr.bin/vi/ex/ex_set.c (renamed from usr.bin/vi/nex/ex_set.c)15
-rw-r--r--usr.bin/vi/ex/ex_shell.c (renamed from usr.bin/vi/nex/ex_shell.c)34
-rw-r--r--usr.bin/vi/ex/ex_shift.c (renamed from usr.bin/vi/nex/ex_shift.c)16
-rw-r--r--usr.bin/vi/ex/ex_source.c (renamed from usr.bin/vi/nex/ex_source.c)15
-rw-r--r--usr.bin/vi/ex/ex_stop.c (renamed from usr.bin/vi/nex/ex_stop.c)14
-rw-r--r--usr.bin/vi/ex/ex_subst.c (renamed from usr.bin/vi/nex/ex_subst.c)94
-rw-r--r--usr.bin/vi/ex/ex_tag.c (renamed from usr.bin/vi/nex/ex_tag.c)283
-rw-r--r--usr.bin/vi/ex/ex_undo.c (renamed from usr.bin/vi/nex/ex_undo.c)15
-rw-r--r--usr.bin/vi/ex/ex_usage.c (renamed from usr.bin/vi/nex/ex_usage.c)30
-rw-r--r--usr.bin/vi/ex/ex_util.c180
-rw-r--r--usr.bin/vi/ex/ex_version.c (renamed from usr.bin/vi/nex/ex_version.c)19
-rw-r--r--usr.bin/vi/ex/ex_visual.c (renamed from usr.bin/vi/nex/ex_visual.c)14
-rw-r--r--usr.bin/vi/ex/ex_write.c (renamed from usr.bin/vi/nex/ex_write.c)53
-rw-r--r--usr.bin/vi/ex/ex_yank.c (renamed from usr.bin/vi/nex/ex_yank.c)15
-rw-r--r--usr.bin/vi/ex/ex_z.c (renamed from usr.bin/vi/nex/ex_z.c)14
-rw-r--r--usr.bin/vi/ex/excmd.c (renamed from usr.bin/vi/nex/excmd.c)72
-rw-r--r--usr.bin/vi/ex/excmd.h.stub (renamed from usr.bin/vi/nex/excmd.h.stub)280
-rw-r--r--usr.bin/vi/ex/filter.c (renamed from usr.bin/vi/nex/filter.c)31
-rw-r--r--usr.bin/vi/ex/script.h (renamed from usr.bin/vi/nex/script.h)0
-rw-r--r--usr.bin/vi/ex/tag.h (renamed from usr.bin/vi/nex/tag.h)0
-rw-r--r--usr.bin/vi/exf.c35
-rw-r--r--usr.bin/vi/exf.h7
-rw-r--r--usr.bin/vi/gs.h28
-rw-r--r--usr.bin/vi/include/bitstring.h143
-rw-r--r--usr.bin/vi/include/cdefs.h98
-rw-r--r--usr.bin/vi/include/compat.h241
-rw-r--r--usr.bin/vi/include/err.h16
-rw-r--r--usr.bin/vi/include/file.h15
-rw-r--r--usr.bin/vi/include/glob.h92
-rw-r--r--usr.bin/vi/include/mpool.h135
-rw-r--r--usr.bin/vi/include/ndbm.h77
-rw-r--r--usr.bin/vi/include/queue.h245
-rw-r--r--usr.bin/vi/interrupt.h96
-rw-r--r--usr.bin/vi/intr.c178
-rw-r--r--usr.bin/vi/line.c27
-rw-r--r--usr.bin/vi/log.c61
-rw-r--r--usr.bin/vi/log.h6
-rw-r--r--usr.bin/vi/main.c196
-rw-r--r--usr.bin/vi/mark.c130
-rw-r--r--usr.bin/vi/mark.h37
-rw-r--r--usr.bin/vi/mem.h11
-rw-r--r--usr.bin/vi/msg.h26
-rw-r--r--usr.bin/vi/nex/ex_cd.c82
-rw-r--r--usr.bin/vi/nex/ex_move.c133
-rw-r--r--usr.bin/vi/nex/ex_util.c78
-rw-r--r--usr.bin/vi/nvi/v_ex.c55
-rw-r--r--usr.bin/vi/nvi/v_section.c146
-rw-r--r--usr.bin/vi/nvi/v_word.c560
-rw-r--r--usr.bin/vi/nvi/v_yank.c114
-rw-r--r--usr.bin/vi/nvi/vcmd.h274
-rw-r--r--usr.bin/vi/options.c142
-rw-r--r--usr.bin/vi/options.h.stub8
-rw-r--r--usr.bin/vi/options_f.c113
-rw-r--r--usr.bin/vi/pathnames.h4
-rw-r--r--usr.bin/vi/put.c248
-rw-r--r--usr.bin/vi/recover.c118
-rw-r--r--usr.bin/vi/screen.c25
-rw-r--r--usr.bin/vi/screen.h129
-rw-r--r--usr.bin/vi/search.c112
-rw-r--r--usr.bin/vi/search.h5
-rw-r--r--usr.bin/vi/seq.c144
-rw-r--r--usr.bin/vi/seq.h7
-rw-r--r--usr.bin/vi/sex/sex_confirm.c15
-rw-r--r--usr.bin/vi/sex/sex_get.c96
-rw-r--r--usr.bin/vi/sex/sex_refresh.c15
-rw-r--r--usr.bin/vi/sex/sex_screen.c33
-rw-r--r--usr.bin/vi/sex/sex_term.c22
-rw-r--r--usr.bin/vi/sex/sex_util.c28
-rw-r--r--usr.bin/vi/svi/svi_confirm.c14
-rw-r--r--usr.bin/vi/svi/svi_ex.c22
-rw-r--r--usr.bin/vi/svi/svi_get.c28
-rw-r--r--usr.bin/vi/svi/svi_line.c41
-rw-r--r--usr.bin/vi/svi/svi_refresh.c140
-rw-r--r--usr.bin/vi/svi/svi_relative.c312
-rw-r--r--usr.bin/vi/svi/svi_screen.c93
-rw-r--r--usr.bin/vi/svi/svi_screen.h37
-rw-r--r--usr.bin/vi/svi/svi_smap.c138
-rw-r--r--usr.bin/vi/svi/svi_split.c57
-rw-r--r--usr.bin/vi/svi/svi_util.c175
-rw-r--r--usr.bin/vi/term.c426
-rw-r--r--usr.bin/vi/term.h129
-rw-r--r--usr.bin/vi/timer.c240
-rw-r--r--usr.bin/vi/trace.c15
-rw-r--r--usr.bin/vi/util.c96
-rw-r--r--usr.bin/vi/vi.h51
-rw-r--r--usr.bin/vi/vi/getc.c (renamed from usr.bin/vi/nvi/getc.c)25
-rw-r--r--usr.bin/vi/vi/v_again.c (renamed from usr.bin/vi/nvi/v_again.c)21
-rw-r--r--usr.bin/vi/vi/v_at.c (renamed from usr.bin/vi/nvi/v_at.c)26
-rw-r--r--usr.bin/vi/vi/v_ch.c (renamed from usr.bin/vi/nvi/v_ch.c)224
-rw-r--r--usr.bin/vi/vi/v_delete.c (renamed from usr.bin/vi/nvi/v_delete.c)106
-rw-r--r--usr.bin/vi/vi/v_ex.c (renamed from usr.bin/vi/nvi/v_exmode.c)35
-rw-r--r--usr.bin/vi/vi/v_filter.c (renamed from usr.bin/vi/nvi/v_filter.c)21
-rw-r--r--usr.bin/vi/vi/v_increment.c (renamed from usr.bin/vi/nvi/v_increment.c)31
-rw-r--r--usr.bin/vi/vi/v_init.c (renamed from usr.bin/vi/nvi/v_init.c)19
-rw-r--r--usr.bin/vi/vi/v_join.c (renamed from usr.bin/vi/nvi/v_join.c)25
-rw-r--r--usr.bin/vi/vi/v_left.c286
-rw-r--r--usr.bin/vi/vi/v_mark.c (renamed from usr.bin/vi/nvi/v_left.c)172
-rw-r--r--usr.bin/vi/vi/v_match.c (renamed from usr.bin/vi/nvi/v_match.c)84
-rw-r--r--usr.bin/vi/vi/v_ntext.c (renamed from usr.bin/vi/nvi/v_ntext.c)305
-rw-r--r--usr.bin/vi/vi/v_paragraph.c (renamed from usr.bin/vi/nvi/v_paragraph.c)188
-rw-r--r--usr.bin/vi/vi/v_put.c (renamed from usr.bin/vi/nvi/v_put.c)31
-rw-r--r--usr.bin/vi/vi/v_redraw.c (renamed from usr.bin/vi/nvi/v_redraw.c)20
-rw-r--r--usr.bin/vi/vi/v_replace.c (renamed from usr.bin/vi/nvi/v_replace.c)84
-rw-r--r--usr.bin/vi/vi/v_right.c (renamed from usr.bin/vi/nvi/v_right.c)119
-rw-r--r--usr.bin/vi/vi/v_screen.c (renamed from usr.bin/vi/nvi/v_screen.c)22
-rw-r--r--usr.bin/vi/vi/v_scroll.c (renamed from usr.bin/vi/nvi/v_scroll.c)214
-rw-r--r--usr.bin/vi/vi/v_search.c (renamed from usr.bin/vi/nvi/v_search.c)281
-rw-r--r--usr.bin/vi/vi/v_section.c201
-rw-r--r--usr.bin/vi/vi/v_sentence.c (renamed from usr.bin/vi/nvi/v_sentence.c)174
-rw-r--r--usr.bin/vi/vi/v_shift.c (renamed from usr.bin/vi/nvi/v_shift.c)28
-rw-r--r--usr.bin/vi/vi/v_status.c (renamed from usr.bin/vi/nvi/v_status.c)19
-rw-r--r--usr.bin/vi/vi/v_stop.c (renamed from usr.bin/vi/nvi/v_stop.c)21
-rw-r--r--usr.bin/vi/vi/v_switch.c (renamed from usr.bin/vi/nvi/v_switch.c)19
-rw-r--r--usr.bin/vi/vi/v_tag.c (renamed from usr.bin/vi/nvi/v_tag.c)25
-rw-r--r--usr.bin/vi/vi/v_text.c (renamed from usr.bin/vi/nvi/v_text.c)325
-rw-r--r--usr.bin/vi/vi/v_ulcase.c (renamed from usr.bin/vi/nvi/v_ulcase.c)71
-rw-r--r--usr.bin/vi/vi/v_undo.c (renamed from usr.bin/vi/nvi/v_undo.c)29
-rw-r--r--usr.bin/vi/vi/v_util.c (renamed from usr.bin/vi/nvi/v_util.c)40
-rw-r--r--usr.bin/vi/vi/v_word.c569
-rw-r--r--usr.bin/vi/vi/v_xchar.c (renamed from usr.bin/vi/nvi/v_xchar.c)112
-rw-r--r--usr.bin/vi/vi/v_yank.c (renamed from usr.bin/vi/nvi/v_mark.c)75
-rw-r--r--usr.bin/vi/vi/v_z.c (renamed from usr.bin/vi/nvi/v_z.c)32
-rw-r--r--usr.bin/vi/vi/v_zexit.c (renamed from usr.bin/vi/nvi/v_exit.c)23
-rw-r--r--usr.bin/vi/vi/vcmd.c (renamed from usr.bin/vi/nvi/vcmd.c)196
-rw-r--r--usr.bin/vi/vi/vcmd.h329
-rw-r--r--usr.bin/vi/vi/vi.c (renamed from usr.bin/vi/nvi/vi.c)303
-rw-r--r--usr.bin/vi/xaw/xaw_screen.c18
192 files changed, 23646 insertions, 6545 deletions
diff --git a/usr.bin/vi/Makefile b/usr.bin/vi/Makefile
index fbb1588cebd8..b1ed449041d8 100644
--- a/usr.bin/vi/Makefile
+++ b/usr.bin/vi/Makefile
@@ -1,21 +1,24 @@
-# @(#)Makefile 8.26 (Berkeley) 1/12/94
-
-PROG= vi
-MAN1= vi.1
-BINDIR?= /usr/bin
+# @(#)Makefile 8.30 (Berkeley) 3/22/94
+# $Id: Makefile,v 1.17 1994/06/02 00:27:52 phk Exp $
+PROG= nvi
#CFLAGS=-g -DDEBUG
#CFLAGS+=-pg
-CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/obj -I${.CURDIR}/include -I${.CURDIR}/nex -I${.CURDIR}/nvi
+CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/ex -I${.CURDIR}/vi
#STRIP=
-.PATH: ${.CURDIR}/nex ${.CURDIR}/sex ${.CURDIR}/nvi ${.CURDIR}/svi \
- ${.CURDIR}/xaw
-CLEANFILES+=ex
+.PATH: ${.CURDIR}/ex ${.CURDIR}/sex ${.CURDIR}/vi \
+ ${.CURDIR}/svi ${.CURDIR}/xaw
+#CLEANFILES+=ex
+CLEANFILES+=vi.1 vi-ref.1
+MANSRC= `pwd`
+MAN1+= vi.1 vi-ref.1
+
+MLINKS+=vi.1 nvi.1
# General sources.
-SRCS= ascii.c cut.c delete.c exf.c line.c log.c main.c mark.c \
- options.c options_f.c screen.c search.c seq.c recover.c \
- term.c timer.c trace.c util.c
+SRCS= ascii.c cut.c delete.c exf.c intr.c line.c log.c main.c \
+ mark.c options.c options_f.c put.c screen.c search.c seq.c \
+ recover.c term.c timer.c trace.c util.c
# Ex source.
SRCS+= ex.c ex_abbrev.c ex_append.c ex_args.c ex_argv.c ex_at.c \
@@ -32,13 +35,13 @@ SRCS+= sex_confirm.c sex_get.c sex_refresh.c sex_screen.c sex_term.c \
sex_util.c
# Vi source.
-SRCS+= getc.c v_again.c v_at.c v_ch.c v_delete.c v_ex.c v_exit.c \
- v_exmode.c v_filter.c v_increment.c v_init.c v_join.c v_left.c \
- v_mark.c v_match.c v_ntext.c v_paragraph.c v_put.c v_redraw.c \
- v_replace.c v_right.c v_screen.c v_scroll.c v_search.c v_section.c \
- v_sentence.c v_shift.c v_status.c v_stop.c v_switch.c v_tag.c \
- v_text.c v_ulcase.c v_undo.c v_util.c v_word.c v_xchar.c v_yank.c \
- v_z.c vcmd.c vi.c
+SRCS+= getc.c v_again.c v_at.c v_ch.c v_delete.c v_ex.c v_filter.c \
+ v_increment.c v_init.c v_join.c v_left.c v_mark.c v_match.c \
+ v_ntext.c v_paragraph.c v_put.c v_redraw.c v_replace.c v_right.c \
+ v_screen.c v_scroll.c v_search.c v_section.c v_sentence.c \
+ v_shift.c v_status.c v_stop.c v_switch.c v_tag.c v_text.c \
+ v_ulcase.c v_undo.c v_util.c v_word.c v_xchar.c v_yank.c \
+ v_z.c v_zexit.c vcmd.c vi.c
# Vi curses screen source.
SRCS+= svi_confirm.c svi_ex.c svi_get.c svi_line.c svi_refresh.c \
@@ -49,17 +52,21 @@ SRCS+= xaw_screen.c
#LDADD+=-pg
DPADD+= ${LIBCURSES} ${LIBTERM} ${LIBUTIL}
-LDADD+= -lcurses -ltermlib -lutil
+LDADD+= -lcurses -ltermlib -lutil
SPECHDR=excmd.h options.h
CLEANFILES+=${SPECHDR}
-DPSRCS+=${SPECHDR}
-LINKS= ${BINDIR}/vi ${BINDIR}/ex ${BINDIR}/vi ${BINDIR}/view
+LINKS= ${BINDIR}/nvi ${BINDIR}/vi ${BINDIR}/nvi ${BINDIR}/ex \
+ ${BINDIR}/nvi ${BINDIR}/view
-all: vi vi.1
+all: excmd.h options.h nvi vi.1 vi-ref.1
+ - rm -f vi
+ - rm -f ex
+ - if [ ! -d vi ]; then ln nvi vi; fi
+ - if [ ! -d ex ]; then ln nvi ex; fi
warn:: ${SRCS}
-(cd ${.CURDIR} && \
- gcc -Wall -O -DDEBUG -Iobj -Invi -Inex -I. ${.ALLSRC} \
+ gcc -Wall -O -DDEBUG -Iobj -Ivi -Iex -I. ${.ALLSRC} \
-lcurses -ltermlib 2>&1 | \
sed -e "/warning: .*sccsid.*defined but not used/d" \
-e "/warning: suggest parentheses around/d" \
@@ -85,15 +92,34 @@ options.h: options.h.stub options.c # Makefile
excmd.h: excmd.h.stub excmd.c # Makefile
rm -f excmd.h
- cp ${.CURDIR}/nex/excmd.h.stub excmd.h
+ cp ${.CURDIR}/ex/excmd.h.stub excmd.h
chmod 664 excmd.h
(echo '/^\/\* C_[0-9A-Z_]* \*\/$$/ {'; \
echo 'printf("#define %s %d\n", $$2, cnt++)'; \
echo 'next'; \
echo '}') > /tmp/__vi.excmd.h
- awk -f /tmp/__vi.excmd.h ${.CURDIR}/nex/excmd.c >> excmd.h
+ awk -f /tmp/__vi.excmd.h ${.CURDIR}/ex/excmd.c >> excmd.h
rm -f /tmp/__vi.excmd.h
+docs: vi.0.txt vi.0.ps vi.ref.txt vi.ref.ps
+vi.0.txt: vi.1 set.opt.roff
+ cpp -DMANUAL -I${.CURDIR}/docs ${.CURDIR}/docs/vi.1 | \
+ sed -e '/^#/d' -e '/^$$/d' | groff -man -Tascii > $@
+vi.0.ps: vi.1 set.opt.roff
+ cpp -DMANUAL -I${.CURDIR}/docs ${.CURDIR}/docs/vi.1 | \
+ sed -e '/^#/d' -e '/^$$/d' | groff -man > $@
+vi.ref.txt: vi.ref set.opt.roff
+ cpp -DREFERENCE -I${.CURDIR}/docs ${.CURDIR}/docs/vi.ref | \
+ sed -e '/^#/d' -e '/^$$/d' | groff -man -Tascii > $@
+vi.ref.ps: vi.ref set.opt.roff
+ cpp -DREFERENCE -I${.CURDIR}/docs ${.CURDIR}/docs/vi.ref | \
+ sed -e '/^#/d' -e '/^$$/d' | groff -man > $@
+
+vi.1: $(.CURDIR)/docs/vi.1 $(.CURDIR)/docs/set.opt.roff
+ cpp -DMANUAL -P -I$(.CURDIR)/docs $(.CURDIR)/docs/vi.1 > vi.1
+
+vi-ref.1: $(.CURDIR)/docs/vi.ref $(.CURDIR)/docs/set.opt.roff
+ cpp -DREFERENCE -P -I$(.CURDIR)/docs $(.CURDIR)/docs/vi.ref > vi-ref.1
.include <bsd.prog.mk>
-.depend: ${SPECHDR}
+.depend: compat.h ${SPECHDR}
diff --git a/usr.bin/vi/README b/usr.bin/vi/README
index a33bfc6f04c3..e46f4de58bd1 100644
--- a/usr.bin/vi/README
+++ b/usr.bin/vi/README
@@ -1,12 +1,13 @@
-# @(#)README 8.40 (Berkeley) 1/12/94
+# @(#)README 8.54 (Berkeley) 3/24/94
-This is the README for version 1.01 of nvi, a freely redistributable
-replacement for the vi and ex text editors. It can be retrieved via
-anonymous ftp from ftp.uu.net, or from ftp.cs.berkeley.edu. In the
-latter, it is in the directory ucb/4bsd, and is named nvi.tar.Z.
+This is the README for version 1.11 of nex/nvi, a freely redistributable
+replacement for the Berkeley ex and vi text editors. The compressed tar
+archive can be retrieved by anonymous ftp from ftp.cs.berkeley.edu, from
+the file ucb/4bsd/nvi.tar.Z. There is a gzip'd tar archive, nvi.tar.z,
+in the same directory.
-If you have any questions or problems with nvi, please send them to
-me by electronic mail at one of the following addresses:
+If you have any questions about nvi, or problems making it work, please
+contact me by electronic mail at one of the following addresses:
uunet!bostic
bostic@cs.berkeley.edu
@@ -16,12 +17,12 @@ Keith Bostic
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
o Redistribution:
-Nvi is copyrighted by the The Regents of the University of California,
-but may be freely redistributed (or used to line your birdcage) under
-the following conditions:
+This software is copyrighted by the The Regents of the University of
+California, but may be freely redistributed (or sold, or used to line
+your birdcage) under the following conditions:
/*-
- * Copyright (c) 1994
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,99 +78,82 @@ o From the original vi acknowledgements, by William Joy and Mark Horton:
work on a large number of terminals and Unix systems.
o And...
-
The financial support of UUNET Communications Services is gratefully
acknowledged.
=-=-=-=-=-=-=-=-=-=-=
-o Comments:
-
-This software is beta software, although it's pretty stable. Almost
-of the necessary functionality for ex/vi is in it, the only missing
-pieces are fairly obscure.
+o Status:
-Code fixes are very much appreciated, of course, but if you can't
-provide them, please send me as much information as you can as to how
-to reproduce the bug, and I'll try to fix it here. In particular, the
-screen routines are nasty stuff, and you probably don't want to mess
-with them. Stack traces of core dumps are sometimes helpful, but an
-example file with a set of keystrokes that causes the problem is far
-better.
+This software is in beta test, and it's believed to be pretty stable.
+Almost all of the historic functionality in ex/vi is there, the missing
+pieces are fairly obscure. In particular, the edcompatible, hardtabs*,
+lisp*, optimize*, redraw*, and slowopen* options are recognized, but not
+implemented.
Nvi is mostly 8-bit clean. This isn't difficult to fix, and was left in
during initial development to make things easier. Wide character support
will be integrated at the same time it is made fully 8-bit clean.
-=-=-=-=-=-=-=-=-=-=-=
-o New features:
-
There aren't a lot of new features in nex/nvi, but there are a few things
-you might like:
-
- o 8-bit clean data, practically infinite lines/files.
- ^Vx[0-9A-Fa-f]* in input mode will insert any
- legal character value.
- o Split screens:
- :sp[lit] [file ...] splits the screen.
- ^W switches between screens.
- :resize count grows/shrinks the current screen.
- o Background/foreground screens
- :bg backgrounds the current screen.
- :di[splay] s[creens] lists the hidden screens.
- :fg [file] foregrounds the specified (or next) screen.
- o Shell screens:
- :sc[ript] [file ...] runs a shell in the screen.
- Carriage return sends a line to the shell.
- o Buffer, screens, tags display:
- :di[splay] b[uffers] displays the current cut buffers.
- :di[splay] s[creens] displays the hidden screen names.
- :di[splay] t[ags] displays the current tags stack.
- o Tag stacks:
- ^T returns to previous tag location.
- :tagpop [number | file] returns to previous tag location,
- or, optionally tag #N, or the tag in a specific file.
- :tagtop returns to first tag location.
- o Infinite undo:
- A '.' command immediately after a 'u' command continues
- either forward or backward depending on whether the 'u'
- command was an undo or a redo.
- o Usage information:
- :exu[sage] [cmd] for ex commands.
- :viu[sage] [key] for vi commands.
- :help
- o Extended RE expressions:
- :set extended turns on extended RE's, so you can
- do "/in|or" and search for the next occurrence of
- more than one expression.
- o Word search:
- ^A searches for the word referenced by the cursor.
- o Number increment:
- # increments the number referenced by the cursor.
- o Previous file:
- :prev[ious][!] edits the previous file from the
- argument list.
+you might like. See the "ADDITIONAL FEATURES" section of the manual page
+(docs/vi.0.txt, docs/vi.0.ps) for a list.
=-=-=-=-=-=-=-=-=-=-=
o Porting information:
-The directory PORT has directories per machine/OS combination, with
-V7-style Makefiles which build nvi. See the file PORT/README for
-more detailed information.
+The directory PORT has directories per OS/machine combination, with
+V7-style Makefiles which build nex/nvi. See the file PORT/README for
+detailed information.
=-=-=-=-=-=-=-=-=-=-=
-o Directories:
+o Bug reports:
+
+Code fixes are appreciated, of course, but if you can't provide them,
+please email me as much information as you can as to how to reproduce
+the bug, and I'll try to fix it locally. In particular, the screen
+routines are nasty stuff, and you probably don't want to mess with them.
+Stack traces of core dumps are sometimes helpful, but an example file
+with a set of keystrokes that causes the problem is far better. Also,
+make sure that you include the dimensions of the screen on which the
+problem occurred, your startup files (.exrc, .nexrc), and the environment
+variable (EXINIT, NEXINIT) values.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Layout:
+
+nvi:
+ Source files for pieces of code that are shared by all the
+ editors, like searching and logging code or code translating
+ line numbers into requests to the dbopen(3) database code.
+ It also has the code for adding, deleting, and changing "records"
+ in the underlying database.
-The main directory, nvi, contains source files for pieces of code that
-are shared by all the editors, like searching and logging code or code
-translating line numbers into requests to the dbopen(3) database code.
-It also has the code for adding, deleting, and changing "records" in
-the underlying database.
+nvi/PORT:
+ Porting directories, one per OS/architecture combination. See
+ nvi/PORT/README for porting information.
nvi/docs:
- The nvi/docs directory has technical information about data
- structures and some of the trickier parts of vi like quoting,
- key mapping, input queues, and executing buffers, and a
- description of how nvi does edit session recovery.
+ The nvi/docs directory has all of the nvi documentation:
+
+ README -- Nvi main README file.
+ USD.doc -- Historic vi documentation (in roff source form).
+ bugs.current -- Known bugs in the current nvi implementation.
+ changelog -- Log of changes from version to version.
+ features -- Todo list, suggested features list.
+ internals/
+ autowrite -- Vi autowrite option discussion.
+ gdb.script -- GDB debugging scripts.
+ input -- Vi maps, executable buffers, and input discussion.
+ quoting -- Vi quoting discussion.
+ structures -- Nvi internal structure description.
+ spell.ok -- Misspellings list for README, vi.1.
+ tutorial -- Historic vi tutorial
+ vi.0.ps -- PostScript of vi.1.
+ vi.0.txt -- Flat text of vi.1.
+ vi.1 -- Nvi man page (in roff source form).
+ vi.ref -- Nvi reference (in roff source form).
+ vi.ref.ps -- PostScript of vi.ref.
+ vi.ref.txt -- Flat text of vi.ref.
nvi/ex:
The nvi/ex directory is the ex source code. Because vi has the
diff --git a/usr.bin/vi/args.h b/usr.bin/vi/args.h
index 4d437442d866..01ce4cec831d 100644
--- a/usr.bin/vi/args.h
+++ b/usr.bin/vi/args.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)args.h 8.3 (Berkeley) 12/19/93
+ * @(#)args.h 8.4 (Berkeley) 3/16/94
*/
/*
diff --git a/usr.bin/vi/ascii.c b/usr.bin/vi/ascii.c
index 7a7102574165..9f6089b93563 100644
--- a/usr.bin/vi/ascii.c
+++ b/usr.bin/vi/ascii.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,44 +32,55 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ascii.c 8.5 (Berkeley) 11/29/93";
+static char sccsid[] = "@(#)ascii.c 8.7 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
CHNAME const asciiname[UCHAR_MAX + 1] = {
{"^@", 2}, {"^A", 2}, {"^B", 2}, {"^C", 2},
- {"^D", 2}, {"^E", 2}, {"^F", 2}, {"^G", 2},
+ {"^D", 2}, {"^E", 2}, {"^F", 2}, {"^G", 2},
{"^H", 2}, {"^I", 2}, {"^J", 2}, {"^K", 2},
- {"^L", 2}, {"^M", 2}, {"^N", 2}, {"^O", 2},
+ {"^L", 2}, {"^M", 2}, {"^N", 2}, {"^O", 2},
{"^P", 2}, {"^Q", 2}, {"^R", 2}, {"^S", 2},
- {"^T", 2}, {"^U", 2}, {"^V", 2}, {"^W", 2},
+ {"^T", 2}, {"^U", 2}, {"^V", 2}, {"^W", 2},
{"^X", 2}, {"^Y", 2}, {"^Z", 2}, {"^[", 2},
- {"^\\", 2}, {"^]", 2}, {"^^", 2}, {"^_", 2},
+ {"^\\", 2}, {"^]", 2}, {"^^", 2}, {"^_", 2},
{" ", 1}, {"!", 1}, {"\"", 1}, {"#", 1},
- {"$", 1}, {"%", 1}, {"&", 1}, {"'", 1},
+ {"$", 1}, {"%", 1}, {"&", 1}, {"'", 1},
{"(", 1}, {")", 1}, {"*", 1}, {"+", 1},
- {",", 1}, {"-", 1}, {".", 1}, {"/", 1},
+ {",", 1}, {"-", 1}, {".", 1}, {"/", 1},
{"0", 1}, {"1", 1}, {"2", 1}, {"3", 1},
- {"4", 1}, {"5", 1}, {"6", 1}, {"7", 1},
+ {"4", 1}, {"5", 1}, {"6", 1}, {"7", 1},
{"8", 1}, {"9", 1}, {":", 1}, {";", 1},
- {"<", 1}, {"=", 1}, {">", 1}, {"?", 1},
+ {"<", 1}, {"=", 1}, {">", 1}, {"?", 1},
{"@", 1}, {"A", 1}, {"B", 1}, {"C", 1},
- {"D", 1}, {"E", 1}, {"F", 1}, {"G", 1},
+ {"D", 1}, {"E", 1}, {"F", 1}, {"G", 1},
{"H", 1}, {"I", 1}, {"J", 1}, {"K", 1},
- {"L", 1}, {"M", 1}, {"N", 1}, {"O", 1},
+ {"L", 1}, {"M", 1}, {"N", 1}, {"O", 1},
{"P", 1}, {"Q", 1}, {"R", 1}, {"S", 1},
- {"T", 1}, {"U", 1}, {"V", 1}, {"W", 1},
+ {"T", 1}, {"U", 1}, {"V", 1}, {"W", 1},
{"X", 1}, {"Y", 1}, {"Z", 1}, {"[", 1},
- {"\\", 1}, {"]", 1}, {"^", 1}, {"_", 1},
+ {"\\", 1}, {"]", 1}, {"^", 1}, {"_", 1},
{"`", 1}, {"a", 1}, {"b", 1}, {"c", 1},
- {"d", 1}, {"e", 1}, {"f", 1}, {"g", 1},
+ {"d", 1}, {"e", 1}, {"f", 1}, {"g", 1},
{"h", 1}, {"i", 1}, {"j", 1}, {"k", 1},
- {"l", 1}, {"m", 1}, {"n", 1}, {"o", 1},
+ {"l", 1}, {"m", 1}, {"n", 1}, {"o", 1},
{"p", 1}, {"q", 1}, {"r", 1}, {"s", 1},
- {"t", 1}, {"u", 1}, {"v", 1}, {"w", 1},
+ {"t", 1}, {"u", 1}, {"v", 1}, {"w", 1},
{"x", 1}, {"y", 1}, {"z", 1}, {"{", 1},
{"|", 1}, {"}", 1}, {"~", 1}, {"^?", 2},
{"0x80", 4}, {"0x81", 4}, {"0x82", 4}, {"0x83", 4},
@@ -80,30 +91,30 @@ CHNAME const asciiname[UCHAR_MAX + 1] = {
{"0x94", 4}, {"0x95", 4}, {"0x96", 4}, {"0x97", 4},
{"0x98", 4}, {"0x99", 4}, {"0x9a", 4}, {"0x9b", 4},
{"0x9c", 4}, {"0x9d", 4}, {"0x9e", 4}, {"0x9f", 4},
- {"\xa0", 1}, {"\xa1", 1}, {"\xa2", 1}, {"\xa3", 1},
- {"\xa4", 1}, {"\xa5", 1}, {"\xa6", 1}, {"\xa7", 1},
- {"\xa8", 1}, {"\xa9", 1}, {"\xaa", 1}, {"\xab", 1},
- {"\xac", 1}, {"\xad", 1}, {"\xae", 1}, {"\xaf", 1},
- {"\xb0", 1}, {"\xb1", 1}, {"\xb2", 1}, {"\xb3", 1},
- {"\xb4", 1}, {"\xb5", 1}, {"\xb6", 1}, {"\xb7", 1},
- {"\xb8", 1}, {"\xb9", 1}, {"\xba", 1}, {"\xbb", 1},
- {"\xbc", 1}, {"\xbd", 1}, {"\xbe", 1}, {"\xbf", 1},
- {"\xc0", 1}, {"\xc1", 1}, {"\xc2", 1}, {"\xc3", 1},
- {"\xc4", 1}, {"\xc5", 1}, {"\xc6", 1}, {"\xc7", 1},
- {"\xc8", 1}, {"\xc9", 1}, {"\xca", 1}, {"\xcb", 1},
- {"\xcc", 1}, {"\xcd", 1}, {"\xce", 1}, {"\xcf", 1},
- {"\xd0", 1}, {"\xd1", 1}, {"\xd2", 1}, {"\xd3", 1},
- {"\xd4", 1}, {"\xd5", 1}, {"\xd6", 1}, {"\xd7", 1},
- {"\xd8", 1}, {"\xd9", 1}, {"\xda", 1}, {"\xdb", 1},
- {"\xdc", 1}, {"\xdd", 1}, {"\xde", 1}, {"\xdf", 1},
- {"\xe0", 1}, {"\xe1", 1}, {"\xe2", 1}, {"\xe3", 1},
- {"\xe4", 1}, {"\xe5", 1}, {"\xe6", 1}, {"\xe7", 1},
- {"\xe8", 1}, {"\xe9", 1}, {"\xea", 1}, {"\xeb", 1},
- {"\xec", 1}, {"\xed", 1}, {"\xee", 1}, {"\xef", 1},
- {"\xf0", 1}, {"\xf1", 1}, {"\xf2", 1}, {"\xf3", 1},
- {"\xf4", 1}, {"\xf5", 1}, {"\xf6", 1}, {"\xf7", 1},
- {"\xf8", 1}, {"\xf9", 1}, {"\xfa", 1}, {"\xfb", 1},
- {"\xfc", 1}, {"\xfd", 1}, {"\xfe", 1}, {"\xff", 1},
+ {"0xa0", 4}, {"0xa1", 4}, {"0xa2", 4}, {"0xa3", 4},
+ {"0xa4", 4}, {"0xa5", 4}, {"0xa6", 4}, {"0xa7", 4},
+ {"0xa8", 4}, {"0xa9", 4}, {"0xaa", 4}, {"0xab", 4},
+ {"0xac", 4}, {"0xad", 4}, {"0xae", 4}, {"0xaf", 4},
+ {"0xb0", 4}, {"0xb1", 4}, {"0xb2", 4}, {"0xb3", 4},
+ {"0xb4", 4}, {"0xb5", 4}, {"0xb6", 4}, {"0xb7", 4},
+ {"0xb8", 4}, {"0xb9", 4}, {"0xba", 4}, {"0xbb", 4},
+ {"0xbc", 4}, {"0xbd", 4}, {"0xbe", 4}, {"0xbf", 4},
+ {"0xc0", 4}, {"0xc1", 4}, {"0xc2", 4}, {"0xc3", 4},
+ {"0xc4", 4}, {"0xc5", 4}, {"0xc6", 4}, {"0xc7", 4},
+ {"0xc8", 4}, {"0xc9", 4}, {"0xca", 4}, {"0xcb", 4},
+ {"0xcc", 4}, {"0xcd", 4}, {"0xce", 4}, {"0xcf", 4},
+ {"0xd0", 4}, {"0xd1", 4}, {"0xd2", 4}, {"0xd3", 4},
+ {"0xd4", 4}, {"0xd5", 4}, {"0xd6", 4}, {"0xd7", 4},
+ {"0xd8", 4}, {"0xd9", 4}, {"0xda", 4}, {"0xdb", 4},
+ {"0xdc", 4}, {"0xdd", 4}, {"0xde", 4}, {"0xdf", 4},
+ {"0xe0", 4}, {"0xe1", 4}, {"0xe2", 4}, {"0xe3", 4},
+ {"0xe4", 4}, {"0xe5", 4}, {"0xe6", 4}, {"0xe7", 4},
+ {"0xe8", 4}, {"0xe9", 4}, {"0xea", 4}, {"0xeb", 4},
+ {"0xec", 4}, {"0xed", 4}, {"0xee", 4}, {"0xef", 4},
+ {"0xf0", 4}, {"0xf1", 4}, {"0xf2", 4}, {"0xf3", 4},
+ {"0xf4", 4}, {"0xf5", 4}, {"0xf6", 4}, {"0xf7", 4},
+ {"0xf8", 4}, {"0xf9", 4}, {"0xfa", 4}, {"0xfb", 4},
+ {"0xfc", 4}, {"0xfd", 4}, {"0xfe", 4}, {"0xff", 4},
};
char *
diff --git a/usr.bin/vi/compat.h b/usr.bin/vi/compat.h
new file mode 100644
index 000000000000..bea07ad84259
--- /dev/null
+++ b/usr.bin/vi/compat.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)compat.h 8.16 (Berkeley) 3/8/94
+ */
+
+#ifndef _COMPAT_H_
+#define _COMPAT_H_
+
+#include <sys/types.h>
+
+/*
+ * If your system doesn't typedef the following basic integral types,
+ * change the 0 to a 1, and change the values as necessary.
+ */
+typedef char int8_t;
+typedef unsigned char u_int8_t;
+typedef short int16_t;
+typedef unsigned short u_int16_t;
+typedef int int32_t;
+typedef unsigned int u_int32_t;
+#ifdef WE_DONT_NEED_QUADS
+typedef long long int64_t;
+typedef unsigned long long u_int64_t;
+#endif
+
+#endif /* !_COMPAT_H_ */
diff --git a/usr.bin/vi/cut.c b/usr.bin/vi/cut.c
index 5a9b292ce175..a4e277a10228 100644
--- a/usr.bin/vi/cut.c
+++ b/usr.bin/vi/cut.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,23 +32,33 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)cut.c 8.20 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)cut.c 8.26 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
-static int cb_line __P((SCR *, EXF *, recno_t, size_t, size_t, TEXT **));
+static int cb_line __P((SCR *, EXF *, recno_t, size_t, size_t, CB *));
static int cb_rotate __P((SCR *));
-/*
+/*
* cut --
* Put a range of lines/columns into a buffer.
*
@@ -57,7 +67,7 @@ static int cb_rotate __P((SCR *));
* default buffer storage. There is a pointer, too, which is the current
* default buffer, i.e. it may point to the default buffer or a named buffer
* depending on into what buffer the last text was cut. In both delete and
- * yank operations, text is cut into either the buffer named by the user, or
+ * yank operations, text is cut into either the buffer named by the user or
* the default buffer. If it's a delete of information on more than a single
* line, the contents of the numbered buffers are rotated up one, the contents
* of the buffer named '9' are discarded, and the text is also cut into the
@@ -68,14 +78,15 @@ static int cb_rotate __P((SCR *));
* of replaced.
*
* !!!
- * The contents of the default buffer would disappear after most operations in
- * historic vi. It's unclear that this is useful, so we don't bother.
+ * The contents of the default buffer would disappear after most operations
+ * in historic vi. It's unclear that this is useful, so we don't bother.
*
* When users explicitly cut text into the numeric buffers, historic vi became
* genuinely strange. I've never been able to figure out what was supposed to
* happen. It behaved differently if you deleted text than if you yanked text,
* and, in the latter case, the text was appended to the buffer instead of
- * replacing the contents. Hopefully it's not worth getting right.
+ * replacing the contents. Hopefully it's not worth getting right, and here
+ * we just treat the numeric buffers like any other named buffer.
*/
int
cut(sp, ep, cbp, namep, fm, tm, flags)
@@ -87,33 +98,26 @@ cut(sp, ep, cbp, namep, fm, tm, flags)
MARK *fm, *tm;
{
CHAR_T name;
- TEXT *tp;
recno_t lno;
- size_t len;
int append, namedbuffer, setdefcb;
-#if defined(DEBUG) && 0
- TRACE(sp, "cut: from {%lu, %d}, to {%lu, %d}%s\n",
- fm->lno, fm->cno, tm->lno, tm->cno,
- LF_ISSET(CUT_LINEMODE) ? " LINE MODE" : "");
-#endif
if (cbp == NULL) {
- if (LF_ISSET(CUT_DELETE) &&
- (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) {
- (void)cb_rotate(sp);
- name = '1';
- goto defcb;
- }
if (namep == NULL) {
+ if (LF_ISSET(CUT_DELETE) &&
+ (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) {
+ (void)cb_rotate(sp);
+ name = '1';
+ goto defcb;
+ }
cbp = sp->gp->dcb_store;
append = namedbuffer = 0;
- setdefcb = 1;
} else {
name = *namep;
defcb: CBNAME(sp, cbp, name);
append = isupper(name);
- namedbuffer = setdefcb = 1;
+ namedbuffer = 1;
}
+ setdefcb = 1;
} else
append = namedbuffer = setdefcb = 0;
@@ -135,45 +139,35 @@ defcb: CBNAME(sp, cbp, name);
cbp->flags = 0;
}
+#define ENTIRE_LINE 0
/* In line mode, it's pretty easy, just cut the lines. */
if (LF_ISSET(CUT_LINEMODE)) {
- for (lno = fm->lno; lno <= tm->lno; ++lno) {
- if (cb_line(sp, ep, lno, 0, 0, &tp))
- goto mem;
- CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
- cbp->len += tp->len;
- }
cbp->flags |= CB_LMODE;
+ for (lno = fm->lno; lno <= tm->lno; ++lno)
+ if (cb_line(sp, ep, lno, 0, 0, cbp))
+ goto cb_line_fail;
} else {
- /* Get the first line. */
- len = fm->lno < tm->lno ? 0 : tm->cno - fm->cno;
- if (cb_line(sp, ep, fm->lno, fm->cno, len, &tp))
- goto mem;
- CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
- cbp->len += tp->len;
+ /*
+ * Get the first line. A length of 0 causes cb_line
+ * to cut from the MARK to the end of the line.
+ */
+ if (cb_line(sp, ep, fm->lno, fm->cno,
+ fm->lno != tm->lno ? ENTIRE_LINE : (tm->cno - fm->cno) + 1,
+ cbp))
+ goto cb_line_fail;
/* Get the intermediate lines. */
- for (lno = fm->lno; ++lno < tm->lno;) {
- if (cb_line(sp, ep, lno, 0, 0, &tp))
- goto mem;
- CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
- cbp->len += tp->len;
- }
+ for (lno = fm->lno; ++lno < tm->lno;)
+ if (cb_line(sp, ep, lno, 0, ENTIRE_LINE, cbp))
+ goto cb_line_fail;
/* Get the last line. */
- if (tm->lno > fm->lno && tm->cno > 0) {
- if (cb_line(sp, ep, lno, 0, tm->cno, &tp)) {
-mem: if (append)
- msgq(sp, M_ERR,
- "Contents of %s buffer lost.",
- charname(sp, name));
- text_lfree(&cbp->textq);
- cbp->len = 0;
- cbp->flags = 0;
- return (1);
- }
- CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
- cbp->len += tp->len;
+ if (tm->lno != fm->lno &&
+ cb_line(sp, ep, lno, 0, tm->cno + 1, cbp)) {
+cb_line_fail: text_lfree(&cbp->textq);
+ cbp->len = 0;
+ cbp->flags = 0;
+ return (1);
}
}
if (setdefcb)
@@ -235,28 +229,30 @@ cb_rotate(sp)
* Cut a portion of a single line.
*/
static int
-cb_line(sp, ep, lno, fcno, clen, newp)
+cb_line(sp, ep, lno, fcno, clen, cbp)
SCR *sp;
EXF *ep;
recno_t lno;
size_t fcno, clen;
- TEXT **newp;
+ CB *cbp;
{
TEXT *tp;
size_t len;
char *p;
+ /* Get the line. */
if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
GETLINE_ERR(sp, lno);
return (1);
}
- if ((*newp = tp = text_init(sp, NULL, 0, len)) == NULL)
+ /* Create a TEXT structure that can hold the entire line. */
+ if ((tp = text_init(sp, NULL, 0, len)) == NULL)
return (1);
/*
- * A length of zero means to cut from the MARK to the end
- * of the line.
+ * If the line isn't empty and it's not the entire line,
+ * copy the portion we want, and reset the TEXT length.
*/
if (len != 0) {
if (clen == 0)
@@ -264,6 +260,11 @@ cb_line(sp, ep, lno, fcno, clen, newp)
memmove(tp->lb, p + fcno, clen);
tp->len = clen;
}
+
+ /* Append to the end of the cut buffer. */
+ CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
+ cbp->len += tp->len;
+
return (0);
}
@@ -279,11 +280,11 @@ text_init(sp, p, len, total_len)
{
TEXT *tp;
- MALLOC(sp, tp, TEXT *, sizeof(TEXT));
+ CALLOC(sp, tp, TEXT *, 1, sizeof(TEXT));
if (tp == NULL)
return (NULL);
/* ANSI C doesn't define a call to malloc(2) for 0 bytes. */
- if (tp->lb_len = total_len) {
+ if ((tp->lb_len = total_len) != 0) {
MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len);
if (tp->lb == NULL) {
free(tp);
@@ -291,12 +292,8 @@ text_init(sp, p, len, total_len)
}
if (p != NULL && len != 0)
memmove(tp->lb, p, len);
- } else
- tp->lb = NULL;
+ }
tp->len = len;
- tp->ai = tp->insert = tp->offset = tp->owrite = 0;
- tp->wd = NULL;
- tp->wd_len = 0;
return (tp);
}
@@ -330,197 +327,3 @@ text_free(tp)
FREE(tp->wd, tp->wd_len);
FREE(tp, sizeof(TEXT));
}
-
-/*
- * put --
- * Put text buffer contents into the file.
- *
- * !!!
- * Historically, pasting into a file with no lines in vi would preserve
- * the single blank line. This is almost certainly a result of the fact
- * that historic vi couldn't deal with a file that had no lines in it.
- * This implementation treats that as a bug, and does not retain the
- * blank line.
- */
-int
-put(sp, ep, cbp, namep, cp, rp, append)
- SCR *sp;
- EXF *ep;
- CB *cbp;
- CHAR_T *namep;
- MARK *cp, *rp;
- int append;
-{
- CHAR_T name;
- TEXT *ltp, *tp;
- recno_t lno;
- size_t blen, clen, len;
- char *bp, *p, *t;
-
- if (cbp == NULL)
- if (namep == NULL) {
- cbp = sp->gp->dcbp;
- if (cbp == NULL) {
- msgq(sp, M_ERR, "The default buffer is empty.");
- return (1);
- }
- } else {
- name = *namep;
- CBNAME(sp, cbp, name);
- if (cbp == NULL) {
- msgq(sp, M_ERR,
- "Buffer %s is empty.", charname(sp, name));
- return (1);
- }
- }
- tp = cbp->textq.cqh_first;
-
- /*
- * It's possible to do a put into an empty file, meaning that the
- * cut buffer simply becomes the file. It's a special case so
- * that we can ignore it in general.
- *
- * Historical practice is that the cursor ends up on the first
- * non-blank character of the first line inserted.
- */
- if (cp->lno == 1) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0) {
- for (; tp != (void *)&cbp->textq;
- ++lno, tp = tp->q.cqe_next)
- if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
- return (1);
- rp->lno = 1;
- rp->cno = 0;
- (void)nonblank(sp, ep, rp->lno, &rp->cno);
- goto ret;
- }
- }
-
- /* If a line mode buffer, append each new line into the file. */
- if (F_ISSET(cbp, CB_LMODE)) {
- lno = append ? cp->lno : cp->lno - 1;
- rp->lno = lno + 1;
- for (; tp != (void *)&cbp->textq; ++lno, tp = tp->q.cqe_next)
- if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
- return (1);
- rp->cno = 0;
- (void)nonblank(sp, ep, rp->lno, &rp->cno);
- goto ret;
- }
-
- /*
- * If buffer was cut in character mode, replace the current line with
- * one built from the portion of the first line to the left of the
- * split plus the first line in the CB. Append each intermediate line
- * in the CB. Append a line built from the portion of the first line
- * to the right of the split plus the last line in the CB.
- *
- * Get the first line.
- */
- lno = cp->lno;
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
-
- GET_SPACE_RET(sp, bp, blen, tp->len + len + 1);
- t = bp;
-
- /* Original line, left of the split. */
- if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) {
- memmove(bp, p, clen);
- p += clen;
- t += clen;
- }
-
- /* First line from the CB. */
- memmove(t, tp->lb, tp->len);
- t += tp->len;
-
- /* Calculate length left in original line. */
- clen = len ? len - cp->cno - (append ? 1 : 0) : 0;
-
- /*
- * If no more lines in the CB, append the rest of the original
- * line and quit. Otherwise, build the last line before doing
- * the intermediate lines, because the line changes will lose
- * the cached line.
- */
- if (tp->q.cqe_next == (void *)&cbp->textq) {
- /*
- * Historical practice is that if a non-line mode put
- * is inside a single line, the cursor ends up on the
- * last character inserted.
- */
- rp->lno = lno;
- rp->cno = (t - bp) - 1;
-
- if (clen > 0) {
- memmove(t, p, clen);
- t += clen;
- }
- if (file_sline(sp, ep, lno, bp, t - bp))
- goto mem;
- } else {
- /*
- * Have to build both the first and last lines of the
- * put before doing any sets or we'll lose the cached
- * line. Build both the first and last lines in the
- * same buffer, so we don't have to have another buffer
- * floating around.
- *
- * Last part of original line; check for space, reset
- * the pointer into the buffer.
- */
- ltp = cbp->textq.cqh_last;
- len = t - bp;
- ADD_SPACE_RET(sp, bp, blen, ltp->len + clen);
- t = bp + len;
-
- /* Add in last part of the CB. */
- memmove(t, ltp->lb, ltp->len);
- if (clen)
- memmove(t + ltp->len, p, clen);
- clen += ltp->len;
-
- /*
- * Now: bp points to the first character of the first
- * line, t points to the last character of the last
- * line, t - bp is the length of the first line, and
- * clen is the length of the last. Just figured you'd
- * want to know.
- *
- * Output the line replacing the original line.
- */
- if (file_sline(sp, ep, lno, bp, t - bp))
- goto mem;
-
- /*
- * Historical practice is that if a non-line mode put
- * covers multiple lines, the cursor ends up on the
- * first character inserted. (Of course.)
- */
- rp->lno = lno;
- rp->cno = (t - bp) - 1;
-
- /* Output any intermediate lines in the CB. */
- for (tp = tp->q.cqe_next;
- tp->q.cqe_next != (void *)&cbp->textq;
- ++lno, tp = tp->q.cqe_next)
- if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
- goto mem;
-
- if (file_aline(sp, ep, 1, lno, t, clen)) {
-mem: FREE_SPACE(sp, bp, blen);
- return (1);
- }
- }
- FREE_SPACE(sp, bp, blen);
-
- /* Reporting... */
-ret: sp->rptlines[L_PUT] += lno - cp->lno;
-
- return (0);
-}
diff --git a/usr.bin/vi/cut.h b/usr.bin/vi/cut.h
index 8ade88f05633..7be20b77ffbd 100644
--- a/usr.bin/vi/cut.h
+++ b/usr.bin/vi/cut.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)cut.h 8.11 (Berkeley) 1/11/94
+ * @(#)cut.h 8.13 (Berkeley) 3/16/94
*/
typedef struct _texth TEXTH; /* TEXT list head structure. */
@@ -46,7 +46,7 @@ struct _cb {
#define CB_LMODE 0x01 /* Cut was in line mode. */
u_char flags;
};
-
+
/* Lines/blocks of text. */
struct _text { /* Text: a linked list of lines. */
CIRCLEQ_ENTRY(_text) q; /* Linked list of text structures. */
diff --git a/usr.bin/vi/delete.c b/usr.bin/vi/delete.c
index e8c0a5d80e1f..4a46ba75d9eb 100644
--- a/usr.bin/vi/delete.c
+++ b/usr.bin/vi/delete.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)delete.c 8.7 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)delete.c 8.9 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
@@ -59,10 +69,6 @@ delete(sp, ep, fm, tm, lmode)
char *bp, *p;
int eof;
-#if defined(DEBUG) && 0
- TRACE(sp, "delete: from %lu/%d to %lu/%d%s\n",
- fm->lno, fm->cno, tm->lno, tm->cno, lmode ? " (LINE MODE)" : "");
-#endif
bp = NULL;
/* Case 1 -- delete in line mode. */
@@ -113,9 +119,11 @@ delete(sp, ep, fm, tm, lmode)
return (1);
}
GET_SPACE_RET(sp, bp, blen, len);
- memmove(bp, p, fm->cno);
- memmove(bp + fm->cno, p + tm->cno, len - tm->cno);
- if (file_sline(sp, ep, fm->lno, bp, len - (tm->cno - fm->cno)))
+ if (fm->cno != 0)
+ memmove(bp, p, fm->cno);
+ memmove(bp + fm->cno, p + (tm->cno + 1), len - (tm->cno + 1));
+ if (file_sline(sp, ep, fm->lno,
+ bp, len - ((tm->cno - fm->cno) + 1)))
goto err;
goto done;
}
@@ -162,8 +170,8 @@ delete(sp, ep, fm, tm, lmode)
GETLINE_ERR(sp, tm->lno);
goto err;
}
- memmove(bp + tlen, p + tm->cno, len - tm->cno);
- tlen += len - tm->cno;
+ memmove(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1));
+ tlen += len - (tm->cno + 1);
/* Set the current line. */
if (file_sline(sp, ep, fm->lno, bp, tlen))
diff --git a/usr.bin/vi/docs/README b/usr.bin/vi/docs/README
new file mode 100644
index 000000000000..e46f4de58bd1
--- /dev/null
+++ b/usr.bin/vi/docs/README
@@ -0,0 +1,177 @@
+# @(#)README 8.54 (Berkeley) 3/24/94
+
+This is the README for version 1.11 of nex/nvi, a freely redistributable
+replacement for the Berkeley ex and vi text editors. The compressed tar
+archive can be retrieved by anonymous ftp from ftp.cs.berkeley.edu, from
+the file ucb/4bsd/nvi.tar.Z. There is a gzip'd tar archive, nvi.tar.z,
+in the same directory.
+
+If you have any questions about nvi, or problems making it work, please
+contact me by electronic mail at one of the following addresses:
+
+ uunet!bostic
+ bostic@cs.berkeley.edu
+
+Keith Bostic
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+o Redistribution:
+
+This software is copyrighted by the The Regents of the University of
+California, but may be freely redistributed (or sold, or used to line
+your birdcage) under the following conditions:
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+o Credit where it's due:
+
+ This software was originally derived from software contributed
+ to the University of California, Berkeley by Steve Kirkendall,
+ the author of the vi clone elvis. Without his work, this work
+ would have been far more difficult.
+
+ POSIX 1003.2 style regular expression support is courtesy of
+ Henry Spencer, for which I am *very* grateful.
+
+ The curses library was originally done by Ken Arnold. Scrolling
+ and general reworking for 4.4BSD was done by Elan Amir.
+
+o From the original vi acknowledgements, by William Joy and Mark Horton:
+
+ Bruce Englar encouraged the early development of this display
+ editor. Peter Kessler helped bring sanity to version 2's
+ command layout. Bill Joy wrote versions 1 and 2.0 through 2.7,
+ and created the framework that users see in the present editor.
+ Mark Horton added macros and other features and made the editor
+ work on a large number of terminals and Unix systems.
+
+o And...
+ The financial support of UUNET Communications Services is gratefully
+ acknowledged.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Status:
+
+This software is in beta test, and it's believed to be pretty stable.
+Almost all of the historic functionality in ex/vi is there, the missing
+pieces are fairly obscure. In particular, the edcompatible, hardtabs*,
+lisp*, optimize*, redraw*, and slowopen* options are recognized, but not
+implemented.
+
+Nvi is mostly 8-bit clean. This isn't difficult to fix, and was left in
+during initial development to make things easier. Wide character support
+will be integrated at the same time it is made fully 8-bit clean.
+
+There aren't a lot of new features in nex/nvi, but there are a few things
+you might like. See the "ADDITIONAL FEATURES" section of the manual page
+(docs/vi.0.txt, docs/vi.0.ps) for a list.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Porting information:
+
+The directory PORT has directories per OS/machine combination, with
+V7-style Makefiles which build nex/nvi. See the file PORT/README for
+detailed information.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Bug reports:
+
+Code fixes are appreciated, of course, but if you can't provide them,
+please email me as much information as you can as to how to reproduce
+the bug, and I'll try to fix it locally. In particular, the screen
+routines are nasty stuff, and you probably don't want to mess with them.
+Stack traces of core dumps are sometimes helpful, but an example file
+with a set of keystrokes that causes the problem is far better. Also,
+make sure that you include the dimensions of the screen on which the
+problem occurred, your startup files (.exrc, .nexrc), and the environment
+variable (EXINIT, NEXINIT) values.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Layout:
+
+nvi:
+ Source files for pieces of code that are shared by all the
+ editors, like searching and logging code or code translating
+ line numbers into requests to the dbopen(3) database code.
+ It also has the code for adding, deleting, and changing "records"
+ in the underlying database.
+
+nvi/PORT:
+ Porting directories, one per OS/architecture combination. See
+ nvi/PORT/README for porting information.
+
+nvi/docs:
+ The nvi/docs directory has all of the nvi documentation:
+
+ README -- Nvi main README file.
+ USD.doc -- Historic vi documentation (in roff source form).
+ bugs.current -- Known bugs in the current nvi implementation.
+ changelog -- Log of changes from version to version.
+ features -- Todo list, suggested features list.
+ internals/
+ autowrite -- Vi autowrite option discussion.
+ gdb.script -- GDB debugging scripts.
+ input -- Vi maps, executable buffers, and input discussion.
+ quoting -- Vi quoting discussion.
+ structures -- Nvi internal structure description.
+ spell.ok -- Misspellings list for README, vi.1.
+ tutorial -- Historic vi tutorial
+ vi.0.ps -- PostScript of vi.1.
+ vi.0.txt -- Flat text of vi.1.
+ vi.1 -- Nvi man page (in roff source form).
+ vi.ref -- Nvi reference (in roff source form).
+ vi.ref.ps -- PostScript of vi.ref.
+ vi.ref.txt -- Flat text of vi.ref.
+
+nvi/ex:
+ The nvi/ex directory is the ex source code. Because vi has the
+ colon command, lots of this code is used by vi. Generally, if
+ functionality is shared by both ex and vi, it's in nvi/ex, if
+ it's vi only, it's in nvi/vi. Files are generally named by the
+ command(s) they support, but occasionally with a name that
+ describes their functionality.
+
+nvi/sex:
+ The nvi/sex directory is the screen support for the ex editor.
+
+nvi/svi:
+ The nvi/svi directory is the screen support for a curses based
+ vi editor.
+
+nvi/vi:
+ The nvi/vi directory is the vi source code.
+
+nvi/xaw:
+ Place reserved for an X11 (Athena Widget) screen.
diff --git a/usr.bin/vi/docs/USD.doc/edit/Makefile b/usr.bin/vi/docs/USD.doc/edit/Makefile
new file mode 100644
index 000000000000..e9b8d3c5610a
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/edit/Makefile
@@ -0,0 +1,18 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= usd/11.edit
+SRCS= edittut.ms
+MACROS= -ms
+
+paper.ps: ${SRCS}
+ ${TBL} ${SRCS} | ${ROFF} > ${.TARGET}
+
+# index for versatec is different from the one in edit.tut
+# because the fonts are different and entries reference page
+# rather than section numbers. if you have a typesetter
+# you should just use the index in edit.tut, and ignore editvindex.
+
+editvindex:
+ ${TROFF} ${MACROS} -n22 edit.vindex
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/vi/docs/USD.doc/edit/edit.vindex b/usr.bin/vi/docs/USD.doc/edit/edit.vindex
new file mode 100644
index 000000000000..2098f14ea190
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/edit/edit.vindex
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)edit.vindex 8.1 (Berkeley) 6/8/93
+.\"
+.bd I
+.ND
+.TL
+Index
+.sp 3
+.2C
+.nf
+addressing, \fIsee\fR line numbers
+append mode, 4
+backslash (\\), 18
+buffer, 2
+command mode, 4
+context search, 8, 10, 13, 18
+control characters (``^'' notation), 8
+control-d, 6
+current filename, 19, 20
+current line (.), 9, 15
+diagnostic messages, 4
+disk, 2
+documentation, 21
+edit (to begin editing session), 3, 7
+editing commands:
+.in +2
+append (a), 4, 7
+change (c), 16
+copy (co), 13
+delete (d), 13-14
+edit (e), 12
+file (f), 19
+global (g), 18-19
+move (m), 12-13
+number (nu), 9
+preserve (pre), 20-21
+print (p), 8
+quit (q), 5, 11
+quit! (q!), 11
+read (r), 20
+recover (rec), 20
+substitute (s), 9-10, 17, 18
+undo (u), 14, 17
+write (w), 5-6, 11, 19-20
+z, 11
+.sp 10i
+! (shell escape), 19
+$= , 15
++, 15
+\-, 15
+//, 8, 18
+??, 18
+\&\fB.\fR, 9, 15
+\&\fB.\fR=, 9, 15
+.in -2
+erasing
+.ti +2
+characters (#), 8
+.ti +2
+lines (@), 8
+ex (text editor), 21
+\fIEx Reference Manual\fR, 21
+file, 1
+file recovery, 20
+filename, 2
+Interrupt (message), 7
+line numbers, \fIsee also\fR current line
+.ti +2
+dollar sign ($), 8, 12-13, 15
+.ti +2
+dot (.), 9, 15
+.ti +2
+relative (+ and \-), 15, 16
+logging out, 6
+login procedure, 2
+``magic'' characters, 21
+non-printing characters, 8
+``not found'' (message), 3
+program, 1
+recovery \fIsee\fR file recovery
+shell, 18
+shell escape (!), 19
+special characters (^, $, \e), 18
+text input mode, 4
+UNIX, 1
diff --git a/usr.bin/vi/docs/USD.doc/edit/edittut.ms b/usr.bin/vi/docs/USD.doc/edit/edittut.ms
new file mode 100644
index 000000000000..5f4c28cb6d2a
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/edit/edittut.ms
@@ -0,0 +1,2322 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)edittut.ms 8.1 (Berkeley) 6/8/93
+.\"
+.EH 'USD:11-%''Edit: A Tutorial'
+.OH 'Edit: A Tutorial''USD:11-%'
+.LP
+.ds u \s-2UNIX\s0
+.ll 5i
+.nr LL 5i
+.ND
+.sp 4
+.ce
+\f3\s+2Edit: A Tutorial\s0\f1
+.sp
+.ce 3
+.I
+Ricki Blau
+.sp
+James Joyce
+.R
+.sp
+.ce 3
+Computing Services
+University of California
+Berkeley, California 94720
+.sp 3
+.ce
+.I
+ABSTRACT
+.R
+.sp
+.LP
+This narrative introduction to the use of the text editor
+.I edit
+assumes no prior familiarity with computers or with text editing.
+Its aim is to lead the beginning \s-2UNIX\(dg\s+2 user through the
+.FS
+\(dgUNIX is a trademark of Bell Laboratories.
+.FE
+fundamental steps of writing and revising a file of text.
+Edit,
+a version of the text editor
+.I ex,
+was designed to provide an informative environment
+for new and casual users.
+.PP
+We welcome comments and suggestions about this tutorial
+and the \s-2UNIX\s+2 documentation in general.
+.sp .5v
+September 1981
+.bp
+.ll 6.5i
+.nr LL 6.5i
+.nr LT 6.5i
+.ds u \s-2UNIX\s0
+.ce
+\s+2\f3Contents\f1\s0
+.LP
+.nf
+Introduction\ \ \ 3
+.sp
+Session 1\ \ \4
+.in +.5i
+Making contact with \s-2UNIX\s+2\ \ \ 4
+Logging in\ \ \4
+Asking for \fIedit\fR\ \ \ 4
+The ``Command not found'' message\ \ \ 5
+A summary\ \ \5
+Entering text\ \ \ 5
+Messages from \fIedit\fR\ \ \ 5
+Text input mode\ \ \ 6
+Making corrections\ \ \ 6
+Writing text to disk\ \ \ 7
+Signing off\ \ \7
+.in -.5i
+.sp
+Session 2\ \ \ 8
+.in +.5i
+Adding more text to the file\ \ \ 8
+Interrupt\ \ \ 8
+Making corrections\ \ \ 8
+Listing what's in the buffer (p)\ \ \ 9
+Finding things in the buffer\ \ \ 9
+The current line\ \ \ 10
+Numbering lines (nu)\ \ \ 10
+Substitute command (s)\ \ \ 10
+Another way to list what's in the buffer (z)\ \ \ 11
+Saving the modified text\ \ \ 12
+.in -.5i
+.sp
+Session 3\ \ \ 13
+.in +.5i
+Bringing text into the buffer (e)\ \ \ 13
+Moving text in the buffer (m)\ \ \ 13
+Copying lines (copy)\ \ \ 14
+Deleting lines (d)\ \ \ 14
+A word or two of caution\ \ \ 15
+Undo (u) to the rescue\ \ \ 15
+More about the dot (.) and buffer end ($)\ \ \ 16
+Moving around in the buffer (+ and \-)\ \ \ 16
+Changing lines (c)\ \ \ 17
+.in -.5i
+.sp
+Session 4\ \ \ 18
+.in +.5i
+Making commands global (g)\ \ \ 18
+More about searching and substituting\ \ \ 19
+Special characters\ \ \ 19
+Issuing \s-2UNIX\s+2 commands from the editor\ \ \ 20
+Filenames and file manipulation\ \ \ 20
+The file (f) command\ \ \ 20
+Reading additional files (r)\ \ \ 21
+Writing parts of the buffer\ \ \ 21
+Recovering files\ \ \ 21
+Other recovery techniques\ \ \ 21
+Further reading and other information\ \ \ 22
+Using \fIex\fR\ \ \ 22
+.in -.5i
+.sp
+Index\ \ \ 23
+.bp
+.SH
+.ce
+\s+2Introduction\s0
+.PP
+Text editing using a terminal connected to a computer
+allows you to create, modify, and print text
+easily.
+A
+.I
+text editor
+.R
+is a program
+that assists you
+as you create and modify text.
+The text editor you will learn here is named
+.I edit.
+Creating text using edit is as easy as typing it
+on an electric typewriter.
+Modifying text involves telling the text editor
+what you want to add, change, or delete.
+You can review your text
+by typing a command
+to print the file contents
+as they are currently.
+Another program (which we do not discuss in this
+document), a text formatter,
+rearranges your text
+for you into ``finished form.''
+.PP
+These lessons assume no prior familiarity with computers
+or with text editing.
+They consist of a series of text editing sessions
+which lead you through the fundamental steps
+of creating and revising text.
+After scanning each lesson and before beginning the next,
+you should try the examples at a terminal to get a feeling
+for the actual process of text editing.
+If you set aside some time for experimentation,
+you will soon become familiar with using the
+computer to write and modify text.
+In addition to the actual use of the text editor,
+other features of \s-2UNIX\s0 will be very important to your work.
+You can begin to
+learn about these other features by
+reading one of the other tutorials
+that provide a general introduction to the system.
+You will be ready to proceed with this lesson as soon as
+you are familiar with (1) your terminal and its special keys,
+(2) how to login,
+(3) and the ways of correcting typing errors.
+Let's first define some terms:
+.sp .5
+.IP program 12
+A set of instructions, given to the computer,
+describing the sequence of steps the computer performs
+in order to accomplish a specific task.
+The task must be specific,
+such as balancing your checkbook
+or editing your text.
+A general task,
+such as working for world peace,
+is something we can all do,
+but not something we can currently write programs to do.
+.IP UNIX
+\s-2UNIX\s0 is a special type of program,
+called an operating system, that supervises the machinery
+and all other programs comprising the total
+computer system.
+.IP edit
+.I edit
+is the name of the \s-2UNIX\s0 text editor you will be learning to use,
+and is a program that aids you in writing or revising text.
+Edit was designed for beginning users,
+and is a simplified version of an editor named
+.I ex.
+.IP file
+Each \s-2UNIX\s0 account is allotted
+space for the permanent storage of information,
+such as programs, data or text.
+A file is a logical unit of data,
+for example, an essay, a program,
+or a chapter from a book,
+which is stored on a computer system.
+Once you create a file,
+it is kept until you instruct the system to remove it.
+You may create a file during one \s-2UNIX\s0 session,
+end the session,
+and return to use it at a later time.
+Files contain anything you choose to write and store in them.
+The sizes of files vary to suit your needs;
+one file might hold only a single number,
+yet another might contain
+a very long document or program.
+The only way to save
+information from one session to the next is to store it in a file,
+which you will learn in Session 1.
+.IP filename
+Filenames are used to distinguish one file from another,
+serving the same purpose as the labels of manila
+folders in a file cabinet.
+In order to write or access information in a file,
+you use the name of that file in a \s-2UNIX\s0 command,
+and the system will automatically locate the file.
+.IP disk
+Files are stored on an input/output device called a disk,
+which looks something like a stack of phonograph records.
+Each surface is coated with a material similar to that
+on magnetic recording tape,
+and information is recorded on it.
+.IP buffer
+A temporary work space, made available to the user
+for the duration of a session of text editing
+and used for creating and modifying
+the text file.
+We can think of the buffer as a blackboard that is
+erased after each class, where each session with the editor
+is a class.
+.bp
+.SH
+.ce 1
+\s+2Session 1\s0
+.sp 1
+.SH
+Making contact with \s-1UNIX\s0
+.PP
+To use the editor you must first make contact with the computer
+by logging in to \s-2UNIX\s0.
+We'll quickly review the standard \s-2UNIX\s0 login procedure
+for the two ways you can make contact:
+on a terminal that is directly linked to the computer,
+or over a telephone line where the computer answers your call.
+.SH
+Directly-linked terminals
+.PP
+Turn on your terminal and press the \s-1RETURN\s0 key.
+You are now ready to login.
+.SH
+Dial-up terminals
+.PP
+If your terminal connects with the computer over a telephone line,
+turn on the terminal, dial the system access number,
+and, when you hear a high-pitched tone, place the
+telephone handset in the acoustic coupler, if you are using one.
+You are now ready to login.
+.SH
+Logging in
+.PP
+The message inviting you to login is:
+.DS I 1i
+login:
+.DE
+.LP
+Type your login name, which identifies you to \s-2UNIX\s0,
+on the same line as the login message,
+and press \s-2RETURN\s+2.
+If the terminal you are using
+has both upper and lower case,
+.B
+be sure you enter your login name in lower case;
+.R
+otherwise \s-2UNIX\s0 assumes your terminal
+has only upper case and will not recognize lower case
+letters you may type.
+\s-2UNIX\s0 types ``login:'' and you reply
+with your login name, for example ``susan'':
+.DS I 1i
+login: \fBsusan\fR \fI(and press the \s-2RETURN\s0 key)\fR
+.DE
+(In the examples, input you would type appears in
+.B "bold face"
+to distinguish it from the responses from \s-2UNIX\s0.)
+.PP
+\s-2UNIX\s0 will next respond with a request for a password
+as an additional precaution to prevent
+unauthorized people from using your account.
+The password will not appear when you type it,
+to prevent others from seeing it.
+The message is:
+.DS I 1i
+Password: \fI(type your password and press \s-2RETURN\s+2)\fR
+.DE
+If any of the information you gave during the login
+sequence was mistyped or incorrect,
+\s-2UNIX\s0 will respond with
+.DS I 1i
+Login incorrect.
+.if t .sp .2v
+.if n .sp 1
+login:
+.DE
+in which case you should start the login process anew.
+Assuming that you have successfully
+logged in, \s-2UNIX\s0
+will print the message of the day and eventually will present
+you with a % at the beginning of a fresh line.
+The % is the \s-2UNIX\s0 prompt symbol
+which tells you that \s-2UNIX\s0 is ready to accept a command.
+.bd I 3
+.SH
+Asking for \fIedit\fP
+.fl
+.bd I
+.PP
+You are ready to tell \s-2UNIX\s0 that you
+want to work with edit, the text editor.
+Now is a convenient time to choose
+a name for the file of text you are about to create.
+To begin your editing session,
+type
+.B edit
+followed by a space and then the filename
+you have selected; for example, ``text''.
+After that,
+press the \s-2RETURN\s0 key and wait for edit's response:
+.DS I 1i
+% \fBedit text\fP \fI(followed by a \s-2RETURN\s+2)\fR
+"text" No such file or directory
+:
+.DE
+If you typed the command correctly,
+you will now be in communication with edit.
+Edit has set aside a buffer for use as
+a temporary working space during your current editing session.
+Since ``text'' is a new file we are about to create
+the editor was unable to find that file, which it
+confirms by saying:
+.DS I 1i
+"text" No such file or directory
+.DE
+On the next line appears edit's prompt ``:'',
+announcing that you are in \f2command mode\f1 and
+edit expects a command from you.
+You may now begin to create the new file.
+.SH
+The ``Command not found'' message
+.PP
+If you misspelled edit by typing, say, ``editor'',
+this might appear:
+.DS I 1i
+% \fBeditor\fP
+editor: Command not found
+%
+.DE
+Your mistake in calling edit ``editor'' was
+treated by \s-2UNIX\s0 as a request
+for a program named ``editor''.
+Since there is no program
+named ``editor'',
+\s-2UNIX\s0 reported that the program was ``not found''.
+A new % indicates that \s-2UNIX\s0 is ready for another command,
+and you may then enter the correct command.
+.SH
+A summary
+.PP
+Your exchange with \s-2UNIX\s0 as you logged in and made contact with edit
+should look something like this:
+.DS I 1i
+login: \fBsusan\fP
+Password:
+\&... A Message of General Interest ...
+% \fBedit text\fP
+"text" No such file or directory
+:
+.DE
+.SH
+Entering text
+.PP
+You may now begin entering text into the buffer.
+This is done by \fIappending\fP (or adding) text to whatever
+is currently in the buffer.
+Since there is nothing in the buffer at the moment,
+you are appending text to nothing;
+in effect,
+since you are adding text to nothing
+you are creating text.
+Most edit commands have two equivalent forms:
+a word that suggests what the command does,
+and a shorter abbreviation of that word.
+Many beginners find the full command names
+easier to remember at first,
+but once you are familiar with editing you may
+prefer to type the shorter abbreviations.
+The command to input text is ``append''.
+(It may be abbreviated ``a''.)
+Type
+.B append
+and press the \s-2RETURN\s0 key.
+.DS I 1i
+% \fBedit text
+\fR:\|\fBappend
+.R
+.DE
+.SH
+.bd I 3
+Messages from
+.I edit
+.fl
+.bd I
+.PP
+If you make a mistake in entering a command and
+type something that edit does not recognize,
+edit will respond with a message
+intended to help you diagnose your error.
+For example, if you misspell the command to input text by typing,
+perhaps, ``add'' instead of ``append'' or ``a'',
+you will receive this message:
+.DS I 1i
+:\|\fBadd\fR
+add: Not an editor command
+:
+.DE
+When you receive a diagnostic message,
+check what you typed in order to determine what
+part of your command confused edit.
+The message above means that edit
+was unable to recognize your mistyped command
+and, therefore, did not execute it.
+Instead, a new ``:''
+appeared to let you know that
+edit is again ready to execute a command.
+.SH
+Text input mode
+.PP
+By giving the command ``append'' (or using the abbreviation ``a''),
+you entered
+.I
+text input mode,
+.R
+also known as
+.I
+append mode.
+.R
+When you enter text input mode,
+edit stops sending you a prompt.
+You will not receive any prompts
+or error messages
+while in text input mode.
+You can enter
+pretty much anything you want on the lines.
+The lines are transmitted one by one to the buffer
+and held there during the editing session.
+You may append as much text as you want, and
+.I
+when you wish to stop entering text lines you should
+type a period as the only character on the line
+and press the \s-2RETURN\s0 key.
+.R
+When you type the period and press \s-2RETURN\s0,
+you signal that you want to stop appending text,
+and edit responds by allowing
+you to exit text input mode and reenter command mode.
+Edit will again
+prompt you for a command by printing ``:''.
+.PP
+Leaving append mode does not destroy the text in
+the buffer.
+You have to leave append
+mode to do any of the other kinds of editing,
+such as changing, adding, or printing text.
+If you type a period as the first character and
+type any other character on the same line,
+edit will believe you want to remain in append mode
+and will not let you out.
+As this can be very frustrating,
+be sure to type
+.B only
+the period and the \s-2RETURN\s0 key.
+.PP
+This is a good place to learn an important
+lesson about computers and text: a blank space is
+a character as far as a computer is concerned.
+If you so much as type a period followed by a blank
+(that is, type a period and then the space bar on the keyboard),
+you will remain in append mode with the last line of text
+being:
+.DS I 1i
+.B
+.ps +2
+\&.
+.ps -2
+.R
+.DE
+Let's say that you enter the lines
+(try to type
+.B exactly
+what you see, including ``thiss''):
+.DS I 1i
+.B
+This is some sample text.
+And thiss is some more text.
+Text editing is strange, but nice.
+\&.
+.R
+.DE
+The last line is the period followed by a \s-2RETURN\s0
+that gets you out of append mode.
+.SH
+Making corrections
+.PP
+If you have read a general introduction to \s-2UNIX\s0,
+you will recall that it is possible to erase individual
+letters that you have typed.
+This is done by typing the designated erase character
+as many times as there are characters
+you want to erase.
+.PP
+The usual erase character varies from place to place and
+user to user. Often it
+is the backspace (control-H),
+so you can correct typing errors
+in the line you are typing
+by holding down the \s-1CTRL\s+1 key
+and typing the ``H'' key. (Sometimes it is the DEL key.)
+If you type the erase character
+you will notice
+that the terminal backspaces in the line you are on.
+You can backspace over your error,
+and then type what you want to be the rest of the line.
+.PP
+If you make a bad start
+in a line
+and would like to begin again,
+you can either backspace to the beginning of the line
+or you can use the at-sign ``@'' to erase everything on the line:
+.DS I 1i
+.B
+Text edtiing is strange, but@
+Text editing is strange, but nice.
+.R
+.fl
+.bd S
+.DE
+When you type the at-sign (@), you erase
+the entire line typed so far
+and are given a fresh line to type on.
+You may immediately begin to retype the line.
+This, unfortunately, does not work after you type the
+line and press \s-2RETURN\s+2.
+To make corrections in lines that have been completed,
+it is necessary to use the editing commands
+covered in the next sessions.
+.SH
+Writing text to disk
+.PP
+You are now ready to edit the text. One common operation
+is to write the text to disk as a file for safekeeping
+after the session is over.
+This is the only way to save information from one session to the next,
+since the editor's buffer is temporary and will last only until the
+end of the editing session.
+Learning how to write a file to disk is second in
+importance only to entering the text.
+To write the contents of the buffer to a disk
+file, use the command ``write''
+(or its abbreviation ``w''):
+.DS I 1i
+:\|\fBwrite
+.R
+.DE
+Edit will copy the contents of the buffer to a disk file.
+If the file does not yet exist,
+a new file will be created automatically
+and the presence of a ``[New file]'' will be noted.
+The newly-created file will be given the name specified when
+you entered the editor, in this case ``text''.
+To confirm that the disk file has been successfully written,
+edit will repeat the filename and give
+the number of lines and the total
+number of characters in the file.
+The buffer remains unchanged by the ``write'' command.
+All of the lines that were written to disk will still be
+in the buffer,
+should you want to modify or add to them.
+.PP
+Edit must have a name for the file to be written.
+If you forgot to indicate the name of the file
+when you began to edit,
+edit will print in response to your write command:
+.DS I 1i
+No current filename
+.DE
+If this happens, you can specify the filename in a new write command:
+.DS I 1i
+:\|\fBwrite text
+.R
+.DE
+After the ``write'' (or ``w''), type a space and then the name of the file.
+.SH
+Signing off
+.PP
+We have done enough for this first lesson on using the
+\s-2UNIX\s0 text editor, and are ready to quit the session with edit.
+To do this we type ``quit'' (or ``q'') and press \s-2RETURN\s+2:
+.DS I 1i
+:\|\fBwrite
+.R
+"text" [New file] 3 lines, 90 characters
+:\|\fBquit\fR
+%
+.DE
+The % is from \s-2UNIX\s0 to tell you that your session with edit is
+over and you may command \s-2UNIX\s0 further.
+Since we want
+to end the entire session at the terminal, we also need to
+exit from \s-2UNIX\s0.
+In response to the \s-2UNIX\s0 prompt of ``\|%\|''
+type the command
+.DS I 1i
+%\|\fBlogout\fR
+.DE
+This will end your session with \s-2UNIX\s0, and will ready the
+terminal for the next user.
+It is always important to type \fBlogout\fR at the end of a session
+to make absolutely sure no one
+could accidentally stumble into your abandoned
+session and thus gain access to your files,
+tempting even the most honest of souls.
+.sp 1
+.PP
+This is the end of the first session on \s-2UNIX\s0 text editing.
+.bp
+.TL
+Session 2
+.sp
+.PP
+Login with \s-2UNIX\s0 as in the first session:
+.DS I 1i
+login: \fBsusan\fP \fI(carriage return)\fR
+Password: \fI(give password and carriage return)\fR
+.if t .sp .2v
+.if n .sp 1
+\&... A Message of General Interest ...
+%
+.DE
+When you indicate you want to edit,
+you can specify the name of the file you worked on last time.
+This will
+start edit working, and it will fetch the contents of the
+file into the buffer, so that you can resume editing the same file.
+When edit has copied the file into the buffer, it
+will repeat its name and tell
+you the number of lines and characters it contains.
+Thus,
+.DS I 1i
+.B
+% edit text
+.R
+"text" 3 lines, 90 characters
+:
+.DE
+means you asked edit to fetch
+the file named ``text'' for editing,
+causing it to copy the
+90 characters of text into the buffer.
+Edit awaits
+your further instructions,
+and indicates this by its prompt character, the colon (:).
+In this session, we will append more text to our file,
+print the contents of the buffer, and learn to change the text of a line.
+.SH
+Adding more text to the file
+.PP
+If you want to add more to the end of your
+text you may do so by using the append command to enter text input mode.
+When ``append'' is the first command
+of your editing session,
+the lines you enter
+are placed at the end of the buffer.
+Here we'll use the abbreviation for the append command, ``a'':
+.DS I 1i
+:\|\fBa
+This is text added in Session 2.
+It doesn't mean much here, but
+it does illustrate the editor.
+\|\fB\s+2\&.\s-2
+.R
+.DE
+You may recall that once you enter append mode
+using the ``a'' (or ``append'') command,
+you need to type a line containing only a period (.)
+to exit append mode.
+.SH
+Interrupt
+.PP
+Should you press the \s-2RUB\s+2 key (sometimes labelled \s-2DELETE\s+2)
+while working with edit,
+it will send this message to you:
+.DS I 1i
+Interrupt
+:
+.DE
+Any command that edit might be executing
+is terminated by rub or delete,
+causing edit to prompt you for a new command.
+If you are appending text at the time,
+you will exit from append mode
+and be expected to give another command.
+The line of text you were typing
+when the append command was interrupted
+will not be entered into the buffer.
+.SH
+Making corrections
+.PP
+If while typing the line you hit an incorrect key,
+recall that
+you may delete the incorrect character
+or cancel the entire line of input by erasing in the usual way.
+Refer either
+to the last few pages of Session 1
+if you need to review
+the procedures for making a correction.
+The most important idea to remember is that
+erasing a character or cancelling a line must be done
+before you press the \s-2RETURN\s+2 key.
+.SH
+Listing what's in the buffer (p)
+.PP
+Having appended text to what you wrote in Session 1,
+you might want to see all the lines in the buffer.
+To print the contents of the buffer, type the command:
+.DS I 1i
+:\|\fB1,$p
+.R
+.DE
+The ``1''\(dg
+.FS
+\(dgThe numeral ``one'' is the top left-most key,
+and should not be confused with the letter ``el''.
+.FE
+stands for line 1 of the buffer,
+the ``$'' is a special symbol designating the last line
+of the buffer,
+and ``p'' (or \fBprint\fR) is the command to print from line 1
+to the end of the buffer.
+The command ``1,$p'' gives you:
+.DS I 1i
+This is some sample text.
+And thiss is some more text.
+Text editing is strange, but nice.
+This is text added in Session 2.
+It doesn't mean much here, but
+it does illustrate the editor.
+.DE
+Occasionally, you may accidentally
+type a character that can't be printed,
+which can be done by striking a key
+while the \s-2CTRL\s0 key is pressed.
+In printing lines, edit uses a special notation to
+show the existence of non-printing characters.
+Suppose you had introduced the non-printing character ``control-A''
+into the word ``illustrate''
+by accidently pressing the \s-2CTRL\s0 key while
+typing ``a''.
+This can happen on many terminals
+because the \s-2CTRL\s+2 key and the ``A'' key
+are beside each other.
+If your finger presses between the two keys,
+control-A results.
+When asked to print the contents of the buffer,
+edit would display
+.DS I 1i
+it does illustr^Ate the editor.
+.DE
+To represent the control-A, edit shows ``^A''.
+The sequence ``^'' followed by a capital
+letter stands for the one character
+entered by holding down the \s-2CTRL\s0 key and typing the letter
+which appears after the ``^''.
+We'll soon discuss the commands that can be used
+to correct this typing error.
+.PP
+In looking over the text we see that
+``this'' is typed as ``thiss'' in the second line,
+a deliberate error so we can learn to make corrections.
+Let's correct the spelling.
+.SH
+Finding things in the buffer
+.PP
+In order to change something in the buffer we first need to
+find it.
+We can find ``thiss'' in the text we have
+entered by looking at a listing
+of the lines.
+Physically speaking, we search the lines
+of text looking for ``thiss'' and stop searching when
+we have found it.
+The way to tell edit to search for something
+is to type it inside slash marks:
+.DS I 1i
+:\|\fB/thiss/
+.R
+.DE
+By typing
+.B /thiss/
+and pressing \s-1RETURN\s0,
+you instruct edit to search for ``thiss''.
+If you ask edit to look for a pattern of characters
+which it cannot find in the buffer,
+it will respond ``Pattern not found''.
+When edit finds
+the characters ``thiss'', it will print the line of text
+for your inspection:
+.DS I 1i
+And thiss is some more text.
+.DE
+Edit is now positioned in the buffer at the
+line it just printed,
+ready to make a change in the line.
+.bp
+.SH
+The current line
+.PP
+Edit keeps track of the line in the buffer where it is located
+at all times during an editing session.
+In general, the line that has been most recently
+printed, entered, or changed
+is the current location in the buffer.
+The editor is prepared to make changes
+at the current location in the buffer,
+unless you direct it to another location.
+.PP
+In particular,
+when you bring a file into the buffer,
+you will be located at the last line in the file,
+where the editor left off copying the lines
+from the file to the buffer.
+If your first editing command is ``append'',
+the lines you enter are added
+to the end of the file,
+after the current line \(em
+the last line in the file.
+.PP
+You can refer to your current location in the buffer by the
+symbol
+period (.) usually known by the name ``dot''.
+If you type ``.'' and carriage
+return you will be instructing edit to print the current line:
+.DS I 1i
+:\|\fB\s+2\&.\s-2
+.R
+And thiss is some more text.
+.DE
+.PP
+If you want to know the number of the current line,
+you can type
+.B \&.=
+and press \s-2RETURN\s+2,
+and edit will respond with the line number:
+.DS I 1i
+:\|\fB\s+2.\s-2=
+.R
+2
+.DE
+If you type the number of any line and press \s-2RETURN\s+2,
+edit will position you at that line and
+print its contents:
+.DS I 1i
+:\|\fB2
+.R
+And thiss is some more text.
+.DE
+You should experiment with these commands
+to gain experience in using them to make changes.
+.SH
+Numbering lines (nu)
+.PP
+The
+.B
+number (nu)
+.R
+command is similar to print,
+giving both the number and the text of each printed line.
+To see the number and the text of the current line type
+.DS I 1i
+:\|\fBnu
+.R
+\0\0\0\0\02\0\0And thiss is some more text.
+.DE
+Note that the shortest abbreviation for the number command is
+``nu'' (and not ``n'', which is used for a different command).
+You may specify a range of lines
+to be listed by the number command in the same way that lines
+are specified for print.
+For example, \f31,$nu\f1 lists all lines in the buffer with their
+corresponding line numbers.
+.SH
+Substitute command (s)
+.PP
+Now that you have found the misspelled word,
+you can change it from ``thiss'' to ``this''.
+As far as edit is concerned,
+changing things is a matter of
+substituting one thing for another.
+As
+.I a
+stood for
+.I append,
+so
+.I s
+stands for
+.I substitute.
+We will use the abbreviation ``s'' to reduce the chance
+of mistyping the substitute command.
+This command will instruct edit to make the change:
+.DS I 1i
+\f32s/thiss/this/\f1
+.DE
+We first indicate the line to be changed, line 2,
+and then
+type an ``s'' to indicate we want
+edit to make a substitution.
+Inside the first set of slashes
+are the characters that we want to change,
+followed by the characters to replace them,
+and then a closing slash mark.
+To summarize:
+.DS I 1i
+2s/ \fIwhat is to be changed\fR / \fIwhat to change it to \fR/
+.DE
+If edit finds an exact match of the characters to be
+changed it will make the change
+.B only
+in the first occurrence of the characters.
+If it does not find the characters
+to be changed, it will respond:
+.DS I 1i
+Substitute pattern match failed
+.DE
+indicating that your instructions could not be carried out.
+When edit does find the characters that you want to change,
+it will make the substitution and automatically print
+the changed line, so that you can check that the correct substitution
+was made.
+In the example,
+.DS I 1i
+:\|\fB2s/thiss/this/
+.R
+And this is some more text.
+.DE
+line 2 (and line 2 only) will be searched for the characters
+``thiss'', and when the first exact match is found, ``thiss''
+will be changed to ``this''.
+Strictly speaking, it was not necessary above to
+specify the number of the line to be changed.
+In
+.DS I 1i
+:\|\fBs/thiss/this/
+.R
+.DE
+edit will assume that we mean to change
+the line where we are currently located (``.'').
+In this case,
+the command without a line number would have produced the same result
+because we were already located
+at the line we wished to change.
+.PP
+For another illustration of the substitute command,
+let us choose the line:
+.DS I 1i
+Text editing is strange, but nice.
+.DE
+You can make this line a bit more positive
+by taking out the characters ``strange, but\ '' so the line
+reads:
+.DS I 1i
+Text editing is nice.
+.DE
+A command that will first position edit at the desired line
+and then make the substitution is:
+.DS I 1i
+:\|\fB/strange/s/strange, but //
+.R
+.DE
+.LP
+What we have done here is combine our search with
+our substitution.
+Such combinations are perfectly legal,
+and speed up editing quite a bit
+once you get used to them.
+That is, you do not necessarily have to use
+line numbers to identify a line to edit.
+Instead, you may identify the line you want to change
+by asking edit to search for a specified pattern of letters
+that occurs in that line.
+The parts of the above command are:
+.TS
+.in +1i
+.nr 35 \n(.u
+.nf
+.ds #d .d
+.if \(ts\n(.z\(ts\(ts .ds #d nl
+.nr 80 0
+.nr 38 \w\f3/strange/\fP
+.if \n(80<\n(38 .nr 80 \n(38
+.nr 38 \w\f3s\fP
+.if \n(80<\n(38 .nr 80 \n(38
+.nr 38 \w\f3/strange, but //\fP
+.if \n(80<\n(38 .nr 80 \n(38
+.nr 81 0
+.nr 38 \wtells edit to find the characters ``strange'' in the text
+.if \n(81<\n(38 .nr 81 \n(38
+.nr 38 \wtells edit to make a substitution
+.if \n(81<\n(38 .nr 81 \n(38
+.nr 38 \wsubstitutes nothing at all for the characters ``strange, but ''
+.if \n(81<\n(38 .nr 81 \n(38
+.nr 38 1n
+.nr 79 0
+.nr 40 \n(79+(0*\n(38)
+.nr 80 +\n(40
+.nr 41 \n(80+(3*\n(38)
+.nr 81 +\n(41
+.nr TW \n(81
+.if t .if (\n(TW+\n(.o)>7.75i .tm Table at line 307 file ed2.tbl is too wide - \n(TW units
+.fc  
+.nr #T 0
+.eo
+.de T#
+.ds #d .d
+.if \(ts\n(.z\(ts\(ts .ds #d nl
+.mk ##
+.nr ## -1v
+..
+.ec
+.ta \n(80u \n(81u
+\&\h'|\n(40u'\f3/strange/\fP\h'|\n(41u'tells edit to find the characters ``strange'' in the text
+.ta \n(80u \n(81u
+\&\h'|\n(40u'\f3s\fP\h'|\n(41u'tells edit to make a substitution
+.ta \n(80u \n(81u
+\&\h'|\n(40u'\f3/strange, but //\fP\h'|\n(41u'substitutes nothing at all for the characters ``strange, but ''
+.fc
+.nr T. 1
+.T# 1
+.if \n(35>0 .fi
+.in -1i
+.TE
+.PP
+You should note the space after ``but'' in ``/strange, but /''.
+If you do not indicate that the space is to be taken out,
+your line will read:
+.DS I 1i
+.if t Text editing is nice.
+.if n Text editing is nice.
+.DE
+which looks a little funny
+because of the extra space between ``is'' and ``nice''.
+Again, we realize from this that a blank space
+is a real character to a computer, and in editing text
+we need to be aware of spaces
+within a line just as we would be aware of an ``a'' or
+a ``4''.
+.SH
+Another way to list what's in the buffer (z)
+.PP
+Although the print command is useful for looking at specific lines
+in the buffer,
+other commands may be more convenient for
+viewing large sections of text.
+You can ask to see a screen full of text at a time
+by using the command
+.B z.
+If you type
+.DS I 1i
+:\|\fB1z
+.R
+.DE
+edit will start with line 1 and continue printing lines,
+stopping either when the screen of
+your terminal is full
+or when the last line in the buffer has been printed.
+If you want to read the next segment of text, type the command
+.DS I 1i
+:\|\fBz
+.DE
+If no starting line number is given for the z command,
+printing will start at the ``current'' line, in this case the
+last line printed.
+Viewing lines in the buffer one screen full at a time
+is known as \fIpaging\fR.
+Paging can also be used to print
+a section of text on a hard-copy terminal.
+.SH
+Saving the modified text
+.PP
+This seems to be a good place to pause in our work,
+and so we should end the second session.
+If you (in haste) type ``q'' to quit the session
+your dialogue with edit will be:
+.DS I 1i
+:\|\fBq
+.R
+No write since last change (:quit! overrides)
+:
+.DE
+This is edit's warning that you have not written
+the modified contents of the buffer to disk.
+You run the risk of losing the work you did
+during the editing session since you typed the latest write
+command.
+Because in this lesson we have not written
+to disk at all, everything we have done
+would have been lost
+if edit had obeyed the \fBq\fR command.
+If you did not want to save the work done during
+this editing session, you would have to type ``q!''
+or (``quit!'')
+to confirm that you indeed wanted to end the session
+immediately,
+leaving the file as it was
+after the most recent ``write'' command.
+However,
+since you want to save what
+you have edited, you need to type:
+.DS I 1i
+:\|\fBw
+.R
+"text" 6 lines, 171 characters
+.DE
+and then follow with the commands to quit and logout:
+.DS I 1i
+:\|\fBq
+% \fBlogout\fR
+.DE
+and hang up the phone or turn off the terminal when
+\s-2UNIX\s0 asks for a name.
+Terminals connected to the port selector
+will stop after the logout command,
+and pressing keys on the keyboard will do nothing.
+.sp 1
+.PP
+This is the end of the second session on \s-2UNIX\s0 text editing.
+.bp
+.TL
+Session 3
+.SH
+Bringing text into the buffer (e)
+.PP
+Login to \s-2UNIX\s0 and make contact with edit.
+You should try to login without
+looking at the notes, but if you must
+then by all means do.
+.PP
+Did you remember to give the name of the file
+you wanted to edit?
+That is, did you type
+.DS I 1i
+% \fBedit text\fR
+.DE
+or simply
+.DS I 1i
+% \fBedit\fR
+.DE
+Both ways get you in contact with edit, but the first way
+will bring a copy of the file named ``text'' into
+the buffer.
+If you did forget to tell edit the name of your file,
+you can get it into the buffer by
+typing:
+.DS I 1i
+:\|\fBe text
+.R
+"text" 6 lines, 171 characters
+.DE
+The command
+.B edit,
+which may be abbreviated \fBe\fR,
+tells edit that you want
+to erase anything that might already be in
+the buffer and bring a copy of the file ``text'' into the buffer
+for editing.
+You may also use the edit (e) command to change files in
+the middle of an editing session,
+or to give edit the name of a new file that you want to create.
+Because the edit command clears the buffer,
+you will receive a warning if you try to edit a new file without
+having saved a copy of the old file.
+This gives you a chance to write the contents of the buffer to disk
+before editing the next file.
+.SH
+Moving text in the buffer (m)
+.PP
+Edit allows you to move lines of text
+from one location in the buffer to another
+by means of the
+.B move
+(\fBm\fR) command.
+The first two examples are for illustration only,
+though after you have read this Session
+you are welcome to return to them for practice.
+The command
+.DS I 1i
+:\|\fB2,4m$
+.R
+.DE
+directs edit to move lines 2, 3, and 4
+to the end of the buffer ($).
+The format for the move command is that you specify
+the first line to be moved, the last line to be moved,
+the move command ``m'', and the line after which
+the moved text is to be placed.
+So,
+.DS I 1i
+:\|\fB1,3m6
+.R
+.DE
+would instruct edit to move lines 1 through 3 (inclusive)
+to a location after line 6 in the buffer.
+To move only one line, say, line 4,
+to a location in the buffer after line 5,
+the command would be ``4m5''.
+.PP
+Let's move some text using the command:
+.DS I 1i
+:\|\fB5,$m1
+.R
+2 lines moved
+it does illustrate the editor.
+.DE
+After executing a command that moves more than one line of the buffer,
+edit tells how many lines were affected by the move
+and prints the last moved line for your inspection.
+If you want to see more than just the last line,
+you can then
+use the print (p), z, or number (nu) command to view more text.
+The buffer should now contain:
+.DS I 1i
+This is some sample text.
+It doesn't mean much here, but
+it does illustrate the editor.
+And this is some more text.
+Text editing is nice.
+This is text added in Session 2.
+.DE
+You can restore the original order by typing:
+.DS I 1i
+:\|\fB4,$m1
+.R
+.DE
+or, combining context searching and the move command:
+.DS I 1i
+:\|\fB/And this is some/,/This is text/m/This is some sample/
+.R
+.DE
+(Do not type both examples here!)
+The problem with combining context searching
+with the move command
+is that your chance of making a typing error
+in such a long command is greater than
+if you type line numbers.
+.SH
+Copying lines (copy)
+.PP
+The
+.B copy
+command
+is used to make a second copy of specified lines,
+leaving the original lines where they were.
+Copy
+has the same format as the move command, for example:
+.DS I 1i
+:\|\fB2,5copy $
+.R
+.DE
+makes a copy of lines 2 through 5,
+placing the added lines after the buffer's end ($).
+Experiment with the copy command
+so that you can become familiar with how it works.
+Note that the shortest abbreviation for copy is
+\f3co\f1 (and
+not the letter ``c'', which has another meaning).
+.SH
+Deleting lines (d)
+.PP
+Suppose you want to delete
+the line
+.DS I 1i
+This is text added in Session 2.
+.DE
+from the buffer.
+If you know the number of the line to be deleted,
+you can type
+that number followed by
+\fBdelete\fR or \fBd\fR.
+This example deletes line 4,
+which is ``This is text added in Session 2.''
+if you typed the commands
+suggested so far.
+.DS I 1i
+:\|\fB4d
+.R
+It doesn't mean much here, but
+.DE
+Here ``4'' is the number of the line to be deleted,
+and ``delete'' or ``d'' is the command to delete the line.
+After executing the delete command,
+edit prints the line that has become the current line (``.'').
+.PP
+If you do not happen to know the line number
+you can search for the line and then delete it using this
+sequence of commands:
+.DS I 1i
+:\|\fB/added in Session 2./
+.R
+This is text added in Session 2.
+:\|\fBd
+.R
+It doesn't mean much here, but
+.DE
+The ``/added in Session 2./''
+asks edit to locate and print
+the line containing the indicated text,
+starting its search at the current line
+and moving line by line
+until it finds the text.
+Once you are sure that you have correctly specified the line
+you want to delete,
+you can enter the delete (d) command.
+In this case it is not necessary to
+specify a line number before the ``d''.
+If no line number is given,
+edit deletes the current line (``.''),
+that is, the line found by our search.
+After the deletion, your buffer should contain:
+.DS I 1i
+This is some sample text.
+And this is some more text.
+Text editing is nice.
+It doesn't mean much here, but
+it does illustrate the editor.
+And this is some more text.
+Text editing is nice.
+This is text added in Session 2.
+It doesn't mean much here, but
+.DE
+To delete both lines 2 and 3:
+.DS I 1i
+And this is some more text.
+Text editing is nice.
+.DE
+you type
+.DS I 1i
+:\|\f32,3d\f1
+2 lines deleted
+.DE
+which specifies the range of lines from 2 to 3,
+and the operation on those lines \(em ``d'' for delete.
+If you delete more than one line
+you will receive a message
+telling you the number of lines deleted,
+as indicated in the example above.
+.PP
+The previous example assumes that you know the line numbers for
+the lines to be deleted.
+If you do not you might combine the search command
+with the delete command:
+.DS I 1i
+:\|\fB/And this is some/,/Text editing is nice./d
+.R
+.DE
+.SH
+A word or two of caution
+.PP
+In using the search function to locate lines to
+be deleted you should be
+.B
+absolutely sure
+.R
+the characters you give as the basis for the search
+will take edit to the line you want deleted.
+Edit will search for the first
+occurrence of the characters starting from where
+you last edited \-
+that is, from the line you see printed if you type dot (.).
+.PP
+A search based on too few
+characters may result in the wrong lines being deleted,
+which edit will do as easily as if you had meant it.
+For this reason, it is usually safer
+to specify the search and then delete in two separate steps,
+at least until you become familiar enough with using the editor
+that you understand how best to specify searches.
+For a beginner it is not a bad idea to double-check
+each command before pressing \s-2RETURN\s+2 to send the command on its way.
+.SH
+Undo (u) to the rescue
+.PP
+The
+.B
+undo (u)
+.R
+command has the ability to
+reverse the effects of the last command that changed the buffer.
+To undo the previous command, type
+``u'' or ``undo''.
+Undo can rescue
+the contents of the buffer from many an unfortunate mistake.
+However, its powers are not unlimited,
+so it is still wise to be reasonably
+careful about the commands you give.
+.PP
+It is possible to undo only commands which
+have the power to change the buffer \(em for example,
+delete, append, move, copy, substitute, and even undo itself.
+The commands write (w) and edit (e), which interact with disk files,
+cannot be undone, nor can commands that do not change
+the buffer, such as print.
+Most importantly,
+the
+.B only
+command that can be reversed by undo
+is the
+last ``undo-able'' command you typed.
+You can use control-H and @ to change
+commands while you are typing them,
+and undo to reverse the effect of the commands
+after you have typed them and pressed \s-2RETURN\s+2.
+.PP
+To illustrate,
+let's issue an undo command.
+Recall that the last buffer-changing command we gave deleted
+the lines formerly numbered 2 and 3.
+Typing undo at this moment will reverse the effects
+of the deletion, causing those two lines to be
+replaced in the buffer.
+.DS I 1i
+:\|\fBu
+.R
+2 more lines in file after undo
+And this is some more text.
+.DE
+Here again, edit informs you if the command affects more
+than one line,
+and prints
+the text of the line which is now ``dot'' (the current line).
+.SH
+More about the dot (.) and buffer end ($)
+.PP
+The function assumed by the symbol dot depends on its context.
+It can be used:
+.IP
+1. to exit from append mode; we type dot (and only a dot) on
+a line and press \s-2RETURN\s+2;
+.IP
+2. to refer to the line we are at in the buffer.
+.LP
+Dot can also be combined with the equal sign to get
+the number of the line currently being edited:
+.DS I 1i
+:\|\fB\&.=
+.R
+.DE
+If we type ``\fB.\fR='' we are asking for the number of the line,
+and if we type ``\fB.\fR'' we are asking for the text of the line.
+.PP
+In this editing session and the last, we used the dollar
+sign to indicate the end of the buffer
+in commands such as print, copy, and move.
+The dollar sign as a command asks edit to print the last
+line in the buffer.
+If the dollar sign is combined with the equal sign (\f3$=\f1)
+edit will print the line number corresponding to the
+last line in the buffer.
+.PP
+``\fB.\fR'' and ``$'', then, represent line numbers.
+Whenever appropriate, these symbols can be used in
+place of line numbers in commands.
+For example
+.DS I 1i
+:\|\fB\s+2.\s-2,$d
+.R
+.DE
+instructs edit to delete all lines from the current line (\fB.\fR)
+to the end of the buffer.
+.SH
+Moving around in the buffer (+ and \-)
+.PP
+When you are editing
+you often want
+to go back and re-read a previous line.
+You could specify a context search for a line you want to
+read if you remember some of its text,
+but if you simply want to see what was written a few, say 3, lines
+ago, you can type
+.DS I 1i
+\-3p
+.DE
+This tells edit to move back to a position 3 lines
+before the current line (.)
+and print that line.
+You can move forward in the buffer similarly:
+.DS I 1i
++2p
+.DE
+instructs edit to print the line that is 2
+ahead of your current position.
+.PP
+You may use ``+'' and ``\-'' in any command where edit
+accepts line numbers.
+Line numbers specified with ``+'' or ``\-''
+can be combined to print a range of lines.
+The command
+.DS I 1i
+:\|\fB\-1,+2copy$
+.R
+.DE
+makes a copy of 4 lines: the current line, the line before it,
+and the two after it.
+The copied lines will be placed after the last line
+in the buffer ($),
+and the original lines referred to by ``\-1'' and ``+2''
+remain where they are.
+.PP
+Try typing only ``\-''; you will move back one line just as
+if you had typed ``\-1p''.
+Typing the command ``+'' works similarly.
+You might also try typing a few plus or minus signs in a row
+(such as ``+++'') to see edit's response.
+Typing \s-2RETURN\s+2 alone on a line is the equivalent
+of typing ``+1p''; it will move you one line ahead in the buffer
+and print that line.
+.PP
+If you are at the last line of the buffer and try
+to move further ahead, perhaps by typing a ``+'' or
+a carriage return alone on the line,
+edit will remind you that you are at the end of the buffer:
+.sp
+.nf
+.ti 1i
+At end-of-file
+.br
+or
+.ti 1i
+Not that many lines in buffer
+.fi
+.LP
+Similarly, if you try to move to a position before the first line,
+edit will print one of these messages:
+.sp
+.nf
+.ti 1i
+Nonzero address required on this command
+.br
+or
+.ti 1i
+Negative address \- first buffer line is 1
+.fi
+.LP
+The number associated with a buffer line is the line's ``address'',
+in that it can be used to locate the line.
+.SH
+Changing lines (c)
+.PP
+You can also delete certain lines and
+insert new text in their place.
+This can be accomplished easily with the
+.B "change (c)"
+command.
+The change command instructs edit to delete specified lines
+and then switch to text input mode to
+accept the text that will replace them.
+Let's say you want to change the first two lines in the buffer:
+.DS I 1i
+This is some sample text.
+And this is some more text.
+.DE
+to read
+.DS I 1i
+This text was created with the \s-2UNIX\s0 text editor.
+.DE
+To do so, you type:
+.DS I 1i
+:\|\fB1,2c
+.R
+2 lines changed
+.B
+This text was created with the \s-2UNIX\s0 text editor.
+\s+2\&.\s-2
+.R
+:
+.DE
+In the command
+.B 1,2c
+we specify that we want to change
+the range of lines beginning with 1 and ending with 2
+by giving line numbers as with the print command.
+These lines will be deleted.
+After you type \s-2RETURN\s+2 to end the change command,
+edit notifies you if more than one line will be changed
+and places you in text input mode.
+Any text typed on the following lines will be inserted into
+the position where lines were deleted by the change command.
+.B
+You will remain in text input mode until you exit in the usual way,
+by typing a period alone on a line.
+.R
+Note that the number of lines added to the buffer need not be
+the same as the number of lines deleted.
+.sp 1
+.PP
+This is the end of the third session on text editing with \s-2UNIX\s0.
+.bp
+.SH
+.ce 1
+\s+2Session 4\s0
+.sp
+.PP
+This lesson covers several topics, starting with
+commands that apply throughout the buffer,
+characters with special meanings,
+and how to issue \s-2UNIX\s0 commands while in the editor.
+The next topics deal with files:
+more on reading and writing,
+and methods of recovering files lost in a crash.
+The final section suggests sources of further information.
+.SH
+Making commands global (g)
+.PP
+One disadvantage to the commands we have used for
+searching or substituting is that if you
+have a number of instances of a word to change
+it appears that you have to type the command
+repeatedly, once for
+each time the change needs to be made.
+Edit, however, provides a way to make commands
+apply to the entire contents of the buffer \-
+the
+.B
+global (g)
+.R
+command.
+.PP
+To print all lines
+containing a certain sequence of characters
+(say, ``text'')
+the command is:
+.DS I 1i
+:\|\fBg/text/p
+.R
+.DE
+The ``g'' instructs edit to
+make a global search for all lines
+in the buffer containing the characters ``text''.
+The ``p'' prints the lines found.
+.PP
+To issue a global command, start by typing a ``g'' and then a search
+pattern identifying
+the lines to be affected.
+Then, on the same line, type the command to be
+executed for the identified lines.
+Global substitutions are frequently useful.
+For example,
+to change all instances of the word ``text'' to the word ``material''
+the command would be a combination of the global search and the
+substitute command:
+.DS I 1i
+:\|\fBg/text/s/text/material/g
+.R
+.DE
+Note the ``g'' at the end of the global command,
+which instructs edit to change
+each and every instance of ``text'' to ``material''.
+If you do not type the ``g'' at the end of the command
+only the
+.I first
+instance of ``text'' \fIin each line\fR will be changed
+(the normal result of the substitute command).
+The ``g'' at the end of the command is independent of the ``g''
+at the beginning.
+You may give a command such as:
+.DS I 1i
+:\|\fB5s/text/material/g
+.R
+.DE
+to change every instance of ``text'' in line 5 alone.
+Further, neither command will change ``text'' to ``material''
+if ``Text'' begins with a capital rather than a lower-case
+.I t.
+.PP
+Edit does not automatically print the lines modified by a
+global command.
+If you want the lines to be printed, type a ``p''
+at the end of the global command:
+.DS I 1i
+:\|\fBg/text/s/text/material/gp
+.R
+.DE
+You should be careful
+about using the global command in combination with any other \-
+in essence, be sure of what you are telling edit to do
+to the entire buffer.
+For example,
+.DS I 1i
+:\|\fBg/ /d
+.R
+72 less lines in file after global
+.DE
+will delete every line containing a blank anywhere in it.
+This could adversely affect
+your document, since most lines have spaces between words
+and thus would be deleted.
+After executing the global command,
+edit will print a warning if the command added or deleted more than one line.
+Fortunately, the undo command can reverse
+the effects of a global command.
+You should experiment with the global command
+on a small file of text to see what it can do for you.
+.SH
+More about searching and substituting
+.PP
+In using slashes to identify a character string
+that we want to search for or change,
+we have always specified the exact characters.
+There is a less tedious way to
+repeat the same string of characters.
+To change ``text'' to ``texts'' we may type either
+.DS I 1i
+:\|\fB/text/s/text/texts/
+.R
+.DE
+as we have done in the past,
+or a somewhat abbreviated command:
+.DS I 1i
+:\|\fB/text/s//texts/
+.R
+.DE
+In this example, the characters to be changed
+are not specified \-
+there are no characters, not even a space,
+between the two slash marks
+that indicate what is to be changed.
+This lack of characters between the slashes
+is taken by the editor to mean
+``use the characters we last searched for as the characters to be changed.''
+.PP
+Similarly, the last context search may be repeated
+by typing a pair of slashes with nothing between them:
+.DS I 1i
+:\|\fB/does/
+.R
+It doesn't mean much here, but
+:\|\fB//
+.R
+it does illustrate the editor.
+.DE
+(You should note that the search command found the characters ``does''
+in the word ``doesn't'' in the first search request.)
+Because no characters are specified for the second search,
+the editor scans the buffer for the next occurrence of the
+characters ``does''.
+.PP
+Edit normally searches forward through the buffer,
+wrapping around from the end of the buffer to the beginning,
+until the specified character string is found.
+If you want to search in the reverse direction,
+use question marks (?) instead of slashes
+to surround the characters you are searching for.
+.PP
+It is also possible
+to repeat the last substitution
+without having to retype the entire command.
+An ampersand (&) used as a command
+repeats the most recent substitute command,
+using the same search and replacement patterns.
+After altering the current line by typing
+.DS I 1i
+:\|\fBs/text/texts/
+.R
+.DE
+you type
+.DS I 1i
+:\|\fB/text/&
+.R
+.DE
+or simply
+.DS I 1i
+:\|\fB//&
+.R
+.DE
+to make the same change on the next line in the buffer
+containing the characters ``text''.
+.SH
+Special characters
+.PP
+Two characters have special meanings when
+used in specifying searches: ``$'' and ``^''.
+``$'' is taken by the editor to mean ``end of the line''
+and is used to identify strings
+that occur at the end of a line.
+.DS I 1i
+:\|\fBg/text.$/s//material./p
+.R
+.DE
+tells the editor to search for all lines ending in ``text.''
+(and nothing else, not even a blank space),
+to change each final ``text.'' to ``material.'',
+and print the changed lines.
+.PP
+The symbol ``^'' indicates the beginning of a line.
+Thus,
+.DS I 1i
+:\|\fBs/^/1. /
+.R
+.DE
+instructs the editor to insert ``1.'' and a space at the beginning
+of the current line.
+.PP
+The characters ``$'' and ``^'' have special meanings only in the context
+of searching.
+At other times, they are ordinary characters.
+If you ever need to search for a character that has a special meaning,
+you must indicate that the
+character is to lose temporarily
+its special significance by typing another special character,
+the backslash (\\), before it.
+.DS I 1i
+:\|\fBs/\\\\\&$/dollar/
+.R
+.DE
+looks for the character ``$'' in the current
+line and replaces it by the word ``dollar''.
+Were it not for the backslash, the ``$'' would have represented
+``the end of the line'' in your search
+rather than the character ``$''.
+The backslash retains its special significance
+unless it is preceded by another backslash.
+.SH
+Issuing \s-2UNIX\s0 commands from the editor
+.PP
+After creating several files with the editor,
+you may want to delete files
+no longer useful to you or ask for a list of your files.
+Removing and listing files are not functions of the editor,
+and so they require the use of \s-2UNIX\s0 system commands
+(also referred to as ``shell'' commands, as
+``shell'' is the name of the program that processes \s-2UNIX\s0 commands).
+You do not need to quit the editor to execute a \s-2UNIX\s0 command
+as long as you indicate that it
+is to be sent to the shell for execution.
+To use the \s-2UNIX\s0 command
+.B rm
+to remove the file named ``junk'' type:
+.DS I 1i
+:\|\fB!rm junk
+.R
+!
+:
+.DE
+The exclamation mark (!)
+indicates that the rest of the line is to be processed as a shell command.
+If the buffer contents have not been written since the last change,
+a warning will be printed before the command is executed:
+.DS I 1i
+[No write since last change]
+.DE
+The editor prints a ``!'' when the command is completed.
+Other tutorials describe useful features of the system,
+of which an editor is only one part.
+.SH
+Filenames and file manipulation
+.PP
+Throughout each editing session,
+edit keeps track of the name of the file being edited as the
+.I "current filename."
+Edit remembers as the current filename the name given
+when you entered the editor.
+The current filename changes whenever the edit (e) command
+is used to specify a new file.
+Once edit has recorded a current filename,
+it inserts that name into any command where a filename has been omitted.
+If a write command does not specify a file,
+edit, as we have seen, supplies the current filename.
+If you are editing a file named ``draft3'' having 283 lines in it,
+you can have the editor write onto a different file
+by including its name in the write command:
+.DS I 1i
+:\fB\|w chapter3
+.R
+"chapter3" [new file] 283 lines, 8698 characters
+.DE
+The current filename remembered by the editor
+.I
+will not be changed as a result of the write command.
+.R
+Thus, if the next write command
+does not specify a name,
+edit will write onto the current file (``draft3'')
+and not onto the file ``chapter3''.
+.SH
+The file (f) command
+.PP
+To ask for the current filename, type
+.B file
+(or
+.B f ).
+In response, the editor provides current information about the buffer,
+including the filename, your current position, the number of
+lines in the buffer,
+and the percent of the distance through the file
+your current location is.
+.DS I 1i
+:\|\fBf
+.R
+"text" [Modified] line 3 of 4 --75%--
+.DE
+.\"The expression ``[Edited]'' indicates that the buffer contains
+.\"either the editor's copy of the existing file ``text''
+.\"or a file which you are just now creating.
+If the contents of the buffer have changed
+since the last time the file was written,
+the editor will tell you that the file has been ``[Modified]''.
+After you save the changes by writing onto a disk file,
+the buffer will no longer be considered modified:
+.DS I 1i
+:\|\fBw
+.R
+"text" 4 lines, 88 characters
+:\|\fBf
+.R
+"text" line 3 of 4 --75%--
+.DE
+.SH
+Reading additional files (r)
+.PP
+The
+\f3read (r)\f1 command allows you to add the contents of a file
+to the buffer
+at a specified location,
+essentially copying new lines
+between two existing lines.
+To use it, specify the line after which the new text will be placed,
+the \f3read (r)\f1 command,
+and then the name of the file.
+If you have a file named ``example'', the command
+.DS I 1i
+:\|\fB$r example
+.R
+"example" 18 lines, 473 characters
+.DE
+reads the file ``example''
+and adds it to the buffer after the last line.
+The current filename is not changed by the read command.
+.SH
+Writing parts of the buffer
+.PP
+The
+.B
+write (w)
+.R
+command can write all or part of the buffer
+to a file you specify.
+We are already familiar with
+writing the entire contents of the
+buffer to a disk file.
+To write only part of the buffer onto a file,
+indicate the beginning and ending lines before the write command,
+for example
+.DS I 1i
+:\|\fB45,$w ending
+.R
+.DE
+Here all lines from 45 through the end of the buffer
+are written onto the file named
+.I ending.
+The lines remain in the buffer
+as part of the document you are editing,
+and you may continue to edit the entire buffer.
+Your original file is unaffected
+by your command to write part of the buffer
+to another file.
+Edit still remembers whether you have saved changes to the buffer
+in your original file or not.
+.SH
+Recovering files
+.PP
+Although it does not happen very often,
+there are times \s-2UNIX\s+2 stops working
+because of some malfunction.
+This situation is known as a \fIcrash\fR.
+Under most circumstances,
+edit's crash recovery feature
+is able to save work to within a few lines of changes
+before a crash (or an accidental phone hang up).
+If you lose the contents of an editing buffer in a system crash,
+you will normally receive mail when you login that gives
+the name of the recovered file.
+To recover the file,
+enter the editor and type the command
+.B recover
+(\fBrec\fR),
+followed by the name of the lost file.
+For example,
+to recover the buffer for an edit session
+involving the file ``chap6'', the command is:
+.DS I 1i
+.R
+:\|\fBrecover chap6
+.R
+.DE
+Recover is sometimes unable to save the entire buffer successfully,
+so always check the contents of the saved buffer carefully
+before writing it back onto the original file.
+For best results,
+write the buffer to a new file temporarily
+so you can examine it without risk to the original file.
+Unfortunately,
+you cannot use the recover command
+to retrieve a file you removed
+using the shell command \f3rm\f1.
+.SH
+Other recovery techniques
+.PP
+If something goes wrong when you are using the editor,
+it may be possible to save your work by using the command
+.B preserve
+(\fBpre\fR),
+which saves the buffer as if the system had crashed.
+If you are writing a file and you get the message
+``Quota exceeded'', you have tried to use more disk storage
+than is allotted to your account.
+.I
+Proceed with caution
+.R
+because it is likely that only a part
+of the editor's buffer is now present in the file you tried to write.
+In this case you should use the shell escape from the editor (!)
+to remove some files you don't need and try to write
+the file again.
+If this is not possible and you cannot find someone to help you,
+enter the command
+.DS I 1i
+:\|\fBpreserve
+.R
+.DE
+and wait for the reply,
+.DS I 1i
+File preserved.
+.DE
+If you do not receive this reply,
+seek help immediately.
+Do not simply leave the editor.
+If you do, the buffer will be lost,
+and you may not be able to save your file.
+If the reply is ``File preserved.''
+you can leave the editor
+(or logout)
+to remedy the situation.
+After a preserve, you can use the recover command
+once the problem has been corrected,
+or the \fB\-r\fR option of the edit command
+if you leave the editor and want to return.
+.PP
+If you make an undesirable change to the buffer
+and type a write command before discovering your mistake,
+the modified version will replace any previous version of the file.
+Should you ever lose a good version of a document in this way,
+do not panic and leave the editor.
+As long as you stay in the editor,
+the contents of the buffer remain accessible.
+Depending on the nature of the problem,
+it may be possible
+to restore the buffer to a more complete
+state with the undo command.
+After fixing the damaged buffer, you can again write the file
+to disk.
+.SH
+Further reading and other information
+.PP
+Edit is an editor designed for beginning and casual users.
+It is actually a version of a more powerful editor called
+.I ex.
+These lessons are intended to introduce you to the editor
+and its more commonly-used commands.
+We have not covered all of the editor's commands,
+but a selection of commands
+that should be sufficient to accomplish most of your editing tasks.
+You can find out more about the editor in the
+.I
+Ex Reference Manual,
+.R
+which is applicable to both
+.I ex
+and
+.I edit.
+One way to become familiar with the manual is to begin by reading
+the description of commands that you already know.
+.bd I 3
+.SH
+Using
+.I ex
+.fl
+.bd I
+.PP
+As you become more experienced with using the editor,
+you may still find that edit continues to meet your needs.
+However, should you become interested in using
+.I ex,
+it is easy to switch.
+To begin an editing session with
+.I ex,
+use the name
+.B ex
+in your command instead of
+.B edit.
+.PP
+Edit commands also work in
+.I ex,
+but the editing environment is somewhat different.
+You should be aware of a few differences
+between
+.I ex
+and
+.I edit.
+In edit, only the characters ``^'', ``$'', and ``\\'' have
+special meanings in searching the buffer
+or indicating characters to be changed by a substitute command.
+Several additional characters have special
+meanings in ex, as described in the
+.I
+Ex Reference Manual.
+.R
+Another feature of the edit environment prevents users from
+accidently entering two alternative modes of editing,
+.I open
+and
+.I visual,
+in which
+the editor behaves quite differently from normal command mode.
+If you are using ex and you encounter strange behavior,
+you may have accidently entered open mode by typing ``o''.
+Type the \s-2ESC\s0 key and then a ``Q''
+to get out of open or visual mode and back into
+the regular editor command mode.
+The document
+.I
+An Introduction to Display Editing with Vi\|\|
+.R
+provide full details of visual mode.
+.bp
+.SH
+.ce 1
+\s+2Index\s0
+.LP
+.sp 2
+.2C
+.nf
+addressing, \fIsee\fR line numbers
+ampersand, 20
+append mode, 6-7
+append (a) command, 6, 7, 9
+``At end of file'' (message), 18
+backslash (\\), 21
+buffer, 3
+caret (^), 10, 20
+change (c) command, 18
+command mode, 5-6
+``Command not found'' (message), 6
+context search, 10-12, 19-21
+control characters (``^'' notation), 10
+control-H, 7
+copy (co) command, 15
+corrections, 7, 16
+current filename, 21
+current line (\|.\|), 11, 17
+delete (d) command, 15-16
+dial-up, 5
+disk, 3
+documentation, 3, 23
+dollar ($), 10, 11, 17, 20-21
+dot (\f3\|.\|\f1) 11, 17
+edit (text editor), 3, 5, 23
+edit (e) command, 5, 9, 14
+editing commands:
+.in +.25i
+append (a), 6, 7, 9
+change (c), 18
+copy (co), 15
+delete (d), 15-16
+edit (text editor), 3, 5, 23
+edit (e), 5, 9, 14
+file (f), 21-22
+global (g), 19
+move (m), 14-15
+number (nu), 11
+preserve (pre), 22-23
+print (p), 10
+quit (q), 8, 13
+read (r), 22
+recover (rec), 22, 23
+substitute (s), 11-12, 19, 20
+undo (u), 16-17, 23
+write (w), 8, 13, 21, 22
+z, 12-13
+! (shell escape), 21
+$=, 17
++, 17
+\-, 17
+//, 12, 20
+??, 20
+\&., 11, 17
+\&.=, 11, 17
+.in -.25i
+entering text, 3, 6-7
+erasing
+.in +.25i
+characters (^H), 7
+lines (@), 7
+.in -.25i
+error corrections, 7, 16
+ex (text editor), 23
+\fIEx Reference Manual\fR, 23
+exclamation (!), 21
+file, 3
+file (f) command, 21-22
+file recovery, 22-23
+filename, 3, 21
+global (g) command, 19
+input mode, 6-7
+Interrupt (message), 9
+line numbers, \fIsee also\fR current line
+.in +.25i
+dollar sign ($), 10, 11, 17
+dot (\|.\|), 11, 17
+relative (+ and \-), 17
+.in -.25i
+list, 10
+logging in, 4-6
+logging out, 8
+``Login incorrect'' (message), 5
+minus (\-), 17
+move (m) command, 14-15
+``Negative address\(emfirst buffer line is 1'' (message), 18
+``No current filename'' (message), 8
+``No such file or directory'' (message), 5, 6
+``No write since last change'' (message), 21
+non-printing characters, 10
+``Nonzero address required'' (message), 18
+``Not an editor command'' (message), 6
+``Not that many lines in buffer'' (message), 18
+number (nu) command, 11
+password, 5
+period (\|.\|), 11, 17
+plus (+), 17
+preserve (pre) command, 22-23
+print (p) command, 10
+program, 3
+prompts
+.in .25i
+% (\s-2UNIX\s0), 5
+: (edit), 5, 6, 7
+\0 (append), 7
+.in -.25i
+question (?), 20
+quit (q) command, 8, 13
+read (r) command, 22
+recover (rec) command, 22, 23
+recovery, \fIsee\fR\| file recovery
+references, 3, 23
+remove (rm) command, 21, 22
+reverse command effects (undo), 16-17, 23
+searching, 10-12, 19-21
+shell, 21
+shell escape (!), 21
+slash (/), 11-12, 20
+special characters (^, $, \\), 10, 11, 17, 20-21
+substitute (s) command, 11-12, 19, 20
+terminals, 4-5
+text input mode, 7
+undo (u) command, 16-17, 23
+\s-1UNIX\s0, 3
+write (w) command, 8, 13, 21, 22
+z command, 12-13
+
diff --git a/usr.bin/vi/docs/USD.doc/ex/Makefile b/usr.bin/vi/docs/USD.doc/ex/Makefile
new file mode 100644
index 000000000000..33ab77080f4a
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/ex/Makefile
@@ -0,0 +1,14 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= usd/13.ex
+SRCS= ex.rm
+MACROS= -ms
+CLEANFILES=summary.*
+
+paper.ps: ${SRCS} summary.ps
+ ${ROFF} ${SRCS} > ${.TARGET}
+
+summary.ps: ex.summary
+ ${TBL} ex.summary | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/vi/docs/USD.doc/ex/ex.rm b/usr.bin/vi/docs/USD.doc/ex/ex.rm
new file mode 100644
index 000000000000..79670c2cf66b
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/ex/ex.rm
@@ -0,0 +1,2230 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ex.rm 8.1 (Berkeley) 6/8/93
+.\"
+.EH 'USD:13-%''Ex Reference Manual'
+.OH 'Ex Reference Manual''USD:13-%'
+.de ZP
+.nr pd \\n()P
+.nr )P 0
+.if \\n(.$=0 .IP
+.if \\n(.$=1 .IP "\\$1"
+.if \\n(.$>=2 .IP "\\$1" "\\$2"
+.nr )P \\n(pd
+.rm pd
+..
+.de LC
+.br
+.sp .1i
+.ne 4
+.LP
+.ta 4.0i
+..
+.bd S B 3
+.\".RP
+.TL
+Ex Reference Manual
+.br
+Version 3.7
+.AU
+William Joy
+.AU
+Mark Horton
+.AI
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, Ca. 94720
+.AB
+.I Ex
+a line oriented text editor, which supports both command and display
+oriented editing.
+This reference manual describes the command oriented part of
+.I ex;
+the display editing features of
+.I ex
+are described in
+.I "An Introduction to Display Editing with Vi."
+Other documents about the editor include the introduction
+.I "Edit: A tutorial",
+the
+.I "Ex/edit Command Summary",
+and a
+.I "Vi Quick Reference"
+card.
+.AE
+.NH 1
+Starting ex
+.PP
+.FS
+The financial support of an \s-2IBM\s0 Graduate Fellowship and the National
+Science Foundation under grants MCS74-07644-A03 and MCS78-07291 is gratefully
+acknowledged.
+.FE
+Each instance of the editor has a set of options,
+which can be set to tailor it to your liking.
+The command
+.I edit
+invokes a version of
+.I ex
+designed for more casual or beginning
+users by changing the default settings of some of these options.
+To simplify the description which follows we
+assume the default settings of the options.
+.PP
+When invoked,
+.I ex
+determines the terminal type from the \s-2TERM\s0 variable in the environment.
+It there is a \s-2TERMCAP\s0 variable in the environment, and the type
+of the terminal described there matches the \s-2TERM\s0 variable,
+then that description
+is used. Also if the \s-2TERMCAP\s0 variable contains a pathname (beginning
+with a \fB/\fR) then the editor will seek the description of the terminal
+in that file (rather than the default /etc/termcap).
+If there is a variable \s-2EXINIT\s0 in the environment, then the editor
+will execute the commands in that variable,
+otherwise if there is a file
+.I \&.exrc
+in your \s-2HOME\s0 directory
+.I ex
+reads commands from that file, simulating a
+.I source
+command.
+Option setting commands placed in
+\s-2EXINIT\s0 or
+.I \&.exrc
+will be executed before each editor session.
+.PP
+A command to enter
+.I ex
+has the following prototype:\(dg
+.FS
+\(dg Brackets `[' `]' surround optional parameters here.
+.FE
+.DS
+\fBex\fP [ \fB\-\fP ] [ \fB\-v\fP ] [ \fB\-t\fP \fItag\fP ] [ \fB\-r\fP ] [ \fB\-l\fP ] [ \fB\-w\fP\fIn\fP ] [ \fB\-x\fP ] [ \fB\-R\fP ] [ \fB+\fP\fIcommand\fP ] name ...
+.DE
+The most common case edits a single file with no options, i.e.:
+.DS
+\fBex\fR name
+.DE
+The
+.B \-
+command line option
+option suppresses all interactive-user feedback
+and is useful in processing editor scripts in command files.
+The
+.B \-v
+option is equivalent to using
+.I vi
+rather than
+.I ex.
+The
+.B \-t
+option is equivalent to an initial
+.I tag
+command, editing the file containing the
+.I tag
+and positioning the editor at its definition.
+The
+.B \-r
+option is used in recovering after an editor or system crash,
+retrieving the last saved version of the named file or,
+if no file is specified,
+typing a list of saved files.
+The
+.B \-l
+option sets up for editing \s-2LISP\s0, setting the
+.I showmatch
+and
+.I lisp
+options.
+The
+.B \-w
+option sets the default window size to
+.I n,
+and is useful on dialups to start in small windows.
+The
+.B \-x
+option causes
+.I ex
+to prompt for a
+.I key ,
+which is used to encrypt and decrypt the contents of the file,
+which should already be encrypted using the same key,
+see
+.I crypt (1).
+The
+.B \-R
+option sets the
+.I readonly
+option at the start.
+.I Name
+arguments indicate files to be edited.
+An argument of the form
+\fB+\fIcommand\fR
+indicates that the editor should begin by executing the specified command.
+If
+.I command
+is omitted, then it defaults to ``$'', positioning the editor at the last
+line of the first file initially. Other useful commands here are scanning
+patterns of the form ``/pat'' or line numbers, e.g. ``+100'' starting
+at line 100.
+.NH 1
+File manipulation
+.NH 2
+Current file
+.PP
+.I Ex
+is normally editing the contents of a single file,
+whose name is recorded in the
+.I current
+file name.
+.I Ex
+performs all editing actions in a buffer
+(actually a temporary file)
+into which the text of the file is initially read.
+Changes made to the buffer have no effect on the file being
+edited unless and until the buffer contents are written out to the
+file with a
+.I write
+command.
+After the buffer contents are written,
+the previous contents of the written file are no longer accessible.
+When a file is edited,
+its name becomes the current file name,
+and its contents are read into the buffer.
+.PP
+The current file is almost always considered to be
+.I edited.
+This means that the contents of the buffer are logically
+connected with the current file name,
+so that writing the current buffer contents onto that file,
+even if it exists,
+is a reasonable action.
+If the current file is not
+.I edited
+then
+.I ex
+will not normally write on it if it already exists.*
+.FS
+* The
+.I file
+command will say ``[Not edited]'' if the current file is not considered
+edited.
+.FE
+.NH 2
+Alternate file
+.PP
+Each time a new value is given to the current file name,
+the previous current file name is saved as the
+.I alternate
+file name.
+Similarly if a file is mentioned but does not become the current file,
+it is saved as the alternate file name.
+.NH 2
+Filename expansion
+.PP
+Filenames within the editor may be specified using the normal
+shell expansion conventions.
+In addition,
+the character `%' in filenames is replaced by the
+.I current
+file name and the character
+`#' by the
+.I alternate
+file name.\(dg
+.FS
+\(dg This makes it easy to deal alternately with
+two files and eliminates the need for retyping the
+name supplied on an
+.I edit
+command after a
+.I "No write since last change"
+diagnostic is received.
+.FE
+.NH 2
+Multiple files and named buffers
+.PP
+If more than one file is given on the command line,
+then the first file is edited as described above.
+The remaining arguments are placed with the first file in the
+.I "argument list."
+The current argument list may be displayed with the
+.I args
+command.
+The next file in the argument list may be edited with the
+.I next
+command.
+The argument list may also be respecified by specifying
+a list of names to the
+.I next
+command.
+These names are expanded,
+the resulting list of names becomes the new argument list,
+and
+.I ex
+edits the first file on the list.
+.PP
+For saving blocks of text while editing, and especially when editing
+more than one file,
+.I ex
+has a group of named buffers.
+These are similar to the normal buffer, except that only a limited number
+of operations are available on them.
+The buffers have names
+.I a
+through
+.I z.\(dd
+.FS
+\(dd It is also possible to refer to
+.I A
+through
+.I Z;
+the upper case buffers are the same as the lower but commands
+append to named buffers rather than replacing
+if upper case names are used.
+.FE
+.NH 2
+Read only
+.PP
+It is possible to use
+.I ex
+in
+.I "read only"
+mode to look at files that you have no intention of modifying.
+This mode protects you from accidently overwriting the file.
+Read only mode is on when the
+.I readonly
+option is set.
+It can be turned on with the
+.B \-R
+command line option,
+by the
+.I view
+command line invocation,
+or by setting the
+.I readonly
+option.
+It can be cleared by setting
+.I noreadonly .
+It is possible to write, even while in read only mode, by indicating
+that you really know what you are doing.
+You can write to a different file, or can use the ! form of write,
+even while in read only mode.
+.NH 1
+Exceptional Conditions
+.NH 2
+Errors and interrupts
+.PP
+When errors occur
+.I ex
+(optionally) rings the terminal bell and, in any case, prints an error
+diagnostic. If the primary input is from a file, editor processing
+will terminate. If an interrupt signal is received,
+.I ex
+prints ``Interrupt'' and returns to its command level. If the primary
+input is a file, then
+.I ex
+will exit when this occurs.
+.NH 2
+Recovering from hangups and crashes
+.PP
+If a hangup signal is received and the buffer has been modified since
+it was last written out, or if the system crashes, either the editor
+(in the first case) or the system (after it reboots in the second) will
+attempt to preserve the buffer. The next time you log in you should be
+able to recover the work you were doing, losing at most a few lines of
+changes from the last point before the hangup or editor crash. To
+recover a file you can use the
+.B \-r
+option. If you were editing the file
+.I resume,
+then you should change
+to the directory where you were when the crash occurred, giving the command
+.DS
+\fBex \-r\fP\fI resume\fP
+.DE
+After checking that the retrieved file is indeed ok, you can
+.I write
+it over the previous contents of that file.
+.PP
+You will normally get mail from the system telling you when a file has
+been saved after a crash. The command
+.DS
+\fBex\fP \-\fBr\fP
+.DE
+will print a list of the files which have been saved for you.
+(In the case of a hangup,
+the file will not appear in the list,
+although it can be recovered.)
+.NH 1
+Editing modes
+.PP
+.I Ex
+has five distinct modes. The primary mode is
+.I command
+mode. Commands are entered in command mode when a `:' prompt is
+present, and are executed each time a complete line is sent. In
+.I "text input"
+mode
+.I ex
+gathers input lines and places them in the file. The
+.I append,
+.I insert,
+and
+.I change
+commands use text input mode.
+No prompt is printed when you are in text input mode.
+This mode is left by typing a `.' alone at the beginning of a line, and
+.I command
+mode resumes.
+.PP
+The last three modes are
+.I open
+and
+.I visual
+modes, entered by the commands of the same name, and, within open and
+visual modes
+.I "text insertion"
+mode.
+.I Open
+and
+.I visual
+modes allow local editing operations to be performed on the text in the
+file. The
+.I open
+command displays one line at a time on any terminal while
+.I visual
+works on \s-2CRT\s0 terminals with random positioning cursors, using the
+screen as a (single) window for file editing changes.
+These modes are described (only) in
+.I "An Introduction to Display Editing with Vi."
+.NH
+Command structure
+.PP
+Most command names are English words,
+and initial prefixes of the words are acceptable abbreviations.
+The ambiguity of abbreviations is resolved in favor of the more commonly
+used commands.*
+.FS
+* As an example, the command
+.I substitute
+can be abbreviated `s'
+while the shortest available abbreviation for the
+.I set
+command is `se'.
+.FE
+.NH 2
+Command parameters
+.PP
+Most commands accept prefix addresses specifying the lines in the file
+upon which they are to have effect.
+The forms of these addresses will be discussed below.
+A number of commands also may take a trailing
+.I count
+specifying the number of lines to be involved in the command.\(dg
+.FS
+\(dg Counts are rounded down if necessary.
+.FE
+Thus the command ``10p'' will print the tenth line in the buffer while
+``delete 5'' will delete five lines from the buffer,
+starting with the current line.
+.PP
+Some commands take other information or parameters,
+this information always being given after the command name.\(dd
+.FS
+\(dd Examples would be option names in a
+.I set
+command i.e. ``set number'',
+a file name in an
+.I edit
+command,
+a regular expression in a
+.I substitute
+command,
+or a target address for a
+.I copy
+command, i.e. ``1,5 copy 25''.
+.FE
+.NH 2
+Command variants
+.PP
+A number of commands have two distinct variants.
+The variant form of the command is invoked by placing an
+`!' immediately after the command name.
+Some of the default variants may be controlled by options;
+in this case, the `!' serves to toggle the default.
+.NH 2
+Flags after commands
+.PP
+The characters `#', `p' and `l' may be placed after many commands.**
+.FS
+**
+A `p' or `l' must be preceded by a blank or tab
+except in the single special case `dp'.
+.FE
+In this case, the command abbreviated by these characters
+is executed after the command completes.
+Since
+.I ex
+normally prints the new current line after each change, `p' is rarely necessary.
+Any number of `+' or `\-' characters may also be given with these flags.
+If they appear, the specified offset is applied to the current line
+value before the printing command is executed.
+.NH 2
+Comments
+.PP
+It is possible to give editor commands which are ignored.
+This is useful when making complex editor scripts
+for which comments are desired.
+The comment character is the double quote: ".
+Any command line beginning with " is ignored.
+Comments beginning with " may also be placed at the ends
+of commands, except in cases where they could be confused as part
+of text (shell escapes and the substitute and map commands).
+.NH 2
+Multiple commands per line
+.PP
+More than one command may be placed on a line by separating each pair
+of commands by a `|' character.
+However the
+.I global
+commands,
+comments,
+and the shell escape `!'
+must be the last command on a line, as they are not terminated by a `|'.
+.NH 2
+Reporting large changes
+.PP
+Most commands which change the contents of the editor buffer give
+feedback if the scope of the change exceeds a threshold given by the
+.I report
+option.
+This feedback helps to detect undesirably large changes so that they may
+be quickly and easily reversed with an
+.I undo.
+After commands with more global effect such as
+.I global
+or
+.I visual,
+you will be informed if the net change in the number of lines
+in the buffer during this command exceeds this threshold.
+.NH 1
+Command addressing
+.NH 2
+Addressing primitives
+.IP \fB.\fR 20
+The current line.
+Most commands leave the current line as the last line which they affect.
+The default address for most commands is the current line,
+thus `\fB.\fR' is rarely used alone as an address.
+.IP \fIn\fR 20
+The \fIn\fRth line in the editor's buffer, lines being numbered
+sequentially from 1.
+.IP \fB$\fR 20
+The last line in the buffer.
+.IP \fB%\fR 20
+An abbreviation for ``1,$'', the entire buffer.
+.IP \fI+n\fR\ \fI\-n\fR 20
+An offset relative to the current buffer line.\(dg
+.FS
+\(dg
+The forms `.+3' `+3' and `+++' are all equivalent;
+if the current line is line 100 they all address line 103.
+.FE
+.IP \fB/\fIpat\fR\fB/\fR\ \fB?\fIpat\fR\fB?\fR 20
+Scan forward and backward respectively for a line containing \fIpat\fR, a
+regular expression (as defined below). The scans normally wrap around the end
+of the buffer.
+If all that is desired is to print the next line containing \fIpat\fR, then
+the trailing \fB/\fR or \fB?\fR may be omitted.
+If \fIpat\fP is omitted or explicitly empty, then the last
+regular expression specified is located.\(dd
+.FS
+\(dd The forms \fB\e/\fP and \fB\e?\fP scan
+using the last regular expression used in a scan; after a substitute
+\fB//\fP and \fB??\fP would scan using the substitute's regular expression.
+.FE
+.IP \fB\(aa\(aa\fP\ \fB\(aa\fP\fIx\fP 20
+Before each non-relative motion of the current line `\fB.\fP',
+the previous current line is marked with a tag, subsequently referred to as
+`\(aa\(aa'.
+This makes it easy to refer or return to this previous context.
+Marks may also be established by the
+.I mark
+command, using single lower case letters
+.I x
+and the marked lines referred to as
+`\(aa\fIx\fR'.
+.NH 2
+Combining addressing primitives
+.PP
+Addresses to commands consist of a series of addressing primitives,
+separated by `,' or `;'.
+Such address lists are evaluated left-to-right.
+When addresses are separated by `;' the current line `\fB.\fR'
+is set to the value of the previous addressing expression
+before the next address is interpreted.
+If more addresses are given than the command requires,
+then all but the last one or two are ignored.
+If the command takes two addresses, the first addressed line must
+precede the second in the buffer.\(dg
+.FS
+\(dg Null address specifications are permitted in a list of addresses,
+the default in this case is the current line `.';
+thus `,100' is equivalent to `\fB.\fR,100'.
+It is an error to give a prefix address to a command which expects none.
+.FE
+.NH 1
+Command descriptions
+.PP
+The following form is a prototype for all
+.I ex
+commands:
+.DS
+\fIaddress\fR \fBcommand\fR \fI! parameters count flags\fR
+.DE
+All parts are optional; the degenerate case is the empty command which prints
+the next line in the file. For sanity with use from within
+.I visual
+mode,
+.I ex
+ignores a ``:'' preceding any command.
+.PP
+In the following command descriptions, the
+default addresses are shown in parentheses,
+which are
+.I not,
+however,
+part of the command.
+.LC
+\fBabbreviate\fR \fIword rhs\fP abbr: \fBab\fP
+.ZP
+Add the named abbreviation to the current list.
+When in input mode in visual, if
+.I word
+is typed as a complete word, it will be changed to
+.I rhs .
+.LC
+( \fB.\fR ) \fBappend\fR abbr: \fBa\fR
+.br
+\fItext\fR
+.br
+\&\fB.\fR
+.ZP
+Reads the input text and places it after the specified line.
+After the command, `\fB.\fR'
+addresses the last line input or the
+specified line if no lines were input.
+If address `0' is given,
+text is placed at the beginning of the buffer.
+.LC
+\fBa!\fR
+.br
+\fItext\fR
+.br
+\&\fB.\fR
+.ZP
+The variant flag to
+.I append
+toggles the setting for the
+.I autoindent
+option during the input of
+.I text.
+.LC
+\fBargs\fR
+.ZP
+The members of the argument list are printed, with the current argument
+delimited by `[' and `]'.
+.ig
+.PP
+\fBcd\fR \fIdirectory\fR
+.ZP
+The
+.I cd
+command is a synonym for
+.I chdir.
+..
+.LC
+( \fB.\fP , \fB.\fP ) \fBchange\fP \fIcount\fP abbr: \fBc\fP
+.br
+\fItext\fP
+.br
+\&\fB.\fP
+.ZP
+Replaces the specified lines with the input \fItext\fP.
+The current line becomes the last line input;
+if no lines were input it is left as for a
+\fIdelete\fP.
+.LC
+\fBc!\fP
+.br
+\fItext\fP
+.br
+\&\fB.\fP
+.ZP
+The variant toggles
+.I autoindent
+during the
+.I change.
+.ig
+.LC
+\fBchdir\fR \fIdirectory\fR
+.ZP
+The specified \fIdirectory\fR becomes the current directory.
+If no directory is specified, the current value of the
+.I home
+option is used as the target directory.
+After a
+.I chdir
+the current file is not considered to have been
+edited so that write restrictions on pre-existing files apply.
+..
+.LC
+( \fB.\fP , \fB.\fP )\|\fBcopy\fP \fIaddr\fP \fIflags\fP abbr: \fBco\fP
+.ZP
+A
+.I copy
+of the specified lines is placed after
+.I addr,
+which may be `0'.
+The current line
+`\fB.\fR'
+addresses the last line of the copy.
+The command
+.I t
+is a synonym for
+.I copy.
+.LC
+( \fB.\fR , \fB.\fR )\|\fBdelete\fR \fIbuffer\fR \fIcount\fR \fIflags\fR abbr: \fBd\fR
+.ZP
+Removes the specified lines from the buffer.
+The line after the last line deleted becomes the current line;
+if the lines deleted were originally at the end,
+the new last line becomes the current line.
+If a named
+.I buffer
+is specified by giving a letter,
+then the specified lines are saved in that buffer,
+or appended to it if an upper case letter is used.
+.LC
+\fBedit\fR \fIfile\fR abbr: \fBe\fR
+.br
+\fBex\fR \fIfile\fR
+.ZP
+Used to begin an editing session on a new file.
+The editor
+first checks to see if the buffer has been modified since the last
+.I write
+command was issued.
+If it has been,
+a warning is issued and the
+command is aborted.
+The
+command otherwise deletes the entire contents of the editor buffer,
+makes the named file the current file and prints the new filename.
+After insuring that this file is sensible\(dg
+.FS
+\(dg I.e., that it is not a binary file such as a directory,
+a block or character special file other than
+.I /dev/tty,
+a terminal,
+or a binary or executable file
+(as indicated by the first word).
+.FE
+the editor reads the file into its buffer.
+.IP
+If the read of the file completes without error,
+the number of lines and characters read is typed.
+If there were any non-\s-2ASCII\s0 characters
+in the file they are stripped of their non-\s-2ASCII\s0
+high bits,
+and any null characters in the file are discarded.
+If none of these errors occurred, the file is considered
+.I edited.
+If the last line of the input file is missing the trailing
+newline character, it will be supplied and a complaint will be issued.
+This command leaves the current line `\fB.\fR' at the last line read.\(dd
+.FS
+\(dd If executed from within
+.I open
+or
+.I visual,
+the current line is initially the first line of the file.
+.FE
+.LC
+\fBe!\fR \fIfile\fR
+.ZP
+The variant form suppresses the complaint about modifications having
+been made and not written from the editor buffer, thus
+discarding all changes which have been made before editing the new file.
+.LC
+\fBe\fR \fB+\fIn\fR \fIfile\fR
+.ZP
+Causes the editor to begin at line
+.I n
+rather than at the last line;
+\fIn\fR may also be an editor command containing no spaces, e.g.: ``+/pat''.
+.LC
+\fBfile\fR abbr: \fBf\fR
+.ZP
+Prints the current file name,
+whether it has been `[Modified]' since the last
+.I write
+command,
+whether it is
+.I "read only" ,
+the current line,
+the number of lines in the buffer,
+and the percentage of the way through the buffer of the current line.*
+.FS
+* In the rare case that the current file is `[Not edited]' this is
+noted also; in this case you have to use the form \fBw!\fR to write to
+the file, since the editor is not sure that a \fBwrite\fR will not
+destroy a file unrelated to the current contents of the buffer.
+.FE
+.LC
+\fBfile\fR \fIfile\fR
+.ZP
+The current file name is changed to
+.I file
+which is considered
+`[Not edited]'.
+.LC
+( 1 , $ ) \fBglobal\fR /\fIpat\|\fR/ \fIcmds\fR abbr: \fBg\fR
+.ZP
+First marks each line among those specified which matches
+the given regular expression.
+Then the given command list is executed with `\fB.\fR' initially
+set to each marked line.
+.IP
+The command list consists of the remaining commands on the current
+input line and may continue to multiple lines by ending all but the
+last such line with a `\e'.
+If
+.I cmds
+(and possibly the trailing \fB/\fR delimiter) is omitted, each line matching
+.I pat
+is printed.
+.I Append,
+.I insert,
+and
+.I change
+commands and associated input are permitted;
+the `\fB.\fR' terminating input may be omitted if it would be on the
+last line of the command list.
+.I Open
+and
+.I visual
+commands are permitted in the command list and take input from the terminal.
+.IP
+The
+.I global
+command itself may not appear in
+.I cmds.
+The
+.I undo
+command is also not permitted there,
+as
+.I undo
+instead can be used to reverse the entire
+.I global
+command.
+The options
+.I autoprint
+and
+.I autoindent
+are inhibited during a
+.I global,
+(and possibly the trailing \fB/\fR delimiter) and the value of the
+.I report
+option is temporarily infinite,
+in deference to a \fIreport\fR for the entire global.
+Finally, the context mark `\'\'' is set to the value of
+`.' before the global command begins and is not changed during a global
+command,
+except perhaps by an
+.I open
+or
+.I visual
+within the
+.I global.
+.LC
+\fBg!\fR \fB/\fIpat\fB/\fR \fIcmds\fR abbr: \fBv\fR
+.IP
+The variant form of \fIglobal\fR runs \fIcmds\fR at each line not matching
+\fIpat\fR.
+.LC
+( \fB.\fR )\|\fBinsert\fR abbr: \fBi\fR
+.br
+\fItext\fR
+.br
+\&\fB.\fR
+.ZP
+Places the given text before the specified line.
+The current line is left at the last line input;
+if there were none input it is left at the line before the addressed line.
+This command differs from
+.I append
+only in the placement of text.
+.KS
+.LC
+\fBi!\fR
+.br
+\fItext\fR
+.br
+\&\fB.\fR
+.ZP
+The variant toggles
+.I autoindent
+during the
+.I insert.
+.KE
+.LC
+( \fB.\fR , \fB.\fR+1 ) \fBjoin\fR \fIcount\fR \fIflags\fR abbr: \fBj\fR
+.ZP
+Places the text from a specified range of lines
+together on one line.
+White space is adjusted at each junction to provide at least
+one blank character, two if there was a `\fB.\fR' at the end of the line,
+or none if the first following character is a `)'.
+If there is already white space at the end of the line,
+then the white space at the start of the next line will be discarded.
+.LC
+\fBj!\fR
+.ZP
+The variant causes a simpler
+.I join
+with no white space processing; the characters in the lines are simply
+concatenated.
+.LC
+( \fB.\fR ) \fBk\fR \fIx\fR
+.ZP
+The
+.I k
+command is a synonym for
+.I mark.
+It does not require a blank or tab before the following letter.
+.LC
+( \fB.\fR , \fB.\fR ) \fBlist\fR \fIcount\fR \fIflags\fR
+.ZP
+Prints the specified lines in a more unambiguous way:
+tabs are printed as `^I'
+and the end of each line is marked with a trailing `$'.
+The current line is left at the last line printed.
+.LC
+\fBmap\fR \fIlhs\fR \fIrhs\fR
+.ZP
+The
+.I map
+command is used to define macros for use in
+.I visual
+mode.
+.I Lhs
+should be a single character, or the sequence ``#n'', for n a digit,
+referring to function key \fIn\fR. When this character or function key
+is typed in
+.I visual
+mode, it will be as though the corresponding \fIrhs\fR had been typed.
+On terminals without function keys, you can type ``#n''.
+See section 6.9 of the ``Introduction to Display Editing with Vi''
+for more details.
+.LC
+( \fB.\fR ) \fBmark\fR \fIx\fR
+.ZP
+Gives the specified line mark
+.I x,
+a single lower case letter.
+The
+.I x
+must be preceded by a blank or a tab.
+The addressing form `\'x' then addresses this line.
+The current line is not affected by this command.
+.LC
+( \fB.\fR , \fB.\fR ) \fBmove\fR \fIaddr\fR abbr: \fBm\fR
+.ZP
+The
+.I move
+command repositions the specified lines to be after
+.I addr .
+The first of the moved lines becomes the current line.
+.LC
+\fBnext\fR abbr: \fBn\fR
+.ZP
+The next file from the command line argument list is edited.
+.LC
+\fBn!\fR
+.ZP
+The variant suppresses warnings about the modifications to the buffer not
+having been written out, discarding (irretrievably) any changes which may
+have been made.
+.LC
+\fBn\fR \fIfilelist\fR
+.br
+\fBn\fR \fB+\fIcommand\fR \fIfilelist\fR
+.ZP
+The specified
+.I filelist
+is expanded and the resulting list replaces the
+current argument list;
+the first file in the new list is then edited.
+If
+.I command
+is given (it must contain no spaces), then it is executed after editing the first such file.
+.LC
+( \fB.\fR , \fB.\fR ) \fBnumber\fR \fIcount\fR \fIflags\fR abbr: \fB#\fR or \fBnu\fR
+.ZP
+Prints each specified line preceded by its buffer line
+number.
+The current line is left at the last line printed.
+.KS
+.LC
+( \fB.\fR ) \fBopen\fR \fIflags\fR abbr: \fBo\fR
+.br
+( \fB.\fR ) \fBopen\fR /\fIpat\|\fR/ \fIflags\fR
+.ZP
+Enters intraline editing \fIopen\fR mode at each addressed line.
+If
+.I pat
+is given,
+then the cursor will be placed initially at the beginning of the
+string matched by the pattern.
+To exit this mode use Q.
+See
+.I "An Introduction to Display Editing with Vi"
+for more details.
+.KE
+.LC
+\fBpreserve\fR
+.ZP
+The current editor buffer is saved as though the system had just crashed.
+This command is for use only in emergencies when a
+.I write
+command has resulted in an error and you don't know how to save your work.
+After a
+.I preserve
+you should seek help.
+.LC
+( \fB.\fR , \fB.\fR )\|\fBprint\fR \fIcount\fR abbr: \fBp\fR or \fBP\fR
+.ZP
+Prints the specified lines
+with non-printing characters printed as control characters `^\fIx\fR\|';
+delete (octal 177) is represented as `^?'.
+The current line is left at the last line printed.
+.LC
+( \fB.\fR )\|\fBput\fR \fIbuffer\fR abbr: \fBpu\fR
+.ZP
+Puts back
+previously
+.I deleted
+or
+.I yanked
+lines.
+Normally used with
+.I delete
+to effect movement of lines,
+or with
+.I yank
+to effect duplication of lines.
+If no
+.I buffer
+is specified, then the last
+.I deleted
+or
+.I yanked
+text is restored.*
+.FS
+* But no modifying commands may intervene between the
+.I delete
+or
+.I yank
+and the
+.I put,
+nor may lines be moved between files without using a named buffer.
+.FE
+By using a named buffer, text may be restored that was saved there at any
+previous time.
+.LC
+\fBquit\fR abbr: \fBq\fR
+.ZP
+Causes
+.I ex
+to terminate.
+No automatic write of the editor buffer to a file is performed.
+However,
+.I ex
+issues a warning message if the file has changed
+since the last
+.I write
+command was issued, and does not
+.I quit.\(dg
+.FS
+\(dg \fIEx\fR
+will also issue a diagnostic if there are more files in the argument
+list.
+.FE
+Normally, you will wish to save your changes, and you
+should give a \fIwrite\fR command;
+if you wish to discard them, use the \fBq!\fR command variant.
+.LC
+\fBq!\fR
+.ZP
+Quits from the editor, discarding changes to the buffer without complaint.
+.LC
+( \fB.\fR ) \fBread\fR \fIfile\fR abbr: \fBr\fR
+.ZP
+Places a copy of the text of the given file in the
+editing buffer after the specified line.
+If no
+.I file
+is given the current file name is used.
+The current file name is not changed unless there is none in which
+case
+.I file
+becomes the current name.
+The sensibility restrictions for the
+.I edit
+command apply here also.
+If the file buffer is empty and there is no current name then
+.I ex
+treats this as an
+.I edit
+command.
+.IP
+Address `0' is legal for this command and causes the file to be read at
+the beginning of the buffer.
+Statistics are given as for the
+.I edit
+command when the
+.I read
+successfully terminates.
+After a
+.I read
+the current line is the last line read.\(dd
+.FS
+\(dd Within
+.I open
+and
+.I visual
+the current line is set to the first line read rather than the last.
+.FE
+.LC
+( \fB.\fR ) \fBread\fR \fB!\fR\fIcommand\fR
+.ZP
+Reads the output of the command
+.I command
+into the buffer after the specified line.
+This is not a variant form of the command, rather a read
+specifying a
+.I command
+rather than a
+.I filename;
+a blank or tab before the \fB!\fR is mandatory.
+.LC
+\fBrecover \fIfile\fR
+.ZP
+Recovers
+.I file
+from the system save area.
+Used after a accidental hangup of the phone**
+.FS
+** The system saves a copy of the file you were editing only if you
+have made changes to the file.
+.FE
+or a system crash** or
+.I preserve
+command.
+Except when you use
+.I preserve
+you will be notified by mail when a file is saved.
+.LC
+\fBrewind\fR abbr: \fBrew\fR
+.ZP
+The argument list is rewound, and the first file in the list is edited.
+.LC
+\fBrew!\fR
+.ZP
+Rewinds the argument list discarding any changes made to the current buffer.
+.LC
+\fBset\fR \fIparameter\fR
+.ZP
+With no arguments, prints those options whose values have been
+changed from their defaults;
+with parameter
+.I all
+it prints all of the option values.
+.IP
+Giving an option name followed by a `?'
+causes the current value of that option to be printed.
+The `?' is unnecessary unless the option is Boolean valued.
+Boolean options are given values either by the form
+`set \fIoption\fR' to turn them on or
+`set no\fIoption\fR' to turn them off;
+string and numeric options are assigned via the form
+`set \fIoption\fR=value'.
+.IP
+More than one parameter may be given to
+.I set \|;
+they are interpreted left-to-right.
+.LC
+\fBshell\fR abbr: \fBsh\fR
+.IP
+A new shell is created.
+When it terminates, editing resumes.
+.LC
+\fBsource\fR \fIfile\fR abbr: \fBso\fR
+.IP
+Reads and executes commands from the specified file.
+.I Source
+commands may be nested.
+.LC
+( \fB.\fR , \fB.\fR ) \fBsubstitute\fR /\fIpat\fR\|/\fIrepl\fR\|/ \fIoptions\fR \fIcount\fR \fIflags\fR abbr: \fBs\fR
+.IP
+On each specified line, the first instance of pattern
+.I pat
+is replaced by replacement pattern
+.I repl.
+If the
+.I global
+indicator option character `g'
+appears, then all instances are substituted;
+if the
+.I confirm
+indication character `c' appears,
+then before each substitution the line to be substituted
+is typed with the string to be substituted marked
+with `\(ua' characters.
+By typing an `y' one can cause the substitution to be performed,
+any other input causes no change to take place.
+After a
+.I substitute
+the current line is the last line substituted.
+.IP
+Lines may be split by substituting
+new-line characters into them.
+The newline in
+.I repl
+must be escaped by preceding it with a `\e'.
+Other metacharacters available in
+.I pat
+and
+.I repl
+are described below.
+.LC
+.B stop
+.ZP
+Suspends the editor, returning control to the top level shell.
+If
+.I autowrite
+is set and there are unsaved changes,
+a write is done first unless the form
+.B stop !
+is used.
+This commands is only available where supported by the teletype driver
+and operating system.
+.LC
+( \fB.\fR , \fB.\fR ) \fBsubstitute\fR \fIoptions\fR \fIcount\fR \fIflags\fR abbr: \fBs\fR
+.ZP
+If
+.I pat
+and
+.I repl
+are omitted, then the last substitution is repeated.
+This is a synonym for the
+.B &
+command.
+.LC
+( \fB.\fR , \fB.\fR ) \fBt\fR \fIaddr\fR \fIflags\fR
+.ZP
+The
+.I t
+command is a synonym for
+.I copy .
+.LC
+\fBta\fR \fItag\fR
+.ZP
+The focus of editing switches to the location of
+.I tag,
+switching to a different line in the current file where it is defined,
+or if necessary to another file.\(dd
+.FS
+\(dd If you have modified the current file before giving a
+.I tag
+command, you must write it out; giving another
+.I tag
+command, specifying no
+.I tag
+will reuse the previous tag.
+.FE
+.IP
+The tags file is normally created by a program such as
+.I ctags,
+and consists of a number of lines with three fields separated by blanks
+or tabs. The first field gives the name of the tag,
+the second the name of the file where the tag resides, and the third
+gives an addressing form which can be used by the editor to find the tag;
+this field is usually a contextual scan using `/\fIpat\fR/' to be immune
+to minor changes in the file. Such scans are always performed as if
+.I nomagic
+was set.
+.PP
+The tag names in the tags file must be sorted alphabetically.
+.LC
+\fBunabbreviate\fR \fIword\fP abbr: \fBuna\fP
+.ZP
+Delete
+.I word
+from the list of abbreviations.
+.LC
+\fBundo\fR abbr: \fBu\fR
+.ZP
+Reverses the changes made in the buffer by the last
+buffer editing command.
+Note that
+.I global
+commands are considered a single command for the purpose of
+.I undo
+(as are
+.I open
+and
+.I visual.)
+Also, the commands
+.I write
+and
+.I edit
+which interact with the
+file system cannot be undone.
+.I Undo
+is its own inverse.
+.IP
+.I Undo
+always marks the previous value of the current line `\fB.\fR'
+as `\'\''.
+After an
+.I undo
+the current line is the first line restored
+or the line before the first line deleted if no lines were restored.
+For commands with more global effect
+such as
+.I global
+and
+.I visual
+the current line regains it's pre-command value after an
+.I undo.
+.LC
+\fBunmap\fR \fIlhs\fR
+.ZP
+The macro expansion associated by
+.I map
+for
+.I lhs
+is removed.
+.LC
+( 1 , $ ) \fBv\fR /\fIpat\fR\|/ \fIcmds\fR
+.ZP
+A synonym for the
+.I global
+command variant \fBg!\fR, running the specified \fIcmds\fR on each
+line which does not match \fIpat\fR.
+.LC
+\fBversion\fR abbr: \fBve\fR
+.ZP
+Prints the current version number of the editor
+as well as the date the editor was last changed.
+.LC
+( \fB.\fR ) \fBvisual\fR \fItype\fR \fIcount\fR \fIflags\fR abbr: \fBvi\fR
+.ZP
+Enters visual mode at the specified line.
+.I Type
+is optional and may be `\-' , `\(ua' or `\fB.\fR'
+as in the
+.I z
+command to specify the placement of the specified line on the screen.
+By default, if
+.I type
+is omitted, the specified line is placed as the first on the screen.
+A
+.I count
+specifies an initial window size; the default is the value of the option
+.I window.
+See the document
+.I "An Introduction to Display Editing with Vi"
+for more details.
+To exit this mode, type Q.
+.LC
+\fBvisual\fP file
+.br
+\fBvisual\fP +\fIn\fP file
+.ZP
+From visual mode,
+this command is the same as edit.
+.LC
+( 1 , $ ) \fBwrite\fR \fIfile\fR abbr: \fBw\fR
+.ZP
+Writes changes made back to \fIfile\fR, printing the number of lines and
+characters written.
+Normally \fIfile\fR is omitted and the text goes back where it came from.
+If a \fIfile\fR is specified, then text will be written to that file.*
+.FS
+* The editor writes to a file only if it is
+the current file and is
+.I edited ,
+if the file does not exist,
+or if the file is actually a teletype,
+.I /dev/tty,
+.I /dev/null.
+Otherwise, you must give the variant form \fBw!\fR to force the write.
+.FE
+If the file does not exist it is created.
+The current file name is changed only if there is no current file
+name; the current line is never changed.
+.IP
+If an error occurs while writing the current and
+.I edited
+file, the editor
+considers that there has been ``No write since last change''
+even if the buffer had not previously been modified.
+.LC
+( 1 , $ ) \fBwrite>>\fR \fIfile\fR abbr: \fBw>>\fR
+.ZP
+Writes the buffer contents at the end of
+an existing file.
+.IP
+.LC
+\fBw!\fR \fIname\fR
+.ZP
+Overrides the checking of the normal \fIwrite\fR command,
+and will write to any file which the system permits.
+.LC
+( 1 , $ ) \fBw\fR \fB!\fR\fIcommand\fR
+.ZP
+Writes the specified lines into
+.I command.
+Note the difference between \fBw!\fR which overrides checks and
+\fBw\ \ !\fR which writes to a command.
+.LC
+\fBwq\fR \fIname\fR
+.ZP
+Like a \fIwrite\fR and then a \fIquit\fR command.
+.LC
+\fBwq!\fR \fIname\fR
+.ZP
+The variant overrides checking on the sensibility of the
+.I write
+command, as \fBw!\fR does.
+.LC
+\fBxit\fP \fIname\fR
+.ZP
+If any changes have been made and not written, writes the buffer out.
+Then, in any case, quits.
+.LC
+( \fB.\fR , \fB.\fR )\|\fByank\fR \fIbuffer\fR \fIcount\fR abbr: \fBya\fR
+.ZP
+Places the specified lines in the named
+.I buffer,
+for later retrieval via
+.I put.
+If no buffer name is specified, the lines go to a more volatile place;
+see the \fIput\fR command description.
+.LC
+( \fB.+1\fR ) \fBz\fR \fIcount\fR
+.ZP
+Print the next \fIcount\fR lines, default \fIwindow\fR.
+.LC
+( \fB.\fR ) \fBz\fR \fItype\fR \fIcount\fR
+.ZP
+Prints a window of text with the specified line at the top.
+If \fItype\fR is `\-' the line is placed at the bottom; a `\fB.\fR' causes
+the line to be placed in the center.*
+A count gives the number of lines to be displayed rather than
+double the number specified by the \fIscroll\fR option.
+On a \s-2CRT\s0 the screen is cleared before display begins unless a
+count which is less than the screen size is given.
+The current line is left at the last line printed.
+.FS
+* Forms `z=' and `z\(ua' also exist; `z=' places the current line in the
+center, surrounds it with lines of `\-' characters and leaves the current
+line at this line. The form `z\(ua' prints the window before `z\-'
+would. The characters `+', `\(ua' and `\-' may be repeated for cumulative
+effect.
+On some v2 editors, no
+.I type
+may be given.
+.FE
+.LC
+\fB!\fR \fIcommand\fR\fR
+.ZP
+The remainder of the line after the `!' character is sent to a shell
+to be executed.
+Within the text of
+.I command
+the characters
+`%' and `#' are expanded as in filenames and the character
+`!' is replaced with the text of the previous command.
+Thus, in particular,
+`!!' repeats the last such shell escape.
+If any such expansion is performed, the expanded line will be echoed.
+The current line is unchanged by this command.
+.IP
+If there has been ``[No\ write]'' of the buffer contents since the last
+change to the editing buffer, then a diagnostic will be printed
+before the command is executed as a warning.
+A single `!' is printed when the command completes.
+.LC
+( \fIaddr\fR , \fIaddr\fR ) \fB!\fR \fIcommand\fR\fR
+.ZP
+Takes the specified address range and supplies it as
+standard input to
+.I command;
+the resulting output then replaces the input lines.
+.LC
+( $ ) \fB=\fR
+.ZP
+Prints the line number of the
+addressed line.
+The current line is unchanged.
+.KS
+.LC
+( \fB.\fR , \fB.\fR ) \fB>\fR \fIcount\fR \fIflags\fR
+.br
+( \fB.\fR , \fB.\fR ) \fB<\fR \fIcount\fR \fIflags\fR
+.IP
+Perform intelligent shifting on the specified lines;
+\fB<\fR shifts left and \fB>\fR shift right.
+The quantity of shift is determined by the
+.I shiftwidth
+option and the repetition of the specification character.
+Only white space (blanks and tabs) is shifted;
+no non-white characters are discarded in a left-shift.
+The current line becomes the last line which changed due to the
+shifting.
+.KE
+.LC
+\fB^D\fR
+.ZP
+An end-of-file from a terminal input scrolls through the file.
+The
+.I scroll
+option specifies the size of the scroll, normally a half screen of text.
+.LC
+( \fB.\fR+1 , \fB.\fR+1 )
+.br
+( \fB.\fR+1 , \fB.\fR+1 ) |
+.ZP
+An address alone causes the addressed lines to be printed.
+A blank line prints the next line in the file.
+.LC
+( \fB.\fR , \fB.\fR ) \fB&\fR \fIoptions\fR \fIcount\fR \fIflags\fR
+.ZP
+Repeats the previous
+.I substitute
+command.
+.LC
+( \fB.\fR , \fB.\fR ) \fB\s+2~\s0\fR \fIoptions\fR \fIcount\fR \fIflags\fR
+.ZP
+Replaces the previous regular expression with the previous
+replacement pattern from a substitution.
+.NH 1
+Regular expressions and substitute replacement patterns
+.NH 2
+Regular expressions
+.PP
+A regular expression specifies a set of strings of characters.
+A member of this set of strings is said to be
+.I matched
+by the regular expression.
+.I Ex
+remembers two previous regular expressions:
+the previous regular expression used in a
+.I substitute
+command
+and the previous regular expression used elsewhere
+(referred to as the previous \fIscanning\fR regular expression.)
+The previous regular expression
+can always be referred to by a null \fIre\fR, e.g. `//' or `??'.
+.NH 2
+Magic and nomagic
+.PP
+The regular expressions allowed by
+.I ex
+are constructed in one of two ways depending on the setting of
+the
+.I magic
+option.
+The
+.I ex
+and
+.I vi
+default setting of
+.I magic
+gives quick access to a powerful set of regular expression
+metacharacters.
+The disadvantage of
+.I magic
+is that the user must remember that these metacharacters are
+.I magic
+and precede them with the character `\e'
+to use them as ``ordinary'' characters.
+With
+.I nomagic,
+the default for
+.I edit,
+regular expressions are much simpler,
+there being only two metacharacters.
+The power of the other metacharacters is still available by preceding
+the (now) ordinary character with a `\e'.
+Note that `\e' is thus always a metacharacter.
+.PP
+The remainder of the discussion of regular expressions assumes
+that
+that the setting of this option is
+.I magic.\(dg
+.FS
+\(dg To discern what is true with
+.I nomagic
+it suffices to remember that the only
+special characters in this case will be `\(ua' at the beginning
+of a regular expression,
+`$' at the end of a regular expression,
+and `\e'.
+With
+.I nomagic
+the characters `\s+2~\s0' and `&' also lose their special meanings
+related to the replacement pattern of a substitute.
+.FE
+.NH 2
+Basic regular expression summary
+.PP
+The following basic constructs are used to construct
+.I magic
+mode regular expressions.
+.IP \fIchar\fR 15
+An ordinary character matches itself.
+The characters `\(ua' at the beginning of a line,
+`$' at the end of line,
+`*' as any character other than the first,
+`.', `\e', `[', and `\s+2~\s0' are not ordinary characters and
+must be escaped (preceded) by `\e' to be treated as such.
+.IP \fB\(ua\fR
+At the beginning of a pattern
+forces the match to succeed only at the beginning of a line.
+.IP \fB$\fR
+At the end of a regular expression forces the match to
+succeed only at the end of the line.
+.IP \&\fB.\fR
+Matches any single character except
+the new-line character.
+.IP \fB\e<\fR
+Forces the match
+to occur only at the beginning of a ``variable'' or ``word'';
+that is, either at the beginning of a line, or just before
+a letter, digit, or underline and after a character not one of
+these.
+.IP \fB\e>\fR
+Similar to `\e<', but matching the end of a ``variable''
+or ``word'', i.e. either the end of the line or before character
+which is neither a letter, nor a digit, nor the underline character.
+.IP \fB[\fIstring\fR]\fR
+Matches any (single) character in the class defined by
+.I string.
+Most characters in
+.I string
+define themselves.
+A pair of characters separated by `\-' in
+.I string
+defines the set of characters collating between the specified lower and upper
+bounds, thus `[a\-z]' as a regular expression matches
+any (single) lower-case letter.
+If the first character of
+.I string
+is an `\(ua' then the construct
+matches those characters which it otherwise would not;
+thus `[\(uaa\-z]' matches anything but a lower-case letter (and of course a
+newline).
+To place any of the characters
+`\(ua', `[', or `\-' in
+.I string
+you must escape them with a preceding `\e'.
+.NH 2
+Combining regular expression primitives
+.PP
+The concatenation of two regular expressions matches the leftmost and
+then longest string
+which can be divided with the first piece matching the first regular
+expression and the second piece matching the second.
+Any of the (single character matching) regular expressions mentioned
+above may be followed by the character `*' to form a regular expression
+which matches any number of adjacent occurrences (including 0) of characters
+matched by the regular expression it follows.
+.PP
+The character `\s+2~\s0' may be used in a regular expression,
+and matches the text which defined the replacement part
+of the last
+.I substitute
+command.
+A regular expression may be enclosed between the sequences
+`\e(' and `\e)' with side effects in the
+.I substitute
+replacement patterns.
+.NH 2
+Substitute replacement patterns
+.PP
+The basic metacharacters for the replacement pattern are
+`&' and `~'; these are
+given as `\e&' and `\e~' when
+.I nomagic
+is set.
+Each instance of `&' is replaced by the characters
+which the regular expression matched.
+The metacharacter `~' stands, in the replacement pattern,
+for the defining text of the previous replacement pattern.
+.PP
+Other metasequences possible in the replacement pattern
+are always introduced by the escaping character `\e'.
+The sequence `\e\fIn\fR' is replaced by the text matched
+by the \fIn\fR-th regular subexpression enclosed between
+`\e(' and `\e)'.\(dg
+.FS
+\(dg When nested, parenthesized subexpressions are present,
+\fIn\fR is determined by counting occurrences of `\e(' starting from the left.
+.FE
+The sequences `\eu' and `\el' cause the immediately following character in
+the replacement to be converted to upper- or lower-case respectively
+if this character is a letter.
+The sequences `\eU' and `\eL' turn such conversion on, either until
+`\eE' or `\ee' is encountered, or until the end of the replacement pattern.
+.de LC
+.br
+.sp .1i
+.ne 4
+.LP
+.ta 3i
+..
+.NH 1
+Option descriptions
+.PP
+.LC
+\fBautoindent\fR, \fBai\fR default: noai
+.ZP
+Can be used to ease the preparation of structured program text.
+At the beginning of each
+.I append ,
+.I change
+or
+.I insert
+command
+or when a new line is
+.I opened
+or created by an
+.I append ,
+.I change ,
+.I insert ,
+or
+.I substitute
+operation within
+.I open
+or
+.I visual
+mode,
+.I ex
+looks at the line being appended after,
+the first line changed
+or the line inserted before and calculates the amount of white space
+at the start of the line.
+It then aligns the cursor at the level of indentation so determined.
+.IP
+If the user then types lines of text in,
+they will continue to be justified at the displayed indenting level.
+If more white space is typed at the beginning of a line,
+the following line will start aligned with the first non-white character
+of the previous line.
+To back the cursor up to the preceding tab stop one can hit
+\fB^D\fR.
+The tab stops going backwards are defined at multiples of the
+.I shiftwidth
+option.
+You
+.I cannot
+backspace over the indent,
+except by sending an end-of-file with a \fB^D\fR.
+.IP
+Specially processed in this mode is a line with no characters added
+to it, which turns into a completely blank line (the white
+space provided for the
+.I autoindent
+is discarded.)
+Also specially processed in this mode are lines beginning with
+an `\(ua' and immediately followed by a \fB^D\fR.
+This causes the input to be repositioned at the beginning of the line,
+but retaining the previous indent for the next line.
+Similarly, a `0' followed by a \fB^D\fR
+repositions at the beginning but without
+retaining the previous indent.
+.IP
+.I Autoindent
+doesn't happen in
+.I global
+commands or when the input is not a terminal.
+.LC
+\fBautoprint\fR, \fBap\fR default: ap
+.ZP
+Causes the current line to be printed after each
+.I delete ,
+.I copy ,
+.I join ,
+.I move ,
+.I substitute ,
+.I t ,
+.I undo
+or
+shift command.
+This has the same effect as supplying a trailing `p'
+to each such command.
+.I Autoprint
+is suppressed in globals,
+and only applies to the last of many commands on a line.
+.LC
+\fBautowrite\fR, \fBaw\fR default: noaw
+.ZP
+Causes the contents of the buffer to be written to the current file
+if you have modified it and give a
+.I next,
+.I rewind,
+.I stop,
+.I tag,
+or
+.I !
+command, or a \fB^\(ua\fR (switch files) or \fB^]\fR (tag goto) command
+in
+.I visual.
+Note, that the
+.I edit
+and
+.I ex
+commands do
+.B not
+autowrite.
+In each case, there is an equivalent way of switching when autowrite
+is set to avoid the
+.I autowrite
+(\fIedit\fR
+for
+.I next ,
+.I rewind!
+for .I rewind ,
+.I stop!
+for
+.I stop ,
+.I tag!
+for
+.I tag ,
+.I shell
+for
+.I ! ,
+and
+\fB:e\ #\fR and a \fB:ta!\fR command from within
+.I visual).
+.LC
+\fBbeautify\fR, \fBbf\fR default: nobeautify
+.ZP
+Causes all control characters except tab, newline and form-feed
+to be discarded from the input.
+A complaint is registered the first time a
+backspace character is discarded.
+.I Beautify
+does not apply to command input.
+.LC
+\fBdirectory\fR, \fBdir\fR default: dir=/tmp
+.ZP
+Specifies the directory in which
+.I ex
+places its buffer file.
+If this directory in not
+writable, then the editor will exit abruptly when it fails to be
+able to create its buffer there.
+.LC
+\fBedcompatible\fR default: noedcompatible
+.ZP
+Causes the presence of absence of
+.B g
+and
+.B c
+suffixes on substitute commands to be remembered, and to be toggled
+by repeating the suffices. The suffix
+.B r
+makes the substitution be as in the
+.I ~
+command, instead of like
+.I &.
+.LC
+\fBerrorbells\fR, \fBeb\fR default: noeb
+.ZP
+Error messages are preceded by a bell.*
+.FS
+* Bell ringing in
+.I open
+and
+.I visual
+on errors is not suppressed by setting
+.I noeb.
+.FE
+If possible the editor always places the error message in a standout mode of the
+terminal (such as inverse video) instead of ringing the bell.
+.LC
+\fBhardtabs\fR, \fBht\fR default: ht=8
+.ZP
+Gives the boundaries on which terminal hardware tabs are set (or
+on which the system expands tabs).
+.LC
+\fBignorecase\fR, \fBic\fR default: noic
+.ZP
+All upper case characters in the text are mapped to lower case in regular
+expression matching.
+In addition, all upper case characters in regular expressions are mapped
+to lower case except in character class specifications.
+.LC
+\fBlisp\fR default: nolisp
+.ZP
+\fIAutoindent\fR indents appropriately for
+.I lisp
+code, and the \fB( ) { } [[\fR and \fB]]\fR commands in
+.I open
+and
+.I visual
+are modified to have meaning for \fIlisp\fR.
+.LC
+\fBlist\fR default: nolist
+.ZP
+All printed lines will be displayed (more) unambiguously,
+showing tabs and end-of-lines as in the
+.I list
+command.
+.LC
+\fBmagic\fR default: magic for \fIex\fR and \fIvi\fR\(dg
+.FS
+\(dg \fINomagic\fR for \fIedit\fR.
+.FE
+.ZP
+If
+.I nomagic
+is set, the number of regular expression metacharacters is greatly reduced,
+with only `\(ua' and `$' having special effects.
+In addition the metacharacters
+`~'
+and
+`&'
+of the replacement pattern are treated as normal characters.
+All the normal metacharacters may be made
+.I magic
+when
+.I nomagic
+is set by preceding them with a `\e'.
+.LC
+\fBmesg\fR default: mesg
+.ZP
+Causes write permission to be turned off to the terminal
+while you are in visual mode, if
+.I nomesg
+is set.
+.LC
+\fBmodeline\fR default: nomodeline
+.ZP
+If
+.I modeline
+is set, then the first 5 lines and the last five lines of the file
+will be checked for ex command lines and the comands issued.
+To be recognized as a command line, the line must have the string
+.B ex:
+or
+.B vi:
+preceeded by a tab or a space. This string may be anywhere in the
+line and anything after the
+.I :
+is interpeted as editor commands. This option defaults to off because
+of unexpected behavior when editting files such as
+.I /etc/passwd.
+.LC
+\fBnumber, nu\fR default: nonumber
+.ZP
+Causes all output lines to be printed with their
+line numbers.
+In addition each input line will be prompted for by supplying the line number
+it will have.
+.LC
+\fBopen\fR default: open
+.ZP
+If \fInoopen\fR, the commands
+.I open
+and
+.I visual
+are not permitted.
+This is set for
+.I edit
+to prevent confusion resulting from accidental entry to
+open or visual mode.
+.LC
+\fBoptimize, opt\fR default: optimize
+.ZP
+Throughput of text is expedited by setting the terminal
+to not do automatic carriage returns
+when printing more than one (logical) line of output,
+greatly speeding output on terminals without addressable
+cursors when text with leading white space is printed.
+.LC
+\fBparagraphs,\ para\fR default: para=IPLPPPQPP\0LIbp
+.ZP
+Specifies the paragraphs for the \fB{\fR and \fB}\fR operations in
+.I open
+and
+.I visual.
+The pairs of characters in the option's value are the names
+of the macros which start paragraphs.
+.LC
+\fBprompt\fR default: prompt
+.ZP
+Command mode input is prompted for with a `:'.
+.LC
+\fBredraw\fR default: noredraw
+.ZP
+The editor simulates (using great amounts of output), an intelligent
+terminal on a dumb terminal (e.g. during insertions in
+.I visual
+the characters to the right of the cursor position are refreshed
+as each input character is typed.)
+Useful only at very high speed.
+.LC
+\fBremap\fP default: remap
+.ZP
+If on, macros are repeatedly tried until they are unchanged.
+For example, if
+.B o
+is mapped to
+.B O ,
+and
+.B O
+is mapped to
+.B I ,
+then if
+.I remap
+is set,
+.B o
+will map to
+.B I ,
+but if
+.I noremap
+is set, it will map to
+.B O .
+.LC
+\fBreport\fR default: report=5\(dg
+.FS
+\(dg 2 for \fIedit\fR.
+.FE
+.ZP
+Specifies a threshold for feedback from commands.
+Any command which modifies more than the specified number of lines
+will provide feedback as to the scope of its changes.
+For commands such as
+.I global ,
+.I open ,
+.I undo ,
+and
+.I visual
+which have potentially more far reaching scope,
+the net change in the number of lines in the buffer is
+presented at the end of the command, subject to this same threshold.
+Thus notification is suppressed during a
+.I global
+command on the individual commands performed.
+.LC
+\fBscroll\fR default: scroll=\(12 window
+.ZP
+Determines the number of logical lines scrolled when an end-of-file
+is received from a terminal input in command mode,
+and the number of lines printed by a command mode
+.I z
+command (double the value of
+.I scroll ).
+.LC
+\fBsections\fR default: sections=SHNHH\0HU
+.ZP
+Specifies the section macros for the \fB[[\fR and \fB]]\fR operations
+in
+.I open
+and
+.I visual.
+The pairs of characters in the options's value are the names
+of the macros which start paragraphs.
+.LC
+\fBshell\fR, \fBsh\fR default: sh=/bin/sh
+.ZP
+Gives the path name of the shell forked for
+the shell escape command `!', and by the
+.I shell
+command.
+The default is taken from SHELL in the environment, if present.
+.LC
+\fBshiftwidth\fR, \fBsw\fR default: sw=8
+.ZP
+Gives the width a software tab stop,
+used in reverse tabbing with \fB^D\fR when using
+.I autoindent
+to append text,
+and by the shift commands.
+.LC
+\fBshowmatch, sm\fR default: nosm
+.ZP
+In
+.I open
+and
+.I visual
+mode, when a \fB)\fR or \fB}\fR is typed, move the cursor to the matching
+\fB(\fR or \fB{\fR for one second if this matching character is on the
+screen. Extremely useful with
+.I lisp.
+.LC
+\fBslowopen, slow\fR terminal dependent
+.ZP
+Affects the display algorithm used in
+.I visual
+mode, holding off display updating during input of new text to improve
+throughput when the terminal in use is both slow and unintelligent.
+See
+.I "An Introduction to Display Editing with Vi"
+for more details.
+.LC
+\fBtabstop,\ ts\fR default: ts=8
+.ZP
+The editor expands tabs in the input file to be on
+.I tabstop
+boundaries for the purposes of display.
+.LC
+\fBtaglength,\ tl\fR default: tl=0
+.ZP
+Tags are not significant beyond this many characters.
+A value of zero (the default) means that all characters are significant.
+.LC
+\fBtags\fR default: tags=tags /usr/lib/tags
+.ZP
+A path of files to be used as tag files for the
+.I tag
+command.
+A requested tag is searched for in the specified files, sequentially.
+By default, files called
+.B tags
+are searched for in the current directory and in /usr/lib
+(a master file for the entire system).
+.LC
+\fBterm\fR from environment TERM
+.ZP
+The terminal type of the output device.
+.LC
+\fBterse\fR default: noterse
+.ZP
+Shorter error diagnostics are produced for the experienced user.
+.LC
+\fBwarn\fR default: warn
+.ZP
+Warn if there has been `[No write since last change]' before a `!'
+command escape.
+.LC
+\fBwindow\fR default: window=speed dependent
+.ZP
+The number of lines in a text window in the
+.I visual
+command.
+The default is 8 at slow speeds (600 baud or less),
+16 at medium speed (1200 baud),
+and the full screen (minus one line) at higher speeds.
+.LC
+\fBw300,\ w1200\, w9600\fR
+.ZP
+These are not true options but set
+.B window
+only if the speed is slow (300), medium (1200), or high (9600),
+respectively.
+They are suitable for an EXINIT
+and make it easy to change the 8/16/full screen rule.
+.LC
+\fBwrapscan\fR, \fBws\fR default: ws
+.ZP
+Searches using the regular expressions in addressing
+will wrap around past the end of the file.
+.LC
+\fBwrapmargin\fR, \fBwm\fR default: wm=0
+.ZP
+Defines a margin for automatic wrapover of text during input in
+.I open
+and
+.I visual
+modes. See
+.I "An Introduction to Text Editing with Vi"
+for details.
+.LC
+\fBwriteany\fR, \fBwa\fR default: nowa
+.IP
+Inhibit the checks normally made before
+.I write
+commands, allowing a write to any file which the system protection
+mechanism will allow.
+.NH 1
+Limitations
+.PP
+Editor limits that the user is likely to encounter are as follows:
+1024 characters per line,
+256 characters per global command list,
+128 characters per file name,
+128 characters in the previous inserted and deleted text in
+.I open
+or
+.I visual,
+100 characters in a shell escape command,
+63 characters in a string valued option,
+and 30 characters in a tag name, and
+a limit of 250000 lines in the file is silently enforced.
+.PP
+The
+.I visual
+implementation limits the number of macros defined with map to
+32, and the total number of characters in macros to be less than 512.
+.LP
+.LP
+.I Acknowledgments.
+Chuck Haley contributed greatly to the early development of
+.I ex.
+Bruce Englar encouraged the redesign which led to
+.I ex
+version 1.
+Bill Joy wrote versions 1 and 2.0 through 2.7,
+and created the framework that users see in the present editor.
+Mark Horton added macros and other features and made the
+editor work on a large number of terminals and Unix systems.
diff --git a/usr.bin/vi/docs/USD.doc/ex/ex.summary b/usr.bin/vi/docs/USD.doc/ex/ex.summary
new file mode 100644
index 000000000000..618da07c7420
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/ex/ex.summary
@@ -0,0 +1,734 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ex.summary 8.1 (Berkeley) 6/8/93
+.\"
+.ds p \v'-0.2'.\v'+0.2'
+.ds U \s-2UNIX\s+2
+.ds c \v'-0.2':\v'+0.2'
+.nr PO .25i
+.nr LL 6.75i
+.lt 6.75i
+.ll 6.75i
+.ds CH
+.ds LF Computing Services, U.C. Berkeley
+.ds RF April 3, 1979
+.de SP
+.sp 1v
+..
+.nr PI 3n
+.nr PD 0
+.ND
+.ps 12
+.ft B
+.ce 1
+Ex/Edit Command Summary (Version 2.0)
+.ft R
+.nr VS 11
+.nr PS 9
+.nr HM 0.5i
+.nr CW
+.2C
+.PP
+.I Ex
+and
+.I edit
+are text editors, used for creating
+and modifying files of text on the \*U
+computer system.
+.I Edit
+is a variant of
+.I ex
+with features designed to
+make it less complicated
+to learn and use.
+In terms of command syntax and effect
+the editors are essentially identical,
+and this command summary applies to both.
+.PP
+The summary is meant as a quick reference
+for users already acquainted
+with
+.I edit
+or \fIex\fP.
+Fuller explanations of the editors are available
+in the documents
+.I
+Edit: A Tutorial
+.R
+(a self-teaching introduction) and the
+.I
+Ex Reference Manual
+.R
+(the comprehensive reference source for
+both \fIedit\fP and \fIex\fP).
+Both of these writeups are available in the
+Computing Services Library.
+.PP
+In the examples included with the
+summary, commands and text entered by
+the user are printed in \fBboldface\fR to
+distinguish them from responses printed
+by the computer.
+.sp 0.45v
+.LP
+.B
+The Editor Buffer
+.PP
+In order to perform its tasks
+the editor sets aside a temporary
+work space,
+called a \fIbuffer\fR,
+separate from the user's permanent
+file.
+Before starting to work on an existing
+file the editor makes a copy of it in the
+buffer, leaving the original untouched.
+All editing changes are made to the
+buffer copy, which must then
+be written back to the permanent
+file in order to update the
+old version.
+The buffer disappears
+at the end of the editing session.
+.sp 0.45v
+.LP
+.B
+Editing: Command and Text Input Modes
+.PP
+.R
+During an editing session there are
+two usual modes of operation:
+\fIcommand\fP mode and \fItext input\fP
+mode.
+(This disregards, for the moment,
+.I open
+and
+.I visual
+modes, discussed below.)
+In command mode, the editor issues a
+colon prompt (:)
+to show that it is ready to
+accept and execute a command.
+In text input mode, on the other hand, there is
+no prompt and the editor merely accepts text to
+be added to the buffer.
+Text input mode is initiated by the commands
+\fIappend\fP, \fIinsert\fP, and \fIchange\fP,
+and is terminated by typing a period as the
+first and only character on a line.
+.sp 0.45v
+.LP
+.B
+Line Numbers and Command Syntax
+.PP
+.R
+The editor keeps track of lines of text
+in the buffer by numbering them consecutively
+starting with 1 and renumbering
+as lines are added or deleted.
+At any given time the editor is positioned
+at one of these lines; this position is
+called the \fIcurrent line\fP.
+Generally, commands that change the
+contents of the buffer print the
+new current line at the end of their
+execution.
+.PP
+Most commands can be preceded by one or two
+line-number addresses which indicate the lines
+to be affected.
+If one number is given the command operates on
+that line only; if two, on an inclusive range
+of lines.
+Commands that can take line-number prefixes also
+assume default prefixes if none are given.
+The default assumed by each command is designed
+to make it convenient to use in many instances
+without any line-number prefix.
+For the most part, a command used without a
+prefix operates on the current line,
+though exceptions to this rule should be noted.
+The \fIprint\fP command
+by itself, for instance, causes
+one line, the current line, to be
+printed at the terminal.
+.PP
+The summary shows the number of line addresses
+that can be
+prefixed to each command as well as
+the defaults assumed if they are omitted.
+For example,
+.I (.,.)
+means that up to 2 line-numbers may be given,
+and that if none is given the
+command operates on the current line.
+(In the address prefix notation, ``.'' stands
+for the current line and ``$'' stands for
+the last line of the buffer.)
+If no such notation appears, no
+line-number prefix may be used.
+.PP
+Some commands take trailing
+information;
+only
+the more important instances of this
+are mentioned in the summary.
+.sp 0.25v
+.LP
+.B
+Open and Visual Modes
+.PP
+.R
+Besides command and text input modes,
+.I ex
+and
+.I edit
+provide on some CRT terminals other modes of editing,
+.I open
+and
+.I visual .
+In these modes the cursor can
+be moved to individual words
+or characters in a line.
+The commands then given are very different
+from the standard editor commands; most do not appear on the screen when
+typed.
+.I
+An Introduction to Display Editing with Vi
+.R
+provides a full discussion.
+.sp 0.25v
+.LP
+.B
+Special Characters
+.PP
+.R
+.fi
+Some characters take on special meanings
+when used in context searches
+and in patterns given to the \fIsubstitute\fP command.
+For \fIedit\fR, these are ``^'' and ``$'',
+meaning the beginning and end of a line,
+respectively.
+.I Ex
+has the following additional special characters:
+.B
+.ce 1
+\&. & * [ ] ~
+.R
+To use one of the special characters as its
+simple graphic representation
+rather than with its special meaning,
+precede it by a backslash (\\).
+The backslash always has a special meaning.
+.1C
+.rm LF
+.rm RF
+.rm CF
+.nr FM 0.4
+.TS
+cp10 cp10 cp10 cp10
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+Name Abbr Description Examples
+.sp 1.75
+(.)\fBappend a T{
+Begins text input mode,
+adding lines to the buffer after
+the line specified. Appending continues
+until ``.'' is typed alone at the
+beginning of a new line, followed by
+a carriage return. \fI0a\fR places
+lines at the beginning of the buffer.
+T} T{
+.nf
+\fR:\fBa
+Three lines of text
+are added to the buffer
+after the current line.
+\*p
+.R
+\*c
+.fi
+T}
+.SP
+\fR(.,.)\fBchange c T{
+Deletes indicated line(s) and
+initiates text input mode to
+replace them with new text which follows.
+New text is terminated the same way
+as with \fIappend\fR.
+T} T{
+.nf
+:\fB5,6c
+Lines 5 and 6 are
+deleted and replaced by
+these three lines.
+\*p
+.R
+\*c
+.fi
+T}
+.SP
+\fR(.,.)\fBcopy \fIaddr co T{
+Places a copy of the specified lines
+after the line indicated by \fIaddr\fR.
+The example places a copy of lines 8 through
+12, inclusive, after line 25.
+T} T{
+.nf
+\fR:\fB8,12co 25
+\fRLast line copied is printed
+\fR\*c
+.fi
+T}
+.SP
+\fR(.,.)\fBdelete d T{
+Removes lines from the buffer
+and prints the current line after the deletion.
+T} T{
+.nf
+\fR:\fB13,15d
+\fRNew current line is printed
+\*c
+.fi
+T}
+.TE
+.sp 0.5v
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+T{
+\fBedit \fIfile\fP
+.br
+\fBedit! \fIfile\fP
+T} T{
+e
+.br
+e!
+T} T{
+.fi
+\fRClears the editor buffer and then
+copies into it the named \fIfile\fR,
+which becomes the current file.
+This is a way of shifting to a different
+file
+without leaving the editor.
+The editor issues a warning
+message if this command is used before
+saving changes
+made to the file already in the buffer;
+using the form \fBe!\fR overrides this protective mechanism.
+T} T{
+.nf
+\fR:\fBe ch10\fR
+No write since last change
+:\fBe! ch10\fR
+"ch10" 3 lines, 62 characters
+\*c
+.fi
+T}
+.SP
+\fBfile \fIname\fR f T{
+\fRIf followed by a \fIname\fR, renames
+the current file to \fIname\fR.
+If used without \fIname\fR, prints
+the name of the current file.
+T} T{
+.nf
+\fR:\fBf ch9
+\fR"ch9" [Modified] 3 lines ...
+:\fBf
+\fR"ch9" [Modified] 3 lines ...
+\*c
+.fi
+T}
+.SP
+(1,$)\fBglobal g \fBglobal/\fIpattern\fB/\fIcommands T{
+.nf
+:\fBg/nonsense/d
+\fR\*c
+.fi
+T}
+\fR(1,$)\fBglobal! g!\fR or \fBv T{
+Searches the entire buffer (unless a smaller
+range is specified by line-number prefixes) and
+executes \fIcommands\fR on every line with
+an expression matching \fIpattern\fR.
+The second form, abbreviated
+either \fBg!\fR or \fBv\fR,
+executes \fIcommands\fR on lines that \fIdo
+not\fR contain the expression \fIpattern\fR.
+T} \^
+.SP
+\fR(.)\fBinsert i T{
+Inserts new lines of text immediately before the specified line.
+Differs from
+.I append
+only in that text is placed before, rather than after, the indicated line.
+In other words, \fB1i\fR has the same effect as \fB0a\fR.
+T} T{
+.nf
+:\fB1i
+These lines of text will
+be added prior to line 1.
+\&.
+\fR:
+.fi
+T} \^
+.SP
+\fR(.,.+1)\fBjoin j T{
+Join lines together, adjusting white space (spaces
+and tabs) as necessary.
+T} T{
+.nf
+:\fB2,5j\fR
+Resulting line is printed
+:
+.fi
+T} \^
+.TE
+.bp
+.TS
+cp10 cp10 cp10 cp10
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+Name Abbr Description Examples
+.sp 1.75
+\fR(.,.)\fBlist l T{
+\fRPrints lines in a more
+unambiguous way than the \fIprint\fR
+command does. The end of a line,
+for example, is marked with a ``$'',
+and tabs printed as ``^I''.
+T} T{
+.nf
+:\fB9l
+\fRThis is line 9$
+\*c
+.fi
+T}
+.TE
+.sp 0.5v
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+\fR(.,.)\fBmove \fIaddr\fB m T{
+\fRMoves the specified lines
+to a position after the line
+indicated by \fIaddr\fR.
+T} T{
+.nf
+\fR:\fB12,15m 25\fR
+New current line is printed
+\*c
+.fi
+T}
+.SP
+\fR(.,.)\fBnumber nu T{
+Prints each line preceded
+by its buffer line number.
+T} T{
+.nf
+\fR:\fBnu
+\0\0\fR10\0 This is line 10
+\*c
+.fi
+T}
+.SP
+\fR(.)\fBopen o T{
+Too involved to discuss here,
+but if you enter open mode
+accidentally, press
+the \s-2ESC\s0 key followed by
+\fBq\fR to
+get back into normal editor
+command mode.
+\fIEdit\fP is designed to
+prevent accidental use of
+the open command.
+T}
+.SP
+\fBpreserve pre T{
+Saves a copy of the current buffer contents as though the system had
+just crashed. This is for use in an emergency when a
+.I write
+command has failed and you don't know how else to save your work.\(dg
+T} T{
+.nf
+:\fBpreserve\fR
+File preserved.
+:
+.fi
+T}
+.SP
+\fR(.,.)\fBprint p Prints the text of line(s). T{
+.nf
+:\fB+2,+3p\fR
+The second and third lines
+after the current line
+:
+.fi
+T}
+.TE
+.FS
+\(dg Seek assistance from a consultant as soon as possible
+after saving a file with the
+.I preserve
+command, because the file is saved on system storage space for only one week.
+.FE
+.SP
+.nf
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+T{
+.nf
+\fBquit
+quit!
+.fi
+T} T{
+.nf
+q
+q!
+T} T{
+.fi
+\fREnds the editing session.
+You will receive a
+warning if you have changed the buffer
+since last writing its contents
+to the file. In this event you
+must either type \fBw\fR to write,
+or type \fBq!\fR to exit from
+the editor without saving your changes.
+T} T{
+.nf
+\fR:\fBq
+\fRNo write since last change
+:\fBq!
+\fR%
+.fi
+T}
+.SP
+\fR(.)\fBread \fIfile\fP r T{
+.fi
+\fRPlaces a copy of \fIfile\fR in the
+buffer after the specified line.
+Address 0 is permissible and causes
+the copy of \fIfile\fR to be placed
+at the beginning of the buffer.
+The \fIread\fP command does not
+erase any text already in the buffer.
+If no line number is specified,
+\fIfile\fR is placed after the
+current line.
+T} T{
+.nf
+\fR:\fB0r newfile
+\fR"newfile" 5 lines, 86 characters
+\*c
+.fi
+T}
+.SP
+\fBrecover \fIfile\fP rec T{
+.fi
+Retrieves a copy of the editor buffer
+after a system crash, editor crash,
+phone line disconnection, or
+\fIpreserve\fR command.
+T}
+.SP
+\fR(.,.)\fBsubstitute s T{
+.nf
+\fBsubstitute/\fIpattern\fB/\fIreplacement\fB/
+substitute/\fIpattern\fB/\fIreplacement\fB/gc
+.fi
+\fRReplaces the first occurrence of \fIpattern\fR
+on a line
+with \fIreplacement\fP.
+Including a \fBg\fR after the command
+changes all occurrences of \fIpattern\fP
+on the line.
+The \fBc\fR option allows the user to
+confirm each substitution before it is
+made; see the manual for details.
+T} T{
+.nf
+:\fB3p
+\fRLine 3 contains a misstake
+:\fBs/misstake/mistake/
+\fRLine 3 contains a mistake
+\*c
+.fi
+T}
+.TE
+.bp
+.TS
+cp10 cp10 cp10 cp10
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+Name Abbr Description Examples
+.sp 1.75
+\fBundo u T{
+.fi
+\fRReverses the changes made in
+the buffer by the last buffer-editing
+command.
+Note that this example contains
+a notification about the number of
+lines affected.
+T} T{
+.nf
+\fR:\fB1,15d
+\fR15 lines deleted
+new line number 1 is printed
+:\fBu
+\fR15 more lines in file ...
+old line number 1 is printed
+\*c
+.fi
+T}
+.SP
+\fR(1,$)\fBwrite \fIfile\fR w T{
+.fi
+\fRCopies data from the buffer onto
+a permanent file. If no \fIfile\fR
+is named, the current filename
+is used.
+The file is automatically created
+if it does not yet exist.
+A response containing the number of
+lines and characters in the file
+indicates that the write
+has been completed successfully.
+The editor's built-in protections
+against overwriting existing files
+will in some circumstances
+inhibit a write.
+The form \fBw!\fR forces the
+write, confirming that
+an existing file is to be overwritten.
+T} T{
+.nf
+\fR:\fBw
+\fR"file7" 64 lines, 1122 characters
+:\fBw file8
+\fR"file8" File exists ...
+:\fBw! file8
+\fR"file8" 64 lines, 1122 characters
+\*c
+.fi
+T}
+\fR(1,$)\fBwrite! \fIfile\fP w! \^ \^
+.TE
+.sp 0.5v
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+\fR(.)\fBz \fIcount\fP z T{
+.fi
+\fRPrints a screen full of text starting
+with the line indicated;
+or, if \fIcount\fR is specified,
+prints that number of lines.
+Variants of the \fIz\fR command
+are described in the manual.
+T}
+.SP
+\fB!\fIcommand T{
+.fi
+Executes the remainder of the line
+after \fB!\fR as a \*U command.
+The buffer is unchanged by this, and
+control is returned to the editor when
+the execution of \fIcommand\fR is complete.
+T} T{
+.nf
+\fR:\fB!date
+\fRFri Jun 9 12:15:11 PDT 1978
+!
+\*c
+.fi
+T}
+.SP
+\fRcontrol-d T{
+.fi
+Prints the next \fIscroll\fR of text,
+normally half of a screen. See the
+manual for details of the \fIscroll\fR
+option.
+T}
+.SP
+\fR(.+1)<cr> T{
+.fi
+An address alone followed by a carriage
+return causes the line to be printed.
+A carriage return by itself prints the
+line following the current line.
+T} T{
+.nf
+:\fR<cr>
+the line after the current line
+\*c
+.fi
+T}
+.TE
+.sp 0.5v
+.TS
+ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i).
+\fB/\fIpattern\fB/ T{
+.fi
+\fRSearches for the next line in which
+\fIpattern\fR occurs and prints it.
+T} T{
+.nf
+\fR:\fB/This pattern/
+\fRThis pattern next occurs here.
+\*c
+.fi
+T}
+.SP
+\fB// T{
+Repeats the most recent search.
+T} T{
+.nf
+\fR:\fB//
+\fRThis pattern also occurs here.
+\*c
+.fi
+T}
+.SP
+\fB?\fIpattern\fB? T{
+Searches in the reverse direction
+for \fIpattern\fP.
+T}
+.SP
+\fB?? T{
+Repeats the most recent search,
+moving in the reverse direction
+through the buffer.
+T}
+.TE
+
diff --git a/usr.bin/vi/docs/USD.doc/vi/Makefile b/usr.bin/vi/docs/USD.doc/vi/Makefile
new file mode 100644
index 000000000000..c6131af77971
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/Makefile
@@ -0,0 +1,17 @@
+# @(#)Makefile 8.1 (Berkeley) 8/14/93
+
+DIR= usd/12.vi
+SRCS= vi.in vi.chars
+MACROS= -ms
+CLEANFILES+=summary.* viapwh.*
+
+paper.ps: ${SRCS} summary.ps viapwh.ps
+ ${TBL} ${SRCS} | ${ROFF} > ${.TARGET}
+
+summary.ps: vi.summary
+ ${TBL} vi.summary | ${ROFF} > ${.TARGET}
+
+viapwh.ps: vi.apwh.ms
+ ${ROFF} vi.apwh.ms > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/vi/docs/USD.doc/vi/vi.apwh.ms b/usr.bin/vi/docs/USD.doc/vi/vi.apwh.ms
new file mode 100644
index 000000000000..d0b62611c701
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/vi.apwh.ms
@@ -0,0 +1,1079 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)vi.apwh.ms 8.1 (Berkeley) 6/8/93
+.\"
+.TL
+Vi Command & Function Reference
+.AU CB 2675
+Alan P.W. Hewett
+.sp
+Revised for version 2.12 by Mark Horton
+.CB
+.NH 1
+Author's Disclaimer
+.LP
+This document does not claim to be 100% complete. There are a
+few commands listed in the original document that I was unable
+to test either because I do not speak \fBlisp\fR, because they
+required programs we don't have, or because I wasn't able to make
+them work. In these cases I left the command out. The commands
+listed in this document have been tried and are known to work.
+It is expected that prospective users of this document will read
+it once to get the flavor of everything that \fBvi\fR can do
+and then use it as a reference document. Experimentation is
+recommended. If you don't understand a command, try it and
+see what happens.
+.LP
+[Note: In revising this document, I have attempted to make it
+completely reflect version 2.12 of
+.B vi .
+It does not attempt to document the VAX version (version 3),
+but with one or two exceptions (wrapmargin, arrow keys)
+everything said about 2.12 should apply to 3.1.
+.I "Mark Horton" ]
+.NH 1
+Notation
+.LP
+\fB[option]\fR is used to denote optional parts of a command.
+Many \fBvi\fR commands have an optional count. \fB[cnt]\fR
+means that an optional number may precede the command to
+multiply or iterate the command.
+\fB{variable item}\fR is used to denote parts of the command
+which must appear, but can take a number of different values.
+\fB<character [-character]>\fR means that the character or
+one of the characters in the range described between the
+two angle brackets is to be typed.
+For example \fB<esc>\fR means
+the \fBescape\fR key is to be typed. \fB<a-z>\fR means that a
+lower case letter is to be typed. \fB^<character>\fR means that
+the character is to be typed as a \fBcontrol\fR character, that is,
+with the \fB<cntl>\fR key held down while simultaneously typing
+the specified character. In this document control characters will
+be denoted using the \fIupper case\fR character, but
+^<uppercase chr> and ^<lowercase chr> are equivalent. That is, for
+example, \fB<^D>\fR is equal to \fB<^d>\fR.
+The most common character abbreviations
+used in this list are as follows:
+.VL 8
+.IP <esc> 8
+escape, octal 033
+.IP <cr> 8
+carriage return, ^M, octal 015
+.IP <lf> 8
+linefeed ^J, octal 012
+.IP <nl> 8
+newline, ^J, octal 012 (same as linefeed)
+.IP <bs> 8
+backspace, ^H, octal 010
+.IP <tab> 8
+tab, ^I, octal 011
+.IP <bell> 8
+bell, ^G, octal 07
+.IP <ff> 8
+formfeed, ^L, octal 014
+.IP <sp> 8
+space, octal 040
+.IP <del> 8
+delete, octal 0177
+.LE
+.sp 1
+.NH 1
+Basics
+.LP
+To run \fBvi\fR the shell variable \fBTERM\fR must be defined and
+exported to your environment.
+How you do this depends on which shell you are using.
+You can tell which shell you have by the character it
+prompts you for commands with.
+The Bourne shell prompts with `$', and the C shell prompts with `%'.
+For these examples, we will suppose
+that you are using an HP 2621 terminal, whose termcap name is ``2621''.
+.NH 2
+Bourne Shell
+.LP
+To manually set your terminal type to 2621 you would type:
+.DS
+TERM=2621
+export TERM
+.DE
+.PP
+There are various ways of having this automatically or
+semi-automatically done when you log in.
+Suppose you usually dial in on a 2621.
+You want to tell this to the machine, but still have it
+work when you use a hardwired terminal.
+The recommended way, if you have the
+.B tset
+program, is to use the sequence
+.DS
+tset \-s \-d 2621 > tset$$
+\&. tset$$
+rm tset$$
+.DE
+in your .login (for csh) or the same thing using `.' instead of `source'
+in your .profile (for sh).
+The above line says that if you are dialing in you are on a 2621,
+but if you are on a hardwired terminal it figures out your terminal
+type from an on-line list.
+.NH 2
+The C Shell
+.LP
+To manually set your terminal type to 2621 you would type:
+.DS
+setenv TERM 2621
+.DE
+.PP
+There are various ways of having this automatically or
+semi-automatically done when you log in.
+Suppose you usually dial in on a 2621.
+You want to tell this to the machine, but still have it
+work when you use a hardwired terminal.
+The recommended way, if you have the
+.B tset
+program, is to use the sequence
+.DS
+tset \-s \-d 2621 > tset$$
+source tset$$
+rm tset$$
+.DE
+in your .login.*
+.FS
+* On a version 6 system
+without environments, the invocation of tset
+is simpler, just add the line ``tset \-d 2621''
+to your .login or .profile.
+.FE
+The above line says that if you are dialing in you are on a 2621,
+but if you are on a hardwired terminal it figures out your terminal
+type from an on-line list.
+.NH 1
+Normal Commands
+.LP
+\fBVi\fR is a visual editor with a window on the file. What
+you see on the screen is \fBvi\fR's current notion of
+what your file will contain,
+(at this point in the file),
+when it is written out.
+Most commands do not cause any change in the screen until the
+complete command is typed. Should you get confused while
+typing a command, you can abort the command by typing an
+<del> character. You will know you are back to command level
+when you hear a <bell>. Usually typing an <esc> will produce the
+same result. When \fBvi\fR gets an improperly formatted command
+it rings the <bell>.
+Following are the \fBvi\fR commands broken down by function.
+.NH 2
+Entry and Exit
+.LP
+To enter
+.B vi
+on a particular
+.I file ,
+type
+.DS
+\fBvi\fP \fIfile\fP
+.DE
+The file will be read in and the cursor will be placed at the beginning
+of the first line.
+The first screenfull of the file will be displayed on the terminal.
+.PP
+To get out of the editor, type
+.DS
+ZZ
+.DE
+If you are in some special mode, such as input mode
+or the middle of a multi-keystroke command, it may
+be necessary to type <esc> first.
+.NH 2
+Cursor and Page Motion
+.LP
+.VL 16
+.B NOTE:
+The arrow keys (see the next four commands)
+on certain kinds of terminals will not work with the
+PDP-11 version of vi. The control versions or the hjkl versions will
+work on any terminal. Experienced users prefer the hjkl keys because
+they are always right under their fingers. Beginners often prefer
+the arrow keys, since they do not require memorization of which hjkl
+key is which.
+The mnemonic value of hjkl is clear from looking at the keyboard of an adm3a.
+.sp
+.IP "[cnt]<bs> or [cnt]h or [cnt]\(<-" 16
+.br
+Move the cursor to the left one character. Cursor stops at the left
+margin of the page.
+If cnt is given, these commands move that many spaces.
+.IP "[cnt]^N or [cnt]j or [cnt]\(da or [cnt]<lf>" 16
+.br
+Move down one line.
+Moving off the screen scrolls the window to force a new line
+onto the screen.
+Mnemonic: \fBN\fRext
+.IP "[cnt]^P or [cnt]k or [cnt]\(ua" 16
+.br
+Move up one line.
+Moving off the top of the screen forces new text onto the screen.
+Mnemonic: \fBP\fRrevious
+.IP "[cnt]<sp> or [cnt]l or [cnt]\(->" 16
+.br
+Move to the right one character.
+Cursor will not go beyond the end of the line.
+.IP [cnt]- 16
+Move the cursor up the screen to the beginning of the next line.
+Scroll if necessary.
+.IP "[cnt]+ or [cnt]<cr>" 16
+.sp 1
+Move the cursor down the screen to the beginning of the next line.
+Scroll up if necessary.
+.IP "[cnt]$" 16
+Move the cursor to the end of the line.
+If there is a count, move to the end of the line "cnt" lines
+forward in the file.
+.IP "^" 16
+Move the cursor to the beginning of the first word on the line.
+.IP "0" 16
+Move the cursor to the left margin of the current line.
+.IP "[cnt]|" 16
+Move the cursor to the column specified by the count. The default is
+column zero.
+.IP "[cnt]w" 16
+Move the cursor to the beginning of the next word. If there
+is a count, then move forward that many words and
+position the cursor at the beginning of the word.
+Mnemonic: next-\fBw\fRord
+.IP "[cnt]W" 16
+Move the cursor to the beginning of the next word which follows
+a "white space" (<sp>,<tab>, or <nl>). Ignore other punctuation.
+.IP "[cnt]b" 16
+Move the cursor to the preceding word. Mnemonic: \fBb\fRackup-word
+.IP "[cnt]B" 16
+Move the cursor to the preceding word that is separated from the
+current word by a "white space" (<sp>,<tab>, or <nl>).
+.IP "[cnt]e" 16
+Move the cursor to the end of the current word or the end of the
+"cnt"'th word hence. Mnemonic: \fBe\fRnd-of-word
+.IP "[cnt]E" 16
+Move the cursor to the end of the current word which is delimited by
+"white space" (<sp>,<tab>, or <nl>).
+.IP "[line number]G" 16
+.br
+Move the cursor to the line specified. Of particular use are the
+sequences "1G" and "G", which move the cursor to the beginning and
+the end of the file respectively. Mnemonic: \fBG\fRo-to
+.LP
+.B NOTE:
+The next four commands (^D, ^U, ^F, ^B)
+are not true motion commands, in that they
+cannot be used as the object of commands such as delete or change.
+.IP "[cnt]^D" 16
+Move the cursor down in the file by "cnt" lines (or the last "cnt"
+if a new count isn't given. The initial default is half a page.) The
+screen is simultaneously scrolled up. Mnemonic: \fBD\fRown
+.IP "[cnt]^U" 16
+Move the cursor up in the file by "cnt" lines. The screen is simultaneously
+scrolled down. Mnemonic: \fBU\fRp
+.IP "[cnt]^F" 16
+Move the cursor to the next page. A count moves that many pages.
+Two lines of the previous page are kept on the screen for continuity if
+possible. Mnemonic: \fBF\fRorward-a-page
+.IP "[cnt]^B" 16
+Move the cursor to the previous page. Two lines of the current page
+are kept if possible. Mnemonic: \fBB\fRackup-a-page
+.IP "[cnt](" 16
+Move the cursor to the beginning of the next sentence.
+A sentence is defined as ending with a ".", "!", or "?"
+followed by two spaces or a <nl>.
+.IP "[cnt])" 16
+Move the cursor backwards to the beginning of a sentence.
+.IP "[cnt]}" 16
+Move the cursor to the beginning of the next paragraph. This command
+works best inside \fBnroff\fR documents. It understands two sets of
+\fBnroff\fR macros, \fB\-ms\fR and \fB\-mm\fR, for which the
+commands ".IP", ".LP", ".PP", ".QP", "P", as well as the nroff command ".bp"
+are considered to be paragraph delimiters.
+A blank line also delimits a paragraph.
+The \fBnroff\fR macros that it accepts as paragraph delimiters is
+adjustable. See \fBparagraphs\fR under the \fBSet Commands\fR section.
+.IP "[cnt]{" 16
+Move the cursor backwards to the beginning of a paragraph.
+.IP "]]" 16
+Move the cursor to the next "section", where a section is defined by
+two sets of \fBnroff\fR macros, \fB\-ms\fR and \fB\-mm\fR, in which
+".NH", ".SH", and ".H" delimit a section. A line beginning with a <ff><nl>
+sequence, or a line beginning with a "{" are also considered to
+be section delimiters. The last option makes it
+useful for finding the beginnings of C functions.
+The \fBnroff\fR macros that are used for section delimiters can be adjusted.
+See \fBsections\fR under the \fBSet Commands\fR section.
+.IP "[[" 16
+Move the cursor backwards to the beginning of a section.
+.IP "%" 16
+Move the cursor to the matching parenthesis
+or brace. This is very useful in C or lisp code. If the
+cursor is sitting on a \fB( ) {\fR or \fB}\fR the cursor
+is moved to the matching character at the other end of the
+section. If the cursor is not sitting on a brace or a
+parenthesis, \fBvi\fR searches forward until it finds one
+and then jumps to the match mate.
+.IP "[cnt]H" 16
+If there is no count move the cursor to the top left position on the screen.
+If there is a count, then move the cursor to the beginning of the line
+"cnt" lines from the top of the screen. Mnemonic: \fBH\fRome
+.IP "[cnt]L" 16
+If there is no count move the cursor to the beginning
+of the last line on the screen.
+If there is a count, then move the cursor to the beginning of the line
+"cnt" lines from the bottom of the screen. Mnemonic: \fBL\fRast
+.IP "M" 16
+Move the cursor to the beginning of the middle line on the screen.
+Mnemonic: \fBM\fRiddle
+.IP "m<a-z>" 16
+This command does not move the cursor, but it \fBmarks\fR the place
+in the file and the character "<a-z>" becomes the label for referring
+to this location in the file. See the next two commands. Mnemonic:
+\fBm\fRark
+.B NOTE:
+The mark command is not a motion, and cannot be used as the target
+of commands such as delete.
+.IP "\(aa<a-z>" 16
+Move the cursor to the beginning of the line that is marked with the label
+"<a-z>".
+.IP "\(ga<a-z>" 16
+Move the cursor to the exact position on the line that was marked with
+with the label "<a-z>".
+.IP "\(aa\(aa" 16
+Move the cursor back to the beginning of the line where it was before the
+last "non-relative" move. A "non-relative" move is something such as a
+search or a jump to a specific line in the file, rather than moving the
+cursor or scrolling the screen.
+.IP "\(ga\(ga" 16
+Move the cursor back to the exact spot on the line where it was located
+before the last "non-relative" move.
+.LE
+.NH 2
+Searches
+.LP
+The following commands allow you to search for items in a file.
+.VL 16
+.IP [cnt]f{chr} 16
+.sp 1
+Search forward on the line for the next or "cnt"'th occurrence of
+the character "chr". The cursor is placed \fBat\fR the character
+of interest. Mnemonic: \fBf\fRind character
+.IP [cnt]F{chr} 16
+.sp 1
+Search backwards on the line for the next or "cnt"'th occurrence of
+the character "chr". The cursor is placed \fBat\fR the character
+of interest.
+.IP [cnt]t{chr} 16
+.sp 1
+Search forward on the line for the next or "cnt"'th occurrence of
+the character "chr". The cursor is placed \fBjust preceding\fR
+the character of interest. Mnemonic: move cursor up \fBt\fRo character
+.IP [cnt]T{chr} 16
+.sp 1
+Search backwards on the line for the next or "cnt"'th occurrence of
+the character "chr". The cursor is placed \fBjust preceding\fR
+the character of interest.
+.IP "[cnt];" 16
+Repeat the last "f", "F", "t" or "T" command.
+.IP "[cnt]," 16
+Repeat the last "f", "F", "t" or "T" command, but in the opposite
+search direction. This is useful if you overshoot.
+.IP "[cnt]/[string]/<nl>" 16
+.br
+Search forward for the next occurrence of "string".
+Wrap around at the end of the file
+does occur.
+The final \fB</>\fR is not required.
+.IP "[cnt]?[string]?<nl>" 16
+.br
+Search backwards for the next occurrence of "string". If a count is
+specified, the count becomes the new window size. Wrap around at the beginning
+of the file does occur.
+The final \fB<?>\fR is not required.
+.IP n 16
+Repeat the last /[string]/ or ?[string]? search. Mnemonic: \fBn\fRext
+occurrence.
+.IP N 16
+Repeat the last /[string]/ or ?[string]? search, but in the reverse
+direction.
+.IP ":g/[string]/[editor command]<nl>" 16
+.sp 1
+Using the \fB:\fR syntax it is possible to do global searches ala the
+standard UNIX "ed" editor.
+.LE
+.NH 2
+Text Insertion
+.LP
+The following commands allow for the insertion of text. All multicharacter
+text insertions are terminated with an <esc> character.
+The last change
+can always be \fBundone\fR by typing a \fBu\fR.
+The text insert in insertion mode can contain newlines.
+.VL 16
+.IP a{text}<esc> 16
+Insert text immediately following the cursor position.
+Mnemonic: \fBa\fRppend
+.IP A{text}<esc> 16
+Insert text at the end of the current line.
+Mnemonic: \fBA\fRppend
+.IP i{text}<esc> 16
+Insert text immediately preceding the cursor position.
+Mnemonic: \fBi\fRnsert
+.IP I{text}<esc> 16
+Insert text at the beginning of the current line.
+.IP o{text}<esc> 16
+Insert a new line after the line on which the cursor appears and
+insert text there. Mnemonic: \fBo\fRpen new line
+.IP O{text}<esc> 16
+Insert a new line preceding the line on which the cursor appears
+and insert text there.
+.LE
+.NH 2
+Text Deletion
+.LP
+The following commands allow the user to delete text in various ways.
+All changes can always be \fBundone\fR by typing the \fBu\fR command.
+.VL 16
+.IP "[cnt]x" 16
+Delete the character or characters starting at the cursor position.
+.IP "[cnt]X" 16
+Delete the character or characters starting at the character preceding
+the cursor position.
+.IP "D" 16
+Deletes the remainder of the line starting at the cursor.
+Mnemonic: \fBD\fRelete the rest of line
+.IP "[cnt]d{motion}" 16
+.br
+Deletes one or more occurrences of the specified motion.
+Any motion from sections 4.1 and 4.2 can be used here.
+The d can be stuttered (e.g. [cnt]dd) to delete cnt lines.
+.LE
+.NH 2
+Text Replacement
+.LP
+The following commands allow the user to simultaneously delete and
+insert new text. All such actions can be \fBundone\fR by typing
+\fBu\fR following the command.
+.VL 16
+.IP "r<chr>" 16
+Replaces the character at the current cursor position with <chr>. This
+is a one character replacement. No <esc> is required for termination.
+Mnemonic: \fBr\fReplace character
+.IP "R{text}<esc>" 16
+Starts overlaying the characters on the screen with whatever you type.
+It does not stop until an <esc> is typed.
+.IP "[cnt]s{text}<esc>" 16
+Substitute for "cnt" characters beginning at the current cursor
+position. A "$" will appear at the position in the text where the
+"cnt"'th character appears so you will know how much you are erasing.
+Mnemonic: \fBs\fRubstitute
+.IP "[cnt]S{text}<esc>" 16
+Substitute for the entire current line (or lines). If no count is given,
+a "$" appears at the end of the current line. If a count of more than
+1 is given, all the lines to be replaced are deleted before the insertion
+begins.
+.IP "[cnt]c{motion}{text}<esc>" 16
+.br
+Change the specified "motion" by replacing it with the
+insertion text. A "$" will appear at the end of the last item
+that is being deleted unless the deletion involves whole lines.
+Motion's can be any motion from sections 4.1 or 4.2.
+Stuttering the c (e.g. [cnt]cc) changes cnt lines.
+.LE
+.NH 2
+Moving Text
+.LP
+\fBVi\fR provides a number of ways of moving chunks of text around.
+There are nine buffers into which each piece of text which is deleted
+or "yanked" is put in addition to the "undo" buffer.
+The most recent deletion or yank is in the "undo" buffer and also
+usually in buffer
+1, the next most recent in buffer 2, and so forth. Each new deletion
+pushes down all the older deletions. Deletions older than 9
+disappear. There is also
+a set of named registers, a-z, into which text can optionally
+be placed. If any delete or replacement type command is preceded
+by \fB"<a-z>\fR, that named buffer will contain the text deleted
+after the command is executed. For example, \fB"a3dd\fR will delete
+three lines starting at the current line and put them in buffer \fB"a\fR.*
+.FS
+* Referring to an upper case letter as a buffer name (A-Z) is the
+same as referring to the lower case letter, except that text placed
+in such a buffer is appended to it instead of replacing it.
+.FE
+There are two more basic commands and
+some variations useful in getting and putting text into a file.
+.VL 16
+.IP ["<a-z>][cnt]y{motion} 16
+.sp 1
+Yank the specified item or "cnt" items and put in the "undo" buffer or
+the specified buffer. The variety of "items" that can be yanked
+is the same as those that can be deleted with the "d" command or
+changed with the "c" command. In the same way that "dd" means
+delete the current line and "cc" means replace the current line,
+"yy" means yank the current line.
+.IP ["<a-z>][cnt]Y 16
+Yank the current line or the "cnt" lines starting from the current
+line. If no buffer is specified, they will go into the "undo" buffer,
+like any delete would. It is equivalent to "yy".
+Mnemonic: \fBY\fRank
+.IP ["<a-z>]p 16
+Put "undo" buffer or the specified buffer down \fBafter\fR the cursor.
+If whole lines were yanked or deleted into the buffer, then they will be
+put down on the line following the line the cursor is on. If
+something else was deleted, like a word or sentence, then it will
+be inserted immediately following the cursor.
+Mnemonic: \fBp\fRut buffer
+.IP
+It should be noted that text in the named buffers remains there when you
+start editing a new file with the \fB:e file<esc>\fR command. Since
+this is so, it is possible to copy or delete text from one file and
+carry it over to another file in the buffers.
+However, the undo buffer and the ability to undo are lost when
+changing files.
+.IP ["<a-z>]P 16
+Put "undo" buffer or the specified buffer down \fBbefore\fR the cursor.
+If whole lines where yanked or deleted into the buffer, then they will be
+put down on the line preceding the line the cursor is on. If
+something else was deleted, like a word or sentence, then it will
+be inserted immediately preceding the cursor.
+.IP [cnt]>{motion} 16
+The shift operator will right shift all the text from the line on which
+the cursor is located to the line where the \fBmotion\fR is located.
+The text is shifted by one \fBshiftwidth\fR. (See section 6.)
+\fB>>\fR means right shift the current line or lines.
+.IP [cnt]<{motion} 16
+The shift operator will left shift all the text from the line on which
+the cursor is located to the line where the \fBitem\fR is located.
+The text is shifted by one \fBshiftwidth\fR. (See section 6.)
+\fB<<\fR means left shift the current line or lines.
+Once the line has reached the left margin it is not further affected.
+.IP [cnt]={motion} 16
+Prettyprints the indicated area according to
+.B lisp
+conventions.
+The area should be a lisp s-expression.
+.LE
+.NH 2
+Miscellaneous Commands
+.LP
+\fBVi\fR has a number of miscellaneous commands that are very
+useful. They are:
+.VL 16
+.IP ZZ 16
+This is the normal way to exit from vi.
+If any changes have been made, the file is written out.
+Then you are returned to the shell.
+.IP ^L 16
+Redraw the current screen. This is useful if someone "write"s you
+while you are in "vi" or if for any reason garbage gets onto the
+screen.
+.IP ^R 16
+On dumb terminals, those not having the "delete line" function
+(the vt100 is such a terminal), \fBvi\fR saves redrawing the
+screen when you delete a line by just marking the line with an
+"@" at the beginning and blanking the line. If you want to
+actually get rid of the lines marked with "@" and see what the
+page looks like, typing a ^R will do this.
+.IP \s+4.\s0 16
+"Dot" is a particularly useful command. It repeats the last
+text modifying command. Therefore you can type a command once and
+then to another place and repeat it by just typing ".".
+.IP u 16
+Perhaps the most important command in the editor,
+u undoes the last command that changed the buffer.
+Mnemonic: \fBu\fRndo
+.IP U 16
+Undo all the text modifying commands performed on the current line
+since the last time you moved onto it.
+.IP [cnt]J 16
+Join the current line and the following line. The <nl> is deleted
+and the two lines joined, usually with a space between the
+end of the first line and the beginning of what was the second
+line. If the first line ended with a "period", then two spaces
+are inserted.
+A count joins the next cnt lines.
+Mnemonic: \fBJ\fRoin lines
+.IP Q 16
+Switch to \fBex\fR editing mode.
+In this mode \fBvi\fR will behave very much like \fBed\fR.
+The editor in this mode will operate on single lines normally and
+will not attempt to keep the "window" up to date.
+Once in this mode it is also possible to switch to the \fBopen\fR
+mode of editing. By entering the command \fB[line number]open<nl>\fR
+you enter this mode. It is similar to the normal visual mode
+except the window is only \fBone\fR line long.
+Mnemonic: \fBQ\fRuit visual mode
+.IP ^] 16
+An abbreviation for a tag command.
+The cursor should be positioned at the beginning of a word.
+That word is taken as a tag name, and the tag with that
+name is found as if it had been typed in a :tag command.
+.IP [cnt]!{motion}{UNIX\ cmd}<nl> 16
+.br
+Any UNIX filter
+(e.g. command that reads the standard input and outputs something
+to the standard output) can be sent a section of the current file and
+have the output of the command replace the original text. Useful
+examples are programs like \fBcb\fR, \fBsort\fR, and
+\fBnroff\fR. For instance, using \fBsort\fR it would be possible to
+sort a section of the current file into a new list.
+Using \fB!!\fR means take a line or lines starting at the line the
+cursor is currently on and pass them to the UNIX command.
+.B NOTE:
+To just escape to the shell for one command,
+use :!{cmd}<nl>, see section 5.
+.IP z{cnt}<nl> 16
+This resets the current window size to "cnt" lines and redraws the screen.
+.LE
+.NH 2
+Special Insert Characters
+.LP
+There are some characters that have special meanings during
+insert modes. They are:
+.VL 16
+.IP ^V 16
+During inserts, typing a ^V allows you to quote control characters
+into the file. Any character typed after the ^V will be inserted
+into the file.
+.IP [^]^D\ or\ [0]^D 16
+<^D> without any argument backs up one \fBshiftwidth\fR. This is necessary
+to remove indentation that was inserted by the \fBautoindent\fR feature.
+^<^D> temporarily removes all the autoindentation, thus placing the cursor
+at the left margin. On the next line, the previous indent level will be
+restored. This is useful for putting "labels" at the left margin.
+0<^D> says remove all autoindents and stay that way. Thus the cursor
+moves to the left margin and stays there on successive lines until
+<tab>'s are typed. As with the <tab>, the <^D> is only effective before
+any other "non-autoindent" controlling characters are typed.
+Mnemonic: \fBD\fRelete a shiftwidth
+.IP ^W 16
+If the cursor is sitting on a word, <^W> moves the cursor back to the beginning
+of the word, thus erasing the word from the insert.
+Mnemonic: erase \fBW\fRord
+.IP <bs> 16
+The backspace always serves as an erase during insert modes in addition
+to your normal "erase" character. To insert a <bs> into your file, use
+the <^V> to quote it.
+.LE
+.NH 1
+\fB:\fR Commands
+.LP
+Typing a ":" during command mode causes \fBvi\fR to put the cursor at
+the bottom on the screen in preparation for a command. In the
+":" mode, \fBvi\fR can be given most \fBed\fR commands. It is
+also from this mode that you exit from \fBvi\fR or switch to different
+files. All commands of this variety are terminated by a <nl>, <cr>,
+or <esc>.
+.VL 16
+.IP ":w[!] [file]" 16
+Causes \fBvi\fR to write out the current text to the disk. It is
+written to the file you are editing unless "file" is supplied. If
+"file" is supplied, the write is directed to that file instead. If
+that file already exists, \fBvi\fR will not perform the write unless
+the "!" is supplied indicating you
+.I really
+want to destroy the older copy of the file.
+.IP :q[!] 16
+Causes \fBvi\fR to exit. If you have modified the file you are
+looking at currently and haven't written it out, \fBvi\fR will
+refuse to exit unless the "!" is supplied.
+.IP ":e[!] [+[cmd]] [file]" 16
+.sp 1
+Start editing a new file called "file" or start editing the current
+file over again. The command ":e!" says "ignore the changes I've made
+to this file and start over from the beginning". It is useful if
+you really mess up the file. The optional "+" says instead of starting
+at the beginning, start at the "end", or,
+if "cmd" is supplied, execute "cmd" first.
+Useful cases of this are where cmd is "n" (any integer) which starts
+at line number n,
+and "/text", which searches for "text" and starts at the line where
+it is found.
+.IP "^^" 16
+Switch back to the place you were before your last tag command.
+If your last tag command stayed within the file, ^^ returns to that tag.
+If you have no recent tag command, it will return to the
+same place in the previous file that it was showing when you switched
+to the current file.
+.IP ":n[!]" 16
+Start editing the next file in the argument list. Since \fBvi\fR
+can be called with multiple file names, the ":n" command tells it to
+stop work on the current file and switch to the next file. If the
+current file was modifies, it has to be written out before the ":n"
+will work or else the "!" must be supplied, which says discard the
+changes I made to the current file.
+.IP ":n[!] file [file file ...]" 16
+.sp
+Replace the current argument list with a new list of files and start
+editing the first file in this new list.
+.IP ":r file" 16
+Read in a copy of "file" on the line after the cursor.
+.IP ":r !cmd" 16
+Execute the "cmd" and take its output and put it into the file after
+the current line.
+.IP ":!cmd" 16
+Execute any UNIX shell command.
+.IP ":ta[!] tag" 16
+.B Vi
+looks in the file named
+.B tags
+in the current directory.
+.B Tags
+is a file of lines in the format:
+.sp 1
+.ti +8
+tag filename \fBvi\fR-search-command
+.sp 1
+If \fBvi\fR finds the tag you specified in the \fB:ta\fR command,
+it stops editing the current file if necessary and if the current file is
+up to date on the disk and switches to the file specified and uses the
+search pattern specified to find the "tagged" item of interest. This
+is particularly useful when editing multi-file C programs such as the
+operating system. There is a program called \fBctags\fR which will
+generate an appropriate \fBtags\fR file for C and f77
+programs so that by saying
+\fB:ta function<nl>\fR you will be switched to that function.
+It could also be useful when editing multi-file documents, though the
+\fBtags\fR file would have to be generated manually.
+.LE
+.NH 1
+Special Arrangements for Startup
+.PP
+\fBVi\fR takes the value of \fB$TERM\fR and looks up the characteristics
+of that terminal in the file \fB/etc/termcap\fR.
+If you don't know \fBvi\fR's name for the terminal you are working
+on, look in \fB/etc/termcap\fR.
+.PP
+When \fBvi\fR starts, it attempts to read the variable EXINIT
+from your environment.*
+If that exists, it takes the values in it as the default values
+for certain of its internal constants. See the section on "Set Values"
+for further details.
+If EXINIT doesn't exist you will get all the normal defaults.
+.FS
+* On version 6 systems
+Instead of EXINIT, put the startup commands in the file .exrc
+in your home directory.
+.FE
+.PP
+Should you inadvertently hang up the phone while inside
+.B vi ,
+or should the computer crash,
+all may not be lost.
+Upon returning to the system, type:
+.DS
+vi \-r file
+.DE
+This will normally recover the file. If there is more than one
+temporary file for a specific file name, \fBvi\fR recovers the
+newest one. You can get an older version by recovering the
+file more than once.
+The command "vi -r" without a file name gives you the list of files
+that were saved in the last system crash
+(but
+.I not
+the file just saved when the phone was hung up).
+.NH 1
+Set Commands
+.LP
+\fBVi\fR has a number of internal variables and switches which can be
+set to achieve special affects.
+These options come in three forms, those that are switches, which toggle
+from off to on and back, those that require a numeric value, and those
+that require an alphanumeric string value.
+The toggle options are set by a command of the form:
+.DS
+:set option<nl>
+.DE
+and turned off with the command:
+.DS
+:set nooption<nl>
+.DE
+Commands requiring a value are set with a command of the form:
+.DS
+:set option=value<nl>
+.DE
+To display the value of a specific option type:
+.DS
+:set option?<nl>
+.DE
+To display only those that you have changed type:
+.DS
+:set<nl>
+.DE
+and to display the long table of all the settable parameters and
+their current values type:
+.DS
+:set all<nl>
+.DE
+.PP
+Most of the options have a long form and an abbreviation. Both are
+listed in the following table as well as the normal default value.
+.PP
+To arrange to have values other than the default used every time you
+enter
+.B vi ,
+place the appropriate
+.B set
+command in EXINIT in your environment, e.g.
+.DS
+EXINIT='set ai aw terse sh=/bin/csh'
+export EXINIT
+.DE
+or
+.DS
+setenv EXINIT 'set ai aw terse sh=/bin/csh'
+.DE
+for
+.B sh
+and
+.B csh ,
+respectively.
+These are usually placed in your .profile or .login.
+If you are running a system without environments (such as version 6)
+you can place the set command in the file .exrc in your home
+directory.
+.VL 16
+.IP autoindent\ ai 16
+Default: noai Type: toggle
+.br
+When in autoindent mode, vi helps you indent code by starting each
+line in the same column as the preceding line.
+Tabbing to the right with <tab> or <^T> will move this boundary to
+the right, and it can be moved to the left with <^D>.
+.IP autoprint\ ap 16
+Default: ap Type: toggle
+.br
+Causes the current line to be printed after each ex text modifying command.
+This is not of much interest in the normal \fBvi\fR visual mode.
+.IP autowrite\ aw 16
+Default: noaw type: toggle
+.br
+Autowrite causes an automatic write to be done if there are unsaved
+changes before certain commands which change files or otherwise
+interact with the outside world.
+These commands are :!, :tag, :next, :rewind, ^^, and ^].
+.IP beautify\ bf 16
+Default: nobf Type: toggle
+.br
+Causes all control characters except <tab>, <nl>, and <ff> to be discarded.
+.IP directory\ dir 16
+Default: dir=/tmp Type: string
+.br
+This is the directory in which \fBvi\fR puts its temporary file.
+.IP errorbells\ eb 16
+Default: noeb Type: toggle
+.br
+Error messages are preceded by a <bell>.
+.IP hardtabs\ ht 16
+Default: hardtabs=8 Type: numeric
+.br
+This option contains the value of hardware tabs in your terminal, or
+of software tabs expanded by the Unix system.
+.IP ignorecase\ ic 16
+Default: noic Type: toggle
+.br
+All upper case characters are mapped to lower case in regular expression
+matching.
+.IP lisp 16
+Default: nolisp Type: toggle
+.br
+Autoindent for \fBlisp\fR code. The commands \fB( ) [[\fR and \fB]]\fR
+are modified appropriately to affect s-expressions and functions.
+.IP list 16
+Default: nolist Type: toggle
+.br
+All printed lines have the <tab> and <nl> characters displayed visually.
+.IP magic 16
+Default: magic Type: toggle
+.br
+Enable the metacharacters for matching. These include \fB. * < > [string]
+[^string]\fR and \fB[<chr>-<chr>]\fR.
+.IP number\ nu 16
+Default: nonu Type: toggle
+.br
+Each line is displayed with its line number.
+.IP open 16
+Default: open Type: toggle
+.br
+When set, prevents entering open or visual modes from ex or edit.
+Not of interest from vi.
+.IP optimize\ opt 16
+Default: opt Type: toggle
+.br
+Basically of use only when using the \fBex\fR capabilities. This
+option prevents automatic <cr>s from taking place,
+and speeds up output of indented lines,
+at the expense of losing typeahead on some versions of UNIX.
+.IP paragraphs\ para 16
+Default: para=IPLPPPQPP\ bp Type: string
+.br
+Each pair of characters in the string indicate \fBnroff\fR macros
+which are to be treated as the beginning of a paragraph for the
+\fB{\fR and \fB}\fR commands. The default string is for the \fB-ms\fR
+and \fB-mm\fR macros.
+To indicate one letter \fBnroff\fR macros, such as \fB.P\fR or \fB.H\fR,
+quote a space in for the second character position. For example:
+.sp 1
+.ti +8
+:set paragraphs=P\e bp<nl>
+.sp 1
+would cause \fBvi\fR to consider \fB.P\fR and \fB.bp\fR as paragraph
+delimiters.
+.IP prompt 16
+Default: prompt Type: toggle
+.br
+In
+.B ex
+command mode the prompt character \fB:\fR will be printed when
+\fBex\fR is waiting for a command. This is not of interest from vi.
+.IP redraw 16
+Default: noredraw Type: toggle
+.br
+On dumb terminals, force the screen to always be up to date,
+by sending great amounts of output. Useful only at high speeds.
+.IP report 16
+Default: report=5 Type: numeric
+.br
+This sets the threshold for the number of lines modified. When
+more than this number of lines are modified, removed, or yanked,
+\fBvi\fR will report the number of lines changed at the bottom of
+the screen.
+.IP scroll 16
+Default: scroll={1/2 window} Type: numeric
+.br
+This is the number of lines that the screen scrolls up or down when
+using the <^U> and <^D> commands.
+.IP sections 16
+Default: sections=SHNHH HU Type: string
+.br
+Each two character pair of this string specify \fBnroff\fR macro names
+which are to be treated as the beginning of a section by the
+\fB]]\fR and \fB[[\fR commands. The default string is for the \fB-ms\fR
+and \fB-mm\fR macros.
+To enter one letter \fBnroff\fR macros, use a quoted space as the
+second character.
+See \fBparagraphs\fR for a fuller explanation.
+.IP shell\ sh 16
+Default: sh=from environment SHELL or /bin/sh Type: string
+.br
+This is the name of the \fBsh\fR to be used for "escaped" commands.
+.IP shiftwidth\ sw 16
+Default: sw=8 Type: numeric
+.br
+This is the number of spaces that a <^T> or <^D> will move over for
+indenting, and the amount < and > shift by.
+.IP showmatch\ sm 16
+Default: nosm Type: toggle
+.br
+When a \fB)\fR or \fB}\fR is typed, show the matching \fB(\fR or \fB{\fR
+by moving the cursor to it for one second if it is on the current screen.
+.IP slowopen\ slow 16
+Default: terminal dependent Type: toggle
+.br
+On terminals that are slow and unintelligent, this option prevents the
+updating of the screen some of the time to improve speed.
+.IP tabstop\ ts 16
+Default: ts=8 Type: numeric
+.br
+<tab>s are expanded to boundaries that are multiples of this value.
+.IP taglength\ tl 16
+Default: tl=0 Type: numeric
+.br
+If nonzero, tag names are only significant to this many characters.
+.IP term 16
+Default: (from environment \fBTERM\fP, else dumb) Type: string
+.br
+This is the terminal and controls the visual displays. It cannot be
+changed when in "visual" mode,
+you have to Q to command mode, type a
+set term command, and do ``vi.'' to get back into visual.
+Or exit vi, fix $TERM, and reenter.
+The definitions that drive a particular
+terminal type are found in the file \fB/etc/termcap\fR.
+.IP terse 16
+Default: terse Type: toggle
+.br
+When set, the error diagnostics are short.
+.IP warn 16
+Default: warn Type: toggle
+.br
+The user is warned if she/he tries to escape to
+the shell without writing out the current changes.
+.IP window 16
+Default: window={8 at 600 baud or less, 16 at 1200 baud, and screen
+size \- 1 at 2400 baud or more} Type: numeric
+.br
+This is the number of lines in the window whenever \fBvi\fR must redraw
+an entire screen. It is useful to make this size smaller if you are
+on a slow line.
+.IP w300,\ w1200,\ w9600
+.br
+These set window, but only within the corresponding speed ranges.
+They are useful in an EXINIT to fine tune window sizes.
+For example,
+.DS
+set w300=4 w1200=12
+.DE
+causes a 4 lines window at speed up to 600 baud, a 12 line window at 1200
+baud, and a full screen (the default) at over 1200 baud.
+.IP wrapscan\ ws 16
+Default: ws Type: toggle
+.br
+Searches will wrap around the end of the file when is option is set. When
+it is off, the search will terminate when it reaches the end or the
+beginning of the file.
+.IP wrapmargin\ wm 16
+Default: wm=0 Type: numeric
+.br
+\fBVi\fR will automatically insert a <nl> when it finds a natural
+break point (usually a <sp> between words) that occurs within
+"wm" spaces of the right margin.
+Therefore with "wm=0" the option is off. Setting it to 10 would
+mean that any time you are within 10 spaces of the right margin
+\fBvi\fR would be looking for a <sp> or <tab> which it could
+replace with a <nl>. This is convenient for people who forget
+to look at the screen while they type.
+(In version 3, wrapmargin behaves more like nroff, in that the
+boundary specified by the distance from the right edge of the screen
+is taken as the rightmost edge of the area where a break is allowed,
+instead of the leftmost edge.)
+.IP writeany\ wa 16
+Default: nowa Type: toggle
+.br
+\fBVi\fR normally makes a number of checks before it writes out a file.
+This prevents the user from inadvertently destroying a file. When the
+"writeany" option is enabled, \fBvi\fR no longer makes these checks.
+.LE
diff --git a/usr.bin/vi/docs/USD.doc/vi/vi.chars b/usr.bin/vi/docs/USD.doc/vi/vi.chars
new file mode 100644
index 000000000000..147c4ff7f2d8
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/vi.chars
@@ -0,0 +1,644 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)vi.chars 8.1 (Berkeley) 6/8/93
+.\"
+.bd S 3
+..pn 21
+.de iP
+.IP "\fB\\$1\fR" \\$2
+..
+.SH
+Appendix: character functions
+.PP
+This appendix gives the uses the editor makes of each character. The
+characters are presented in their order in the \s-2ASCII\s0 character
+set: Control characters come first, then most special characters, then
+the digits, upper and then lower case characters.
+.PP
+For each character we tell a meaning it has as a command and any meaning it
+has during an insert.
+If it has only meaning as a command, then only this is discussed.
+Section numbers in parentheses indicate where the character is discussed;
+a `f' after the section number means that the character is mentioned
+in a footnote.
+.iP "^@" 15
+Not a command character.
+If typed as the first character of an insertion it is replaced with the
+last text inserted, and the insert terminates. Only 128 characters are
+saved from the last insert; if more characters were inserted the mechanism
+is not available.
+A \fB^@\fR cannot be part of the file due to the editor implementation
+(7.5f).
+.iP "^A" 15
+Unused.
+.iP "^B" 15
+Backward window.
+A count specifies repetition.
+Two lines of continuity are kept if possible (2.1, 6.1, 7.2).
+.iP "^C" 15
+Unused.
+.iP "^D" 15
+As a command, scrolls down a half-window of text.
+A count gives the number of (logical) lines to scroll, and is remembered
+for future \fB^D\fR and \fB^U\fR commands (2.1, 7.2).
+During an insert, backtabs over \fIautoindent\fR white space at the beginning
+of a line (6.6, 7.5); this white space cannot be backspaced over.
+.iP "^E" 15
+Exposes one more line below the current screen in the file, leaving
+the cursor where it is if possible.
+(Version 3 only.)
+.iP "^F" 15
+Forward window. A count specifies repetition.
+Two lines of continuity are kept if possible (2.1, 6.1, 7.2).
+.iP "^G" 15
+Equivalent to \fB:f\fR\s-2CR\s0, printing the current file, whether
+it has been modified, the current line number and the number of lines
+in the file, and the percentage of the way through the file that you
+are.
+.iP "^H (\fR\s-2BS\s0\fP)" 15
+Same as
+.B "left arrow" .
+(See
+.B h ).
+During an insert, eliminates the last input character, backing over it
+but not erasing it; it remains so you can see what you typed if you
+wish to type something only slightly different (3.1, 7.5).
+.iP "^I\ (\fR\s-2TAB\s0\fP)" 15
+Not a command character.
+When inserted it prints as some
+number of spaces.
+When the cursor is at a tab character it rests at the last of the spaces
+which represent the tab.
+The spacing of tabstops is controlled by the \fItabstop\fR option (4.1, 6.6).
+.iP "^J\ (\fR\s-2LF\s0\fP)" 15
+Same as
+.B "down arrow"
+(see
+.B j ).
+.iP "^K" 15
+Unused.
+.iP "^L" 15
+The \s-2ASCII\s0 formfeed character, this causes the screen to be cleared
+and redrawn. This is useful after a transmission error, if characters
+typed by a program other than the editor scramble the screen,
+or after output is stopped by an interrupt (5.4, 7.2f).
+.iP "^M\ (\fR\s-2CR\s0\fP)" 15
+A carriage return advances to the next line, at the first non-white position
+in the line. Given a count, it advances that many lines (2.3).
+During an insert, a \s-2CR\s0 causes the insert to continue onto
+another line (3.1).
+.iP "^N" 15
+Same as
+.B "down arrow"
+(see
+.B j ).
+.iP "^O" 15
+Unused.
+.iP "^P" 15
+Same as
+.B "up arrow"
+(see
+.B k ).
+.iP "^Q" 15
+Not a command character.
+In input mode,
+.B ^Q
+quotes the next character, the same as
+.B ^V ,
+except that some teletype drivers will eat the
+.B ^Q
+so that the editor never sees it.
+.iP "^R" 15
+Redraws the current screen, eliminating logical lines not corresponding
+to physical lines (lines with only a single @ character on them).
+On hardcopy terminals in \fIopen\fR mode, retypes the current line
+(5.4, 7.2, 7.8).
+.iP "^S" 15
+Unused. Some teletype drivers use
+.B ^S
+to suspend output until
+.B ^Q is pressed.
+.iP "^T" 15
+Not a command character.
+During an insert, with \fIautoindent\fR set and at the beginning of the
+line, inserts \fIshiftwidth\fR white space.
+.iP "^U" 15
+Scrolls the screen up, inverting \fB^D\fR which scrolls down. Counts work as
+they do for \fB^D\fR, and the previous scroll amount is common to both.
+On a dumb terminal, \fB^U\fR will often necessitate clearing and redrawing
+the screen further back in the file (2.1, 7.2).
+.iP "^V" 15
+Not a command character.
+In input mode, quotes the next character so that it is possible
+to insert non-printing and special characters into the file (4.2, 7.5).
+.iP "^W" 15
+Not a command character.
+During an insert, backs up as \fBb\fR would in command mode; the deleted
+characters remain on the display (see \fB^H\fR) (7.5).
+.iP "^X" 15
+Unused.
+.iP "^Y" 15
+Exposes one more line above the current screen, leaving the cursor where
+it is if possible. (No mnemonic value for this key; however, it is next
+to \fB^U\fR which scrolls up a bunch.)
+(Version 3 only.)
+.iP "^Z" 15
+If supported by the Unix system,
+stops the editor, exiting to the top level shell.
+Same as \fB:stop\fP\s-2CR\s0.
+Otherwise, unused.
+.iP "^[\ (\fR\s-2ESC\s0\fP)" 15
+Cancels a partially formed command, such as a \fBz\fR when no following
+character has yet been given; terminates inputs on the last line (read
+by commands such as \fB: /\fR and \fB?\fR); ends insertions of new text
+into the buffer.
+If an \s-2ESC\s0 is given when quiescent in command state, the editor
+rings the bell or flashes the screen. You can thus hit \s-2ESC\s0 if
+you don't know what is happening till the editor rings the bell.
+If you don't know if you are in insert mode you can type \s-2ESC\s0\fBa\fR,
+and then material to be input; the material will be inserted correctly
+whether or not you were in insert mode when you started (1.5, 3.1, 7.5).
+.iP "^\e" 15
+Unused.
+.iP "^]" 15
+Searches for the word which is after the cursor as a tag. Equivalent
+to typing \fB:ta\fR, this word, and then a \s-2CR\s0.
+Mnemonically, this command is ``go right to'' (7.3).
+.iP "^\(ua" 15
+Equivalent to \fB:e #\fR\s-2CR\s0, returning to the previous position
+in the last edited file, or editing a file which you specified if you
+got a `No write since last change diagnostic' and do not want to have
+to type the file name again (7.3).
+(You have to do a \fB:w\fR before \fB^\(ua\fR
+will work in this case. If you do not wish to write the file you should
+do \fB:e!\ #\fR\s-2CR\s0 instead.)
+.iP "^_" 15
+Unused.
+Reserved as the command character for the
+Tektronix 4025 and 4027 terminal.
+.iP "\fR\s-2SPACE\s0\fP" 15
+Same as
+.B "right arrow"
+(see
+.B l ).
+.iP "!" 15
+An operator, which processes lines from the buffer with reformatting commands.
+Follow \fB!\fR with the object to be processed, and then the command name
+terminated by \s-2CR\s0. Doubling \fB!\fR and preceding it by a count
+causes count lines to be filtered; otherwise the count
+is passed on to the object after the \fB!\fR. Thus \fB2!}\fR\fIfmt\fR\s-2CR\s0
+reformats the next two paragraphs by running them through the program
+\fIfmt\fR. If you are working on \s-2LISP\s0,
+the command \fB!%\fR\fIgrind\fR\s-2CR\s0,*
+.FS
+*Both
+.I fmt
+and
+.I grind
+are Berkeley programs and may not be present at all installations.
+.FE
+given at the beginning of a
+function, will run the text of the function through the \s-2LISP\s0 grinder
+(6.7, 7.3).
+To read a file or the output of a command into the buffer use \fB:r\fR (7.3).
+To simply execute a command use \fB:!\fR (7.3).
+.tr "
+.iP  15
+Precedes a named buffer specification. There are named buffers \fB1\-9\fR
+used for saving deleted text and named buffers \fBa\-z\fR into which you can
+place text (4.3, 6.3)
+.tr 
+.iP "#" 15
+The macro character which, when followed by a number, will substitute
+for a function key on terminals without function keys (6.9).
+In input mode,
+if this is your erase character, it will delete the last character
+you typed in input mode, and must be preceded with a \fB\e\fR to insert
+it, since it normally backs over the last input character you gave.
+.iP "$" 15
+Moves to the end of the current line. If you \fB:se list\fR\s-2CR\s0,
+then the end of each line will be shown by printing a \fB$\fR after the
+end of the displayed text in the line. Given a count, advances to the
+count'th following end of line; thus \fB2$\fR advances to the end of the
+following line.
+.iP "%" 15
+Moves to the parenthesis or brace \fB{ }\fR which balances the parenthesis
+or brace at the current cursor position.
+.iP "&" 15
+A synonym for \fB:&\fR\s-2CR\s0, by analogy with the
+.I ex
+.B &
+command.
+.iP "\(aa" 15
+When followed by a \fB\(aa\fR returns to the previous context at the
+beginning of a line. The previous context is set whenever the current
+line is moved in a non-relative way.
+When followed by a letter \fBa\fR\-\fBz\fR, returns to the line which
+was marked with this letter with a \fBm\fR command, at the first non-white
+character in the line. (2.2, 5.3).
+When used with an operator such as \fBd\fR, the operation takes place
+over complete lines; if you use \fB\(ga\fR, the operation takes place
+from the exact marked place to the current cursor position within the
+line.
+.iP "(" 15
+Retreats to the beginning of a
+sentence, or to the beginning of a \s-2LISP\s0 s-expression
+if the \fIlisp\fR option is set.
+A sentence ends at a \fB. !\fR or \fB?\fR which is followed by either
+the end of a line or by two spaces. Any number of closing \fB) ] "\fR
+and \fB\(aa\fR characters may appear after the \fB. !\fR or \fB?\fR,
+and before the spaces or end of line. Sentences also begin
+at paragraph and section boundaries
+(see \fB{\fR and \fB[[\fR below).
+A count advances that many sentences (4.2, 6.8).
+.iP ")" 15
+Advances to the beginning of a sentence.
+A count repeats the effect.
+See \fB(\fR above for the definition of a sentence (4.2, 6.8).
+.iP "*" 15
+Unused.
+.iP "+" 15
+Same as \s-2CR\s0 when used as a command.
+.iP "," 15
+Reverse of the last \fBf F t\fR or \fBT\fR command, looking the other way
+in the current line. Especially useful after hitting too many \fB;\fR
+characters. A count repeats the search.
+.iP "\-" 15
+Retreats to the previous line at the first non-white character.
+This is the inverse of \fB+\fR and \s-2RETURN\s0.
+If the line moved to is not on the screen, the screen is scrolled, or
+cleared and redrawn if this is not possible.
+If a large amount of scrolling would be required the screen is also cleared
+and redrawn, with the current line at the center (2.3).
+.iP "\&." 15
+Repeats the last command which changed the buffer. Especially useful
+when deleting words or lines; you can delete some words/lines and then
+hit \fB.\fR to delete more and more words/lines.
+Given a count, it passes it on to the command being repeated. Thus after
+a \fB2dw\fR, \fB3.\fR deletes three words (3.3, 6.3, 7.2, 7.4).
+.iP "/" 15
+Reads a string from the last line on the screen, and scans forward for
+the next occurrence of this string. The normal input editing sequences may
+be used during the input on the bottom line; an returns to command state
+without ever searching.
+The search begins when you hit \s-2CR\s0 to terminate the pattern;
+the cursor moves to the beginning of the last line to indicate that the search
+is in progress; the search may then
+be terminated with a \s-2DEL\s0 or \s-2RUB\s0, or by backspacing when
+at the beginning of the bottom line, returning the cursor to
+its initial position.
+Searches normally wrap end-around to find a string
+anywhere in the buffer.
+.IP
+When used with an operator the enclosed region is normally affected.
+By mentioning an
+offset from the line matched by the pattern you can force whole lines
+to be affected. To do this give a pattern with a closing
+a closing \fB/\fR and then an offset \fB+\fR\fIn\fR or \fB\-\fR\fIn\fR.
+.IP
+To include the character \fB/\fR in the search string, you must escape
+it with a preceding \fB\e\fR.
+A \fB\(ua\fR at the beginning of the pattern forces the match to occur
+at the beginning of a line only; this speeds the search. A \fB$\fR at
+the end of the pattern forces the match to occur at the end of a line
+only.
+More extended pattern matching is available, see section 7.4;
+unless you set \fBnomagic\fR in your \fI\&.exrc\fR file you will have
+to preceed the characters \fB. [ *\fR and \fB~\fR in the search pattern
+with a \fB\e\fR to get them to work as you would naively expect (1.5, 2,2,
+6.1, 7.2, 7.4).
+.iP "0" 15
+Moves to the first character on the current line.
+Also used, in forming numbers, after an initial \fB1\fR\-\fB9\fR.
+.iP "1\-9" 15
+Used to form numeric arguments to commands (2.3, 7.2).
+.iP ":" 15
+A prefix to a set of commands for file and option manipulation and escapes
+to the system. Input is given on the bottom line and terminated with
+an \s-2CR\s0, and the command then executed. You can return to where
+you were by hitting \s-2DEL\s0 or \s-2RUB\s0 if you hit \fB:\fR accidentally
+(see primarily 6.2 and 7.3).
+.iP ";" 15
+Repeats the last single character find which used \fBf F t\fR or \fBT\fR.
+A count iterates the basic scan (4.1).
+.iP "<" 15
+An operator which shifts lines left one \fIshiftwidth\fR, normally 8
+spaces. Like all operators, affects lines when repeated, as in
+\fB<<\fR. Counts are passed through to the basic object, thus \fB3<<\fR
+shifts three lines (6.6, 7.2).
+.iP "=" 15
+Reindents line for \s-2LISP\s0, as though they were typed in with \fIlisp\fR
+and \fIautoindent\fR set (6.8).
+.iP ">" 15
+An operator which shifts lines right one \fIshiftwidth\fR, normally 8
+spaces. Affects lines when repeated as in \fB>>\fR. Counts repeat the
+basic object (6.6, 7.2).
+.iP "?" 15
+Scans backwards, the opposite of \fB/\fR. See the \fB/\fR description
+above for details on scanning (2.2, 6.1, 7.4).
+.iP "@" 15
+A macro character (6.9). If this is your kill character, you must escape it with a \e
+to type it in during input mode, as it normally backs over the input you
+have given on the current line (3.1, 3.4, 7.5).
+.iP "A" 15
+Appends at the end of line, a synonym for \fB$a\fR (7.2).
+.iP "B" 15
+Backs up a word, where words are composed of non-blank sequences, placing
+the cursor at the beginning of the word. A count repeats the effect
+(2.4).
+.iP "C" 15
+Changes the rest of the text on the current line; a synonym for \fBc$\fR.
+.iP "D" 15
+Deletes the rest of the text on the current line; a synonym for \fBd$\fR.
+.iP "E" 15
+Moves forward to the end of a word, defined as blanks and non-blanks,
+like \fBB\fR and \fBW\fR. A count repeats the effect.
+.iP "F" 15
+Finds a single following character, backwards in the current line.
+A count repeats this search that many times (4.1).
+.iP "G" 15
+Goes to the line number given as preceding argument, or the end of the
+file if no preceding count is given. The screen is redrawn with the
+new current line in the center if necessary (7.2).
+.iP "H" 15
+.B "Home arrow" .
+Homes the cursor to the top line on the screen. If a count is given,
+then the cursor is moved to the count'th line on the screen.
+In any case the cursor is moved to the first non-white character on the
+line. If used as the target of an operator, full lines are affected
+(2.3, 3.2).
+.iP "I" 15
+Inserts at the beginning of a line; a synonym for \fB\(uai\fR.
+.iP "J" 15
+Joins together lines, supplying appropriate white space: one space between
+words, two spaces after a \fB.\fR, and no spaces at all if the first
+character of the joined on line is \fB)\fR. A count causes that many
+lines to be joined rather than the default two (6.5, 7.1f).
+.iP "K" 15
+Unused.
+.iP "L" 15
+Moves the cursor to the first non-white character of the last line on
+the screen. With a count, to the first non-white of the count'th line
+from the bottom. Operators affect whole lines when used with \fBL\fR
+(2.3).
+.iP "M" 15
+Moves the cursor to the middle line on the screen, at the first non-white
+position on the line (2.3).
+.iP "N" 15
+Scans for the next match of the last pattern given to
+\fB/\fR or \fB?\fR, but in the reverse direction; this is the reverse
+of \fBn\fR.
+.iP "O" 15
+Opens a new line above the current line and inputs text there up to an
+\s-2ESC\s0. A count can be used on dumb terminals to specify a number
+of lines to be opened; this is generally obsolete, as the \fIslowopen\fR
+option works better (3.1).
+.iP "P" 15
+Puts the last deleted text back before/above the cursor. The text goes
+back as whole lines above the cursor if it was deleted as whole lines.
+Otherwise the text is inserted between the characters before and at the
+cursor. May be preceded by a named buffer specification \fB"\fR\fIx\fR
+to retrieve the contents of the buffer; buffers \fB1\fR\-\fB9\fR contain
+deleted material, buffers \fBa\fR\-\fBz\fR are available for general
+use (6.3).
+.iP "Q" 15
+Quits from \fIvi\fR to \fIex\fR command mode. In this mode, whole lines
+form commands, ending with a \s-2RETURN\s0. You can give all the \fB:\fR
+commands; the editor supplies the \fB:\fR as a prompt (7.7).
+.iP "R" 15
+Replaces characters on the screen with characters you type (overlay fashion).
+Terminates with an \s-2ESC\s0.
+.iP "S" 15
+Changes whole lines, a synonym for \fBcc\fR. A count substitutes for
+that many lines. The lines are saved in the numeric buffers, and erased
+on the screen before the substitution begins.
+.iP "T" 15
+Takes a single following character, locates the character before the
+cursor in the current line, and places the cursor just after that character.
+A count repeats the effect. Most useful with operators such as \fBd\fR
+(4.1).
+.iP "U" 15
+Restores the current line to its state before you started changing it
+(3.5).
+.iP "V" 15
+Unused.
+.iP "W" 15
+Moves forward to the beginning of a word in the current line,
+where words are defined as sequences of blank/non-blank characters.
+A count repeats the effect (2.4).
+.iP "X" 15
+Deletes the character before the cursor. A count repeats the effect,
+but only characters on the current line are deleted.
+.iP "Y" 15
+Yanks a copy of the current line into the unnamed buffer, to be put back
+by a later \fBp\fR or \fBP\fR; a very useful synonym for \fByy\fR.
+A count yanks that many lines. May be preceded by a buffer name to put
+lines in that buffer (7.4).
+.iP "ZZ" 15
+Exits the editor.
+(Same as \fB:x\fP\s-2CR\s0.)
+If any changes have been made, the buffer is written out to the current file.
+Then the editor quits.
+.iP "[[" 15
+Backs up to the previous section boundary. A section begins at each
+macro in the \fIsections\fR option,
+normally a `.NH' or `.SH' and also at lines which which start
+with a formfeed \fB^L\fR. Lines beginning with \fB{\fR also stop \fB[[\fR;
+this makes it useful for looking backwards, a function at a time, in C
+programs. If the option \fIlisp\fR is set, stops at each \fB(\fR at the
+beginning of a line, and is thus useful for moving backwards at the top
+level \s-2LISP\s0 objects. (4.2, 6.1, 6.6, 7.2).
+.iP "\e" 15
+Unused.
+.iP "]]" 15
+Forward to a section boundary, see \fB[[\fR for a definition (4.2, 6.1,
+6.6, 7.2).
+.iP "\(ua" 15
+Moves to the first non-white position on the current line (4.4).
+.iP "_" 15
+Unused.
+.iP "\(ga" 15
+When followed by a \fB\(ga\fR returns to the previous context.
+The previous context is set whenever the current
+line is moved in a non-relative way.
+When followed by a letter \fBa\fR\-\fBz\fR, returns to the position which
+was marked with this letter with a \fBm\fR command.
+When used with an operator such as \fBd\fR, the operation takes place
+from the exact marked place to the current position within the line;
+if you use \fB\(aa\fR, the operation takes place over complete lines
+(2.2, 5.3).
+.iP "a" 15
+Appends arbitrary text after the current cursor position; the insert
+can continue onto multiple lines by using \s-2RETURN\s0 within the insert.
+A count causes the inserted text to be replicated, but only if the inserted
+text is all on one line.
+The insertion terminates with an \s-2ESC\s0 (3.1, 7.2).
+.iP "b" 15
+Backs up to the beginning of a word in the current line. A word is a
+sequence of alphanumerics, or a sequence of special characters.
+A count repeats the effect (2.4).
+.iP "c" 15
+An operator which changes the following object, replacing it with the
+following input text up to an \s-2ESC\s0. If more than part of a single
+line is affected, the text which is changed away is saved in the numeric named
+buffers. If only part of the current line is affected, then the last
+character to be changed away is marked with a \fB$\fR.
+A count causes that many objects to be affected, thus both
+\fB3c)\fR and \fBc3)\fR change the following three sentences (7.4).
+.iP "d" 15
+An operator which deletes the following object. If more than part of
+a line is affected, the text is saved in the numeric buffers.
+A count causes that many objects to be affected; thus \fB3dw\fR is the
+same as \fBd3w\fR (3.3, 3.4, 4.1, 7.4).
+.iP "e" 15
+Advances to the end of the next word, defined as for \fBb\fR and \fBw\fR.
+A count repeats the effect (2.4, 3.1).
+.iP "f" 15
+Finds the first instance of the next character following the cursor on
+the current line. A count repeats the find (4.1).
+.iP "g" 15
+Unused.
+.sp
+Arrow keys
+.B h ,
+.B j ,
+.B k ,
+.B l ,
+and
+.B H .
+.iP "h" 15
+.B "Left arrow" .
+Moves the cursor one character to the left.
+Like the other arrow keys, either
+.B h ,
+the
+.B "left arrow"
+key, or one of the synonyms (\fB^H\fP) has the same effect.
+On v2 editors, arrow keys on certain kinds of terminals
+(those which send escape sequences, such as vt52, c100, or hp)
+cannot be used.
+A count repeats the effect (3.1, 7.5).
+.iP "i" 15
+Inserts text before the cursor, otherwise like \fBa\fR (7.2).
+.iP "j" 15
+.B "Down arrow" .
+Moves the cursor one line down in the same column.
+If the position does not exist,
+.I vi
+comes as close as possible to the same column.
+Synonyms include
+.B ^J
+(linefeed) and
+.B ^N .
+.iP "k" 15
+.B "Up arrow" .
+Moves the cursor one line up.
+.B ^P
+is a synonym.
+.iP "l" 15
+.B "Right arrow" .
+Moves the cursor one character to the right.
+\s-2SPACE\s0 is a synonym.
+.iP "m" 15
+Marks the current position of the cursor in the mark register which is
+specified by the next character \fBa\fR\-\fBz\fR. Return to this position
+or use with an operator using \fB\(ga\fR or \fB\(aa\fR (5.3).
+.iP "n" 15
+Repeats the last \fB/\fR or \fB?\fR scanning commands (2.2).
+.iP "o" 15
+Opens new lines below the current line; otherwise like \fBO\fR (3.1).
+.iP "p" 15
+Puts text after/below the cursor; otherwise like \fBP\fR (6.3).
+.iP "q" 15
+Unused.
+.iP "r" 15
+Replaces the single character at the cursor with a single character you
+type. The new character may be a \s-2RETURN\s0; this is the easiest
+way to split lines. A count replaces each of the following count characters
+with the single character given; see \fBR\fR above which is the more
+usually useful iteration of \fBr\fR (3.2).
+.iP "s" 15
+Changes the single character under the cursor to the text which follows
+up to an \s-2ESC\s0; given a count, that many characters from the current
+line are changed. The last character to be changed is marked with \fB$\fR
+as in \fBc\fR (3.2).
+.iP "t" 15
+Advances the cursor upto the character before the next character typed.
+Most useful with operators such as \fBd\fR and \fBc\fR to delete the
+characters up to a following character. You can use \fB.\fR to delete
+more if this doesn't delete enough the first time (4.1).
+.iP "u" 15
+Undoes the last change made to the current buffer. If repeated, will
+alternate between these two states, thus is its own inverse. When used
+after an insert which inserted text on more than one line, the lines are
+saved in the numeric named buffers (3.5).
+.iP "v" 15
+Unused.
+.iP "w" 15
+Advances to the beginning of the next word, as defined by \fBb\fR (2.4).
+.iP "x" 15
+Deletes the single character under the cursor. With a count deletes
+deletes that many characters forward from the cursor position, but only
+on the current line (6.5).
+.iP "y" 15
+An operator, yanks the following object into the unnamed temporary buffer.
+If preceded by a named buffer specification, \fB"\fR\fIx\fR, the text
+is placed in that buffer also. Text can be recovered by a later \fBp\fR
+or \fBP\fR (7.4).
+.iP "z" 15
+Redraws the screen with the current line placed as specified by the following
+character: \s-2RETURN\s0 specifies the top of the screen, \fB.\fR the
+center of the screen, and \fB\-\fR at the bottom of the screen.
+A count may be given after the \fBz\fR and before the following character
+to specify the new screen size for the redraw.
+A count before the \fBz\fR gives the number of the line to place in the
+center of the screen instead of the default current line. (5.4)
+.iP "{" 15
+Retreats to the beginning of the beginning of the preceding paragraph.
+A paragraph begins at each macro in the \fIparagraphs\fR option, normally
+`.IP', `.LP', `.PP', `.QP' and `.bp'.
+A paragraph also begins after a completely
+empty line, and at each section boundary (see \fB[[\fR above) (4.2, 6.8,
+7.6).
+.iP "|" 15
+Places the cursor on the character in the column specified
+by the count (7.1, 7.2).
+.iP "}" 15
+Advances to the beginning of the next paragraph. See \fB{\fR for the
+definition of paragraph (4.2, 6.8, 7.6).
+.iP "~" 15
+Unused.
+.iP "^?\ (\s-2\fRDEL\fP\s0)" 15
+Interrupts the editor, returning it to command accepting state (1.5,
+7.5)
+.bp
+\&.
diff --git a/usr.bin/vi/docs/USD.doc/vi/vi.in b/usr.bin/vi/docs/USD.doc/vi/vi.in
new file mode 100644
index 000000000000..3bdfeb95b65e
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/vi.in
@@ -0,0 +1,2064 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)vi.in 8.1 (Berkeley) 6/8/93
+.\"
+.EH 'USD:12-%''An Introduction to Display Editing with Vi'
+.OH 'An Introduction to Display Editing with Vi''USD:12-%'
+.bd S 3
+.if t .ds dg \(dg
+.if n .ds dg +
+.if t .ds dd \(dd
+.if n .ds dd ++
+.\".RP
+.TL
+An Introduction to Display Editing with Vi
+.AU
+William Joy
+.AU
+Mark Horton
+.AI
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, Ca. 94720
+.AB
+.PP
+.I Vi
+(visual) is a display oriented interactive text editor.
+When using
+.I vi
+the screen of your terminal acts as a window into the file which you
+are editing. Changes which you make to the file are reflected
+in what you see.
+.PP
+Using
+.I vi
+you can insert new text any place in the file quite easily.
+Most of the commands to
+.I vi
+move the cursor around in the file.
+There are commands to move the cursor
+forward and backward in units of characters, words,
+sentences and paragraphs.
+A small set of operators, like
+.B d
+for delete and
+.B c
+for change, are combined with the motion commands to form operations
+such as delete word or change paragraph, in a simple and natural way.
+This regularity and the mnemonic assignment of commands to keys makes the
+editor command set easy to remember and to use.
+.PP
+.I Vi
+will work on a large number of display terminals,
+and new terminals are easily driven after editing a terminal description file.
+While it is advantageous to have an intelligent terminal which can locally
+insert and delete lines and characters from the display, the editor will
+function quite well on dumb terminals over slow phone lines.
+The editor makes allowance for the low bandwidth in these situations
+and uses smaller window sizes and
+different display updating algorithms to make best use of the
+limited speed available.
+.PP
+It is also possible to use the command set of
+.I vi
+on hardcopy terminals, storage tubes and ``glass tty's'' using a one line
+editing window; thus
+.I vi's
+command set is available on all terminals.
+The full command set of the more traditional, line
+oriented editor
+.I ex
+is available within
+.I vi;
+it is quite simple to switch between the two modes of editing.
+.AE
+.NH 1
+Getting started
+.PP
+.FS
+The financial support of an \s-2IBM\s0 Graduate Fellowship and the
+National Science Foundation under grants MCS74-07644-A03 and MCS78-07291
+is gratefully acknowledged.
+.FE
+This document provides a quick introduction to
+.I vi.
+(Pronounced \fIvee-eye\fP.)
+You should be running
+.I vi
+on a file you are familiar with while you are reading this.
+The first part of this document (sections 1 through 5)
+describes the basics of using
+.I vi.
+Some topics of special interest are presented in section 6, and
+some nitty-gritty details of how the editor functions are saved for section
+7 to avoid cluttering the presentation here.
+.PP
+There is also a short appendix here, which gives for each character the
+special meanings which this character has in \fIvi\fR. Attached to
+this document should be a quick reference card.
+This card summarizes the commands of
+.I vi
+in a very compact format. You should have the card handy while you are
+learning
+.I vi.
+.NH 2
+Specifying terminal type
+.PP
+Before you can start
+.I vi
+you must tell the system what kind of terminal you are using.
+Here is a (necessarily incomplete) list of terminal type codes.
+If your terminal does not appear here, you should consult with one of
+the staff members on your system to find out the code for your terminal.
+If your terminal does not have a code, one can be assigned and a description
+for the terminal can be created.
+.LP
+.TS
+center;
+ab ab ab
+a a a.
+Code Full name Type
+_
+2621 Hewlett-Packard 2621A/P Intelligent
+2645 Hewlett-Packard 264x Intelligent
+act4 Microterm ACT-IV Dumb
+act5 Microterm ACT-V Dumb
+adm3a Lear Siegler ADM-3a Dumb
+adm31 Lear Siegler ADM-31 Intelligent
+c100 Human Design Concept 100 Intelligent
+dm1520 Datamedia 1520 Dumb
+dm2500 Datamedia 2500 Intelligent
+dm3025 Datamedia 3025 Intelligent
+fox Perkin-Elmer Fox Dumb
+h1500 Hazeltine 1500 Intelligent
+h19 Heathkit h19 Intelligent
+i100 Infoton 100 Intelligent
+mime Imitating a smart act4 Intelligent
+t1061 Teleray 1061 Intelligent
+vt52 Dec VT-52 Dumb
+.TE
+.PP
+Suppose for example that you have a Hewlett-Packard HP2621A
+terminal. The code used by the system for this terminal is `2621'.
+In this case you can use one of the following commands to tell the system
+the type of your terminal:
+.DS
+% \fBsetenv TERM\fP 2621
+.DE
+This command works with the
+.I csh
+shell.
+If you are using the standard Bourne shell
+.I sh
+then you should give the commands
+.DS
+$ \fBTERM=\fP2621
+$ \fBexport TERM\fP
+.DE
+.PP
+If you want to arrange to have your terminal type set up automatically
+when you log in, you can use the
+.I tset
+program.
+If you dial in on a
+.I mime ,
+but often use hardwired ports, a typical line for your
+.I .login
+file (if you use csh) would be
+.DS
+\fBsetenv TERM \(gatset\fP \- \-d mime\(ga
+.DE
+or for your
+.I .profile
+file (if you use sh)
+.DS
+\fBTERM=\(gatse\fPt \- \-d mime\(ga
+.DE
+.I Tset
+knows which terminals are hardwired to each port
+and needs only to be told that when you dial in you
+are probably on a
+.I mime .
+.I Tset
+is usually used to change the erase and kill characters, too.
+.NH 2
+Editing a file
+.PP
+After telling the system which kind of terminal you have, you should
+make a copy of a file you are familiar with, and run
+.I vi
+on this file, giving the command
+.DS
+% \fBvi\fR \fIname\fR
+.DE
+replacing \fIname\fR with the name of the copy file you just created.
+The screen should clear and the text of your file should appear on the
+screen. If something else happens refer to the footnote.\*(dd
+.FS
+\*(dd If you gave the system an incorrect terminal type code then the
+editor may have just made a mess out of your screen. This happens when
+it sends control codes for one kind of terminal to some other
+kind of terminal. In this case hit
+the keys \fB:q\fR (colon and the q key) and then hit the \s-2RETURN\s0 key.
+This should get you back to the command level interpreter.
+Figure out what you did wrong (ask someone else if necessary) and try again.
+ Another thing which can go wrong is that you typed the wrong file name and
+the editor just printed an error diagnostic. In this case you should
+follow the above procedure for getting out of the editor, and try again
+this time spelling the file name correctly.
+ If the editor doesn't seem to respond to the commands which you type
+here, try sending an interrupt to it by hitting the \s-2DEL\s0 or \s-2RUB\s0
+key on your terminal, and then hitting the \fB:q\fR command again followed
+by a carriage return.
+.sp
+.FE
+.NH 2
+The editor's copy: the buffer
+.PP
+The editor does not directly modify the file which you are editing.
+Rather, the editor makes a copy of this file, in a place called the
+.I buffer,
+and remembers the file's
+name. You do not affect the contents of the file unless and until you
+write the changes you make back into the original file.
+.NH 2
+Notational conventions
+.PP
+In our examples, input which must be typed as is will be presented in
+\fBbold face\fR. Text which should be replaced with appropriate input
+will be given in \fIitalics\fR. We will represent special characters
+in \s-2SMALL CAPITALS\s0.
+.NH 2
+Arrow keys
+.PP
+The editor command set is independent of the terminal
+you are using. On most terminals with cursor positioning keys, these keys
+will also work within the editor.
+If you don't have cursor positioning keys, or even if you do, you can use
+the \fBh j k\fR and \fBl\fR keys as cursor positioning
+keys (these are labelled with arrows on an
+.I adm3a).*
+.PP
+(Particular note for the HP2621: on this terminal the function keys
+must be \fIshifted\fR (ick) to send to the machine, otherwise they
+only act locally. Unshifted use will leave the cursor positioned
+incorrectly.)
+.FS
+* As we will see later,
+.I h
+moves back to the left (like control-h which is a backspace),
+.I j
+moves down (in the same column),
+.I k
+moves up (in the same column),
+and
+.I l
+moves to the right.
+.FE
+.NH 2
+Special characters: \s-2ESC\s0, \s-2CR\s0 and \s-2DEL\s0
+.PP
+Several of these special characters are very important, so be sure to
+find them right now. Look on your keyboard for a key labelled \s-2ESC\s0
+or \s-2ALT\s0. It should be near the upper left corner of your terminal.
+Try hitting this key a few times. The editor will ring the bell
+to indicate that it is in a quiescent state.\*(dd
+.FS
+\*(dd On smart terminals where it is possible, the editor will quietly
+flash the screen rather than ringing the bell.
+.FE
+Partially formed commands are cancelled by \s-2ESC\s0, and when you insert
+text in the file you end the text insertion
+with \s-2ESC\s0. This key is a fairly
+harmless one to hit, so you can just hit it if you don't know
+what is going on until the editor rings the bell.
+.PP
+The \s-2CR\s0 or \s-2RETURN\s0 key is important because it is used
+to terminate certain commands.
+It is usually at the right side of the keyboard,
+and is the same command used at the end of each shell command.
+.PP
+Another very useful key is the \s-2DEL\s0 or \s-2RUB\s0 key, which generates
+an interrupt, telling the editor to stop what it is doing.
+It is a forceful way of making the editor listen
+to you, or to return it to the quiescent state if you don't know or don't
+like what is going on. Try hitting the `/' key on your terminal. This
+key is used when you want to specify a string to be searched for. The
+cursor should now be positioned at the bottom line of the terminal after
+a `/' printed as a prompt. You can get the cursor back to the current
+position by hitting the \s-2DEL\s0 or \s-2RUB\s0 key; try this now.*
+.FS
+* Backspacing over the `/' will also cancel the search.
+.FE
+From now on we will simply refer to hitting the \s-2DEL\s0 or \s-2RUB\s0
+key as ``sending an interrupt.''**
+.FS
+** On some systems, this interruptibility comes at a price: you cannot type
+ahead when the editor is computing with the cursor on the bottom line.
+.FE
+.PP
+The editor often echoes your commands on the last line of the terminal.
+If the cursor is on the first position of this last line, then the editor
+is performing a computation, such as computing a new position in the
+file after a search or running a command to reformat part of the buffer.
+When this is happening you can stop the editor by
+sending an interrupt.
+.NH 2
+Getting out of the editor
+.PP
+After you have worked with this introduction for a while, and you wish
+to do something else, you can give the command \fBZZ\fP
+to the editor.
+This will write the contents of the editor's buffer back into
+the file you are editing, if you made any changes, and then quit from
+the editor. You can also end an editor
+session by giving the command \fB:q!\fR\s-2CR\s0;\*(dg
+.FS
+\*(dg All commands which read from the last display line can also be
+terminated with a \s-2ESC\s0 as well as an \s-2CR\s0.
+.FE
+this is a dangerous but occasionally essential
+command which ends the editor session and discards all your changes.
+You need to know about this command in case you change the editor's
+copy of a file you wish only to look at. Be very careful
+not to give this command when you really want to save
+the changes you have made.
+.NH 1
+Moving around in the file
+.NH 2
+Scrolling and paging
+.PP
+The editor has a number of commands for moving around in the file.
+The most useful of these is generated by hitting the control and D keys
+at the same time, a control-D or `^D'. We will use this two character
+notation for referring to these control keys from now on. You may have
+a key labelled `^' on your terminal. This key will be represented as `\(ua'
+in this document; `^' is exclusively used as part of the `^x' notation
+for control characters.\*(dd
+.FS
+\*(dd If you don't have a `^' key on your terminal
+then there is probably a key labelled `\(ua'; in any case these characters
+are one and the same.
+.FE
+.PP
+As you know now if you tried hitting \fB^D\fR, this command scrolls down in
+the file. The \fBD\fR thus stands for down. Many editor commands are mnemonic
+and this makes them much easier to remember. For instance the command
+to scroll up is \fB^U\fR. Many dumb terminals can't scroll up at all, in which
+case hitting \fB^U\fR clears the screen and refreshes it
+with a line which is farther back in the file at the top.
+.PP
+If you want to see more of the file below where you are, you can
+hit \fB^E\fR to expose one more line at the bottom of the screen,
+leaving the cursor where it is.
+The command \fB^Y\fR (which is hopelessly non-mnemonic, but next to \fB^U\fR
+on the keyboard) exposes one more line at the top of the screen.
+.PP
+There are other ways to move around in the file; the keys \fB^F\fR and \fB^B\fR
+move forward and backward a page,
+keeping a couple of lines of continuity between screens
+so that it is possible to read through a file using these rather than
+\fB^D\fR and \fB^U\fR if you wish.
+.PP
+Notice the difference between scrolling and paging. If you are trying
+to read the text in a file, hitting \fB^F\fR to move forward a page
+will leave you only a little context to look back at. Scrolling on the
+other hand leaves more context, and happens more smoothly. You can continue
+to read the text as scrolling is taking place.
+.NH 2
+Searching, goto, and previous context
+.PP
+Another way to position yourself in the file is by giving the editor a string
+to search for. Type the character \fB/\fR followed by a string of characters
+terminated by \s-2CR\s0. The editor will position the cursor
+at the next occurrence of this string.
+Try hitting \fBn\fR to then go to the next occurrence of this string.
+The character \fB?\fR will search backwards from where you are, and is
+otherwise like \fB/\fR.\*(dg
+.FS
+\*(dg These searches will normally wrap around the end of the file, and thus
+find the string even if it is not on a line in the direction you search
+provided it is anywhere else in the file. You can disable this wraparound
+in scans by giving the command \fB:se nowrapscan\fR\s-2CR\s0,
+or more briefly \fB:se nows\fR\s-2CR\s0.
+.FE
+.PP
+If the search string you give the editor is not present in the
+file the editor will print
+a diagnostic on the last line of the screen, and the cursor will be returned
+to its initial position.
+.PP
+If you wish the search to match only at the beginning of a line, begin
+the search string with an \fB\(ua\fR. To match only at the end of
+a line, end the search string with a \fB$\fR.
+Thus \fB/\(uasearch\fR\s-2CR\s0 will search for the word `search' at
+the beginning of a line, and \fB/last$\fR\s-2CR\s0 searches for the
+word `last' at the end of a line.*
+.FS
+*Actually, the string you give to search for here can be a
+.I "regular expression"
+in the sense of the editors
+.I ex (1)
+and
+.I ed (1).
+If you don't wish to learn about this yet, you can disable this more
+general facility by doing
+\fB:se\ nomagic\fR\s-2CR\s0;
+by putting this command in
+EXINIT
+in your environment, you can have this always be in effect (more
+about
+.I EXINIT
+later.)
+.FE
+.PP
+The command \fBG\fR, when preceded by a number will position the cursor
+at that line in the file.
+Thus \fB1G\fR will move the cursor to
+the first line of the file. If you give \fBG\fR no count, then it moves
+to the end of the file.
+.PP
+If you are near the end of the file, and the last line is not at the bottom
+of the screen, the editor will place only the character `~' on each remaining
+line. This indicates that the last line in the file is on the screen;
+that is, the `~' lines are past the end of the file.
+.PP
+You can find out the state of the file you are editing by typing a \fB^G\fR.
+The editor will show you the name of the file you are editing, the number
+of the current line, the number of lines in the buffer, and the percentage
+of the way through the buffer which you are.
+Try doing this now, and remember the number of the line you are on.
+Give a \fBG\fR command to get to the end and then another \fBG\fR command
+to get back where you were.
+.PP
+You can also get back to a previous position by using the command
+\fB\(ga\(ga\fR (two back quotes).
+This is often more convenient than \fBG\fR because it requires no advance
+preparation.
+Try giving a \fBG\fR or a search with \fB/\fR or \fB?\fR and then a
+\fB\(ga\(ga\fR to get back to where you were. If you accidentally hit
+\fBn\fR or any command which moves you far away from a context of interest, you
+can quickly get back by hitting \fB\(ga\(ga\fR.
+.NH 2
+Moving around on the screen
+.PP
+Now try just moving the cursor around on the screen.
+If your terminal has arrow keys (4 or 5 keys with arrows
+going in each direction) try them and convince yourself
+that they work.
+If you don't have working arrow keys, you can always use
+.B h ,
+.B j ,
+.B k ,
+and
+.B l .
+Experienced users of
+.I vi
+prefer these keys to arrow keys,
+because they are usually right underneath their fingers.
+.PP
+Hit the \fB+\fR key. Each time you do, notice that the cursor
+advances to the next line in the file, at the first non-white position
+on the line. The \fB\-\fR key is like \fB+\fR but goes the other way.
+.PP
+These are very common keys for moving up and down lines in the file.
+Notice that if you go off the bottom or top with these keys then the
+screen will scroll down (and up if possible) to bring a line at a time
+into view. The \s-2RETURN\s0 key has the same effect as the \fB+\fR
+key.
+.PP
+.I Vi
+also has commands to take you to the top, middle and bottom of the screen.
+\fBH\fR will take you to the top (home) line on the screen.
+Try preceding it with a
+number as in \fB3H\fR.
+This will take you to the third line on the screen.
+Many
+.I vi
+commands take preceding numbers and do interesting things with them.
+Try \fBM\fR,
+which takes you to the middle line on the screen,
+and \fBL\fR,
+which takes you to the last line on the screen.
+\fBL\fR also takes counts, thus
+\fB5L\fR will take you to the fifth line from the bottom.
+.NH 2
+Moving within a line
+.PP
+Now try picking a word on some line on the screen, not the
+first word on the line.
+move the cursor using \s-2RETURN\s0 and \fB\-\fR to be on the line where
+the word is.
+Try hitting the \fBw\fR key. This will advance the cursor to the
+next word on the line.
+Try hitting the \fBb\fR key to back up words
+in the line.
+Also try the \fBe\fR key which advances you to the end of the current
+word rather than to the beginning of the next word.
+Also try \s-2SPACE\s0 (the space bar) which moves right one character
+and the \s-2BS\s0 (backspace or \fB^H\fR) key which moves left one character.
+The key \fBh\fR works as \fB^H\fR does and is useful if you don't have
+a \s-2BS\s0 key.
+(Also, as noted just above, \fBl\fR will move to the right.)
+.PP
+If the line had punctuation in it you may have noticed that
+that the \fBw\fR and \fBb\fR
+keys stopped at each group of punctuation. You can also go back and
+forwards words without stopping at punctuation by using \fBW\fR and \fBB\fR
+rather than the lower case equivalents. Think of these as bigger words.
+Try these on a few lines with punctuation to see how they differ from
+the lower case \fBw\fR and \fBb\fR.
+.PP
+The word keys wrap around the end of line,
+rather than stopping at the end. Try moving to a word on a line below
+where you are by repeatedly hitting \fBw\fR.
+.NH 2
+Summary
+.IP
+.TS
+lw(.50i)b a.
+\fR\s-2SPACE\s0\fP advance the cursor one position
+^B backwards to previous page
+^D scrolls down in the file
+^E exposes another line at the bottom
+^F forward to next page
+^G tell what is going on
+^H backspace the cursor
+^N next line, same column
+^P previous line, same column
+^U scrolls up in the file
+^Y exposes another line at the top
++ next line, at the beginning
+\- previous line, at the beginning
+/ scan for a following string forwards
+? scan backwards
+B back a word, ignoring punctuation
+G go to specified line, last default
+H home screen line
+M middle screen line
+L last screen line
+W forward a word, ignoring punctuation
+b back a word
+e end of current word
+n scan for next instance of \fB/\fR or \fB?\fR pattern
+w word after this word
+.TE
+.NH 2
+View
+.PP
+If you want to use the editor to look at a file,
+rather than to make changes,
+invoke it as
+.I view
+instead of
+.I vi .
+This will set the
+.I readonly
+option which will prevent you from
+accidently overwriting the file.
+.NH 1
+Making simple changes
+.NH 2
+Inserting
+.PP
+One of the most useful commands is the
+\fBi\fR (insert) command.
+After you type \fBi\fR, everything you type until you hit \s-2ESC\s0
+is inserted into the file.
+Try this now; position yourself to some word in the file and try inserting
+text before this word.
+If you are on an dumb terminal it will seem, for a minute,
+that some of the characters in your line have been overwritten, but they will
+reappear when you hit \s-2ESC\s0.
+.PP
+Now try finding a word which can, but does not, end in an `s'.
+Position yourself at this word and type \fBe\fR (move to end of word), then
+\fBa\fR for append and then `s\s-2ESC\s0' to terminate the textual insert.
+This sequence of commands can be used to easily pluralize a word.
+.PP
+Try inserting and appending a few times to make sure you understand how
+this works; \fBi\fR placing text to the left of the cursor, \fBa\fR to
+the right.
+.PP
+It is often the case that you want to add new lines to the file you are
+editing, before or after some specific line in the file. Find a line
+where this makes sense and then give the command \fBo\fR to create a
+new line after the line you are on, or the command \fBO\fR to create
+a new line before the line you are on. After you create a new line in
+this way, text you type up to an \s-2ESC\s0 is inserted on the new line.
+.PP
+Many related editor commands
+are invoked by the same letter key and differ only in that one is given
+by a lower
+case key and the other is given by
+an upper case key. In these cases, the
+upper case key often differs from the lower case key in its sense of
+direction, with
+the upper case key working backward and/or up, while the lower case
+key moves forward and/or down.
+.PP
+Whenever you are typing in text, you can give many lines of input or
+just a few characters.
+To type in more than one line of text,
+hit a \s-2RETURN\s0 at the middle of your input. A new line will be created
+for text, and you can continue to type. If you are on a slow
+and dumb terminal the editor may choose to wait to redraw the
+tail of the screen, and will let you type over the existing screen lines.
+This avoids the lengthy delay which would occur if the editor attempted
+to keep the tail of the screen always up to date. The tail of the screen will
+be fixed up, and the missing lines will reappear, when you hit \s-2ESC\s0.
+.PP
+While you are inserting new text, you can use the characters you normally use
+at the system command level (usually \fB^H\fR or \fB#\fR) to backspace
+over the last
+character which you typed, and the character which you use to kill input lines
+(usually \fB@\fR, \fB^X\fR, or \fB^U\fR)
+to erase the input you have typed on the current line.\*(dg
+.FS
+\*(dg In fact, the character \fB^H\fR (backspace) always works to erase the
+last input character here, regardless of what your erase character is.
+.FE
+The character \fB^W\fR
+will erase a whole word and leave you after the space after the previous
+word; it is useful for quickly backing up in an insert.
+.PP
+Notice that when you backspace during an insertion the characters you
+backspace over are not erased; the cursor moves backwards, and the characters
+remain on the display. This is often useful if you are planning to type
+in something similar. In any case the characters disappear when when
+you hit \s-2ESC\s0; if you want to get rid of them immediately, hit an
+\s-2ESC\s0 and then \fBa\fR again.
+.PP
+Notice also that you can't erase characters which you didn't insert, and that
+you can't backspace around the end of a line. If you need to back up
+to the previous line to make a correction, just hit \s-2ESC\s0 and move
+the cursor back to the previous line. After making the correction you
+can return to where you were and use the insert or append command again.
+.NH 2
+Making small corrections
+.PP
+You can make small corrections in existing text quite easily.
+Find a single character which is wrong or just pick any character.
+Use the arrow keys to find the character, or
+get near the character with the word motion keys and then either
+backspace (hit the \s-2BS\s0 key or \fB^H\fR or even just \fBh\fR) or
+\s-2SPACE\s0 (using the space bar)
+until the cursor is on the character which is wrong.
+If the character is not needed then hit the \fBx\fP key; this deletes
+the character from the file. It is analogous to the way you \fBx\fP
+out characters when you make mistakes on a typewriter (except it's not
+as messy).
+.PP
+If the character
+is incorrect, you can replace it with the correct character by giving
+the command \fBr\fR\fIc\fR,
+where \fIc\fR is replaced by the correct character.
+Finally if the character which is incorrect should be replaced
+by more than one character, give the command \fBs\fR which substitutes
+a string of characters, ending with \s-2ESC\s0, for it.
+If there are a small number of characters
+which are wrong you can precede \fBs\fR with a count of the number of
+characters to be replaced. Counts are also useful with \fBx\fR to specify
+the number of characters to be deleted.
+.NH 2
+More corrections: operators
+.PP
+You already know almost enough to make changes at a higher level.
+All you need to know now is that the
+.B d
+key acts as a delete operator. Try the command
+.B dw
+to delete a word.
+Try hitting \fB.\fR a few times. Notice that this repeats the effect
+of the \fBdw\fR. The command \fB.\fR repeats the last command which
+made a change. You can remember it by analogy with an ellipsis `\fB...\fR'.
+.PP
+Now try
+\fBdb\fR.
+This deletes a word backwards, namely the preceding word.
+Try
+\fBd\fR\s-2SPACE\s0. This deletes a single character, and is equivalent
+to the \fBx\fR command.
+.PP
+Another very useful operator is
+.B c
+or change. The command
+.B cw
+thus changes the text of a single word.
+You follow it by the replacement text ending with an \s-2ESC\s0.
+Find a word which you can change to another, and try this
+now.
+Notice that the end of the text to be changed was marked with the character
+`$' so that you can see this as you are typing in the new material.
+.NH 2
+Operating on lines
+.PP
+It is often the case that you want to operate on lines.
+Find a line which you want to delete, and type
+\fBdd\fR,
+the
+.B d
+operator twice. This will delete the line.
+If you are on a dumb terminal, the editor may just erase the line on
+the screen, replacing it with a line with only an @ on it. This line
+does not correspond to any line in your file, but only acts as a place
+holder. It helps to avoid a lengthy redraw of the rest of the screen
+which would be necessary to close up the hole created by the deletion
+on a terminal without a delete line capability.
+.PP
+Try repeating the
+.B c
+operator twice; this will change a whole line, erasing its previous contents and
+replacing them with text you type up to an \s-2ESC\s0.\*(dg
+.FS
+\*(dg The command \fBS\fR is a convenient synonym for for \fBcc\fR, by
+analogy with \fBs\fR. Think of \fBS\fR as a substitute on lines, while
+\fBs\fR is a substitute on characters.
+.FE
+.PP
+You can delete or change more than one line by preceding the
+.B dd
+or
+.B cc
+with a count, i.e. \fB5dd\fR deletes 5 lines.
+You can also give a command like \fBdL\fR to delete all the lines up to
+and including
+the last line on the screen, or \fBd3L\fR to delete through the third from
+the bottom line. Try some commands like this now.*
+.FS
+* One subtle point here involves using the \fB/\fR search after a \fBd\fR.
+This will normally delete characters from the current position to the
+point of the match. If what is desired is to delete whole lines
+including the two points, give the pattern as \fB/pat/+0\fR, a line address.
+.FE
+Notice that the editor lets you know when you change a large number of
+lines so that you can see the extent of the change.
+The editor will also always tell you when a change you make affects text which
+you cannot see.
+.NH 2
+Undoing
+.PP
+Now suppose that the last change which you made was incorrect;
+you could use the insert, delete and append commands to put the correct
+material back. However, since it is often the case that we regret a
+change or make a change incorrectly, the editor provides a
+.B u
+(undo) command to reverse the last change which you made.
+Try this a few times, and give it twice in a row to notice that an
+.B u
+also undoes a
+.B u.
+.PP
+The undo command lets you reverse only a single change. After you make
+a number of changes to a line, you may decide that you would rather have
+the original state of the line back. The
+.B U
+command restores the current line to the state before you started changing
+it.
+.PP
+You can recover text which you delete, even if
+undo will not bring it back; see the section on recovering lost text
+below.
+.NH 2
+Summary
+.IP
+.TS
+lw(.50i)b a.
+\fR\s-2SPACE\s0\fP advance the cursor one position
+^H backspace the cursor
+^W erase a word during an insert
+\fRerase\fP your erase (usually ^H or #), erases a character during an insert
+\fRkill\fP your kill (usually @, ^X, or ^U), kills the insert on this line
+\&\fB.\fP repeats the changing command
+O opens and inputs new lines, above the current
+U undoes the changes you made to the current line
+a appends text after the cursor
+c changes the object you specify to the following text
+d deletes the object you specify
+i inserts text before the cursor
+o opens and inputs new lines, below the current
+u undoes the last change
+.TE
+.NH 1
+Moving about; rearranging and duplicating text
+.NH 2
+Low level character motions
+.PP
+Now move the cursor to a line where there is a punctuation or a bracketing
+character such as a parenthesis or a comma or period. Try the command
+\fBf\fR\fIx\fR where \fIx\fR is this character. This command finds
+the next \fIx\fR character to the right of the cursor in the current
+line. Try then hitting a \fB;\fR, which finds the next instance of the
+same character. By using the \fBf\fR command and then a sequence of
+\fB;\fR's you can often
+get to a particular place in a line much faster than with a sequence
+of word motions or \s-2SPACE\s0s.
+There is also a \fBF\fR command, which is like \fBf\fR, but searches
+backward. The \fB;\fR command repeats \fBF\fR also.
+.PP
+When you are operating on the text in a line it is often desirable to
+deal with the characters up to, but not including, the first instance of
+a character. Try \fBdf\fR\fIx\fR for some \fIx\fR now and
+notice that the \fIx\fR character is deleted. Undo this with \fBu\fR
+and then try \fBdt\fR\fIx\fR; the \fBt\fR here stands for to, i.e.
+delete up to the next \fIx\fR, but not the \fIx\fR. The command \fBT\fR
+is the reverse of \fBt\fR.
+.PP
+When working with the text of a single line, an \fB\(ua\fR moves the
+cursor to the first non-white position on the line, and a
+\fB$\fR moves it to the end of the line. Thus \fB$a\fR will append new
+text at the end of the current line.
+.PP
+Your file may have tab (\fB^I\fR) characters in it. These
+characters are represented as a number of spaces expanding to a tab stop,
+where tab stops are every 8 positions.*
+.FS
+* This is settable by a command of the form \fB:se ts=\fR\fIx\fR\s-2CR\s0,
+where \fIx\fR is 4 to set tabstops every four columns. This has
+effect on the screen representation within the editor.
+.FE
+When the cursor is at a tab, it sits on the last of the several spaces
+which represent that tab. Try moving the cursor back and forth over
+tabs so you understand how this works.
+.PP
+On rare occasions, your file may have nonprinting characters in it.
+These characters are displayed in the same way they are represented in
+this document, that is with a two character code, the first character
+of which is `^'. On the screen non-printing characters resemble a `^'
+character adjacent to another, but spacing or backspacing over the character
+will reveal that the two characters are, like the spaces representing
+a tab character, a single character.
+.PP
+The editor sometimes discards control characters,
+depending on the character and the setting of the
+.I beautify
+option,
+if you attempt to insert them in your file.
+You can get a control character in the file by beginning
+an insert and then typing a \fB^V\fR before the control
+character. The
+\fB^V\fR quotes the following character, causing it to be
+inserted directly into the file.
+.PP
+.NH 2
+Higher level text objects
+.PP
+In working with a document it is often advantageous to work in terms
+of sentences, paragraphs, and sections. The operations \fB(\fR and \fB)\fR
+move to the beginning of the previous and next sentences respectively.
+Thus the command \fBd)\fR will delete the rest of the current sentence;
+likewise \fBd(\fR will delete the previous sentence if you are at the
+beginning of the current sentence, or the current sentence up to where
+you are if you are not at the beginning of the current sentence.
+.PP
+A sentence is defined to end at a `.', `!' or `?' which is followed by
+either the end of a line, or by two spaces. Any number of closing `)',
+`]', `"' and `\(aa' characters may appear after the `.', `!' or `?' before
+the spaces or end of line.
+.PP
+The operations \fB{\fR and \fB}\fR move over paragraphs and the operations
+\fB[[\fR and \fB]]\fR move over sections.\*(dg
+.FS
+\*(dg The \fB[[\fR and \fB]]\fR operations
+require the operation character to be doubled because they can move the
+cursor far from where it currently is. While it is easy to get back
+with the command \fB\(ga\(ga\fP,
+these commands would still be frustrating
+if they were easy to hit accidentally.
+.FE
+.PP
+A paragraph begins after each empty line, and also
+at each of a set of paragraph macros, specified by the pairs of characters
+in the definition of the string valued option \fIparagraphs\fR.
+The default setting for this option defines the paragraph macros of the
+\fI\-ms\fR and \fI\-mm\fR macro packages, i.e. the `.IP', `.LP', `.PP'
+and `.QP', `.P' and `.LI' macros.\*(dd
+.FS
+\*(dd You can easily change or extend this set of macros by assigning a
+different string to the \fIparagraphs\fR option in your EXINIT.
+See section 6.2 for details.
+The `.bp' directive is also considered to start a paragraph.
+.FE
+Each paragraph boundary is also a sentence boundary. The sentence
+and paragraph commands can
+be given counts to operate over groups of sentences and paragraphs.
+.PP
+Sections in the editor begin after each macro in the \fIsections\fR option,
+normally `.NH', `.SH', `.H' and `.HU', and each line with a formfeed \fB^L\fR
+in the first column.
+Section boundaries are always line and paragraph boundaries also.
+.PP
+Try experimenting with the sentence and paragraph commands until you are
+sure how they work. If you have a large document, try looking through
+it using the section commands.
+The section commands interpret a preceding count as a different window size in
+which to redraw the screen at the new location, and this window size
+is the base size for newly drawn windows until another size is specified.
+This is very useful
+if you are on a slow terminal and are looking for a particular section.
+You can give the first section command a small count to then see each successive
+section heading in a small window.
+.NH 2
+Rearranging and duplicating text
+.PP
+The editor has a single unnamed buffer where the last deleted or
+changed away text is saved, and a set of named buffers \fBa\fR\-\fBz\fR
+which you can use to save copies of text and to move text around in
+your file and between files.
+.PP
+The operator
+.B y
+yanks a copy of the object which follows into the unnamed buffer.
+If preceded by a buffer name, \fB"\fR\fIx\fR\|\fBy\fR, where
+\fIx\fR here is replaced by a letter \fBa\-z\fR, it places the text in the named
+buffer. The text can then be put back in the file with the commands
+.B p
+and
+.B P;
+\fBp\fR puts the text after or below the cursor, while \fBP\fR puts the text
+before or above the cursor.
+.PP
+If the text which you
+yank forms a part of a line, or is an object such as a sentence which
+partially spans more than one line, then when you put the text back,
+it will be placed after the cursor (or before if you
+use \fBP\fR). If the yanked text forms whole lines, they will be put
+back as whole lines, without changing the current line. In this case,
+the put acts much like a \fBo\fR or \fBO\fR command.
+.PP
+Try the command \fBYP\fR. This makes a copy of the current line and
+leaves you on this copy, which is placed before the current line.
+The command \fBY\fR is a convenient abbreviation for \fByy\fR.
+The command \fBYp\fR will also make a copy of the current line, and place
+it after the current line. You can give \fBY\fR a count of lines to
+yank, and thus duplicate several lines; try \fB3YP\fR.
+.PP
+To move text within the buffer, you need to delete it in one place, and
+put it back in another. You can precede a delete operation by the
+name of a buffer in which the text is to be stored as in \fB"a5dd\fR
+deleting 5 lines into the named buffer \fIa\fR. You can then move the
+cursor to the eventual resting place of the these lines and do a \fB"ap\fR
+or \fB"aP\fR to put them back.
+In fact, you can switch and edit another file before you put the lines
+back, by giving a command of the form \fB:e \fR\fIname\fR\s-2CR\s0 where
+\fIname\fR is the name of the other file you want to edit. You will
+have to write back the contents of the current editor buffer (or discard
+them) if you have made changes before the editor will let you switch
+to the other file.
+An ordinary delete command saves the text in the unnamed buffer,
+so that an ordinary put can move it elsewhere.
+However, the unnamed buffer is lost when you change files,
+so to move text from one file to another you should use an unnamed buffer.
+.NH 2
+Summary.
+.IP
+.TS
+lw(.50i)b a.
+\(ua first non-white on line
+$ end of line
+) forward sentence
+} forward paragraph
+]] forward section
+( backward sentence
+{ backward paragraph
+[[ backward section
+f\fIx\fR find \fIx\fR forward in line
+p put text back, after cursor or below current line
+y yank operator, for copies and moves
+t\fIx\fR up to \fIx\fR forward, for operators
+F\fIx\fR f backward in line
+P put text back, before cursor or above current line
+T\fIx\fR t backward in line
+.TE
+.NH 1
+High level commands
+.NH 2
+Writing, quitting, editing new files
+.PP
+So far we have seen how to enter
+.I vi
+and to write out our file using either
+\fBZZ\fR or \fB:w\fR\s-2CR\s0. The first exits from
+the editor,
+(writing if changes were made),
+the second writes and stays in the editor.
+.PP
+If you have changed the editor's copy of the file but do not wish to
+save your changes, either because you messed up the file or decided that the
+changes are not an improvement to the file, then you can give the command
+\fB:q!\fR\s-2CR\s0 to quit from the editor without writing the changes.
+You can also reedit the same file (starting over) by giving the command
+\fB:e!\fR\s-2CR\s0. These commands should be used only rarely, and with
+caution, as it is not possible to recover the changes you have made after
+you discard them in this manner.
+.PP
+You can edit a different file without leaving the editor by giving the
+command \fB:e\fR\ \fIname\fR\s-2CR\s0. If you have not written out
+your file before you try to do this, then the editor will tell you this,
+and delay editing the other file. You can then give the command
+\fB:w\fR\s-2CR\s0 to save your work and then the \fB:e\fR\ \fIname\fR\s-2CR\s0
+command again, or carefully give the command \fB:e!\fR\ \fIname\fR\s-2CR\s0,
+which edits the other file discarding the changes you have made to the
+current file.
+To have the editor automatically save changes,
+include
+.I "set autowrite"
+in your EXINIT,
+and use \fB:n\fP instead of \fB:e\fP.
+.NH 2
+Escaping to a shell
+.PP
+You can get to a shell to execute a single command by giving a
+.I vi
+command of the form \fB:!\fIcmd\fR\s-2CR\s0.
+The system will run the single command
+.I cmd
+and when the command finishes, the editor will ask you to hit a \s-2RETURN\s0
+to continue. When you have finished looking at the output on the screen,
+you should hit \s-2RETURN\s0 and the editor will clear the screen and
+redraw it. You can then continue editing.
+You can also give another \fB:\fR command when it asks you for a \s-2RETURN\s0;
+in this case the screen will not be redrawn.
+.PP
+If you wish to execute more than one command in the shell, then you can
+give the command \fB:sh\fR\s-2CR\s0.
+This will give you a new shell, and when you finish with the shell, ending
+it by typing a \fB^D\fR, the editor will clear the screen and continue.
+.PP
+On systems which support it, \fB^Z\fP will suspend the editor
+and return to the (top level) shell.
+When the editor is resumed, the screen will be redrawn.
+.NH 2
+Marking and returning
+.PP
+The command \fB\(ga\(ga\fR returned to the previous place
+after a motion of the cursor by a command such as \fB/\fR, \fB?\fR or
+\fBG\fR. You can also mark lines in the file with single letter tags
+and return to these marks later by naming the tags. Try marking the
+current line with the command \fBm\fR\fIx\fR, where you should pick some
+letter for \fIx\fR, say `a'. Then move the cursor to a different line
+(any way you like) and hit \fB\(gaa\fR. The cursor will return to the
+place which you marked.
+Marks last only until you edit another file.
+.PP
+When using operators such as
+.B d
+and referring to marked lines, it is often desirable to delete whole lines
+rather than deleting to the exact position in the line marked by \fBm\fR.
+In this case you can use the form \fB\(aa\fR\fIx\fR rather than
+\fB\(ga\fR\fIx\fR. Used without an operator, \fB\(aa\fR\fIx\fR will move to
+the first non-white character of the marked line; similarly \fB\(aa\(aa\fR
+moves to the first non-white character of the line containing the previous
+context mark \fB\(ga\(ga\fR.
+.NH 2
+Adjusting the screen
+.PP
+If the screen image is messed up because of a transmission error to your
+terminal, or because some program other than the editor wrote output
+to your terminal, you can hit a \fB^L\fR, the \s-2ASCII\s0 form-feed
+character, to cause the screen to be refreshed.
+.PP
+On a dumb terminal, if there are @ lines in the middle of the screen
+as a result of line deletion, you may get rid of these lines by typing
+\fB^R\fR to cause the editor to retype the screen, closing up these holes.
+.PP
+Finally, if you wish to place a certain line on the screen at the top
+middle or bottom of the screen, you can position the cursor to that line,
+and then give a \fBz\fR command.
+You should follow the \fBz\fR command with a \s-2RETURN\s0 if you want
+the line to appear at the top of the window, a \fB.\fR if you want it
+at the center, or a \fB\-\fR if you want it at the bottom.
+.NH 1
+Special topics
+.NH 2
+Editing on slow terminals
+.PP
+When you are on a slow terminal, it is important to limit the amount
+of output which is generated to your screen so that you will not suffer
+long delays, waiting for the screen to be refreshed. We have already
+pointed out how the editor optimizes the updating of the screen during
+insertions on dumb terminals to limit the delays, and how the editor erases
+lines to @ when they are deleted on dumb terminals.
+.PP
+The use of the slow terminal insertion mode is controlled by the
+.I slowopen
+option. You can force the editor to use this mode even on faster terminals
+by giving the command \fB:se slow\fR\s-2CR\s0. If your system is sluggish
+this helps lessen the amount of output coming to your terminal.
+You can disable this option by \fB:se noslow\fR\s-2CR\s0.
+.PP
+The editor can simulate an intelligent terminal on a dumb one. Try
+giving the command \fB:se redraw\fR\s-2CR\s0. This simulation generates
+a great deal of output and is generally tolerable only on lightly loaded
+systems and fast terminals. You can disable this by giving the command
+ \fB:se noredraw\fR\s-2CR\s0.
+.PP
+The editor also makes editing more pleasant at low speed by starting
+editing in a small window, and letting the window expand as you edit.
+This works particularly well on intelligent terminals. The editor can
+expand the window easily when you insert in the middle of the screen
+on these terminals. If possible, try the editor on an intelligent terminal
+to see how this works.
+.PP
+You can control the size of the window which is redrawn each time the
+screen is cleared by giving window sizes as argument to the commands
+which cause large screen motions:
+.DS
+.B ": / ? [[ ]] \(ga \(aa"
+.DE
+Thus if you are searching for a particular instance of a common string
+in a file you can precede the first search command by a small number,
+say 3, and the editor will draw three line windows around each instance
+of the string which it locates.
+.PP
+You can easily expand or contract the window, placing the current line
+as you choose, by giving a number on a \fBz\fR command, after the \fBz\fR
+and before the following \s-2RETURN\s0, \fB.\fR or \fB\-\fR. Thus the
+command \fBz5.\fR redraws the screen with the current line in the center
+of a five line window.\*(dg
+.FS
+\*(dg Note that the command \fB5z.\fR has an entirely different effect,
+placing line 5 in the center of a new window.
+.FE
+.PP
+If the editor is redrawing or otherwise updating large portions of the
+display, you can interrupt this updating by hitting a \s-2DEL\s0 or \s-2RUB\s0
+as usual. If you do this you may partially confuse the editor about
+what is displayed on the screen. You can still edit the text on
+the screen if you wish; clear up the confusion
+by hitting a \fB^L\fR; or move or search again, ignoring the
+current state of the display.
+.PP
+See section 7.8 on \fIopen\fR mode for another way to use the
+.I vi
+command set on slow terminals.
+.NH 2
+Options, set, and editor startup files
+.PP
+The editor has a set of options, some of which have been mentioned above.
+The most useful options are given in the following table.
+.KF
+.TS
+lb lb lb lb
+l l l a.
+Name Default Description
+_
+autoindent noai Supply indentation automatically
+autowrite noaw Automatic write before \fB:n\fR, \fB:ta\fR, \fB^\(ua\fR, \fB!\fR
+ignorecase noic Ignore case in searching
+lisp nolisp \fB( { ) }\fR commands deal with S-expressions
+list nolist Tabs print as ^I; end of lines marked with $
+magic nomagic The characters . [ and * are special in scans
+number nonu Lines are displayed prefixed with line numbers
+paragraphs para=IPLPPPQPbpP LI Macro names which start paragraphs
+redraw nore Simulate a smart terminal on a dumb one
+sections sect=NHSHH HU Macro names which start new sections
+shiftwidth sw=8 Shift distance for <, > and input \fB^D\fP and \fB^T\fR
+showmatch nosm Show matching \fB(\fP or \fB{\fP as \fB)\fP or \fB}\fR is typed
+slowopen slow Postpone display updates during inserts
+term dumb The kind of terminal you are using.
+.TE
+.KE
+.PP
+The options are of three kinds: numeric options, string options, and
+toggle options. You can set numeric and string options by a statement
+of the form
+.DS
+\fBset\fR \fIopt\fR\fB=\fR\fIval\fR
+.DE
+and toggle options can be set or unset by statements of one of the forms
+.DS
+\fBset\fR \fIopt\fR
+\fBset\fR \fBno\fR\fIopt\fR
+.DE
+These statements can be placed in your EXINIT in your environment,
+or given while you are running
+.I vi
+by preceding them with a \fB:\fR and following them with a \s-2CR\s0.
+.PP
+You can get a list of all options which you have changed by the
+command \fB:set\fR\s-2CR\s0, or the value of a single option by the
+command \fB:set\fR \fIopt\fR\fB?\fR\s-2CR\s0.
+A list of all possible options and their values is generated by
+\fB:set all\fP\s-2CR\s0.
+Set can be abbreviated \fBse\fP.
+Multiple options can be placed on one line, e.g.
+\fB:se ai aw nu\fP\s-2CR\s0.
+.PP
+Options set by the \fBset\fP command only last
+while you stay in the editor.
+It is common to want to have certain options set whenever you
+use the editor.
+This can be accomplished by creating a list of \fIex\fP commands\*(dg
+.FS
+\*(dg
+All commands which start with
+.B :
+are \fIex\fP commands.
+.FE
+which are to be run every time you start up \fIex\fP, \fIedit\fP,
+or \fIvi\fP.
+A typical list includes a \fBset\fP command, and possibly a few
+\fBmap\fP commands.
+Since it is advisable to get these commands on one line, they can
+be separated with the | character, for example:
+.DS
+\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x
+.DE
+which sets the options \fIautoindent\fP, \fIautowrite\fP, \fIterse\fP,
+(the
+.B set
+command),
+makes @ delete a line,
+(the first
+.B map ),
+and makes # delete a character,
+(the second
+.B map ).
+(See section 6.9 for a description of the \fBmap\fP command)
+This string should be placed in the variable EXINIT in your environment.
+If you use the shell \fIcsh\fP,
+put this line in the file
+.I .login
+in your home directory:
+.DS
+setenv EXINIT \(aa\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x\(aa
+.DE
+If you use the standard shell \fIsh\fP,
+put these lines in the file
+.I .profile
+in your home directory:
+.DS
+EXINIT=\(aa\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x\(aa
+export EXINIT
+.DE
+Of course, the particulars of the line would depend on which options
+you wanted to set.
+.NH 2
+Recovering lost lines
+.PP
+You might have a serious problem if you delete a number of lines and then
+regret that they were deleted. Despair not, the editor saves the last
+9 deleted blocks of text in a set of numbered registers 1\-9.
+You can get the \fIn\fR'th previous deleted text back in your file by
+the command
+"\fR\fIn\fR\|\fBp\fR.
+The "\fR here says that a buffer name is to follow,
+\fIn\fR is the number of the buffer you wish to try
+(use the number 1 for now),
+and
+.B p
+is the put command, which puts text in the buffer after the cursor.
+If this doesn't bring back the text you wanted, hit
+.B u
+to undo this and then
+\fB\&.\fR
+(period)
+to repeat the put command.
+In general the
+\fB\&.\fR
+command will repeat the last change you made.
+As a special case, when the last command refers to a numbered text buffer,
+the \fB.\fR command increments the number of the buffer before repeating
+the command. Thus a sequence of the form
+.DS
+\fB"1pu.u.u.\fR
+.DE
+will, if repeated long enough, show you all the deleted text which has
+been saved for you.
+You can omit the
+.B u
+commands here to gather up all this text in the buffer, or stop after any
+\fB\&.\fR command to keep just the then recovered text.
+The command
+.B P
+can also be used rather than
+.B p
+to put the recovered text before rather than after the cursor.
+.NH 2
+Recovering lost files
+.PP
+If the system crashes, you can recover the work you were doing
+to within a few changes. You will normally receive mail when you next
+login giving you the name of the file which has been saved for you.
+You should then change to the directory where you were when the system
+crashed and give a command of the form:
+.DS
+% \fBvi \-r\fR \fIname\fR
+.DE
+replacing \fIname\fR with the name of the file which you were editing.
+This will recover your work to a point near where you left off.\*(dg
+.FS
+\*(dg In rare cases, some of the lines of the file may be lost. The
+editor will give you the numbers of these lines and the text of the lines
+will be replaced by the string `LOST'. These lines will almost always
+be among the last few which you changed. You can either choose to discard
+the changes which you made (if they are easy to remake) or to replace
+the few lost lines by hand.
+.FE
+.PP
+You can get a listing of the files which are saved for you by giving
+the command:
+.DS
+% \fBvi \-r\fR
+.DE
+If there is more than one instance of a particular file saved, the editor
+gives you the newest instance each time you recover it. You can thus
+get an older saved copy back by first recovering the newer copies.
+.PP
+For this feature to work,
+.I vi
+must be correctly installed by a super user on your system,
+and the
+.I mail
+program must exist to receive mail.
+The invocation ``\fIvi -r\fP'' will not always list all saved files,
+but they can be recovered even if they are not listed.
+.NH 2
+Continuous text input
+.PP
+When you are typing in large amounts of text it is convenient to have
+lines broken near the right margin automatically. You can cause this
+to happen by giving the command
+\fB:se wm=10\fR\s-2CR\s0.
+This causes all lines to be broken at a space at least 10 columns
+from the right hand edge of the screen.
+.PP
+If the editor breaks an input line and you wish to put it back together
+you can tell it to join the lines with \fBJ\fR. You can give \fBJ\fR
+a count of the number of lines to be joined as in \fB3J\fR to join 3
+lines. The editor supplies white space, if appropriate,
+at the juncture of the joined
+lines, and leaves the cursor at this white space.
+You can kill the white space with \fBx\fR if you don't want it.
+.NH 2
+Features for editing programs
+.PP
+The editor has a number of commands for editing programs.
+The thing that most distinguishes editing of programs from editing of text
+is the desirability of maintaining an indented structure to the body of
+the program. The editor has a
+.I autoindent
+facility for helping you generate correctly indented programs.
+.PP
+To enable this facility you can give the command \fB:se ai\fR\s-2CR\s0.
+Now try opening a new line with \fBo\fR and type some characters on the
+line after a few tabs. If you now start another line, notice that the
+editor supplies white space at the beginning of the line to line it up
+with the previous line. You cannot backspace over this indentation,
+but you can use \fB^D\fR key to backtab over the supplied indentation.
+.PP
+Each time you type \fB^D\fR you back up one position, normally to an
+8 column boundary. This amount is settable; the editor has an option
+called
+.I shiftwidth
+which you can set to change this value.
+Try giving the command \fB:se sw=4\fR\s-2CR\s0
+and then experimenting with autoindent again.
+.PP
+For shifting lines in the program left and right, there are operators
+.B <
+and
+.B >.
+These shift the lines you specify right or left by one
+.I shiftwidth.
+Try
+.B <<
+and
+.B >>
+which shift one line left or right, and
+.B <L
+and
+.B >L
+shifting the rest of the display left and right.
+.PP
+If you have a complicated expression and wish to see how the parentheses
+match, put the cursor at a left or right parenthesis and hit \fB%\fR.
+This will show you the matching parenthesis.
+This works also for braces { and }, and brackets [ and ].
+.PP
+If you are editing C programs, you can use the \fB[[\fR and \fB]]\fR keys
+to advance or retreat to a line starting with a \fB{\fR, i.e. a function
+declaration at a time. When \fB]]\fR is used with an operator it stops
+after a line which starts with \fB}\fR; this is sometimes useful with
+\fBy]]\fR.
+.NH 2
+Filtering portions of the buffer
+.PP
+You can run system commands over portions of the buffer using the operator
+\fB!\fR.
+You can use this to sort lines in the buffer, or to reformat portions
+of the buffer with a pretty-printer.
+Try typing in a list of random words, one per line and ending them
+with a blank line. Back up to the beginning of the list, and then give
+the command \fB!}sort\fR\s-2CR\s0. This says to sort the next paragraph
+of material, and the blank line ends a paragraph.
+.NH 2
+Commands for editing \s-2LISP\s0
+.PP
+If you are editing a \s-2LISP\s0 program you should set the option
+.I lisp
+by doing
+\fB:se\ lisp\fR\s-2CR\s0.
+This changes the \fB(\fR and \fB)\fR commands to move backward and forward
+over s-expressions.
+The \fB{\fR and \fB}\fR commands are like \fB(\fR and \fB)\fR but don't
+stop at atoms. These can be used to skip to the next list, or through
+a comment quickly.
+.PP
+The
+.I autoindent
+option works differently for \s-2LISP\s0, supplying indent to align at
+the first argument to the last open list. If there is no such argument
+then the indent is two spaces more than the last level.
+.PP
+There is another option which is useful for typing in \s-2LISP\s0, the
+.I showmatch
+option.
+Try setting it with
+\fB:se sm\fR\s-2CR\s0
+and then try typing a `(' some words and then a `)'. Notice that the
+cursor shows the position of the `(' which matches the `)' briefly.
+This happens only if the matching `(' is on the screen, and the cursor
+stays there for at most one second.
+.PP
+The editor also has an operator to realign existing lines as though they
+had been typed in with
+.I lisp
+and
+.I autoindent
+set. This is the \fB=\fR operator.
+Try the command \fB=%\fR at the beginning of a function. This will realign
+all the lines of the function declaration.
+.PP
+When you are editing \s-2LISP\s0,, the \fB[[\fR and \fR]]\fR advance
+and retreat to lines beginning with a \fB(\fR, and are useful for dealing
+with entire function definitions.
+.NH 2
+Macros
+.PP
+.I Vi
+has a parameterless macro facility, which lets you set it up so that
+when you hit a single keystroke, the editor will act as though
+you had hit some longer sequence of keys. You can set this up if
+you find yourself typing the same sequence of commands repeatedly.
+.PP
+Briefly, there are two flavors of macros:
+.IP a)
+Ones where you put the macro body in a buffer register, say \fIx\fR.
+You can then type \fB@x\fR to invoke the macro. The \fB@\fR may be followed
+by another \fB@\fR to repeat the last macro.
+.IP b)
+You can use the
+.I map
+command from
+.I vi
+(typically in your
+.I EXINIT )
+with a command of the form:
+.DS
+:map \fIlhs\fR \fIrhs\fR\s-2CR\f0
+.DE
+mapping
+.I lhs
+into
+.I rhs.
+There are restrictions:
+.I lhs
+should be one keystroke (either 1 character or one function key)
+since it must be entered within one second
+(unless
+.I notimeout
+is set, in which case you can type it as slowly as you wish,
+and
+.I vi
+will wait for you to finish it before it echoes anything).
+The
+.I lhs
+can be no longer than 10 characters, the
+.I rhs
+no longer than 100.
+To get a space, tab or newline into
+.I lhs
+or
+.I rhs
+you should escape them with a \fB^V\fR.
+(It may be necessary to double the \fB^V\fR if the map
+command is given inside
+.I vi,
+rather than in
+.I ex.)
+Spaces and tabs inside the
+.I rhs
+need not be escaped.
+.PP
+Thus to make the \fBq\fR key write and exit the editor, you can give
+the command
+.DS
+:map q :wq\fB^V^V\fP\s-2CR CR\s0
+.DE
+which means that whenever you type \fBq\fR, it will be as though you
+had typed the four characters \fB:wq\fR\s-2CR\s0.
+A \fB^V\fR's is needed because without it the \s-2CR\s0 would end the
+\fB:\fR command, rather than becoming part of the
+.I map
+definition.
+There are two
+.B ^V 's
+because from within
+.I vi ,
+two
+.B ^V 's
+must be typed to get one.
+The first \s-2CR\s0 is part of the
+.I rhs ,
+the second terminates the : command.
+.PP
+Macros can be deleted with
+.DS
+unmap lhs
+.DE
+.PP
+If the
+.I lhs
+of a macro is ``#0'' through ``#9'', this maps the particular function key
+instead of the 2 character ``#'' sequence. So that terminals without
+function keys can access such definitions, the form ``#x'' will mean function
+key
+.I x
+on all terminals (and need not be typed within one second.)
+The character ``#'' can be changed by using a macro in the usual way:
+.DS
+:map \fB^V^V^I\fP #
+.DE
+to use tab, for example. (This won't affect the
+.I map
+command, which still uses
+.B #,
+but just the invocation from visual mode.
+.PP
+The undo command reverses an entire macro call as a unit,
+if it made any changes.
+.PP
+Placing a `!' after the word
+.B map
+causes the mapping to apply
+to input mode, rather than command mode.
+Thus, to arrange for \fB^T\fP to be the same as 4 spaces in input mode,
+you can type:
+.DS
+:map \fB^T\fP \fB^V\fP\o'b/'\o'b/'\o'b/'\o'b/'
+.DE
+where
+.B \o'b/'
+is a blank.
+The \fB^V\fP is necessary to prevent the blanks from being taken as
+white space between the
+.I lhs
+and
+.I rhs .
+.NH
+Word Abbreviations
+.PP
+A feature similar to macros in input mode is word abbreviation.
+This allows you to type a short word and have it expanded into
+a longer word or words.
+The commands are
+.B :abbreviate
+and
+.B :unabbreviate
+(\fB:ab\fP
+and
+.B :una )
+and have the same syntax as
+.B :map .
+For example:
+.DS
+:ab eecs Electrical Engineering and Computer Sciences
+.DE
+causes the word `eecs' to always be changed into the
+phrase `Electrical Engineering and Computer Sciences'.
+Word abbreviation is different from macros in that
+only whole words are affected.
+If `eecs' were typed as part of a larger word, it would
+be left alone.
+Also, the partial word is echoed as it is typed.
+There is no need for an abbreviation to be a single keystroke,
+as it should be with a macro.
+.NH 2
+Abbreviations
+.PP
+The editor has a number of short
+commands which abbreviate longer commands which we
+have introduced here. You can find these commands easily
+on the quick reference card.
+They often save a bit of typing and you can learn them as convenient.
+.NH 1
+Nitty-gritty details
+.NH 2
+Line representation in the display
+.PP
+The editor folds long logical lines onto many physical lines in the display.
+Commands which advance lines advance logical lines and will skip
+over all the segments of a line in one motion. The command \fB|\fR moves
+the cursor to a specific column, and may be useful for getting near the
+middle of a long line to split it in half. Try \fB80|\fR on a line which
+is more than 80 columns long.\*(dg
+.FS
+\*(dg You can make long lines very easily by using \fBJ\fR to join together
+short lines.
+.FE
+.PP
+The editor only puts full lines on the display; if there is not enough
+room on the display to fit a logical line, the editor leaves the physical
+line empty, placing only an @ on the line as a place holder. When you
+delete lines on a dumb terminal, the editor will often just clear the
+lines to @ to save time (rather than rewriting the rest of the screen.)
+You can always maximize the information on the screen by giving the \fB^R\fR
+command.
+.PP
+If you wish, you can have the editor place line numbers before each line
+on the display. Give the command \fB:se nu\fR\s-2CR\s0 to enable
+this, and the command \fB:se nonu\fR\s-2CR\s0 to turn it off.
+You can have tabs represented as \fB^I\fR and the ends of lines indicated
+with `$' by giving the command \fB:se list\fR\s-2CR\s0;
+\fB:se nolist\fR\s-2CR\s0 turns this off.
+.PP
+Finally, lines consisting of only the character `~' are displayed when
+the last line in the file is in the middle of the screen. These represent
+physical lines which are past the logical end of file.
+.NH 2
+Counts
+.PP
+Most
+.I vi
+commands will use a preceding count to affect their behavior in some way.
+The following table gives the common ways in which the counts are used:
+.DS
+.TS
+l lb.
+new window size : / ? [[ ]] \` \'
+scroll amount ^D ^U
+line/column number z G |
+repeat effect \fRmost of the rest\fP
+.TE
+.DE
+.PP
+The editor maintains a notion of the current default window size.
+On terminals which run at speeds greater than 1200 baud
+the editor uses the full terminal screen.
+On terminals which are slower than 1200 baud
+(most dialup lines are in this group)
+the editor uses 8 lines as the default window size.
+At 1200 baud the default is 16 lines.
+.PP
+This size is the size used when the editor clears and refills the screen
+after a search or other motion moves far from the edge of the current window.
+The commands which take a new window size as count all often cause the
+screen to be redrawn. If you anticipate this, but do not need as large
+a window as you are currently using, you may wish to change the screen
+size by specifying the new size before these commands.
+In any case, the number of lines used on the screen will expand if you
+move off the top with a \fB\-\fR or similar command or off the bottom
+with a command such as \s-2RETURN\s0 or \fB^D\fR.
+The window will revert to the last specified size the next time it is
+cleared and refilled.\*(dg
+.FS
+\*(dg But not by a \fB^L\fR which just redraws the screen as it is.
+.FE
+.PP
+The scroll commands \fB^D\fR and \fB^U\fR likewise remember the amount
+of scroll last specified, using half the basic window size initially.
+The simple insert commands use a count to specify a repetition of the
+inserted text. Thus \fB10a+\-\-\-\-\fR\s-2ESC\s0 will insert a grid-like
+string of text.
+A few commands also use a preceding count as a line or column number.
+.PP
+Except for a few commands which ignore any counts (such as \fB^R\fR),
+the rest of the editor commands use a count to indicate a simple repetition
+of their effect. Thus \fB5w\fR advances five words on the current line,
+while \fB5\fR\s-2RETURN\s0 advances five lines. A very useful instance
+of a count as a repetition is a count given to the \fB.\fR command, which
+repeats the last changing command. If you do \fBdw\fR and then \fB3.\fR,
+you will delete first one and then three words. You can then delete
+two more words with \fB2.\fR.
+.NH 2
+More file manipulation commands
+.PP
+The following table lists the file manipulation commands which you can
+use when you are in
+.I vi.
+.KF
+.DS
+.TS
+lb l.
+:w write back changes
+:wq write and quit
+:x write (if necessary) and quit (same as ZZ).
+:e \fIname\fP edit file \fIname\fR
+:e! reedit, discarding changes
+:e + \fIname\fP edit, starting at end
+:e +\fIn\fP edit, starting at line \fIn\fP
+:e # edit alternate file
+:w \fIname\fP write file \fIname\fP
+:w! \fIname\fP overwrite file \fIname\fP
+:\fIx,y\fPw \fIname\fP write lines \fIx\fP through \fIy\fP to \fIname\fP
+:r \fIname\fP read file \fIname\fP into buffer
+:r !\fIcmd\fP read output of \fIcmd\fP into buffer
+:n edit next file in argument list
+:n! edit next file, discarding changes to current
+:n \fIargs\fP specify new argument list
+:ta \fItag\fP edit file containing tag \fItag\fP, at \fItag\fP
+.TE
+.DE
+.KE
+All of these commands are followed by a \s-2CR\s0 or \s-2ESC\s0.
+The most basic commands are \fB:w\fR and \fB:e\fR.
+A normal editing session on a single file will end with a \fBZZ\fR command.
+If you are editing for a long period of time you can give \fB:w\fR commands
+occasionally after major amounts of editing, and then finish
+with a \fBZZ\fR. When you edit more than one file, you can finish
+with one with a \fB:w\fR and start editing a new file by giving a \fB:e\fR
+command,
+or set
+.I autowrite
+and use \fB:n\fP <file>.
+.PP
+If you make changes to the editor's copy of a file, but do not wish to
+write them back, then you must give an \fB!\fR after the command you
+would otherwise use; this forces the editor to discard any changes
+you have made. Use this carefully.
+.PP
+The \fB:e\fR command can be given a \fB+\fR argument to start at the
+end of the file, or a \fB+\fR\fIn\fR argument to start at line \fIn\fR\^.
+In actuality, \fIn\fR may be any editor command not containing a space,
+usefully a scan like \fB+/\fIpat\fR or \fB+?\fIpat\fR.
+In forming new names to the \fBe\fR command, you can use the character
+\fB%\fR which is replaced by the current file name, or the character
+\fB#\fR which is replaced by the alternate file name.
+The alternate file name is generally the last name you typed other than
+the current file. Thus if you try to do a \fB:e\fR and get a diagnostic
+that you haven't written the file, you can give a \fB:w\fR command and
+then a \fB:e #\fR command to redo the previous \fB:e\fR.
+.PP
+You can write part of the buffer to a file by finding out the lines
+that bound the range to be written using \fB^G\fR, and giving these
+numbers after the \fB:\fR
+and before the \fBw\fP, separated by \fB,\fR's.
+You can also mark these lines with \fBm\fR and
+then use an address of the form \fB\(aa\fR\fIx\fR\fB,\fB\(aa\fR\fIy\fR
+on the \fBw\fR command here.
+.PP
+You can read another file into the buffer after the current line by using
+the \fB:r\fR command.
+You can similarly read in the output from a command, just use \fB!\fR\fIcmd\fR
+instead of a file name.
+.PP
+If you wish to edit a set of files in succession, you can give all the
+names on the command line, and then edit each one in turn using the command
+\fB:n\fR. It is also possible to respecify the list of files to be edited
+by giving the \fB:n\fR command a list of file names, or a pattern to
+be expanded as you would have given it on the initial
+.I vi
+command.
+.PP
+If you are editing large programs, you will find the \fB:ta\fR command
+very useful. It utilizes a data base of function names and their locations,
+which can be created by programs such as
+.I ctags,
+to quickly find a function whose name you give.
+If the \fB:ta\fR command will require the editor to switch files, then
+you must \fB:w\fR or abandon any changes before switching. You can repeat
+the \fB:ta\fR command without any arguments to look for the same tag
+again.
+.NH 2
+More about searching for strings
+.PP
+When you are searching for strings in the file with \fB/\fR and \fB?\fR,
+the editor normally places you at the next or previous occurrence
+of the string. If you are using an operator such as \fBd\fR,
+\fBc\fR or \fBy\fR, then you may well wish to affect lines up to the
+line before the line containing the pattern. You can give a search of
+the form \fB/\fR\fIpat\fR\fB/\-\fR\fIn\fR to refer to the \fIn\fR'th line
+before the next line containing \fIpat\fR, or you can use \fB\+\fR instead
+of \fB\-\fR to refer to the lines after the one containing \fIpat\fR.
+If you don't give a line offset, then the editor will affect characters
+up to the match place, rather than whole lines; thus use ``+0'' to affect
+to the line which matches.
+.PP
+You can have the editor ignore the case of words in the searches it does
+by giving the command \fB:se ic\fR\s-2CR\s0.
+The command \fB:se noic\fR\s-2CR\s0 turns this off.
+.PP
+Strings given to searches may actually be regular expressions.
+If you do not want or need this facility, you should
+.DS
+set nomagic
+.DE
+in your EXINIT.
+In this case,
+only the characters \fB\(ua\fR and \fB$\fR are special in patterns.
+The character \fB\e\fR is also then special (as it is most everywhere in
+the system), and may be used to get at the
+an extended pattern matching facility.
+It is also necessary to use a \e before a
+\fB/\fR in a forward scan or a \fB?\fR in a backward scan, in any case.
+The following table gives the extended forms when \fBmagic\fR is set.
+.DS
+.TS
+bl l.
+\(ua at beginning of pattern, matches beginning of line
+$ at end of pattern, matches end of line
+\fB\&.\fR matches any character
+\e< matches the beginning of a word
+\e> matches the end of a word
+[\fIstr\fP] matches any single character in \fIstr\fP
+[\(ua\fIstr\fP] matches any single character not in \fIstr\fP
+[\fIx\fP\-\fIy\fP] matches any character between \fIx\fP and \fIy\fP
+* matches any number of the preceding pattern
+.TE
+.DE
+If you use \fBnomagic\fR mode, then
+the \fB. [\fR and \fB*\fR primitives are given with a preceding
+\e.
+.NH 2
+More about input mode
+.PP
+There are a number of characters which you can use to make corrections
+during input mode. These are summarized in the following table.
+.DS
+.TS
+lb l.
+^H deletes the last input character
+^W deletes the last input word, defined as by \fBb\fR
+erase your erase character, same as \fB^H\fP
+kill your kill character, deletes the input on this line
+\e escapes a following \fB^H\fP and your erase and kill
+\s-2ESC\s0 ends an insertion
+\s-2DEL\s0 interrupts an insertion, terminating it abnormally
+\s-2CR\s0 starts a new line
+^D backtabs over \fIautoindent\fP
+0^D kills all the \fIautoindent\fP
+\(ua^D same as \fB0^D\fP, but restores indent next line
+^V quotes the next non-printing character into the file
+.TE
+.DE
+.PP
+The most usual way of making corrections to input is by typing \fB^H\fR
+to correct a single character, or by typing one or more \fB^W\fR's to
+back over incorrect words. If you use \fB#\fR as your erase character
+in the normal system, it will work like \fB^H\fR.
+.PP
+Your system kill character, normally \fB@\fR, \fB^X\fP or \fB^U\fR,
+will erase all
+the input you have given on the current line.
+In general, you can neither
+erase input back around a line boundary nor can you erase characters
+which you did not insert with this insertion command. To make corrections
+on the previous line after a new line has been started you can hit \s-2ESC\s0
+to end the insertion, move over and make the correction, and then return
+to where you were to continue. The command \fBA\fR which appends at the
+end of the current line is often useful for continuing.
+.PP
+If you wish to type in your erase or kill character (say # or @) then
+you must precede it with a \fB\e\fR, just as you would do at the normal
+system command level. A more general way of typing non-printing characters
+into the file is to precede them with a \fB^V\fR. The \fB^V\fR echoes
+as a \fB\(ua\fR character on which the cursor rests. This indicates that
+the editor expects you to type a control character. In fact you may
+type any character and it will be inserted into the file at that point.*
+.FS
+* This is not quite true. The implementation of the editor does
+not allow the \s-2NULL\s0 (\fB^@\fR) character to appear in files. Also
+the \s-2LF\s0 (linefeed or \fB^J\fR) character is used by the editor
+to separate lines in the file, so it cannot appear in the middle of a
+line. You can insert any other character, however, if you wait for the
+editor to echo the \fB\(ua\fR before you type the character. In fact,
+the editor will treat a following letter as a request for the corresponding
+control character. This is the only way to type \fB^S\fR or \fB^Q\fP,
+since the system normally uses them to suspend and resume output
+and never gives them to the editor to process.
+.FE
+.PP
+If you are using \fIautoindent\fR you can backtab over the indent which
+it supplies by typing a \fB^D\fR. This backs up to a \fIshiftwidth\fR
+boundary.
+This only works immediately after the supplied \fIautoindent\fR.
+.PP
+When you are using \fIautoindent\fR you may wish to place a label at
+the left margin of a line. The way to do this easily is to type \fB\(ua\fR
+and then \fB^D\fR. The editor will move the cursor to the left margin
+for one line, and restore the previous indent on the next. You can also
+type a \fB0\fR followed immediately by a \fB^D\fR if you wish to kill
+all the indent and not have it come back on the next line.
+.NH 2
+Upper case only terminals
+.PP
+If your terminal has only upper case, you can still use
+.I vi
+by using the normal
+system convention for typing on such a terminal.
+Characters which you normally type are converted to lower case, and you
+can type upper case letters by preceding them with a \e.
+The characters { ~ } | \(ga are not available on such terminals, but you
+can escape them as \e( \e\(ua \e) \e! \e\(aa.
+These characters are represented on the display in the same way they
+are typed.\*(dd
+.FS
+\*(dd The \e character you give will not echo until you type another
+key.
+.FE
+.NH 2
+Vi and ex
+.PP
+.I Vi
+is actually one mode of editing within the editor
+.I ex.
+When you are running
+.I vi
+you can escape to the line oriented editor of
+.I ex
+by giving the command
+\fBQ\fR.
+All of the
+.B :
+commands which were introduced above are available in
+.I ex.
+Likewise, most
+.I ex
+commands can be invoked from
+.I vi
+using :.
+Just give them without the \fB:\fR and follow them with a \s-2CR\s0.
+.PP
+In rare instances, an internal error may occur in
+.I vi.
+In this case you will get a diagnostic and be left in the command mode of
+.I ex.
+You can then save your work and quit if you wish by giving a command
+\fBx\fR after the \fB:\fR which \fIex\fR prompts you with, or you can
+reenter \fIvi\fR by giving
+.I ex
+a
+.I vi
+command.
+.PP
+There are a number of things which you can do more easily in
+.I ex
+than in
+.I vi.
+Systematic changes in line oriented material are particularly easy.
+You can read the advanced editing documents for the editor
+.I ed
+to find out a lot more about this style of editing.
+Experienced
+users often mix their use of
+.I ex
+command mode and
+.I vi
+command mode to speed the work they are doing.
+.NH 2
+Open mode: vi on hardcopy terminals and ``glass tty's''
+\(dd
+.PP
+If you are on a hardcopy terminal or a terminal which does not have a cursor
+which can move off the bottom line, you can still use the command set of
+.I vi,
+but in a different mode.
+When you give a
+.I vi
+command, the editor will tell you that it is using
+.I open
+mode.
+This name comes from the
+.I open
+command in
+.I ex,
+which is used to get into the same mode.
+.PP
+The only difference between
+.I visual
+mode
+and
+.I open
+mode is the way in which the text is displayed.
+.PP
+In
+.I open
+mode the editor uses a single line window into the file, and moving backward
+and forward in the file causes new lines to be displayed, always below the
+current line.
+Two commands of
+.I vi
+work differently in
+.I open:
+.B z
+and
+\fB^R\fR.
+The
+.B z
+command does not take parameters, but rather draws a window of context around
+the current line and then returns you to the current line.
+.PP
+If you are on a hardcopy terminal,
+the
+.B ^R
+command will retype the current line.
+On such terminals, the editor normally uses two lines to represent the
+current line.
+The first line is a copy of the line as you started to edit it, and you work
+on the line below this line.
+When you delete characters, the editor types a number of \e's to show
+you the characters which are deleted. The editor also reprints the current
+line soon after such changes so that you can see what the line looks
+like again.
+.PP
+It is sometimes useful to use this mode on very slow terminals which
+can support
+.I vi
+in the full screen mode.
+You can do this by entering
+.I ex
+and using an
+.I open
+command.
+.LP
+.SH
+Acknowledgements
+.PP
+Bruce Englar encouraged the early development of this display editor.
+Peter Kessler helped bring sanity to version 2's command layout.
+Bill Joy wrote versions 1 and 2.0 through 2.7,
+and created the framework that users see in the present editor.
+Mark Horton added macros and other features and made the
+editor work on a large number of terminals and Unix systems.
diff --git a/usr.bin/vi/docs/USD.doc/vi/vi.summary b/usr.bin/vi/docs/USD.doc/vi/vi.summary
new file mode 100644
index 000000000000..a7d99384dc86
--- /dev/null
+++ b/usr.bin/vi/docs/USD.doc/vi/vi.summary
@@ -0,0 +1,468 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)vi.summary 8.1 (Berkeley) 6/8/93
+.\"
+.ds CH
+.ds CF
+.de TS
+.br
+.if !\\n(1T .RT
+.ul 0
+.ti \\n(.iu
+.if t .sp 0.25
+.if n .sp
+.if \\$1H .TQ
+.nr IX 1
+..
+.nr PS 9
+.ps 9
+.nr VS 11
+.vs 11
+.nr HM .50i
+.nr FM .25i
+.nr PO 0
+.po 0
+.nr LL 3.5i
+.ll 3.5i
+.de nc
+.bp
+..
+.de h
+.LG
+.B
+\\$1
+.R
+.NL
+..
+.LG
+.LG
+.B
+.ce
+Ex Quick Reference
+.R
+.NL
+.LP
+.LP
+.h "Entering/leaving ex"
+.TS
+aw(1.4i)b aw(1.8i).
+% ex \fIname\fP edit \fIname\fP, start at end
+% ex +\fIn\fP \fIname\fP ... at line \fIn\fP
+% ex \-t \fItag\fP start at \fItag\fP
+% ex \-r list saved files
+% ex \-r \fIname\fP recover file \fIname\fP
+% ex \fIname\fP ... edit first; rest via \fB:n\fP
+% ex \-R \fIname\fP read only mode
+: x exit, saving changes
+: q! exit, discarding changes
+.TE
+.h "Ex states"
+.TS
+lw(1i) lw(2.0i).
+Command T{
+Normal and initial state. Input prompted for by \fB:\fP.
+Your kill character cancels partial command.
+T}
+Insert T{
+Entered by \fBa\fP \fBi\fP and \fBc\fP.
+Arbitrary text then terminates with line having only \fB.\fP
+character on it or abnormally with interrupt.
+T}
+Open/visual T{
+Entered by \fBopen\fP or \fBvi\fP, terminates with \fBQ\fP
+or ^\e.
+T}
+.TE
+.h "Ex commands"
+.TS
+lw(.45i) lw(.08i)b lw(.45i) lw(.08i)b lw(.45i) lw(.08i)b.
+abbrev ab next n unabbrev una
+append a number nu undo u
+args ar open o unmap unm
+change c preserve pre version ve
+copy co print p visual vi
+delete d put pu write w
+edit e quit q xit x
+file f read re yank ya
+global g recover rec \fIwindow\fP z
+insert i rewind rew \fIescape\fP !
+join j set se \fIlshift\fP <
+list l shell sh \fIprint next\fP \fRCR\fP
+map source so \fIresubst\fP &
+mark ma stop st \fIrshift\fP >
+move m substitute s \fIscroll\fP ^D
+.TE
+.h "Ex command addresses"
+.TS
+lw(.3i)b lw(0.8i) lw(.3i)b lw(0.8i).
+\fIn\fP line \fIn\fP /\fIpat\fP next with \fIpat\fP
+\&. current ?\fIpat\fP previous with \fIpat\fP
+$ last \fIx\fP-\fIn\fP \fIn\fP before \fIx\fP
++ next \fIx\fP,\fIy\fP \fIx\fP through \fIy\fP
+\- previous \(aa\fIx\fP marked with \fIx\fP
++\fIn\fP \fIn\fP forward \(aa\(aa previous context
+% 1,$
+.TE
+.nc
+.h "Specifying terminal type"
+.TS
+aw(1.7i)b aw(1.5i).
+% setenv TERM \fItype\fP \fIcsh\fP and all version 6
+$ TERM=\fItype\fP; export TERM \fIsh\fP in Version 7
+See also \fItset\fR(1)
+.TE
+.h "Some terminal types"
+.TS
+lw(.4i) lw(.4i) lw(.4i) lw(.4i) lw(.4i).
+2621 43 adm31 dw1 h19
+2645 733 adm3a dw2 i100
+300s 745 c100 gt40 mime
+33 act4 dm1520 gt42 owl
+37 act5 dm2500 h1500 t1061
+4014 adm3 dm3025 h1510 vt52
+.TE
+.h "Initializing options"
+.TS
+lw(.9i)b aw(1.5i).
+EXINIT place \fBset\fP's here in environment var.
+set \fIx\fP enable option
+set no\fIx\fP disable option
+set \fIx\fP=\fIval\fP give value \fIval\fP
+set show changed options
+set all show all options
+set \fIx\fP? show value of option \fIx\fP
+.TE
+.h "Useful options"
+.TS
+lw(.9i)b lw(.3i) lw(1.0i).
+autoindent ai supply indent
+autowrite aw write before changing files
+ignorecase ic in scanning
+lisp \fB( ) { }\fP are s-exp's
+list print ^I for tab, $ at end
+magic \fB. [ *\fP special in patterns
+number nu number lines
+paragraphs para macro names which start ...
+redraw simulate smart terminal
+scroll command mode lines
+sections sect macro names ...
+shiftwidth sw for \fB< >\fP, and input \fB^D\fP
+showmatch sm to \fB)\fP and \fB}\fP as typed
+slowopen slow choke updates during insert
+window visual mode lines
+wrapscan ws around end of buffer?
+wrapmargin wm automatic line splitting
+.TE
+.LP
+.h "Scanning pattern formation"
+.TS
+aw(.9i)b aw(1.0i).
+\(ua beginning of line
+$ end of line
+\fB.\fR any character
+\e< beginning of word
+\e> end of word
+[\fIstr\fP] any char in \fIstr\fP
+[\(ua\fIstr\fP] ... not in \fIstr\fP
+[\fIx\-y\fP] ... between \fIx\fP and \fIy\fP
+* any number of preceding
+.TE
+.nc
+.LP
+.LG
+.LG
+.B
+.ce
+Vi Quick Reference
+.NL
+.R
+.LP
+.LP
+.h "Entering/leaving vi"
+.TS
+aw(1.4i)b aw(1.8i).
+% vi \fIname\fP edit \fIname\fP at top
+% vi +\fIn\fP \fIname\fP ... at line \fIn\fP
+% vi + \fIname\fP ... at end
+% vi \-r list saved files
+% vi \-r \fIname\fP recover file \fIname\fP
+% vi \fIname\fP ... edit first; rest via \fB:n\fP
+% vi \-t \fItag\fP start at \fItag\fP
+% vi +/\fIpat\fP \fIname\fP search for \fIpat\fP
+% view \fIname\fP read only mode
+ZZ exit from vi, saving changes
+^Z stop vi for later resumption
+.TE
+.h "The display"
+.TS
+lw(.75i) lw(2.2i).
+Last line T{
+Error messages, echoing input to \fB: / ?\fP and \fB!\fR,
+feedback about i/o and large changes.
+T}
+@ lines On screen only, not in file.
+~ lines Lines past end of file.
+^\fIx\fP Control characters, ^? is delete.
+tabs Expand to spaces, cursor at last.
+.TE
+.LP
+.h "Vi states"
+.TS
+lw(.75i) lw(2.2i).
+Command T{
+Normal and initial state. Others return here.
+ESC (escape) cancels partial command.
+T}
+Insert T{
+Entered by \fBa i A I o O c C s S\fP \fBR\fP.
+Arbitrary text then terminates with ESC character,
+or abnormally with interrupt.
+T}
+Last line T{
+Reading input for \fB: / ?\fP or \fB!\fP; terminate
+with ESC or CR to execute, interrupt to cancel.
+T}
+.TE
+.h "Counts before vi commands"
+.TS
+lw(1.5i) lw(1.7i)b.
+line/column number z G |
+scroll amount ^D ^U
+replicate insert a i A I
+repeat effect \fRmost rest\fP
+.TE
+.h "Simple commands"
+.TS
+lw(1.5i)b lw(1.7i).
+dw delete a word
+de ... leaving punctuation
+dd delete a line
+3dd ... 3 lines
+i\fItext\fP\fRESC\fP insert text \fIabc\fP
+cw\fInew\fP\fRESC\fP change word to \fInew\fP
+ea\fIs\fP\fRESC\fP pluralize word
+xp transpose characters
+.TE
+.nc
+.h "Interrupting, cancelling"
+.TS
+aw(0.75i)b aw(1.6i).
+ESC end insert or incomplete cmd
+^? (delete or rubout) interrupts
+^L reprint screen if \fB^?\fR scrambles it
+.TE
+.h "File manipulation"
+.TS
+aw(0.75i)b aw(1.6i).
+:w write back changes
+:wq write and quit
+:q quit
+:q! quit, discard changes
+:e \fIname\fP edit file \fIname\fP
+:e! reedit, discard changes
+:e + \fIname\fP edit, starting at end
+:e +\fIn\fR edit starting at line \fIn\fR
+:e # edit alternate file
+^\(ua synonym for \fB:e #\fP
+:w \fIname\fP write file \fIname\fP
+:w! \fIname\fP overwrite file \fIname\fP
+:sh run shell, then return
+:!\fIcmd\fP run \fIcmd\fR, then return
+:n edit next file in arglist
+:n \fIargs\fP specify new arglist
+:f show current file and line
+^G synonym for \fB:f\fP
+:ta \fItag\fP to tag file entry \fItag\fP
+^] \fB:ta\fP, following word is \fItag\fP
+.TE
+.h "Positioning within file"
+.TS
+aw(0.75i)b aw(1.6i).
+^F forward screenfull
+^B backward screenfull
+^D scroll down half screen
+^U scroll up half screen
+G goto line (end default)
+/\fIpat\fR next line matching \fIpat\fR
+?\fIpat\fR prev line matching \fIpat\fR
+n repeat last \fB/\fR or \fB?\fR
+N reverse last \fB/\fR or \fB?\fR
+/\fIpat\fP/+\fIn\fP n'th line after \fIpat\fR
+?\fIpat\fP?\-\fIn\fP n'th line before \fIpat\fR
+]] next section/function
+[[ previous section/function
+% find matching \fB( ) {\fP or \fB}\fP
+.TE
+.h "Adjusting the screen"
+.TS
+aw(0.75i)b aw(1.6i).
+^L clear and redraw
+^R retype, eliminate @ lines
+z\fRCR\fP redraw, current at window top
+z\- ... at bottom
+z\|. ... at center
+/\fIpat\fP/z\- \fIpat\fP line at bottom
+z\fIn\fP\|. use \fIn\fP line window
+^E scroll window down 1 line
+^Y scroll window up 1 line
+.TE
+.nc
+.h "Marking and returning
+.TS
+aw(0.5i)b aw(2.0i).
+\(ga\(ga previous context
+\(aa\(aa ... at first non-white in line
+m\fIx\fP mark position with letter \fIx\fP
+\(ga\fIx\fP to mark \fIx\fP
+\(aa\fIx\fP ... at first non-white in line
+.TE
+.h "Line positioning"
+.TS
+aw(0.5i)b aw(2.0i).
+H home window line
+L last window line
+M middle window line
++ next line, at first non-white
+\- previous line, at first non-white
+\fRCR\fP return, same as +
+\(da \fRor\fP j next line, same column
+\(ua \fRor\fP k previous line, same column
+.TE
+.h "Character positioning"
+.TS
+aw(0.5i)b aw(2.0i).
+\(ua first non white
+0 beginning of line
+$ end of line
+h \fRor\fP \(-> forward
+l \fRor\fP \(<- backwards
+^H same as \fB\(<-\fP
+\fRspace\fP same as \fB\(->\fP
+f\fIx\fP find \fIx\fP forward
+F\fIx\fP \fBf\fR backward
+t\fIx\fP upto \fIx\fP forward
+T\fIx\fP back upto \fIx\fP
+; repeat last \fBf F t\fP or \fBT\fP
+, inverse of \fB;\fP
+| to specified column
+% find matching \fB( { )\fP or \fB}\fR
+.TE
+.h "Words, sentences, paragraphs"
+.TS
+aw(0.5i)b aw(2.0i).
+w word forward
+b back word
+e end of word
+) to next sentence
+} to next paragraph
+( back sentence
+{ back paragraph
+W blank delimited word
+B back \fBW\fP
+E to end of \fBW\fP
+.TE
+.h "Commands for \s-2LISP\s0"
+.TS
+aw(0.5i)b aw(2.0i).
+) Forward s-expression
+} ... but don't stop at atoms
+( Back s-expression
+{ ... but don't stop at atoms
+.TE
+.nc
+.h "Corrections during insert"
+.TS
+aw(.5i)b aw(2.0i).
+^H erase last character
+^W erases last word
+\fRerase\fP your erase, same as \fB^H\fP
+\fRkill\fP your kill, erase input this line
+\e escapes \fB^H\fR, your erase and kill
+\fRESC\fP ends insertion, back to command
+^? interrupt, terminates insert
+^D backtab over \fIautoindent\fP
+\(ua^D kill \fIautoindent\fP, save for next
+0^D ... but at margin next also
+^V quote non-printing character
+.TE
+.h "Insert and replace"
+.TS
+aw(.5i)b aw(2.0i).
+a append after cursor
+i insert before
+A append at end of line
+I insert before first non-blank
+o open line below
+O open above
+r\fIx\fP replace single char with \fIx\fP
+R replace characters
+.TE
+.h "Operators (double to affect lines)"
+.TS
+aw(0.5i)b aw(2.0i).
+d delete
+c change
+< left shift
+> right shift
+! filter through command
+\&\= indent for \s-2LISP\s0
+y yank lines to buffer
+.TE
+.h "Miscellaneous operations"
+.TS
+aw(0.5i)b aw(2.0i).
+C change rest of line
+D delete rest of line
+s substitute chars
+S substitute lines
+J join lines
+x delete characters
+X ... before cursor
+Y yank lines
+.TE
+.h "Yank and put"
+.TS
+aw(0.5i)b aw(2.0i).
+p put back lines
+P put before
+"\fIx\fPp put from buffer \fIx\fP
+"\fIx\fPy yank to buffer \fIx\fP
+"\fIx\fPd delete into buffer \fIx\fP
+.TE
+.h "Undo, redo, retrieve"
+.TS
+aw(0.5i)b aw(2.0i).
+u undo last change
+U restore current line
+\fB.\fP repeat last change
+"\fId\fP\|p retrieve \fId\fP'th last delete
+.TE
diff --git a/usr.bin/vi/docs/bugs.current b/usr.bin/vi/docs/bugs.current
new file mode 100644
index 000000000000..de2b01a6891d
--- /dev/null
+++ b/usr.bin/vi/docs/bugs.current
@@ -0,0 +1,48 @@
+List of known bugs:
+
++ Large numbers of matches (e.g. %, g or v commands), with the
+ ignorecase option set, triggers a memory corruption bug in the
+ regex routines.
+
++ Autoindent doesn't work in the ex editor.
+
++ ^C isn't passed to the shell in the script windows as an interrupt
+ character.
+
++ The command ":ab foo^J bar" prints a usage message -- non-word
+ characters should be quoted in the underlying terminal engine
+ so that the upper-level knows they're quoted and doesn't use them
+ as delimiters. (Note, this isn't historical practice, vi didn't
+ permit escaping of ^J in this type of command.)
+
++ The options edcompatible, hardtabs*, lisp*, optimize*, redraw*,
+ and slowopen* are recognized, but not implemented. Options with
+ an asterisk are unlikely to ever be implemented, so if you want
+ them you might want to say something! I will implement lisp if
+ anyone ever documents how it really worked.
+
++ Screen repainting over slow lines, for some screen changes, is not
+ as good as the historic vi's.
+
++ If an error results during input in ex, it is not displayed until
+ after input mode is exited.
+
++ If the ex append command is used from vi, the input command buffer
+ is overwritten by the ex_append function, causing random errors.
+
++ Colon commands longer than a single line cause the display to be
+ incorrect.
+
++ When switching files in a small screen (O_WINDOW) with :e, the status
+ message isn't displayed.
+
++ The usages of S_{REDRAW,REFORMAT,REFRESH,RENUMBER,RESIZE} are
+ inconsistent, and should be reviewed. In particular, S_REFRESH
+ in any screen redraws all screens.
+
++ Historic vi permitted :g/xxx/vi, i.e. you could execute ex/vi as
+ global commands. Need to review all of the old commands to verify
+ which ones could/could not be used as global commands.
+
++ If you run out of space in the recovery directory, the recovery
+ file is left in place.
diff --git a/usr.bin/vi/docs/changelog b/usr.bin/vi/docs/changelog
new file mode 100644
index 000000000000..5f1e7fded0ca
--- /dev/null
+++ b/usr.bin/vi/docs/changelog
@@ -0,0 +1,138 @@
+1.10 -> 1.11: Thu Mar 24 16:07:45 EST 1994
+ + Change H, M, and L to set the absolute mark, historical practice.
+ + Fix bug in stepping through multiple tags files.
+ + Add "remapmax" option that turns off map counts so you can remap
+ infinitely. If it's off, term_key() can be interrupted from the
+ keyboard, which will cause the buffers to flush. I also dropped
+ the default max number of remaps to 50. (Only Dave Hitz's TM
+ macros and maze appear to go over that limit.)
+ + Change :mkexrc to not dump w{300,1200,9600}, lisp options.
+ + Fix backward search within a line bug.
+ + Change all the includes of "pathnames.h" to use <>'s so that the
+ PORT versions can use -I. to replace it with their own versions.
+ + Make reads and writes interruptible. Rework code that enters and
+ leaves ex for '!' and filter commands, rework all interrupt and
+ timer code.
+ + Fix core dump when user displayed option in .exrc file.
+ + Fix bug where writing empty files didn't update the saved
+ modification time.
+ + Fix bug where /pattern/ addressing was always a backward search.
+ + Fix bug triggered by autoindent of more than 32 characters, where
+ nvi wasn't checking the right TEXT length.
+ + Fix bug where joining only empty lines caused a core dump.
+1.09 -> 1.10: Sat Mar 19 15:40:29 EST 1994
+ + Fix "set all" core dump.
+1.08 -> 1.09: Sat Mar 19 10:11:14 EST 1994
+ + If the tag's file path is relative, and it doesn't exist, check
+ relative to the tag file location.
+ + Fix ~ command to free temporary buffer on error return.
+ + Create vi.ref, a first cut at a reference document for vi.
+ The manual page and the reference document only document the
+ set options, so far.
+ + Fix 1G bug not always going to the first non-blank.
+ + Upgrade PORT/regex to release alpha3.4, from Henry Spencer.
+ + Add MKS vi's "cdpath" option, supporting a cd search path.
+ + Handle if search as a motion was discarded, i.e. "d/<erase>".
+ + Change nvi to not create multiple recovery files if modifying
+ a recovered file.
+ + Decide to ignore that the cursor is before the '$' when inserting
+ in list mode. It's too hard to fix.
+1.07 -> 1.08: Wed Mar 16 07:37:36 EST 1994
+ + Leftright and big line scrolling fixes. This meant more changes
+ to the screen display code, so there may be new problems.
+ + Don't permit search-style addresses until a file has been read.
+ + "c[Ww]" command incorrectly handled the "in whitespace" case.
+ + Fix key space allocation bug triggered by cut/paste under SunOS.
+ + Ex move command got the final cursor position wrong.
+ + Delete "optimize option not implemented" message.
+ + Make the literal-next character turn off mapping for the next
+ character in text input mode.
+1.06 -> 1.07: Mon Mar 14 11:10:33 EST 1994
+ + The "wire down" change in 1.05 broke ex command parsing, there
+ wasn't a corresponding change to handle multiple K_VLNEXT chars.
+ + Fix final position for vi's 't' command.
+1.05 -> 1.06: Sun Mar 13 16:12:52 EST 1994
+ + Wire down ^D, ^H, ^W, and ^V, regardless of the user's termios
+ values.
+ + Add ^D as the ex scroll command.
+ + Support ^Q as a literal-next character.
+ + Rework abbreviations to be delimited by any !inword() character.
+ + Add options description to the manual page.
+ + Minor screen cache fix for svi_get.c.
+ + Rework beautify option support to match historical practice.
+ + Exit immediately if not reading from a tty and a command fails.
+ + Default the SunOS 4.* ports to the distributed curses, not SMI's.
+1.04 -> 1.05: Thu Mar 24 16:07:45 EST 1994
+ + Make cursor keys work in input mode.
+ + Rework screen column code in vi curses screen. MAJOR CHANGE --
+ after this, we'll be debugging curses screen presentation from
+ scratch.
+ + Explode include files in vi.h into the source files.
+1.03 -> 1.04: Sun Mar 6 14:14:16 EST 1994
+ + Make the ex move command keep the marks on the moved lines.
+ + Change resize semantics so you can set the screen size to a
+ specific value. A couple of screen fixes for the resize code.
+ + Fixes for foreground/background due to SIGWINCH.
+ + Complete rework of all of vi's cursor movements. The underlying
+ assumption in the old code was that the starting cursor position
+ was part of the range of lines cut or deleted. The command
+ "d[[" is an example where this isn't true. Change it so that all
+ motion component commands set the final cursor position separately
+ from the range, as it can't be done correctly later. This is a
+ MAJOR CHANGE -- after this change, we'll be debugging the cursor
+ positioning from scratch.
+ + Rewrite the B, b, E, e commands to use vi's getc() interface
+ instead of rolling their own.
+ + Add a second MARK structure, LMARK, which is the larger mark
+ needed by the logging and mark queue code. Everything else uses
+ the reworked MARK structure, which is simply a line/column pair.
+ + Rework cut/delete to not expect 1-past-the-end in the range, but
+ to act on text to the end of the range, inclusive.
+ + Sync on write's, to force NFS to flush.
+1.01 -> 1.03: Sun Jan 23 17:50:35 EST 1994 (PUBLICLY AVAILABLE VERSION)
+ + Tag stack fixes, was returning to the tag, not the position from
+ which the user tagged.
+ + Only use from the cursor to the end of the word in cursor word
+ searches and tags. (Matches historical vi behavior.)
+ + Fix delete-last-line bug when line number option set.
+ + Fix usage line for :split command.
+ + If O_NUMBER set, long input lines would eventually fail, the column
+ count for the second screen of long lines wasn't set correctly.
+ + Fix for [[ reaching SOF with a column longer than the first line.
+ + Fix for multiple error messages if no screen displayed.
+ + Fix :read to set alternate file name as in historical practice.
+ + Fix cut to rotate the numeric buffers if line mode flag set.
+1.00 -> 1.01: Wed Jan 12 13:37:18 EST 1994
+ + Don't put cut items into numeric buffers if cutting less than
+ parts of two lines.
+0.94 -> 1.00: Mon Jan 10 02:27:27 EST 1994
+ + Read-ahead not there; BSD tty driver problem, SunOS curses
+ problem.
+ + Global command could error if it deleted the last line of
+ the file.
+ + Change '.' to only apply to the 'u' if entered immediately
+ after the 'u' command. "1pu.u.u. is still broken, but I
+ expect that it's going to be sacrificed for multiple undo.
+ + If backward motion on a command, now move to the point; get
+ yank cursor positioning correct.
+ + Rework cut buffers to match historic practice -- yank/delete
+ numeric buffers redone sensibly, ignoring historic practice.
+0.92 -> 0.93: Mon Dec 20 19:52:14 EST 1993
+ + Christos Zoulas reimplemented the script windows using pty's,
+ which means that they now work reasonably. The down side of
+ this is that almost all ports other than 4.4BSD need to include
+ two new files, login_tty.c and pty.c from the PORT/clib directory.
+ I've added them to the Makefiles.
+ + All calloc/malloc/realloc functions now cast their pointers, for
+ SunOS -- there should be far fewer warning messages, during the
+ build. The remaining messages are where CHAR_T's meet char *'s,
+ i.e. where 8-bit clean meets strcmp.
+ + The user's argument list handling has been reworked so that there
+ is always a single consistent position for use by :next, :prev and
+ :rewind.
+ + All of the historical options are now at least accepted, although
+ not all of them are implemented. (Edcompatible, hardtabs, lisp,
+ optimize, redraw, and slowopen aren't implemented.)
+ + The RE's have been reworked so that matches of length 0 are handled
+ in the same way as vi used to handle them.
+ + Several more mapping fixes and ex parser addressing fixes.
diff --git a/usr.bin/vi/docs/features b/usr.bin/vi/docs/features
new file mode 100644
index 000000000000..ee07857fdab1
--- /dev/null
+++ b/usr.bin/vi/docs/features
@@ -0,0 +1,47 @@
+List of things that should be added at some point:
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
++ X11 interface.
+
++ Forms editing package; use RE's to verify field contents.
+
++ Internationalization, including wide character support.
+
++ Make db, curses real libraries that we load against instead of
+ compiling directly.
+
++ Add a ":resize =N" command, that sets the window to a specific
+ size.
+
+List of suggested features:
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
++ Change tags to also attempt to find the file using the directory
+ where it found the tags file.
+
++ Add versioning based on a "set version" variable, that would
+ create backup copies when the file was written back, i.e. the
+ ":w" and autowrite's would copy the original.
+
++ Add "set searchdir" for a list of directories to look in for
+ files to edit. The semantic is that ":e foo" is replaced with
+ the file name that is found, so there's no confusion as to
+ which file is written.
+
++ Change
+ :di[splay] tags -> :tags
+ :di[splay] screens -> :screens
+ :di[splay] buffers -> :buffers
+
++ A macro record function. Add the ability to record a sequence
+ of keystrokes into a named buffer for later use. Handy when
+ you're trying to build a semi-complex macro.
+
++ Put multiple messages on a single line if they fit in their entirety,
+ so that ":n" with autowrite set doesn't force users to hit return to
+ get see both the "written" and "new file status" messages.
+
++ The semantics of :split, :bg, and :fg aren't right. Someone needs to
+ rethink how they should interact. The main problem arises when users
+ want to get a window into a new file. Currently, the necessary sequence
+ is ":split newfile|^W|:bg". It would be nice if you could simply
+ background the current screen and edit a new one.
diff --git a/usr.bin/vi/docs/internals/autowrite b/usr.bin/vi/docs/internals/autowrite
new file mode 100644
index 000000000000..55cd13b8f72e
--- /dev/null
+++ b/usr.bin/vi/docs/internals/autowrite
@@ -0,0 +1,88 @@
+# @(#)autowrite 8.2 (Berkeley) 9/28/93
+
+Vi autowrite behavior, the fields with *'s are "don't cares".
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Commands that are affected only by autowrite:
+
+Command File Autowrite? Action:
+ modified?
+-----------------------------------------------
+^Z Y Y Write file and suspend.
+^Z Y N Suspend.
+^Z N * Suspend.
+
+# This behavior is NOT identical to :edit.
+^ Y Y Write file and jump.
+^ Y N Error.
+^ N * Jump.
+
+# The new nvi command ^T (:tagpop) behaves identically to ^].
+# This behavior is identical to :tag, :tagpop, and :tagpush with
+# force always set to N.
+^] Y Y Write file and jump.
+^] Y N Error.
+^] N * Jump.
+
+# There's no way to specify a force flag to the '!' command.
+:! Y Y Write file and execute.
+:! Y N Warn (if warn option) and execute.
+:! N * Execute.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Commands that are affected by both autowrite and force:
+
+NOTE: the "force" flag is never passed on, i.e. the write
+to the file caused by the autowrite flag is never forced.
+
+Command File Autowrite? Force? Action:
+ modified? (!)
+-------------------------------------------------------
+# The first rule (YYY) is historic practice, but seems wrong.
+# In nvi, :next and :prev commands behave identically to :rewind.
+:next Y Y Y Write changes and jump.
+:next Y Y N Write changes and jump.
+:next Y N Y Abandon changes and jump.
+:next Y N N Error.
+:next N * * Jump.
+
+:rewind Y Y Y Abandon changes and jump.
+:rewind Y Y N Write changes and jump.
+:rewind Y N Y Abandon changes and jump.
+:rewind Y N N Error.
+:rewind N * * Jump.
+
+# The new nvi commands, :tagpop and :tagtop, behave identically to :tag.
+# Note, this behavior is the same as :rewind and friends, as well.
+:tag Y Y Y Abandon changes and jump.
+:tag Y Y N Write changes and jump.
+:tag Y N Y Abandon changes and jump.
+:tag Y N N Error.
+:tag N * * Jump.
+
+# The command :suspend behaves identically to :stop.
+:stop Y Y Y Suspend.
+:stop Y Y N Write changes and suspend.
+:stop Y N Y Suspend.
+:stop Y N N Suspend.
+:stop N * * Suspend.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Commands that might be affected by autowrite, but aren't:
+
+Command File Autowrite? Force? Action:
+ modified? (!)
+-------------------------------------------------------
+#:ex, and :vi (executed while in vi mode) behave identically to :edit.
+:edit Y * Y Abandon changes and jump.
+:edit Y * N Error.
+:edit N * * Jump.
+
+:quit Y * Y Quit.
+:quit Y * N Error.
+:quit N * * Quit.
+
+:shell * * * Execute shell.
+
+:xit Y * * Write changes and exit.
+:xit N * * Exit.
diff --git a/usr.bin/vi/docs/internals/gdb.script b/usr.bin/vi/docs/internals/gdb.script
new file mode 100644
index 000000000000..5f180edcd642
--- /dev/null
+++ b/usr.bin/vi/docs/internals/gdb.script
@@ -0,0 +1,68 @@
+# @(#)gdb.script 8.2 (Berkeley) 9/29/93
+
+# display the SVI screen map
+# usage dmap(sp)
+define dmap
+ set $h = ((SVI_PRIVATE *)$arg0->svi_private)->h_smap
+ set $t = ((SVI_PRIVATE *)$arg0->svi_private)->t_smap
+ while ($h <= $t)
+ printf "lno: %d; off %d ", (int)$h->lno, (int)$h->off
+ if ($h->c_ecsize == 0)
+ printf "flushed\n"
+ else
+ printf "\n\tsboff %d; scoff %d\n", \
+ (int)$h->c_sboff, (int)$h->c_scoff
+ printf "\teboff %d; eclen %d; ecsize %d\n", \
+ (int)$h->c_eboff, (int)$h->c_eclen, \
+ (int)$h->c_ecsize
+ end
+ set $h = $h + 1
+ end
+end
+
+# display the tail of the SVI screen map
+define tmap
+ set $h = ((SVI_PRIVATE *)$arg0->svi_private)->h_smap
+ set $t = ((SVI_PRIVATE *)$arg0->svi_private)->t_smap
+ while ($t >= $h)
+ printf "lno: %d; off %d ", (int)$t->lno, (int)$t->off
+ if ($t->c_ecsize == 0)
+ printf "flushed\n"
+ else
+ printf "\n\tsboff %d; scoff %d\n", \
+ (int)$t->c_sboff, (int)$t->c_scoff
+ printf "\teboff %d; eclen %d; ecsize %d\n", \
+ (int)$t->c_eboff, (int)$t->c_eclen, \
+ (int)$t->c_ecsize
+ end
+ set $t = $t - 1
+ end
+end
+
+# display the SVI private structure
+define svp
+ print *((SVI_PRIVATE *)sp->svi_private)
+end
+
+# display the marks
+define markp
+ set $h = sp->ep->marks.next
+ set $t = &sp->ep->marks
+ while ($h != 0 && $h != $t)
+ printf "key %c lno: %d cno: %d flags: %x\n", \
+ ((MARK *)$h)->name, ((MARK *)$h)->lno, \
+ ((MARK *)$h)->cno, ((MARK *)$h)->flags
+ set $h = ((MARK *)$h)->next
+ end
+end
+
+# display the tags
+define tagp
+ set $h = sp->taghdr.next
+ set $t = &sp->taghdr
+ while ($h != 0 && $h != $t)
+ printf "tag: %s lno %d cno %d\n", ((TAG *)$h)->frp->fname, \
+ ((TAG *)$h)->lno, ((TAG *)$h)->cno
+ set $h= ((TAG *)$h)->next
+ end
+end
diff --git a/usr.bin/vi/docs/internals/input b/usr.bin/vi/docs/internals/input
new file mode 100644
index 000000000000..f5aa80c7aa8e
--- /dev/null
+++ b/usr.bin/vi/docs/internals/input
@@ -0,0 +1,314 @@
+# @(#)input 5.4 (Berkeley) 8/26/93
+
+MAPS, EXECUTABLE BUFFERS AND INPUT IN EX/VI:
+
+The basic rule is that input in ex/vi is a stack. Every time a key which
+gets expanded is encountered, it is expanded and the expansion is treated
+as if it were input from the user. So, maps and executable buffers are
+simply pushed onto the stack from which keys are returned. The exception
+is that if the "remap" option is turned off, only a single map expansion
+is done. I intend to be fully backward compatible with this.
+
+Historically, if the mode of the editor changed (ex to vi or vice versa),
+any queued input was silently discarded. I don't see any reason to either
+support or not support this semantic. I intend to retain the queued input,
+mostly because it's simpler than throwing it away.
+
+Historically, neither the initial command on the command line (the + flag)
+or the +cmd associated with the ex and edit commands was subject to mapping.
+Also, while the +cmd appears to be subject to "@buffer" expansion, once
+expanded it doesn't appear to work correctly. I don't see any reason to
+either support or not support these semantics, so, for consistency, I intend
+to pass both the initial command and the command associated with ex and edit
+commands through the standard mapping and @ buffer expansion.
+
+One other difference between the historic ex/vi and nex/nvi is that nex
+displays the executed buffers as it executes them. This means that if
+the file is:
+
+ set term=xterm
+ set term=yterm
+ set term=yterm
+
+the user will see the following during a typical edit session:
+
+ nex testfile
+ testfile: unmodified: line 3
+ :1,$yank a
+ :@a
+ :set term=zterm
+ :set term=yterm
+ :set term=xterm
+ :q!
+
+This seems like a feature and unlikely to break anything, so I don't
+intend to match historic practice in this area.
+
+The rest of this document is a set of conclusions as to how I believe
+the historic maps and @ buffers work. The summary is as follows:
+
+1: For buffers that are cut in "line mode", or buffers that are not cut
+ in line mode but which contain portions of more than a single line, a
+ trailing <newline> character appears in the input for each line in the
+ buffer when it is executed. For buffers not cut in line mode and which
+ contain portions of only a single line, no additional characters
+ appear in the input.
+2: Executable buffers that execute other buffers don't load their
+ contents until they execute them.
+3: Maps and executable buffers are copied when they are executed --
+ they can be modified by the command but that does not change their
+ actions.
+4: Historically, executable buffers are discarded if the editor
+ switches between ex and vi modes.
+5: Executable buffers inside of map commands are expanded normally.
+ Maps inside of executable buffers are expanded normally.
+6: If an error is encountered while executing a mapped command or buffer,
+ the rest of the mapped command/buffer is discarded. No user input
+ characters are discarded.
+
+Individual test cases follow. Note, in the test cases, control characters
+are not literal and will have to be replaced to make the test cases work.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+1: For buffers that are cut in "line mode", or buffers that are not cut
+ in line mode but which contain portions of more than a single line, a
+ trailing <newline> character appears in the input for each line in the
+ buffer when it is executed. For buffers not cut in line mode and which
+ contain portions of only a single line, no additional characters
+ appear in the input.
+
+=== test file ===
+3Gw
+w
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+=== end test file ===
+
+ If the first line is loaded into 'a' and executed:
+
+1G"ayy@a
+
+ The cursor ends up on the '2', a result of pushing "3Gw^J" onto
+ the stack.
+
+ If the first two lines are loaded into 'a' and executed:
+
+1G2"ayy@a
+
+ The cursor ends up on the 'f' in "foo" in the fifth line of the
+ file, a result of pushing "3Gw^Jw^J" onto the stack.
+
+ If the first line is loaded into 'a', but not using line mode,
+ and executed:
+
+1G"ay$@a
+
+ The cursor ends up on the '1', a result of pushing "3Gw" onto
+ the stack
+
+ If the first two lines are loaded into 'a', but not using line mode,
+ and executed:
+
+1G2"ay$@a
+
+ The cursor ends up on the 'f' in "foo" in the fifth line of the
+ file, a result of pushing "3Gw^Jw^J" onto the stack.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+2: Executable buffers that execute other buffers don't load their
+ contents until they execute them.
+
+=== test file ===
+cwLOAD B^[
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+@a@b
+"byy
+=== end test file ===
+
+ The command is loaded into 'e', and then executed. 'e' executes
+ 'a', which loads 'b', then 'e' executes 'b'.
+
+5G"eyy6G"ayy1G@e
+
+ The output should be:
+
+=== output file ===
+cwLOAD B^[
+LOAD B 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+@a@b
+"byy
+=== end output file ===
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+3: Maps and executable buffers are copied when they are executed --
+ they can be modified by the command but that does not change their
+ actions.
+
+ Executable buffers:
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+@a@b
+"eyy
+cwEXECUTE B^[
+=== end test file ===
+
+4G"eyy5G"ayy6G"byy1G@eG"ep
+
+ The command is loaded into 'e', and then executed. 'e' executes
+ 'a', which loads 'e', then 'e' executes 'b' anyway.
+
+ The output should be:
+
+=== output file ===
+line 1 foo bar baz
+EXECUTE B 2 foo bar baz
+line 3 foo bar baz
+@a@b
+"eyy
+cwEXECUTE B^[
+line 1 foo bar baz
+=== end output file ===
+
+ Maps:
+
+=== test file ===
+Cine 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+=== end test file ===
+
+ Entering the command ':map = :map = rB^V^MrA^M1G==' shows that
+ the first time the '=' is entered the '=' map is set and the
+ character is changed to 'A', the second time the character is
+ changed to 'B'.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+4: Historically, executable buffers are discarded if the editor
+ switches between ex and vi modes.
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+cwCHANGE^[Q:set
+set|visual|1Gwww
+=== end test file ===
+
+vi testfile
+4G"ayy@a
+
+ex testfile
+$p
+yank a
+@a
+
+ In vi, the command is loaded into 'a' and then executed. The command
+ subsequent to the 'Q' is (historically, silently) discarded.
+
+ In ex, the command is loaded into 'a' and then executed. The command
+ subsequent to the 'visual' is (historically, silently) discarded. The
+ first set command is output by ex, although refreshing the screen usually
+ causes it not to be seen.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+5: Executable buffers inside of map commands are expanded normally.
+ Maps inside of executable buffers are expanded normally.
+
+ Buffers inside of map commands:
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+cwREPLACE BY A^[
+=== end test file ===
+
+4G"ay$:map x @a
+1Gx
+
+ The output should be:
+
+=== output file ===
+REPLACE BY A 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+cwREPLACE BY A^[
+=== end output file ===
+
+ Maps commands inside of executable buffers:
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+X
+=== end test file ===
+
+:map X cwREPLACE BY XMAP^[
+4G"ay$1G@a
+
+ The output should be:
+
+=== output file ===
+REPLACE BY XMAP 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+X
+=== end output file ===
+
+ Here's a test that does both, repeatedly.
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+X
+Y
+cwREPLACED BY C^[
+blank line
+=== end test file ===
+
+:map x @a
+4G"ay$
+:map X @b
+5G"by$
+:map Y @c
+6G"cy$
+1Gx
+
+ The output should be:
+
+=== output file ===
+REPLACED BY C 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+X
+Y
+cwREPLACED BY C^[
+blank line
+=== end output file ===
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+6: If an error is encountered while executing a mapped command or
+ a buffer, the rest of the mapped command/buffer is discarded. No
+ user input characters are discarded.
+
+=== test file ===
+line 1 foo bar baz
+line 2 foo bar baz
+line 3 foo bar baz
+:map = 10GcwREPLACMENT^V^[^[
+=== end test file ===
+
+ The above mapping fails, however, if the 10G is changed to 1, 2,
+ or 3G, it will succeed.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
diff --git a/usr.bin/vi/docs/internals/quoting b/usr.bin/vi/docs/internals/quoting
new file mode 100644
index 000000000000..f20bd3f2b1e9
--- /dev/null
+++ b/usr.bin/vi/docs/internals/quoting
@@ -0,0 +1,219 @@
+# @(#)quoting 5.4 (Berkeley) 8/20/93
+
+QUOTING IN EX/VI:
+
+There are two escape characters in historic ex/vi, ^V (or whatever
+character the user specified as their literal next character) and
+backslashes. There are two different areas in ex/vi where escaping
+is interesting: the command and text input modes, and within the ex
+commands themselves. In the examples below, ^V is used as the
+typical literal next character.
+
+1: Escaping characters in ex and vi command and text input modes.
+ The set of characters that users might want to escape are as
+ follows:
+
+ vi text input mode (a, i, o, etc.):
+
+ carriage return (^M)
+ escape (^[)
+ autoindent characters
+ (^D, 0, ^, ^T)
+ erase, word erase, and line erase
+ (^H, ^W, ^U)
+ newline (^J) (not historic practice)
+ suspend (^Z) (not historic practice)
+ repaint (^L) (not historic practice)
+
+ vi command line (:colon commands):
+
+ carriage return (^M)
+ escape (^[)
+ erase, word erase, and line erase
+ (^H, ^W, ^U)
+ newline (^J) (not historic practice)
+ suspend (^Z) (not historic practice)
+ repaint (^L) (not historic practice)
+
+ ex text input mode (a, i, o, etc.):
+
+ carriage return (^M)
+ erase, word erase, and line erase
+ (^H, ^W, ^U)
+ newline (^J) (not historic practice)
+
+ ex command line:
+
+ carriage return (^M)
+ erase, word erase, and line erase
+ (^H, ^W, ^U)
+ newline (^J) (not historic practice)
+ suspend (^Z)
+
+ I intend to follow historic practice for all of these cases, which
+ was that ^V was the only way to escape any of these characters, and
+ that whatever character followed the ^V was taken literally, i.e.
+ ^V^V is a single ^V.
+
+ The historic ex/vi disallowed the insertion of various control
+ characters (^D, ^T, whatever) during various different modes, or,
+ permitted the insertion of only a single one, or lots of other random
+ behaviors (you can use ^D to enter a command in ex). I have
+ regularized this behavior in nvi, there are no characters that cannot
+ be entered or which have special meaning other than the ones listed
+ above.
+
+ One comment regarding the autoindent characters. In historic vi,
+ if you entered "^V0^D" autoindent erasure was still triggered,
+ although it wasn't if you entered "0^V^D". In nvi, if you escape
+ either character, autoindent erasure is not triggered.
+
+ This doesn't permit whitespace in command names, but that wasn't
+ historic practice and doesn't seem worth doing.
+
+ Fun facts to know and tell:
+ The historic vi implementation for the 'r' command requires
+ *three* ^V's to replace a single character with ^V.
+
+2: Ex commands:
+
+ Ex commands are delimited by '|' or newline characters. Within
+ the commands, whitespace characters delimit the arguments.
+
+ I intend to treat ^V, followed by any character, as that literal
+ character.
+
+ This is historic behavior in vi, although there are special
+ cases where it's impossible to escape a character, generally
+ a whitespace character.
+
+3: Escaping characters in file names in ex commands:
+
+ :cd [directory] (directory)
+ :chdir [directory] (directory)
+ :edit [+cmd] [file] (file)
+ :ex [+cmd] [file] (file)
+ :file [file] (file)
+ :next [file ...] (file ...)
+ :read [!cmd | file] (file)
+ :source [file] (file)
+ :write [!cmd | file] (file)
+ :wq [file] (file)
+ :xit [file] (file)
+
+ I intend to treat a backslash in a file name, followed by any
+ character, as that literal character.
+
+ This is historic behavior in vi.
+
+ In addition, since file names are also subject to word expansion,
+ the rules for escape characters in section 3 of this document also
+ apply. This is NOT historic behavior in vi, making it impossible
+ to insert a whitespace, newline or carriage return character into
+ a file name. This change could cause a problem if there were files
+ with ^V's in their names, but I think that's unlikely.
+
+4: Escaping characters in non-file arguments in ex commands:
+
+ :abbreviate word string (word, string)
+* :edit [+cmd] [file] (+cmd)
+* :ex [+cmd] [file] (+cmd)
+ :k key (key)
+ :map word string (word, string)
+ :mark key (key)
+* :set [option ...] (option)
+* :tag string (string)
+ :unabbreviate word (word)
+ :unmap word (word)
+
+ These commands use whitespace to delimit their arguments, and use
+ ^V to escape those characters. The exceptions are starred in the
+ above list, and are discussed below.
+
+ In general, I intend to treat a ^V in any argument, followed by
+ any character, as that literal character. This will permit
+ editing of files name "foo|", for example, by using the string
+ "foo\^V|", where the literal next character protects the pipe
+ from the ex command parser and the backslash protects it from the
+ shell expansion.
+
+ This is backward compatible with historical vi, although there
+ were a number of special cases where vi wasn't consistent.
+
+4.1: The edit/ex commands:
+
+ The edit/ex commands are a special case because | symbols may
+ occur in the "+cmd" field, for example:
+
+ :edit +10|s/abc/ABC/ file.c
+
+ In addition, the edit and ex commands have historically ignored
+ literal next characters in the +cmd string, so that the following
+ command won't work.
+
+ :edit +10|s/X/^V / file.c
+
+ I intend to handle the literal next character in edit/ex consistently
+ with how it is handled in other commands.
+
+ More fun facts to know and tell:
+ The acid test for the ex/edit commands:
+
+ date > file1; date > file2
+ vi
+ :edit +1|s/./XXX/|w file1| e file2|1 | s/./XXX/|wq
+
+ No version of vi, of which I'm aware, handles it.
+
+4.2: The set command:
+
+ The set command treats ^V's as literal characters, so the following
+ command won't work. Backslashes do work in this case, though, so
+ the second version of the command does work.
+
+ set tags=tags_file1^V tags_file2
+ set tags=tags_file1\ tags_file2
+
+ I intend to continue permitting backslashes in set commands, but
+ to also permit literal next characters to work as well. This is
+ backward compatible, but will also make set consistent with the
+ other commands. I think it's unlikely to break any historic
+ .exrc's, given that there are probably very few files with ^V's
+ in their name.
+
+4.3: The tag command:
+
+ The tag command ignores ^V's and backslashes; there's no way to
+ get a space into a tag name.
+
+ I think this is a don't care, and I don't intend to fix it.
+
+5: Regular expressions:
+
+ :global /pattern/ command
+ :substitute /pattern/replace/
+ :vglobal /pattern/ command
+
+ I intend to treat a backslash in the pattern, followed by the
+ delimiter character or a backslash, as that literal character.
+
+ This is historic behavior in vi. It would get rid of a fairly
+ hard-to-explain special case if we could just use the character
+ immediately following the backslash in all cases, or, if we
+ changed nvi to permit using the literal next character as a
+ pattern escape character, but that would probably break historic
+ scripts.
+
+ There is an additional escaping issue for regular expressions.
+ Within the pattern and replacement, the '|' character did not
+ delimit ex commands. For example, the following is legal.
+
+ :substitute /|/PIPE/|s/P/XXX/
+
+ This is a special case that I will support.
+
+6: Ending anything with an escape character:
+
+ In all of the above rules, an escape character (either ^V or a
+ backslash) at the end of an argument or file name is not handled
+ specially, but used as a literal character.
diff --git a/usr.bin/vi/docs/internals/structures b/usr.bin/vi/docs/internals/structures
new file mode 100644
index 000000000000..d49ab65cbeed
--- /dev/null
+++ b/usr.bin/vi/docs/internals/structures
@@ -0,0 +1,61 @@
+# @(#)structures 5.2 (Berkeley) 11/1/93
+
+There are three major data structures in this package. The first is a
+single global structure (named GS) which contains information common to
+all files and screens. It's really pretty tiny, and functions more as a
+single place to hang things than anything else.
+
+The second and third structures are the file structures (named EXF) and
+the screen structures (named SCR). They contain information theoretically
+unique to a screen or file, respectively. Each SCR structure has a set
+of functions which update the screen and/or return information about the
+screen from the underlying screen package.
+
+The GS structure contains linked lists SCR structures. The structures
+can also be classed by persistence. The GS structure never goes away
+and the SCR structure persists over instances of files.
+
+File names have different properties than files themselves, so the name
+information for a file is held in an FREF structure which is chained from
+the SCR structure.
+
+In general, functions are always passed an SCR structure and often an EXF
+structure as well. The SCR structure is necessary for any routine that
+wishes to talk to the screen, the EXF structure is necessary for any
+routine that wants to modify the file. The relationship between an SCR
+structure and its underlying EXF structure is not fixed, and although you
+can translate from an SCR to the underlying EXF, it is discouraged. If
+this becomes too onerous, I suspect I'll just stop passing around the EXF
+in the future.
+
+The naming of the structures is consistent across the program. (Macros
+even depend on it, so don't try and change it!) The global structure is
+"gp", the screen structure is "sp", and the file structure is "ep".
+
+A few other data structures:
+
+TEXT In nvi/cut.h. This structure describes a portion of a line,
+ and is used by the input routines and as the "line" part of a
+ cut buffer.
+
+CB In nvi/cut.h. A cut buffer. A cut buffer is a place to
+ hang a list of TEXT structures.
+
+MARK In nvi/mark.h. A cursor position, consisting of a line number
+ and a column number.
+
+MSG In nvi/msg.h. A chain of messages for the user.
+
+SEQ In nvi/seq.h. An abbreviation or a map entry.
+
+EXCMDARG
+ In nvi/ex/excmd.h.stub. The structure that gets passed around
+ to the functions that implement the ex commands. (The main
+ ex command loop (see nvi/ex/ex.c) builds this up and then passes
+ it to the ex functions.)
+
+VICMDARG
+ In nvi/vi/vcmd.h. The structure that gets passed around to the
+ functions that implement the vi commands. (The main vi command
+ loop (see nvi/vi/vi.c) builds this up and then passes it to the
+ vi functions.)
diff --git a/usr.bin/vi/docs/set.opt.roff b/usr.bin/vi/docs/set.opt.roff
new file mode 100644
index 000000000000..e39dc810d1d7
--- /dev/null
+++ b/usr.bin/vi/docs/set.opt.roff
@@ -0,0 +1,1065 @@
+.\" Copyright (c) 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)set.opt.roff 8.5 (Berkeley) 3/22/94
+.\"
+There are a large number of options that may be set (or unset) to
+change the editor's behavior.
+This section describes the options, their abbreviations and their
+default values.
+.Pp
+In each entry below, the first part of the tag line is the full name
+of the option, followed by any equivalent abbreviations.
+#ifdef REFERENCE
+(Regardless of the abbreviations, it is only necessary to use the
+minimum number of characters necessary to distinguish an abbreviation
+from all other commands for it to be accepted, in
+.Nm nex/nvi .
+Historically, only the full name and the official abbreviations
+were accepted by
+.Nm ex/vi .
+Using full names in your startup files and environmental variables will
+probably make them more portable.)
+#endif
+The part in square brackets is the default value of the option.
+Most of the options are boolean, i.e. they are either on or off,
+and do not have an associated value.
+.Pp
+Options apply to both
+.Nm \&ex
+and
+.Nm \&vi
+modes, unless otherwise specified.
+#ifdef REFERENCE
+.Pp
+For information on modifying the options or to display the options and
+their current values, see the
+.Dq set
+command in the Ex Commands section.
+#endif
+.Bl -tag -width "XXXX" -compact
+.It Li "altwerase [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Select an alternate word erase algorithm.
+#endif
+#ifdef REFERENCE
+Change how
+.Nm \&vi
+does word erase during text input.
+When this option is set, text is broken up into three classes:
+alphabetic, numeric and underscore characters, other non-blank
+characters, and blank characters.
+Changing from one class to another marks the end of a word.
+In addition, the class of the first character erased is ignored
+(which is exactly what you want when erasing pathname components).
+#endif
+.It Li "autoindent, ai [off]"
+#ifdef MANUAL
+Automatically indent new lines.
+#endif
+#ifdef REFERENCE
+If this option is set, whenever you create a new line (using the
+.Nm \&vi
+.Sy \&A ,
+.Sy \&a ,
+.Sy \&C ,
+.Sy \&c ,
+.Sy \&I ,
+.Sy \&i ,
+.Sy \&O ,
+.Sy \&o ,
+.Sy \&R ,
+.Sy \&r ,
+.Sy \&S ,
+and
+.Sy \&s
+commands, or the
+.Nm \&ex
+.Sy append ,
+.Sy change ,
+and
+.Sy insert
+commands) the new line is automatically indented to align the cursor with
+the first non-blank character of the line from which you created it.
+Lines are indented using tab characters to the extent possible (based on
+the value of the
+.Sy tabstop
+option) and then using space characters as necessary.
+For commands inserting text into the middle of a line, any blank characters
+to the right of the cursor are discarded, and the first non-blank character
+to the right of the cursor is aligned as described above.
+.Pp
+The indent characters are themselves somewhat special.
+If you do not enter more characters on the new line before moving moving to
+another line, or entering <escape>, the indent character will be deleted and
+the line will be empty.
+For example, if you enter <carriage-return> twice in succession, the line
+created by the first <carriage-return> will not have any characters in it,
+regardless of the indentation of the previous or subsequent line.
+.Pp
+Indent characters also require that you enter additional erase characters
+to delete them.
+For example, if you have an indented line, containing only blanks, the first
+<word-erase> character you enter will erase up to end of the indent characters,
+and the second will erase back to the beginning of the line.
+(Historically, only the
+.Sy \&^D
+key would erase the indent characters.
+Both the
+.Sy \&^D
+key and the usual erase keys work in
+.Nm nvi .)
+In addition, if the cursor is positioned at the end of the indent
+characters, the keys
+.Dq 0^D
+will erase all of the indent characters for the current line,
+resetting the indentation level to 0.
+Similarly, the keys
+.Dq ^^D
+(i.e. a carat followed by a <control-D>) will erase all of the indent
+characters for the current line, leaving the indentation level for
+future created lines unaffected.
+.Pp
+Finally, if
+.Sy autoindent
+is set, the
+.Sy \&S
+and
+.Sy \&cc
+commands change from the first non-blank of the line to the end of the
+line, instead of from the beginning of the line to the end of the line.
+#endif
+.It Li "autoprint, ap [off]"
+.Nm \&Ex
+only.
+#ifdef MANUAL
+Display the current line automatically.
+.
+#endif
+#ifdef REFERENCE
+.Nm \&Ex
+only.
+Cause the current line to be automatically displayed after the
+.Nm \&ex
+commands
+.Sy \&< ,
+.Sy \&> ,
+.Sy copy ,
+.Sy delete ,
+.Sy join ,
+.Sy move ,
+.Sy put ,
+.Sy \&t ,
+.Sy Undo ,
+and
+.Sy undo .
+This automatic display is suppressed during
+.Sy global
+and
+.Sy vglobal
+commands, and for any command where optional flags are used to explicitly
+display the line.
+#endif
+.It Li "autowrite, aw [off]"
+#ifdef MANUAL
+Write modified files automatically when changing files.
+#endif
+#ifdef REFERENCE
+If this option is set, the
+.Nm \&vi
+.Sy \&!
+.Sy \&^^
+.Sy \&^]
+and
+.Sy \&^Z
+commands, and the
+.Nm \&ex
+.Sy edit ,
+.Sy next ,
+.Sy rewind ,
+.Sy stop ,
+.Sy suspend ,
+.Sy tag ,
+.Sy tagpop ,
+and
+.Sy tagtop
+commands automatically write the current file back to the current file name
+if it has been modified since it was last written.
+If the write fails, the command fails and goes no further.
+.Pp
+Appending the optional force flag
+.Dq \&!
+to the
+.Nm \&ex
+commands
+.Sy next ,
+.Sy rewind ,
+.Sy stop ,
+.Sy suspend ,
+.Sy tag ,
+.Sy tagpop ,
+and
+.Sy tagtop
+stops the automatic write from being attempted.
+.Pp
+(Historically, the
+.Sy next
+command ignored the optional force flag.)
+Note, the
+.Nm \&ex
+commands
+.Sy edit ,
+.Sy quit ,
+.Sy shell ,
+and
+.Sy xit
+are
+.Em not
+affected by the
+.Sy autowrite
+option.
+#endif
+.It Li "beautify, bf [off]"
+#ifdef MANUAL
+Discard control characters.
+#endif
+#ifdef REFERENCE
+If this option is set, all control characters that are not currently being
+specially interpreted, other than <tab>, <newline>, and <form-feed>, are
+discarded from commands read in by
+.Nm \&ex
+from command files, and from input text entered to
+.Nm \&vi
+(either into the file or to the colon command line).
+Text files read by
+.Nm ex/vi
+are
+.Em not
+affected by the
+.Sy beautify
+option.
+#endif
+.It Li "cdpath [environment variable CDPATH, or ``.'']"
+#ifdef MANUAL
+The directory paths used as path prefixes for the
+.Sy cd
+command.
+#endif
+#ifdef REFERENCE
+This option is used to specify a colon separated list of directories
+which are used as path prefixes for any relative path names used as
+arguments for the
+.Sy cd
+command.
+The value of this option defaults to the value of the environmental
+variable
+.Ev CDPATH
+if it is set, otherwise to the current directory.
+For compatibility with the POSIX 1003.2 shell, the
+.Sy cd
+command does
+.Em not
+check the current directory as a path prefix for relative path names
+unless it is explicitly specified.
+It may be so specified by entering an empty string or a
+.Dq \&.
+into the
+.Ev CDPATH
+variable or the option value.
+#endif
+.It Li "columns, co [80]"
+#ifdef MANUAL
+Set the number of columns in the screen.
+#endif
+#ifdef REFERENCE
+The number of columns in the screen.
+Setting this option causes
+.Nm ex/vi
+to set (or reset) the environmental variable
+.Ev COLUMNS .
+See the SCREEN SIZING section for more information.
+#endif
+.It Li "comment [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Skip leading comments in files.
+#endif
+#ifdef REFERENCE
+If the first non-empty line of the file begins with the string
+.Dq \&/\&* ,
+this option causes
+.Nm \&vi
+to skip to the end of that C comment (probably a terribly boring
+legal notice) before displaying the file.
+#endif
+.It Li "directory, dir [environment variable TMPDIR, or /tmp]"
+#ifdef MANUAL
+The directory where temporary files are created.
+#endif
+#ifdef REFERENCE
+The directory where temporary files are created.
+The environmental variable
+.Ev TMPDIR
+is used as the default value if it exists, otherwise
+.Pa /tmp
+is used.
+#endif
+.It Li "edcompatible, ed [off]"
+#ifdef MANUAL
+Modify the behavior of certain suffices for the
+.Nm ex
+.Sy substitute
+command.
+#endif
+#ifdef REFERENCE
+This option causes the presence or absence of
+.Sy \&g
+and
+.Sy \&c
+suffixes on
+.Sy substitute
+commands to be remembered,
+and to be toggled by repeating the suffices.
+The suffix
+.Sy \&r
+makes the substitution be as in the
+.Sy \&~
+command, instead of like the
+.Sy \&&
+command.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "errorbells, eb [off]"
+.Nm \&Ex
+only.
+#ifdef MANUAL
+Precede error messages with a bell.
+#endif
+#ifdef REFERENCE
+Causes
+.Nm \&ex
+error messages to be preceded by a bell.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "exrc, ex [off]"
+#ifdef MANUAL
+Never read startup files in the local directory.
+#endif
+#ifdef REFERENCE
+If this option is turned off in the system or $HOME startup files,
+the local startup files are never read (unless they are the same
+as the system or $HOME startup files).
+Turning it on has no effect, i.e. the normal checks for local startup
+files are performed, regardless.
+See the STARTUP INFORMATION section for more information.
+#endif
+.It Li "extended [off]"
+#ifdef MANUAL
+Regular expressions are extended (i.e.
+.Xr egrep 1
+style) expressions.
+#endif
+#ifdef REFERENCE
+This option causes all regular expressions to be treated as POSIX
+1003.2 extended regular expressions (which are similar to historic
+.Xr egrep 1
+style expressions).
+#endif
+.It Li "flash [on]"
+#ifdef MANUAL
+Flash the screen instead of beeping the keyboard on error.
+#endif
+#ifdef REFERENCE
+This option causes the screen to flash instead of beeping the keyboard,
+on error, if the terminal has the capability.
+#endif
+.It Li "hardtabs, ht [8]"
+#ifdef MANUAL
+Set the spacing between hardware tab settings.
+#endif
+#ifdef REFERENCE
+This option defines the spacing between hardware tab settings, i.e.
+the tab expansion done by the operating system and/or the terminal
+itself.
+As
+.Nm nex/nvi
+never writes tabs to the terminal, unlike historic versions of
+.Nm ex/vi ,
+this option does not currently have any affect.
+#endif
+.It Li "ignorecase, ic [off]"
+#ifdef MANUAL
+Ignore case differences in regular expressions.
+#endif
+#ifdef REFERENCE
+This option causes regular expressions, both in
+.Nm \&ex
+commands and in searches,
+to be evaluated in a case-insensitive manner.
+#endif
+.It Li "keytime [6]"
+The 10th's of a second
+.Nm ex/vi
+waits for a subsequent key to complete a key mapping.
+.It Li "leftright [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Do left-right scrolling.
+#endif
+#ifdef REFERENCE
+This option causes the screen to be scrolled left-right to view
+lines longer than the screen, instead of the traditional
+.Nm \&vi
+screen interface which folds long lines at the right-hand margin
+of the terminal.
+#endif
+.It Li "lines, li [24]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Set the number of lines in the screen.
+#endif
+#ifdef REFERENCE
+The number of lines in the screen.
+Setting this option causes
+.Nm ex/vi
+to set (or reset) the environmental variable
+.Ev LINES .
+See the Screen Sizing section for more information.
+#endif
+.It Li "lisp [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Modify various search commands and options to work with Lisp.
+#endif
+#ifdef REFERENCE
+This option changes the behavior of the
+.Nm \&vi
+.Sy \&( ,
+.Sy \&) ,
+.Sy \&{ ,
+.Sy \&} ,
+.Sy \&[[
+and
+.Sy \&]]
+commands to match the Lisp language.
+Also, the
+.Sy autoindent
+option's behavior is changed to be appropriate for Lisp.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "list [off]"
+#ifdef MANUAL
+Display lines in an unambiguous fashion.
+#endif
+#ifdef REFERENCE
+This option causes lines to be displayed in an unambiguous fashion.
+Specifically, tabs are displayed as control characters, i.e.
+.Dq \&^I ,
+and the ends of lines are marked with a
+.Dq \&$
+character.
+#endif
+.It Li "magic [on]"
+#ifdef MANUAL
+Treat certain characters specially in regular expressions.
+#endif
+#ifdef REFERENCE
+This option is on by default.
+Turning the
+.Sy magic
+option off causes all regular expression characters except for
+.Dq \&^
+and
+.Dq \&$ ,
+to be treated as ordinary characters.
+To re-enable characters individually, when the
+.Sy magic
+option is off,
+precede them with an
+.Dq \&\e .
+See the REGULAR EXPRESSIONS AND REPLACEMENT STRINGS section for
+more information.
+#endif
+.It Li "matchtime [7]"
+.Nm \&Vi
+only.
+The 10th's of a second
+.Nm ex/vi
+pauses on the matching character when the
+.Sy showmatch
+option is set.
+.It Li "mesg [on]"
+#ifdef MANUAL
+Permit messages from other users.
+#endif
+#ifdef REFERENCE
+This option allows other users to contact you using the
+.Xr talk 1
+and
+.Xr write 1
+utilities, while you are editing.
+.Nm Ex/vi
+does not turn message on, i.e. if messages were turned off when the
+editor was invoked, they will stay turned off.
+This option only permits you to disallow messages for the edit session.
+See the
+.Xr mesg 1
+utility for more information.
+#endif
+.It Li "modelines, modeline [off]"
+#ifdef MANUAL
+Read the first and last few lines of each file for
+.Nm ex
+commands.
+#endif
+#ifdef REFERENCE
+If the
+.Sy modelines
+option is set,
+.Nm ex/vi
+has historically scanned the first and last five lines of each file as
+it is read for editing, looking for any
+.Nm \&ex
+commands that have been placed in those lines.
+After the startup information has been processed, and before the user
+starts editing the file, any commands embedded in the file are executed.
+Commands are recognized by the letters
+.Dq \&e
+or
+.Dq \&v
+followed by
+.Dq \&x
+or
+.Dq \&i ,
+at the beginning of a line or following a tab or space character,
+and followed by a
+.Dq \&: ,
+an
+.Nm \&ex
+command, and another
+.Dq \&: .
+This option is a security problem of immense proportions,
+and should not be used under any circumstances.
+#endif
+.br
+.Em "This option will never be implemented."
+.It Li "number, nu [off]"
+Precede each line displayed with its current line number.
+.It Li "open [on]"
+.Nm \&Ex
+only.
+If this option is not set, the
+.Sy open
+and
+.Sy visual
+commands are disallowed.
+.It Li "optimize, opt [on]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Optimize text throughput to dumb terminals.
+#endif
+#ifdef REFERENCE
+Throughput of text is expedited by setting the terminal to no do automatic
+carriage returns when printing more than one (logical) line of output,
+greatly speeding output on terminals without addressable cursors when text
+with leading white space is printed.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "paragraphs, para [IPLPPPQPP LIpplpipbp]"
+.Nm \&Vi
+only.
+Define additional paragraph boundaries for the
+.Sy \&{
+and
+.Sy \&}
+commands.
+#ifdef REFERENCE
+The value of this option must be a character string consisting
+of zero or more character pairs.
+.Pp
+In the text to be edited, the character string <newline>.<char-pair>,
+(where <char-pair> is one of the character pairs in the option's value)
+defines a paragraph boundary.
+For example, if the option were set to
+.Dq "LaA ##" ,
+then all of the following additional paragraph boundaries would be
+recognized:
+.Bd -literal -offset indent -compact
+<newline>.La
+<newline>.A<space>
+<newline>.##
+.Ed
+#endif
+.It Li "prompt [on]"
+.Nm \&Ex
+only.
+#ifdef MANUAL
+Display a command prompt.
+#endif
+#ifdef REFERENCE
+This option causes
+.Nm \&ex
+to prompt for command input with a
+.Dq \&:
+character; when it's not set, no prompt is displayed.
+#endif
+.It Li "readonly, ro [off]"
+#ifdef MANUAL
+Mark the file as read-only.
+#endif
+#ifdef REFERENCE
+This option causes a force flag to be required to attempt to write
+the file back to the original file name.
+Setting this option is equivalent to using the
+.Fl R
+command line option, or editing a file which lacks write permission.
+#endif
+.It Li "recdir [/var/tmp/vi.recover]"
+The directory where recovery files are stored.
+.It Li "redraw, re [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Simulate an intelligent terminal on a dumb one.
+#endif
+#ifdef REFERENCE
+The editor simulates (using great amounts of output), an intelligent
+terminal on a dumb terminal (e.g. during insertions in visual mode
+the characters to the right of the cursor are refreshed as each input
+character is typed).
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "remap [on]"
+#ifdef MANUAL
+Remap keys until resolved.
+#endif
+#ifdef REFERENCE
+If this option is set,
+it's possible to define macros in terms of other macros.
+Otherwise, each key is only remapped up to one time.
+For example, if
+.Dq \&A
+is mapped to
+.Dq \&B ,
+and
+.Dq \&B
+is mapped to
+.Dq \&C ,
+The keystroke
+.Dq \&A
+will be mapped to
+.Dq \&C
+if
+.Sy remap
+is set, and to
+.Dq \&B
+if it is not set.
+#endif
+.It Li "remapmax [on]"
+#ifdef MANUAL
+Limit the number of times a key may be remapped.
+#endif
+#ifdef REFERENCE
+If this option is set, a key may only be remapped 50 times.
+If it is not set, a key may be remapped an infinite number of times,
+and the editor can be placed into infinite loops.
+#endif
+.It Li "report [5]"
+#ifdef MANUAL
+Set the number of lines about which the editor reports changes.
+#endif
+#ifdef REFERENCE
+Set the threshold of the number of lines that need to be changed
+before a message will be displayed to the user.
+The value is the largest value about which the editor is silent,
+i.e. by default, 6 lines must change before the user is notified.
+#endif
+.It Li "ruler [off]"
+.Nm \&Vi
+only.
+Display a row/column ruler on the colon command line.
+.It Li "scroll, scr [window / 2]"
+#ifdef MANUAL
+Set the number of lines scrolled.
+#endif
+#ifdef REFERENCE
+Set the number of lines scrolled by the
+.Nm \&vi
+commands
+.Sy \&^D
+and
+.Sy \&^U .
+.Pp
+Historically, the
+.Nm ex
+.Sy z
+command, when specified without a count, used two times the size of the
+scroll value; the POSIX 1003.2 standard specified the window size, which
+is a better choice.
+#endif
+.It Li "sections, sect [NHSHH HUnhsh]"
+.Nm \&Vi
+only.
+Define additional section boundaries for the
+.Sy \&[[
+and
+.Sy \&]]
+commands.
+#ifdef REFERENCE
+The
+.Sy sections
+option should be set to a character string consisting of zero or
+more character pairs.
+In the text to be edited, the character string <newline>.<char-pair>,
+(where <char-pair> is one of the character pairs in the option's value),
+defines a section boundary in the same manner that
+.Sy paragraph
+option boundaries are defined.
+#endif
+.It Li "shell, sh [environment variable SHELL, or /bin/sh]"
+Select the shell used by the editor.
+#ifdef REFERENCE
+The specified path is the pathname of the shell invoked by the
+.Nm \&vi
+.Sy \&!
+shell escape command and by the
+.Nm \&ex
+.Sy shell
+command.
+This program is also used to resolve any shell meta-characters in
+.Nm \&ex
+commands.
+#endif
+.It Li "shiftwidth, sw [8]"
+Set the autoindent and shift command indentation width.
+#ifdef REFERENCE
+This width is used by the
+.Sy autoindent
+option and by the
+.Sy \&< ,
+.Sy \&> ,
+and
+.Sy shift
+commands.
+#endif
+.It Li "showdirty [off]"
+.Nm \&Vi
+only.
+Display an asterisk on the colon command line if the file has been modified.
+.It Li "showmatch, sm [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Note matching
+.Dq \&{
+and
+.Dq \&(
+for
+.Dq \&}
+and
+.Dq \&)
+characters.
+#endif
+#ifdef REFERENCE
+This option causes
+.Nm \&vi ,
+when a
+.Dq \&}
+or
+.Dq \&)
+is entered, to briefly move the cursor the matching
+.Dq \&{
+or
+.Dq \&( .
+See the
+.Sy matchtime
+option for more information.
+#endif
+.It Li "showmode [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Display the current editor mode (command or input).
+#endif
+#ifdef REFERENCE
+This option causes
+.Nm \&vi
+to display the strings
+.Dq Command
+or
+.Dq Input
+on the colon command line, based on the current mode of the editor.
+#endif
+.It Li "sidescroll [16]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Set the amount a left-right scroll will shift.
+#endif
+#ifdef REFERENCE
+Sets the number of columns that are shifted to the left or right,
+when
+.Nm \&vi
+is doing left-right scrolling and the left or right margin is
+crossed.
+See the
+.Sy leftright
+option for more information.
+#endif
+.It Li "slowopen, slow [off]"
+#ifdef MANUAL
+Delay display updating during text input.
+#endif
+#ifdef REFERENCE
+This option affects the display algorithm used by
+.Nm \&vi ,
+holding off display updating during input of new text to improve
+throughput when the terminal in use is slow and unintelligent.
+#endif
+.br
+.Em "This option is not yet implemented."
+.It Li "sourceany [off]"
+#ifdef MANUAL
+Read startup files not owned by the current user.
+#endif
+#ifdef REFERENCE
+If this option is turned on,
+.Nm \&vi
+historically read startup files that were owned by someone other than
+the editor user.
+See the STARTUP INFORMATION section for more information.
+This option is a security problem of immense proportions,
+and should not be used under any circumstances.
+#endif
+.br
+.Em "This option will never be implemented."
+.It Li "tabstop, ts [8]"
+This option sets tab widths for the editor display.
+.It Li "taglength, tl [0]"
+#ifdef MANUAL
+Set the number of significant characters in tag names.
+#endif
+#ifdef REFERENCE
+This option sets the maximum number of characters that are considered
+significant in a tag name.
+Setting the value to 0 makes all of the characters in the tag name
+significant.
+#endif
+.It Li "tags, tag [tags /var/db/libc.tags /sys/kern/tags]"
+#ifdef MANUAL
+Set the list of tags files.
+#endif
+#ifdef REFERENCE
+Sets the list of tags files, in search order,
+which are used when the editor searches for a tag.
+#endif
+.It Li "term, ttytype, tty [environment variable TERM]"
+Set the terminal type.
+#ifdef REFERENCE
+Setting this option causes
+.Nm ex/vi
+to set (or reset) the environmental variable
+.Ev TERM .
+#endif
+.It Li "terse [off]"
+This option has historically made editor messages less verbose.
+It has no effect in this implementation.
+#ifdef REFERENCE
+See the
+.Sy verbose
+option for more information.
+#endif
+.It Li "timeout, to [on]"
+#ifdef MANUAL
+Time out on keys which may be mapped.
+#endif
+#ifdef REFERENCE
+If this option is set,
+.Nm ex/vi
+waits for a specific period for a subsequent key to complete a key
+mapping (see the
+.Sy keytime
+option).
+If the option is not set, the editor waits until enough keys are
+entered to resolve the ambiguity, regardless of how long it takes.
+#endif
+.It Li "ttywerase [off]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Select an alternate erase algorithm.
+#endif
+#ifdef REFERENCE
+This option changes how
+.Nm \&vi
+does word erase during text input.
+If this option is set, text is broken up into two classes,
+blank characters and non-blank characters.
+Changing from one class to another marks the end of a word.
+#endif
+.It Li "verbose [off]"
+.NM \&Vi
+only.
+#ifdef MANUAL
+Display an error message for every error.
+#endif
+#ifdef REFERENCE
+.Nm \&Vi
+historically bells the terminal for many obvious mistakes, e.g. trying
+to move past the left-hand margin, or past the end of the file.
+If this option is set, an error message is displayed for all errors.
+#endif
+.It Li "w300 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is less than 1200 baud.
+#ifdef REFERENCE
+See the
+.Sy window
+option for more information.
+#endif
+.It Li "w1200 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is equal to 1200 baud.
+#ifdef REFERENCE
+See the
+.Sy window
+option for more information.
+#endif
+.It Li "w9600 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is greater than 1200 baud.
+#ifdef REFERENCE
+See the
+.Sy window
+option for more information.
+#endif
+.It Li "warn [on]"
+.Nm \&Ex
+only.
+This option causes a warning message to the terminal if the file has
+been modified, since it was last written, before a
+.Sy \&!
+command.
+.It Li "window, w, wi [environment variable LINES]"
+#ifdef MANUAL
+Set the window size for the screen.
+#endif
+#ifdef REFERENCE
+This option determines the default number of lines in a screenful,
+as written by the
+.Sy \&z
+command.
+It also determines the number of lines scrolled by the
+.Nm \&vi
+commands
+.Sy \&^F
+and
+.Sy \&^B .
+The value of window can be unrelated to the real screen size,
+although it starts out as the number of lines on the screen (see
+the SCREEN SIZING section).
+Setting the value of the
+.Sy window
+option is the same as using the
+.Fl w
+command line option.
+.Pp
+If the value of
+.Sy window
+(as set by the
+.Sy window ,
+.Sy w300 ,
+.Sy w1200
+or
+.Sy w9600
+options) is smaller than the actual size of the screen, large screen
+movements will result in displaying only that smaller number of lines
+on the screen.
+(Further movements in that same area will result in the screen being
+filled.)
+This can provide a performance improvement when viewing different
+places in one or more files over a slow link.
+#endif
+.It Li "wrapmargin, wm [0]"
+.Nm \&Vi
+only.
+#ifdef MANUAL
+Break lines automatically when they reach the right-hand margin.
+#endif
+#ifdef REFERENCE
+If the value of wrapmargin is non-zero,
+.Nm \&vi
+will break lines, that are more than that number of characters long,
+into two lines at the blank character closest to the value.
+If wrapmargin is 0,
+or if there is no blank character upon which to break the line,
+the line will not be broken.
+#endif
+.It Li "wrapscan, ws [on]"
+#ifdef MANUAL
+Set searches to wrap around the end or beginning of the file.
+#endif
+#ifdef REFERENCE
+This option causes searches to wrap around the end or the beginning
+of the file, and back to the starting point.
+Otherwise, the end or beginning of the file terminates the search.
+#endif
+.It Li "writeany, wa [off]"
+#ifdef MANUAL
+Turn off file-overwriting checks.
+#endif
+#ifdef REFERENCE
+If this option is set, file-overwriting checks that would usually be
+made before the
+.Sy write
+and
+.Sy xit
+commands, or before an automatic write (see the
+.Sy autowrite
+option), are not made.
+This allows a write to any file, provided the file permissions allow it.
+#endif
+.El
diff --git a/usr.bin/vi/docs/spell.ok b/usr.bin/vi/docs/spell.ok
new file mode 100644
index 000000000000..fce3673fac73
--- /dev/null
+++ b/usr.bin/vi/docs/spell.ok
@@ -0,0 +1,163 @@
+Amir
+Autoprint
+BRE's
+Bostic
+Ds
+ERE's
+EXINIT
+Englar
+Ev
+Fa
+Fl
+HUnhsh
+IPLPPPQPP
+Kirkendall
+LIpplpipbp
+LaA
+Li
+Makefiles
+NEXINIT
+NHSHH
+Nex
+Nvi
+OS
+POSIX
+PostScript
+RE's
+README
+SIGHUP
+SIGWINCH
+Se
+Std1003.2
+Sy
+TANDARDS
+TIOCGWINSZ
+TMPDIR
+Todo
+USD.doc
+UUNET
+Vx
+XXCOLUMNS
+XXXX
+ags
+ai
+altwerase
+autoindent
+autoprint
+autowrite
+aw
+bf
+bostic
+bugs.current
+carat
+changelog
+cmd
+creens
+cs.berkeley.edu
+db
+dbopen
+def
+di
+dir
+docs
+eFlRsv
+eFlRv
+eb
+edcompatible
+elvis
+email
+enum
+errorbells
+esc
+exrc
+exu
+fi
+ftp.cs.berkeley.edu
+ftp.uu.net
+gdb
+gdb.script
+gzip'd
+hangup
+hardtabs
+ht
+ic
+ifdef
+ignorecase
+ious
+keystroke
+keystrokes
+keytime
+leftright
+li
+libc.tags
+lowercase
+matchtime
+meta
+modeful
+modeline
+modelines
+nex
+nexrc
+nomagic
+nvi
+nvi.tar.Z
+nvi.tar.z
+para
+pathname
+rc.local
+readonly
+recdir
+recover.XXXX
+recover.c
+ript
+ro
+roff
+sc
+scr
+screeen
+set.opt.roff
+shiftwidth
+showmatch
+showmode
+sidescroll
+slowopen
+sm
+sourceany
+sp
+spell.ok
+svi
+sw
+tabstop
+taglength
+tagpop
+tagtop
+th
+tl
+tmp
+ts
+ttytype
+ttywerase
+ucb
+uffers
+uppercase
+uunet
+var
+vglobal
+vi.0.ps
+vi.0.txt
+vi.1
+vi.XXXX
+vi.exrc
+vi.recover
+virecovery
+viu
+wa
+wi
+wm
+wrapmargin
+wrapscan
+writeany
+ws
+xaw
+xit
+yy
diff --git a/usr.bin/vi/docs/tutorial/vi.advanced b/usr.bin/vi/docs/tutorial/vi.advanced
new file mode 100644
index 000000000000..f757ad19c44a
--- /dev/null
+++ b/usr.bin/vi/docs/tutorial/vi.advanced
@@ -0,0 +1,1458 @@
+Section 26: Index to the rest of the tutorial
+
+The remainder of the tutorial can be perused at your leisure. Simply find the
+topic of interest in the following list, and {/Section xx:/^M} to get to the
+appropriate section. (Remember that ^M means the return key)
+
+The material in the following sections is not necessarily in a bottom up
+order. It should be fairly obvious that if a section mentions something with
+which you are not familiar, say, buffers, you might {/buffer/^M} followed by
+several {n} to do a keyword search of the file for more details on that item.
+Another point to remember is that commands are surrounded by curly-braces and
+can therefore be found rather easily. To see where, say, the X command is
+used try {/{X}/^M}. Subsequent {n} will show you other places the command was
+used. We have tried to maintain the convention of placing the command letter
+surrounded by curly-braces on the section line where that command is
+mentioned.
+
+Finally, you should have enough 'savvy' at this point to be able to do your
+own experimentation with commands without too much hand-holding on the part of
+the tutorial. Experimentation is the best way to learn the effects of the
+commands.
+
+ Section Topic - description
+ ------- -------------------
+(Sections 1 through 25 are located in the file vi.beginner.)
+ 1 introduction: {^F} {ZZ}
+ 2 introduction (con't) and positioning: {^F} {^B}
+ 3 introduction (con't) and positioning: {^F} {^B}
+ 4 positioning: {^F} {^B} ^M (return key)
+ 5 quitting: {:q!} ^M key
+ 6 marking, cursor and screen positioning: {m} {G} {'} {z}
+ 7 marking, cursor and screen positioning: {m} {G} {'} {z}
+ 8 marking, cursor and screen positioning: {z} {m} {'}
+ 9 marking and positioning: {m} {''}
+ 10 line positioning: {^M} {-}
+ 11 scrolling with {^M}
+ 12 scrolling with {-} and screen adjustment {z}
+ 13 notes on use of tutorial
+ 14 other scrolling and postioning commands: {^E} {^Y} {^D} {^U}
+ 15 searching: {/ .. /^M}
+ 16 searching: {? .. ?^M} {n} (in search strings ^ $)
+ 17 searching: \ and magic-characters in search strings
+ 18 colon commands, exiting: {:} {ZZ}
+ 19 screen positioning: {H} {M} {L}
+ 20 character positioning: {w} {b} {0} {W} {B} {e} {E} {'} {`}
+ 21 cursor positioning: {l} {k} {j} {h}
+ 22 adding text: {i} {a} {I} {A} {o} {O} ^[ (escape key)
+ 23 character manipulation: {f} {x} {X} {w} {l} {r} {R} {s} {S} {J}
+ 24 undo: {u} {U}
+ 25 review
+(The following sections are in this file.)
+ 26 Index to the rest of the tutorial ******** YOU ARE HERE *******
+ 27 discussion of repeat counts and the repeat command: {.}
+ 28 more on low-level character motions: {t} {T} {|}
+ 29 advanced correction operators: {d} {c}
+ 30 updating the screen: {^R}
+ 31 text buffers: {"}
+ 32 rearranging and duplicating text: {p} {P} {y} {Y}
+ 33 recovering lost lines
+ 34 advanced file manipulation with vi
+ 34.1 more than one file at a time: {:n}
+ 34.2 reading files and command output: {:r}
+ 34.3 invoking vi from within vi: {:e} {:vi}
+ 34.4 escaping to a shell: {:sh} {:!}
+ 34.5 writing parts of a file: {:w}
+ 34.6 filtering portions of text: {!}
+ 35 advanced searching: magic patterns
+ 36 advanced substitution: {:s}
+ 37 advanced line addressing: {:p} {:g} {:v}
+ 38 higher level text objects and nroff: ( ) { } [[ ]]
+ 39 more about inserting text
+ 40 more on operators: {d} {c} {<} {>} {!} {=} {y}
+ 41 abbreviations: {:ab}
+ 42 vi's relationship with the ex editor: {:}
+ 43 vi on hardcopy terminals and dumb terminals: open mode
+ 44 options: {:set} {setenv EXINIT}
+ 44.1 autoindent
+ 44.2 autoprint
+ 44.3 autowrite
+ 44.4 beautify
+ 44.5 directory
+ 44.6 edcompatible
+ 44.7 errorbells
+ 44.8 hardtabs
+ 44.9 ignorecase
+ 44.10 lisp
+ 44.11 list
+ 44.12 magic
+ 44.13 mesg
+ 44.14 number
+ 44.15 open
+ 44.16 optimize
+ 44.17 paragraphs
+ 44.18 prompt
+ 44.19 readonly
+ 44.20 redraw
+ 44.21 remap
+ 44.22 report
+ 44.23 scroll
+ 44.24 sections
+ 44.25 shell
+ 44.26 shiftwidth
+ 44.27 showmatch
+ 44.28 slowopen
+ 44.29 tabstop
+ 44.30 tags
+ 44.31 taglength
+ 44.32 term
+ 44.33 terse
+ 44.34 timeout
+ 44.35 ttytype
+ 44.36 warn
+ 44.37 window
+ 44.38 wrapscan
+ 44.39 wrapmargin
+ 44.40 writeany
+ 44.41 w300, w1200, w9600
+
+Section 27: repetition counts and the repeat command {.}
+
+Most vi commands will use a preceding count to affect their behavior in some
+way. We have already seen how {3x} deletes three characters, and {22G} moves
+us to line 22 of the file. For almost all of the commands, one can survive by
+thinking of these leading numbers as a 'repeat count' specifying that the
+command is to be repeated so many number of times.
+
+Other commands use the repeat count slightly differently, like the {G} command
+which use it as a line number.
+
+For example:
+
+{3^D} means scroll down in the file three lines. Subsequent {^D} OR {^U} will
+scroll only three lines in their respective directions!
+
+{3z^M} says put line three of the file at the top of the screen, while {3z.}
+says put line three as close to the middle of the screen as possible.
+
+{50|} moves the cursor to column fifty in the current line.
+
+{3^F} says move forward 3 screenfulls. This is a repetition count. The
+documents advertise that {3^B} should move BACK three screenfulls, but I
+can't get it to work.
+
+Position the cursor on some text and try {3r.}. This replaces three characters
+with '...'. However, {3s.....^[} is the same as {3xi.....^[}.
+
+Try {10a+----^[}.
+
+A very useful instance of a repetition count is one given to the '.' command,
+which repeats the last 'change' command. If you {dw} and then {3.}, you will
+delete first one and then three words. You can then delete two more words with
+{2.}. If you {3dw}, you will delete three words. A subsequent {.} will delete
+three more words. But a subsequent {2.} will delete only two words, not three
+times two words.
+
+Caveat: The author has noticed that any repetition count with {^B} will NOT
+work: indeed, if you are at the end of your file and try {3^B} sufficiently
+often, the editor will hang you in an infinite loop. Please don't try it:
+take my word for it.
+
+Section 28: {t} {T} {|}
+
+Position the cursor on line 13 below:
+
+Line 13: Four score and seven years ago, our forefathers brought ...
+
+Note that {fv} moves the cursor on/over the 'v' in 'seven'. Do a {0} to return
+to the beginning of the line and try a {tv}. The cursor is now on/over the
+first 'e' in 'seven'. The {f} command finds the next occurrence of the
+specified letter and moves the cursor to it. The {t} command finds the
+specified letter and moves the cursor to the character immediately preceding
+it. {T} searches backwards, as does {F}.
+
+Now try {60|}: the cursor is now on the 'o' in 'brought', which is the
+sixtieth character on the line.
+
+Section 29: {d} {c}
+
+Due to their complexity we have delayed discussion of two of the most powerful
+operators in vi until now. Effective use of these operators requires more
+explanation than was deemed appropriate for the first half of the tutorial.
+
+{d} and {c} are called operators instead of commands because they consist of
+three parts: a count specification or a buffer specification (see section
+#BUFFERS), the {d} or {c}, and the object or range description. We will not
+discuss buffers at this stage, but will limit ourselves to count
+specifications. Examples speak louder than words: position the cursor at the
+beginning of line 14:
+
+Line 14: Euclid alone has looked on beauty bear.
+
+Obviously, there is something wrong with this quotation. Type {2fb} to
+position the cursor on the 'b' of 'bear'. Now, type {cwbare^[}
+and observe the results. The {cw} specifies that the change command {c} is to
+operate on a word object. More accurately, it specifies that the range of the
+change command includes the next word.
+
+Position the cursor on the period in Line 14. (one way is to use {f.})
+Now, type {cbbeast^[}. This specifies the range of the change command to be the
+previous word (the 'b' reminiscent of the {b} command). If we had wished to
+delete the word rather than change it, we would have used the {d} operator,
+rather than the {c} operator.
+
+Position the cursor at the beginning of the line with {0}. Type
+{d/look/^M}. The search string specified the range of the delete.
+Everything UP TO the word 'looking' was deleted from the line.
+
+In general, almost any command that would move the cursor will specify a range
+for these commands. The most confusing exception to this rule is when {dd} or
+{cc} is entered: they refer to the whole line. Following is a summary of the
+suffixes (suffices? suffici?) and the ranges they specify:
+
+ suffix will delete{d}/change{c}
+ ------ ------------------------
+ ^[ cancels the command
+ w the word to the right of the cursor
+ W ditto, but ignoring punctuation
+ b the word to the left of the cursor
+ B ditto, but ignoring punctuation
+ e see below.
+ E ditto
+ (space) a character
+ $ to the end of the line
+ ^ to the beginning of the line
+ / .. / up to, but not including, the string
+ ? .. ? back to and including the string
+ fc up to and including the occurrence of c
+ Fc back to and including the occurrence of c
+ tc up to but not including the occurrence of c
+ Tc back to but not including the occurrence of c
+ ^M TWO lines (that's right: two)
+ (number)^M that many lines plus one
+ (number)G up to and including line (number)
+ ( the previous sentence if you are at the beginning of
+ the current sentence, or the current sentence up to where
+ you are if you are not at the beginning of the current
+ sentence. Here, 'sentence' refers to the intuitive
+ notion of an English sentence, ending with '!', '?',
+ or '.' and followed by an end of line or two spaces.
+ ) the rest of the current sentence
+ { analogous to '(', but in reference to paragraphs:
+ sections of text surrounded by blank lines
+ } analogous to ')', but in reference to paragraphs
+ [[ analogous to '(', but in reference to sections
+ ]] analogous to ')', but in reference to sections
+ H the first line on the screen
+ M the middle line on the screen
+ L the last line on the screen
+ 3L through the third line from the bottom of the screen
+ ^F forward a screenful
+ ^B backward a screenful
+ :
+ : etc. etc. etc.
+
+This list is not exhaustive, but it should be sufficient to get the idea
+across: after the {c} or {d} operator, you can specify a range with another
+move-the-cursor command, and that is the region of text over which the command
+will be effective.
+
+Section 30: updating the screen {^R}
+
+Vi tries to be very intelligent about the type of terminal you are working on
+and tries to use the in-terminal computing power (if any) of your terminal.
+Also if the terminal is running at a low baud rate (say 1200 or below), vi sets
+various parameters to make things easier for you. For example, if you were
+running on a 300 baud terminal (that's 30 characters per second transmission
+rate) not all 24 lines of the screen would be used by vi. In addition, there
+is a large portion of the editor keeping track of what your screen currently
+looks like, and what it would look like after a command has been executed. Vi
+then compares the two, and updates only those portions of the screen that have
+changed.
+
+Furthermore, some of you may have noticed (it depends on your terminal) that
+deleting lines or changing large portions of text may leave some lines on the
+screen looking like:
+@
+meaning that this line of the screen does not correspond to any line in your
+file. It would cost more to update the line than to leave it blank for the
+moment. If you would like to see your screen fully up-to-date with the
+contents of your file, type {^R}.
+
+To see it in action, delete several lines with {5dd}, type {^R}, and then type
+{u} to get the lines back.
+
+Here is as good a place as any to mention that if the editor is displaying the
+end of your file, there may be lines on the screen that look like:
+~
+indicating that that screen line would not be affected by {^R}. These lines
+simply indicate the end of the file.
+
+Section 31: text buffers {"}
+
+Vi gives you the ability to store text away in "buffers". This feature is very
+convenient for moving text around in your file. There are a total of thirty-
+five buffers available in vi. There is the "unnamed" buffer that is used by all
+commands that delete text, including the change operator {c}, the substitute
+and replace commands {s} and {r}, as well as the delete operator {d} and delete
+commands {x} and {X}. This buffer is filled each time any of these commands
+are used. However, the undo command {u} has no effect on the unnamed buffer.
+
+There are twenty-six buffers named 'a' through 'z' which are available for the
+user. If the name of the buffer is capitalized, then the buffer is not
+overwritten but appended to. For example, the command {"qdd} will delete one
+line and store that line in the 'q' buffer, destroying the previous contents of
+the buffer. However, {"Qdd} will delete one line of text and append that line
+to the current contents of the 'q' buffer.
+
+Finally, there are nine buffers named '1' through '9' in which the last nine
+deletes are stored. Buffer 1 is the default buffer for the modify commands and
+is sometimes called the unnamed buffer.
+
+To reference a specific buffer, use the double-quote command {"} followed by
+the name of the buffer. The next two sections show how buffers can be used to
+advantage.
+
+Section 32: rearranging and duplicating text: {y} {Y} {p} {P}
+
+Position yourself on line 15 below and {z^M}:
+
+Line 15: A tree as lovely as a poem ...
+Line 16: I think that I shall never see
+
+Type {dd}. Line 15 has disappeared and been replaced with the empty line (one
+with the single character @ on it) or (again depending on your terminal) Line
+16 has moved up and taken its place. We could recover Line 15 with an undo
+{u} but that would simply return it to its original location. Obviously, the
+two lines are reversed, so we want to put line 15 AFTER line 16. This is
+simply done with the put command {p}, which you should type now. What has
+happened is that {dd} put Line 15 into the unnamed buffer, and the {p} command
+retrieved the line from the unnamed buffer.
+
+Now type {u} and observe that Line 15 disappears again (the put was undone
+without affecting the unnamed buffer). Type {P} and see that the capital {P}
+puts the line BEFORE the cursor.
+
+To get Line 15 where it belongs again type {dd}{p}.
+
+Also in Line 15 note that the words 'tree' and 'poem' are reversed. Using the
+unnamed buffer again: {ft}{dw}{ma}{fp}{P}{w}{dw}{`aP} will set things aright
+(note the use of the reverse quote).
+
+The put commands {p} and {P} do not affect the contents of the buffer.
+Therefore, multiple {p} or {P} will put multiple copies of the unnamed buffer
+into your file.
+
+Experiment with {d} and {p} on words, paragraphs, etc. Whatever {d}
+deletes, {p} can put.
+
+Position the cursor on Line 17 and {z^M}:
+
+Line 17: interest apple cat elephant boy dog girl hay farmer
+
+Our task is to alphabetize the words on line 17. With the named buffers (and a
+contrived example) it is quite easy:
+
+{"idw}{"adw}{"cdw}{"edw}{"bdw}{"ddw}{"gdw}{"hdw}{"fdw}
+
+stores each of the words in the named buffer corresponding to the first letter
+of each of the words ('interest' goes in buffer "i, 'apple' goes in buffer "a,
+etc.). Now to put the words in order type:
+
+{"ap$}{"bp$}{"cp$}{"dp$}{"ep$}{"fp$}{"gp$}{"hp$}{"ip$}
+
+Notice that, because 'farmer' was at the end of the line, {dw} did not include
+a space after it, and that, therefore, there is no space between 'farmer' and
+'girl'. This is corrected with {Fg}{i ^[}.
+
+This example could have been done just as easily with lines as with
+words.
+
+You do not have to delete the text in order to put it into a buffer. If all
+you wish to do is to copy the text somewhere else, don't use {d}, rather use
+the yank commands {y} or {Y}. {y} is like {d} and {c} - an operator rather
+than a command. It, too, takes a buffer specification and a range
+specification. Therefore, instead of {dw}{P} to load the unnamed buffer with a
+word without deleting the word, use {yw} (yank a word).
+
+{Y} is designed yank lines, and not arbitrary ranges. That is, {Y} is
+equivalent to {yy} (remember that operators doubled means the current line),
+and {3Y} is equivalent to {3yy}.
+
+If the text you yank or modify forms a part of a line, or is an object such as
+a sentence which partially spans more than one line, then when you put the text
+back, it will be placed after the cursor (or before if you use {P}). If the
+yanked text forms whole lines, they will be put back as whole lines, without
+changing the current line. In this case, the put acts much like the {o} or {O}
+command.
+
+The named buffers "a through "z are not affected by changing edit files.
+However, the unnamed buffer is lost when you change files, so to move text from
+one file to another you should use a named buffer.
+
+Section 33: recovering lost lines
+
+Vi also keeps track of the last nine deletes, whether you ask for it or not.
+This is very convenient if you would like to recover some text that was
+accidentally deleted or modified. Position the cursor on line 18 following,
+and {z^M}.
+
+
+Line 18: line 1
+Line 19: line 2
+Line 20: line 3
+Line 21: line 4
+Line 22: line 5
+Line 23: line 6
+Line 24: line 7
+Line 25: line 8
+Line 26: line 9
+Type {dd} nine times: now don't cheat with {9dd}! That is totally different.
+
+The command {"1p} will retrieve the last delete. Furthermore, when the
+numbered buffers are used, the repeat-command command {.} will increment the
+buffer numbers before executing, so that subsequent {.} will recover all nine
+of the deleted lines, albeit in reverse order. If you would like to review the
+last nine deletes without affecting the buffers or your file, do an undo {u}
+after each put {p} and {.}:
+
+{"1p}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}
+
+will show you all the buffers and leave them and your file intact.
+
+If you had cheated above and deleted the nine lines with {9dd}, all nine lines
+would have been stored in both the unnamed buffer and in buffer number 1.
+(Obviously, buffer number 1 IS the unnamed buffer and is just the default
+buffer for the modify commands.)
+
+Section 34: advanced file manipulation: {:r} {:e} {:n} {:w} {!} {:!}
+
+We've already looked at writing out the file you are editing with the
+{:w} command. Now let's look at some other vi commands to make editing
+more efficient.
+
+Section 34.1: more than one file at a time {:n} {:args}
+
+Many times you will want to edit more than one file in an editing session.
+Instead of entering vi and editing the first file, exiting, entering vi and
+editing the second, etc., vi will allow you to specify ALL files that you wish
+to edit on the invocation line. Therefore, if you wanted to edit file1 and
+file2:
+
+% vi file1 file2
+
+will set up file1 for editing. When you are done editing file one, write it
+out {:w^M} and then type {:n^M} to get the next file on the list. On large
+programming projects with many source files, it is often convenient just to
+specify all source files with, say:
+
+% vi *.c
+
+If {:n^M} brings in a file that does not need any editing, another {:n^M}
+will bring in the next file.
+
+If you have made changes to the first file, but decide to discard these changes
+and proceed to the next file, {:n!^M} forces the editor to discard the current
+contents of the editor.
+
+You can specify a new list of files after {:n}; e.g., {:n f1 f2 f3^M}. This
+will replace the current list of files (if any).
+
+You can see the current list of files being edited with {:args^M}.
+
+Section 34.2: reading files and command output: {:r}
+
+Typing {:r fname^M} will read the contents of file fname into the editor and
+put the contents AFTER the cursor line.
+
+Typing {:r !cmd^M} will read the output of the command cmd and place that
+output after the cursor line.
+
+Section 34.3: invoking vi from within vi: {:e} {:vi}
+
+To edit another file not mentioned on the invocation line, type {:e filename^M}
+or {:vi filename^M}. If you wish to discard the changes to the current file,
+use the exclamation point after the command, e.g. {:e! filename^M}.
+
+Section 34.4: escaping to a shell: {:sh} {:!} {^Z}
+
+Occasionally, it is useful to interrupt the current editing session to perform
+a UNIX task. However, there is no need to write the current file out, exit
+the editor, perform the task, and then reinvoke the editor on the same file.
+One thing to do is to spin off another process. If there are several UNIX
+commands you will need to execute, simply create another shell with {:sh^M}.
+At this point, the editor is put to sleep and will be reawakened when you log
+out of the shell.
+
+If it is a single command that you want to execute, type {:!cmd^M}, where cmd
+is the command that you wish to run. The output of the command will come to
+the terminal as normal, and will not be made part of your file. The message
+"[Hit return to continue]" will be displayed by vi after the command is
+finished. Hitting return will then repaint the screen. Typing another
+{:!cmd^M} at this point is also acceptable.
+
+However, there is a quicker, easier way: type {^Z}. Now this is a little
+tricky, but hang in there. When you logged into UNIX, the first program you
+began communicating with was a program that is called a "shell" (i.e. it 'lays
+over' the operating system protecting you from it, sort of like a considerate
+porcupine). When you got your first prompt on the terminal (probably a '%'
+character) this was the shell telling you to type your first command. When
+you typed {vi filename} for some file, the shell did not go away, it just went
+to sleep. The shell is now the parent of vi. When you type {^Z} the editor
+goes to sleep, the shell wakes up and says "you rang?" in the form of another
+prompt (probably '%'). At this point you are talking to the shell again and
+you can do anything that you could before including edit another file! (The
+only thing you can't do is log out: you will get the message "There are
+stopped jobs.")
+
+When your business with the shell is done, type {fg} for 'foreground' and the
+last process which you ^Z'd out of will be reawakened and the shell will go
+back to sleep. I will refer you to the documentation for the Berkeley shell
+'csh' for more information on this useful capability.
+
+Section 34.5: writing parts of a file: {:w}
+
+The {:w} command will accept a range specifier that will then write only a
+selected range of lines to a file. To write this section to a file, position
+the cursor on the section line (e.g. {/^Section 34.5:/^M}) and {z^M}. Now type
+{^G} to find out the line number (it will be something like "line 513"). Now
+{/^Section 34.6:/-1^M} to find the last line of this section, and {^G} to find
+its line number (it will be something like 542). To write out this section of
+text by itself to a separate file which we will call "sepfile", type
+{:510,542w sepfile^M}. If sepfile already exists, you will have to use the
+exclamation point: {:1147,1168w! sepfile^M} or write to a different, non-
+existent file.
+
+{:!cat sepfile^M} will display the file just written, and it should be the
+contents of this section.
+
+There is an alternate method of determining the line numbers for the write.
+{:set number^M} will repaint the screen with each line numbered. When the file
+is written and the numbers no longer needed, {:set nonumber^M} will remove the
+numbers, and {^R} will adjust the screen.
+
+Or, if you remember your earlier lessons about marking lines of text,
+mark the beginning and ending lines. Suppose we had used {ma} to mark the
+first line of the section and {mb} to mark the last. Then the command
+{:'a,'bw sepfile^M} will write the section into "sepfile". In general,
+you can replace a line number with the 'name' of a marked line (a single-quote
+followed by the letter used to mark the line)
+
+
+Section 34.6: filtering portions of text: {!}
+
+{!} is an operator like {c} and {d}. That is, it consists of a repetition
+count, {!}, and a range specifier. Once the {!} operator is entered in its
+entirety, a prompt will be given at the bottom of the screen for a UNIX
+command. The text specified by the {!} operator is then deleted and
+passed/filtered/piped to the UNIX command you type. The output of the UNIX
+command is then placed in your file. For example, place the cursor at the
+beginning of the following line and {z^M}:
+
+ls -l vi.tutorial
+********* marks the bottom of the output from the ls command **********
+
+Now type {!!csh^M}. The line will be replaced with the output from the ls
+command. The {u} command works on {!}, also.
+
+Here is an extended exercise to display some of these capabilities. When this
+tutorial was prepared, certain auxiliary programs were created to aid in its
+development. Of major concern was the formatting of sections of the tutorial
+to fit on a single screen, particularly the first few sections. What was
+needed was a vi command that would 'format' a paragraph; that is, fill out
+lines with as many words as would fit in eighty columns. There is no such vi
+command. Therefore, another method had to be found.
+
+Of course, nroff was designed to do text formatting. However, it produces a
+'page'; meaning that there may be many blank lines at the end of a formatted
+paragraph from nroff. The awk program was used to strip these blank lines from
+the output from nroff. Below are the two files used for this purpose: I refer
+you to documentation on nroff and awk for a full explanation of their function.
+Position the cursor on the next line and {z^M}.
+
+******** contents of file f **********
+#
+nroff -i form.mac | awk "length != 0 { print }"
+***** contents of file form.mac ******
+.na
+.nh
+.ll 79
+.ec 
+.c2 
+.cc 
+**************************************
+
+Determine the line numbers of the two lines of file f. They should be
+something like 574 and 575, although you better double check: this file is
+under constant revision and the line numbers may change inadvertently. Then
+{:574,575w f^M}. Do the same for the lines of file form.mac. They will be
+approximately 577 and 582. Then {:577,582w form.mac^M}. File f must have
+execute privileges as a shell file: {:!chmod 744 f^M}.
+
+Observe that this paragraph is
+rather ratty in appearance. With our newly created files we can
+clean it up dramatically. Position the cursor at the beginning
+of this paragraph and type the following sequence of
+characters
+(note that we must abandon temporarily our convention
+of curly braces since the command itself contains a curly brace - we
+will use square brackets for the nonce): [!}f^M].
+
+Here is a brief explanation of what has happened. By typing [!}f^M] we
+specified that the paragraph (all text between the cursor and the first blank
+line) will be removed from the edit file and piped to a UNIX program called
+"f". This is a shell command file that we have created. This shell file runs
+nroff, pipes its output to awk to remove blank lines, and the output from awk
+is then read back into our file in the place of the old, ratty paragraph. The
+file form.mac is a list of commands to nroff to get it to produce paragraphs
+to our taste (the right margin is not justified, the line is 79 characters
+long, words are not hyphenated, and three nroff characters are renamed to
+avoid conflict: note that in this file, the {^G} you see there is vi's display
+of the control-G character, and not the two separate characters ^ up-arrow and
+G upper-case g).
+
+This example was created before the existence of the fmt program. I now type
+[!}fmt^M] to get the same effect much faster. Actually, I don't type those
+six keys each time: I have an abbreviation (which see).
+
+Section 35: searching with magic patterns
+
+The documentation available for "magic patterns" (i.e. regular expressions) is
+very scanty. The following should explain this possibly very confusing feature
+of the editor. This section assumes that the magic option is on. To make
+sure, you might want to type {:set magic^M}.
+
+By "magic pattern" we mean a general description of a piece of text that the
+editor attempts to find during a search. Most search patterns consist of
+strings of characters that must be matched exactly, e.g. {/card/^M} searches
+for a specific string of four characters. Let us suppose that you have
+discovered that you consistently have mistyped this simple word as either ccrd
+or czrd (this is not so far-fetched for touch typists). You could {/ccrd/^M}
+and {n} until there are no more of this spelling, followed by {/czrd/^M} and
+{n} until there are no more of these. Or you could {/c.rd/^M} and catch all of
+them on the first pass. Try typing {/c.rd/^M} followed by several {n} and
+observe the effect.
+
+Line 27: card cord curd ceard
+
+When '.' is used in a search string, it has the effect of matching any single
+character.
+
+The character '^' (up-arrow) used at the beginning of a search string means
+the beginning of the line. {/^Line 27/^M} will find the example line above,
+while {/Line 27/^M} will find an occurrence of this string anywhere in the
+line.
+
+Similarly, {/ the$/^M} will find all occurrences of the word 'the' occurring
+at the end of a line. There are several of them in this file.
+
+Note that {:set nomagic^M} will turn off the special meaning of these magic
+characters EXCEPT for '^' and '$' which retain their special meanings at the
+beginning and end of a search string. Within the search string they hold no
+special meaning. Try {/\/ the$\//^M} and note that the dollar-sign is not the
+last character in the search string. Let the dollar-sign be the last
+character in the search string, as in {/\/ the$/^M} and observe the result.
+
+Observe the result of {/back.*file/^M}. This command, followed by sufficient
+{n}, will show you all lines in the file that contain both the words 'back'
+and 'file' on the same line. The '*' magic character specifies that the
+previous regular expression (the '.' in our example) is to be repeatedly
+matched zero or more times. In our example we specified that the words 'back'
+and 'file' must appear on the same line (they may be parts of words such as
+'backwards' or 'workfile') separated by any number (including zero) of
+characters.
+
+We could have specified that 'back' and 'file' are to be words by themselves by
+using the magic sequences '\<' or '\>'. E.g. {/\<back\>.*\<file\>/^M}. The
+sequence '\<' specifies that this point of the search string must match the
+beginning of a word, while '\>' specifies a match at the end of a word. By
+surrounding a string with these characters we have specified that they must be
+words.
+
+To find all words that begin with an 'l' or a 'w', followed by an 'a' or an
+'e', and ending in 'ing', try {/\<[lw][ea][a-z]*ing\>/^M}. This will match
+words like 'learning', 'warning', and 'leading'. The '[..]' notation matches
+exactly ONE character. The character matched will be one of the characters
+enclosed in the square brackets. The characters may be specified individually
+as in [abcd] or a '-' may be used to specify a range of characters as in [a-d].
+That is, [az] will match the letter 'a' OR the letter 'z', while [a-z] will
+match any of the lower case letters from 'a' through 'z'. If you would like to
+match either an 'a', a '-', or a 'z', then the '-' must be escaped: [a\-z] will
+match ONE of the three characters 'a', '-', or 'z'.
+
+If you wish to find all Capitalized words, try {/\<[A-Z][a-z]*\>/^M}. The
+following will find all character sequences that do NOT begin with an
+uncapitalized letter by applying a special meaning to the '^' character in
+square brackets: {/\<[^a-z][a-z]*\>/^M}. When '^' is the first character of a
+square-bracket expression, it specifies "all but these characters". (No
+one claimed vi was consistent.)
+
+To find all variable names (the first character is alphabetic, the remaining
+characters are alphanumeric): try {/\<[A-Za-z][A-Za-z0-9]*\>/^M}.
+
+In summary, here are the primitives for building regular expressions:
+
+ ^ at beginning of pattern, matches beginning of line
+ $ at end of pattern, matches end of line
+ . matches any single character
+ \< matches the beginning of a word
+ \> matches the end of a word
+ [str] matches any single character in str
+ [^str] matches any single character NOT in str
+ [x-y] matches any character in the ASCII range between x and y
+ * matches any number (including zero) of the preceding pattern
+
+Section 36: advanced substitution: {:s}
+
+The straightforward colon-substitute command looks like the substitute
+command of most line-oriented editors. Indeed, vi is nothing more than a
+superstructure on the line-oriented editor ex and the colon commands are
+simply a way of accessing commands within ex (see section #EX). This gives us
+a lot of global file processing not usually found in visual oriented editors.
+
+The colon-substitute command looks like: {:s/ .. / .. /^M} and will find the
+pattern specified after the first slash (this is called the search pattern),
+and replace it with the pattern specified after the second slash (called,
+obviously enough, the replacement pattern). E.g. position the cursor on line
+28 below and {:s/esample/example/^M}:
+
+Line 28: This is an esample.
+
+The {u} and {U} commands work for {:s}. The first pattern (the search pattern)
+may be a regular expression just as for the search command (after all, it IS a
+search, albeit limited to the current line). Do an {u} on the above line, and
+try the following substitute, which will do almost the same thing:
+{:s/s[^ ]/x/^M}.
+Better undo it with {u}. The first pattern {s[^ ]} matches an 's'
+NOT followed by a blank: the search therefore ignores the 's'es in 'This' and
+'is'. However, the character matched by {[^ ]} must appear in the replacement
+pattern. But, in general, we do not know what that character is! (In this
+particular example we obviously do, but more complicated examples will follow.)
+Therefore, vi (really ex) has a duplication mechanism to copy patterns matched
+in the search string into the replacement string. Line 29 below is a copy of
+line 28 above so you can adjust your screen.
+
+Line 29: This is an esample.
+
+In general, you can nest parts of the search pattern in \( .. \) and refer to
+it in the replacement pattern as \n, where n is a digit. The problem outlined
+in the previous paragraph is solved with {:s/s\([^ ]\)/x\1/^M}: try it. Here
+\1 refers to the first pattern grouping \( .. \) in the search string.
+
+Obviously, for a single line, this is rather tedious. Where it becomes
+powerful, if not necessary, is in colon-substitutes that cover a range of
+lines. (See the next section for a particularly comprehensive example.)
+
+If the entire character sequence matched by the search pattern is needed in
+the replacement pattern, then the unescaped character '&' can be used. On
+Line 29 above, try {:s/an e.ample/not &/^M}. If another line is to have the
+word 'not' prepended to a pattern, then '~' can save you from re-typing the
+replacement pattern. E.g. {:s/some pattern/~/^M} after the previous example
+would be equivalent to {:s/some pattern/not &/^M}.
+
+One other useful replacement pattern allows you to change the case of
+individual letters. The sequences {\u} and {\l} cause the immediately
+following character in the replacement to be converted to upper- or lower-case,
+respectively, if this character is a letter. The sequences {\U} and {\L} turn
+such conversion on, either until {\E} or {\e} is encountered, or until the end
+of the replacement pattern.
+
+For example, position the cursor on a line: pick a line, any line. Type
+{:s/.*/\U&/^M} and observe the result. You can undo it with {u}.
+
+The search pattern may actually match more than once on a single line.
+However, only the first pattern is substituted. If you would like ALL
+patterns matched on the line to be substituted, append a 'g' after the
+replacement pattern: {:s/123/456/g^M} will substitute EVERY occurrence
+on the line of 123 with 456.
+
+Section 37: advanced line addressing: {:p} {:g} {:v}
+
+Ex (available through the colon command in vi) offers several methods for
+specifying the lines on which a set of commands will act. For example, if you
+would like to see lines 50 through 100 of your file: {:50,100p^M} will display
+them, wait for you to [Hit return to continue], and leave you on line 100.
+Obviously, it would be easier just to do {100G} from within vi. But
+what if you would like to make changes to just those lines? Then the
+addressing is important and powerful.
+
+Line 30: This is a text.
+Line 31: Here is another text.
+Line 32: One more text line.
+
+The lines above contain a typing error that the author of this tutorial tends
+to make every time he attempts to type the word 'test'. To change all of these
+'text's into 'test's, try the following:
+{:/^Line 30/,/^Line 32/s/text/test/^M}. This finds the beginning and end of
+the portion of text to be changed, and limits the substitution to each of the
+lines in that range. The {u} command applies to ALL of the substitutions as
+a group.
+
+This provides a mechanism for powerful text manipulations.
+And very complicated examples.
+
+Line 33: This test is a.
+Line 34: Here test is another.
+Line 35: One line more test.
+
+The above three lines have the second word out of order. The following command
+string will put things right. Be very careful when typing this: it is very
+long, full of special characters, and easy to mess up. You may want to
+consider reading the following section to understand it before trying the
+experiment. Don't worry about messing up the rest of the file, though: the
+address range is specified.
+
+{:/^Line 33/,/^Line 35/s/\([^:]*\): \([^ ]*\) \([^ ]*\) \([^.]*\)/\1: \2 \4 \3/^M}
+
+There are several things to note about this command string. First of all, the
+range of the substitute was limited by the address specification {/^Line
+33/,/^Line 35/^M}. It might have been simpler to do {:set number^M} to see the
+line numbers directly, and then, in place of the two searches, typed
+the line numbers, e.g. {1396,1398}. Or to mark the lines with {ma} and {mb}
+and use {'a,'b}.
+
+Then follows the substitute pattern itself. To make it easier to understand
+what the substitute is doing, the command is duplicated below with the various
+patterns named for easier reference:
+
+ s/\([^:]*\): \([^ ]*\) \([^ ]*\) \([^.]*\)/\1: \2 \4 \3/
+ |--\1---| |--\2---| |--\3---| |--\4---|
+ |--------search pattern------------------|-replacement|
+ |--pattern---|
+
+In overview, the substitute looks for a particular pattern made up of
+sub-patterns, which are named \1, \2, \3, and \4. These patterns are specified
+by stating what they are NOT. Pattern \1 is the sequence of characters that
+are NOT colons: in the search string, {[^:]} will match exactly one character
+that is not a colon, while appending the asterisk {[^:]*} specifies that the
+'not a colon' pattern is to be repeated until no longer satisfied, and
+{\([^:]*\)} then gives the pattern its name, in this case \1. Outside of the
+specification of \1 comes {: }, specifying that the next two characters must be
+a colon followed by a blank.
+
+Patterns \2 and \3 are similar, specifying character sequences that are
+not blanks. Pattern \4 matches up to the period at the end of the line.
+
+The replacement pattern then consists of specifying the new order of the
+patterns.
+
+This is a particularly complicated example, perhaps the most complicated
+in this tutorial/reference. For our small examples, it is obviously
+tedious and error prone. For large files, however, it may be the most
+efficient way to make the desired modifications.
+
+(The reader is advised to look at the documentation for awk. This tool is very
+powerful and slightly simpler to use than vi for this kind of file
+manipulation. But, it is another command language to learn.)
+
+Many times, you will not want to operate on every line in a certain
+range. Rather you will want to make changes on lines that satisfy
+certain patterns; e.g. for every line that has the string 'NPS' on it,
+change 'NPS' to 'Naval Postgraduate School'. The {:g} addressing
+command was designed for this purpose. The example of this paragraph
+could be typed as {:g/NPS/s//Naval Postgraduate School/^M}.
+
+The general format of the command is {:g/(pattern)/cmds^M} and it
+works in the following way: all lines that match the pattern
+following the {:g} are 'tagged' in a special way. Then each of these
+lines have the commands following the pattern executed over them.
+
+Line 36: ABC rhino george farmer Dick jester lest
+Line 37: george farmer rhino lest jester ABC
+Line 38: rhino lest george Dick farmer ABC jester
+
+Type:
+
+{:g/^Line.*ABC/s/Dick/Harry Binswanger/|s/george farmer/gentleman george/p^M}
+
+There are several things of note here. First, lines 36, 37, and 38 above are
+tagged by the {:g}. Type {:g/^Line.*ABC/p^M} to verify this. Second, there
+are two substitutes on the same line separated by '|'. In general, any colon
+commands can be strung together with '|'. Third, both substitutes operate on
+all three lines, even though the first stubstitute works on only two of the
+lines (36 and 38). Fourth, the second substitute works on only two lines (36
+and 37) and those are the two lines printed by the trailing 'p'.
+
+The {:v} command works similarly to the {:g} command, except that the sense of
+the test for 'tagging' the lines is reversed: all lines NOT matching the search
+pattern are tagged and operated on by the commands.
+
+Using {^V} to quote carriage return (see section 39) can be used in global
+substitutions to split two lines. For example, the command
+{:g/\. /s//.^V^M/g^M} will change your file so that each sentence is on a
+separate line. (Note that we have to 'escape' the '.', because '.' by itself
+matches any character. Our command says to find any line which contains a
+period followed by 2 spaces, and inserts a carriage return after the period.)
+
+Caveat: In some of the documentation for ex and vi you may find the
+comment to the effect that {\^M} can be used between commands following
+{:g}. The author of this tutorial has never gotten this to work and has
+crashed the editor trying.
+
+Section 38: higher level text objects and nroff: {(} {)} [{] [}] {[[} {]]}
+
+(Note: this section may be a little confusing because of our command
+notation. Using curly braces to surround command strings works fine as
+long as the command string does not contain any curly braces itself.
+However, the curly braces are legitimate commands in vi. Therefore, for
+any command sequence that contains curly braces, we will surround that
+sequence with SQUARE braces, as on the previous Section line.)
+
+In working with a document, particularly if using the text formatting
+programs nroff or troff, it is often advantageous to work in terms of
+sentences, paragraphs, and sections. The operations {(} and {)} move to
+the beginning of the previous and next sentences, respectively. Thus
+the command {d)} will delete the rest of the current sentence; likewise
+{d(} will delete the previous sentence if you are at the beginning of
+the current sentence, or, if you are not at the beginning of a sentence,
+it will delete the current sentence from the beginning
+up to where you are.
+
+A sentence is defined to end at a '.', '!', or '?' which is followed
+by either the end of a line, or by two spaces. Any number of closing
+')', ']', '"', and ''' characters may appear after the '.', '!', or '?'
+before the spaces or end of line. Therefore, the {(} and {)} commands
+would recognize only one sentence in the following line, but two
+sentences on the second following line.
+
+Line 39: This is one sentence. Even though it looks like two.
+Line 40: This is two sentences. Because it has two spaces after the '.'.
+
+The operations [{] and [}] move over paragraphs and the operations {[[}
+and {]]} move over sections.
+
+A paragraph begins after each empty line, and also at each of a set of nroff
+paragraph macros. A section begins after each line with a form-feed ^L in the
+first column, and at each of a set of nroff section macros. When preparing a
+text file as input to nroff, you will probably be using a set of nroff macros
+to make the formatting specifications easier, or more to your taste. These
+macros are invoked by beginning a line with a period followed by the one or two
+letter macro name. Vi has been programmed to recognize these nroff macros, and
+if it doesn't recognize your particular macro you can use the {:set paragraphs}
+or {:set sections} commands so that it will.
+
+Section 39: more about inserting text
+
+There are a number of characters which you can use to make correnctions
+during input mode. These are summarized in the following table.
+
+ ^H deletes the last input character
+ ^W deletes the last input word
+ (erase) same as ^H; each terminal can define its own erase character;
+ for some it is ^H, for others it is the DELETE key, and for
+ others it is '@'.
+ (kill) deletes the input on this line; each terminal can define its
+ own line-kill character; for some it is ^U, for others it is
+ '@'; you will need to experiment on your terminal to find
+ out what your line-kill and erase characters are.
+ \ escapes a following ^H, (kill), and (erase) characters: i.e.
+ this is how to put these characters in your file.
+ ^[ escape key; ends insertion mode
+ ^? the delete key; interrupts an insertion, terminating it
+ abnormally.
+ ^M the return key; starts a new line.
+ ^D backtabs over the indentation set by the autoindent option
+ 0^D backtabs over all indentation back to the beginning of the line
+ ^^D (up-arrow followed by control-d)same as 0^D, except the indentation
+ will be restored at the beginning of the next line.
+ ^V quotes the next non-printing character into the file
+
+If you wish to type in your erase or kill character (say # or @ or ^U) then you
+must precede it with a \, just as you would do at the normal system command
+level. A more general way of typing non-printing characters into the file is
+to precede them with a ^V. The ^V echoes as a ^ character on which the cursor
+rests. This indicates that the editor expects you to type a control character
+and it will be inserted into the file at that point. There are a few
+exceptions to note. The implementation of the editor does not allow the null
+character ^@ to appear in files. Also the linefeed character ^J is used by the
+editor to separate lines in the file, so it cannot appear in the middle of a
+line. (Trying to insert a ^M into a file, or putting it in the replacement
+part of a substitution string will result in the matched line being split in
+two. This, in effect, is how to split lines by using a substitution.) You can
+insert any other character, however, if you wait for the editor to echo the ^
+before you type the character. In fact, the editor will treat a following
+letter as a request for the corresponding control character. This is the only
+way to type ^S or ^Q, since the system normally uses them to suspend and resume
+output and never gives them to the editor to process.
+
+If you are using the autoindent option you can backtab over the indent which it
+supplies by typing a ^D. This backs up to the boundary specified by the
+shiftwidth option. This only works immediately after the supplied autoindent.
+
+When you are using the autoindent option you may wish to place a label at the
+left margin of a line. The way to do this easily is to type ^ (up-arrow) and
+then ^D. The editor will move the cursor to the left margin for one line, and
+restore the previous indent on the next. You can also type a 0 followed
+immediately by a ^D if you wish to kill all indentation and not have it resume
+on the next line.
+
+Section 40: more on operators: {d} {c} {<} {>} {!} {=} {y}
+
+Below is a non-exhaustive list of commands that can follow the operators
+to affect the range over which the operators will work. However, note
+that the operators {<}, {>}, {!}, and {=} do not operate on any object
+less than a line. Try {!w} and you will get a beep. To get the
+operator to work on just the current line, double it. E.g. {<<}.
+
+ suffix will operate on
+ ------ ------------------------
+ ^[ cancels the command
+ w the word to the right of the cursor
+ W ditto, but ignoring punctuation
+ b the word to the left of the cursor
+ B ditto, but ignoring punctuation
+ e see below.
+ E ditto
+ (space) a character
+ $ to the end of the line
+ ^ to the beginning of the line
+ / .. / up to, but not including, the string
+ ? .. ? back to and including the string
+ fc up to and including the occurrence of c
+ Fc back to and including the occurrence of c
+ tc up to but not including the occurrence of c
+ Tc back to but not including the occurrence of c
+ ^M TWO lines (that's right: two)
+ (number)^M that many lines plus one
+ (number)G up to and including line (number)
+ ( the previous sentence if you are at the beginning of
+ the current sentence, or the current sentence up to where
+ you are if you are not at the beginning of the current
+ sentence. Here, 'sentence' refers to the intuitive
+ notion of an English sentence, ending with '!', '?',
+ or '.' and followed by an end of line or two spaces.
+ ) the rest of the current sentence
+ { analogous to '(', but in reference to paragraphs:
+ sections of text surrounded by blank lines
+ } analogous to ')', but in reference to paragraphs
+ [[ analogous to '(', but in reference to sections
+ ]] analogous to ')', but in reference to sections
+ H the first line on the screen
+ M the middle line on the screen
+ L the last line on the screen
+ 3L through the third line from the bottom of the screen
+ ^F forward a screenful
+ ^B backward a screenful
+ :
+ : etc. etc. etc.
+
+This list is not exhaustive, but it should be sufficient to get the idea
+across: after the operator, you can specify a range with a move-the-cursor
+command, and that is the region of text over which the operator will be
+effective.
+
+Section 41: abbreviations: {:ab}
+
+When typing large documents you may find yourself typing a large phrase
+over and over. Vi gives you the ability to specify an abbreviation for
+a long string such that typing the abbreviation will automatically
+expand into the longer phrase.
+
+Type {:ab nps Naval Postgraduate School^M}. Now type:
+
+{iThis is to show off the nps's UNIX editor.^M^[}
+
+Section 42: vi's relationship with the ex editor: {:}
+
+Vi is actually one mode of editing within the editor ex. When you are
+running vi you can escape to the line oriented editor of ex by giving
+the command {Q}. All of the colon-commands which were introduced above
+are available in ex. Likewise, most ex commands can be invoked from vi
+using {:}.
+
+In rare instances, an internal error may occur in vi. In this case you
+will get a diagnostic and will be left in the command mode of ex. You can
+then save your work and quit if you wish by giving the command {x} after
+the colon prompt of ex. Or you can reenter vi (if you are brave) by
+giving ex the command {vi}.
+
+Section 43: vi on hardcopy terminals and dumb terminals: open mode
+
+(The author has not checked the following documentation for accuracy. It is
+abstracted from the Introduction to Vi Editing document.)
+
+If you are on a hardcopy terminal or a terminal which does not have a cursor
+which can move off the bottom line, you can still use the command set of vi,
+but in a different mode. When you give the vi command to UNIX, the editor will
+tell you that it is using open mode. This name comes from the open command in
+ex, which is used to get into the same mode.
+
+The only difference between visual mode (normal vi) and open mode is the way in
+which the text is displayed.
+
+In open mode the editor uses a single line window into the file, and moving
+backward and forward in the file causes new lines to be displayed, always below
+the current line. Two commands of vi work differently in open: {z} and {^R}.
+The {z} command does not take parameters, but rather draws a window of context
+around the current line and then returns you to the current line.
+
+If you are on a hardcopy terminal, the {^R} command will retype the current
+line. On such terminals, the editor normally uses two lines to represent the
+current line. The first line is a copy of the line as you started to edit it,
+and you work on the line below this line. When you delete characters, the
+editor types a number of \'s to show you the characters which are deleted. The
+editor also reprints the current line soon after such changes so that you can
+see what the line looks like again.
+
+It is sometimes useful to use this mode on very slow terminals which can
+support vi in the full screen mode. You can do this by entering ex and using
+an {open} command.
+
+*********************************************************************
+Section 44: options: {:set} {setenv EXINIT}
+
+You will discover options as you need them. Do not worry about them very much
+on the first pass through this document. My advice is to glance through them,
+noting the ones that look interesting, ignoring the ones you don't understand,
+and try re-scanning them in a couple of weeks.
+
+If you decide that you have a favorite set of options and would like to change
+the default values for the editor, place a {setenv EXINIT} command in your
+.login file. When you are given an account under UNIX your directory has
+placed in it a file that is executed each time you log in. If one of the
+commands in this file sets the environment variable EXINIT to a string of vi
+commands, you can have many things done for you each time you invoke vi. For
+example, if you decide that you don't like tabstops placed every eight columns
+but prefer every four columns, and that you wish the editor to insert linefeeds
+for you when your typing gets you close to column 72, and you want
+autoindentation, then include the following line in your .login file:
+
+setenv EXINIT='set tabstop=4 wrapmargin=8 autoindent'
+
+or equivalently
+
+setenv EXINIT='se ts=4 wm=8 ai'
+
+Each time you bring up vi, this command will be executed and the options set.
+
+There are forty options in the vi/ex editor that the user can set for his/her
+own convenience. They are described in more detail in individual sections
+below. The section line will show the full spelling of the option name, the
+abbreviation, and the default value of the option. The text itself
+comes from the ex reference manual and is not the epitome of clarity.
+
+Section 44.1: {autoindent}, {ai} default: noai
+
+Can be used to ease the preparation of structured program text. At the
+beginning of each append, change or insert command or when a new line is opened
+or created by an append, change, insert, or substitute operation within open or
+visual mode, ex looks at the line being appended after, the first line changed
+or the line inserted before and calculates the amount of white space at the
+start of the line. It then aligns the cursor at the level of indentation so
+determined.
+
+If the user then types lines of text in, they will continue to be justified at
+the displayed indenting level. If more white space is typed at the beginning
+of a line, the following line will start aligned with the first non-white
+character of the previous line. To back the cursor up to the preceding tab
+stop one can hit {^D}. The tab stops going backwards are defined at multiples
+of the shiftwidth option. You cannot backspace over the indent, except by
+sending an end-of-file with a {^D}. A line with no characters added to it
+turns into a completely blank line (the white space provided for the autoindent
+is discarded). Also specially processed in this mode are lines beginning with
+an up-arrow `^' and immediately followed by a {^D}. This causes the input to
+be repositioned at the beginning of the line, but retaining the previous indent
+for the next line. Similarly, a `0' followed by a {^D} repositions at the
+beginning but without retaining the previous indent. Autoindent doesn't happen
+in global commands or when the input is not a terminal.
+
+Section 44.2: {autoprint}, {ap} default: ap
+
+Causes the current line to be printed after each delete, copy, join, move,
+substitute, t, undo or shift command. This has the same effect as supplying a
+trailing `p' to each such command. Autoprint is suppressed in globals, and
+only applies to the last of many commands on a line.
+
+Section 44.3: {autowrite}, {aw} default: noaw
+
+Causes the contents of the buffer to be written to the current file if you have
+modified it and give a next, rewind, stop, tag, or {!} command, or a control-
+up-arrow {^^} (switch files) or {^]} (tag goto) command in visual. Note, that
+the edit and ex commands do not autowrite. In each case, there is an
+equivalent way of switching when autowrite is set to avoid the autowrite
+({edit} for next, rewind! for rewind, stop! for stop, tag! for tag, shell
+for {!}, and {:e #} and a {:ta!} command from within visual).
+
+Section 44.4: {beautify}, {bf} default: nobeautify
+
+Causes all control characters except tab ^I, newline ^M and form-feed ^L to be
+discarded from the input. A complaint is registered the first time a backspace
+character is discarded. Beautify does not apply to command input.
+
+Section 44.5: {directory}, {dir} default: dir=/tmp
+
+Specifies the directory in which ex places its buffer file. If this directory
+in not writable, then the editor will exit abruptly when it fails to be able to
+create its buffer there.
+
+Section 44.6: {edcompatible} default: noedcompatible
+
+Causes the presence or absence of g and c suffixes on substitute commands to be
+remembered, and to be toggled by repeating the suffices. The suffix r makes
+the substitution be as in the {~} command, instead of like {&}.
+
+[Author's note: this should not concern users of vi.]
+
+Section 44.7: {errorbells}, {eb} default: noeb
+
+Error messages are preceded by a bell. However, bell ringing in open and
+visual modes on errors is not suppressed by setting noeb. If possible the
+editor always places the error message in a standout mode of the terminal (such
+as inverse video) instead of ringing the bell.
+
+Section 44.8: {hardtabs}, {ht} default: ht=8
+
+Gives the boundaries on which terminal hardware tabs are set (or on which the
+system expands tabs).
+
+Section 44.9: {ignorecase}, {ic} default: noic
+
+All upper case characters in the text are mapped to lower case in regular
+expression matching. In addition, all upper case characters in regular
+expressions are mapped to lower case except in character class specifications
+(that is, character in square brackets).
+
+Section 44.10: {lisp} default: nolisp
+
+Autoindent indents appropriately for lisp code, and the {(}, {)}, [{], [}],
+{[[}, and {]]} commands in open and visual modes are modified in a
+striaghtforward, intuitive fashion to have meaning for lisp.
+
+[Author's note: but don't ask me to define them precisely.]
+
+Section 44.11: {list} default: nolist
+
+All printed lines will be displayed (more) unambiguously, showing tabs as ^I
+and end-of-lines with `$'. This is the same as in the ex command {list}.
+
+Section 44.12: {magic} default: magic for {ex} and {vi}, nomagic for edit.
+
+If nomagic is set, the number of regular expression metacharacters is greatly
+reduced, with only up-arrow `^' and `$' having special effects. In addition
+the metacharacters `~' and `&' of the replacement pattern are treated as normal
+characters. All the normal metacharacters may be made magic when nomagic is
+set by preceding them with a `\'.
+
+[Author's note: In other words, if magic is set a back-slant turns the magic
+off for the following character, and if nomagic is set a back-slant turns the
+magic ON for the following character. And, no, we are not playing Dungeons and
+Dragons, although I think the writers of these option notes must have played it
+all the time.]
+
+Section 44.13: {mesg} default: mesg
+
+Causes write permission to be turned off to the terminal while you are in
+visual mode, if nomesg is set.
+
+[Author's note: I don't know if anyone could have made any one sentence
+paragraph more confusing than this one. What it says is: mesg allows people to
+write to you even if you are in visual or open mode; nomesg locks your terminal
+so they can't write to you and mess up your screen.]
+
+Section 44.14: {number, nu} default: nonumber
+
+Causes all output lines to be printed with their line numbers. In addition
+each input line will be prompted with its line number.
+
+Section 44.15: {open} default: open
+
+If {noopen}, the commands open and visual are not permitted. This is set for
+edit to prevent confusion resulting from accidental entry to open or visual
+mode.
+
+[Author's note: As you may have guessed by now, there are actually three
+editors available under Berkeley UNIX that are in reality the same
+program, ex, with different options set: ex itself, vi, and edit.]
+
+Section 44.16: {optimize, opt} default: optimize
+
+Throughput of text is expedited by setting the terminal to not do automatic
+carriage returns when printing more than one (logical) line of output, greatly
+speeding output on terminals without addressable cursors when text with leading
+white space is printed.
+
+[Author's note: I still don't know what this option does.]
+
+Section 44.17: {paragraphs, para} default: para=IPLPPPQPP LIbp
+
+Specifies the paragraphs for the [{] and [}] operations in open and visual.
+The pairs of characters in the option's value are the names of the nroff macros
+which start paragraphs.
+
+Section 44.18: {prompt} default: prompt
+
+Command mode input is prompted for with a `:'.
+
+[Author's note: Doesn't seem to have any effect on vi.]
+
+Section 44.19: {readonly}, {ro} default: noro, unless invoked with -R
+ or insufficient privileges on file
+
+This option allows you to guarantee that you won't clobber your file by
+accident. You can set the option and writes will fail unless you use an `!'
+after the write. Commands such as {x}, {ZZ}, the autowrite option, and in
+general anything that writes is affected. This option is turned on if you
+invoke the editor with the -R flag.
+
+Section 44.20: {redraw} default: noredraw
+
+The editor simulates (using great amounts of output), an intelligent terminal
+on a dumb terminal (e.g. during insertions in visual the characters to the
+right of the cursor position are refreshed as each input character is typed).
+Useful only at very high baud rates, and should be used only if the system is
+not heavily loaded: you will notice the performance degradation yourself.
+
+Section 44.21: {remap} default: remap
+
+If on, macros are repeatedly tried until they are unchanged. For example, if o
+is mapped to O, and O is mapped to I, then if remap is set, o will map to I,
+but if noremap is set, it will map to O .
+
+Section 44.22: {report} default: report=5 for ex and vi, 2 for edit
+
+Specifies a threshold for feedback from commands. Any command which modifies
+more than the specified number of lines will provide feedback as to the scope
+of its changes. For commands such as global, open, undo, and visual which have
+potentially more far reaching scope, the net change in the number of lines in
+the buffer is presented at the end of the command, subject to this same
+threshold. Thus notification is suppressed during a global command on the
+individual commands performed.
+
+Section 44.23: {scroll} default: scroll=1/2 window
+
+Determines the number of logical lines scrolled when a {^D} is received from a
+terminal in command mode, and determines the number of lines printed by a
+command mode z command (double the value of scroll).
+
+[Author's note: Doesn't seem to affect {^D} and {z} in visual (vi) mode.]
+
+Section 44.24: sections {sections} default: sections=SHNHH HU
+
+Specifies the section macros from nroff for the {[[} and {]]} operations in
+open and visual. The pairs of characters in the options's value are the names
+of the macros which start paragraphs.
+
+Section 44.25: {shell}, {sh} default: sh=/bin/sh
+
+Gives the path name of the shell forked for the shell escape command `!', and
+by the shell command. The default is taken from SHELL in the environment, if
+present.
+
+[Editor's note: I would suggest that you place the following line in
+your .login file:
+setenv SHELL '/bin/csh'
+]
+
+Section 44.26: {shiftwidth}, {sw} default: sw=8
+
+Used in reverse tabbing with {^D} when using autoindent to append text, and
+used by the shift commands. Should probably be the same value as the tabstop
+option.
+
+Section 44.27: {showmatch}, {sm} default: nosm
+
+In open and visual mode, when a `)' or `}' is typed, if the matching `(' or `{'
+is on the screen, move the cursor to it for one second. Extremely useful with
+complicated nested expressions, or with lisp.
+
+Section 44.28: {slowopen}, {slow} default: terminal dependent
+
+Affects the display algorithm used in visual mode, holding off display updating
+during input of new text to improve throughput when the terminal in use is both
+slow and unintelligent. See "An Introduction to Display Editing with Vi" for
+more details.
+
+Section 44.29: {tabstop}, {ts} default: ts=8
+
+The editor expands tabs ^I to tabstop boundaries in the display.
+
+Section 44.30: {taglength}, {tl} default: tl=0
+
+Tags are not significant beyond this many characters.
+A value of zero (the default) means that all characters are significant.
+
+Section 44.31: {tags} default: tags=tags /usr/lib/tags
+
+A path of files to be used as tag files for the tag command. A requested tag
+is searched for in the specified files, sequentially. By default files called
+tags are searched for in the current directory and in /usr/lib (a master file
+for the entire system).
+
+[Author's note: The author of this tutorial has never used this option, nor
+seen it used. I'm not even sure I know what they are talking about.]
+
+Section 44.32: {term} default: from environment variable TERM
+
+The terminal type of the output device.
+
+Section 44.33: {terse} default: noterse
+
+Shorter error diagnostics are produced for the experienced user.
+
+Section 44.34: {timeout} default: timeout
+
+Causes macros to time out after one second. Turn it off and they will
+wait forever. This is useful if you want multi-character macros, but if
+your terminal sends escape sequences for arrow keys, it will be
+necessary to hit escape twice to get a beep.
+
+[Editor's note: Another paragraph which requires a cryptographer.]
+
+Section 44.35: ttytype
+
+[Editor's note: I have found no documentation for this option at all.]
+
+Section 44.36: {warn} default: warn
+
+Warn if there has been `[No write since last change]' before a `!' command
+escape.
+
+Section 44.37: {window} default: window=speed dependent
+
+The number of lines in a text window in the visual command. The default is 8
+at slow speeds (600 baud or less), 16 at medium speed (1200 baud), and the full
+screen (minus one line) at higher speeds.
+
+Section 44.38: {wrapscan}, {ws} default: ws
+
+Searches using the regular expressions in addressing will wrap around past the
+end of the file.
+
+Section 44.39: {wrapmargin}, {wm} default: wm=0
+
+Defines a margin for automatic wrapover of text during input in open and visual
+modes. The numeric value is the number of columns from the right edge of the
+screen around which vi looks for a convenient place to insert a new-line
+character (wm=0 is OFF). This is very convenient for touch typists.
+Wrapmargin behaves much like fill/nojustify mode does in nroff.
+
+Section 44.40: {writeany}, {wa} default: nowa
+
+Inhibit the checks normally made before write commands, allowing a write to any
+file which the system protection mechanism will allow.
+
+Section 44.41: {w300}, {w1200}, {w9600} defaults: w300=8
+ w1200=16
+ w9600=full screen minus one
+
+These are not true options but set the default size of the window for when the
+speed is slow (300), medium (1200), or high (9600), respectively. They are
+suitable for an EXINIT and make it easy to change the 8/16/full screen rule.
+
+Section 45: Limitations
+
+Here are some editor limits that the user is likely to encounter:
+ 1024 characters per line
+ 256 characters per global command list
+ 128 characters per file name
+ 128 characters in the previous inserted and deleted text in open or
+ visual
+ 100 characters in a shell escape command
+ 63 characters in a string valued option
+ 30 characters in a tag name
+ 250000 lines in the file (this is silently enforced).
+
+The visual implementation limits the number of macros defined with map to 32,
+and the total number of characters in macros to be less than 512.
+
+[Editor's note: these limits may not apply to versions after 4.1BSD.]
diff --git a/usr.bin/vi/docs/tutorial/vi.beginner b/usr.bin/vi/docs/tutorial/vi.beginner
new file mode 100644
index 000000000000..3bf35ac939f8
--- /dev/null
+++ b/usr.bin/vi/docs/tutorial/vi.beginner
@@ -0,0 +1,741 @@
+Section 1: {^F} {ZZ}
+
+To get out of this tutorial, type: ZZ (two capital Z's).
+
+Learning a new computer system implies learning a new text editor. These
+tutorial lessons were created by Dain Samples to help you come to grips with
+UC Berkeley's screen oriented editor called vi (for VIsual). This tutorial
+uses the vi editor itself as the means of presentation.
+
+For best use of this tutorial, read all of a screen before performing any of
+the indicated actions. This tutorial (or, at least, the first half of it) has
+been designed to systematically present the vi commands IF THE INSTRUCTIONS
+ARE FOLLOWED! If you are too adventuresome, you may find yourself lost. If
+you ever find yourself stuck, remember the first line of this section.
+
+OK, now find the control key on your keyboard; it usually has CTL or CTRL
+written on its upper surface. Your first assignment is to hold the control
+key down while you press the 'F' key on your keyboard. Please do so now.
+
+
+
+Section 2: {^F} {^B}
+Many of vi's commands use the control key and some other key in combination,
+as with the control and the 'F' key above. This is abbreviated CTL-F, or ^F.
+
+As you have probably guessed by now, ^F (CTL-F) moves you forward a fixed
+number of lines in the file. Throughout the remainder of the tutorial when
+you are ready to advance to the next section of text, hit ^F.
+
+The opposite command is ^B. Just for fun, you might want to try a ^B to see
+the previous section again. Be sure to do a ^F to return you here.
+
+Determine what the cursor looks like on your screen. Whatever it is (a box,
+an underscore, blinking, flashing, inverse, etc.) it should now be positioned
+in the upper left-hand corner of your screen under or on the S of Section.
+Become familiar with your cursor: to use vi correctly it is important to
+always know where the cursor is.
+
+Did you notice that when you do a ^F the cursor is left at the top of the
+screen, and a ^B leaves the cursor near the bottom of the screen? Try the two
+commands ^B^F again. And now do another ^F to see the next section.
+
+Section 3: {^F} {^B}
+You now have two basic commands for examining a file, both forwards (^F) and
+backwards (^B).
+
+Note that these are vi text editing commands: they are not commands for the
+tutorial. Indeed, this tutorial is nothing but a text file which you are now
+editing. Everything you do and learn in this tutorial will be applicable to
+editing text files.
+
+Therefore, when you are editing a file and are ready to see more of the text,
+entering ^F will get you to the next section of the file. Entering ^B will
+show you the previous section.
+
+Time for you to do another ^F.
+
+
+
+
+
+
+
+Section 4: {^F} {^B} {^M} (return key)
+We will adopt the notation of putting commands in curly braces so we can write
+them unambiguously. For example, if you are to type the command sequence
+"control B control F" (as we asked you to do above) it would appear as {^B^F}.
+This allows clear delineation of the command strings from the text. Remember
+that the curly braces are NOT part of the command string you are to type. Do
+NOT type the curly braces.
+
+Sometimes, the command string in the curly braces will be rather long, and may
+be such that the first couple of characters of the command will erase from
+the screen the string you are trying to read and type. It is suggested that
+you write down the longer commands BEFORE you type them so you won't forget
+them once they disappear.
+
+Now locate the return key on your keyboard: it is usually marked 'RETURN',
+indicate hitting the return key. In fact, the control-M key sequence is
+exactly the same as if you hit the return key, and vice versa.
+
+Now type {^F}.
+
+
+Section 5: {:q!} {ZZ} {^M} (return key)
+Recognize that this tutorial is nothing more than a text file that you
+are editing. This means that if you do something wrong, it is possible
+for you to destroy the information in this file. Don't worry. If this
+happens, type {ZZ} (two capital Z's) or {:q!^M} to leave the tutorial.
+Restart the tutorial. Once in the tutorial, you can then page forward
+with {^F} until you are back to where you want to be. (There are
+easier ways to do this, some of which will be discussed later, but this
+is the most straightforward.)
+
+You may want to write these commands down in a convenient place for quick
+reference: {:q!^M} and {ZZ}
+
+We will assume that you now know to do a {^F} to advance the file
+
+
+
+
+
+
+
+Section 6: {m} {G} {'} {z}
+Now that you know how to get around in the file via ^F and ^B let's look at
+other ways of examining a text file. Sometimes it is necessary, in the midst
+of editing a file, to examine another part of the file. You are then faced
+with the problem of remembering your place in the file, looking at the other
+text, and then getting back to your original location. Vi has a 'mark'
+command, m. Type {mp}. You have just 'marked' your current location in the
+file and given it the name 'p'. The command string below will do three
+things: position you at the beginning of the file (line 1), then return you to
+the location 'p' that you just marked with the 'm' command, and, since the
+screen will not look exactly the same as it does right now, the 'z' command
+will reposition the screen. (You may want to write the string down before
+typing it: once you type {1G} it will no longer be on the screen.)
+
+So now type {1G'pz^M} - a one followed by a capital G, followed by the quote
+mark, followed by a lower case 'p', then a lower case 'z', then a return
+(which is the same as a ^M). The {1G} moves you to line 1, i.e. the beginning
+of the file. The {'p} moves you to the location you marked with {mp}. The
+{z^M} command will repaint the screen putting the cursor at the top of the
+screen. (Now {^F}.)
+
+Section 7: {m} {G} {'} {z}
+Let's look at some variations on those commands. If you wanted to look at
+line 22 in the file and return to this location you could type {mp22G'p}. Do
+so now, observing that {22G} puts your cursor at the beginning of section 2 in
+the middle of the screen.
+
+Also note that, without the {z^M} command, the line with 'Section 7' on it is
+now in the MIDDLE of the screen, and not at the top. Our cursor is on the
+correct line (where we did the {mp} command) but the line is not where we
+might like it to be on the screen. That is the function of the {z^M} command.
+(Remember, ^M is the same as the 'return' key on your keyboard.) Type {z^M}
+now and observe the effect.
+
+As you can see, the 'Section 7' line is now at the top of the screen with the
+cursor happily under the capital S. If you would like the cursor line (i.e.
+the line which the cursor is on) in the middle of the screen again, you would
+type {z.}. If you wanted the cursor line to be at the BOTTOM of the screen,
+type {z-}. Try typing {z-z.z^M} and watch what happens.
+
+{^F}
+
+Section 8: {z} {m} {'}
+
+Note that the z command does not change the position of our cursor in the file
+itself, it simply moves the cursor around on the screen by moving the contents
+of the file around on the screen. The cursor stays on the same line of the
+file when using the z command.
+
+This brings up an important point. There are two questions that the users of
+vi continually need to know the answer to: "Where am I in the file?" and
+"Where am I on the screen?" The cursor on your terminal shows the answer to
+both questions. Some commands will move you around in the file, usually
+changing the location of the cursor on the screen as well. Other commands
+move the cursor around on the screen without changing your location in the
+file.
+
+Now type {ma}. Your location in the file has been given the name 'a'. If you
+type {'p'a} you will see the previous location we marked in section 7, and
+then will be returned to the current location. (You will want to do a {z^M}
+to repaint the screen afterwards.) Try it.
+{^F}
+
+Section 9: {m} {''}
+Now we can move about in our file pretty freely. By using the {m} command we
+can give the current cursor position a lower-case-character name, like 'p',
+'a', 'e', 'm', or 'b'. Using the {G} command preceded by a line number we can
+look at any line in the file we like. Using the single quote command {'}
+followed by a character used in an {m} command, we can return to any location
+in the file we have marked.
+
+However, try {m3}, or {mM}. You should hear a beep, or bell. Only lower-case
+letters are acceptable to the {m} and {'} commands: numbers, upper-case
+letters, and special characters are not acceptable.
+
+If you type the {'} command with a character that is lower-case alphabetic but
+that has not been used in an {m} command, or for which the 'marked' text has
+been deleted, you will also get a beep. Try {'i}. You should get a beep
+because the command {mi} has never been issued. (Unless you've been
+experimenting.)
+
+The command {''} attempts to return you to the location at which you last
+modified some part of your file. However, my experience has been that it is
+difficult to predict exactly where you will end up.
+Section 10: {^M} {-}
+Now do {ma}, marking your position at the top of the screen. Now hit {^M} (or
+return) until the cursor is right ...
+* <- here, over/under the asterisk. Now
+type {mb'a'b} and watch the cursor move from the asterisk to the top of the
+screen and back again.
+
+The {^M} command moves the cursor to the beginning of the next line. Now type
+{^M} until the cursor is right ...
+* <- here. The command to move the cursor to the beginning of the
+previous line is {-}. Practice moving the cursor around on the screen by using
+{^M} and {-}. BE CAREFUL to not move the cursor OFF the screen just yet. If
+you do, type {'az^M}.
+
+Now we can move to any line within the screen. Practice moving around in the
+file using the {^F}, {^B}, {-}, {^M}, {z}, and {'} commands. When you are
+fairly confident that you can get to where you need to be in the file, and
+position the cursor on the screen where you want it type {'az^M^F} (which, of
+course, moves you back to the beginning of this section, repositions the
+cursor at the top of the screen, and advances you to the next section).
+
+Section 11: scrolling: {^M}
+The cursor should now be on the S of 'Section 11', and this should be on the
+first line of the screen. If it is not, do {^M} or {-} as appropriate to put
+the cursor on the section line, and type {z^M}.
+
+Type {mc} to mark your place.
+
+Now type {^M} until the cursor is on the last line of this screen. Now do one
+more {^M} and observe the result. This is called scrolling. When you
+attempted to move to a line not displayed on the screen, the line at the top of
+the screen was 'scrolled off', and a line at the bottom of the screen was
+'scrolled on'. The top line with 'Section 11' should no longer be visible.
+
+Now type {'cz^M} to reset the screen and type {^F} for the next section.
+
+
+
+
+
+
+
+Section 12: {-} {z}
+
+The {-} command moves the cursor to the previous line in the file. Now type
+{-}, which attempts to move the cursor to the previous line in this file.
+However, that line is not on the screen. The resulting action will depend on
+your terminal. (Do a {^Mz^M} to reposition the file). On intelligent
+terminals (e.g. VT100s, Z19s, Concept 100s), a top line is 'scrolled on' and
+the bottom line is 'scrolled off'. Other terminals, however, may not have
+this 'reverse scrolling' feature. They will simply repaint the screen with
+the cursor line in the middle of the screen. On such terminals it is
+necessary to type {z^M} to get the cursor line back to the top of the screen.
+
+
+
+
+
+
+
+
+
+
+Section 13:
+Up until this point, the tutorial has always tried to make sure that the first
+line of each screen has on it the section number and a list of the commands
+covered in that section. This will no longer be strictly maintained. If you
+want the section line at the top of the screen, you now know enough commands to
+do it easily: do {^M} or {-} until the cursor is on the section line and
+then {z^M}. Also, from this point on, it may not be the case that a {^F} will
+put you at the beginning of the next section. Therefore, be aware of where you
+are in the file as we look at other commands. You may have to find your way
+back to a particular section without any help from the tutorial. If you do not
+feel comfortable with this, then it is suggested that you practice moving from
+section 1 to section 13, back and forth, using {^M}, {-}, {^F}, and {^B}
+commands for a while.
+
+Also make liberal use of the mark command {m}: if, for example, you make a
+habit of using {mz} to mark your current location in the file, then you will
+always be able to return to that location with {'z} if the editor does
+something strange and you have no idea where you are or what happened.
+
+And finally, the proscription against experimentation is hereby lifted: play
+with the editor. Feel free to try out variations on the commands and move
+around in the file. By this time you should be able to recover from any gross
+errors.
+
+Section 14: {^E} {^Y} {^D} {^U}
+Let us now look at a few other commands for moving around in the file, and
+moving the file around on the screen. Note that the commands we have already
+looked at are sufficient: you really don't need any more commands for looking
+in a file. The following commands are not absolutely necessary. However,
+they can make editing more convenient, and you should take note of their
+existence. But it would be perfectly valid to decide to ignore them on this
+first pass: you can learn them later when you see a need for them, if you ever
+do.
+
+First, let's clear up some potentially confusing language. In at least one
+place in the official document ('An Introduction to Display Editing with Vi'
+by William Joy, and Mark Horton, September 1980), the expression "to scroll
+down text" means that the cursor is moved down in your file. However, note
+that this may result in the text on the screen moving UP. This use of the
+word 'scroll' refers to the action of the cursor within the file. However,
+another legitimate use of the word refers to the action of the text on the
+screen. That is, if the lines on your screen move up toward the top of the
+screen, this would be 'scrolling the screen up'. If the lines move down
+toward the bottom of the screen, this would be refered to as scrolling down.
+
+I have tried to maintain the following jargon: 'scrolling' refers to what the
+text does on the screen, not to what the cursor does within the file. For the
+latter I will refer to the cursor 'moving', or to 'moving the cursor'. I
+realize that this is not necessarily consistent with Joy and Horton, but they
+were wrong.
+
+{^E} scrolls the whole screen up one line, keeping the cursor on the same line,
+if possible. However, if the cursor line is the first line on the screen, then
+the cursor is moved to the next line in the file. Try typing {^E}.
+
+{^Y} scrolls the screen down one line, keeping the cursor on the same line, if
+possible. However, if the cursor line is the last line on the screen, then the
+cursor is moved to the previous line in the file. Try it.
+
+{^D} moves the cursor down into the file, scrolling the screen up.
+
+{^U} moves the cursor up into the file, also scrolling the screen if the
+terminal you are on has the reverse scroll capability. Otherwise the
+screen is repainted.
+
+Note that {^E} and {^Y} move the cursor on the screen while trying to keep the
+cursor at the same place in the file (if possible: however, the cursor can
+never move off screen), while {^D} and {^U} keep the cursor at the same place
+on the screen while moving the cursor within the file.
+
+Section 15: {/ .. /^M}
+
+Another way to position yourself in the file is by giving the editor a string
+to search for. Type the following: {/Here 1/^M} and the cursor should end up
+right ...........................here ^. Now type {/Section 15:/^M} and the
+cursor will end up over/on .....................here ^. Now type {//^M} and
+observe that the cursor is now over the capital S five lines above this line.
+Typing {//^M} several more times will bounce the cursor back and forth between
+the two occurrences of the string. In other words, when you type a string
+between the two slashes, it is searched for. Typing the slashes with nothing
+between them acts as if you had typed the previous string again.
+
+Observe that the string you type between the two slashes is entered on the
+bottom line of the screen. Now type {/Search for x /^M} except replace the 'x'
+in the string with some other character, say 'b'. The message "Pattern not
+found" should appear on the bottom of the screen. If you hadn't replaced the
+'x', then you would have found the string. Try it.
+
+Section 16: {? .. ?^M} {n} (search strings: ^ $)
+
+When you surround the sought-for string with slashes as in {/Search/}, the
+file is searched beginning from your current position in the file. If the
+string is not found by the end of the file, searching is restarted at the
+beginning of the file. However, if you do want the search to find the
+PREVIOUS rather than the NEXT occurrence of the string, surround the string
+with question marks instead of slash marks.
+
+Below are several occurrences of the same string.
+Here 2 Here 2 Here 2
+ Here 2 Here 2.
+Observe the effect of the following search commands (try them in the
+sequence shown):
+{/Here 2/^M} {//^M} {??^M}
+{/^Here 2/^M} {//^M} {??^M}
+{/Here 2$/^M} {//^M} {??^M}
+
+The first command looks for the next occurrence of the string 'Here 2'.
+However the second line of commands looks for an occurrence of 'Here 2' that
+is at the beginning of the line. When the up-arrow is the first character of
+a search string it stands for the beginning of the line. When the dollar-sign
+is the last character of the search string it stands for the end of the line.
+Therefore, the third line of commands searches for the string only when it is
+at the end of the line. Since there is only one place the string begins a
+line, and only one place the string ends the line, subsequent {//^M} and
+{??^M} will find those same strings over and over.
+
+The {n} command will find the next occurrence of the / or ? search
+string. Try {/Here 2/^M} followed by several {n} and observe the
+effect. Then try {??^M} followed by several {n}. The {n} command
+remembers the direction of the last search. It is just a way to save a
+few keystrokes.
+
+Section 17: \ and magic-characters in search strings
+
+Now type {/Here 3$/^M}. You might expect the cursor to end up
+right......^ here. However, you will get "Pattern not found" at the bottom of
+the screen. Remember that the dollar-sign stands for the end of the line.
+Somehow, you must tell vi that you do not want the end of the line, but a
+dollar-sign. In other words, you must take away the special meaning that the
+dollar-sign has for the search mechanism. You do this (for any special
+character, including the up-arrow ^) by putting a back-slash ('\', not '/') in
+front of the character.
+
+Now try {/Here 3\$/^M} and you should end up nine lines above this one. Try
+{//^M} and note that it returns you to the same place, and not to the first
+line of this paragraph: the back-slash character is not part of the search
+string and will not be found. To find the string in the first line of this
+paragraph, type {/Here 3\\\$/^M}. There are three back-slashes: the first takes
+away the special meaning from the second, and the third takes away the special
+meaning from the dollar-sign.
+
+Following is a list of the characters that have special meanings in search
+strings. If you wish to find a string containing one of these characters, you
+will have to be precede the character with a backslash. These characters are
+called magic characters because of the fun and games you can have with them
+and they can have with you, if you aren't aware of what they do.
+
+ ^ - (up-arrow) beginning of a line
+ $ - (dollar-sign) end of a line
+ . - (period) matches any character
+ \ - (backslant) the escape character itself
+ [ - (square bracket) for finding patterns (see section #SEARCH)
+ ] - (square bracket) ditto
+ * - (asterisk) ditto
+
+Without trying to explain it here, note that {:set nomagic^M} turns off the
+special meanings of all but the ^ up-arrow, $ dollar-sign, and backslash
+characters.
+
+Section 18: {: (colon commands)} {ZZ}
+
+In this section we will discuss getting into and out of the editor in more
+detail. If you are editing a file and wish to save the results the command
+sequence {:w^M} writes the current contents of the file out to disk, using the
+file name you used when you invoked the editor. That is, if you are at the
+command level in Unix, and you invoke vi with {vi foo} where foo is the name
+of the file you wish to edit, then foo is the name of the file used by the
+{:w^M} command.
+
+If you are done, the write and quit commands can be combined into a single
+command {:wq^M}. An even simpler way is the command {ZZ} (two capital Z's).
+
+If, for some reason, you wish to exit without saving any changes you have made,
+{:q!^M} does the trick. If you have not made any changes, the exclamation
+point is not necessary: {:q^M}. Vi is pretty good about not letting you
+get out without warning you that you haven't saved your file.
+
+We have mentioned before that you are currently in the vi editor, editing a
+file. If you wish to start the tutorial over from the very beginning, you
+could {ZZ}, and then type {vi.tut beginner} in response to the Unix prompt.
+This will create a fresh copy of this file for you, which might be necessary
+if you accidentally destroyed the copy you were working with. Just do a
+search for the last section you were in: e.g. {/Section 18:/^Mz^M}.
+
+Section 19: {H} {M} {L}
+
+Here are a few more commands that will move you around on the screen. Again,
+they are not absolutely necessary, but they can make screen positioning easier:
+
+{H} - puts the cursor at the top of the screen (the 'home' position)
+
+{M} - puts the cursor in the middle of the screen
+
+{L} - puts the cursor at the bottom of the screen.
+
+Try typing {HML} and watch the cursor.
+
+Try typing {5HM5L} and note that 5H puts you five lines from the top of the
+screen, and 5L puts you five lines from the bottom of the screen.
+
+Section 20: {w} {b} {0} {W} {B} {e} {E} {'} {`}
+
+Up to this point we have concentrated on positioning in the file, and
+positioning on the screen. Now let's look at positioning in a line. Put the
+cursor at the beginning of the following line and type {z^M}:
+
+This is a test line: your cursor should initially be at its beginning.
+
+The test line should now be at the top of your screen. Type {w} several times.
+Note that it moves you forward to the beginning of the next word. Now type
+{b} (back to the beginning of the word) several times till you are at the
+beginning of the line. (If you accidentally type too many {b}, type {w} until
+you are on the beginning of the line again.) Type {wwwww} (five w's) and note
+that the cursor is now on the colon in the sentence. The lower-case w command
+moves you forward one word, paying attention to certain characters such as
+colon and period as delimiters and counting them as words themselves. Now
+type {0} (zero, not o 'oh'): this moves you to the beginning of the current
+line. Now type {5w} and notice that this has the effect of repeating {w} five
+times and that you are now back on the colon. Type {0} (zero) again. To
+ignore the delimiters and to move to the beginning of the next word using only
+blanks, tabs and carriage-returns (these are called white-space characters) to
+delimit the words, use the {W} command: upper-case W. {B} takes you back a
+word using white-space characters as word delimiters.
+
+Note that the commands {wbWB} do not stop at the beginning or end of a line:
+they will continue to the next word on the next line in the direction specified
+(a blank line counts as a word).
+
+If you are interested in the END of the word, and not the BEGINNING, then use
+the {e} and {E} commands. These commands only move forward and there are no
+corresponding 'reverse search' commands for the end of a word.
+
+Also, we have been using the {'} command to move the cursor to a position that
+we have previously marked with the {m} command. However, position the cursor
+in the middle of a line (any line, just pick one) and type {mk}, marking that
+position with the letter k. Now type a few returns {^M} and type {'k}.
+Observe that the cursor is now at the beginning of the line that you marked.
+Now try {`k}: note that this is the reverse apostrophe, or back-quote, or grave
+accent, or whatever you want to call it. Also note that it moves you to the
+character that was marked, not just to the line that was marked.
+
+In addition, the {``} command works just like the {''} command except that you
+are taken to the exact character, not just to the line. (I'm still not
+sure which exact character, just as I'm still not sure which line.)
+
+Section 21: {l} {k} {j} {h}
+
+There are several commands to move around on the screen on a character by
+character basis:
+
+l - moves the cursor one character to the RIGHT
+k - moves the cursor UP one line
+j - moves the cursor DOWN one line
+h - moves the cursor one character to the LEFT
+
+Section 22: {i} {a} {I} {A} {o} {O} ^[ (escape key)
+
+For this and following sections you will need to use the ESCAPE key on your
+terminal. It is usually marked ESC. Since the escape key is the same as
+typing {^[} we will use ^[ for the escape key.
+
+Probably the most often used command in an editor is the insert command. Below
+are two lines of text, the first correct, the second incorrect. Position your
+cursor at the beginning of Line 1 and type {z^M}.
+
+Line 1: This is an example of the insert command.
+Line 2: This is an of the insert command.
+
+To make line 2 look like line 1, we are going to insert the characters
+'example ' before the word 'of'. So, now move the cursor so that it is
+positioned on the 'o' of 'of'. (You can do this by typing {^M} to move
+to the beginning of line 2, followed by {6w} or {wwwwww} to position the cursor
+on the word 'of'.)
+
+Now carefully type the following string and observe the effects:
+ {iexample ^[} (remember: ^[ is the escape key)}
+The {i} begins the insert mode, and 'example ' is inserted into the line:
+be sure to notice the blank in 'example '. The ^[ ends insertion mode,
+and the line is updated to include the new string. Line 1 should look exactly
+like Line 2.
+
+Move the cursor to the beginning of Line 3 below and type {z^M}:
+
+Line 3: These lines are examples for the 'a' command.
+Line 4: These line are examples for the '
+
+We will change line four to look like line three by using the append command.
+We need to append an 's' to the word 'line'. Position the cursor on the 'e'
+of 'line'. You can do this in several ways, one way is the following:
+First, type {/line /^M}. This puts us on the word 'line' in Line 4
+(the blank in the search string is important!). Next, type {e}. The 'e' puts
+us at the end of the word. Now, type {as^[ (^[ is the escape character)}.
+The 'a' puts us in insert mode, AFTER the current character. We appended the
+'s', and the escape ^[ ended the insert mode.
+
+The difference between {i} (insert) and {a} (append) is that {i} begins
+inserting text BEFORE the cursor, and {a} begins inserting AFTER the cursor.
+
+Now type {Aa' command.^[}. The cursor is moved to the end of the line and the
+string following {A} is inserted into the text. Line 4 should now look like
+line 3.
+
+Just as {A} moves you to the end of the line to begin inserting, {I} would
+begin inserting at the FRONT of the line.
+
+To begin the insertion of a line after the cursor line, type {o}. To insert a
+line before the cursor line, type {O}. In other words {o123^[} is equivalent
+to {A^M123^[}, and {O123^[} is equivalent to {I123^M^[}. The text after the
+{o} or {O} is ended with an escape ^[.
+
+This paragraph contains information that is terminal dependent: you will just
+have to experiment to discover what your terminal does. Once in the insert
+mode, if you make a mistake in the typing, ^H will delete the previous
+character up to the beginning of the current insertion. ^W will delete the
+previous word, and one of ^U, @, or ^X will delete the current line (up to the
+beginning of the current insertion). You will need to experiment with ^U, @,
+and ^X to determine which works for your terminal.
+
+Section 23: {f} {x} {X} {w} {l} {r} {R} {s} {S} {J}
+
+Position the cursor at the beginning of line 5 and {z^M}:
+
+Line 5: The line as it should be.
+Line 6: The line as it shouldn't be.
+
+To make Line 6 like Line 5, we have to delete the 'n', the apostrophe, and the
+'t'. There are several ways to position ourselves at the 'n'. Choose
+whichever one suits your fancy:
+
+{/n't/^M}
+{^M7w6l} or {^M7w6 } (note the space)
+{^M3fn} (finds the 3rd 'n' on the line)
+
+Now {xxx} will delete the three characters, as will {3x}.
+
+Note that {X} deletes the character just BEFORE the cursor, as opposed
+to the character AT the cursor.
+
+Position the cursor at line 7 and {z^M}:
+
+Line 7: The line as it would be.
+Line 8: The line as it could be.
+
+To change line 8 into line 7 we need to change the 'c' in 'could' into a 'w'.
+The 'r' (replace) command was designed for this. Typing {rc} is the same as
+typing {xic^[} (i.e. delete the 'bad' character and insert the correct
+new character). Therefore, assuming that you have positioned the cursor on the
+'c' of 'could', the easiest way to change 'could' into 'would' is {rw}.
+
+If you would like to now change the 'would' into 'should', use the substitute
+command, 's': {ssh^[}. The difference between 'r' and 's' is that 'r'
+(replace) replaces the current character with another character, while 's'
+(substitute) substitutes the current character with a string, ended with an
+escape.
+
+The capital letter version of replace {R} replaces each character by a
+character one at a time until you type an escape, ^[. The 'S' command
+substitutes the whole line.
+
+Position your cursor at the beginning of line 9 and {z^M}.
+
+Line 9: Love is a many splendored thing.
+Line 10: Love is a most splendored thing.
+
+To change line 10 into line 9, position the cursor at the beginning of 'most',
+and type {Rmany^[}.
+
+You may have noticed that, when inserting text, a new line is formed by typing
+{^M}. When changing, replacing, or substituting text you can make a new line
+by typing {^M}. However, neither {x} nor {X} will remove ^M to make two lines
+into one line. To do this, position the cursor on the first of the two lines
+you wish to make into a single line and type {J} (uppercase J for 'Join').
+
+Section 24: {u} {U}
+
+Finally, before we review, let's look at the undo command. Position
+your cursor on line 11 below and {z^M}.
+
+Line 11: The quick brown fox jumped over the lazy hound dog.
+Line 12: the qwick black dog dumped over the laxy poune fox.
+
+Type the following set of commands, and observe carefully the effect of each
+of the commands:
+
+{/^Line 12:/^M} {ft} {rT} {fw} {ru} {w} {Rbrown fox^[} {w} {rj}
+{fx} {rz} {w} {Rhound dog^[}
+
+Line 12 now matches line 11. Now type {U} - capital 'U'. And line 12 now
+looks like it did before you typed in the command strings. Now type:
+
+{ft} {rT} {fw} {ru} {^M} {^M}
+
+and then type {u}: the cursor jumps back to the line containing the second
+change you made and 'undoes' it. That is, {U} 'undoes' all the changes on the
+line, and {u} 'undoes' only the last change. Type {u} several times and
+observe what happens: {u} can undo a previous {u}!
+
+Caveat: {U} only works as long as the cursor is still on the line. Move the
+cursor off the line and {U} will have no effect, except to possibly beep at
+you. However, {u} will undo the last change, no matter where it occurred.
+
+Section 25: review
+
+At this point, you have all the commands you need in order to make use of vi.
+The remainder of this tutorial will discuss variations on these commands as
+well as introduce new commands that make the job of editing more efficient.
+Here is a brief review of the basic commands we have covered. They are listed
+in the order of increasing complexity and/or decreasing necessity (to say that
+a command is less necessary is not to say that it is less useful!). These
+commands allow you to comfortably edit any text file. There are other
+commands that will make life easier but will require extra time to learn,
+obviously. You may want to consider setting this tutorial aside for several
+weeks and returning to it later after gaining experience with vi and getting
+comfortable with it. The convenience of some of the more exotic commands may
+then be apparent and worth the extra investment of time and effort
+required to master them.
+
+to get into the editor from Unix: {vi filename}
+to exit the editor
+ saving all changes {ZZ} or {:wq^M}
+ throwing away all changes {:q!^M}
+ when no changes have been made {:q^M}
+save a file without exiting the editor {:w^M}
+write the file into another file {:w filename^M}
+insert text
+ before the cursor {i ...text... ^[}
+ at the beginning of the line {I ...text... ^[}
+ after the cursor (append) {a ...text... ^[}
+ at the end of the line {A ...text... ^[}
+ after the current line {o ...text... ^[}
+ before the current line {O ...text... ^[}
+delete the character ...
+ under the cursor {x}
+ to the left of the cursor {X}
+delete n characters {nx} or {nX} (for n a number)
+make two lines into one line (Join) {J}
+find a string in the file ...
+ searching forward {/ ...string... /^M}
+ searching backwards {? ...string... ?^M}
+repeat the last search command {n}
+repeat the last search command in the
+ opposite direction {N}
+find the character c on this line ...
+ searching forward {fc}
+ searching backward {Fc}
+repeat the last 'find character' command {;}
+replace a character with character x {rx}
+substitute a single character with text {s ...text... ^[}
+substitute n characters with text {ns ...text... ^[}
+replace characters one-by-one with text {R ...text... ^[}
+undo all changes to the current line {U}
+undo the last single change {u}
+move forward in the file a "screenful" {^F}
+move back in the file a "screenful" {^B}
+move forward in the file one line {^M} or {+}
+move backward in the file one line {-}
+move to the beginning of the line {0}
+move to the end of the line {$}
+move forward one word {w}
+move forward one word, ignoring punctuation {W}
+move forward to the end of the next word {e}
+to the end of the word, ignoring punctuation{E}
+move backward one word {b}
+move back one word, ignoring punctuation {B}
+return to the last line modified {''}
+scroll a line onto the top of the screen {^Y}
+scroll a line onto the bottom of the screen {^E}
+move "up" in the file a half-screen {^U}
+move "down" in the file a half-screen {^D}
+move the cursor to the top screen line {H}
+move the cursor to the bottom screen line {L}
+move the cursor to the middle line {M}
+move LEFT one character position {h} or {^H}
+move RIGHT one character position {l} or { }
+move UP in the same column {k} or {^P}
+move DOWN in the same column {j} or {^N}
+mark the current position, name it x {mx}
+move to the line marked/named x {'x}
+move to the character position named x {`x}
+move to the beginning of the file {1G}
+move to the end of the file {G}
+move to line 23 in the file {23G}
+repaint the screen with the cursor line
+ at the top of the screen {z^M}
+ in the middle of the screen {z.}
+ at the bottom of the screen {z-}
+
+More information on vi can be found in the file vi.advanced, which you can
+peruse at your leisure. From UNIX, type {vi.tut advanced^M}.
diff --git a/usr.bin/vi/docs/tutorial/vi.tut.csh b/usr.bin/vi/docs/tutorial/vi.tut.csh
new file mode 100644
index 000000000000..01554bc4e5fd
--- /dev/null
+++ b/usr.bin/vi/docs/tutorial/vi.tut.csh
@@ -0,0 +1,24 @@
+#!/bin/csh -f
+#
+# This makes the user's EXINIT variable set to the 'correct' things.
+# I don't know what will happen if they also have a .exrc file!
+#
+# XXX
+# Make sure that user is using a 24 line window!!!
+#
+if ($1 != "beginner" && $1 != "advanced") then
+ echo Usage: $0 beginner or $0 advanced
+ exit
+endif
+
+if ($?EXINIT) then
+ set oexinit="$EXINIT"
+ setenv EXINIT 'se ts=4 wm=8 sw=4'
+endif
+
+vi vi.{$1}
+
+onintr:
+ if ($?oexinit) then
+ setenv EXINIT "$oexinit"
+endif
diff --git a/usr.bin/vi/vi.1 b/usr.bin/vi/docs/vi.1
index 7c39b10c5ae2..d13042c7f17e 100644
--- a/usr.bin/vi/vi.1
+++ b/usr.bin/vi/docs/vi.1
@@ -397,6 +397,7 @@ local directory startup file.
.El
.Sh SEE ALSO
.Xr ctags 1 ,
+.Xr vi-ref 1 ,
.Xr more 1 ,
.Xr curses 3 ,
.Xr dbopen 3
diff --git a/usr.bin/vi/docs/vi.ref b/usr.bin/vi/docs/vi.ref
new file mode 100644
index 000000000000..d2d79bd204ed
--- /dev/null
+++ b/usr.bin/vi/docs/vi.ref
@@ -0,0 +1,523 @@
+.\" Copyright (c) 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)vi.ref 8.19 (Berkeley) 3/18/94
+.\"
+.Dd "March 18, 1994"
+.Dt "EX/VI REFERENCE MANUAL" 1
+.Os
+.Sh NAME
+.Nm ex, vi, view
+.Nd text editors
+.Sh DESCRIPTION
+.Nm \&Vi
+is a screen oriented text editor.
+.Nm \&Ex
+is a line-oriented text editor.
+.Nm \&Ex
+and
+.Nm \&vi
+are different interfaces to the same program,
+and it is possible to switch back and forth during an edit session.
+.Nm View
+is the equivalent of using the
+.Fl R
+(read-only) option of
+.Nm \&vi .
+.Pp
+This reference manual is the one provided with the
+.Nm ex/vi
+versions of the
+.Nm ex/vi
+text editors.
+.Nm Ex/vi
+are intended as bug-for-bug compatible replacements for the original
+Fourth Berkeley Software Distribution (4BSD)
+.Nm \&ex
+and
+.Nm \&vi
+programs.
+This reference manual is accompanied by a traditional-style manual page.
+That manual page describes the functionality found in
+.Nm ex/vi
+in far less detail than the description here.
+In addition, it describes the system interface to
+.Nm ex/vi ,
+e.g. command line options, environmental variables, and similar things.
+.Pp
+This reference is intended for users already familiar with
+.Nm ex/vi .
+Anyone else should almost certainly read a good tutorial on the
+editor first.
+If you're in an unfamiliar environment, and you absolutely have to
+get work done immediately, see the section entitled FAST STARTUP
+in the manual page.
+It's probably enough to get you going.
+.Pp
+For the rest of this reference,
+.Nm ex/vi
+is used only when it's necessary to distinguish it from the historic
+implementations of
+.Nm ex/vi .
+.Sh ADDITIONAL FEATURES
+There are a few features in
+.Nm ex/vi
+that are not found in historic versions of
+.Nm ex/vi .
+A list of those features is as follows:
+.Bl -tag -width indent
+.It "8-bit clean data, large lines, files"
+.Nm \&Vi/ex
+will edit any format file.
+Line lengths are limited by available memory,
+and file sizes are limited by available disk space.
+The command
+.Dq "^Vx[0-9A-Fa-f]* ,"
+in input mode, will insert any
+legal character value into the text.
+.It "Split screens"
+The command
+.Dq ":sp[lit] [file ...]"
+splits the screen in vi mode.
+The key
+.Dq "^W"
+switches between the foreground screens,
+and the
+.Dq ":resize count"
+command can be used to grow or shrink a particular screen.
+.It "Background and foreground screens"
+The command
+.Dq ":bg"
+backgrounds the current screen,
+and the command
+.Dq ":fg [file]"
+foregrounds the backgrounded screen
+that is editing the specified file, or, by default, the first background
+screen on the queue.
+The command
+.Dq ":di[splay] s[creens]"
+lists the background screens.
+.It "Shell screens"
+The command
+.Dq ":sc[ript] [file ...]"
+runs a shell in the screen.
+Editing is unchanged, with the exception that a <carriage-return>
+enters the current line (stripped of any prompt) as input to the
+shell.
+.It "Tag stacks"
+Tags are now maintained in a stack.
+The command
+.Dq "^T"
+returns to the previous tag location.
+The command
+.Dq ":tagpop [number \| file]"
+returns to the most recent tag
+location by default, or, optionally to a specific tag number in the
+tag stack, or the most recent tag from the specified file.
+Use the command
+.Dq ":di[splay] t[ags]"
+to view the tags stack.
+The command
+.Dq ":tagtop"
+returns to the top of the tag stack.
+.It "New displays"
+The command
+.Dq ":di[splay] b[uffers] \| s[creens] \| t[ags]"
+can be
+used to display, respectively, the current cut buffers,
+the backgrounded screens, and the tags stack.
+.It "Infinite undo"
+The changes made during an edit session may be rolled backward and
+forward.
+A '.' command immediately after a 'u' command continues either forward
+or backward depending on whether the 'u' command was an undo or a redo.
+.It "Usage information"
+The command
+.Dq ":exu[sage] [cmd]"
+and
+.Dq "viu[sage] [key]"
+provide usage
+information for all of the ex and vi commands by default, or, optionally,
+for a specific command or key.
+.It "Extended regular expressions"
+The
+.Dq ":set extended"
+command treats search and other command regular
+expressions as extended (egrep(1) style) regular expressions.
+.It "Word search"
+The command
+.Dq "^A"
+searches for the word referenced by the cursor.
+.It "Number increment"
+The command
+.Dq "#"
+increments the number referenced by the cursor.
+.It "Previous file"
+The command
+.Dq ":prev[ious][!]"
+edits the previous file from the
+argument list.
+.It "Left-Right scrolling"
+The command
+.Dq ":set leftright"
+makes
+.Nm vi
+do left-right screen scrolling, instead of the traditional
+.Nm \&vi
+line wrapping.
+.Sh RECOVERY
+There is no recovery program for
+.Nm vi ,
+nor does
+.Nm vi
+run setuid.
+Users may recover any file which they may read, and the superuser
+may recover any edit session.
+.Pp
+Edit sessions are backed by files in
+.Pa /var/tmp/vi.recover ,
+and are named
+.Dq "vi.XXXX" ,
+where
+.Dq "XXXX"
+is a number related to the process id.
+When a file is first modified, a second file, which contains an
+email message for the user, is created, and is named
+.Dq "recover.XXXX" ,
+where, again,
+.Dq "XXXX"
+is associated with the process id.
+Both files are removed at the end of a normal edit session,
+but will remain if the edit session is abnormally terminated
+or the user enters the ex/vi
+.Dq "preserve"
+command.
+The use of the
+.Pa /var/tmp
+directory may be changed setting the
+.Sy recdir
+option in the user's or system startup information.
+.Pp
+The recovery directory should have the
+.Dq "sticky-bit"
+set so that only the owners of files may remove them.
+If this is not possible on the system, then a pseudo-user should
+own the recovery directory.
+The recovery directory must be both read and write-able by
+any user.
+.Pp
+The recovery file has all of the necessary information in it to enable the
+user to recover the edit session.
+In addition, it has all of the necessary email headers for sendmail.
+When the system is rebooted, all of the files in
+.Pa /var/tmp/vi.recover
+named
+.Dq "recover.XXXX"
+should be sent by email,
+using the
+.Fl t
+flag of sendmail (or a similar mechanism in other mailers).
+A simple way to do this is to insert the following script into your
+.Pa /etc/rc.local
+(or other startup) file:
+.ne 7v
+.Bd -literal -offset indent -compact
+# Recover vi editor files.
+virecovery=`echo /var/tmp/vi.recover/recover.*`
+if [ "$virecovery" != "/var/tmp/vi.recover/recover.*" ]; then
+ echo 'Recovering vi editor sessions'
+ for i in $virecovery; do
+ sendmail -t < $i
+ done
+fi
+.Ed
+.Pp
+If
+.Nm ex/vi
+receives a hangup (SIGHUP) signal, it will email the recovery
+information to the user itself.
+.Pp
+If you don't have the sendmail program on your system, the source file
+.Pa vi/recover.c
+will have to be modified to use your local mail delivery programs.
+.Sh STARTUP INFORMATION
+.Nm Ex/vi
+interprets one of two possible environmental variables and reads up
+to three of five possible files during startup.
+The variables and files are expected to contain
+.Nm \&ex
+commands, not
+.Nm \&vi
+commands.
+In addition, they are interpreted
+.Em before
+the file to be edited is read, and therefore many
+.Nm \&ex
+commands may not be used.
+Generally, any command that requires output to the screen or that
+needs a file upon which to operate, will cause an error if included
+in a startup file or environmental variable.
+.Pp
+First, the file
+.Pa /etc/vi.exrc
+is read.
+Second, the environmental variable
+.Ev EXINIT
+is interpreted.
+Third, if
+.Ev EXINIT
+was not set, the file
+.Pa $HOME/.exrc
+is read.
+Fourth, the file
+.Pa .exrc
+is read.
+.Pp
+Startup files will not be read if they are owned by anyone other
+than the real user-id of the user running
+.Nm \&vi ,
+(or by
+.Dq root
+in the case of the file
+.Pa /etc/vi.exrc )
+or if they are writable by anyone other than the owner.
+Home directory startup file (i.e.
+.Pa $HOME/.exrc )
+will not be read if the
+.Dq HOME
+environmental variable is not set.
+The local startup file (i.e.
+.Pa .exrc )
+will not be read if the
+.Sy exrc
+option is turned off in the
+.Pa /etc/vi.exrc
+or
+.Pa $HOME/.exrc
+files, or in the
+.Ev EXINIT
+environmental variable.
+It is not an error for any of the startup environmental variables
+or files not to exist.
+.Pp
+Because the
+.Nm \&ex
+command set supported by
+.Nm ex/vi
+is a superset of the command set supported by most historical implementations
+of
+.Nm \&ex ,
+.Nm ex/vi
+can use the startup files created for the historical implementations,
+but the converse is often not true.
+.Sh SIZING THE SCREEN
+The size of the screen can be set in a number of ways.
+.Nm Ex/vi
+takes the following steps until values are obtained for both the
+number of rows and number of columns in the screen.
+.sp
+.Bl -enum -compact
+.It
+If the environmental variable
+.Ev LINES
+exists, it is used to specify the number of rows in the screen.
+.It
+If the environmental variable
+.Ev COLUMNS
+exists, it is used to specify the number of columns in the screen.
+.It
+The TIOCGWINSZ
+.Xr ioctl 2
+is attempted on the standard error file descriptor.
+.It
+The termcap entry is checked for the
+.Dq \&li
+entry (rows) and the
+.Dq \&co
+entry (columns).
+.It
+The number of rows is set to 24, and the number of columns is set
+to 80.
+.El
+.Pp
+If a window change size signal (SIGWINCH) is received,
+the same steps are taken with the exception that the first two steps
+are skipped.
+.Sh REGULAR EXPRESSIONS AND REPLACEMENT STRINGS
+Regular expressions are used in line addresses,
+as the first part of
+.Sy substitute ,
+.Sy global ,
+and
+.Sy vglobal
+commands,
+and in search patterns.
+.Pp
+The regular expressions supported by
+.Nm \&ex
+and
+.Nm \&vi
+are, by default, the Basic Regular Expressions (BRE's) described in the
+IEEE POSIX Standard 1003.2.
+The
+.Sy extended
+option causes all regular expressions to be interpreted as the Extended
+Regular Expressions (ERE's) described by the same standard.
+(See
+.Xr re_format 7
+for more information.
+Generally speaking, BRE's are
+.Xr ed 1
+and
+.Xr grep 1
+style regular expressions, and ERE's are
+.Xr egrep 1
+style regular expressions.)
+.Pp
+There are some special strings and characters that can be used in
+RE's:
+.Bl -enum -compact
+.It
+An empty RE (e.g.
+.Dq \&// )
+is equivalent to the last RE used.
+.It
+The construct
+.Dq \e<
+matches the beginning of a word.
+.It
+The construct
+.Dq \e>
+matches the end of a word.
+.It
+The character
+.Dq \&~
+matches the replacement part of the last
+.Sy substitute
+command.
+.El
+.Pp
+When the
+.Sy magic
+option is
+.Em not
+set,
+the only characters with special meanings are
+.Dq \&^
+at the beginning of an RE,
+.Dq \&$
+at the end of an RE, and the escaping character
+.Dq \&\e .
+The characters
+.Dq \&. ,
+.Dq \&* ,
+.Dq \&[ ,
+and
+.Dq \&~
+are treated as ordinary characters unless preceded by a
+.Dq \&\e ;
+when preceded by a
+.Dq \&\e
+they regain their special meaning.
+.Pp
+Replacement strings are the second part of a
+.Sy substitute
+command.
+.Pp
+The character
+.Dq \&&
+(or
+.Dq \e&
+if the
+.Sy magic
+option is
+.Em not
+set) in the replacement string stands for the text matched by the RE
+that's being replaced.
+The character
+.Dq \&~
+(or
+.Dq \e~
+if the
+.Sy magic
+option is
+.Em not
+set) stands for the replacement part of the previous
+.Sy substitute
+command.
+.Pp
+The string
+.Dq \e# ,
+where
+.Dq \&#
+is an integer value from 1 to 9, stands for the text matched by
+the portion of the RE enclosed in the #'th set of escaped parentheses,
+e.g.
+.Dq \e(
+and
+.Dq \e) .
+For example,
+.Dq "s/abc\e(.*\e)def/\e1/"
+deletes the strings
+.Dq abc
+and
+.Dq def
+from the matched pattern.
+.Pp
+The strings
+.Dq \el ,
+.Dq \eu ,
+.Dq \eL ,
+and
+.Dq \eU
+can be used to modify the case of elements in the replacement string.
+The string
+.Dq \el
+causes the next character to be converted to lowercase; the string
+.Dq \eu
+behaves similarly, but converts to uppercase.
+The strings
+.Dq \eL
+causes characters up to the end of the string or the next occurrence of
+the strings
+.Dq \ee
+or
+.Dq \eE
+to be converted to lowercase; the string
+.Dq \eU
+behaves similarly, but converts to uppercase.
+.Pp
+In
+.Nm \&vi ,
+inserting a <control-M> into the replacement string will cause the
+matched line to be split into two lines at that point.
+.Sh SET OPTIONS
+#include <set.opt.roff>
diff --git a/usr.bin/vi/docs/vi.ref.txt b/usr.bin/vi/docs/vi.ref.txt
new file mode 100644
index 000000000000..e5fc627072db
--- /dev/null
+++ b/usr.bin/vi/docs/vi.ref.txt
@@ -0,0 +1,634 @@
+EX/VI REFERENCE MANUAL(1) BSD Reference Manual EX/VI REFERENCE MANUAL(1)
+
+NNAAMMEE
+ eexx,, vvii,, vviieeww - text editors
+
+DDEESSCCRRIIPPTTIIOONN
+ VVii is a screen oriented text editor. EExx is a line-oriented text editor.
+ EExx and vvii are different interfaces to the same program, and it is possi-
+ ble to switch back and forth during an edit session. VViieeww is the equiva-
+ lent of using the --RR (read-only) option of vvii.
+
+ This reference manual is the one provided with the nneexx//nnvvii versions of
+ the eexx//vvii text editors. NNeexx//nnvvii are intended as bug-for-bug compatible
+ replacements for the original Fourth Berkeley Software Distribution
+ (4BSD) eexx and vvii programs. This reference manual is accompanied by a
+ traditional-style manual page. That manual page describes the function-
+ ality found in eexx//vvii in far less detail than the description here. In
+ addition, it describes the system interface to eexx//vvii, e.g. command line
+ options, environmental variables, and similar things.
+
+ This reference is intended for users already familiar with eexx//vvii. Anyone
+ else should almost certainly read a good tutorial on the editor first.
+ If you're in an unfamiliar environment, and you absolutely have to get
+ work done immediately, see the section entitled FAST STARTUP in the manu-
+ al page. It's probably enough to get you going.
+
+ For the rest of this reference, nneexx//nnvvii is used only when it's necessary
+ to distinguish it from the historic implementations of eexx//vvii.
+
+AADDDDIITTIIOONNAALL FFEEAATTUURREESS
+ There are a few features in nneexx//nnvvii that are not found in historic ver-
+ sions of eexx//vvii. A list of those features is as follows:
+
+ 8-bit clean data, large lines, files
+ NNvvii//nneexx will edit any format file. Line lengths are limited by
+ available memory, and file sizes are limited by available disk
+ space. The command ``^Vx[0-9A-Fa-f]*'', in input mode, will in-
+ sert any legal character value into the text.
+
+ Split screens
+ The command ``:sp[lit] [file ...]'' splits the screen in vi mode.
+ The key ``^W'' switches between the foreground screens, and the
+ ``:resize count'' command can be used to grow or shrink a partic-
+ ular screen.
+
+ Background and foreground screens
+ The command ``:bg'' backgrounds the current screen, and the com-
+ mand ``:fg [file]'' foregrounds the backgrounded screen that is
+ editing the specified file, or, by default, the first background
+ screen on the queue. The command ``:di[splay] s[creens]'' lists
+ the background screens.
+
+ Shell screens
+ The command ``:sc[ript] [file ...]'' runs a shell in the screen.
+ Editing is unchanged, with the exception that a <carriage-return>
+ enters the current line (stripped of any prompt) as input to the
+ shell.
+
+ Tag stacks
+ Tags are now maintained in a stack. The command ``^T'' returns
+ to the previous tag location. The command ``:tagpop [number
+ file]'' returns to the most recent tag location by default, or,
+ optionally to a specific tag number in the tag stack, or the most
+ recent tag from the specified file. Use the command ``:di[splay]
+ t[ags]'' to view the tags stack. The command ``:tagtop'' returns
+
+ to the top of the tag stack.
+
+ New displays
+ The command ``:di[splay] b[uffers] s[creens] t[ags]'' can be
+ used to display, respectively, the current cut buffers, the back-
+ grounded screens, and the tags stack.
+
+ Infinite undo
+ The changes made during an edit session may be rolled backward
+ and forward. A '.' command immediately after a 'u' command con-
+ tinues either forward or backward depending on whether the 'u'
+ command was an undo or a redo.
+
+ Usage information
+ The command ``:exu[sage] [cmd]'' and ``viu[sage] [key]'' provide
+ usage information for all of the ex and vi commands by default,
+ or, optionally, for a specific command or key.
+
+ Extended regular expressions
+ The ``:set extended'' command treats search and other command
+ regular expressions as extended (egrep(1) style) regular expres-
+ sions.
+
+ Word search
+ The command ``^A'' searches for the word referenced by the cur-
+ sor.
+
+ Number increment
+ The command ``#'' increments the number referenced by the cursor.
+
+ Previous file
+ The command ``:prev[ious][!]'' edits the previous file from the
+ argument list.
+
+ Left-Right scrolling
+ The command ``:set leftright'' makes nnvvii do left-right screen
+ scrolling, instead of the traditional vvii line wrapping.
+
+RREECCOOVVEERRYY
+ There is no recovery program for nnvvii, nor does nnvvii run setuid. Users may
+ recover any file which they may read, and the superuser may recover any
+ edit session.
+
+ Edit sessions are backed by files in _/_v_a_r_/_t_m_p_/_v_i_._r_e_c_o_v_e_r, and are named
+ ``vi.XXXX'', where ``XXXX'' is a number related to the process id. When
+ a file is first modified, a second file, which contains an email message
+ for the user, is created, and is named ``recover.XXXX'', where, again,
+ ``XXXX'' is associated with the process id. Both files are removed at
+ the end of a normal edit session, but will remain if the edit session is
+ abnormally terminated or the user enters the ex/vi ``preserve'' command.
+ The use of the _/_v_a_r_/_t_m_p directory may be changed setting the rreeccddiirr op-
+ tion in the user's or system startup information.
+
+ The recovery directory should have the ``sticky-bit'' set so that only
+ the owners of files may remove them. If this is not possible on the sys-
+ tem, then a pseudo-user should own the recovery directory. The recovery
+ directory must be both read and write-able by any user.
+
+ The recovery file has all of the necessary information in it to enable
+ the user to recover the edit session. In addition, it has all of the
+ necessary email headers for sendmail. When the system is rebooted, all
+ of the files in _/_v_a_r_/_t_m_p_/_v_i_._r_e_c_o_v_e_r named ``recover.XXXX'' should be sent
+ by email, using the --tt flag of sendmail (or a similar mechanism in other
+ mailers). A simple way to do this is to insert the following script into
+
+ your _/_e_t_c_/_r_c_._l_o_c_a_l (or other startup) file:
+ virecovery=`echo /var/tmp/vi.recover/recover.*`
+ if [ "$virecovery" != "/var/tmp/vi.recover/recover.*" ]; then
+ echo 'Recovering vi editor sessions'
+ for i in $virecovery; do
+ sendmail -t < $i
+ done
+ fi
+
+ If eexx//vvii receives a hangup (SIGHUP) signal, it will email the recovery
+ information to the user itself.
+
+ If you don't have the sendmail program on your system, the source file
+ _n_v_i_/_r_e_c_o_v_e_r_._c will have to be modified to use your local mail delivery
+ programs.
+
+SSTTAARRTTUUPP IINNFFOORRMMAATTIIOONN
+ EExx//vvii interprets one of two possible environmental variables and reads up
+ to three of five possible files during startup. The variables and files
+ are expected to contain eexx commands, not vvii commands. In addition, they
+ are interpreted _b_e_f_o_r_e the file to be edited is read, and therefore many
+ eexx commands may not be used. Generally, any command that requires output
+ to the screen or that needs a file upon which to operate, will cause an
+ error if included in a startup file or environmental variable.
+
+ First, the file _/_e_t_c_/_v_i_._e_x_r_c is read. Second, the environmental variable
+ NEXINIT (or the variable EXINIT, if NEXINIT isn't set) is interpreted.
+ Third, if neither NEXINIT or EXINIT was set, the file _$_H_O_M_E_/_._n_e_x_r_c (or
+ the file _$_H_O_M_E_/_._e_x_r_c, if _$_H_O_M_E_/_._n_e_x_r_c doesn't exist) is read. Fourth,
+ the file _._n_e_x_r_c (or the file _._e_x_r_c, if _._n_e_x_r_c doesn't exist) is read.
+
+ Startup files will not be read if they are owned by anyone other than the
+ real user-id of the user running vvii, (or by ``root'' in the case of the
+ file _/_e_t_c_/_v_i_._e_x_r_c) or if they are writable by anyone other than the own-
+ er. Home directory startup files (i.e. _$_H_O_M_E_/_._n_e_x_r_c and _$_H_O_M_E_/_._e_x_r_c)
+ will not be read if the ``HOME'' environmental variable is not set. Lo-
+ cal startup files (i.e. _._n_e_x_r_c and _._e_x_r_c) will not be read if the eexxrrcc
+ option is turned off in the _/_e_t_c_/_v_i_._e_x_r_c, _$_H_O_M_E_/_._n_e_x_r_c, or _$_H_O_M_E_/_._e_x_r_c
+ files, or in the NEXINIT or EXINIT environmental variables. It is not an
+ error for any of the startup environmental variables or files not to ex-
+ ist.
+
+ Because the eexx command set supported by nneexx//nnvvii is a superset of the com-
+ mand set supported by most historical implementations of eexx, nneexx//nnvvii can
+ use the startup files created for the historical implementations, but the
+ converse is often not true.
+
+SSIIZZIINNGG TTHHEE SSCCRREEEENN
+ The size of the screen can be set in a number of ways. EExx//vvii takes the
+ following steps until values are obtained for both the number of rows and
+ number of columns in the screen.
+
+ 1. If the environmental variable LINES exists, it is used to specify
+ the number of rows in the screen.
+ 2. If the environmental variable COLUMNS exists, it is used to specify
+ the number of columns in the screen.
+ 3. The TIOCGWINSZ ioctl(2) is attempted on the standard error file de-
+ scriptor.
+ 4. The termcap entry is checked for the ``li'' entry (rows) and the
+ ``co'' entry (columns).
+ 5. The number of rows is set to 24, and the number of columns is set to
+ 80.
+
+ If a window change size signal (SIGWINCH) is received, the same steps are
+ taken with the exception that the first two steps are skipped.
+
+RREEGGUULLAARR EEXXPPRREESSSSIIOONNSS AANNDD RREEPPLLAACCEEMMEENNTT SSTTRRIINNGGSS
+ Regular expressions are used in line addresses, as the first part of
+ ssuubbssttiittuuttee, gglloobbaall, and vvgglloobbaall commands, and in search patterns.
+
+ The regular expressions supported by eexx and vvii are, by default, the Basic
+ Regular Expressions (BRE's) described in the IEEE POSIX Standard 1003.2.
+ The eexxtteennddeedd option causes all regular expressions to be interpreted as
+ the Extended Regular Expressions (ERE's) described by the same standard.
+ (See re_format(7) for more information. Generally speaking, BRE's are
+ ed(1) and grep(1) style regular expressions, and ERE's are egrep(1) style
+ regular expressions.)
+
+ There are some special strings and characters that can be used in RE's:
+ 1. An empty RE (e.g. ``//'') is equivalent to the last RE used.
+ 2. The construct ``\<'' matches the beginning of a word.
+ 3. The construct ``\>'' matches the end of a word.
+ 4. The character ``~'' matches the replacement part of the last
+ ssuubbssttiittuuttee command.
+
+ When the mmaaggiicc option is _n_o_t set, the only characters with special mean-
+ ings are ``^'' at the beginning of an RE, ``$'' at the end of an RE, and
+ the escaping character ``\''. The characters ``.'', ``*'', ``['', and
+ ``~'' are treated as ordinary characters unless preceded by a ``\''; when
+ preceded by a ``\'' they regain their special meaning.
+
+ Replacement strings are the second part of a ssuubbssttiittuuttee command.
+
+ The character ``&'' (or ``\&'' if the mmaaggiicc option is _n_o_t set) in the re-
+ placement string stands for the text matched by the RE that's being re-
+ placed. The character ``~'' (or ``\~'' if the mmaaggiicc option is _n_o_t set)
+ stands for the replacement part of the previous ssuubbssttiittuuttee command.
+
+ The string ``\#'', where ``#'' is an integer value from 1 to 9, stands
+ for the text matched by the portion of the RE enclosed in the #'th set of
+ escaped parentheses, e.g. ``\('' and ``\)''. For example,
+ ``s/abc\(.*\)def/\1/'' deletes the strings ``abc'' and ``def'' from the
+ matched pattern.
+
+ The strings ``\l'', ``\u'', ``\L'', and ``\U'' can be used to modify the
+ case of elements in the replacement string. The string ``\l'' causes the
+ next character to be converted to lowercase; the string ``\u'' behaves
+ similarly, but converts to uppercase. The strings ``\L'' causes charac-
+ ters up to the end of the string or the next occurrence of the strings
+ ``\e'' or ``\E'' to be converted to lowercase; the string ``\U'' behaves
+ similarly, but converts to uppercase.
+
+ In vvii, inserting a <control-M> into the replacement string will cause the
+ matched line to be split into two lines at that point.
+
+SSEETT OOPPTTIIOONNSS
+ There are a large number of options that may be set (or unset) to change
+ the editor's behavior. This section describes the options, their abbre-
+ viations and their default values.
+
+ In each entry below, the first part of the tag line is the full name of
+ the option, followed by any equivalent abbreviations. (Regardless of the
+ abbreviations, it is only necessary to use the minimum number of charac-
+ ters necessary to distinguish an abbreviation from all other commands for
+ it to be accepted, in nneexx//nnvvii. Historically, only the full name and the
+ official abbreviations were accepted by eexx//vvii. Using full names in your
+ startup files and environmental variables will probably make them more
+ portable.) The part in square brackets is the default value of the op-
+ tion. Most of the options are boolean, i.e. they are either on or off,
+ and do not have an associated value.
+
+
+ Options apply to both eexx and vvii modes, unless otherwise specified.
+
+ For information on modifying the options or to display the options and
+ their current values, see the ``set'' command in the Ex Commands section.
+ altwerase [off]
+ VVii only. Change how vvii does word erase during text input. When
+ this option is set, text is broken up into three classes: alphabet-
+ ic, numeric and underscore characters, other non-blank characters,
+ and blank characters. Changing from one class to another marks the
+ end of a word. In addition, the class of the first character
+ erased is ignored (which is exactly what you want when erasing
+ pathname components).
+ autoindent, ai [off]
+ If this option is set, whenever you create a new line (using the vvii
+ AA, aa, CC, cc, II, ii, OO, oo, RR, rr, SS, and ss commands, or the eexx aappppeenndd,
+ cchhaannggee, and iinnsseerrtt commands) the new line is automatically indented
+ to align the cursor with the first non-blank character of the line
+ from which you created it. Lines are indented using tab characters
+ to the extent possible (based on the value of the ttaabbssttoopp option)
+ and then using space characters as necessary. For commands insert-
+ ing text into the middle of a line, any blank characters to the
+ right of the cursor are discarded, and the first non-blank charac-
+ ter to the right of the cursor is aligned as described above.
+
+ The indent characters are themselves somewhat special. If you do
+ not enter more characters on the new line before moving moving to
+ another line, or entering <escape>, the indent character will be
+ deleted and the line will be empty. For example, if you enter
+ <carriage-return> twice in succession, the line created by the
+ first <carriage-return> will not have any characters in it, regard-
+ less of the indentation of the previous or subsequent line.
+
+ Indent characters also require that you enter additional erase
+ characters to delete them. For example, if you have an indented
+ line, containing only blanks, the first <word-erase> character you
+ enter will erase up to end of the indent characters, and the second
+ will erase back to the beginning of the line. (Historically, only
+ the ^^DD key would erase the indent characters. Both the ^^DD key and
+ the usual erase keys work in nnvvii ..)) In addition, if the cursor is
+ positioned at the end of the indent characters, the keys ``0^D''
+ will erase all of the indent characters for the current line, re-
+ setting the indentation level to 0. Similarly, the keys ``^^D''
+ (i.e. a carat followed by a <control-D>) will erase all of the in-
+ dent characters for the current line, leaving the indentation level
+ for future created lines unaffected.
+
+ Finally, if aauuttooiinnddeenntt is set, the SS and cccc commands change from
+ the first non-blank of the line to the end of the line, instead of
+ from the beginning of the line to the end of the line.
+ autoprint, ap [off]
+ EExx only. EExx only. Cause the current line to be automatically dis-
+ played after the eexx commands <<, >>, ccooppyy, ddeelleettee, jjooiinn, mmoovvee, ppuutt,
+ tt, UUnnddoo, and uunnddoo. This automatic display is suppressed during
+ gglloobbaall and vvgglloobbaall commands, and for any command where optional
+ flags are used to explicitly display the line.
+ autowrite, aw [off]
+ If this option is set, the vvii !! ^^^^ ^^]] and ^^ZZ commands, and the eexx
+ eeddiitt, nneexxtt, rreewwiinndd, ssttoopp, ssuussppeenndd, ttaagg, ttaaggppoopp, and ttaaggttoopp commands
+ automatically write the current file back to the current file name
+ if it has been modified since it was last written. If the write
+ fails, the command fails and goes no further.
+
+ Appending the optional force flag ``!'' to the eexx commands nneexxtt,
+ rreewwiinndd, ssttoopp, ssuussppeenndd, ttaagg, ttaaggppoopp, and ttaaggttoopp stops the automatic
+ write from being attempted.
+
+
+ (Historically, the nneexxtt command ignored the optional force flag.)
+ Note, the eexx commands eeddiitt, qquuiitt, sshheellll, and xxiitt are _n_o_t affected
+ by the aauuttoowwrriittee option.
+ beautify, bf [off]
+ If this option is set, all control characters that are not current-
+ ly being specially interpreted, other than <tab>, <newline>, and
+ <form-feed>, are discarded from commands read in by eexx from command
+ files, and from input text entered to vvii (either into the file or
+ to the colon command line). Text files read by eexx//vvii are _n_o_t af-
+ fected by the bbeeaauuttiiffyy option.
+ cdpath [environment variable CDPATH, or ``.'']
+ This option is used to specify a colon separated list of directo-
+ ries which are used as path prefixes for any relative path names
+ used as arguments for the ccdd command. The value of this option de-
+ faults to the value of the environmental variable CDPATH if it is
+ set, otherwise to the current directory. For compatibility with
+ the POSIX 1003.2 shell, the ccdd command does _n_o_t check the current
+ directory as a path prefix for relative path names unless it is ex-
+ plicitly specified. It may be so specified by entering an empty
+ string or a ``.'' into the CDPATH variable or the option value.
+ columns, co [80]
+ The number of columns in the screen. Setting this option causes
+ eexx//vvii to set (or reset) the environmental variable COLUMNS. See the
+ SCREEN SIZING section for more information.
+ comment [off]
+ VVii only. If the first non-empty line of the file begins with the
+ string ``/*'', this option causes vvii to skip to the end of that C
+ comment (probably a terribly boring legal notice) before displaying
+ the file.
+ directory, dir [environment variable TMPDIR, or /tmp]
+ The directory where temporary files are created. The environmental
+ variable TMPDIR is used as the default value if it exists, other-
+ wise _/_t_m_p is used.
+ edcompatible, ed [off]
+ This option causes the presence or absence of gg and cc suffixes on
+ ssuubbssttiittuuttee commands to be remembered, and to be toggled by repeat-
+ ing the suffices. The suffix rr makes the substitution be as in the
+ ~~ command, instead of like the && command.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ errorbells, eb [off]
+ EExx only. Causes eexx error messages to be preceded by a bell.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ exrc, ex [off]
+ If this option is turned off in the system or $HOME startup files,
+ the local startup files are never read (unless they are the same as
+ the system or $HOME startup files). Turning it on has no effect,
+ i.e. the normal checks for local startup files are performed, re-
+ gardless. See the STARTUP INFORMATION section for more informa-
+ tion.
+ extended [off]
+ This option causes all regular expressions to be treated as POSIX
+ 1003.2 extended regular expressions (which are similar to historic
+ egrep(1) style expressions).
+ flash [on]
+ This option causes the screen to flash instead of beeping the key-
+ board, on error, if the terminal has the capability.
+ hardtabs, ht [8]
+ This option defines the spacing between hardware tab settings, i.e.
+ the tab expansion done by the operating system and/or the terminal
+ itself. As nneexx//nnvvii never writes tabs to the terminal, unlike his-
+ toric versions of eexx//vvii, this option does not currently have any
+ affect.
+ ignorecase, ic [off]
+ This option causes regular expressions, both in eexx commands and in
+
+ searches, to be evaluated in a case-insensitive manner.
+ keytime [6]
+ The 10th's of a second eexx//vvii waits for a subsequent key to complete
+ a key mapping.
+ leftright [off]
+ VVii only. This option causes the screen to be scrolled left-right
+ to view lines longer than the screen, instead of the traditional vvii
+ screen interface which folds long lines at the right-hand margin of
+ the terminal.
+ lines, li [24]
+ VVii only. The number of lines in the screen. Setting this option
+ causes eexx//vvii to set (or reset) the environmental variable LINES.
+ See the Screen Sizing section for more information.
+ lisp [off]
+ VVii only. This option changes the behavior of the vvii ((, )), {{, }}, [[[[
+ and ]]]] commands to match the Lisp language. Also, the aauuttooiinnddeenntt
+ option's behavior is changed to be appropriate for Lisp.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ list [off]
+ This option causes lines to be displayed in an unambiguous fashion.
+ Specifically, tabs are displayed as control characters, i.e.
+ ``^I'', and the ends of lines are marked with a ``$'' character.
+ magic [on]
+ This option is on by default. Turning the mmaaggiicc option off causes
+ all regular expression characters except for ``^'' and ``$'', to be
+ treated as ordinary characters. To re-enable characters individu-
+ ally, when the mmaaggiicc option is off, precede them with an ``\''. See
+ the REGULAR EXPRESSIONS AND REPLACEMENT STRINGS section for more
+ information.
+ matchtime [7]
+ VVii only. The 10th's of a second eexx//vvii pauses on the matching char-
+ acter when the sshhoowwmmaattcchh option is set.
+ mesg [on]
+ This option allows other users to contact you using the talk(1) and
+ write(1) utilities, while you are editing. EExx//vvii does not turn
+ message on, i.e. if messages were turned off when the editor was
+ invoked, they will stay turned off. This option only permits you
+ to disallow messages for the edit session. See the mesg(1) utility
+ for more information.
+ modelines, modeline [off]
+ If the mmooddeelliinneess option is set, eexx//vvii has historically scanned the
+ first and last five lines of each file as it is read for editing,
+ looking for any eexx commands that have been placed in those lines.
+ After the startup information has been processed, and before the
+ user starts editing the file, any commands embedded in the file are
+ executed. Commands are recognized by the letters ``e'' or ``v''
+ followed by ``x'' or ``i'', at the beginning of a line or following
+ a tab or space character, and followed by a ``:'', an eexx command,
+ and another ``:''. This option is a security problem of immense
+ proportions, and should not be used under any circumstances.
+ _T_h_i_s _o_p_t_i_o_n _w_i_l_l _n_e_v_e_r _b_e _i_m_p_l_e_m_e_n_t_e_d_.
+ number, nu [off]
+ Precede each line displayed with its current line number.
+ open [on]
+ EExx only. If this option is not set, the ooppeenn and vviissuuaall commands
+ are disallowed.
+ optimize, opt [on]
+ VVii only. Throughput of text is expedited by setting the terminal
+ to no do automatic carriage returns when printing more than one
+ (logical) line of output, greatly speeding output on terminals
+ without addressable cursors when text with leading white space is
+ printed.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ paragraphs, para [IPLPPPQPP LIpplpipbp]
+ VVii only. Define additional paragraph boundaries for the {{ and }}
+ commands. The value of this option must be a character string con-
+ sisting of zero or more character pairs.
+
+ In the text to be edited, the character string <newline>.<char-
+ pair>, (where <char-pair> is one of the character pairs in the op-
+ tion's value) defines a paragraph boundary. For example, if the
+ option were set to ``LaA ##'', then all of the following additional
+ paragraph boundaries would be recognized:
+ <newline>.La
+ <newline>.A<space>
+ <newline>.##
+ prompt [on]
+ EExx only. This option causes eexx to prompt for command input with a
+ ``:'' character; when it's not set, no prompt is displayed.
+ readonly, ro [off]
+ This option causes a force flag to be required to attempt to write
+ the file back to the original file name. Setting this option is
+ equivalent to using the --RR command line option, or editing a file
+ which lacks write permission.
+ recdir [/var/tmp/vi.recover]
+ The directory where recovery files are stored.
+ redraw, re [off]
+ VVii only. The editor simulates (using great amounts of output), an
+ intelligent terminal on a dumb terminal (e.g. during insertions in
+ visual mode the characters to the right of the cursor are refreshed
+ as each input character is typed).
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ remap [on]
+ If this option is set, it's possible to define macros in terms of
+ other macros. Otherwise, each key is only remapped up to one time.
+ For example, if ``A'' is mapped to ``B'', and ``B'' is mapped to
+ ``C'', The keystroke ``A'' will be mapped to ``C'' if rreemmaapp is set,
+ and to ``B'' if it is not set.
+ remapmax [on]
+ If this option is set, a key may only be remapped 50 times. If it
+ is not set, a key may be remapped an infinite number of times, and
+ the editor can be placed into infinite loops.
+ report [5]
+ Set the threshold of the number of lines that need to be changed
+ before a message will be displayed to the user. The value is the
+ largest value about which the editor is silent, i.e. by default, 6
+ lines must change before the user is notified.
+ ruler [off]
+ VVii only. Display a row/column ruler on the colon command line.
+ scroll, scr [window / 2]
+ Set the number of lines scrolled by the vvii commands ^^DD and ^^UU.
+
+ Historically, the eexx zz command, when specified without a count,
+ used two times the size of the scroll value; the POSIX 1003.2 stan-
+ dard specified the window size, which is a better choice.
+ sections, sect [NHSHH HUnhsh]
+ VVii only. Define additional section boundaries for the [[[[ and ]]]]
+ commands. The sseeccttiioonnss option should be set to a character string
+ consisting of zero or more character pairs. In the text to be
+ edited, the character string <newline>.<char-pair>, (where <char-
+ pair> is one of the character pairs in the option's value), defines
+ a section boundary in the same manner that ppaarraaggrraapphh option bound-
+ aries are defined.
+ shell, sh [environment variable SHELL, or /bin/sh]
+ Select the shell used by the editor. The specified path is the
+ pathname of the shell invoked by the vvii !! shell escape command and
+ by the eexx sshheellll command. This program is also used to resolve any
+ shell meta-characters in eexx commands.
+ shiftwidth, sw [8]
+ Set the autoindent and shift command indentation width. This width
+ is used by the aauuttooiinnddeenntt option and by the <<, >>, and sshhiifftt com-
+
+ mands.
+ showdirty [off]
+ VVii only. Display an asterisk on the colon command line if the file
+ has been modified.
+ showmatch, sm [off]
+ VVii only. This option causes vvii, when a ``}'' or ``)'' is entered,
+ to briefly move the cursor the matching ``{'' or ``(''. See the
+ mmaattcchhttiimmee option for more information.
+ showmode [off]
+ VVii only. This option causes vvii to display the strings ``Command''
+ or ``Input'' on the colon command line, based on the current mode
+ of the editor.
+ sidescroll [16]
+ VVii only. Sets the number of columns that are shifted to the left
+ or right, when vvii is doing left-right scrolling and the left or
+ right margin is crossed. See the lleeffttrriigghhtt option for more infor-
+ mation.
+ slowopen, slow [off]
+ This option affects the display algorithm used by vvii, holding off
+ display updating during input of new text to improve throughput
+ when the terminal in use is slow and unintelligent.
+ _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+ sourceany [off]
+ If this option is turned on, vvii historically read startup files
+ that were owned by someone other than the editor user. See the
+ STARTUP INFORMATION section for more information. This option is a
+ security problem of immense proportions, and should not be used un-
+ der any circumstances.
+ _T_h_i_s _o_p_t_i_o_n _w_i_l_l _n_e_v_e_r _b_e _i_m_p_l_e_m_e_n_t_e_d_.
+ tabstop, ts [8]
+ This option sets tab widths for the editor display.
+ taglength, tl [0]
+ This option sets the maximum number of characters that are consid-
+ ered significant in a tag name. Setting the value to 0 makes all
+ of the characters in the tag name significant.
+ tags, tag [tags /var/db/libc.tags /sys/kern/tags]
+ Sets the list of tags files, in search order, which are used when
+ the editor searches for a tag.
+ term, ttytype, tty [environment variable TERM]
+ Set the terminal type. Setting this option causes eexx//vvii to set (or
+ reset) the environmental variable TERM.
+ terse [off]
+ This option has historically made editor messages less verbose. It
+ has no effect in this implementation. See the vveerrbboossee option for
+ more information.
+ timeout, to [on]
+ If this option is set, eexx//vvii waits for a specific period for a sub-
+ sequent key to complete a key mapping (see the kkeeyyttiimmee option). If
+ the option is not set, the editor waits until enough keys are en-
+ tered to resolve the ambiguity, regardless of how long it takes.
+ ttywerase [off]
+ VVii only. This option changes how vvii does word erase during text
+ input. If this option is set, text is broken up into two classes,
+ blank characters and non-blank characters. Changing from one class
+ to another marks the end of a word.
+ verbose [off]
+ only. VVii historically bells the terminal for many obvious mis-
+ takes, e.g. trying to move past the left-hand margin, or past the
+ end of the file. If this option is set, an error message is dis-
+ played for all errors.
+ w300 [no default]
+ VVii only. Set the window size if the baud rate is less than 1200
+ baud. See the wwiinnddooww option for more information.
+ w1200 [no default]
+ VVii only. Set the window size if the baud rate is equal to 1200
+
+ baud. See the wwiinnddooww option for more information.
+ w9600 [no default]
+ VVii only. Set the window size if the baud rate is greater than 1200
+ baud. See the wwiinnddooww option for more information.
+ warn [on]
+ EExx only. This option causes a warning message to the terminal if
+ the file has been modified, since it was last written, before a !!
+ command.
+ window, w, wi [environment variable LINES]
+ This option determines the default number of lines in a screenful,
+ as written by the zz command. It also determines the number of
+ lines scrolled by the vvii commands ^^FF and ^^BB. The value of window
+ can be unrelated to the real screen size, although it starts out as
+ the number of lines on the screen (see the SCREEN SIZING section).
+ Setting the value of the wwiinnddooww option is the same as using the --ww
+ command line option.
+
+ If the value of wwiinnddooww (as set by the wwiinnddooww, ww330000, ww11220000 or ww99660000
+ options) is smaller than the actual size of the screen, large
+ screen movements will result in displaying only that smaller number
+ of lines on the screen. (Further movements in that same area will
+ result in the screen being filled.) This can provide a performance
+ improvement when viewing different places in one or more files over
+ a slow link.
+ wrapmargin, wm [0]
+ VVii only. If the value of wrapmargin is non-zero, vvii will break
+ lines, that are more than that number of characters long, into two
+ lines at the blank character closest to the value. If wrapmargin
+ is 0, or if there is no blank character upon which to break the
+ line, the line will not be broken.
+ wrapscan, ws [on]
+ This option causes searches to wrap around the end or the beginning
+ of the file, and back to the starting point. Otherwise, the end or
+ beginning of the file terminates the search.
+ writeany, wa [off]
+ If this option is set, file-overwriting checks that would usually
+ be made before the wwrriittee and xxiitt commands, or before an automatic
+ write (see the aauuttoowwrriittee option), are not made. This allows a
+ write to any file, provided the file permissions allow it.
+
+4.4BSD March 18, 1994 10
diff --git a/usr.bin/vi/nex/ex.c b/usr.bin/vi/ex/ex.c
index 3f5beac4a734..5b27de36fa98 100644
--- a/usr.bin/vi/nex/ex.c
+++ b/usr.bin/vi/ex/ex.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,19 +32,29 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex.c 8.90 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)ex.c 8.106 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
@@ -65,7 +75,7 @@ ex(sp, ep)
EXF *ep;
{
TEXT *tp;
- u_int saved_mode;
+ u_int flags, saved_mode;
int eval;
char defcom[sizeof(DEFCOM)];
@@ -76,38 +86,57 @@ ex(sp, ep)
return (ex_end(sp));
/* If reading from a file, messages should have line info. */
- if (!F_ISSET(sp->gp, G_ISFROMTTY)) {
+ if (!F_ISSET(sp->gp, G_STDIN_TTY)) {
sp->if_lno = 1;
sp->if_name = strdup("input");
}
+
+ /*
+ * !!!
+ * Historically, the beautify option applies to ex command input read
+ * from a file. In addition, the first time a ^H was discarded from
+ * the input, a message "^H discarded" was displayed. We don't bother.
+ */
+ LF_INIT(TXT_CNTRLD | TXT_CR | TXT_PROMPT);
+ if (O_ISSET(sp, O_BEAUTIFY))
+ LF_SET(TXT_BEAUTIFY);
+
for (eval = 0;; ++sp->if_lno) {
/* Get the next command. */
- switch (sp->s_get(sp, ep, &sp->tiq, ':', TXT_CR | TXT_PROMPT)) {
+ switch (sp->s_get(sp, ep, &sp->tiq, ':', flags)) {
case INP_OK:
break;
case INP_EOF:
+ case INP_ERR:
F_SET(sp, S_EXIT_FORCE);
goto ret;
- case INP_ERR:
- continue;
}
saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
tp = sp->tiq.cqh_first;
if (tp->len == 0) {
- if (F_ISSET(sp->gp, G_ISFROMTTY)) {
+ if (F_ISSET(sp->gp, G_STDIN_TTY)) {
+ /* Special case \r command. */
(void)fputc('\r', stdout);
(void)fflush(stdout);
}
memmove(defcom, DEFCOM, sizeof(DEFCOM));
- (void)ex_icmd(sp, ep, defcom, sizeof(DEFCOM) - 1);
+ if (ex_icmd(sp, ep, defcom, sizeof(DEFCOM) - 1) &&
+ !F_ISSET(sp->gp, G_STDIN_TTY))
+ F_SET(sp, S_EXIT_FORCE);
} else {
- if (F_ISSET(sp->gp, G_ISFROMTTY))
- (void)fputc('\n', stdout);
- (void)ex_icmd(sp, ep, tp->lb, tp->len);
+ if (F_ISSET(sp->gp, G_STDIN_TTY))
+ /* Special case ^D command. */
+ if (tp->len == 1 && tp->lb[0] == '\004') {
+ (void)fputc('\r', stdout);
+ (void)fflush(stdout);
+ } else
+ (void)fputc('\n', stdout);
+ if (ex_icmd(sp, ep, tp->lb, tp->len) &&
+ !F_ISSET(sp->gp, G_STDIN_TTY))
+ F_SET(sp, S_EXIT_FORCE);
}
(void)msg_rpt(sp, 0);
-
if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))
break;
@@ -163,11 +192,16 @@ err: rval = 1;
} else {
bp[sb.st_size] = '\0'; /* XXX */
- /* Run the command. Messages include file/line information. */
+ /*
+ * Run the command. Messages include file/line information,
+ * but we don't care if we can't get space.
+ */
sp->if_lno = 1;
sp->if_name = strdup(filename);
+ F_SET(sp, S_VLITONLY);
rval = ex_icmd(sp, ep, bp, len);
- FREE(sp->if_name, strlen(sp->if_name) + 1);
+ F_CLR(sp, S_VLITONLY);
+ free(sp->if_name);
sp->if_name = NULL;
}
@@ -205,7 +239,7 @@ ex_icmd(sp, ep, cmd, len)
}
/* Special command structure for :s as a repeat substitution command. */
-static EXCMDLIST const cmd_subagain =
+static EXCMDLIST const cmd_subagain =
{"s", ex_subagain, E_ADDR2|E_NORC,
"s",
"[line [,line]] s [cgr] [count] [#lp]",
@@ -222,7 +256,6 @@ ex_cmd(sp, ep, cmd, cmdlen)
char *cmd;
size_t cmdlen;
{
- CHAR_T vlit;
EX_PRIVATE *exp;
EXCMDARG exc;
EXCMDLIST const *cp;
@@ -318,7 +351,7 @@ loop: if (nl) {
* the command "cut" wasn't known. However, it makes ":e+35 file" work
* correctly.
*/
-#define SINGLE_CHAR_COMMANDS "!#&<=>@~"
+#define SINGLE_CHAR_COMMANDS "\004!#&<=>@~"
if (cmdlen != 0 && cmd[0] != '|' && cmd[0] != '\n') {
if (strchr(SINGLE_CHAR_COMMANDS, *cmd)) {
p = cmd;
@@ -346,8 +379,6 @@ loop: if (nl) {
* Historic vi permitted pretty much anything to follow the
* substitute command, e.g. "s/e/E/|s|sgc3p" was fine. Make
* it work.
- *
- * Use of msgq below is safe, command names are all alphabetics.
*/
if ((cp = ex_comm_search(p, namelen)) == NULL)
if (p[0] == 'k' && p[1] && !p[2]) {
@@ -415,12 +446,14 @@ loop: if (nl) {
* called when reading the .exrc file and similar things. There's
* this little chicken and egg problem -- if we read the file first,
* we won't know how to display it. If we read/set the exrc stuff
- * first, we can't allow any command that requires file state.
- * Historic vi generally took the easy way out and dropped core.
+ * first, we can't allow any command that requires file state. We
+ * don't have a "reading an rc" bit, because we want the commands
+ * to work when the user source's the rc file later. Historic vi
+ * generally took the easy way out and dropped core.
*/
if (LF_ISSET(E_NORC) && ep == NULL) {
msgq(sp, M_ERR,
- "The %s command requires that a file already have been read in.",
+ "The %s command requires that a file have already been read in.",
cp->name);
goto err;
}
@@ -474,7 +507,6 @@ loop: if (nl) {
*/
arg1_len = 0;
save_cmd = cmd;
- (void)term_key_ch(sp, K_VLNEXT, &vlit);
if (cp == &cmds[C_EDIT] ||
cp == &cmds[C_EX] || cp == &cmds[C_VISUAL_VI]) {
/*
@@ -501,7 +533,8 @@ loop: if (nl) {
++cmd;
--cmdlen;
for (arg1 = p = cmd; cmdlen > 0; --cmdlen, ++cmd) {
- if ((ch = *cmd) == vlit && cmdlen > 1) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
--cmdlen;
ch = *++cmd;
} else if (isblank(ch))
@@ -573,22 +606,23 @@ loop: if (nl) {
*
* Historically, vi permitted ^V's to escape <newline>'s in the .exrc
* file. It was almost certainly a bug, but that's what bug-for-bug
- * compatibility means, Grasshopper. Also, ^V's escape the command
+ * compatibility means, Grasshopper. Also, ^V's escape the command
* delimiters. Literal next quote characters in front of the newlines,
* '|' characters or literal next characters are stripped as as they're
* no longer useful.
*/
for (p = cmd, cnt = 0; cmdlen > 0; --cmdlen, ++cmd) {
- if ((ch = cmd[0]) == vlit && cmdlen > 1) {
- ch = cmd[1];
- if (ch == '\n' || ch == '|') {
- if (ch == '\n')
+ ch = cmd[0];
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ tmp = cmd[1];
+ if (tmp == '\n' || tmp == '|') {
+ if (tmp == '\n')
++sp->if_lno;
--cmdlen;
++cmd;
++cnt;
- } else
- ch = vlit;
+ ch = tmp;
+ }
} else if (ch == '\n' || ch == '|') {
if (ch == '\n')
nl = 1;
@@ -619,7 +653,7 @@ loop: if (nl) {
if (cp == &cmds[C_SET])
for (p = cmd, len = cmdlen; len > 0; --len, ++p)
if (*p == '\\')
- *p = vlit;
+ *p = LITERAL_CH;
/*
* Set the default addresses. It's an error to specify an address for
@@ -695,7 +729,7 @@ two: switch (exc.addrcnt) {
if (lno == 0) {
exc.addr1.lno = exc.addr2.lno = 0;
LF_SET(E_ZERO);
- } else
+ } else
exc.addr1.lno = exc.addr2.lno = sp->lno;
} else
exc.addr1.lno = exc.addr2.lno = sp->lno;
@@ -714,6 +748,24 @@ two: switch (exc.addrcnt) {
goto usage;
}
+ /*
+ * !!!
+ * The ^D scroll command historically scrolled half the screen size
+ * rows down, rounded down, or to EOF. It was an error if the cursor
+ * was already at EOF. (Leading addresses were permitted, but were
+ * then ignored.)
+ */
+ if (cp == &cmds[C_SCROLL]) {
+ exc.addrcnt = 2;
+ exc.addr1.lno = sp->lno + 1;
+ exc.addr2.lno = sp->lno + 1 + (O_VAL(sp, O_LINES) + 1) / 2;
+ exc.addr1.cno = exc.addr2.cno = sp->cno;
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (lno != 0 && lno > sp->lno && exc.addr2.lno > lno)
+ exc.addr2.lno = lno;
+ }
+
flagoff = 0;
for (p = cp->syntax; *p != '\0'; ++p) {
/*
@@ -820,9 +872,15 @@ end2: break;
break;
case 'c': /* count [01+a] */
++p;
+ /* Validate any signed value. */
if (!isdigit(*cmd) &&
(*p != '+' || (*cmd != '+' && *cmd != '-')))
break;
+ /* If a signed value, set appropriate flags. */
+ if (*cmd == '-')
+ F_SET(&exc, E_COUNT_NEG);
+ else if (*cmd == '+')
+ F_SET(&exc, E_COUNT_POS);
/* 8-bit XXX */ if ((lno = strtol(cmd, &t, 10)) == 0 && *p != '0') {
msgq(sp, M_ERR, "Count may not be zero.");
goto err;
@@ -855,7 +913,7 @@ end2: break;
goto err;
/* Line specifications are always required. */
if (!tmp) {
- msgq(sp, M_ERR,
+ msgq(sp, M_ERR,
"%s: bad line specification", cmd);
goto err;
}
@@ -881,7 +939,8 @@ end2: break;
* First there was the word.
*/
for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd) {
- if ((ch = *cmd) == vlit && cmdlen > 1) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
--cmdlen;
*p++ = *++cmd;
} else if (isblank(ch)) {
@@ -893,7 +952,7 @@ end2: break;
}
if (argv_exp0(sp, ep, &exc, t, p - t))
goto err;
-
+
/* Delete intervening whitespace. */
for (; cmdlen > 0; --cmdlen, ++cmd) {
ch = *cmd;
@@ -904,12 +963,14 @@ end2: break;
goto usage;
/* Followed by the string. */
- for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd, ++p)
- if ((ch = *cmd) == vlit && cmdlen > 1) {
+ for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd, ++p) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
--cmdlen;
*p = *++cmd;
} else
*p = ch;
+ }
if (argv_exp0(sp, ep, &exc, t, p - t))
goto err;
goto addr2;
@@ -1194,8 +1255,9 @@ addr2: switch (exc.addrcnt) {
* to know if part of the command was discarded.
*/
err: if (save_cmdlen == 0)
- for (; cmdlen; --cmdlen)
- if ((ch = *cmd++) == vlit && cmdlen > 1) {
+ for (; cmdlen; --cmdlen) {
+ ch = *cmd++;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
--cmdlen;
++cmd;
} else if (ch == '\n' || ch == '|') {
@@ -1203,6 +1265,7 @@ err: if (save_cmdlen == 0)
save_cmdlen = 1;
break;
}
+ }
if (save_cmdlen != 0)
msgq(sp, M_ERR,
"Ex command failed: remaining command input discarded.");
@@ -1343,10 +1406,11 @@ ep_line(sp, ep, cur, cmdp, cmdlenp, addr_found)
size_t *cmdlenp;
int *addr_found;
{
- MARK m, *mp;
+ MARK m;
long total;
u_int flags;
size_t cmdlen;
+ int (*sf) __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *));
char *cmd, *endp;
*addr_found = 0;
@@ -1389,9 +1453,8 @@ ep_line(sp, ep, cur, cmdp, cmdlenp, addr_found)
msgq(sp, M_ERR, "No mark name supplied.");
return (1);
}
- if ((mp = mark_get(sp, ep, cmd[1])) == NULL)
+ if (mark_get(sp, ep, cmd[1], cur))
return (1);
- *cur = *mp;
cmd += 2;
cmdlen -= 2;
break;
@@ -1408,29 +1471,23 @@ ep_line(sp, ep, cur, cmdp, cmdlenp, addr_found)
}
++cmd;
--cmdlen;
- if (cmd[0] == '/')
- goto forward;
- if (cmd[0] == '?')
- goto backward;
- /* NOTREACHED */
+ sf = cmd[0] == '/' ? f_search : b_search;
+ goto search;
case '/': /* Search forward. */
-forward: *addr_found = 1;
- m.lno = sp->lno;
- m.cno = sp->cno;
- flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET;
- if (f_search(sp, ep, &m, &m, cmd, &endp, &flags))
- return (1);
- cur->lno = m.lno;
- cur->cno = m.cno;
- cmdlen -= (endp - cmd);
- cmd = endp;
- break;
+ sf = f_search;
+ goto search;
case '?': /* Search backward. */
-backward: *addr_found = 1;
+ sf = b_search;
+search: if (ep == NULL) {
+ msgq(sp, M_ERR,
+ "A search address requires that a file have already been read in.");
+ return (1);
+ }
+ *addr_found = 1;
m.lno = sp->lno;
m.cno = sp->cno;
flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET;
- if (b_search(sp, ep, &m, &m, cmd, &endp, &flags))
+ if (sf(sp, ep, &m, &m, cmd, &endp, &flags))
return (1);
cur->lno = m.lno;
cur->cno = m.cno;
@@ -1476,14 +1533,18 @@ backward: *addr_found = 1;
++cmd;
}
}
- if (total < 0 && -total > cur->lno) {
- msgq(sp, M_ERR, "Reference to a line number less than 0.");
- return (1);
- }
- cur->lno += total;
- *cmdp = cmd;
- *cmdlenp = cmdlen;
+ if (*addr_found) {
+ if (total < 0 && -total > cur->lno) {
+ msgq(sp, M_ERR,
+ "Reference to a line number less than 0.");
+ return (1);
+ }
+ cur->lno += total;
+
+ *cmdp = cmd;
+ *cmdlenp = cmdlen;
+ }
return (0);
}
@@ -1504,6 +1565,30 @@ ex_is_abbrev(name, len)
(cp == &cmds[C_ABBR] || cp == &cmds[C_UNABBREVIATE]));
}
+/*
+ * ex_is_unmap -
+ * The vi text input routine needs to know if ex thinks this is
+ * an unmap command, so it can turn off input mapping. Usual
+ * ranting in the vi/v_ntext:txt_unmap() routine.
+ */
+int
+ex_is_unmap(name, len)
+ char *name;
+ size_t len;
+{
+ EXCMDLIST const *cp;
+
+ /*
+ * The command the vi input routines are really interested in
+ * is "unmap!", not just unmap.
+ */
+ if (name[len - 1] != '!')
+ return (0);
+ --len;
+ return ((cp = ex_comm_search(name, len)) != NULL &&
+ cp == &cmds[C_UNMAP]);
+}
+
static inline EXCMDLIST const *
ex_comm_search(name, len)
char *name;
diff --git a/usr.bin/vi/nex/ex_abbrev.c b/usr.bin/vi/ex/ex_abbrev.c
index f28cbe45e490..9db3ce148761 100644
--- a/usr.bin/vi/nex/ex_abbrev.c
+++ b/usr.bin/vi/ex/ex_abbrev.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_abbrev.c 8.6 (Berkeley) 12/22/93";
+static char sccsid[] = "@(#)ex_abbrev.c 8.8 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "seq.h"
@@ -65,7 +75,7 @@ ex_abbr(sp, ep, cmdp)
}
if (seq_set(sp, NULL, 0, cmdp->argv[0]->bp, cmdp->argv[0]->len,
- cmdp->argv[1]->bp, cmdp->argv[1]->len, SEQ_ABBREV, 1))
+ cmdp->argv[1]->bp, cmdp->argv[1]->len, SEQ_ABBREV, S_USERDEF))
return (1);
F_SET(sp->gp, G_ABBREV);
return (0);
diff --git a/usr.bin/vi/nex/ex_append.c b/usr.bin/vi/ex/ex_append.c
index c6edfd57db3b..f75b22fa31af 100644
--- a/usr.bin/vi/nex/ex_append.c
+++ b/usr.bin/vi/ex/ex_append.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_append.c 8.6 (Berkeley) 11/23/93";
+static char sccsid[] = "@(#)ex_append.c 8.9 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -95,6 +106,7 @@ aci(sp, ep, cmdp, cmd)
MARK m;
TEXT *tp;
recno_t cnt;
+ u_int flags;
int rval, aiset;
/*
@@ -118,6 +130,11 @@ aci(sp, ep, cmdp, cmd)
--m.lno;
cmd = APPEND;
}
+
+ LF_INIT(TXT_CR | TXT_NLECHO);
+ if (O_ISSET(sp, O_BEAUTIFY))
+ LF_SET(TXT_BEAUTIFY);
+
if (cmd == CHANGE)
for (;; ++m.lno) {
if (m.lno > cmdp->addr2.lno) {
@@ -125,8 +142,7 @@ aci(sp, ep, cmdp, cmd)
--m.lno;
break;
}
- switch (sp->s_get(sp, ep, &sp->tiq, 0,
- TXT_BEAUTIFY | TXT_CR | TXT_NLECHO)) {
+ switch (sp->s_get(sp, ep, &sp->tiq, 0, flags)) {
case INP_OK:
break;
case INP_EOF:
@@ -152,8 +168,7 @@ aci(sp, ep, cmdp, cmd)
if (cmd == APPEND)
for (;; ++m.lno) {
- switch (sp->s_get(sp, ep, &sp->tiq, 0,
- TXT_BEAUTIFY | TXT_CR | TXT_NLECHO)) {
+ switch (sp->s_get(sp, ep, &sp->tiq, 0, flags)) {
case INP_OK:
break;
case INP_EOF:
diff --git a/usr.bin/vi/nex/ex_args.c b/usr.bin/vi/ex/ex_args.c
index 2f96df727dd8..e035704a4a29 100644
--- a/usr.bin/vi/nex/ex_args.c
+++ b/usr.bin/vi/ex/ex_args.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_args.c 8.13 (Berkeley) 12/20/93";
+static char sccsid[] = "@(#)ex_args.c 8.16 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -64,7 +74,7 @@ ex_next(sp, ep, cmdp)
FREF *frp;
char *name;
- MODIFY_CHECK(sp, ep, F_ISSET(cmdp, E_FORCE));
+ MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));
if (cmdp->argc) {
/* Mark all the current files as ignored. */
@@ -76,7 +86,7 @@ ex_next(sp, ep, cmdp)
for (argv = cmdp->argv; argv[0]->len != 0; ++argv)
if (file_add(sp, NULL, argv[0]->bp, 0) == NULL)
return (1);
-
+
if ((frp = file_first(sp)) == NULL)
return (1);
} else if ((frp = file_next(sp, sp->a_frp)) == NULL) {
@@ -118,7 +128,7 @@ ex_prev(sp, ep, cmdp)
FREF *frp;
char *name;
- MODIFY_CHECK(sp, ep, F_ISSET(cmdp, E_FORCE));
+ MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));
if ((frp = file_prev(sp, sp->a_frp)) == NULL) {
msgq(sp, M_ERR, "No previous files to edit.");
@@ -160,7 +170,7 @@ ex_rew(sp, ep, cmdp)
return (1);
}
- MODIFY_CHECK(sp, ep, F_ISSET(cmdp, E_FORCE));
+ MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));
/*
* !!!
diff --git a/usr.bin/vi/nex/ex_argv.c b/usr.bin/vi/ex/ex_argv.c
index 6ad76c61dfbc..de2f6d5340aa 100644
--- a/usr.bin/vi/nex/ex_argv.c
+++ b/usr.bin/vi/ex/ex_argv.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,17 +32,27 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_argv.c 8.26 (Berkeley) 1/2/94";
+static char sccsid[] = "@(#)ex_argv.c 8.28 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
@@ -215,13 +225,11 @@ argv_exp3(sp, ep, excp, cmd, cmdlen)
char *cmd;
size_t cmdlen;
{
- CHAR_T vlit;
EX_PRIVATE *exp;
size_t len;
int ch, off;
char *ap, *p;
- (void)term_key_ch(sp, K_VLNEXT, &vlit);
for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) {
/* Skip any leading whitespace. */
for (; cmdlen > 0; --cmdlen, ++cmd) {
@@ -234,20 +242,22 @@ argv_exp3(sp, ep, excp, cmd, cmdlen)
/*
* Determine the length of this whitespace delimited
- * argument.
+ * argument.
*
* QUOTING NOTE:
*
* Skip any character preceded by the user's quoting
* character.
*/
- for (ap = cmd, len = 0; cmdlen > 0; ++cmd, --cmdlen, ++len)
- if ((ch = *cmd) == vlit && cmdlen > 1) {
- ++cmd;
+ for (ap = cmd, len = 0; cmdlen > 0; ++cmd, --cmdlen, ++len) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ ++cmd;
--cmdlen;
} else if (isblank(ch))
break;
-
+ }
+
/*
* Copy the argument into place.
*
@@ -259,7 +269,7 @@ argv_exp3(sp, ep, excp, cmd, cmdlen)
off = exp->argsoff;
exp->args[off]->len = len;
for (p = exp->args[off]->bp; len > 0; --len, *p++ = *ap++)
- if (*ap == vlit) {
+ if (IS_ESCAPE(sp, *ap)) {
++ap;
--exp->args[off]->len;
}
@@ -380,7 +390,7 @@ argv_alloc(sp, len)
SCR *sp;
size_t len;
{
- ARGS *ap;
+ ARGS *ap;
EX_PRIVATE *exp;
int cnt, off;
@@ -406,33 +416,33 @@ argv_alloc(sp, len)
if (exp->args[off] == NULL) {
CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
if (exp->args[off] == NULL)
- goto mem;
- }
+ goto mem;
+ }
/* First argument buffer. */
- ap = exp->args[off];
- ap->len = 0;
- if (ap->blen < len + 1) {
- ap->blen = len + 1;
+ ap = exp->args[off];
+ ap->len = 0;
+ if (ap->blen < len + 1) {
+ ap->blen = len + 1;
REALLOC(sp, ap->bp, CHAR_T *, ap->blen * sizeof(CHAR_T));
if (ap->bp == NULL) {
- ap->bp = NULL;
- ap->blen = 0;
- F_CLR(ap, A_ALLOCATED);
-mem: msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- F_SET(ap, A_ALLOCATED);
- }
+ ap->bp = NULL;
+ ap->blen = 0;
+ F_CLR(ap, A_ALLOCATED);
+mem: msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ F_SET(ap, A_ALLOCATED);
+ }
/* Second argument. */
if (exp->args[++off] == NULL) {
CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
if (exp->args[off] == NULL)
- goto mem;
- }
+ goto mem;
+ }
/* 0 length serves as end-of-argument marker. */
- exp->args[off]->len = 0;
+ exp->args[off]->len = 0;
return (0);
}
@@ -505,7 +515,7 @@ argv_sexp(sp, bpp, blenp, lenp)
msgq(sp, M_SYSERR, "fdopen");
goto err;
}
-
+
/*
* Do the minimal amount of work possible, the shell is going
* to run briefly and then exit. Hopefully.
diff --git a/usr.bin/vi/nex/ex_at.c b/usr.bin/vi/ex/ex_at.c
index 51d001f304a7..9b3da3fdb1cb 100644
--- a/usr.bin/vi/nex/ex_at.c
+++ b/usr.bin/vi/ex/ex_at.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_at.c 8.16 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)ex_at.c 8.18 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -82,7 +92,7 @@ ex_at(sp, ep, cmdp)
/* Save for reuse. */
exp->at_lbuf = name;
exp->at_lbuf_set = 1;
-
+
/*
* If the buffer was cut in line mode or had portions of more
* than one line, <newlines> are appended to each line as it
diff --git a/usr.bin/vi/nex/ex_bang.c b/usr.bin/vi/ex/ex_bang.c
index 4f7222b4e78c..34b477a0d97a 100644
--- a/usr.bin/vi/nex/ex_bang.c
+++ b/usr.bin/vi/ex/ex_bang.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_bang.c 8.22 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)ex_bang.c 8.24 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "sex/sex_screen.h"
@@ -77,7 +87,6 @@ ex_bang(sp, ep, cmdp)
int rval;
char *bp, *msg;
-
ap = cmdp->argv[0];
if (ap->len == 0) {
msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
diff --git a/usr.bin/vi/ex/ex_cd.c b/usr.bin/vi/ex/ex_cd.c
new file mode 100644
index 000000000000..098af534f676
--- /dev/null
+++ b/usr.bin/vi/ex/ex_cd.c
@@ -0,0 +1,205 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_cd.c 8.10 (Berkeley) 3/19/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_cd -- :cd[!] [directory]
+ * Change directories.
+ */
+int
+ex_cd(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ CDPATH *cdp;
+ EX_PRIVATE *exp;
+ char *dir, buf[MAXPATHLEN];
+
+ switch (cmdp->argc) {
+ case 0:
+ if ((dir = getenv("HOME")) == NULL) {
+ msgq(sp, M_ERR,
+ "Environment variable HOME not set.");
+ return (1);
+ }
+ break;
+ case 1:
+ dir = cmdp->argv[0]->bp;
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * If the user has a CDPATH variable, we use it, otherwise
+ * we use the current directory.
+ *
+ * !!!
+ * This violates historic practice. Historic vi didn't consider
+ * CDPATH, and therefore always used the current directory. This
+ * is probably correct; if user's have set CDPATH to not include
+ * the current directory, they probably had a reason.
+ */
+ exp = EXP(sp);
+ if (dir[0] == '/') {
+ if (chdir(dir) < 0)
+ goto err;
+ } else {
+ for (cdp = exp->cdq.tqh_first;
+ cdp != NULL; cdp = cdp->q.tqe_next) {
+ (void)snprintf(buf,
+ sizeof(buf), "%s/%s", cdp->path, dir);
+ if (!chdir(buf))
+ break;
+ }
+ if (cdp == NULL) {
+err: msgq(sp, M_SYSERR, dir);
+ return (1);
+ }
+ }
+ if (getcwd(buf, sizeof(buf)) != NULL)
+ msgq(sp, M_INFO, "New directory: %s", buf);
+ return (0);
+}
+
+#define FREE_CDPATH(cdp) { \
+ TAILQ_REMOVE(&exp->cdq, (cdp), q); \
+ free((cdp)->path); \
+ FREE((cdp), sizeof(CDPATH)); \
+}
+/*
+ * ex_cdalloc --
+ * Create a new list of cd paths.
+ */
+int
+ex_cdalloc(sp, str)
+ SCR *sp;
+ char *str;
+{
+ EX_PRIVATE *exp;
+ CDPATH *cdp;
+ size_t len;
+ int founddot;
+ char *p, *t;
+
+ /* Free current queue. */
+ exp = EXP(sp);
+ while ((cdp = exp->cdq.tqh_first) != NULL)
+ FREE_CDPATH(cdp);
+
+ /*
+ * Create new queue. The CDPATH environmental variable (and the
+ * user's manual entry) are delimited by colon characters.
+ */
+ for (p = t = str, founddot = 0;; ++p) {
+ if (*p == '\0' || *p == ':') {
+ /*
+ * Empty strings specify ".". The only way to get an
+ * empty string is a leading colon, colons in a row,
+ * or a trailing colon. Or, to put it the other way,
+ * if the the length is zero, then it's either ":XXX",
+ * "XXX::XXXX" , "XXX:", or "", and the only failure
+ * mode is the last one. Note, the string ":" gives
+ * us two entries of '.', so we only include one of
+ * them.
+ */
+ if ((len = p - t) == 0) {
+ if (p == str && *p == '\0')
+ break;
+ if (founddot) {
+ if (*p == '\0')
+ break;
+ continue;
+ }
+ len = 1;
+ t = ".";
+ founddot = 1;
+ }
+ MALLOC_RET(sp, cdp, CDPATH *, sizeof(CDPATH));
+ MALLOC(sp, cdp->path, char *, len + 1);
+ if (cdp->path == NULL) {
+ free(cdp);
+ return (1);
+ }
+ memmove(cdp->path, t, len);
+ cdp->path[len] = '\0';
+ TAILQ_INSERT_TAIL(&exp->cdq, cdp, q);
+ t = p + 1;
+ }
+ if (*p == '\0')
+ break;
+ }
+ return (0);
+}
+ /* Free previous queue. */
+/*
+ * ex_cdfree --
+ * Free the cd path list.
+ */
+int
+ex_cdfree(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ CDPATH *cdp;
+
+ /* Free up cd path information. */
+ exp = EXP(sp);
+ while ((cdp = exp->cdq.tqh_first) != NULL)
+ FREE_CDPATH(cdp);
+ return (0);
+}
diff --git a/usr.bin/vi/nex/ex_delete.c b/usr.bin/vi/ex/ex_delete.c
index 5b737e8f547d..78512699c202 100644
--- a/usr.bin/vi/nex/ex_delete.c
+++ b/usr.bin/vi/ex/ex_delete.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_delete.c 8.6 (Berkeley) 1/11/94";
+static char sccsid[] = "@(#)ex_delete.c 8.7 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_digraph.c b/usr.bin/vi/ex/ex_digraph.c
index 20f1bf327ded..0b80cd01a333 100644
--- a/usr.bin/vi/nex/ex_digraph.c
+++ b/usr.bin/vi/ex/ex_digraph.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_digraph.c 8.4 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)ex_digraph.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#ifndef NO_DIGRAPH
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_display.c b/usr.bin/vi/ex/ex_display.c
index 0cfef42f675b..2f4f65bdca62 100644
--- a/usr.bin/vi/nex/ex_display.c
+++ b/usr.bin/vi/ex/ex_display.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_display.c 8.14 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)ex_display.c 8.15 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "tag.h"
diff --git a/usr.bin/vi/nex/ex_edit.c b/usr.bin/vi/ex/ex_edit.c
index eeafedaed778..03629bf7309f 100644
--- a/usr.bin/vi/nex/ex_edit.c
+++ b/usr.bin/vi/ex/ex_edit.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_edit.c 8.14 (Berkeley) 1/22/94";
+static char sccsid[] = "@(#)ex_edit.c 8.15 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_equal.c b/usr.bin/vi/ex/ex_equal.c
index f0a18bef41f4..0caf0051ec2f 100644
--- a/usr.bin/vi/nex/ex_equal.c
+++ b/usr.bin/vi/ex/ex_equal.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_equal.c 8.4 (Berkeley) 11/2/93";
+static char sccsid[] = "@(#)ex_equal.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_exit.c b/usr.bin/vi/ex/ex_exit.c
index b0f929a5bbe3..ebfc9d03bca2 100644
--- a/usr.bin/vi/nex/ex_exit.c
+++ b/usr.bin/vi/ex/ex_exit.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_exit.c 8.7 (Berkeley) 12/10/93";
+static char sccsid[] = "@(#)ex_exit.c 8.8 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_file.c b/usr.bin/vi/ex/ex_file.c
index d556d5214e0e..57923db350c1 100644
--- a/usr.bin/vi/nex/ex_file.c
+++ b/usr.bin/vi/ex/ex_file.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_file.c 8.7 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)ex_file.c 8.8 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_global.c b/usr.bin/vi/ex/ex_global.c
index 4f942a39f680..ea770a6c3c07 100644
--- a/usr.bin/vi/nex/ex_global.c
+++ b/usr.bin/vi/ex/ex_global.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,25 +32,33 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_global.c 8.29 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)ex_global.c 8.32 (Berkeley) 3/22/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
-#include "interrupt.h"
enum which {GLOBAL, VGLOBAL};
static int global __P((SCR *, EXF *, EXCMDARG *, enum which));
-static void global_intr __P((int));
/*
* ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands]
@@ -86,14 +94,13 @@ global(sp, ep, cmdp, cmd)
EXCMDARG *cmdp;
enum which cmd;
{
- DECLARE_INTERRUPTS;
RANGE *rp;
EX_PRIVATE *exp;
recno_t elno, lno;
regmatch_t match[1];
regex_t *re, lre;
size_t clen, len;
- int delim, eval, reflags, replaced, rval;
+ int delim, eval, reflags, replaced, rval, teardown;
char *cb, *ptrn, *p, *t;
/*
@@ -188,7 +195,7 @@ global(sp, ep, cmdp, cmd)
/* Set the global flag, and set up interrupts. */
F_SET(sp, S_GLOBAL);
- SET_UP_INTERRUPTS(global_intr);
+ teardown = !intr_init(sp);
/*
* For each line... The semantics of global matching are that we first
@@ -200,7 +207,7 @@ global(sp, ep, cmdp, cmd)
* What we do is create linked list of lines that are tracked through
* each ex command. There's a callback routine which the DB interface
* routines call when a line is created or deleted. This doesn't help
- * the layering much.
+ * the layering much.
*/
exp = EXP(sp);
for (rval = 0, lno = cmdp->addr1.lno,
@@ -288,9 +295,9 @@ interrupted: msgq(sp, M_INFO, "Interrupted.");
err: rval = 1;
}
-interrupt_err:
F_CLR(sp, S_GLOBAL);
- TEAR_DOWN_INTERRUPTS;
+ if (teardown)
+ intr_end(sp);
/* Free any remaining ranges and the command buffer. */
while ((rp = exp->rangeq.cqh_first) != (void *)&exp->rangeq) {
@@ -378,26 +385,3 @@ global_insdel(sp, ep, op, lno)
*/
exp->range_lno = lno;
}
-
-/*
- * global_intr --
- * Set the interrupt bit in any screen that is running an interruptible
- * global.
- *
- * XXX
- * In the future this may be a problem. The user should be able to move to
- * another screen and keep typing while this runs. If so, and the user has
- * more than one global running, it will be hard to decide which one to
- * stop.
- */
-static void
-global_intr(signo)
- int signo;
-{
- SCR *sp;
-
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_GLOBAL) && F_ISSET(sp, S_INTERRUPTIBLE))
- F_SET(sp, S_INTERRUPTED);
-}
diff --git a/usr.bin/vi/nex/ex_init.c b/usr.bin/vi/ex/ex_init.c
index 26acf2f44c92..cef766757303 100644
--- a/usr.bin/vi/nex/ex_init.c
+++ b/usr.bin/vi/ex/ex_init.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_init.c 8.11 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)ex_init.c 8.14 (Berkeley) 3/18/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -62,6 +72,7 @@ ex_screen_copy(orig, sp)
/* Initialize queues. */
TAILQ_INIT(&nexp->tagq);
TAILQ_INIT(&nexp->tagfq);
+ TAILQ_INIT(&nexp->cdq);
CIRCLEQ_INIT(&nexp->rangeq);
if (orig == NULL) {
@@ -109,6 +120,12 @@ ex_screen_end(sp)
if (exp->lastbcomm != NULL)
FREE(exp->lastbcomm, strlen(exp->lastbcomm) + 1);
+ if (ex_tagfree(sp))
+ rval = 1;
+
+ if (ex_cdfree(sp))
+ rval = 1;
+
/* Free private memory. */
FREE(exp, sizeof(EX_PRIVATE));
sp->ex_private = NULL;
@@ -164,11 +181,6 @@ int
ex_end(sp)
SCR *sp;
{
- /* Save the cursor location. */
- sp->frp->lno = sp->lno;
- sp->frp->cno = sp->cno;
- F_SET(sp->frp, FR_CURSORSET);
-
return (0);
}
@@ -182,6 +194,8 @@ ex_optchange(sp, opt)
int opt;
{
switch (opt) {
+ case O_CDPATH:
+ return (ex_cdalloc(sp, O_STR(sp, O_CDPATH)));
case O_TAGS:
return (ex_tagalloc(sp, O_STR(sp, O_TAGS)));
}
diff --git a/usr.bin/vi/nex/ex_join.c b/usr.bin/vi/ex/ex_join.c
index 33bace97500e..97946952cd6f 100644
--- a/usr.bin/vi/nex/ex_join.c
+++ b/usr.bin/vi/ex/ex_join.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_join.c 8.8 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)ex_join.c 8.11 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -85,8 +95,8 @@ ex_join(sp, ep, cmdp)
++cmdp->addr2.lno;
clen = tlen = 0;
- for (first = 1, from = cmdp->addr1.lno,
- to = cmdp->addr2.lno; from <= to; ++from) {
+ for (first = 1,
+ from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
/*
* Get next line. Historic versions of vi allowed "10J" while
* less than 10 lines from the end-of-file, so we do too.
@@ -136,7 +146,7 @@ ex_join(sp, ep, cmdp)
for (; len && isblank(*p); --len, ++p);
}
}
-
+
if (len != 0) {
memmove(tbp, p, len);
tbp += len;
@@ -176,9 +186,9 @@ ex_join(sp, ep, cmdp)
for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to)
if (file_dline(sp, ep, to))
goto err;
-
- /* Reset the original line. */
- if (file_sline(sp, ep, from, bp, tbp - bp)) {
+
+ /* If the original line changed, reset it. */
+ if (!first && file_sline(sp, ep, from, bp, tbp - bp)) {
err: FREE_SPACE(sp, bp, blen);
return (1);
}
diff --git a/usr.bin/vi/nex/ex_map.c b/usr.bin/vi/ex/ex_map.c
index 0154c34699be..1d754941c1a6 100644
--- a/usr.bin/vi/nex/ex_map.c
+++ b/usr.bin/vi/ex/ex_map.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_map.c 8.6 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)ex_map.c 8.8 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "seq.h"
@@ -122,7 +132,7 @@ ex_map(sp, ep, cmdp)
}
}
return (seq_set(sp, name, nlen, input, cmdp->argv[0]->len,
- cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, 1));
+ cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, S_USERDEF));
}
/*
diff --git a/usr.bin/vi/nex/ex_mark.c b/usr.bin/vi/ex/ex_mark.c
index 34efe21648b1..50174a38d0f2 100644
--- a/usr.bin/vi/nex/ex_mark.c
+++ b/usr.bin/vi/ex/ex_mark.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_mark.c 8.4 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)ex_mark.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_mkexrc.c b/usr.bin/vi/ex/ex_mkexrc.c
index b26c7f814532..0fa5450b78c4 100644
--- a/usr.bin/vi/nex/ex_mkexrc.c
+++ b/usr.bin/vi/ex/ex_mkexrc.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,22 +32,32 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_mkexrc.c 8.8 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)ex_mkexrc.c 8.10 (Berkeley) 3/22/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
#include "excmd.h"
#include "seq.h"
-#include "pathnames.h"
/*
* ex_mkexrc -- :mkexrc[!] [file]
diff --git a/usr.bin/vi/ex/ex_move.c b/usr.bin/vi/ex/ex_move.c
new file mode 100644
index 000000000000..dbda992a190a
--- /dev/null
+++ b/usr.bin/vi/ex/ex_move.c
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_move.c 8.11 (Berkeley) 3/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_copy -- :[line [,line]] co[py] line [flags]
+ * Copy selected lines.
+ */
+int
+ex_copy(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ CB cb;
+ MARK fm1, fm2, m, tm;
+ recno_t cnt;
+ int rval;
+
+ /*
+ * It's possible to copy things into the area that's being
+ * copied, e.g. "2,5copy3" is legitimate. Save the text to
+ * a cut buffer.
+ */
+ fm1 = cmdp->addr1;
+ fm2 = cmdp->addr2;
+ memset(&cb, 0, sizeof(cb));
+ CIRCLEQ_INIT(&cb.textq);
+ if (cut(sp, ep, &cb, NULL, &fm1, &fm2, CUT_LINEMODE))
+ return (1);
+
+ /* Put the text into place. */
+ tm.lno = cmdp->lineno;
+ tm.cno = 0;
+ if (put(sp, ep, &cb, NULL, &tm, &m, 1))
+ rval = 1;
+ else {
+ /*
+ * Copy puts the cursor on the last line copied. The cursor
+ * returned by the put routine is the first line put, not the
+ * last, because that's the historic semantic of vi.
+ */
+ cnt = (fm2.lno - fm1.lno) + 1;
+ sp->lno = m.lno + (cnt - 1);
+ sp->cno = 0;
+
+ sp->rptlines[L_COPIED] += cnt;
+ rval = 0;
+ }
+ text_lfree(&cb.textq);
+ return (rval);
+}
+
+/*
+ * ex_move -- :[line [,line]] mo[ve] line
+ * Move selected lines.
+ */
+int
+ex_move(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ LMARK *lmp;
+ MARK fm1, fm2;
+ recno_t cnt, diff, fl, tl, mfl, mtl;
+ size_t len;
+ int mark_reset;
+ char *p;
+
+ /*
+ * It's not possible to move things into the area that's being
+ * moved.
+ */
+ fm1 = cmdp->addr1;
+ fm2 = cmdp->addr2;
+ if (cmdp->lineno >= fm1.lno && cmdp->lineno < fm2.lno) {
+ msgq(sp, M_ERR, "Destination line is inside move range.");
+ return (1);
+ }
+
+ /*
+ * Log the positions of any marks in the to-be-deleted lines. This
+ * has to work with the logging code. What happens is that we log
+ * the old mark positions, make the changes, then log the new mark
+ * positions. Then the marks end up in the right positions no matter
+ * which way the log is traversed.
+ *
+ * XXX
+ * Reset the MARK_USERSET flag so that the log can undo the mark.
+ * This isn't very clean, and should probably be fixed.
+ */
+ fl = fm1.lno;
+ tl = cmdp->lineno;
+
+ /* Log the old positions of the marks. */
+ mark_reset = 0;
+ for (lmp = ep->marks.lh_first; lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->name != ABSMARK1 &&
+ lmp->lno >= fl && lmp->lno <= tl) {
+ mark_reset = 1;
+ F_CLR(lmp, MARK_USERSET);
+ (void)log_mark(sp, ep, lmp);
+ }
+
+ /* Move the lines. */
+ diff = (fm2.lno - fm1.lno) + 1;
+ if (tl > fl) { /* Destination > source. */
+ mfl = tl - diff;
+ mtl = tl;
+ for (cnt = diff; cnt--;) {
+ if ((p = file_gline(sp, ep, fl, &len)) == NULL)
+ return (1);
+ if (file_aline(sp, ep, 1, tl, p, len))
+ return (1);
+ if (mark_reset)
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->name != ABSMARK1 &&
+ lmp->lno == fl)
+ lmp->lno = tl + 1;
+ if (file_dline(sp, ep, fl))
+ return (1);
+ }
+ } else { /* Destination < source. */
+ mfl = tl;
+ mtl = tl + diff;
+ for (cnt = diff; cnt--;) {
+ if ((p = file_gline(sp, ep, fl, &len)) == NULL)
+ return (1);
+ if (file_aline(sp, ep, 1, tl++, p, len))
+ return (1);
+ if (mark_reset)
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->name != ABSMARK1 &&
+ lmp->lno == fl)
+ lmp->lno = tl;
+ ++fl;
+ if (file_dline(sp, ep, fl))
+ return (1);
+ }
+ }
+ sp->lno = tl; /* Last line moved. */
+ sp->cno = 0;
+
+ /* Log the new positions of the marks. */
+ if (mark_reset)
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->name != ABSMARK1 &&
+ lmp->lno >= mfl && lmp->lno <= mtl)
+ (void)log_mark(sp, ep, lmp);
+
+
+ sp->rptlines[L_MOVED] += diff;
+ return (0);
+}
diff --git a/usr.bin/vi/nex/ex_open.c b/usr.bin/vi/ex/ex_open.c
index 77b418a41d6f..c727be985d53 100644
--- a/usr.bin/vi/nex/ex_open.c
+++ b/usr.bin/vi/ex/ex_open.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_open.c 8.2 (Berkeley) 10/3/93";
+static char sccsid[] = "@(#)ex_open.c 8.3 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_preserve.c b/usr.bin/vi/ex/ex_preserve.c
index a7f35485698d..fd765a7d20ea 100644
--- a/usr.bin/vi/nex/ex_preserve.c
+++ b/usr.bin/vi/ex/ex_preserve.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_preserve.c 8.4 (Berkeley) 11/8/93";
+static char sccsid[] = "@(#)ex_preserve.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_print.c b/usr.bin/vi/ex/ex_print.c
index d25e9ff563b1..ad37c2b2235c 100644
--- a/usr.bin/vi/nex/ex_print.c
+++ b/usr.bin/vi/ex/ex_print.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_print.c 8.6 (Berkeley) 11/2/93";
+static char sccsid[] = "@(#)ex_print.c 8.8 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -123,7 +133,7 @@ ex_print(sp, ep, fp, tp, flags)
col = ex_printf(EXCOOKIE, "%7ld ", from);
else
col = 0;
-
+
/*
* Display the line. The format for E_F_PRINT isn't very good,
* especially in handling end-of-line tabs, but they're almost
diff --git a/usr.bin/vi/nex/ex_put.c b/usr.bin/vi/ex/ex_put.c
index 3bc687fd1496..e56199d4fe68 100644
--- a/usr.bin/vi/nex/ex_put.c
+++ b/usr.bin/vi/ex/ex_put.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_put.c 8.4 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)ex_put.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_read.c b/usr.bin/vi/ex/ex_read.c
index 9328b93c329a..724c7e9fd407 100644
--- a/usr.bin/vi/nex/ex_read.c
+++ b/usr.bin/vi/ex/ex_read.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_read.c 8.21 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)ex_read.c 8.26 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -62,7 +72,7 @@ ex_read(sp, ep, cmdp)
MARK rm;
recno_t nlines;
size_t blen, len;
- int rval;
+ int btear, itear, rval;
char *bp, *name;
/*
@@ -146,7 +156,18 @@ ex_read(sp, ep, cmdp)
return (1);
}
+ /*
+ * Nvi handles the interrupt when reading from a file, but not
+ * when reading from a filter, since the terminal settings have
+ * been reset.
+ */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Reading...");
+ itear = !intr_init(sp);
rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1);
+ if (btear)
+ busy_off(sp);
+ if (itear)
+ intr_end(sp);
/*
* Set the cursor to the first line read in, if anything read
@@ -157,7 +178,7 @@ ex_read(sp, ep, cmdp)
sp->lno = cmdp->addr1.lno;
if (nlines)
++sp->lno;
-
+
F_SET(EXP(sp), EX_AUTOPRINT);
return (rval);
}
@@ -177,19 +198,25 @@ ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
int success_msg;
{
EX_PRIVATE *exp;
- u_long ccnt;
+ recno_t lcnt, lno;
size_t len;
- recno_t lno, nlines;
+ u_long ccnt; /* XXX: can't print off_t portably. */
int rval;
+ rval = 0;
+ exp = EXP(sp);
+
/*
* Add in the lines from the output. Insertion starts at the line
* following the address.
*/
ccnt = 0;
- rval = 0;
- exp = EXP(sp);
- for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno) {
+ lcnt = 0;
+ for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
+ if (F_ISSET(sp, S_INTERRUPTED)) {
+ msgq(sp, M_INFO, "Interrupted.");
+ break;
+ }
if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
rval = 1;
break;
@@ -211,13 +238,12 @@ ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
return (1);
/* Return the number of lines read in. */
- nlines = lno - fm->lno;
if (nlinesp != NULL)
- *nlinesp = nlines;
+ *nlinesp = lcnt;
if (success_msg)
msgq(sp, M_INFO, "%s: %lu line%s, %lu characters.",
- name, nlines, nlines == 1 ? "" : "s", ccnt);
+ name, lcnt, lcnt == 1 ? "" : "s", ccnt);
return (0);
}
diff --git a/usr.bin/vi/nex/ex_screen.c b/usr.bin/vi/ex/ex_screen.c
index 0fd000d4898a..de0f946621af 100644
--- a/usr.bin/vi/nex/ex_screen.c
+++ b/usr.bin/vi/ex/ex_screen.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_screen.c 8.10 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)ex_screen.c 8.12 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -83,7 +93,7 @@ ex_fg(sp, ep, cmdp)
}
/*
- * ex_resize -- :resize [change]
+ * ex_resize -- :resize [+-]rows
* Change the screen size.
*/
int
@@ -92,9 +102,19 @@ ex_resize(sp, ep, cmdp)
EXF *ep;
EXCMDARG *cmdp;
{
- if (!F_ISSET(cmdp, E_COUNT))
- cmdp->count = 1;
- return (sp->s_rabs(sp, cmdp->count));
+ enum adjust adj;
+
+ if (!F_ISSET(cmdp, E_COUNT)) {
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+ if (F_ISSET(cmdp, E_COUNT_NEG))
+ adj = A_DECREASE;
+ else if (F_ISSET(cmdp, E_COUNT_POS))
+ adj = A_INCREASE;
+ else
+ adj = A_SET;
+ return (sp->s_rabs(sp, cmdp->count, adj));
}
/*
diff --git a/usr.bin/vi/nex/ex_script.c b/usr.bin/vi/ex/ex_script.c
index 606e479d6af4..e8e3b0e0a4db 100644
--- a/usr.bin/vi/nex/ex_script.c
+++ b/usr.bin/vi/ex/ex_script.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,28 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_script.c 8.10 (Berkeley) 12/22/93";
+static char sccsid[] = "@(#)ex_script.c 8.12 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/ioctl.h>
+#include <queue.h>
+#include <sys/time.h>
#include <sys/wait.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "script.h"
@@ -471,7 +481,7 @@ ret: FREE_SPACE(sp, bp, blen);
* sscr_setprompt --
*
* Set the prompt to the last line we got from the shell.
- *
+ *
*/
static int
sscr_setprompt(sp, buf, len)
@@ -551,7 +561,7 @@ sscr_end(sp)
/* Turn off the script flag. */
F_CLR(sp, S_SCRIPT);
-
+
/* Close down the parent's file descriptors. */
if (sc->sh_master != -1)
(void)close(sc->sh_master);
diff --git a/usr.bin/vi/nex/ex_set.c b/usr.bin/vi/ex/ex_set.c
index a463524e5fa9..ac6994cf5f0e 100644
--- a/usr.bin/vi/nex/ex_set.c
+++ b/usr.bin/vi/ex/ex_set.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_set.c 8.2 (Berkeley) 10/3/93";
+static char sccsid[] = "@(#)ex_set.c 8.3 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_shell.c b/usr.bin/vi/ex/ex_shell.c
index 282cc8f4fbdc..08e0a3e5bbff 100644
--- a/usr.bin/vi/nex/ex_shell.c
+++ b/usr.bin/vi/ex/ex_shell.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,17 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_shell.c 8.17 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)ex_shell.c 8.21 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/param.h>
-#include <sys/stat.h>
+#include <queue.h>
+#include <sys/time.h>
-#include <curses.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "../svi/svi_screen.h"
@@ -73,19 +81,16 @@ ex_exec_proc(sp, cmd, p1, p2)
SCR *sp;
char *cmd, *p1, *p2;
{
- struct sigaction act, oact;
- struct stat osb, sb;
- struct termios term;
const char *name;
pid_t pid;
- int isig, rval;
+ int rval, teardown;
/* Clear the rest of the screen. */
if (sp->s_clear(sp))
return (1);
/* Save ex/vi terminal settings, and restore the original ones. */
- EX_LEAVE(sp, isig, act, oact, sb, osb, term);
+ teardown = !ex_sleave(sp);
/* Put out various messages. */
if (p1 != NULL)
@@ -121,14 +126,15 @@ ex_exec_proc(sp, cmd, p1, p2)
rval = proc_wait(sp, (long)pid, cmd, 0);
/* Restore ex/vi terminal settings. */
-err: EX_RETURN(sp, isig, act, oact, sb, osb, term);
+err: if (teardown)
+ ex_rleave(sp);
/*
* XXX
- * EX_LEAVE/EX_RETURN only give us 1-second resolution on the tty
- * changes. A fast '!' command, e.g. ":!pwd" can beat us to the
- * refresh. When there's better resolution from the stat(2) timers,
- * this can go away.
+ * Stat of the tty structures (see ex_sleave, ex_rleave) only give
+ * us 1-second resolution on the tty changes. A fast '!' command,
+ * e.g. ":!pwd" can beat us to the refresh. When there's better
+ * resolution from the stat(2) timers, this can go away.
*/
F_SET(sp, S_REFRESH);
diff --git a/usr.bin/vi/nex/ex_shift.c b/usr.bin/vi/ex/ex_shift.c
index 8a0b858cbb6f..fb12432f6517 100644
--- a/usr.bin/vi/nex/ex_shift.c
+++ b/usr.bin/vi/ex/ex_shift.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_shift.c 8.12 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)ex_shift.c 8.14 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -54,7 +64,7 @@ ex_shiftl(sp, ep, cmdp)
{
return (shift(sp, ep, cmdp, LEFT));
}
-
+
int
ex_shiftr(sp, ep, cmdp)
SCR *sp;
diff --git a/usr.bin/vi/nex/ex_source.c b/usr.bin/vi/ex/ex_source.c
index bf2a9f1b275e..4aba34ae0373 100644
--- a/usr.bin/vi/nex/ex_source.c
+++ b/usr.bin/vi/ex/ex_source.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_source.c 8.3 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)ex_source.c 8.4 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_stop.c b/usr.bin/vi/ex/ex_stop.c
index 26ec067c622a..1ed01f2c8757 100644
--- a/usr.bin/vi/nex/ex_stop.c
+++ b/usr.bin/vi/ex/ex_stop.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_stop.c 8.4 (Berkeley) 10/28/93";
+static char sccsid[] = "@(#)ex_stop.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "sex/sex_screen.h"
diff --git a/usr.bin/vi/nex/ex_subst.c b/usr.bin/vi/ex/ex_subst.c
index 6d132c56dd24..c8c03a4a2e79 100644
--- a/usr.bin/vi/nex/ex_subst.c
+++ b/usr.bin/vi/ex/ex_subst.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,20 +32,29 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_substitute.c 8.33 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)ex_subst.c 8.39 (Berkeley) 3/22/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
-#include "interrupt.h"
#define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */
#define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */
@@ -53,7 +62,6 @@ static char sccsid[] = "@(#)ex_substitute.c 8.33 (Berkeley) 1/9/94";
static int checkmatchsize __P((SCR *, regex_t *));
static inline int regsub __P((SCR *,
char *, char **, size_t *, size_t *));
-static void subst_intr __P((int));
static int substitute __P((SCR *, EXF *,
EXCMDARG *, char *, regex_t *, u_int));
@@ -129,8 +137,11 @@ ex_substitute(sp, ep, cmdp)
*t = '\0';
break;
}
- if (p[0] == '\\' && p[1] == delim)
- ++p;
+ if (p[0] == '\\')
+ if (p[1] == delim)
+ ++p;
+ else if (p[1] == '\\')
+ *t++ = *p++;
*t++ = *p++;
}
@@ -187,18 +198,20 @@ ex_substitute(sp, ep, cmdp)
/*
* Get the replacement string.
*
- * The special character ~ (\~ if O_MAGIC not set) inserts the
- * previous replacement string into this replacement string.
- *
* The special character & (\& if O_MAGIC not set) matches the
* entire RE. No handling of & is required here, it's done by
* regsub().
*
+ * The special character ~ (\~ if O_MAGIC not set) inserts the
+ * previous replacement string into this replacement string.
+ * Count ~'s to figure out how much space we need. We could
+ * special case nonexistent last patterns or whether or not
+ * O_MAGIC is set, but it's probably not worth the effort.
+ *
* QUOTING NOTE:
*
* Only toss an escape character if it escapes a delimiter or
- * an escape character, or if O_MAGIC is set and it escapes a
- * tilde.
+ * if O_MAGIC is set and it escapes a tilde.
*/
if (*p == '\0') {
if (sp->repl != NULL)
@@ -206,11 +219,6 @@ ex_substitute(sp, ep, cmdp)
sp->repl = NULL;
sp->repl_len = 0;
} else {
- /*
- * Count ~'s to figure out how much space we need. We could
- * special case nonexistent last patterns or whether or not
- * O_MAGIC is set, but it's probably not worth the effort.
- */
for (rep = p, len = 0;
p[0] != '\0' && p[0] != delim; ++p, ++len)
if (p[0] == '~')
@@ -223,9 +231,12 @@ ex_substitute(sp, ep, cmdp)
break;
}
if (p[0] == '\\') {
- if (p[1] == '\\' || p[1] == delim)
+ if (p[1] == delim)
++p;
- else if (p[1] == '~') {
+ else if (p[1] == '\\') {
+ *t++ = *p++;
+ ++len;
+ } else if (p[1] == '~') {
++p;
if (!O_ISSET(sp, O_MAGIC))
goto tilde;
@@ -295,7 +306,7 @@ ex_subtilde(sp, ep, cmdp)
return (substitute(sp, ep, cmdp, cmdp->argv[0]->bp, &sp->sre, 0));
}
-/*
+/*
* The nasty part of the substitution is what happens when the replacement
* string contains newlines. It's a bit tricky -- consider the information
* that has to be retained for "s/f\(o\)o/^M\1^M\1/". The solution here is
@@ -355,13 +366,12 @@ substitute(sp, ep, cmdp, s, re, flags)
regex_t *re;
u_int flags;
{
- DECLARE_INTERRUPTS;
MARK from, to;
recno_t elno, lno;
size_t blen, cnt, last, lbclen, lblen, len, llen, offset, saved_offset;
- int didsub, do_eol_match, eflags, empty_ok, eval;
- int linechanged, matched, quit, rval;
int cflag, gflag, lflag, nflag, pflag, rflag;
+ int didsub, do_eol_match, eflags, empty_ok, eval;
+ int linechanged, matched, quit, rval, teardown;
char *bp, *lb;
/*
@@ -453,8 +463,8 @@ usage: msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
return (1);
}
- if (!F_ISSET(sp, S_GLOBAL))
- SET_UP_INTERRUPTS(subst_intr);
+ /* Set up interrupts. */
+ teardown = !intr_init(sp);
/*
* bp: if interactive, line cache
@@ -618,7 +628,7 @@ nextmatch: sp->match[0].rm_so = 0;
/* If interruptible, pass the info back. */
if (F_ISSET(sp, S_INTERRUPTIBLE))
F_SET(sp, S_INTERRUPTED);
-
+
/*
* If any changes, resolve them, otherwise
* return to the main loop.
@@ -636,11 +646,12 @@ nextmatch: sp->match[0].rm_so = 0;
*
* !!!
* Historic vi just put the cursor on the first non-blank
- * of the last line changed. This might be better.
+ * of the last line changed. We move to the beginning of
+ * the next substitution.
*/
if (!cflag) {
sp->lno = lno;
- sp->cno = sp->match[0].rm_so + offset;
+ sp->cno = lbclen;
}
/* Substitute the matching bytes. */
@@ -795,9 +806,8 @@ endmatch: if (!linechanged)
ret1: rval = 1;
}
-interrupt_err:
- if (!F_ISSET(sp, S_GLOBAL))
- TEAR_DOWN_INTERRUPTS;
+ if (teardown)
+ intr_end(sp);
if (bp != NULL)
FREE_SPACE(sp, bp, blen);
@@ -835,7 +845,7 @@ regsub(sp, ip, lbp, lbclenp, lblenp)
* There are some special sequences that vi provides in the
* replacement patterns.
* & string the RE matched (\& if nomagic set)
- * \# n-th regular subexpression
+ * \# n-th regular subexpression
* \E end \U, \L conversion
* \e end \U, \L conversion
* \l convert the next character to lower-case
@@ -960,25 +970,3 @@ checkmatchsize(sp, re)
}
return (0);
}
-
-/*
- * subst_intr --
- * Set the interrupt bit in any screen that is interruptible.
- *
- * XXX
- * In the future this may be a problem. The user should be able to move to
- * another screen and keep typing while this runs. If so, and the user has
- * more than one substitute running, it will be hard to decide which one to
- * stop.
- */
-static void
-subst_intr(signo)
- int signo;
-{
- SCR *sp;
-
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_INTERRUPTIBLE))
- F_SET(sp, S_INTERRUPTED);
-}
diff --git a/usr.bin/vi/nex/ex_tag.c b/usr.bin/vi/ex/ex_tag.c
index c47ab0de9c44..64ef4cbb4966 100644
--- a/usr.bin/vi/nex/ex_tag.c
+++ b/usr.bin/vi/ex/ex_tag.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@@ -35,21 +35,31 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_tag.c 8.31 (Berkeley) 1/22/94";
+static char sccsid[] = "@(#)ex_tag.c 8.40 (Berkeley) 3/22/94";
#endif /* not lint */
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/mman.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "tag.h"
@@ -92,8 +102,9 @@ ex_tagfirst(sp, tagarg)
/*
* !!!
- * Historic vi accepted a line number as well as a search
- * string, and people are apparently still using the format.
+ * The historic tags file format (from a long, long time ago...)
+ * used a line number, not a search string. I got complaints, so
+ * people are still using the format.
*/
if (isdigit(search[0])) {
m.lno = atoi(search);
@@ -129,6 +140,19 @@ ex_tagfirst(sp, tagarg)
return (0);
}
+/* Free a tag or tagf structure from a queue. */
+#define FREETAG(tp) { \
+ TAILQ_REMOVE(&exp->tagq, (tp), q); \
+ if ((tp)->search != NULL) \
+ free((tp)->search); \
+ FREE((tp), sizeof(TAGF)); \
+}
+#define FREETAGF(tfp) { \
+ TAILQ_REMOVE(&exp->tagfq, (tfp), q); \
+ free((tfp)->name); \
+ FREE((tfp), sizeof(TAGF)); \
+}
+
/*
* ex_tagpush -- :tag [file]
* Move to a new tag.
@@ -157,7 +181,7 @@ ex_tagpush(sp, ep, cmdp)
int sval;
long tl;
char *name, *p, *search, *tag;
-
+
exp = EXP(sp);
switch (cmdp->argc) {
case 1:
@@ -186,10 +210,15 @@ ex_tagpush(sp, ep, cmdp)
if (tag_get(sp, exp->tlast, &tag, &name, &search))
return (1);
- /* Get a new FREF structure. */
- if ((frp = file_add(sp, sp->frp, name, 1)) == NULL) {
- FREE(tag, strlen(tag));
- return (1);
+ /* Get the (possibly new) FREF structure. */
+ if ((frp = file_add(sp, sp->frp, name, 1)) == NULL)
+ goto modify_err;
+
+ if (sp->frp == frp)
+ which = TC_CURRENT;
+ else {
+ MODIFY_GOTO(sp, sp->ep, F_ISSET(cmdp, E_FORCE));
+ which = TC_CHANGE;
}
/*
@@ -219,19 +248,15 @@ ex_tagpush(sp, ep, cmdp)
TAILQ_INSERT_HEAD(&exp->tagq, tp, q);
}
- /* Switch to the new file. */
- if (sp->frp == frp)
- which = TC_CURRENT;
- else {
- MODIFY_CHECK(sp, sp->ep, F_ISSET(cmdp, E_FORCE));
-
- if (file_init(sp, frp, NULL, 0)) {
- if (tp != NULL)
- FREE(tp, sizeof(TAG));
- FREE(tag, strlen(tag));
- return (1);
- }
- which = TC_CHANGE;
+ /* Switch files. */
+ if (which == TC_CHANGE && file_init(sp, frp, NULL, 0)) {
+ if (tp != NULL)
+ FREETAG(tp);
+ /* Handle special, first-tag case. */
+ if (exp->tagq.tqh_first->q.tqe_next == NULL)
+ TAILQ_REMOVE(&exp->tagq, exp->tagq.tqh_first, q);
+modify_err: free(tag);
+ return (1);
}
/*
@@ -280,19 +305,6 @@ ex_tagpush(sp, ep, cmdp)
return (0);
}
-/* Free a tag or tagf structure from a queue. */
-#define FREETAG(tp) { \
- TAILQ_REMOVE(&exp->tagq, (tp), q); \
- if ((tp)->search != NULL) \
- free((tp)->search); \
- FREE((tp), sizeof(TAGF)); \
-}
-#define FREETAGF(tfp) { \
- TAILQ_REMOVE(&exp->tagfq, (tfp), q); \
- free((tfp)->name); \
- FREE((tfp), sizeof(TAGF)); \
-}
-
/*
* ex_tagpop -- :tagp[op][!] [number | file]
* Pop the tag stack.
@@ -305,9 +317,8 @@ ex_tagpop(sp, ep, cmdp)
{
EX_PRIVATE *exp;
TAG *ntp, *tp;
- recno_t lno;
- long off, saved_off;
- size_t arglen, cno;
+ long off;
+ size_t arglen;
char *arg, *p, *t;
/* Check for an empty stack. */
@@ -319,41 +330,35 @@ ex_tagpop(sp, ep, cmdp)
switch (cmdp->argc) {
case 0: /* Pop one tag. */
- tp = exp->tagq.tqh_first;
- FREETAG(tp);
+ ntp = exp->tagq.tqh_first;
break;
case 1: /* Name or number. */
arg = cmdp->argv[0]->bp;
- saved_off = strtol(arg, &p, 10);
+ off = strtol(arg, &p, 10);
if (*p == '\0') {
- if (saved_off < 1)
+ if (off < 1)
return (0);
- for (tp = exp->tagq.tqh_first, off = saved_off;
- tp != NULL && off-- > 1; tp = tp->q.tqe_next);
+ for (tp = exp->tagq.tqh_first;
+ tp != NULL && --off > 1; tp = tp->q.tqe_next);
if (tp == NULL) {
msgq(sp, M_ERR,
-"Less than %d entries on the tags stack; use :display to see the tags stack.",
- saved_off);
+"Less than %s entries on the tags stack; use :display to see the tags stack.",
+ arg);
return (1);
}
- for (off = saved_off; off-- > 1;) {
- tp = exp->tagq.tqh_first;
- FREETAG(tp);
- }
+ ntp = tp;
} else {
arglen = strlen(arg);
for (tp = exp->tagq.tqh_first;
- tp != NULL; tp = tp->q.tqe_next) {
+ tp != NULL; ntp = tp, tp = tp->q.tqe_next) {
/* Use the user's original file name. */
p = tp->frp->name;
if ((t = strrchr(p, '/')) == NULL)
t = p;
else
++t;
- if (!strncmp(arg, t, arglen)) {
- ntp = tp;
+ if (!strncmp(arg, t, arglen))
break;
- }
}
if (tp == NULL) {
msgq(sp, M_ERR,
@@ -361,12 +366,6 @@ ex_tagpop(sp, ep, cmdp)
arg);
return (1);
}
- for (;;) {
- tp = exp->tagq.tqh_first;
- if (tp == ntp)
- break;
- FREETAG(tp);
- }
}
break;
default:
@@ -374,13 +373,12 @@ ex_tagpop(sp, ep, cmdp)
}
/* Update the cursor from the saved TAG information. */
- tp = exp->tagq.tqh_first;
+ tp = ntp->q.tqe_next;
if (tp->frp == sp->frp) {
sp->lno = tp->lno;
sp->cno = tp->cno;
} else {
- MODIFY_CHECK(sp, ep, F_ISSET(cmdp, E_FORCE));
-
+ MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));
if (file_init(sp, tp->frp, NULL, 0))
return (1);
@@ -391,16 +389,24 @@ ex_tagpop(sp, ep, cmdp)
F_SET(sp, S_FSWITCH);
}
- /* If returning to the first tag, the stack is now empty. */
- if (tp->q.tqe_next == NULL)
+ /* Pop entries off the queue up to ntp. */
+ for (;;) {
+ tp = exp->tagq.tqh_first;
FREETAG(tp);
+ if (tp == ntp)
+ break;
+ }
+
+ /* If returning to the first tag, the stack is now empty. */
+ if (exp->tagq.tqh_first->q.tqe_next == NULL)
+ TAILQ_REMOVE(&exp->tagq, exp->tagq.tqh_first, q);
return (0);
}
/*
* ex_tagtop -- :tagt[op][!]
* Clear the tag stack.
- */
+ */
int
ex_tagtop(sp, ep, cmdp)
SCR *sp;
@@ -408,39 +414,36 @@ ex_tagtop(sp, ep, cmdp)
EXCMDARG *cmdp;
{
EX_PRIVATE *exp;
- TAG *tp, tmp;
- int found;
+ TAG *tp;
- /* Pop to oldest saved information. */
+ /* Find oldest saved information. */
exp = EXP(sp);
- for (found = 0; (tp = exp->tagq.tqh_first) != NULL; found = 1) {
- if (exp->tagq.tqh_first == NULL)
- tmp = *tp;
- FREETAG(tp);
- }
-
- if (!found) {
+ for (tp = exp->tagq.tqh_first;
+ tp != NULL && tp->q.tqe_next != NULL; tp = tp->q.tqe_next);
+ if (tp == NULL) {
msgq(sp, M_INFO, "The tags stack is empty.");
return (1);
}
/* If not switching files, it's easy; else do the work. */
- if (tmp.frp == sp->frp) {
- sp->lno = tmp.lno;
- sp->cno = tmp.cno;
+ if (tp->frp == sp->frp) {
+ sp->lno = tp->lno;
+ sp->cno = tp->cno;
} else {
- MODIFY_CHECK(sp, sp->ep, F_ISSET(cmdp, E_FORCE));
-
- if (file_init(sp, tmp.frp, NULL, 0))
+ MODIFY_RET(sp, sp->ep, F_ISSET(cmdp, E_FORCE));
+ if (file_init(sp, tp->frp, NULL, 0))
return (1);
- tmp.frp->lno = tmp.lno;
- tmp.frp->cno = tmp.cno;
+ tp->frp->lno = tp->lno;
+ tp->frp->cno = tp->cno;
F_SET(sp->frp, FR_CURSORSET);
-
F_SET(sp, S_FSWITCH);
}
+
+ /* Empty out the queue. */
+ while ((tp = exp->tagq.tqh_first) != NULL)
+ FREETAG(tp);
return (0);
}
@@ -560,7 +563,8 @@ ex_tagfree(sp)
FREETAG(tp);
while ((tfp = exp->tagfq.tqh_first) != NULL)
FREETAGF(tfp);
- FREE(exp->tlast, strlen(exp->tlast) + 1);
+ if (exp->tlast != NULL)
+ free(exp->tlast);
return (0);
}
@@ -601,7 +605,7 @@ ex_tagcopy(orig, sp)
goto nomem;
TAILQ_INSERT_TAIL(&nexp->tagfq, tfp, q);
}
-
+
/* Copy the last tag. */
if (oexp->tlast != NULL &&
(nexp->tlast = strdup(oexp->tlast)) == NULL) {
@@ -620,10 +624,12 @@ tag_get(sp, tag, tagp, filep, searchp)
SCR *sp;
char *tag, **tagp, **filep, **searchp;
{
+ struct stat sb;
EX_PRIVATE *exp;
TAGF *tfp;
+ size_t plen, slen, tlen;
int dne;
- char *p;
+ char *p, pbuf[MAXPATHLEN];
/*
* Find the tag, only display missing file messages once, and
@@ -643,8 +649,11 @@ tag_get(sp, tag, tagp, filep, searchp)
}
} else
msgq(sp, M_SYSERR, tfp->name);
+ else
+ if (p != NULL)
+ break;
}
-
+
if (p == NULL) {
msgq(sp, M_ERR, "%s: tag not found.", tag);
if (dne)
@@ -660,8 +669,8 @@ tag_get(sp, tag, tagp, filep, searchp)
/*
* Set the return pointers; tagp points to the tag, and, incidentally
- * the allocated string, filep points to the nul-terminated file name,
- * searchp points to the nul-terminated search string.
+ * the allocated string, filep points to the file name, and searchp
+ * points to the search string. All three are nul-terminated.
*/
for (*tagp = p; *p && !isblank(*p); ++p);
if (*p == '\0')
@@ -677,6 +686,38 @@ malformed: free(*tagp);
msgq(sp, M_ERR, "%s: corrupted tag in %s.", tag, tfp->name);
return (1);
}
+
+ /*
+ * !!!
+ * If the tag file path is a relative path, see if it exists. If it
+ * doesn't, look relative to the tags file path. It's okay for a tag
+ * file to not exist, and, historically, vi simply displayed a "new"
+ * file. However, if the path exists relative to the tag file, it's
+ * pretty clear what's happening, so we may as well do it right.
+ */
+ if ((*filep)[0] != '/'
+ && stat(*filep, &sb) && (p = strrchr(tfp->name, '/')) != NULL) {
+ *p = '\0';
+ plen = snprintf(pbuf, sizeof(pbuf), "%s/%s", tfp->name, *filep);
+ *p = '/';
+ if (stat(pbuf, &sb) == 0) {
+ slen = strlen(*searchp);
+ tlen = strlen(*tagp);
+ MALLOC(sp, p, char *, plen + slen + tlen + 5);
+ if (p != NULL) {
+ memmove(p, *tagp, tlen);
+ free(*tagp);
+ *tagp = p;
+ *(p += tlen) = '\0';
+ memmove(++p, pbuf, plen);
+ *filep = p;
+ *(p += plen) = '\0';
+ memmove(++p, *searchp, slen);
+ *searchp = p;
+ *(p += slen) = '\0';
+ }
+ }
+ }
return (0);
}
@@ -710,7 +751,7 @@ search(sp, name, tname, tag)
* large.
*/
if (fstat(fd, &sb) || (map = mmap(NULL, (size_t)sb.st_size,
- PROT_READ, MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) {
+ PROT_READ, MAP_FILE|MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) {
(void)close(fd);
return (1);
}
@@ -744,40 +785,40 @@ done: if (munmap(map, (size_t)sb.st_size))
/*
* Binary search for "string" in memory between "front" and "back".
- *
+ *
* This routine is expected to return a pointer to the start of a line at
* *or before* the first word matching "string". Relaxing the constraint
* this way simplifies the algorithm.
- *
+ *
* Invariants:
- * front points to the beginning of a line at or before the first
+ * front points to the beginning of a line at or before the first
* matching string.
- *
- * back points to the beginning of a line at or after the first
+ *
+ * back points to the beginning of a line at or after the first
* matching line.
- *
+ *
* Base of the Invariants.
- * front = NULL;
+ * front = NULL;
* back = EOF;
- *
+ *
* Advancing the Invariants:
- *
+ *
* p = first newline after halfway point from front to back.
- *
- * If the string at "p" is not greater than the string to match,
+ *
+ * If the string at "p" is not greater than the string to match,
* p is the new front. Otherwise it is the new back.
- *
+ *
* Termination:
- *
- * The definition of the routine allows it return at any point,
+ *
+ * The definition of the routine allows it return at any point,
* since front is always at or before the line to print.
- *
- * In fact, it returns when the chosen "p" equals "back". This
- * implies that there exists a string is least half as long as
- * (back - front), which in turn implies that a linear search will
+ *
+ * In fact, it returns when the chosen "p" equals "back". This
+ * implies that there exists a string is least half as long as
+ * (back - front), which in turn implies that a linear search will
* be no more expensive than the cost of simply printing a string or two.
- *
- * Trying to continue with binary search at this point would be
+ *
+ * Trying to continue with binary search at this point would be
* more trouble than it's worth.
*/
#define SKIP_PAST_NEWLINE(p, back) while (p < back && *p++ != '\n');
@@ -805,12 +846,12 @@ binary_search(string, front, back)
/*
* Find the first line that starts with string, linearly searching from front
* to back.
- *
+ *
* Return NULL for no such line.
- *
+ *
* This routine assumes:
- *
- * o front points at the first character in a line.
+ *
+ * o front points at the first character in a line.
* o front is before or at the first line to be printed.
*/
static char *
@@ -821,10 +862,8 @@ linear_search(string, front, back)
switch (compare(string, front, back)) {
case EQUAL: /* Found it. */
return (front);
- break;
case LESS: /* No such string. */
return (NULL);
- break;
case GREATER: /* Keep going. */
break;
}
@@ -836,10 +875,10 @@ linear_search(string, front, back)
/*
* Return LESS, GREATER, or EQUAL depending on how the string1 compares
* with string2 (s1 ??? s2).
- *
- * o Matches up to len(s1) are EQUAL.
+ *
+ * o Matches up to len(s1) are EQUAL.
* o Matches up to len(s2) are GREATER.
- *
+ *
* The string "s1" is null terminated. The string s2 is '\t', space, (or
* "back") terminated.
*
diff --git a/usr.bin/vi/nex/ex_undo.c b/usr.bin/vi/ex/ex_undo.c
index c8dedd8d401a..cb9e9a808b0f 100644
--- a/usr.bin/vi/nex/ex_undo.c
+++ b/usr.bin/vi/ex/ex_undo.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_undo.c 8.4 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)ex_undo.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_usage.c b/usr.bin/vi/ex/ex_usage.c
index da84995d2993..251c7df85937 100644
--- a/usr.bin/vi/nex/ex_usage.c
+++ b/usr.bin/vi/ex/ex_usage.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,11 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_usage.c 8.11 (Berkeley) 12/17/93";
+static char sccsid[] = "@(#)ex_usage.c 8.14 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -76,7 +87,8 @@ ex_usage(sp, ep, cmdp)
{
ARGS *ap;
EXCMDLIST const *cp;
-
+ char *name;
+
switch (cmdp->argc) {
case 1:
ap = cmdp->argv[0];
@@ -106,9 +118,16 @@ ex_usage(sp, ep, cmdp)
}
break;
case 0:
- for (cp = cmds; cp->name != NULL; ++cp)
+ F_SET(sp, S_INTERRUPTIBLE);
+ for (cp = cmds; cp->name != NULL; ++cp) {
+ /* The ^D command has an unprintable name. */
+ if (cp == &cmds[C_SCROLL])
+ name = "^D";
+ else
+ name = cp->name;
(void)ex_printf(EXCOOKIE,
- "%*s: %s\n", MAXCMDNAMELEN, cp->name, cp->help);
+ "%*s: %s\n", MAXCMDNAMELEN, name, cp->help);
+ }
break;
default:
abort();
@@ -150,6 +169,7 @@ nokey: (void)ex_printf(EXCOOKIE,
isblank(*kp->help) ? "" : " ", kp->help, kp->usage);
break;
case 0:
+ F_SET(sp, S_INTERRUPTIBLE);
for (key = 0; key <= MAXVIKEY; ++key) {
kp = &vikeys[key];
if (kp->help != NULL)
diff --git a/usr.bin/vi/ex/ex_util.c b/usr.bin/vi/ex/ex_util.c
new file mode 100644
index 000000000000..05bf9bd85c86
--- /dev/null
+++ b/usr.bin/vi/ex/ex_util.c
@@ -0,0 +1,180 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_util.c 8.6 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_getline --
+ * Return a line from the terminal.
+ */
+int
+ex_getline(sp, fp, lenp)
+ SCR *sp;
+ FILE *fp;
+ size_t *lenp;
+{
+ EX_PRIVATE *exp;
+ size_t off;
+ int ch;
+ char *p;
+
+ exp = EXP(sp);
+ for (off = 0, p = exp->ibp;; ++off) {
+ ch = getc(fp);
+ if (off >= exp->ibp_len) {
+ BINC_RET(sp, exp->ibp, exp->ibp_len, off + 1);
+ p = exp->ibp + off;
+ }
+ if (ch == EOF || ch == '\n') {
+ if (ch == EOF && !off)
+ return (1);
+ *lenp = off;
+ return (0);
+ }
+ *p++ = ch;
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * ex_sleave --
+ * Save the terminal/signal state, not screen modification time.
+ * Specific to ex/filter.c and ex/ex_shell.c.
+ */
+int
+ex_sleave(sp)
+ SCR *sp;
+{
+ struct sigaction act;
+ struct stat sb;
+ EX_PRIVATE *exp;
+
+ /* Ignore sessions not using tty's. */
+ if (!F_ISSET(sp->gp, G_STDIN_TTY))
+ return (1);
+
+ /*
+ * The old terminal values almost certainly turn on VINTR, VQUIT and
+ * VSUSP. We don't want to interrupt the parent(s), so we ignore
+ * VINTR. VQUIT is ignored by main() because nvi never wants to catch
+ * it. A VSUSP handler have been installed by the screen code.
+ */
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ exp = EXP(sp);
+ if (sigaction(SIGINT, &act, &exp->leave_act)) {
+ msgq(sp, M_SYSERR, "sigaction");
+ return (1);
+ }
+ if (tcgetattr(STDIN_FILENO, &exp->leave_term)) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ goto err;
+ }
+ if (tcsetattr(STDIN_FILENO,
+ TCSANOW | TCSASOFT, &sp->gp->original_termios)) {
+ msgq(sp, M_SYSERR, "tcsetattr");
+ /*
+ * If an error occurs, back out the changes and run
+ * without interrupts.
+ */
+err: (void)sigaction(SIGINT, &exp->leave_act, NULL);
+ return (1);
+ }
+ /*
+ * The process may write to the terminal. Save the access time
+ * (read) and modification time (write) of the tty; if they have
+ * changed when we restore the modes, will have to refresh the
+ * screen.
+ */
+ if (fstat(STDIN_FILENO, &sb)) {
+ msgq(sp, M_SYSERR, "stat: stdin");
+ exp->leave_atime = exp->leave_mtime = 0;
+ } else {
+ exp->leave_atime = sb.st_atime;
+ exp->leave_mtime = sb.st_mtime;
+ }
+ return (0);
+}
+
+/*
+ * ex_rleave --
+ * Return the terminal/signal state, not screen modification time.
+ * Specific to ex/filter.c and ex/ex_shell.c.
+ */
+void
+ex_rleave(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ struct stat sb;
+
+ exp = EXP(sp);
+
+ /* Turn off interrupts. */
+ if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, &exp->leave_term))
+ msgq(sp, M_SYSERR, "tcsetattr");
+
+ /* Reset the signal state. */
+ if (sigaction(SIGINT, &exp->leave_act, NULL))
+ msgq(sp, M_SYSERR, "sigaction");
+
+ /* If the terminal was used, refresh the screen. */
+ if (fstat(STDIN_FILENO, &sb) || exp->leave_atime == 0 ||
+ exp->leave_atime != sb.st_atime || exp->leave_mtime != sb.st_mtime)
+ F_SET(sp, S_REFRESH);
+}
diff --git a/usr.bin/vi/nex/ex_version.c b/usr.bin/vi/ex/ex_version.c
index 230632d2de3c..648d323ed681 100644
--- a/usr.bin/vi/nex/ex_version.c
+++ b/usr.bin/vi/ex/ex_version.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_version.c 8.32 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)ex_version.c 8.41 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -50,10 +61,10 @@ ex_version(sp, ep, cmdp)
EXF *ep;
EXCMDARG *cmdp;
{
- static time_t then = 759365451;
+ static time_t then = 764543281;
(void)ex_printf(EXCOOKIE,
-"Version 1.03, %sThe CSRG, University of California, Berkeley.\n",
+"Version 1.11, %sThe CSRG, University of California, Berkeley.\n",
ctime(&then));
return (0);
}
diff --git a/usr.bin/vi/nex/ex_visual.c b/usr.bin/vi/ex/ex_visual.c
index d53152bde8e8..66ffb2ba0b7f 100644
--- a/usr.bin/vi/nex/ex_visual.c
+++ b/usr.bin/vi/ex/ex_visual.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_visual.c 8.7 (Berkeley) 11/29/93";
+static char sccsid[] = "@(#)ex_visual.c 8.8 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_write.c b/usr.bin/vi/ex/ex_write.c
index 5a51b6dff914..049e0bba1289 100644
--- a/usr.bin/vi/nex/ex_write.c
+++ b/usr.bin/vi/ex/ex_write.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,28 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_write.c 8.19 (Berkeley) 12/18/93";
+static char sccsid[] = "@(#)ex_write.c 8.27 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
@@ -185,7 +195,7 @@ exwr(sp, ep, cmdp, cmd)
switch (cmdp->argc) {
case 1:
/*
- * Nothing to expand, write the current file.
+ * Nothing to expand, write the current file.
* XXX
* Should never happen, already checked this case.
*/
@@ -222,8 +232,11 @@ ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
MARK *fm, *tm;
u_long *nlno, *nch;
{
- register u_long ccnt, fline, tline;
+ struct stat sb;
+ u_long ccnt; /* XXX: can't print off_t portably. */
+ recno_t fline, tline, lcnt;
size_t len;
+ int sv_errno;
char *p;
fline = fm->lno;
@@ -233,7 +246,6 @@ ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
*nch = 0;
*nlno = 0;
}
- ccnt = 0;
/*
* The vi filter code has multiple processes running simultaneously,
@@ -250,8 +262,14 @@ ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
*
* "Alex, I'll take vi trivia for $1000."
*/
- if (tline != 0)
- for (; fline <= tline; ++fline) {
+ ccnt = 0;
+ lcnt = 0;
+ if (tline != 0) {
+ for (; fline <= tline; ++fline, ++lcnt) {
+ if (F_ISSET(sp, S_INTERRUPTED)) {
+ msgq(sp, M_INFO, "Interrupted.");
+ break;
+ }
if ((p = file_gline(sp, ep, fline, &len)) == NULL)
break;
if (fwrite(p, 1, len, fp) != len) {
@@ -264,14 +282,25 @@ ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
break;
++ccnt;
}
- if (fclose(fp)) {
- if (!F_ISSET(ep, F_MULTILOCK))
- msgq(sp, M_SYSERR, name);
- return (1);
}
+
+ /* If it's a regular file, sync it so that NFS is forced to flush. */
+ if (!fstat(fileno(fp), &sb) &&
+ S_ISREG(sb.st_mode) && fsync(fileno(fp))) {
+ sv_errno = errno;
+ (void)fclose(fp);
+ errno = sv_errno;
+ goto err;
+ }
+ if (fclose(fp))
+ goto err;
if (nlno != NULL) {
*nch = ccnt;
- *nlno = tm->lno == 0 ? 0 : tm->lno - fm->lno + 1;
+ *nlno = lcnt;
}
return (0);
+
+err: if (!F_ISSET(ep, F_MULTILOCK))
+ msgq(sp, M_SYSERR, name);
+ return (1);
}
diff --git a/usr.bin/vi/nex/ex_yank.c b/usr.bin/vi/ex/ex_yank.c
index 0897034bf022..e37b8362fdde 100644
--- a/usr.bin/vi/nex/ex_yank.c
+++ b/usr.bin/vi/ex/ex_yank.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_yank.c 8.3 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)ex_yank.c 8.4 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/ex_z.c b/usr.bin/vi/ex/ex_z.c
index 2842a22855a5..45eef1423d4c 100644
--- a/usr.bin/vi/nex/ex_z.c
+++ b/usr.bin/vi/ex/ex_z.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ex_z.c 8.4 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)ex_z.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/nex/excmd.c b/usr.bin/vi/ex/excmd.c
index 27ebc39eebe8..b4016ccb37d1 100644
--- a/usr.bin/vi/nex/excmd.c
+++ b/usr.bin/vi/ex/excmd.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)excmd.c 8.36 (Berkeley) 1/22/94";
+static char sccsid[] = "@(#)excmd.c 8.41 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -48,7 +59,7 @@ static char sccsid[] = "@(#)excmd.c 8.36 (Berkeley) 1/22/94";
* e.g. "r" means "read", not "rewind", because "read" is listed before
* "rewind".
*
- * The syntax of the ex commands is unbelievably irregular, and a special
+ * The syntax of the ex commands is unbelievably irregular, and a special
* case from beginning to end. Each command has an associated "syntax
* script" which describes the "arguments" that are possible. The script
* syntax is as follows:
@@ -67,6 +78,11 @@ static char sccsid[] = "@(#)excmd.c 8.36 (Berkeley) 1/22/94";
* w[N#][or] -- word (a number or N, optional or required)
*/
EXCMDLIST const cmds[] = {
+/* C_SCROLL */
+ {"\004", ex_pr, E_ADDR2|E_NORC,
+ "",
+ "^D",
+ "scroll lines"},
/* C_BANG */
{"!", ex_bang, E_ADDR2_NONE|E_NORC,
"S",
@@ -119,7 +135,7 @@ EXCMDLIST const cmds[] = {
"specify an input abbreviation"},
/* C_ARGS */
{"args", ex_args, E_NOGLOBAL|E_NORC,
- "",
+ "",
"ar[gs]",
"display file argument list"},
/* C_BG */
@@ -154,12 +170,12 @@ EXCMDLIST const cmds[] = {
"delete lines from the file"},
/* C_DISPLAY */
{"display", ex_display, E_NOGLOBAL|E_NORC,
- "w1r",
+ "w1r",
"display b[uffers] | s[creens] | t[ags]",
"display buffers, screens or tags"},
/* C_DIGRAPH */
{"digraph", ex_digraph, E_NOGLOBAL|E_NOPERM|E_NORC,
- "",
+ "",
"digraph",
"specify digraphs (not implemented)"},
/* C_EDIT */
@@ -190,8 +206,8 @@ EXCMDLIST const cmds[] = {
/* C_GLOBAL */
{"global", ex_global, E_ADDR2_ALL|E_NOGLOBAL|E_NORC,
"!s",
- "[line [,line]] g[lobal][!] [;/]pattern[;/] [commands]",
- "execute a global command on lines matching a pattern"},
+ "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]",
+ "execute a global command on lines matching an RE"},
/* C_HELP */
{"help", ex_help, E_NOGLOBAL|E_NORC,
"",
@@ -250,7 +266,7 @@ EXCMDLIST const cmds[] = {
/* C_OPEN */
{"open", ex_open, E_ADDR1,
"s",
- "[line] o[pen] [/pattern/] [flags]",
+ "[line] o[pen] [/RE/] [flags]",
"enter \"open\" mode (not implemented)"},
/* C_PRINT */
{"print", ex_pr, E_ADDR2|E_F_PRCLEAR|E_NORC|E_SETLAST,
@@ -259,7 +275,7 @@ EXCMDLIST const cmds[] = {
"display lines"},
/* C_PRESERVE */
{"preserve", ex_preserve, E_NOGLOBAL|E_NORC,
- "",
+ "",
"pre[serve]",
"preserve an edit session for recovery"},
/* C_PREVIOUS */
@@ -285,7 +301,7 @@ EXCMDLIST const cmds[] = {
/* C_RESIZE */
{"resize", ex_resize, E_NOGLOBAL|E_NORC,
"c+",
- "resize [change]",
+ "resize [+-]rows",
"grow or shrink the current screen"},
/* C_REWIND */
{"rewind", ex_rew, E_NOGLOBAL|E_NORC,
@@ -295,8 +311,8 @@ EXCMDLIST const cmds[] = {
/* C_SUBSTITUTE */
{"substitute", ex_substitute, E_ADDR2|E_NORC,
"s",
-"[line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]]",
- "substitute on lines matching a pattern"},
+"[line [,line]] s[ubstitute] [[/;]RE[/;]/repl[/;] [cgr] [count] [#lp]]",
+ "substitute on lines matching an RE"},
/* C_SCRIPT */
{"script", ex_script, E_NOGLOBAL|E_NORC,
"!f1o",
@@ -309,12 +325,12 @@ EXCMDLIST const cmds[] = {
"set options (use \":set all\" to see all options)"},
/* C_SHELL */
{"shell", ex_shell, E_NOGLOBAL|E_NORC,
- "",
+ "",
"sh[ell]",
"suspend editing and run a shell"},
/* C_SOURCE */
{"source", ex_source, E_NOGLOBAL,
- "f1r",
+ "f1r",
"so[urce] file",
"read a file of ex commands"},
/* C_SPLIT */
@@ -334,57 +350,57 @@ EXCMDLIST const cmds[] = {
"suspend the edit session"},
/* C_T */
{"t", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC,
- "l1",
+ "l1",
"[line [,line]] t line [flags]",
"move lines elsewhere in the file"},
/* C_TAG */
{"tag", ex_tagpush, E_NOGLOBAL,
- "!w1o",
+ "!w1o",
"ta[g][!] [string]",
"edit the file containing the tag"},
/* C_TAGPOP */
{"tagpop", ex_tagpop, E_NOGLOBAL|E_NORC,
- "!w1o",
+ "!w1o",
"tagp[op][!] [number | file]",
"return to a previous tag"},
/* C_TAGTOP */
{"tagtop", ex_tagtop, E_NOGLOBAL|E_NORC,
- "!",
+ "!",
"tagt[op][!]",
"return to the first tag"},
/* C_UNDOL */
{"Undo", ex_undol, E_AUTOPRINT|E_NOGLOBAL|E_NORC,
- "",
+ "",
"U[ndo]",
"undo all the changes to this line"},
/* C_UNDO */
{"undo", ex_undo, E_AUTOPRINT|E_NOGLOBAL|E_NORC,
- "",
+ "",
"u[ndo]",
"undo the most recent change"},
/* C_UNABBREVIATE */
{"unabbreviate",ex_unabbr, E_NOGLOBAL,
- "w1r",
+ "w1r",
"una[bbrev] word",
"delete an abbreviation"},
/* C_UNMAP */
{"unmap", ex_unmap, E_NOGLOBAL,
- "!w1r",
+ "!w1r",
"unm[ap][!] word",
"delete an input or command map"},
/* C_VGLOBAL */
{"vglobal", ex_vglobal, E_ADDR2_ALL|E_NOGLOBAL|E_NORC,
- "s",
- "[line [,line]] v[global] [;/]pattern[;/] [commands]",
- "execute a global command on lines NOT matching a pattern"},
+ "s",
+ "[line [,line]] v[global] [;/]RE[;/] [commands]",
+ "execute a global command on lines NOT matching an RE"},
/* C_VERSION */
{"version", ex_version, E_NOGLOBAL|E_NORC,
- "",
+ "",
"version",
"display the program version information"},
/* C_VISUAL_EX */
{"visual", ex_visual, E_ADDR1|E_NOGLOBAL|E_NORC|E_ZERODEF,
- "2c11",
+ "2c11",
"[line] vi[sual] [-|.|+|^] [window_size] [flags]",
"enter visual (vi) mode from ex mode"},
/* C_VISUAL_VI */
diff --git a/usr.bin/vi/nex/excmd.h.stub b/usr.bin/vi/ex/excmd.h.stub
index ce2715c8b086..99c81a844503 100644
--- a/usr.bin/vi/nex/excmd.h.stub
+++ b/usr.bin/vi/ex/excmd.h.stub
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)excmd.h.stub 8.44 (Berkeley) 12/29/93
+ * @(#)excmd.h.stub 8.54 (Berkeley) 3/23/94
*/
/* Ex command structure. */
@@ -47,25 +47,27 @@ typedef struct _excmdlist {
#define E_AUTOPRINT 0x0000020 /* Command always sets autoprint. */
#define E_BUFFER 0x0000040 /* Buffer name supplied. */
#define E_COUNT 0x0000080 /* Count supplied. */
-#define E_FORCE 0x0000100 /* ! */
+#define E_COUNT_NEG 0x0000100 /* Count was signed negative. */
+#define E_COUNT_POS 0x0000200 /* Count was signed positive. */
+#define E_FORCE 0x0000400 /* ! */
-#define E_F_CARAT 0x0000200 /* ^ flag. */
-#define E_F_DASH 0x0000400 /* - flag. */
-#define E_F_DOT 0x0000800 /* . flag. */
-#define E_F_EQUAL 0x0001000 /* = flag. */
-#define E_F_HASH 0x0002000 /* # flag. */
-#define E_F_LIST 0x0004000 /* l flag. */
-#define E_F_PLUS 0x0008000 /* + flag. */
-#define E_F_PRINT 0x0010000 /* p flag. */
+#define E_F_CARAT 0x0000800 /* ^ flag. */
+#define E_F_DASH 0x0001000 /* - flag. */
+#define E_F_DOT 0x0002000 /* . flag. */
+#define E_F_EQUAL 0x0004000 /* = flag. */
+#define E_F_HASH 0x0008000 /* # flag. */
+#define E_F_LIST 0x0010000 /* l flag. */
+#define E_F_PLUS 0x0020000 /* + flag. */
+#define E_F_PRINT 0x0040000 /* p flag. */
-#define E_F_PRCLEAR 0x0020000 /* Clear the print (#, l, p) flags. */
-#define E_MODIFY 0x0040000 /* File name expansion modified arg. */
-#define E_NOGLOBAL 0x0080000 /* Not in a global. */
-#define E_NOPERM 0x0100000 /* Permission denied for now. */
-#define E_NORC 0x0200000 /* Not from a .exrc or EXINIT. */
-#define E_SETLAST 0x0400000 /* Reset last command. */
-#define E_ZERO 0x0800000 /* 0 is a legal addr1. */
-#define E_ZERODEF 0x1000000 /* 0 is default addr1 of empty files. */
+#define E_F_PRCLEAR 0x0080000 /* Clear the print (#, l, p) flags. */
+#define E_MODIFY 0x0100000 /* File name expansion modified arg. */
+#define E_NOGLOBAL 0x0200000 /* Not in a global. */
+#define E_NOPERM 0x0400000 /* Permission denied for now. */
+#define E_NORC 0x0800000 /* Not from a .exrc or EXINIT. */
+#define E_SETLAST 0x1000000 /* Reset last command. */
+#define E_ZERO 0x2000000 /* 0 is a legal addr1. */
+#define E_ZERODEF 0x4000000 /* 0 is default addr1 of empty files. */
u_long flags;
char *syntax; /* Syntax script. */
char *usage; /* Usage line. */
@@ -95,6 +97,13 @@ struct _range {
recno_t start, stop; /* Start/stop of the range. */
};
+/* Cd paths. */
+typedef struct _cdpath CDPATH;
+struct _cdpath {
+ TAILQ_ENTRY(_cdpath) q; /* Linked list of cd paths. */
+ char *path; /* Path. */
+};
+
/* Ex private, per-screen memory. */
typedef struct _ex_private {
ARGS **args; /* Arguments. */
@@ -111,10 +120,18 @@ typedef struct _ex_private {
CHAR_T *lastbcomm; /* Last bang command. */
- TAILQ_HEAD(_tagh, _tag) tagq; /* Tag stack. */
- TAILQ_HEAD(_tagfh, _tagf) tagfq;/* Tag stack. */
+ struct sigaction leave_act; /* ex_[sr]leave signal state. */
+ struct termios leave_term; /* ex_[sr]leave tty state. */
+ /* XXX: Should be struct timespec's, but time_t is more portable. */
+ time_t leave_atime; /* ex_[sr]leave old access time. */
+ time_t leave_mtime; /* ex_[sr]leave old mod time. */
+
+ TAILQ_HEAD(_tagh, _tag) tagq; /* Tag list (stack). */
+ TAILQ_HEAD(_tagfh, _tagf) tagfq;/* Tag file list. */
char *tlast; /* Saved last tag. */
+ TAILQ_HEAD(_cdh, _cdpath) cdq; /* Cd path list. */
+
/* Linked list of ranges. */
CIRCLEQ_HEAD(_rangeh, _range) rangeq;
recno_t range_lno; /* Range set line number. */
@@ -123,7 +140,7 @@ typedef struct _ex_private {
u_int flags;
} EX_PRIVATE;
#define EXP(sp) ((EX_PRIVATE *)((sp)->ex_private))
-
+
/* Macro to set up a command structure. */
#define SETCMDARG(s, cmd_id, naddr, lno1, lno2, force, arg) { \
ARGS *__ap[2], __a; \
@@ -148,78 +165,38 @@ typedef struct _ex_private {
}
/*
+ * !!!
+ * Historically, .exrc files and EXINIT variables could only use ^V
+ * as an escape character, neither ^Q or a user specified character
+ * worked. We enforce that here, just in case someone depends on it.
+ */
+#define IS_ESCAPE(sp, ch) \
+ (F_ISSET(sp, S_VLITONLY) ? \
+ (ch) == LITERAL_CH : term_key_val(sp, ch) == K_VLNEXT)
+
+/*
* :next, :prev, :rewind, :tag, :tagpush, :tagpop modifications check.
* If force is set, the autowrite is skipped.
*/
-#define MODIFY_CHECK(sp, ep, force) { \
+#define MODIFY_GOTO(sp, ep, force) { \
if (F_ISSET((ep), F_MODIFIED)) \
if (O_ISSET((sp), O_AUTOWRITE)) { \
if (!(force) && \
file_write((sp), (ep), NULL, NULL, NULL, \
FS_ALL | FS_POSSIBLE)) \
- return (1); \
+ goto modify_err; \
} else if (ep->refcnt <= 1 && !(force)) { \
msgq(sp, M_ERR, \
"Modified since last write; write or use ! to override."); \
- return (1); \
+ goto modify_err; \
} \
}
-
-/*
- * Macros to set and restore the terminal values, and note if the screen
- * was modified. Specific to their uses in ex/filter.c and ex/ex_shell.c.
- *
- * The old terminal values almost certainly turn on VINTR, VQUIT and VSUSP.
- * We don't want to interrupt the parent(s), so we ignore VINTR. VQUIT is
- * ignored by main() because nvi never wants to catch it. A VSUSP handler
- * have been installed by the screen code.
- */
-#define EX_LEAVE(sp, isig, act, oact, sb, osb, term) \
- if (F_ISSET(sp->gp, G_ISFROMTTY)) { \
- (act).sa_handler = SIG_IGN; \
- sigemptyset(&(act).sa_mask); \
- (act).sa_flags = 0; \
- if ((isig) = !sigaction(SIGINT, &(act), &(oact))) { \
- if (tcgetattr(STDIN_FILENO, &(term))) { \
- msgq(sp, M_SYSERR, "tcgetattr"); \
- rval = 1; \
- goto err; \
- } \
- if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, \
- &sp->gp->original_termios)) { \
- msgq(sp, M_SYSERR, "tcsetattr"); \
- rval = 1; \
- goto err; \
- } \
- } \
- /* \
- * The process may write to the terminal. Save the \
- * access time (read) and modification time (write) \
- * of the tty; if they have changed when we restore \
- * the modes, will have to refresh the screen. \
- */ \
- sb.st_mtime = 1; \
- osb.st_mtime = 0; \
- (void)fstat(STDIN_FILENO, &osb); \
- }
-
-#define EX_RETURN(sp, isig, act, oact, sb, osb, term) \
- if (F_ISSET(sp->gp, G_ISFROMTTY) && (isig)) { \
- if (sigaction(SIGINT, &(oact), NULL)) { \
- msgq(sp, M_SYSERR, "signal"); \
- rval = 1; \
- } \
- if (tcsetattr(STDIN_FILENO, \
- TCSANOW | TCSASOFT, &(term))) { \
- msgq(sp, M_SYSERR, "tcsetattr"); \
- rval = 1; \
- } \
- /* If the terminal was used, refresh the screen. */ \
- (void)fstat(STDIN_FILENO, &(sb)); \
- if ((sb).st_mtime != (osb).st_mtime || \
- (sb).st_atime != (osb).st_atime) \
- F_SET(sp, S_REFRESH); \
- }
+#define MODIFY_RET(sp, ep, force) { \
+ MODIFY_GOTO(sp, ep, force); \
+ if (0) { \
+modify_err: return (1); \
+ } \
+}
/*
* Filter actions:
@@ -244,6 +221,8 @@ int argv_free __P((SCR *));
int ex __P((SCR *, EXF *));
int ex_cfile __P((SCR *, EXF *, char *));
int ex_cmd __P((SCR *, EXF *, char *, size_t));
+int ex_cdalloc __P((SCR *, char *));
+int ex_cdfree __P((SCR *));
int ex_end __P((SCR *));
int ex_exec_proc __P((SCR *, char *, char *, char *));
int ex_gb __P((SCR *, EXF *, TEXTH *, int, u_int));
@@ -251,13 +230,16 @@ int ex_getline __P((SCR *, FILE *, size_t *));
int ex_icmd __P((SCR *, EXF *, char *, size_t));
int ex_init __P((SCR *, EXF *));
int ex_is_abbrev __P((char *, size_t));
+int ex_is_unmap __P((char *, size_t));
int ex_optchange __P((SCR *, int));
int ex_print __P((SCR *, EXF *, MARK *, MARK *, int));
int ex_readfp __P((SCR *, EXF *, char *, FILE *, MARK *, recno_t *, int));
void ex_refresh __P((SCR *, EXF *));
+void ex_rleave __P((SCR *));
int ex_screen_copy __P((SCR *, SCR *));
int ex_screen_end __P((SCR *));
int ex_sdisplay __P((SCR *, EXF *));
+int ex_sleave __P((SCR *));
int ex_suspend __P((SCR *));
int ex_tdisplay __P((SCR *, EXF *));
int ex_writefp __P((SCR *, EXF *,
@@ -268,73 +250,71 @@ int sscr_end __P((SCR *));
int sscr_exec __P((SCR *, EXF *, recno_t));
int sscr_input __P((SCR *));
-#define EXPROTO(type, name) \
- type name __P((SCR *, EXF *, EXCMDARG *))
-
-EXPROTO(int, ex_abbr);
-EXPROTO(int, ex_append);
-EXPROTO(int, ex_args);
-EXPROTO(int, ex_at);
-EXPROTO(int, ex_bang);
-EXPROTO(int, ex_bg);
-EXPROTO(int, ex_cd);
-EXPROTO(int, ex_change);
-EXPROTO(int, ex_color);
-EXPROTO(int, ex_copy);
-EXPROTO(int, ex_debug);
-EXPROTO(int, ex_delete);
-EXPROTO(int, ex_digraph);
-EXPROTO(int, ex_display);
-EXPROTO(int, ex_edit);
-EXPROTO(int, ex_equal);
-EXPROTO(int, ex_fg);
-EXPROTO(int, ex_file);
-EXPROTO(int, ex_global);
-EXPROTO(int, ex_help);
-EXPROTO(int, ex_insert);
-EXPROTO(int, ex_join);
-EXPROTO(int, ex_list);
-EXPROTO(int, ex_map);
-EXPROTO(int, ex_mark);
-EXPROTO(int, ex_mkexrc);
-EXPROTO(int, ex_move);
-EXPROTO(int, ex_next);
-EXPROTO(int, ex_number);
-EXPROTO(int, ex_open);
-EXPROTO(int, ex_pr);
-EXPROTO(int, ex_preserve);
-EXPROTO(int, ex_prev);
-EXPROTO(int, ex_put);
-EXPROTO(int, ex_quit);
-EXPROTO(int, ex_read);
-EXPROTO(int, ex_resize);
-EXPROTO(int, ex_rew);
-EXPROTO(int, ex_script);
-EXPROTO(int, ex_set);
-EXPROTO(int, ex_shell);
-EXPROTO(int, ex_shiftl);
-EXPROTO(int, ex_shiftr);
-EXPROTO(int, ex_source);
-EXPROTO(int, ex_split);
-EXPROTO(int, ex_stop);
-EXPROTO(int, ex_subagain);
-EXPROTO(int, ex_substitute);
-EXPROTO(int, ex_subtilde);
-EXPROTO(int, ex_tagpop);
-EXPROTO(int, ex_tagpush);
-EXPROTO(int, ex_tagtop);
-EXPROTO(int, ex_unabbr);
-EXPROTO(int, ex_undo);
-EXPROTO(int, ex_undol);
-EXPROTO(int, ex_unmap);
-EXPROTO(int, ex_usage);
-EXPROTO(int, ex_validate);
-EXPROTO(int, ex_version);
-EXPROTO(int, ex_vglobal);
-EXPROTO(int, ex_visual);
-EXPROTO(int, ex_viusage);
-EXPROTO(int, ex_wq);
-EXPROTO(int, ex_write);
-EXPROTO(int, ex_xit);
-EXPROTO(int, ex_yank);
-EXPROTO(int, ex_z);
+#define EXPROTO(name) int name __P((SCR *, EXF *, EXCMDARG *))
+EXPROTO(ex_abbr);
+EXPROTO(ex_append);
+EXPROTO(ex_args);
+EXPROTO(ex_at);
+EXPROTO(ex_bang);
+EXPROTO(ex_bg);
+EXPROTO(ex_cd);
+EXPROTO(ex_change);
+EXPROTO(ex_color);
+EXPROTO(ex_copy);
+EXPROTO(ex_debug);
+EXPROTO(ex_delete);
+EXPROTO(ex_digraph);
+EXPROTO(ex_display);
+EXPROTO(ex_edit);
+EXPROTO(ex_equal);
+EXPROTO(ex_fg);
+EXPROTO(ex_file);
+EXPROTO(ex_global);
+EXPROTO(ex_help);
+EXPROTO(ex_insert);
+EXPROTO(ex_join);
+EXPROTO(ex_list);
+EXPROTO(ex_map);
+EXPROTO(ex_mark);
+EXPROTO(ex_mkexrc);
+EXPROTO(ex_move);
+EXPROTO(ex_next);
+EXPROTO(ex_number);
+EXPROTO(ex_open);
+EXPROTO(ex_pr);
+EXPROTO(ex_preserve);
+EXPROTO(ex_prev);
+EXPROTO(ex_put);
+EXPROTO(ex_quit);
+EXPROTO(ex_read);
+EXPROTO(ex_resize);
+EXPROTO(ex_rew);
+EXPROTO(ex_script);
+EXPROTO(ex_set);
+EXPROTO(ex_shell);
+EXPROTO(ex_shiftl);
+EXPROTO(ex_shiftr);
+EXPROTO(ex_source);
+EXPROTO(ex_split);
+EXPROTO(ex_stop);
+EXPROTO(ex_subagain);
+EXPROTO(ex_substitute);
+EXPROTO(ex_subtilde);
+EXPROTO(ex_tagpop);
+EXPROTO(ex_tagpush);
+EXPROTO(ex_tagtop);
+EXPROTO(ex_unabbr);
+EXPROTO(ex_undo);
+EXPROTO(ex_undol);
+EXPROTO(ex_unmap);
+EXPROTO(ex_usage);
+EXPROTO(ex_validate);
+EXPROTO(ex_version);
+EXPROTO(ex_vglobal);
+EXPROTO(ex_visual);
+EXPROTO(ex_viusage);
+EXPROTO(ex_wq);
+EXPROTO(ex_write);
+EXPROTO(ex_xit);
+EXPROTO(ex_yank);
+EXPROTO(ex_z);
diff --git a/usr.bin/vi/nex/filter.c b/usr.bin/vi/ex/filter.c
index d50e1e665d8d..16d879ea686d 100644
--- a/usr.bin/vi/nex/filter.c
+++ b/usr.bin/vi/ex/filter.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,21 +32,30 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)filter.c 8.26 (Berkeley) 1/2/94";
+static char sccsid[] = "@(#)filter.c 8.31 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/types.h>
-#include <sys/stat.h>
+#include <queue.h>
+#include <sys/time.h>
#include <sys/wait.h>
+#include <bitstring.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
#include "excmd.h"
-#include "pathnames.h"
static int filter_ldisplay __P((SCR *, FILE *));
@@ -64,13 +73,10 @@ filtercmd(sp, ep, fm, tm, rp, cmd, ftype)
char *cmd;
enum filtertype ftype;
{
- struct sigaction act, oact;
- struct stat osb, sb;
- struct termios term;
FILE *ifp, *ofp; /* GCC: can't be uninitialized. */
pid_t parent_writer_pid, utility_pid;
recno_t lno, nread;
- int input[2], isig, output[2], rval;
+ int input[2], output[2], rval, teardown;
char *name;
/* Set return cursor position; guard against a line number of zero. */
@@ -94,6 +100,7 @@ filtercmd(sp, ep, fm, tm, rp, cmd, ftype)
* input. Redirect its input from /dev/null. Otherwise open
* up utility input pipe.
*/
+ teardown = 0;
ifp = ofp = NULL;
input[0] = input[1] = output[0] = output[1] = -1;
if (ftype == FILTER_READ) {
@@ -127,7 +134,7 @@ filtercmd(sp, ep, fm, tm, rp, cmd, ftype)
* Save ex/vi terminal settings, and restore the original ones.
* Restoration so that users can do things like ":r! cat /dev/tty".
*/
- EX_LEAVE(sp, isig, act, oact, sb, osb, term);
+ teardown = !ex_sleave(sp);
/* Fork off the utility process. */
switch (utility_pid = vfork()) {
@@ -306,8 +313,8 @@ err: if (input[0] != -1)
uwait: rval |= proc_wait(sp, (long)utility_pid, cmd, 0);
/* Restore ex/vi terminal settings. */
-ret: EX_RETURN(sp, isig, act, oact, sb, osb, term);
-
+ret: if (teardown)
+ ex_rleave(sp);
return (rval);
}
@@ -328,7 +335,7 @@ proc_wait(sp, pid, cmd, okpipe)
const char *cmd;
int okpipe;
{
- extern const char *const sys_siglist[];
+ extern char *sys_siglist[];
size_t len;
int pstat;
diff --git a/usr.bin/vi/nex/script.h b/usr.bin/vi/ex/script.h
index a04f14459165..a04f14459165 100644
--- a/usr.bin/vi/nex/script.h
+++ b/usr.bin/vi/ex/script.h
diff --git a/usr.bin/vi/nex/tag.h b/usr.bin/vi/ex/tag.h
index f75d9b3fd466..f75d9b3fd466 100644
--- a/usr.bin/vi/nex/tag.h
+++ b/usr.bin/vi/ex/tag.h
diff --git a/usr.bin/vi/exf.c b/usr.bin/vi/exf.c
index 0f9ac4ba0e4b..7d0c104d4a15 100644
--- a/usr.bin/vi/exf.c
+++ b/usr.bin/vi/exf.c
@@ -32,11 +32,13 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)exf.c 8.65 (Berkeley) 1/11/94";
+static char sccsid[] = "@(#)exf.c 8.71 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/param.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
/*
* We include <sys/file.h>, because the flock(2) #defines were
@@ -45,15 +47,23 @@ static char sccsid[] = "@(#)exf.c 8.65 (Berkeley) 1/11/94";
*/
#include <sys/file.h>
+#include <bitstring.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
#include "excmd.h"
-#include "pathnames.h"
/*
* file_add --
@@ -262,7 +272,7 @@ file_init(sp, frp, rcv_name, force)
msgq(sp, M_ERR,
"Warning: %s is not a regular file.", oname);
}
-
+
/* Set up recovery. */
memset(&oinfo, 0, sizeof(RECNOINFO));
oinfo.bval = '\n'; /* Always set. */
@@ -524,7 +534,7 @@ file_write(sp, ep, fm, tm, name, flags)
FREF *frp;
MARK from, to;
u_long nlno, nch;
- int fd, oflags, rval;
+ int btear, fd, itear, oflags, rval;
char *msg;
/*
@@ -655,17 +665,22 @@ exists: if (LF_ISSET(FS_POSSIBLE))
tm = &to;
}
- /* Write the file. */
+ /* Write the file, allowing interrupts. */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Writing...");
+ itear = !intr_init(sp);
rval = ex_writefp(sp, ep, name, fp, fm, tm, &nlno, &nch);
+ if (btear)
+ busy_off(sp);
+ if (itear)
+ intr_end(sp);
/*
* Save the new last modification time -- even if the write fails
- * we re-init the time if we wrote anything. That way the user can
- * clean up the disk and rewrite without having to force it.
+ * we re-init the time. That way the user can clean up the disk
+ * and rewrite without having to force it.
*/
- if (nlno || nch)
- frp->mtime = stat(name, &sb) ? 0 : sb.st_mtime;
-
+ frp->mtime = stat(name, &sb) ? 0 : sb.st_mtime;
+
/* If the write failed, complain loudly. */
if (rval) {
if (!LF_ISSET(FS_APPEND))
diff --git a/usr.bin/vi/exf.h b/usr.bin/vi/exf.h
index 5049f3ea2418..b9874dae2dc5 100644
--- a/usr.bin/vi/exf.h
+++ b/usr.bin/vi/exf.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)exf.h 8.20 (Berkeley) 12/28/93
+ * @(#)exf.h 8.23 (Berkeley) 3/23/94
*/
/* Undo direction. */
/*
@@ -55,7 +55,7 @@ struct _exf {
MARK l_cursor; /* Log cursor position. */
enum direction lundo; /* Last undo direction. */
- LIST_HEAD(_markh, _mark) marks; /* Linked list of file MARK's. */
+ LIST_HEAD(_markh, _lmark) marks;/* Linked list of file MARK's. */
/*
* Paths for the recovery mail file and the vi recovery file and
@@ -74,6 +74,7 @@ struct _exf {
char *rcv_path; /* Recover file name. */
char *rcv_mpath; /* Recover mail file name. */
int rcv_fd; /* Locked mail file descriptor. */
+ struct timeval rcv_tod; /* ITIMER_REAL: recovery time-of-day. */
#define F_FIRSTMODIFY 0x001 /* File not yet modified. */
#define F_MODIFIED 0x002 /* File is currently dirty. */
diff --git a/usr.bin/vi/gs.h b/usr.bin/vi/gs.h
index 86af7299b3c7..a10f16f3da5b 100644
--- a/usr.bin/vi/gs.h
+++ b/usr.bin/vi/gs.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)gs.h 8.26 (Berkeley) 1/9/94
+ * @(#)gs.h 8.29 (Berkeley) 3/16/94
*/
struct _gs {
CIRCLEQ_HEAD(_dqh, _scr) dq; /* Displayed screens. */
CIRCLEQ_HEAD(_hqh, _scr) hq; /* Hidden screens. */
-
+
mode_t origmode; /* Original terminal mode. */
struct termios
original_termios; /* Original terminal values. */
@@ -75,16 +75,18 @@ struct _gs {
#define G_BELLSCHED 0x00002 /* Bell scheduled. */
#define G_CURSES_INIT 0x00004 /* Curses: initialized. */
#define G_CURSES_S5CB 0x00008 /* Curses: s5_curses_botch set. */
-#define G_ISFROMTTY 0x00010 /* Reading from a tty. */
-#define G_RECOVER_SET 0x00020 /* Recover system initialized. */
-#define G_SETMODE 0x00040 /* Tty mode changed. */
-#define G_SIGALRM 0x00080 /* SIGALRM arrived. */
-#define G_SIGHUP 0x00100 /* SIGHUP arrived. */
-#define G_SIGTERM 0x00200 /* SIGTERM arrived. */
-#define G_SIGWINCH 0x00400 /* SIGWINCH arrived. */
-#define G_SLEEPING 0x00800 /* Asleep (die on signal). */
-#define G_SNAPSHOT 0x01000 /* Always snapshot files. */
-#define G_TMP_INUSE 0x02000 /* Temporary buffer in use. */
+#define G_RECOVER_SET 0x00010 /* Recover system initialized. */
+#define G_SETMODE 0x00020 /* Tty mode changed. */
+#define G_SIGALRM 0x00040 /* SIGALRM arrived. */
+#define G_SIGHUP 0x00080 /* SIGHUP arrived. */
+#define G_SIGTERM 0x00100 /* SIGTERM arrived. */
+#define G_SIGWINCH 0x00200 /* SIGWINCH arrived. */
+#define G_SLEEPING 0x00400 /* Asleep (die on signal). */
+#define G_SNAPSHOT 0x00800 /* Always snapshot files. */
+#define G_STDIN_TTY 0x01000 /* Standard input is a tty. */
+#define G_TERMIOS_SET 0x02000 /* Termios structure is valid. */
+#define G_TMP_INUSE 0x04000 /* Temporary buffer in use. */
+
u_int flags;
};
diff --git a/usr.bin/vi/include/bitstring.h b/usr.bin/vi/include/bitstring.h
deleted file mode 100644
index 88437e7fb9f7..000000000000
--- a/usr.bin/vi/include/bitstring.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Paul Vixie.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)bitstring.h 8.1 (Berkeley) 7/19/93
- */
-
-#ifndef _BITSTRING_H_
-#define _BITSTRING_H_
-
-typedef unsigned char bitstr_t;
-
-/* internal macros */
- /* byte of the bitstring bit is in */
-#define _bit_byte(bit) \
- ((bit) >> 3)
-
- /* mask for the bit within its byte */
-#define _bit_mask(bit) \
- (1 << ((bit)&0x7))
-
-/* external macros */
- /* bytes in a bitstring of nbits bits */
-#define bitstr_size(nbits) \
- ((((nbits) - 1) >> 3) + 1)
-
- /* allocate a bitstring */
-#define bit_alloc(nbits) \
- (bitstr_t *)calloc(1, \
- (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t))
-
- /* allocate a bitstring on the stack */
-#define bit_decl(name, nbits) \
- (name)[bitstr_size(nbits)]
-
- /* is bit N of bitstring name set? */
-#define bit_test(name, bit) \
- ((name)[_bit_byte(bit)] & _bit_mask(bit))
-
- /* set bit N of bitstring name */
-#define bit_set(name, bit) \
- (name)[_bit_byte(bit)] |= _bit_mask(bit)
-
- /* clear bit N of bitstring name */
-#define bit_clear(name, bit) \
- (name)[_bit_byte(bit)] &= ~_bit_mask(bit)
-
- /* clear bits start ... stop in bitstring */
-#define bit_nclear(name, start, stop) { \
- register bitstr_t *_name = name; \
- register int _start = start, _stop = stop; \
- register int _startbyte = _bit_byte(_start); \
- register int _stopbyte = _bit_byte(_stop); \
- if (_startbyte == _stopbyte) { \
- _name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \
- (0xff << ((_stop&0x7) + 1))); \
- } else { \
- _name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \
- while (++_startbyte < _stopbyte) \
- _name[_startbyte] = 0; \
- _name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \
- } \
-}
-
- /* set bits start ... stop in bitstring */
-#define bit_nset(name, start, stop) { \
- register bitstr_t *_name = name; \
- register int _start = start, _stop = stop; \
- register int _startbyte = _bit_byte(_start); \
- register int _stopbyte = _bit_byte(_stop); \
- if (_startbyte == _stopbyte) { \
- _name[_startbyte] |= ((0xff << (_start&0x7)) & \
- (0xff >> (7 - (_stop&0x7)))); \
- } else { \
- _name[_startbyte] |= 0xff << ((_start)&0x7); \
- while (++_startbyte < _stopbyte) \
- _name[_startbyte] = 0xff; \
- _name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \
- } \
-}
-
- /* find first bit clear in name */
-#define bit_ffc(name, nbits, value) { \
- register bitstr_t *_name = name; \
- register int _byte, _nbits = nbits; \
- register int _stopbyte = _bit_byte(_nbits), _value = -1; \
- for (_byte = 0; _byte <= _stopbyte; ++_byte) \
- if (_name[_byte] != 0xff) { \
- _value = _byte << 3; \
- for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
- ++_value, _stopbyte >>= 1); \
- break; \
- } \
- *(value) = _value; \
-}
-
- /* find first bit set in name */
-#define bit_ffs(name, nbits, value) { \
- register bitstr_t *_name = name; \
- register int _byte, _nbits = nbits; \
- register int _stopbyte = _bit_byte(_nbits), _value = -1; \
- for (_byte = 0; _byte <= _stopbyte; ++_byte) \
- if (_name[_byte]) { \
- _value = _byte << 3; \
- for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
- ++_value, _stopbyte >>= 1); \
- break; \
- } \
- *(value) = _value; \
-}
-
-#endif /* !_BITSTRING_H_ */
diff --git a/usr.bin/vi/include/cdefs.h b/usr.bin/vi/include/cdefs.h
deleted file mode 100644
index c4157bcd1a8d..000000000000
--- a/usr.bin/vi/include/cdefs.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)cdefs.h 8.2 (Berkeley) 10/4/93
- */
-
-#ifndef _CDEFS_H_
-#define _CDEFS_H_
-
-#if defined(__cplusplus)
-#define __BEGIN_DECLS extern "C" {
-#define __END_DECLS };
-#else
-#define __BEGIN_DECLS
-#define __END_DECLS
-#endif
-
-/*
- * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
- * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
- * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
- * in between its arguments. __CONCAT can also concatenate double-quoted
- * strings produced by the __STRING macro, but this only works with ANSI C.
- */
-#if defined(__STDC__) || defined(__cplusplus)
-#define __P(protos) protos /* full-blown ANSI C */
-#define __CONCAT(x,y) x ## y
-#define __STRING(x) #x
-
-#if !defined(__GNUC__) && !defined(__cplusplus)
-#define inline
-#endif
-
-#else /* !(__STDC__ || __cplusplus) */
-#define __P(protos) () /* traditional C preprocessor */
-#define __CONCAT(x,y) x/**/y
-#define __STRING(x) "x"
-
-#ifdef __GNUC__
-#define const __const /* GCC: ANSI C with -traditional */
-#define inline __inline
-#define signed __signed
-#define volatile __volatile
-
-#else /* !__GNUC__ */
-#define const /* delete ANSI C keywords */
-#define inline
-#define signed
-#define volatile
-#endif /* !__GNUC__ */
-#endif /* !(__STDC__ || __cplusplus) */
-
-/*
- * GCC has extensions for declaring functions as `pure' (always returns
- * the same value given the same inputs, i.e., has no external state and
- * no side effects) and `dead' (nonreturning). These mainly affect
- * optimization and warnings. Unfortunately, GCC complains if these are
- * used under strict ANSI mode (`gcc -ansi -pedantic'), hence we need to
- * define them only if compiling without this.
- */
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-#define __dead __volatile
-#define __pure __const
-#else
-#define __dead
-#define __pure
-#endif
-
-#endif /* !_CDEFS_H_ */
diff --git a/usr.bin/vi/include/compat.h b/usr.bin/vi/include/compat.h
deleted file mode 100644
index 10406993014b..000000000000
--- a/usr.bin/vi/include/compat.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)compat.h 8.10 (Berkeley) 1/11/94
- */
-
-#ifndef _COMPAT_H_
-#define _COMPAT_H_
-
-#include <sys/types.h>
-#include <machine/limits.h>
-#include <termios.h>
-#include <errno.h>
-
-/*
- * If your system doesn't typedef u_long, u_short, or u_char, change
- * the 0 to a 1.
- */
-#if 0
-typedef unsigned char u_char; /* 4.[34]BSD names. */
-typedef unsigned int u_int;
-typedef unsigned long u_long;
-typedef unsigned short u_short;
-#endif
-
-/* If your system doesn't typedef size_t, change the 0 to a 1. */
-#if 0
-typedef unsigned int size_t; /* 4.[34]BSD names. */
-#endif
-
-/*
- * If your system doesn't have the POSIX type for a signal mask,
- * change the 0 to a 1.
- */
-#if 0 /* POSIX 1003.1 signal mask type. */
-typedef unsigned int sigset_t;
-#endif
-
-/*
- * If your system's vsprintf returns a char *, not an int,
- * change the 0 to a 1.
- */
-#if 0
-#define VSPRINTF_CHARSTAR
-#endif
-
-/*
- * If you don't have POSIX 1003.1 signals, the signal code surrounding the
- * temporary file creation is intended to block all of the possible signals
- * long enough to create the file and unlink it. All of this stuff is
- * intended to use old-style BSD calls to fake POSIX 1003.1 calls.
- */
-#ifdef NO_POSIX_SIGNALS
-#define sigemptyset(set) (*(set) = 0)
-#define sigfillset(set) (*(set) = ~(sigset_t)0, 0)
-#define sigaddset(set,signo) (*(set) |= sigmask(signo), 0)
-#define sigdelset(set,signo) (*(set) &= ~sigmask(signo), 0)
-#define sigismember(set,signo) ((*(set) & sigmask(signo)) != 0)
-
-#define SIG_BLOCK 1
-#define SIG_UNBLOCK 2
-#define SIG_SETMASK 3
-
-static int __sigtemp; /* For the use of sigprocmask */
-
-/* Repeated test of oset != NULL is to avoid "*0". */
-#define sigprocmask(how, set, oset) \
- ((__sigtemp = \
- (((how) == SIG_BLOCK) ? \
- sigblock(0) | *(set) : \
- (((how) == SIG_UNBLOCK) ? \
- sigblock(0) & ~(*(set)) : \
- ((how) == SIG_SETMASK ? \
- *(set) : sigblock(0))))), \
- ((oset) ? (*(oset ? oset : set) = sigsetmask(__sigtemp)) : \
- sigsetmask(__sigtemp)), 0)
-#endif
-
-/*
- * If realloc(3) of a NULL pointer on your system isn't the same as
- * a malloc(3) call, change the 0 to a 1, and add realloc.o to the
- * MISC line in your Makefile.
- */
-#if 0
-#define realloc __fix_realloc
-#endif
-
-/*
- * If your system doesn't have an include file with the appropriate
- * byte order set, make sure you specify the correct one.
- */
-#ifndef BYTE_ORDER
-#define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
-#define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
-#define BYTE_ORDER LITTLE_ENDIAN /* Set for your system. */
-#endif
-
-#if defined(SYSV) || defined(SYSTEM5)
-#define index(a, b) strchr(a, b)
-#define rindex(a, b) strrchr(a, b)
-#define bzero(a, b) memset(a, 0, b)
-#define bcmp(a, b, n) memcmp(a, b, n)
-#define bcopy(a, b, n) memmove(b, a, n)
-#endif
-
-#if defined(BSD) || defined(BSD4_3)
-#define strchr(a, b) index(a, b)
-#define strrchr(a, b) rindex(a, b)
-#define memcmp(a, b, n) bcmp(a, b, n)
-#define memmove(a, b, n) bcopy(b, a, n)
-#endif
-
-/*
- * 32-bit machine. The db routines are theoretically independent of
- * the size of u_shorts and u_longs, but I don't know that anyone has
- * ever actually tried it. At a minimum, change the following #define's
- * if you are trying to compile on a different type of system.
- */
-#ifndef USHRT_MAX
-#define USHRT_MAX 0xFFFF
-#define ULONG_MAX 0xFFFFFFFF
-#endif
-
-#ifndef O_ACCMODE /* POSIX 1003.1 access mode mask. */
-#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
-#endif
-
-#ifndef _POSIX2_RE_DUP_MAX /* POSIX 1003.2 RE limit. */
-#define _POSIX2_RE_DUP_MAX 255
-#endif
-
-/*
- * If you can't provide lock values in the open(2) call. Note, this
- * allows races to happen.
- */
-#ifndef O_EXLOCK /* 4.4BSD extension. */
-#define O_EXLOCK 0
-#endif
-
-#ifndef O_SHLOCK /* 4.4BSD extension. */
-#define O_SHLOCK 0
-#endif
-
-#ifndef EFTYPE
-#define EFTYPE EINVAL /* POSIX 1003.1 format errno. */
-#endif
-
-#ifndef WCOREDUMP /* 4.4BSD extension */
-#define WCOREDUMP(a) 0
-#endif
-
-#ifndef STDERR_FILENO
-#define STDIN_FILENO 0 /* ANSI C #defines */
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
-#endif
-
-#ifndef SEEK_END
-#define SEEK_SET 0 /* POSIX 1003.1 seek values */
-#define SEEK_CUR 1
-#define SEEK_END 2
-#endif
-
-#ifndef _POSIX_VDISABLE /* POSIX 1003.1 disabling char. */
-#define _POSIX_VDISABLE 0 /* Some systems used 0. */
-#endif
-
-#ifndef S_ISLNK /* BSD POSIX 1003.1 extensions */
-#define S_ISLNK(m) ((m & 0170000) == 0120000)
-#define S_ISSOCK(m) ((m & 0170000) == 0140000)
-#endif
-
-#ifndef TCSASOFT /* 4.4BSD extension. */
-#define TCSASOFT 0
-#endif
-
-#ifndef _POSIX2_RE_DUP_MAX /* POSIX 1003.2 values. */
-#define _POSIX2_RE_DUP_MAX 255
-#endif
-
-#ifndef NULL /* ANSI C #defines NULL everywhere. */
-#define NULL 0
-#endif
-
-#ifndef MAX /* Usually found in <sys/param.h>. */
-#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a))
-#endif
-#ifndef MIN /* Usually found in <sys/param.h>. */
-#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
-#endif
-
-/* Default file permissions. */
-#ifndef DEFFILEMODE /* 4.4BSD extension. */
-#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
-#endif
-
-#ifndef S_ISDIR /* POSIX 1003.1 file type tests. */
-#define S_ISDIR(m) ((m & 0170000) == 0040000) /* directory */
-#define S_ISCHR(m) ((m & 0170000) == 0020000) /* char special */
-#define S_ISBLK(m) ((m & 0170000) == 0060000) /* block special */
-#define S_ISREG(m) ((m & 0170000) == 0100000) /* regular file */
-#define S_ISFIFO(m) ((m & 0170000) == 0010000) /* fifo */
-#define S_ISLNK(m) ((m & 0170000) == 0120000) /* symbolic link */
-#define S_ISSOCK(m) ((m & 0170000) == 0140000) /* socket */
-#endif
-
-/* The type of a va_list. */
-#ifndef _BSD_VA_LIST_ /* 4.4BSD #define. */
-#define _BSD_VA_LIST_ char *
-#endif
-
-#endif /* !_COMPAT_H_ */
diff --git a/usr.bin/vi/include/err.h b/usr.bin/vi/include/err.h
deleted file mode 100644
index b6d7e5f94b87..000000000000
--- a/usr.bin/vi/include/err.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <sys/cdefs.h>
-
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void err __P((int, const char *, ...));
-void verr __P((int, const char *, va_list));
-void errx __P((int, const char *, ...));
-void verrx __P((int, const char *, va_list));
-void warn __P((const char *, ...));
-void vwarn __P((const char *, va_list));
-void warnx __P((const char *, ...));
-void vwarnx __P((const char *, va_list));
diff --git a/usr.bin/vi/include/file.h b/usr.bin/vi/include/file.h
deleted file mode 100644
index 680797fa6a52..000000000000
--- a/usr.bin/vi/include/file.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * If we're doing flock(2) emulation, we need to get the LOCK_* #defines.
- * This stub <sys/file.h> includes the real one, and, if they're not in
- * it, we #define them here.
- */
-
-#include </usr/include/sys/file.h>
-
-#ifndef LOCK_SH
-/* lock operations for flock(2) */
-#define LOCK_SH 0x01 /* shared file lock */
-#define LOCK_EX 0x02 /* exclusive file lock */
-#define LOCK_NB 0x04 /* don't block when locking */
-#define LOCK_UN 0x08 /* unlock file */
-#endif
diff --git a/usr.bin/vi/include/glob.h b/usr.bin/vi/include/glob.h
deleted file mode 100644
index b679f6aef62a..000000000000
--- a/usr.bin/vi/include/glob.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Guido van Rossum.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)glob.h 8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _GLOB_H_
-#define _GLOB_H_
-
-#include <sys/cdefs.h>
-
-#include "compat.h"
-
-struct stat;
-typedef struct {
- int gl_pathc; /* Count of total paths so far. */
- int gl_matchc; /* Count of paths matching pattern. */
- int gl_offs; /* Reserved at beginning of gl_pathv. */
- int gl_flags; /* Copy of flags parameter to glob. */
- char **gl_pathv; /* List of paths matching pattern. */
- /* Copy of errfunc parameter to glob. */
- int (*gl_errfunc) __P((const char *, int));
-
- /*
- * Alternate filesystem access methods for glob; replacement
- * versions of closedir(3), readdir(3), opendir(3), stat(2)
- * and lstat(2).
- */
- void (*gl_closedir) __P((void *));
- struct dirent *(*gl_readdir) __P((void *));
- void *(*gl_opendir) __P((const char *));
- int (*gl_lstat) __P((const char *, struct stat *));
- int (*gl_stat) __P((const char *, struct stat *));
-} glob_t;
-
-#define GLOB_APPEND 0x0001 /* Append to output from previous call. */
-#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */
-#define GLOB_ERR 0x0004 /* Return on error. */
-#define GLOB_MARK 0x0008 /* Append / to matching directories. */
-#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */
-#define GLOB_NOSORT 0x0020 /* Don't sort. */
-
-#ifndef _POSIX_SOURCE
-#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */
-#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */
-#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
-#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */
-#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */
-#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */
-#endif
-
-#define GLOB_NOSPACE (-1) /* Malloc call failed. */
-#define GLOB_ABEND (-2) /* Unignored error. */
-
-__BEGIN_DECLS
-int glob __P((const char *, int, int (*)(const char *, int), glob_t *));
-void globfree __P((glob_t *));
-__END_DECLS
-
-#endif /* !_GLOB_H_ */
diff --git a/usr.bin/vi/include/mpool.h b/usr.bin/vi/include/mpool.h
deleted file mode 100644
index 910e0782aa9d..000000000000
--- a/usr.bin/vi/include/mpool.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)mpool.h 8.1 (Berkeley) 6/2/93
- */
-
-/*
- * The memory pool scheme is a simple one. Each in memory page is referenced
- * by a bucket which is threaded in three ways. All active pages are threaded
- * on a hash chain (hashed by the page number) and an lru chain. Inactive
- * pages are threaded on a free chain. Each reference to a memory pool is
- * handed an MPOOL which is the opaque cookie passed to all of the memory
- * routines.
- */
-#define HASHSIZE 128
-#define HASHKEY(pgno) ((pgno - 1) % HASHSIZE)
-
-/* The BKT structures are the elements of the lists. */
-typedef struct BKT {
- struct BKT *hnext; /* next hash bucket */
- struct BKT *hprev; /* previous hash bucket */
- struct BKT *cnext; /* next free/lru bucket */
- struct BKT *cprev; /* previous free/lru bucket */
- void *page; /* page */
- pgno_t pgno; /* page number */
-
-#define MPOOL_DIRTY 0x01 /* page needs to be written */
-#define MPOOL_PINNED 0x02 /* page is pinned into memory */
- unsigned long flags; /* flags */
-} BKT;
-
-/* The BKTHDR structures are the heads of the lists. */
-typedef struct BKTHDR {
- struct BKT *hnext; /* next hash bucket */
- struct BKT *hprev; /* previous hash bucket */
- struct BKT *cnext; /* next free/lru bucket */
- struct BKT *cprev; /* previous free/lru bucket */
-} BKTHDR;
-
-typedef struct MPOOL {
- BKTHDR free; /* The free list. */
- BKTHDR lru; /* The LRU list. */
- BKTHDR hashtable[HASHSIZE]; /* Hashed list by page number. */
- pgno_t curcache; /* Current number of cached pages. */
- pgno_t maxcache; /* Max number of cached pages. */
- pgno_t npages; /* Number of pages in the file. */
- u_long pagesize; /* File page size. */
- int fd; /* File descriptor. */
- /* Page in conversion routine. */
- void (*pgin) __P((void *, pgno_t, void *));
- /* Page out conversion routine. */
- void (*pgout) __P((void *, pgno_t, void *));
- void *pgcookie; /* Cookie for page in/out routines. */
-#ifdef STATISTICS
- unsigned long cachehit;
- unsigned long cachemiss;
- unsigned long pagealloc;
- unsigned long pageflush;
- unsigned long pageget;
- unsigned long pagenew;
- unsigned long pageput;
- unsigned long pageread;
- unsigned long pagewrite;
-#endif
-} MPOOL;
-
-#ifdef __MPOOLINTERFACE_PRIVATE
-/* Macros to insert/delete into/from hash chain. */
-#define rmhash(bp) { \
- (bp)->hprev->hnext = (bp)->hnext; \
- (bp)->hnext->hprev = (bp)->hprev; \
-}
-#define inshash(bp, pg) { \
- hp = &mp->hashtable[HASHKEY(pg)]; \
- (bp)->hnext = hp->hnext; \
- (bp)->hprev = (struct BKT *)hp; \
- hp->hnext->hprev = (bp); \
- hp->hnext = (bp); \
-}
-
-/* Macros to insert/delete into/from lru and free chains. */
-#define rmchain(bp) { \
- (bp)->cprev->cnext = (bp)->cnext; \
- (bp)->cnext->cprev = (bp)->cprev; \
-}
-#define inschain(bp, dp) { \
- (bp)->cnext = (dp)->cnext; \
- (bp)->cprev = (struct BKT *)(dp); \
- (dp)->cnext->cprev = (bp); \
- (dp)->cnext = (bp); \
-}
-#endif
-
-__BEGIN_DECLS
-MPOOL *mpool_open __P((DBT *, int, pgno_t, pgno_t));
-void mpool_filter __P((MPOOL *, void (*)(void *, pgno_t, void *),
- void (*)(void *, pgno_t, void *), void *));
-void *mpool_new __P((MPOOL *, pgno_t *));
-void *mpool_get __P((MPOOL *, pgno_t, u_int));
-int mpool_put __P((MPOOL *, void *, u_int));
-int mpool_sync __P((MPOOL *));
-int mpool_close __P((MPOOL *));
-#ifdef STATISTICS
-void mpool_stat __P((MPOOL *));
-#endif
-__END_DECLS
diff --git a/usr.bin/vi/include/ndbm.h b/usr.bin/vi/include/ndbm.h
deleted file mode 100644
index a545bca1326e..000000000000
--- a/usr.bin/vi/include/ndbm.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Margo Seltzer.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)ndbm.h 8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _NDBM_H_
-#define _NDBM_H_
-
-#include <db.h>
-
-/* Map dbm interface onto db(3). */
-#define DBM_RDONLY O_RDONLY
-
-/* Flags to dbm_store(). */
-#define DBM_INSERT 0
-#define DBM_REPLACE 1
-
-/*
- * The db(3) support for ndbm(3) always appends this suffix to the
- * file name to avoid overwriting the user's original database.
- */
-#define DBM_SUFFIX ".db"
-
-typedef struct {
- char *dptr;
- int dsize;
-} datum;
-
-typedef DB DBM;
-#define dbm_pagfno(a) DBM_PAGFNO_NOT_AVAILABLE
-
-__BEGIN_DECLS
-void dbm_close __P((DBM *));
-int dbm_delete __P((DBM *, datum));
-datum dbm_fetch __P((DBM *, datum));
-datum dbm_firstkey __P((DBM *));
-long dbm_forder __P((DBM *, datum));
-datum dbm_nextkey __P((DBM *));
-DBM *dbm_open __P((const char *, int, int));
-int dbm_store __P((DBM *, datum, datum, int));
-int dbm_dirfno __P((DBM *));
-__END_DECLS
-
-#endif /* !_NDBM_H_ */
diff --git a/usr.bin/vi/include/queue.h b/usr.bin/vi/include/queue.h
deleted file mode 100644
index 40d32ccb6e29..000000000000
--- a/usr.bin/vi/include/queue.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)queue.h 8.3 (Berkeley) 12/13/93
- */
-
-#ifndef _QUEUE_H_
-#define _QUEUE_H_
-
-/*
- * This file defines three types of data structures: lists, tail queues,
- * and circular queues.
- *
- * A list is headed by a single forward pointer (or an array of forward
- * pointers for a hash table header). The elements are doubly linked
- * so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list after
- * an existing element or at the head of the list. A list may only be
- * traversed in the forward direction.
- *
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list after
- * an existing element, at the head of the list, or at the end of the
- * list. A tail queue may only be traversed in the forward direction.
- *
- * A circle queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or after
- * an existing element, at the head of the list, or at the end of the list.
- * A circle queue may be traversed in either direction, but has a more
- * complex end of list detection.
- *
- * For details on the use of these macros, see the queue(3) manual page.
- */
-
-/*
- * List definitions.
- */
-#define LIST_HEAD(name, type) \
-struct name { \
- struct type *lh_first; /* first element */ \
-}
-
-#define LIST_ENTRY(type) \
-struct { \
- struct type *le_next; /* next element */ \
- struct type **le_prev; /* address of previous next element */ \
-}
-
-/*
- * List functions.
- */
-#define LIST_INIT(head) { \
- (head)->lh_first = NULL; \
-}
-
-#define LIST_INSERT_AFTER(listelm, elm, field) { \
- if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
- (listelm)->field.le_next->field.le_prev = \
- &(elm)->field.le_next; \
- (listelm)->field.le_next = (elm); \
- (elm)->field.le_prev = &(listelm)->field.le_next; \
-}
-
-#define LIST_INSERT_HEAD(head, elm, field) { \
- if (((elm)->field.le_next = (head)->lh_first) != NULL) \
- (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
- (head)->lh_first = (elm); \
- (elm)->field.le_prev = &(head)->lh_first; \
-}
-
-#define LIST_REMOVE(elm, field) { \
- if ((elm)->field.le_next != NULL) \
- (elm)->field.le_next->field.le_prev = \
- (elm)->field.le_prev; \
- *(elm)->field.le_prev = (elm)->field.le_next; \
-}
-
-/*
- * Tail queue definitions.
- */
-#define TAILQ_HEAD(name, type) \
-struct name { \
- struct type *tqh_first; /* first element */ \
- struct type **tqh_last; /* addr of last next element */ \
-}
-
-#define TAILQ_ENTRY(type) \
-struct { \
- struct type *tqe_next; /* next element */ \
- struct type **tqe_prev; /* address of previous next element */ \
-}
-
-/*
- * Tail queue functions.
- */
-#define TAILQ_INIT(head) { \
- (head)->tqh_first = NULL; \
- (head)->tqh_last = &(head)->tqh_first; \
-}
-
-#define TAILQ_INSERT_HEAD(head, elm, field) { \
- if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
- (elm)->field.tqe_next->field.tqe_prev = \
- &(elm)->field.tqe_next; \
- else \
- (head)->tqh_last = &(elm)->field.tqe_next; \
- (head)->tqh_first = (elm); \
- (elm)->field.tqe_prev = &(head)->tqh_first; \
-}
-
-#define TAILQ_INSERT_TAIL(head, elm, field) { \
- (elm)->field.tqe_next = NULL; \
- (elm)->field.tqe_prev = (head)->tqh_last; \
- *(head)->tqh_last = (elm); \
- (head)->tqh_last = &(elm)->field.tqe_next; \
-}
-
-#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \
- if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
- (elm)->field.tqe_next->field.tqe_prev = \
- &(elm)->field.tqe_next; \
- else \
- (head)->tqh_last = &(elm)->field.tqe_next; \
- (listelm)->field.tqe_next = (elm); \
- (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
-}
-
-#define TAILQ_REMOVE(head, elm, field) { \
- if (((elm)->field.tqe_next) != NULL) \
- (elm)->field.tqe_next->field.tqe_prev = \
- (elm)->field.tqe_prev; \
- else \
- (head)->tqh_last = (elm)->field.tqe_prev; \
- *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
-}
-
-/*
- * Circular queue definitions.
- */
-#define CIRCLEQ_HEAD(name, type) \
-struct name { \
- struct type *cqh_first; /* first element */ \
- struct type *cqh_last; /* last element */ \
-}
-
-#define CIRCLEQ_ENTRY(type) \
-struct { \
- struct type *cqe_next; /* next element */ \
- struct type *cqe_prev; /* previous element */ \
-}
-
-/*
- * Circular queue functions.
- */
-#define CIRCLEQ_INIT(head) { \
- (head)->cqh_first = (void *)(head); \
- (head)->cqh_last = (void *)(head); \
-}
-
-#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) { \
- (elm)->field.cqe_next = (listelm)->field.cqe_next; \
- (elm)->field.cqe_prev = (listelm); \
- if ((listelm)->field.cqe_next == (void *)(head)) \
- (head)->cqh_last = (elm); \
- else \
- (listelm)->field.cqe_next->field.cqe_prev = (elm); \
- (listelm)->field.cqe_next = (elm); \
-}
-
-#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) { \
- (elm)->field.cqe_next = (listelm); \
- (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
- if ((listelm)->field.cqe_prev == (void *)(head)) \
- (head)->cqh_first = (elm); \
- else \
- (listelm)->field.cqe_prev->field.cqe_next = (elm); \
- (listelm)->field.cqe_prev = (elm); \
-}
-
-#define CIRCLEQ_INSERT_HEAD(head, elm, field) { \
- (elm)->field.cqe_next = (head)->cqh_first; \
- (elm)->field.cqe_prev = (void *)(head); \
- if ((head)->cqh_last == (void *)(head)) \
- (head)->cqh_last = (elm); \
- else \
- (head)->cqh_first->field.cqe_prev = (elm); \
- (head)->cqh_first = (elm); \
-}
-
-#define CIRCLEQ_INSERT_TAIL(head, elm, field) { \
- (elm)->field.cqe_next = (void *)(head); \
- (elm)->field.cqe_prev = (head)->cqh_last; \
- if ((head)->cqh_first == (void *)(head)) \
- (head)->cqh_first = (elm); \
- else \
- (head)->cqh_last->field.cqe_next = (elm); \
- (head)->cqh_last = (elm); \
-}
-
-#define CIRCLEQ_REMOVE(head, elm, field) { \
- if ((elm)->field.cqe_next == (void *)(head)) \
- (head)->cqh_last = (elm)->field.cqe_prev; \
- else \
- (elm)->field.cqe_next->field.cqe_prev = \
- (elm)->field.cqe_prev; \
- if ((elm)->field.cqe_prev == (void *)(head)) \
- (head)->cqh_first = (elm)->field.cqe_next; \
- else \
- (elm)->field.cqe_prev->field.cqe_next = \
- (elm)->field.cqe_next; \
-}
-#endif /* !_QUEUE_H_ */
diff --git a/usr.bin/vi/interrupt.h b/usr.bin/vi/interrupt.h
deleted file mode 100644
index baa75fef2ca9..000000000000
--- a/usr.bin/vi/interrupt.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-
- * Copyright (c) 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)interrupt.h 8.1 (Berkeley) 1/9/94
- */
-
-/*
- * Macros to declare the variables and then turn on and off interrupts.
- */
-#define DECLARE_INTERRUPTS \
- struct sigaction __act, __oact; \
- struct termios __nterm, __term; \
- u_int __istate; \
- int __isig, __termreset
-
-/*
- * Search, global, and substitute interruptions.
- *
- * ISIG turns on VINTR, VQUIT and VSUSP. We want VINTR to interrupt the
- * search, so we install a handler. VQUIT is ignored by main() because
- * nvi never wants to catch it. A handler for VSUSP should have been
- * installed by the screen code.
- */
-#define SET_UP_INTERRUPTS(handler) { \
- if (F_ISSET(sp->gp, G_ISFROMTTY)) { \
- __act.sa_handler = handler; \
- sigemptyset(&__act.sa_mask); \
- __act.sa_flags = 0; \
- if (__isig = !sigaction(SIGINT, &__act, &__oact)) { \
- __termreset = 0; \
- __istate = F_ISSET(sp, S_INTERRUPTIBLE); \
- F_CLR(sp, S_INTERRUPTED); \
- F_SET(sp, S_INTERRUPTIBLE); \
- if (tcgetattr(STDIN_FILENO, &__term)) { \
- rval = 1; \
- msgq(sp, M_SYSERR, "tcgetattr"); \
- goto interrupt_err; \
- } \
- __nterm = __term; \
- __nterm.c_lflag |= ISIG; \
- if (tcsetattr(STDIN_FILENO, \
- TCSANOW | TCSASOFT, &__nterm)) { \
- rval = 1; \
- msgq(sp, M_SYSERR, "tcsetattr"); \
- goto interrupt_err; \
- } \
- __termreset = 1; \
- } \
- } \
-}
-
-#define TEAR_DOWN_INTERRUPTS { \
- if (F_ISSET(sp->gp, G_ISFROMTTY) && __isig) { \
- if (sigaction(SIGINT, &__oact, NULL)) { \
- rval = 1; \
- msgq(sp, M_SYSERR, "signal"); \
- } \
- if (__termreset && tcsetattr(STDIN_FILENO, \
- TCSANOW | TCSASOFT, &__term)) { \
- rval = 1; \
- msgq(sp, M_SYSERR, "tcsetattr"); \
- } \
- F_CLR(sp, S_INTERRUPTED); \
- if (!__istate) \
- F_CLR(sp, S_INTERRUPTIBLE); \
- } \
-}
diff --git a/usr.bin/vi/intr.c b/usr.bin/vi/intr.c
new file mode 100644
index 000000000000..512e3ae025c8
--- /dev/null
+++ b/usr.bin/vi/intr.c
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)intr.c 8.1 (Berkeley) 3/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * There's a count of how deep the interrupt level in the SCR structure
+ * has gone. Each routine that wants to be interrupted increments this
+ * level, and decrements it when it tears the interrupts down. There are
+ * two simplifying assumptions:
+ *
+ * 1: All interruptible areas want the same handler (we don't have
+ * to save/restore the old handler).
+ * 2: This is the only way to turn on interrupts (we don't have to
+ * worry about them already being turned on if the interrupt
+ * level is 0).
+ *
+ * We do it this way because interrupts have to be very fast -- if the
+ * O_REMAPMAX option is turned off, we are setting interrupts per key
+ * stroke.
+ *
+ * If an interrupt arrives, the S_INTERRUPTED bit is set in any SCR that
+ * has the S_INTERRUPTIBLE bit set. In the future this may be a problem.
+ * The user should be able to move to another screen and keep typing while
+ * another screen runs. Currently, if the user does this and the user has
+ * more than one interruptible thing running, there will be no way to know
+ * which one to stop.
+ */
+
+static void intr_def __P((int));
+
+/*
+ * intr_init --
+ * Set up a interrupts.
+ */
+int
+intr_init(sp)
+ SCR *sp;
+{
+ struct sigaction act;
+ struct termios nterm;
+
+ /* You can never interrupt sessions not using tty's. */
+ if (!F_ISSET(sp->gp, G_STDIN_TTY))
+ return (1);
+
+ /* If interrupts already set up, just increase the level. */
+ if (sp->intr_level++)
+ return (0);
+
+ /* Turn interrupts on in this screen. */
+ F_SET(sp, S_INTERRUPTIBLE);
+
+ /* Install a handler. */
+ act.sa_handler = intr_def;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (sigaction(SIGINT, &act, &sp->intr_act)) {
+ msgq(sp, M_SYSERR, "sigaction");
+ goto err1;
+ }
+
+ /*
+ * Turn on interrupts. ISIG turns on VINTR, VQUIT and VSUSP. We
+ * want VINTR to interrupt, so we install a handler. VQUIT is
+ * ignored by main() because nvi never wants to catch it. A handler
+ * for VSUSP should have been installed by the screen code.
+ */
+ if (tcgetattr(STDIN_FILENO, &sp->intr_term)) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ goto err2;
+ }
+ nterm = sp->intr_term;
+ nterm.c_lflag |= ISIG;
+ if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, &nterm)) {
+ msgq(sp, M_SYSERR, "tcsetattr");
+ /*
+ * If an error occurs, back out the changes and run
+ * without interrupts.
+ */
+err2: (void)sigaction(SIGINT, &sp->intr_act, NULL);
+err1: sp->intr_level = 0;
+ F_CLR(sp, S_INTERRUPTIBLE);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * intr_end --
+ * Tear down interrupts.
+ */
+void
+intr_end(sp)
+ SCR *sp;
+{
+ /* If not the bottom level of interrupts, just return. */
+ if (--sp->intr_level)
+ return;
+
+ /* Turn off interrupts. */
+ if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, &sp->intr_term))
+ msgq(sp, M_SYSERR, "tcsetattr");
+
+ /* Reset the signal state. */
+ if (sigaction(SIGINT, &sp->intr_act, NULL))
+ msgq(sp, M_SYSERR, "sigaction");
+
+ /* Clear interrupt bits in this screen. */
+ F_CLR(sp, S_INTERRUPTED | S_INTERRUPTIBLE);
+}
+
+/*
+ * intr_def --
+ * Default interrupt handler.
+ */
+static void
+intr_def(signo)
+ int signo;
+{
+ SCR *sp;
+
+ for (sp = __global_list->dq.cqh_first;
+ sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
+ if (F_ISSET(sp, S_INTERRUPTIBLE))
+ F_SET(sp, S_INTERRUPTED);
+}
diff --git a/usr.bin/vi/line.c b/usr.bin/vi/line.c
index a7473491cf17..1842b161dfbb 100644
--- a/usr.bin/vi/line.c
+++ b/usr.bin/vi/line.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)line.c 8.20 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)line.c 8.23 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -270,7 +280,7 @@ file_aline(sp, ep, update, lno, p, len)
* updated/scrolled as each line was entered. So, when this routine
* is called to copy the new lines from the cut buffer into the file,
* it has to know not to update the screen again.
- */
+ */
return (scr_update(sp, ep, lno, LINE_APPEND, update));
}
@@ -385,7 +395,7 @@ file_sline(sp, ep, lno, p, len)
/* Log after change. */
log_line(sp, ep, lno, LOG_LINE_RESET_F);
-
+
/* Update screen. */
return (scr_update(sp, ep, lno, LINE_RESET, 1));
}
@@ -422,18 +432,19 @@ file_lline(sp, ep, lnop)
*lnop = 0;
return (1);
case 1:
- lno = 0;
- break;
+ *lnop = 0;
+ return (0);
default:
- memmove(&lno, key.data, sizeof(lno));
break;
}
/* Fill the cache. */
+ memmove(&lno, key.data, sizeof(lno));
ep->c_nlines = ep->c_lno = lno;
ep->c_len = data.size;
ep->c_lp = data.data;
-
+
+ /* Return the value. */
*lnop = (F_ISSET(sp, S_INPUT) &&
((TEXT *)sp->tiq.cqh_last)->lno > lno ?
((TEXT *)sp->tiq.cqh_last)->lno : lno);
diff --git a/usr.bin/vi/log.c b/usr.bin/vi/log.c
index fdf959f4d8a9..07d617ef92b1 100644
--- a/usr.bin/vi/log.c
+++ b/usr.bin/vi/log.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)log.c 8.9 (Berkeley) 12/28/93";
+static char sccsid[] = "@(#)log.c 8.14 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
@@ -56,7 +66,7 @@ static char sccsid[] = "@(#)log.c 8.9 (Berkeley) 12/28/93";
* LOG_LINE_INSERT recno_t char *
* LOG_LINE_RESET_F recno_t char *
* LOG_LINE_RESET_B recno_t char *
- * LOG_MARK MARK
+ * LOG_MARK LMARK
*
* We do before image physical logging. This means that the editor layer
* MAY NOT modify records in place, even if simply deleting or overwriting
@@ -149,7 +159,7 @@ log_end(sp, ep)
ep->l_high = ep->l_cur = 1;
return (0);
}
-
+
/*
* log_cursor --
* Log the current cursor position, starting an event.
@@ -239,7 +249,7 @@ log_line(sp, ep, lno, action)
return (1);
ep->l_cursor.lno = OOBLNO;
}
-
+
/*
* Put out the changes. If it's a LOG_LINE_RESET_B call, it's a
* special case, avoid the caches. Also, if it fails and it's
@@ -311,10 +321,10 @@ log_line(sp, ep, lno, action)
* cause any other change.
*/
int
-log_mark(sp, ep, mp)
+log_mark(sp, ep, lmp)
SCR *sp;
EXF *ep;
- MARK *mp;
+ LMARK *lmp;
{
DBT data, key;
@@ -329,17 +339,21 @@ log_mark(sp, ep, mp)
}
BINC_RET(sp, ep->l_lp,
- ep->l_len, sizeof(u_char) + sizeof(MARK));
+ ep->l_len, sizeof(u_char) + sizeof(LMARK));
ep->l_lp[0] = LOG_MARK;
- memmove(ep->l_lp + sizeof(u_char), mp, sizeof(MARK));
+ memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
key.data = &ep->l_cur;
key.size = sizeof(recno_t);
data.data = ep->l_lp;
- data.size = sizeof(u_char) + sizeof(MARK);
+ data.size = sizeof(u_char) + sizeof(LMARK);
if (ep->log->put(ep->log, &key, &data, 0) == -1)
LOG_ERR;
+#if defined(DEBUG) && 0
+ TRACE(sp, "%lu: mark %c: %lu/%u\n",
+ ep->l_cur, lmp->name, lmp->lno, lmp->cno);
+#endif
/* Reset high water mark. */
ep->l_high = ++ep->l_cur;
return (0);
@@ -356,6 +370,7 @@ log_backward(sp, ep, rp)
MARK *rp;
{
DBT key, data;
+ LMARK lm;
MARK m;
recno_t lno;
int didop;
@@ -423,8 +438,10 @@ log_backward(sp, ep, rp)
break;
case LOG_MARK:
didop = 1;
- memmove(&m, p + sizeof(u_char), sizeof(MARK));
- if (mark_set(sp, ep, m.name, &m, 0))
+ memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
+ m.lno = lm.lno;
+ m.cno = lm.cno;
+ if (mark_set(sp, ep, lm.name, &m, 0))
goto err;
break;
default:
@@ -452,6 +469,7 @@ log_setline(sp, ep)
EXF *ep;
{
DBT key, data;
+ LMARK lm;
MARK m;
recno_t lno;
u_char *p;
@@ -507,8 +525,10 @@ log_setline(sp, ep)
goto err;
++sp->rptlines[L_CHANGED];
case LOG_MARK:
- memmove(&m, p + sizeof(u_char), sizeof(MARK));
- if (mark_set(sp, ep, m.name, &m, 0))
+ memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
+ m.lno = lm.lno;
+ m.cno = lm.cno;
+ if (mark_set(sp, ep, lm.name, &m, 0))
goto err;
break;
default:
@@ -531,6 +551,7 @@ log_forward(sp, ep, rp)
MARK *rp;
{
DBT key, data;
+ LMARK lm;
MARK m;
recno_t lno;
int didop;
@@ -599,8 +620,10 @@ log_forward(sp, ep, rp)
break;
case LOG_MARK:
didop = 1;
- memmove(&m, p + sizeof(u_char), sizeof(MARK));
- if (mark_set(sp, ep, m.name, &m, 0))
+ memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
+ m.lno = lm.lno;
+ m.cno = lm.cno;
+ if (mark_set(sp, ep, lm.name, &m, 0))
goto err;
break;
default:
@@ -620,6 +643,7 @@ log_trace(sp, msg, rno, p)
recno_t rno;
u_char *p;
{
+ LMARK lm;
MARK m;
recno_t lno;
@@ -653,8 +677,9 @@ log_trace(sp, msg, rno, p)
TRACE(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno);
break;
case LOG_MARK:
- memmove(&m, p + sizeof(u_char), sizeof(MARK));
- TRACE(sp, "%lu: %s: MARK: %u/%u\n", rno, msg, m.lno, m.cno);
+ memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
+ TRACE(sp,
+ "%lu: %s: MARK: %u/%u\n", rno, msg, lm.lno, lm.cno);
break;
default:
abort();
diff --git a/usr.bin/vi/log.h b/usr.bin/vi/log.h
index 840cf8532c0c..2974df4d14b6 100644
--- a/usr.bin/vi/log.h
+++ b/usr.bin/vi/log.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)log.h 8.3 (Berkeley) 12/28/93
+ * @(#)log.h 8.5 (Berkeley) 3/16/94
*/
#define LOG_NOTYPE 0
@@ -49,5 +49,5 @@ int log_end __P((SCR *, EXF *));
int log_forward __P((SCR *, EXF *, MARK *));
int log_init __P((SCR *, EXF *));
int log_line __P((SCR *, EXF *, recno_t, u_int));
-int log_mark __P((SCR *, EXF *, MARK *));
+int log_mark __P((SCR *, EXF *, LMARK *));
int log_setline __P((SCR *, EXF *));
diff --git a/usr.bin/vi/main.c b/usr.bin/vi/main.c
index 3413a475ddf8..cb74a051d460 100644
--- a/usr.bin/vi/main.c
+++ b/usr.bin/vi/main.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,16 +38,22 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)main.c 8.65 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)main.c 8.76 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/param.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
@@ -59,12 +65,17 @@ static char sccsid[] = "@(#)main.c 8.65 (Berkeley) 1/23/94";
#include <varargs.h>
#endif
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
#include "excmd.h"
-#include "pathnames.h"
#include "tag.h"
-static int exrc_isok __P((SCR *, char *, int));
+enum rc { NOEXIST, NOPERM, OK };
+
+static enum rc exrc_isok __P((SCR *, struct stat *, char *, int));
static void gs_end __P((GS *));
static GS *gs_init __P((void));
static void h_hup __P((int));
@@ -84,6 +95,7 @@ main(argc, argv)
extern char *optarg;
static int reenter; /* STATIC: Re-entrancy check. */
struct sigaction act;
+ struct stat hsb, lsb;
GS *gp;
FREF *frp;
SCR *sp;
@@ -196,7 +208,7 @@ main(argc, argv)
/* Build and initialize the GS structure. */
__global_list = gp = gs_init();
-
+
if (snapshot)
F_SET(gp, G_SNAPSHOT);
@@ -263,8 +275,8 @@ main(argc, argv)
#endif
/*
- * Source the system, environment, ~user and local .exrc values.
- * Vi historically didn't check ~user/.exrc if the environment
+ * Source the system, environment, $HOME and local .exrc values.
+ * Vi historically didn't check $HOME/.exrc if the environment
* variable EXINIT was set. This is all done before the file is
* read in because things in the .exrc information can set, for
* example, the recovery directory.
@@ -273,52 +285,75 @@ main(argc, argv)
* While nvi can handle any of the options settings of historic vi,
* the converse is not true. Since users are going to have to have
* files and environmental variables that work with both, we use nvi
- * versions if they exist, otherwise the historic ones.
+ * versions of both the $HOME and local startup files if they exist,
+ * otherwise the historic ones.
+ *
+ * !!!
+ * According to O'Reilly ("Learning the VI Editor", Fifth Ed., May
+ * 1992, page 106), System V release 3.2 and later, has an option
+ * "[no]exrc", causing vi to not "read .exrc files in the current
+ * directory unless the exrc option in the home directory's .exrc
+ * file" was set. The problem that this (hopefully) solves is that
+ * on System V you can give away files, so there's no possible test
+ * we can make to determine that the file is safe.
+ *
+ * We initialize the exrc variable to off. If it's explicitly turned
+ * off by the user, then we never read the local .exrc file. If the
+ * user didn't initialize it or initialized it to on, we make all of
+ * the standard checks of the file before reading it.
+ *
+ * !!!
+ * If the user started the historic of vi in $HOME, vi read the user's
+ * .exrc file twice, as $HOME/.exrc and as ./.exrc. We don't since
+ * it's going to make some commands behave oddly, and I can't imagine
+ * anyone depending on it.
*/
if (!silent) {
- if (exrc_isok(sp, _PATH_SYSEXRC, 1))
+ switch (exrc_isok(sp, &hsb, _PATH_SYSEXRC, 1)) {
+ case NOEXIST:
+ case NOPERM:
+ break;
+ case OK:
(void)ex_cfile(sp, NULL, _PATH_SYSEXRC);
+ break;
+ }
- /* Source the {N,}EXINIT environment variable. */
- if ((p = getenv("NEXINIT")) != NULL ||
- (p = getenv("EXINIT")) != NULL)
+ if ((p = getenv("EXINIT")) != NULL)
if ((p = strdup(p)) == NULL) {
msgq(sp, M_SYSERR, NULL);
goto err;
} else {
+ F_SET(sp, S_VLITONLY);
(void)ex_icmd(sp, NULL, p, strlen(p));
+ F_CLR(sp, S_VLITONLY);
free(p);
}
else if ((p = getenv("HOME")) != NULL && *p) {
(void)snprintf(path,
- sizeof(path), "%s/%s", p, _PATH_NEXRC);
- if (exrc_isok(sp, path, 0))
+ sizeof(path), "%s/%s", p, _PATH_EXRC);
+ switch (exrc_isok(sp, &hsb, path, 0)) {
+ case NOEXIST:
+ break;
+ case NOPERM:
+ break;
+ case OK:
(void)ex_cfile(sp, NULL, path);
- else {
- (void)snprintf(path,
- sizeof(path), "%s/%s", p, _PATH_EXRC);
- if (exrc_isok(sp, path, 0))
- (void)ex_cfile(sp, NULL, path);
+ break;
}
}
- /*
- * !!!
- * According to O'Reilly ("Learning the VI Editor", Fifth Ed.,
- * May 1992, page 106), System V release 3.2 and later, has an
- * option "[no]exrc", causing vi to not "read .exrc files in
- * the current directory unless you first set the exrc option
- * in your home directory's .exrc file". Yeah, right. Did
- * someone actually believe that users would change their home
- * .exrc file based on whether or not they wanted to source the
- * current local .exrc? Or that users would want ALL the local
- * .exrc files on some systems, and none of them on others?
- * I think not.
- *
- * Apply the same tests to local .exrc files that are applied
- * to any other .exrc file.
- */
- if (exrc_isok(sp, _PATH_EXRC, 0))
- (void)ex_cfile(sp, NULL, _PATH_EXRC);
+
+ if (!F_ISSET(&sp->opts[O_EXRC], OPT_SET) || O_ISSET(sp, O_EXRC))
+ switch (exrc_isok(sp, &lsb, _PATH_EXRC, 0)) {
+ case NOEXIST:
+ break;
+ case NOPERM:
+ break;
+ case OK:
+ if (lsb.st_dev != hsb.st_dev ||
+ lsb.st_ino != hsb.st_ino)
+ (void)ex_cfile(sp, NULL, _PATH_EXRC);
+ break;
+ }
}
/* List recovery files if -l specified. */
@@ -358,9 +393,20 @@ main(argc, argv)
* would be nice in some cases to restart system calls, but SA_RESTART
* is a 4BSD extension so we can't use it.
*
- * SIGWINCH, SIGHUP, SIGTERM:
+ * SIGALRM:
+ * Walk structures and call handling routines.
+ * SIGHUP, SIGTERM, SIGWINCH:
* Catch and set a global bit.
+ * SIGQUIT:
+ * Always ignore.
*/
+ act.sa_handler = h_alrm;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (sigaction(SIGALRM, &act, NULL)) {
+ msgq(sp, M_SYSERR, "timer: sigaction");
+ goto err;
+ }
act.sa_handler = h_hup;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
@@ -373,11 +419,6 @@ main(argc, argv)
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
(void)sigaction(SIGWINCH, &act, NULL);
-
- /*
- * SIGQUIT:
- * Always ignore.
- */
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
@@ -400,9 +441,9 @@ main(argc, argv)
if (term_push(sp, ":", 1, 0, 0))
goto err;
}
-
+
/* Vi reads from the terminal. */
- if (!F_ISSET(gp, G_ISFROMTTY) && !F_ISSET(sp, S_EX)) {
+ if (!F_ISSET(gp, G_STDIN_TTY) && !F_ISSET(sp, S_EX)) {
msgq(sp, M_ERR, "Vi's standard input must be a terminal.");
goto err;
}
@@ -472,7 +513,7 @@ err: eval = 1;
* other systems mess up characters typed after the quit command to
* vi but before vi actually exits.
*/
- if (F_ISSET(gp, G_ISFROMTTY))
+ if (F_ISSET(gp, G_TERMIOS_SET))
(void)tcsetattr(STDIN_FILENO, TCSADRAIN, &gp->original_termios);
exit(eval);
}
@@ -505,26 +546,27 @@ gs_init()
/* Set a flag if we're reading from the tty. */
if (isatty(STDIN_FILENO))
- F_SET(gp, G_ISFROMTTY);
+ F_SET(gp, G_STDIN_TTY);
/*
- * XXX
- * Set a flag and don't do terminal sets/resets if the input isn't
- * from a tty. Under all circumstances put reasonable things into
- * the original_termios field, as some routines (seq.c:seq_save()
- * and term.c:term_init()) want values for special characters.
+ * Set the G_STDIN_TTY flag. It's purpose is to avoid setting and
+ * resetting the tty if the input isn't from there.
+ *
+ * Set the G_TERMIOS_SET flag. It's purpose is to avoid using the
+ * original_termios information (mostly special character values)
+ * if it's not valid. We expect that if we've lost our controlling
+ * terminal that the open() (but not the tcgetattr()) will fail.
*/
- if (F_ISSET(gp, G_ISFROMTTY)) {
- if (tcgetattr(STDIN_FILENO, &gp->original_termios))
+ if (F_ISSET(gp, G_STDIN_TTY)) {
+ if (tcgetattr(STDIN_FILENO, &gp->original_termios) == -1)
err(1, "tcgetattr");
- } else {
- if ((fd = open(_PATH_TTY, O_RDONLY, 0)) == -1)
- err(1, "%s", _PATH_TTY);
- if (tcgetattr(fd, &gp->original_termios))
+ F_SET(gp, G_TERMIOS_SET);
+ } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
+ if (tcgetattr(fd, &gp->original_termios) == -1)
err(1, "tcgetattr");
+ F_SET(gp, G_TERMIOS_SET);
(void)close(fd);
}
-
return (gp);
}
@@ -556,16 +598,16 @@ gs_end(gp)
for (sp = __global_list->dq.cqh_first;
sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
for (mp = sp->msgq.lh_first;
- mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
+ mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
(void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf);
for (sp = __global_list->hq.cqh_first;
sp != (void *)&__global_list->hq; sp = sp->q.cqe_next)
for (mp = sp->msgq.lh_first;
- mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
+ mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
(void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf);
/* Flush messages on the global queue. */
for (mp = gp->msgq.lh_first;
- mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
+ mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next)
(void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf);
if (gp->special_key != NULL)
@@ -632,19 +674,19 @@ h_winch(signo)
* exrc_isok --
* Check a .exrc for source-ability.
*/
-static int
-exrc_isok(sp, path, rootok)
+static enum rc
+exrc_isok(sp, sbp, path, rootok)
SCR *sp;
+ struct stat *sbp;
char *path;
int rootok;
{
- struct stat sb;
uid_t uid;
char *emsg, buf[MAXPATHLEN];
/* Check for the file's existence. */
- if (stat(path, &sb))
- return (0);
+ if (stat(path, sbp))
+ return (NOEXIST);
/*
* !!!
@@ -658,29 +700,29 @@ exrc_isok(sp, path, rootok)
/* Owned by the user or root. */
uid = getuid();
if (rootok) {
- if (sb.st_uid != uid && sb.st_uid != 0) {
+ if (sbp->st_uid != uid && sbp->st_uid != 0) {
emsg = "not owned by you or root";
- goto err;
+ goto denied;
}
} else
- if (sb.st_uid != uid) {
+ if (sbp->st_uid != uid) {
emsg = "not owned by you";
- goto err;
+ goto denied;
}
/* Not writeable by anyone but the owner. */
- if (sb.st_mode & (S_IWGRP | S_IWOTH)) {
+ if (sbp->st_mode & (S_IWGRP | S_IWOTH)) {
emsg = "writeable by a user other than the owner";
-err: if (strchr(path, '/') == NULL &&
+denied: if (strchr(path, '/') == NULL &&
getcwd(buf, sizeof(buf)) != NULL)
msgq(sp, M_ERR,
"%s/%s: not sourced: %s.", buf, path, emsg);
else
msgq(sp, M_ERR,
"%s: not sourced: %s.", path, emsg);
- return (0);
+ return (NOPERM);
}
- return (1);
+ return (OK);
}
static void
@@ -688,7 +730,7 @@ obsolete(argv)
char *argv[];
{
size_t len;
- char *p, *myname;
+ char *p;
/*
* Translate old style arguments into something getopt will like.
@@ -699,7 +741,7 @@ obsolete(argv)
* Change "-" into "-s"
* Change "-r" into "-l"
*/
- for (myname = argv[0]; *++argv;)
+ while (*++argv)
if (argv[0][0] == '+') {
if (argv[0][1] == '\0') {
MALLOC_NOMSG(NULL, argv[0], char *, 4);
diff --git a/usr.bin/vi/mark.c b/usr.bin/vi/mark.c
index c510a22002fc..26c02afb4226 100644
--- a/usr.bin/vi/mark.c
+++ b/usr.bin/vi/mark.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,28 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)mark.c 8.12 (Berkeley) 12/27/93";
+static char sccsid[] = "@(#)mark.c 8.17 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
-static MARK *mark_find __P((SCR *, EXF *, ARG_CHAR_T));
+static LMARK *mark_find __P((SCR *, EXF *, ARG_CHAR_T));
/*
* Marks are maintained in a key sorted doubly linked list. We can't
@@ -69,7 +79,7 @@ static MARK *mark_find __P((SCR *, EXF *, ARG_CHAR_T));
* deleted, we delete (and log) any marks on that line. An undo will create
* the mark. Any mark creations are noted as to whether the user created
* it or if it was created by an undo. The former cannot be reset by another
- * undo, but the latter may.
+ * undo, but the latter may.
*
* All of these routines translate ABSMARK2 to ABSMARK1. Setting either of
* the absolute mark locations sets both, so that "m'" and "m`" work like
@@ -85,18 +95,18 @@ mark_init(sp, ep)
SCR *sp;
EXF *ep;
{
- MARK *mp;
+ LMARK *lmp;
/*
* Make sure the marks have been set up. If they
* haven't, do so, and create the absolute mark.
*/
- MALLOC_RET(sp, mp, MARK *, sizeof(MARK));
- mp->lno = 1;
- mp->cno = 0;
- mp->name = ABSMARK1;
- mp->flags = 0;
- LIST_INSERT_HEAD(&ep->marks, mp, q);
+ MALLOC_RET(sp, lmp, LMARK *, sizeof(LMARK));
+ lmp->lno = 1;
+ lmp->cno = 0;
+ lmp->name = ABSMARK1;
+ lmp->flags = 0;
+ LIST_INSERT_HEAD(&ep->marks, lmp, q);
return (0);
}
@@ -109,11 +119,11 @@ mark_end(sp, ep)
SCR *sp;
EXF *ep;
{
- MARK *mp;
+ LMARK *lmp;
- while ((mp = ep->marks.lh_first) != NULL) {
- LIST_REMOVE(mp, q);
- FREE(mp, sizeof(MARK));
+ while ((lmp = ep->marks.lh_first) != NULL) {
+ LIST_REMOVE(lmp, q);
+ FREE(lmp, sizeof(LMARK));
}
return (0);
}
@@ -122,36 +132,38 @@ mark_end(sp, ep)
* mark_get --
* Get the location referenced by a mark.
*/
-MARK *
-mark_get(sp, ep, key)
+int
+mark_get(sp, ep, key, mp)
SCR *sp;
EXF *ep;
ARG_CHAR_T key;
-{
MARK *mp;
+{
+ LMARK *lmp;
size_t len;
- char *p;
if (key == ABSMARK2)
key = ABSMARK1;
- mp = mark_find(sp, ep, key);
- if (mp == NULL || mp->name != key) {
+ lmp = mark_find(sp, ep, key);
+ if (lmp == NULL || lmp->name != key) {
msgq(sp, M_BERR, "Mark %s: not set.", charname(sp, key));
- return (NULL);
+ return (1);
}
- if (F_ISSET(mp, MARK_DELETED)) {
+ if (F_ISSET(lmp, MARK_DELETED)) {
msgq(sp, M_BERR,
"Mark %s: the line was deleted.", charname(sp, key));
- return (NULL);
+ return (1);
}
- if ((p = file_gline(sp, ep, mp->lno, &len)) == NULL ||
- mp->cno > len || mp->cno == len && len != 0) {
+ if (file_gline(sp, ep, lmp->lno, &len) == NULL ||
+ lmp->cno > len || lmp->cno == len && len != 0) {
msgq(sp, M_BERR, "Mark %s: cursor position no longer exists.",
charname(sp, key));
- return (NULL);
+ return (1);
}
- return (mp);
+ mp->lno = lmp->lno;
+ mp->cno = lmp->cno;
+ return (0);
}
/*
@@ -166,7 +178,7 @@ mark_set(sp, ep, key, value, userset)
MARK *value;
int userset;
{
- MARK *mp, *mt;
+ LMARK *lmp, *lmt;
if (key == ABSMARK2)
key = ABSMARK1;
@@ -177,22 +189,22 @@ mark_set(sp, ep, key, value, userset)
* an undo, and we set it if it's not already set or if it was set
* by a previous undo.
*/
- mp = mark_find(sp, ep, key);
- if (mp == NULL || mp->name != key) {
- MALLOC_RET(sp, mt, MARK *, sizeof(MARK));
- if (mp == NULL) {
- LIST_INSERT_HEAD(&ep->marks, mt, q);
+ lmp = mark_find(sp, ep, key);
+ if (lmp == NULL || lmp->name != key) {
+ MALLOC_RET(sp, lmt, LMARK *, sizeof(LMARK));
+ if (lmp == NULL) {
+ LIST_INSERT_HEAD(&ep->marks, lmt, q);
} else
- LIST_INSERT_AFTER(mp, mt, q);
- mp = mt;
+ LIST_INSERT_AFTER(lmp, lmt, q);
+ lmp = lmt;
} else if (!userset &&
- !F_ISSET(mp, MARK_DELETED) && F_ISSET(mp, MARK_USERSET))
+ !F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET))
return (0);
- mp->lno = value->lno;
- mp->cno = value->cno;
- mp->name = key;
- mp->flags = userset ? MARK_USERSET : 0;
+ lmp->lno = value->lno;
+ lmp->cno = value->cno;
+ lmp->name = key;
+ lmp->flags = userset ? MARK_USERSET : 0;
return (0);
}
@@ -201,23 +213,23 @@ mark_set(sp, ep, key, value, userset)
* Find the requested mark, or, the slot immediately before
* where it would go.
*/
-static MARK *
+static LMARK *
mark_find(sp, ep, key)
SCR *sp;
EXF *ep;
ARG_CHAR_T key;
{
- MARK *mp, *lastmp;
+ LMARK *lmp, *lastlmp;
/*
* Return the requested mark or the slot immediately before
* where it should go.
*/
- for (lastmp = NULL, mp = ep->marks.lh_first;
- mp != NULL; lastmp = mp, mp = mp->q.le_next)
- if (mp->name >= key)
- return (mp->name == key ? mp : lastmp);
- return (lastmp);
+ for (lastlmp = NULL, lmp = ep->marks.lh_first;
+ lmp != NULL; lastlmp = lmp, lmp = lmp->q.le_next)
+ if (lmp->name >= key)
+ return (lmp->name == key ? lmp : lastlmp);
+ return (lastlmp);
}
/*
@@ -231,24 +243,26 @@ mark_insdel(sp, ep, op, lno)
enum operation op;
recno_t lno;
{
- MARK *mp;
+ LMARK *lmp;
switch (op) {
case LINE_APPEND:
return;
case LINE_DELETE:
- for (mp = ep->marks.lh_first; mp != NULL; mp = mp->q.le_next)
- if (mp->lno >= lno)
- if (mp->lno == lno) {
- F_SET(mp, MARK_DELETED);
- (void)log_mark(sp, ep, mp);
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->lno >= lno)
+ if (lmp->lno == lno) {
+ F_SET(lmp, MARK_DELETED);
+ (void)log_mark(sp, ep, lmp);
} else
- --mp->lno;
+ --lmp->lno;
return;
case LINE_INSERT:
- for (mp = ep->marks.lh_first; mp != NULL; mp = mp->q.le_next)
- if (mp->lno >= lno)
- ++mp->lno;
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->lno >= lno)
+ ++lmp->lno;
return;
case LINE_RESET:
return;
diff --git a/usr.bin/vi/mark.h b/usr.bin/vi/mark.h
index 9c28151314b9..04b445298a7e 100644
--- a/usr.bin/vi/mark.h
+++ b/usr.bin/vi/mark.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,22 +30,31 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)mark.h 8.5 (Berkeley) 12/27/93
+ * @(#)mark.h 8.8 (Berkeley) 3/16/94
*/
/*
- * The MARK structure defines a position in the file. Because of the different
- * interfaces used by the db(3) package, curses, and users, the line number is
- * 1 based, while the column number is 0 based. Additionally, it is known that
- * the out-of-band line number is less than any legal line number. The line
- * number is of type recno_t, as that's the underlying type of the database.
- * The column number is of type size_t, guaranteeing that we can malloc a line.
+ * The MARK and LMARK structures define positions in the file. There are
+ * two structures because the mark subroutines are the only places where
+ * anything cares about something other than line and column.
+ *
+ * Because of the different interfaces used by the db(3) package, curses,
+ * and users, the line number is 1 based and the column number is 0 based.
+ * Additionally, it is known that the out-of-band line number is less than
+ * any legal line number. The line number is of type recno_t, as that's
+ * the underlying type of the database. The column number is of type size_t,
+ * guaranteeing that we can malloc a line.
*/
struct _mark {
- LIST_ENTRY(_mark) q; /* Linked list of marks. */
#define OOBLNO 0 /* Out-of-band line number. */
recno_t lno; /* Line number. */
size_t cno; /* Column number. */
+};
+
+struct _lmark {
+ LIST_ENTRY(_lmark) q; /* Linked list of marks. */
+ recno_t lno; /* Line number. */
+ size_t cno; /* Column number. */
CHAR_T name; /* Mark name. */
#define MARK_DELETED 0x01 /* Mark was deleted. */
@@ -57,8 +66,8 @@ struct _mark {
#define ABSMARK2 '`' /* Absolute mark name. */
/* Mark routines. */
-int mark_end __P((SCR *, EXF *));
-MARK *mark_get __P((SCR *, EXF *, ARG_CHAR_T));
-int mark_init __P((SCR *, EXF *));
-void mark_insdel __P((SCR *, EXF *, enum operation, recno_t));
-int mark_set __P((SCR *, EXF *, ARG_CHAR_T, MARK *, int));
+int mark_end __P((SCR *, EXF *));
+int mark_get __P((SCR *, EXF *, ARG_CHAR_T, MARK *));
+int mark_init __P((SCR *, EXF *));
+void mark_insdel __P((SCR *, EXF *, enum operation, recno_t));
+int mark_set __P((SCR *, EXF *, ARG_CHAR_T, MARK *, int));
diff --git a/usr.bin/vi/mem.h b/usr.bin/vi/mem.h
index 0f8fac4b8f39..f604cbd0aeed 100644
--- a/usr.bin/vi/mem.h
+++ b/usr.bin/vi/mem.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)mem.h 8.2 (Berkeley) 12/19/93
+ * @(#)mem.h 8.5 (Berkeley) 3/16/94
*/
/* Increase the size of a malloc'd buffer. Two versions, one that
@@ -163,4 +163,11 @@
msgq(sp, M_SYSERR, NULL); \
}
+/*
+ * Versions of memmove(3) and memset(3) that use the size of the
+ * initial pointer to figure out how much memory to manipulate.
+ */
+#define MEMMOVE(p, t, len) memmove(p, t, (len) * sizeof(*(p)))
+#define MEMSET(p, value, len) memset(p, value, (len) * sizeof(*(p)))
+
int binc __P((SCR *, void *, size_t *, size_t));
diff --git a/usr.bin/vi/msg.h b/usr.bin/vi/msg.h
index 6b20bb4bb63b..15eaf356ef4f 100644
--- a/usr.bin/vi/msg.h
+++ b/usr.bin/vi/msg.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,21 +30,23 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)msg.h 8.8 (Berkeley) 11/18/93
+ * @(#)msg.h 8.10 (Berkeley) 3/16/94
*/
/*
- * M_BERR -- Error: ring a bell if O_VERBOSE not set, else
- * display in inverse video.
- * M_ERR -- Error: display in inverse video.
- * M_INFO -- Info: display in normal video.
- * M_SYSERR -- M_ERR, but use standard error message.
- * M_VINFO -- Info: display only if O_VERBOSE set.
+ * Message types.
*
- * In historical vi, O_VERBOSE didn't exist, and O_TERSE made the
- * error messages shorter. In this version, O_TERSE has no effect
- * and O_VERBOSE results in informational displays about common
- * errors.
+ * !!!
+ * In historical vi, O_VERBOSE didn't exist, and O_TERSE made the error
+ * messages shorter. In this implementation, O_TERSE has no effect and
+ * O_VERBOSE results in informational displays about common errors for
+ * naive users.
+ *
+ * M_BERR Error: M_ERR if O_VERBOSE, else bell.
+ * M_ERR Error: Display in inverse video.
+ * M_INFO Info: Display in normal video.
+ * M_SYSERR Error: M_ERR, using strerror(3) message.
+ * M_VINFO Info: M_INFO if O_VERBOSE, else ignore.
*/
enum msgtype { M_BERR, M_ERR, M_INFO, M_SYSERR, M_VINFO };
diff --git a/usr.bin/vi/nex/ex_cd.c b/usr.bin/vi/nex/ex_cd.c
deleted file mode 100644
index 6b51bc51c15e..000000000000
--- a/usr.bin/vi/nex/ex_cd.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_cd.c 8.3 (Berkeley) 12/2/93";
-#endif /* not lint */
-
-#include <sys/param.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_cd -- :cd[!] [directory]
- * Change directories.
- */
-int
-ex_cd(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- char *dir, buf[MAXPATHLEN];
-
- switch (cmdp->argc) {
- case 0:
- if ((dir = getenv("HOME")) == NULL) {
- msgq(sp, M_ERR,
- "Environment variable HOME not set.");
- return (1);
- }
- break;
- case 1:
- dir = cmdp->argv[0]->bp;
- break;
- default:
- abort();
- }
-
- if (chdir(dir) < 0) {
- msgq(sp, M_SYSERR, dir);
- return (1);
- }
- if (getcwd(buf, sizeof(buf)) != NULL)
- msgq(sp, M_INFO, "New directory: %s", buf);
- return (0);
-}
diff --git a/usr.bin/vi/nex/ex_move.c b/usr.bin/vi/nex/ex_move.c
deleted file mode 100644
index 965618b0834f..000000000000
--- a/usr.bin/vi/nex/ex_move.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_move.c 8.6 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-enum which {COPY, MOVE};
-static int cm __P((SCR *, EXF *, EXCMDARG *, enum which));
-
-/*
- * ex_copy -- :[line [,line]] co[py] line [flags]
- * Copy selected lines.
- */
-int
-ex_copy(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (cm(sp, ep, cmdp, COPY));
-}
-
-/*
- * ex_move -- :[line [,line]] co[py] line
- * Move selected lines.
- */
-int
-ex_move(sp, ep, cmdp)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
-{
- return (cm(sp, ep, cmdp, MOVE));
-}
-
-static int
-cm(sp, ep, cmdp, cmd)
- SCR *sp;
- EXF *ep;
- EXCMDARG *cmdp;
- enum which cmd;
-{
- CB cb;
- MARK fm1, fm2, m, tm;
- recno_t diff;
- int rval;
-
- fm1 = cmdp->addr1;
- fm2 = cmdp->addr2;
- tm.lno = cmdp->lineno;
- tm.cno = 0;
-
- /* Make sure the destination is valid. */
- if (cmd == MOVE && tm.lno >= fm1.lno && tm.lno < fm2.lno) {
- msgq(sp, M_ERR, "Destination line is inside move range.");
- return (1);
- }
-
- /* Save the text to a cut buffer. */
- memset(&cb, 0, sizeof(cb));
- CIRCLEQ_INIT(&cb.textq);
- if (cut(sp, ep, &cb, NULL, &fm1, &fm2, CUT_LINEMODE))
- return (1);
-
- /* If we're not copying, delete the old text and adjust tm. */
- if (cmd == MOVE) {
- if (delete(sp, ep, &fm1, &fm2, 1)) {
- rval = 1;
- goto err;
- }
- if (tm.lno >= fm1.lno)
- tm.lno -= (fm2.lno - fm1.lno) + 1;
- }
-
- /* Add the new text. */
- if (put(sp, ep, &cb, NULL, &tm, &m, 1)) {
- rval = 1;
- goto err;
- }
-
- /*
- * Move and copy put the cursor on the last line moved or copied.
- * The returned cursor from the put routine is the first line put,
- * not the last, because that's the semantics of vi.
- */
- diff = (fm2.lno - fm1.lno) + 1;
- sp->lno = m.lno + (diff - 1);
- sp->cno = 0;
-
- sp->rptlines[cmd == COPY ? L_COPIED : L_MOVED] += diff;
- rval = 0;
-
-err: (void)text_lfree(&cb.textq);
- return (rval);
-}
diff --git a/usr.bin/vi/nex/ex_util.c b/usr.bin/vi/nex/ex_util.c
deleted file mode 100644
index fa7e70b9dfcc..000000000000
--- a/usr.bin/vi/nex/ex_util.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ex_util.c 8.4 (Berkeley) 12/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vi.h"
-#include "excmd.h"
-
-/*
- * ex_getline --
- * Return a line from the terminal.
- */
-int
-ex_getline(sp, fp, lenp)
- SCR *sp;
- FILE *fp;
- size_t *lenp;
-{
- EX_PRIVATE *exp;
- size_t off;
- int ch;
- char *p;
-
- exp = EXP(sp);
- for (off = 0, p = exp->ibp;; ++off) {
- ch = getc(fp);
- if (off >= exp->ibp_len) {
- BINC_RET(sp, exp->ibp, exp->ibp_len, off + 1);
- p = exp->ibp + off;
- }
- if (ch == EOF || ch == '\n') {
- if (ch == EOF && !off)
- return (1);
- *lenp = off;
- return (0);
- }
- *p++ = ch;
- }
- /* NOTREACHED */
-}
diff --git a/usr.bin/vi/nvi/v_ex.c b/usr.bin/vi/nvi/v_ex.c
deleted file mode 100644
index 631cd342d010..000000000000
--- a/usr.bin/vi/nvi/v_ex.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_ex.c 8.1 (Berkeley) 6/9/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_ex --
- * Run ex.
- */
-int
-v_ex(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (sp->s_ex_run(sp, ep, rp));
-}
diff --git a/usr.bin/vi/nvi/v_section.c b/usr.bin/vi/nvi/v_section.c
deleted file mode 100644
index 8d97e2f10b4e..000000000000
--- a/usr.bin/vi/nvi/v_section.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_section.c 8.4 (Berkeley) 1/22/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * In historic vi, the section commands ignored empty lines, unlike the
- * paragraph commands, which was probably okay. However, they also moved
- * to the start of the last line when there where no more sections instead
- * of the end of the last line like the paragraph commands. I've changed
- * the latter behaviore to match the paragraphs command.
- *
- * In historic vi, a "function" was defined as the first character of the
- * line being an open brace, which could be followed by anything. This
- * implementation follows that historic practice.
- */
-
-/* Macro to do a check on each line. */
-#define CHECK { \
- if (len == 0) \
- continue; \
- if (p[0] == '{') { \
- if (!--cnt) { \
- rp->cno = 0; \
- rp->lno = lno; \
- return (0); \
- } \
- continue; \
- } \
- if (p[0] != '.' || len < 3) \
- continue; \
- for (lp = list; *lp; lp += 2) \
- if (lp[0] == p[1] && \
- (lp[1] == ' ' || lp[1] == p[2]) && !--cnt) { \
- rp->cno = 0; \
- rp->lno = lno; \
- return (0); \
- } \
-}
-
-/*
- * v_sectionf -- [count]]]
- * Move forward count sections/functions.
- */
-int
-v_sectionf(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- size_t len;
- recno_t cnt, lno;
- char *p, *list, *lp;
-
- /* Get macro list. */
- if ((list = O_STR(sp, O_SECTIONS)) == NULL)
- return (1);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- for (lno = fm->lno; (p = file_gline(sp, ep, ++lno, &len)) != NULL;)
- CHECK;
-
- /* EOF is a movement sink. */
- if (fm->lno != lno - 1) {
- rp->lno = lno - 1;
- rp->cno = len ? len - 1 : 0;
- return (0);
- }
- v_eof(sp, ep, NULL);
- return (1);
-}
-
-/*
- * v_sectionb -- [count][[
- * Move backward count sections/functions.
- */
-int
-v_sectionb(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- size_t len;
- recno_t cnt, lno;
- char *p, *list, *lp;
-
- /* Check for SOF. */
- if (fm->lno <= 1) {
- v_sof(sp, NULL);
- return (1);
- }
-
- /* Get macro list. */
- if ((list = O_STR(sp, O_SECTIONS)) == NULL)
- return (1);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- for (lno = fm->lno; (p = file_gline(sp, ep, --lno, &len)) != NULL;)
- CHECK;
-
- /* SOF is a movement sink. */
- rp->lno = 1;
- rp->cno = 0;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_word.c b/usr.bin/vi/nvi/v_word.c
deleted file mode 100644
index 8d917d68e088..000000000000
--- a/usr.bin/vi/nvi/v_word.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_word.c 8.10 (Berkeley) 10/26/93";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * There are two types of "words". Bigwords are easy -- groups of anything
- * delimited by whitespace. Normal words are trickier. They are either a
- * group of characters, numbers and underscores, or a group of anything but,
- * delimited by whitespace. When for a word, if you're in whitespace, it's
- * easy, just remove the whitespace and go to the beginning or end of the
- * word. Otherwise, figure out if the next character is in a different group.
- * If it is, go to the beginning or end of that group, otherwise, go to the
- * beginning or end of the current group. The historic version of vi didn't
- * get this right, so, for example, there were cases where "4e" was not the
- * same as "eeee". To get it right you have to resolve the cursor after each
- * search so that the look-ahead to figure out what type of "word" the cursor
- * is in will be correct.
- *
- * Empty lines, and lines that consist of only white-space characters count
- * as a single word, and the beginning and end of the file counts as an
- * infinite number of words.
- *
- * Movements associated with commands are different than movement commands.
- * For example, in "abc def", with the cursor on the 'a', "cw" is from
- * 'a' to 'c', while "w" is from 'a' to 'd'. In general, trailing white
- * space is discarded from the change movement. Another example is that,
- * in the same string, a "cw" on any white space character replaces that
- * single character, and nothing else. Ain't nothin' in here that's easy.
- *
- * One historic note -- in the original vi, the 'w', 'W' and 'B' commands
- * would treat groups of empty lines as individual words, i.e. the command
- * would move the cursor to each new empty line. The 'e' and 'E' commands
- * would treat groups of empty lines as a single word, i.e. the first use
- * would move past the group of lines. The 'b' command would just beep at
- * you. If the lines contained only white-space characters, the 'w' and 'W'
- * commands will just beep at you, and the 'B', 'b', 'E' and 'e' commands
- * will treat the group as a single word, and the 'B' and 'b' commands will
- * treat the lines as individual words. This implementation treats both
- * cases as a single white-space word.
- */
-
-#define FW(test) for (; len && (test); --len, ++p)
-#define BW(test) for (; len && (test); --len, --p)
-
-enum which {BIGWORD, LITTLEWORD};
-
-static int bword __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, int));
-static int eword __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, int));
-static int fword __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, enum which));
-
-/*
- * v_wordw -- [count]w
- * Move forward a word at a time.
- */
-int
-v_wordw(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (fword(sp, ep, vp, fm, rp, LITTLEWORD));
-}
-
-/*
- * v_wordW -- [count]W
- * Move forward a bigword at a time.
- */
-int
-v_wordW(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (fword(sp, ep, vp, fm, rp, BIGWORD));
-}
-
-/*
- * fword --
- * Move forward by words.
- */
-static int
-fword(sp, ep, vp, fm, rp, type)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *rp;
- enum which type;
-{
- enum { INWORD, NOTWORD } state;
- VCS cs;
- u_long cnt;
-
- cs.cs_lno = fm->lno;
- cs.cs_cno = fm->cno;
- if (cs_init(sp, ep, &cs))
- return (1);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * If in white-space:
- * If the count is 1, and it's a change command, we're done.
- * Else, move to the first non-white-space character, which
- * counts as a single word move. If it's a motion command,
- * don't move off the end of the line.
- */
- if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
- if (cs.cs_flags != CS_EMP && cnt == 1) {
- if (F_ISSET(vp, VC_C)) {
- ++cs.cs_cno;
- goto ret3;
- }
- if (F_ISSET(vp, VC_D | VC_Y)) {
- if (cs_fspace(sp, ep, &cs))
- return (1);
- goto ret1;
- }
- }
- if (cs_fblank(sp, ep, &cs))
- return (1);
- --cnt;
- }
-
- /*
- * Cyclically move to the next word -- this involves skipping
- * over word characters and then any trailing non-word characters.
- * Note, for the 'w' command, the definition of a word keeps
- * switching.
- */
- if (type == BIGWORD)
- while (cnt--) {
- for (;;) {
- if (cs_next(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- goto ret2;
- if (cs.cs_flags != 0 || isblank(cs.cs_ch))
- break;
- }
- /*
- * If a motion command and we're at the end of the
- * last word, we're done. Delete and yank eat any
- * trailing blanks, but we don't move off the end
- * of the line regardless.
- */
- if (cnt == 0 && F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- if (F_ISSET(vp, VC_D | VC_Y) &&
- cs_fspace(sp, ep, &cs))
- return (1);
- break;
- }
-
- /* Eat whitespace characters. */
- if (cs_fblank(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- goto ret2;
- }
- else
- while (cnt--) {
- state = cs.cs_flags == 0 &&
- inword(cs.cs_ch) ? INWORD : NOTWORD;
- for (;;) {
- if (cs_next(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- goto ret2;
- if (cs.cs_flags != 0 || isblank(cs.cs_ch))
- break;
- if (state == INWORD) {
- if (!inword(cs.cs_ch))
- break;
- } else
- if (inword(cs.cs_ch))
- break;
- }
- /* See comment above. */
- if (cnt == 0 && F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- if (F_ISSET(vp, VC_D | VC_Y) &&
- cs_fspace(sp, ep, &cs))
- return (1);
- break;
- }
-
- /* Eat whitespace characters. */
- if (cs.cs_flags != 0 || isblank(cs.cs_ch))
- if (cs_fblank(sp, ep, &cs))
- return (1);
- if (cs.cs_flags == CS_EOF)
- goto ret2;
- }
-
- /*
- * If a motion command, and eating the trailing non-word would
- * move us off this line, don't do it. Move the return cursor
- * to one past the EOL instead.
- */
-ret1: if (F_ISSET(vp, VC_C | VC_D | VC_Y) && cs.cs_flags == CS_EOL)
- ++cs.cs_cno;
-
- /* If we didn't move, we must be at EOF. */
-ret2: if (cs.cs_lno == fm->lno && cs.cs_cno == fm->cno) {
- v_eof(sp, ep, fm);
- return (1);
- }
- /*
- * If at EOF, and it's a motion command, move the return cursor
- * one past the EOF.
- */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y) && cs.cs_flags == CS_EOF)
- ++cs.cs_cno;
-ret3: rp->lno = cs.cs_lno;
- rp->cno = cs.cs_cno;
- return (0);
-}
-
-/*
- * v_wordb -- [count]b
- * Move backward a word at a time.
- */
-int
-v_wordb(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (bword(sp, ep, vp, fm, rp, 0));
-}
-
-/*
- * v_WordB -- [count]B
- * Move backward a bigword at a time.
- */
-int
-v_wordB(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (bword(sp, ep, vp, fm, rp, 1));
-}
-
-/*
- * bword --
- * Move backward by words.
- */
-static int
-bword(sp, ep, vp, fm, rp, spaceonly)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *rp;
- int spaceonly;
-{
- register char *p;
- recno_t lno;
- size_t len;
- u_long cno, cnt;
- char *startp;
-
- lno = fm->lno;
- cno = fm->cno;
-
- /* Check for start of file. */
- if (lno == 1 && cno == 0) {
- v_sof(sp, NULL);
- return (1);
- }
-
- if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- v_sof(sp, NULL);
- else
- GETLINE_ERR(sp, lno);
- return (1);
- }
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * Reset the length to the number of characters in the line; the
- * first character is the current cursor position.
- */
- len = cno ? cno + 1 : 0;
- if (len == 0)
- goto line;
- for (startp = p, p += cno; cnt--;) {
- if (spaceonly) {
- if (!isblank(*p)) {
- if (len < 2)
- goto line;
- --p;
- --len;
- }
- BW(isblank(*p));
- if (len)
- BW(!isblank(*p));
- else
- goto line;
- } else {
- if (!isblank(*p)) {
- if (len < 2)
- goto line;
- --p;
- --len;
- }
- BW(isblank(*p));
- if (len)
- if (inword(*p))
- BW(inword(*p));
- else
- BW(!isblank(*p) && !inword(*p));
- else
- goto line;
- }
-
- if (cnt && len == 0) {
- /* If we hit SOF, stay there (historic practice). */
-line: if (lno == 1) {
- rp->lno = 1;
- rp->cno = 0;
- return (0);
- }
-
- /*
- * Get the line. If the line is empty, decrement
- * count and get another one.
- */
- if ((p = file_gline(sp, ep, --lno, &len)) == NULL) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
- if (len == 0) {
- if (cnt == 0 || --cnt == 0) {
- rp->lno = lno;
- rp->cno = 0;
- return (0);
- }
- goto line;
- }
-
- /*
- * Set the cursor to the end of the line. If the word
- * at the end of this line has only a single character,
- * we've already skipped over it.
- */
- startp = p;
- if (len) {
- p += len - 1;
- if (cnt && len > 1 && !isblank(p[0]))
- if (inword(p[0])) {
- if (!inword(p[-1]))
- --cnt;
- } else if (!isblank(p[-1]) &&
- !inword(p[-1]))
- --cnt;
- }
- } else {
- ++p;
- ++len;
- }
- }
- rp->lno = lno;
- rp->cno = p - startp;
- return (0);
-}
-
-/*
- * v_worde -- [count]e
- * Move forward to the end of the word.
- */
-int
-v_worde(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (eword(sp, ep, vp, fm, rp, 0));
-}
-
-/*
- * v_wordE -- [count]E
- * Move forward to the end of the bigword.
- */
-int
-v_wordE(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- return (eword(sp, ep, vp, fm, rp, 1));
-}
-
-/*
- * eword --
- * Move forward to the end of the word.
- */
-static int
-eword(sp, ep, vp, fm, rp, spaceonly)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *rp;
- int spaceonly;
-{
- register char *p;
- recno_t lno;
- size_t len, llen;
- u_long cno, cnt;
- int empty;
- char *startp;
-
- lno = fm->lno;
- cno = fm->cno;
-
- if ((p = file_gline(sp, ep, lno, &llen)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno == 0)
- v_eof(sp, ep, NULL);
- else
- GETLINE_ERR(sp, lno);
- return (1);
- }
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- /*
- * Reset the length; the first character is the current cursor
- * position. If no more characters in this line, may already
- * be at EOF.
- */
- len = llen - cno;
- if (empty = llen == 0 || llen == cno + 1)
- goto line;
-
- for (startp = p += cno; cnt--; empty = 0) {
- if (spaceonly) {
- if (!isblank(*p)) {
- if (len < 2)
- goto line;
- ++p;
- --len;
- }
- FW(isblank(*p));
- if (len)
- FW(!isblank(*p));
- else
- ++cnt;
- } else {
- if (!isblank(*p)) {
- if (len < 2)
- goto line;
- ++p;
- --len;
- }
- FW(isblank(*p));
- if (len)
- if (inword(*p))
- FW(inword(*p));
- else
- FW(!isblank(*p) && !inword(*p));
- else
- ++cnt;
- }
-
- if (cnt && len == 0) {
- /* If we hit EOF, stay there (historic practice). */
-line: if ((p = file_gline(sp, ep, ++lno, &llen)) == NULL) {
- /*
- * If already at eof, complain, unless it's
- * a change command or a delete command and
- * there's something to delete.
- */
- if (empty) {
- if (F_ISSET(vp, VC_C) ||
- F_ISSET(vp, VC_D) && llen != 0) {
- rp->lno = lno - 1;
- rp->cno = llen ? llen : 1;
- return (0);
- }
- v_eof(sp, ep, NULL);
- return (1);
- }
- if ((p =
- file_gline(sp, ep, --lno, &llen)) == NULL) {
- GETLINE_ERR(sp, lno);
- return (1);
- }
- rp->lno = lno;
- rp->cno = llen ? llen - 1 : 0;
- /* The 'c', 'd' and 'y' need one more space. */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- ++rp->cno;
- return (0);
- }
- len = llen;
- cno = 0;
- startp = p;
- } else {
- --p;
- ++len;
- }
- }
- rp->lno = lno;
- rp->cno = cno + (p - startp);
-
- /* The 'c', 'd' and 'y' need one more space. */
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- ++rp->cno;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/v_yank.c b/usr.bin/vi/nvi/v_yank.c
deleted file mode 100644
index 7b2718e647a4..000000000000
--- a/usr.bin/vi/nvi/v_yank.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)v_yank.c 8.11 (Berkeley) 1/9/94";
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include "vi.h"
-#include "vcmd.h"
-
-/*
- * v_Yank -- [buffer][count]Y
- * Yank lines of text into a cut buffer.
- */
-int
-v_Yank(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- if (file_gline(sp, ep, tm->lno, NULL) == NULL) {
- v_eof(sp, ep, fm);
- return (1);
- }
- if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, CUT_LINEMODE))
- return (1);
-
- sp->rptlines[L_YANKED] += (tm->lno - fm->lno) + 1;
- return (0);
-}
-
-/*
- * v_yank -- [buffer][count]y[count][motion]
- * Yank text (or lines of text) into a cut buffer.
- */
-int
-v_yank(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- if (F_ISSET(vp, VC_LMODE)) {
- if (file_gline(sp, ep, tm->lno, NULL) == NULL) {
- v_eof(sp, ep, fm);
- return (1);
- }
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, CUT_LINEMODE))
- return (1);
- } else if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, 0))
- return (1);
-
- /*
- * !!!
- * Historic vi moved the cursor to the from MARK if it was before the
- * current cursor. This makes no sense. For example, "yj" moves the
- * cursor but "yk" does not. Unfortunately, it's too late to change
- * this now. Matching the historic semantics isn't easy. The line
- * number was always changed and column movement was usually relative.
- * However, "y'a" moved the cursor to the first non-blank of the line
- * marked by a, while "y`a" moved the cursor to the line and column
- * marked by a.
- */
- if (F_ISSET(vp, VC_REVMOVE)) {
- rp->lno = fm->lno;
- if (vp->mkp == &vikeys['\'']) {
- rp->cno = 0;
- (void)nonblank(sp, ep, rp->lno, &rp->cno);
- } else if (vp->mkp == &vikeys['`'])
- rp->cno = fm->cno;
- else
- rp->cno = sp->s_relative(sp, ep, rp->lno);
- }
-
- sp->rptlines[L_YANKED] += (tm->lno - fm->lno) + 1;
- return (0);
-}
diff --git a/usr.bin/vi/nvi/vcmd.h b/usr.bin/vi/nvi/vcmd.h
deleted file mode 100644
index d48fa26acf5e..000000000000
--- a/usr.bin/vi/nvi/vcmd.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)vcmd.h 8.23 (Berkeley) 1/8/94
- */
-
-typedef struct _vikeys VIKEYS;
-
-/* Structure passed around to functions implementing vi commands. */
-typedef struct _vicmdarg {
-#define vp_startzero buffer /* START ZERO OUT. */
- CHAR_T buffer; /* Buffer. */
- CHAR_T character; /* Character. */
- u_long count; /* Count. */
- u_long count2; /* Second count (only used by z). */
- int key; /* Command key. */
- VIKEYS const *kp; /* VIKEYS key. */
- VIKEYS const *mkp; /* VIKEYS motion key. */
- size_t klen; /* Keyword length. */
-
-/*
- * Historic vi allowed "dl" when the cursor was on the last column, deleting
- * the last character, and similarly allowed "dw" when the cursor was on the
- * last column of the file. It didn't allow "dh" when the cursor was on
- * column 1, although these cases are not strictly analogous. The point is
- * that some movements would succeed if they were associated with a motion
- * command, and fail otherwise. This is part of the off-by-1 schizophrenia
- * that plagued vi. Other examples are that "dfb" deleted everything up to
- * and including the next 'b' character, but "d/b" only deleted everything
- * up to the next 'b' character. While this implementation regularizes the
- * interface to the extent possible, there are many special cases that can't
- * be fixed. This is implemented by setting special flags per command so that
- * the motion routines know what's really going on.
- *
- * Note, the VC_COMMASK flags are set in the vikeys array, and therefore
- * must have values not used in the set of flags declared in the VIKEYS
- * structure below.
- */
-#define VC_C 0x0001 /* The 'c' command. */
-#define VC_D 0x0002 /* The 'd' command. */
-#define VC_SH 0x0004 /* The '>' command. */
-#define VC_Y 0x0008 /* The 'y' command. */
-#define VC_COMMASK 0x000f /* Mask for special flags. */
-
-#define VC_BUFFER 0x0010 /* Buffer set. */
-#define VC_C1SET 0x0020 /* Count 1 set. */
-#define VC_C1RESET 0x0040 /* Reset the C1SET flag for dot commands. */
-#define VC_C2SET 0x0080 /* Count 2 set. */
-#define VC_LMODE 0x0100 /* Motion is line oriented. */
-#define VC_ISDOT 0x0200 /* Command was the dot command. */
-#define VC_REVMOVE 0x0400 /* Movement was before the cursor. */
-
- u_int flags;
-
-#define vp_endzero keyword /* END ZERO OUT. */
- char *keyword; /* Keyword. */
- size_t kbuflen; /* Keyword buffer length. */
-} VICMDARG;
-
-/* Vi command structure. */
-struct _vikeys { /* Underlying function. */
- int (*func) __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, MARK *));
-
-#define V_DONTUSE1 0x000001 /* VC_C */
-#define V_DONTUSE2 0x000002 /* VC_D */
-#define V_DONTUSE3 0x000004 /* VC_SH */
-#define V_DONTUSE4 0x000008 /* VC_Y */
-#define V_ABS 0x000010 /* Absolute movement, set '' mark. */
-#define V_CHAR 0x000020 /* Character (required, trailing). */
-#define V_CNT 0x000040 /* Count (optional, leading). */
-#define V_DOT 0x000080 /* On success, sets dot command. */
-#define V_KEYNUM 0x000100 /* Cursor referenced number. */
-#define V_KEYW 0x000200 /* Cursor referenced word. */
-#define V_LMODE 0x000400 /* Motion is line oriented. */
-#define V_MOTION 0x000800 /* Motion (required, trailing). */
-#define V_MOVE 0x001000 /* Command defines movement. */
-#define V_OBUF 0x002000 /* Buffer (optional, leading). */
-#define V_RBUF 0x004000 /* Buffer (required, trailing). */
-#define V_RCM 0x008000 /* Use relative cursor movment (RCM). */
-#define V_RCM_SET 0x010000 /* RCM: set to current position. */
-#define V_RCM_SETFNB 0x020000 /* RCM: set to first non-blank (FNB). */
-#define V_RCM_SETLAST 0x040000 /* RCM: set to last character. */
-#define V_RCM_SETLFNB 0x080000 /* RCM: set to FNB if line moved. */
-#define V_RCM_SETNNB 0x100000 /* RCM: set to next non-blank. */
- u_long flags;
- char *usage; /* Usage line. */
- char *help; /* Help line. */
-};
-#define MAXVIKEY 126 /* List of vi commands. */
-extern VIKEYS const vikeys[MAXVIKEY + 1];
-
-/* Definition of a "word". */
-#define inword(ch) (isalnum(ch) || (ch) == '_')
-
-/* Character stream structure, prototypes. */
-typedef struct _vcs {
- recno_t cs_lno; /* Line. */
- size_t cs_cno; /* Column. */
- char *cs_bp; /* Buffer. */
- size_t cs_len; /* Length. */
- int cs_ch; /* Character. */
-#define CS_EMP 1 /* Empty line. */
-#define CS_EOF 2 /* End-of-file. */
-#define CS_EOL 3 /* End-of-line. */
-#define CS_SOF 4 /* Start-of-file. */
- int cs_flags; /* Return flags. */
-} VCS;
-
-int cs_bblank __P((SCR *, EXF *, VCS *));
-int cs_fblank __P((SCR *, EXF *, VCS *));
-int cs_fspace __P((SCR *, EXF *, VCS *));
-int cs_init __P((SCR *, EXF *, VCS *));
-int cs_next __P((SCR *, EXF *, VCS *));
-int cs_prev __P((SCR *, EXF *, VCS *));
-
-/* Vi private, per-screen memory. */
-typedef struct _vi_private {
- VICMDARG sdot; /* Saved dot, motion command. */
- VICMDARG sdotmotion;
-
- CHAR_T rlast; /* Last 'r' command character. */
-
- char *rep; /* Input replay buffer. */
- size_t rep_len; /* Input replay buffer length. */
- size_t rep_cnt; /* Input replay buffer characters. */
-
- CHAR_T inc_lastch; /* Last increment character. */
- long inc_lastval; /* Last increment value. */
-
- char *paragraph; /* Paragraph search list. */
- size_t paragraph_len; /* Paragraph search list length. */
-
- u_long u_ccnt; /* Undo command count. */
-} VI_PRIVATE;
-
-#define VIP(sp) ((VI_PRIVATE *)((sp)->vi_private))
-
-/* Vi function prototypes. */
-int txt_auto __P((SCR *, EXF *, recno_t, TEXT *, size_t, TEXT *));
-int v_buildparagraph __P((SCR *));
-int v_end __P((SCR *));
-void v_eof __P((SCR *, EXF *, MARK *));
-void v_eol __P((SCR *, EXF *, MARK *));
-int v_exwrite __P((void *, const char *, int));
-int v_init __P((SCR *, EXF *));
-int v_isempty __P((char *, size_t));
-int v_msgflush __P((SCR *));
-int v_ntext __P((SCR *, EXF *, TEXTH *, MARK *,
- const char *, const size_t, MARK *, int, recno_t, u_int));
-int v_optchange __P((SCR *, int));
-int v_screen_copy __P((SCR *, SCR *));
-int v_screen_end __P((SCR *));
-void v_sof __P((SCR *, MARK *));
-int vi __P((SCR *, EXF *));
-
-#define VIPROTO(type, name) \
- type name __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, MARK *))
-
-VIPROTO(int, v_again);
-VIPROTO(int, v_at);
-VIPROTO(int, v_bottom);
-VIPROTO(int, v_cfirst);
-VIPROTO(int, v_Change);
-VIPROTO(int, v_change);
-VIPROTO(int, v_chF);
-VIPROTO(int, v_chf);
-VIPROTO(int, v_chrepeat);
-VIPROTO(int, v_chrrepeat);
-VIPROTO(int, v_chT);
-VIPROTO(int, v_cht);
-VIPROTO(int, v_cr);
-VIPROTO(int, v_Delete);
-VIPROTO(int, v_delete);
-VIPROTO(int, v_dollar);
-VIPROTO(int, v_down);
-VIPROTO(int, v_ex);
-VIPROTO(int, v_exit);
-VIPROTO(int, v_exmode);
-VIPROTO(int, v_filter);
-VIPROTO(int, v_first);
-VIPROTO(int, v_gomark);
-VIPROTO(int, v_home);
-VIPROTO(int, v_hpagedown);
-VIPROTO(int, v_hpageup);
-VIPROTO(int, v_iA);
-VIPROTO(int, v_ia);
-VIPROTO(int, v_iI);
-VIPROTO(int, v_ii);
-VIPROTO(int, v_increment);
-VIPROTO(int, v_iO);
-VIPROTO(int, v_io);
-VIPROTO(int, v_join);
-VIPROTO(int, v_left);
-VIPROTO(int, v_lgoto);
-VIPROTO(int, v_linedown);
-VIPROTO(int, v_lineup);
-VIPROTO(int, v_mark);
-VIPROTO(int, v_match);
-VIPROTO(int, v_middle);
-VIPROTO(int, v_ncol);
-VIPROTO(int, v_pagedown);
-VIPROTO(int, v_pageup);
-VIPROTO(int, v_paragraphb);
-VIPROTO(int, v_paragraphf);
-VIPROTO(int, v_Put);
-VIPROTO(int, v_put);
-VIPROTO(int, v_redraw);
-VIPROTO(int, v_Replace);
-VIPROTO(int, v_replace);
-VIPROTO(int, v_right);
-VIPROTO(int, v_screen);
-VIPROTO(int, v_searchb);
-VIPROTO(int, v_searchf);
-VIPROTO(int, v_searchN);
-VIPROTO(int, v_searchn);
-VIPROTO(int, v_searchw);
-VIPROTO(int, v_sectionb);
-VIPROTO(int, v_sectionf);
-VIPROTO(int, v_sentenceb);
-VIPROTO(int, v_sentencef);
-VIPROTO(int, v_shiftl);
-VIPROTO(int, v_shiftr);
-VIPROTO(int, v_status);
-VIPROTO(int, v_stop);
-VIPROTO(int, v_Subst);
-VIPROTO(int, v_subst);
-VIPROTO(int, v_switch);
-VIPROTO(int, v_tagpop);
-VIPROTO(int, v_tagpush);
-VIPROTO(int, v_ulcase);
-VIPROTO(int, v_Undo);
-VIPROTO(int, v_undo);
-VIPROTO(int, v_up);
-VIPROTO(int, v_wordB);
-VIPROTO(int, v_wordb);
-VIPROTO(int, v_wordE);
-VIPROTO(int, v_worde);
-VIPROTO(int, v_wordW);
-VIPROTO(int, v_wordw);
-VIPROTO(int, v_Xchar);
-VIPROTO(int, v_xchar);
-VIPROTO(int, v_Yank);
-VIPROTO(int, v_yank);
-VIPROTO(int, v_z);
-VIPROTO(int, v_zero);
diff --git a/usr.bin/vi/options.c b/usr.bin/vi/options.c
index 9c74160c5c01..b4301a228460 100644
--- a/usr.bin/vi/options.c
+++ b/usr.bin/vi/options.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,27 +32,36 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)options.c 8.36 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)options.c 8.52 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
-#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
#include "excmd.h"
-#include "pathnames.h"
static int opts_abbcmp __P((const void *, const void *));
static int opts_cmp __P((const void *, const void *));
static OPTLIST const *opts_prefix __P((char *));
-static int opts_print __P((SCR *, OPTLIST const *, OPTION *));
+static int opts_print __P((SCR *, OPTLIST const *));
/*
* O'Reilly noted options and abbreviations are from "Learning the VI Editor",
@@ -73,6 +82,8 @@ static OPTLIST const optlist[] = {
{"autowrite", NULL, OPT_0BOOL, 0},
/* O_BEAUTIFY 4BSD */
{"beautify", NULL, OPT_0BOOL, 0},
+/* O_CDPATH 4.4BSD */
+ {"cdpath", f_cdpath, OPT_STR, 0},
/* O_COLUMNS 4.4BSD */
{"columns", f_columns, OPT_NUM, OPT_NOSAVE},
/* O_COMMENT 4.4BSD */
@@ -102,7 +113,12 @@ static OPTLIST const optlist[] = {
/* O_LINES 4.4BSD */
{"lines", f_lines, OPT_NUM, OPT_NOSAVE},
/* O_LISP 4BSD */
- {"lisp", f_lisp, OPT_0BOOL, 0},
+/*
+ * XXX
+ * When the lisp option is implemented, delete
+ * the OPT_NOSAVE flag, so that :mkexrc dumps it.
+ */
+ {"lisp", f_lisp, OPT_0BOOL, OPT_NOSAVE},
/* O_LIST 4BSD */
{"list", f_list, OPT_0BOOL, 0},
/* O_MAGIC 4BSD */
@@ -118,7 +134,7 @@ static OPTLIST const optlist[] = {
/* O_OPEN 4BSD */
{"open", NULL, OPT_1BOOL, 0},
/* O_OPTIMIZE 4BSD */
- {"optimize", f_optimize, OPT_1BOOL, 0},
+ {"optimize", NULL, OPT_1BOOL, 0},
/* O_PARAGRAPHS 4BSD */
{"paragraphs", f_paragraph, OPT_STR, 0},
/* O_PROMPT 4BSD */
@@ -131,6 +147,8 @@ static OPTLIST const optlist[] = {
{"redraw", NULL, OPT_0BOOL, 0},
/* O_REMAP 4BSD */
{"remap", NULL, OPT_1BOOL, 0},
+/* O_REMAPMAX 4.4BSD */
+ {"remapmax", NULL, OPT_1BOOL, 0},
/* O_REPORT 4BSD */
{"report", NULL, OPT_NUM, OPT_NOSTR},
/* O_RULER 4.4BSD */
@@ -172,11 +190,11 @@ static OPTLIST const optlist[] = {
/* O_VERBOSE 4.4BSD */
{"verbose", NULL, OPT_0BOOL, 0},
/* O_W1200 4BSD */
- {"w1200", f_w1200, OPT_NUM, OPT_NEVER},
+ {"w1200", f_w1200, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
/* O_W300 4BSD */
- {"w300", f_w300, OPT_NUM, OPT_NEVER},
+ {"w300", f_w300, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
/* O_W9600 4BSD */
- {"w9600", f_w9600, OPT_NUM, OPT_NEVER},
+ {"w9600", f_w9600, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
/* O_WARN 4BSD */
{"warn", NULL, OPT_1BOOL, 0},
/* O_WINDOW 4BSD */
@@ -273,7 +291,11 @@ opts_init(sp)
O_CLR(sp, cnt);
else if (op->type == OPT_1BOOL)
O_SET(sp, cnt);
-
+
+ (void)snprintf(b1, sizeof(b1), "cdpath=%s",
+ (s = getenv("CDPATH")) == NULL ? ":" : s);
+ SET_DEF(O_CDPATH, b1);
+
/*
* !!!
* Vi historically stored temporary files in /var/tmp. We store them
@@ -293,16 +315,16 @@ opts_init(sp)
(void)snprintf(b1, sizeof(b1), "scroll=%ld", O_VAL(sp, O_LINES) / 2);
SET_DEF(O_SCROLL, b1);
SET_DEF(O_SECTIONS, "sections=NHSHH HUnhsh");
- (void)snprintf(b1, sizeof(b1),
- "shell=%s", (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s);
+ (void)snprintf(b1, sizeof(b1), "shell=%s",
+ (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s);
SET_DEF(O_SHELL, b1);
SET_DEF(O_SHIFTWIDTH, "shiftwidth=8");
SET_DEF(O_SIDESCROLL, "sidescroll=16");
SET_DEF(O_TABSTOP, "tabstop=8");
(void)snprintf(b1, sizeof(b1), "tags=%s", _PATH_TAGS);
SET_DEF(O_TAGS, b1);
- (void)snprintf(b1, sizeof(b1),
- "term=%s", (s = getenv("TERM")) == NULL ? "unknown" : s);
+ (void)snprintf(b1, sizeof(b1), "term=%s",
+ (s = getenv("TERM")) == NULL ? "unknown" : s);
SET_DEF(O_TERM, b1);
/*
@@ -348,7 +370,7 @@ opts_set(sp, argv)
u_long value, turnoff;
int ch, offset, rval;
char *endp, *equals, *name, *p;
-
+
disp = NO_DISPLAY;
for (rval = 0; (*argv)->len != 0; ++argv) {
/*
@@ -359,10 +381,11 @@ opts_set(sp, argv)
disp = ALL_DISPLAY;
continue;
}
-
+
/* Find equals sign or end of set, skipping backquoted chars. */
- for (p = name = argv[0]->bp, equals = NULL; ch = *p; ++p)
- switch(ch) {
+ for (equals = NULL,
+ p = name = argv[0]->bp; (ch = *p) != '\0'; ++p)
+ switch (ch) {
case '=':
equals = p;
break;
@@ -525,7 +548,7 @@ change: if (sp->s_optchange != NULL)
abort();
}
}
- if (disp)
+ if (disp != NO_DISPLAY)
opts_dump(sp, disp);
return (rval);
}
@@ -546,31 +569,41 @@ opts_dump(sp, type)
char nbuf[20];
/*
+ * XXX
+ * It's possible to get here by putting "set option" in the
+ * .exrc file. I can't think of a clean way to layer this,
+ * or a reasonable check to make, so we block it here.
+ */
+ if (sp->stdfp == NULL) {
+ msgq(sp, M_ERR,
+ "Option display requires that the screen be initialized.");
+ return;
+ }
+
+ /*
* Options are output in two groups -- those that fit in a column and
* those that don't. Output is done on 6 character "tab" boundaries
* for no particular reason. (Since we don't output tab characters,
* we can ignore the terminal's tab settings.) Ignore the user's tab
* setting because we have no idea how reasonable it is.
+ *
+ * Find a column width we can live with.
*/
-#define BOUND 6
-
- /* Find a column width we can live with. */
for (cnt = 6; cnt > 1; --cnt) {
- colwidth = (sp->cols - 1) / cnt & ~(BOUND - 1);
+ colwidth = (sp->cols - 1) / cnt & ~(STANDARD_TAB - 1);
if (colwidth >= 10) {
- colwidth = (colwidth + BOUND) & ~(BOUND - 1);
+ colwidth =
+ (colwidth + STANDARD_TAB) & ~(STANDARD_TAB - 1);
break;
}
colwidth = 0;
}
- /*
- * Two passes. First, get the set of options to list, entering them
- * into the column list or the overflow list. No error checking,
- * since we know that at least one option (O_TERM) has the OPT_SET bit
- * set.
+ /*
+ * Get the set of options to list, entering them into
+ * the column list or the overflow list.
*/
- for (b_num = s_num = 0, op = optlist; op->name; ++op) {
+ for (b_num = s_num = 0, op = optlist; op->name != NULL; ++op) {
cnt = op - optlist;
/* If OPT_NEVER set, it's never displayed. */
@@ -618,29 +651,32 @@ opts_dump(sp, type)
b_op[b_num++] = cnt;
}
- numcols = (sp->cols - 1) / colwidth;
- if (s_num > numcols) {
- numrows = s_num / numcols;
- if (s_num % numcols)
- ++numrows;
- } else
- numrows = 1;
-
- for (row = 0; row < numrows;) {
- for (base = row, col = 0; col < numcols; ++col) {
- cnt = opts_print(sp,
- &optlist[s_op[base]], &sp->opts[s_op[base]]);
- if ((base += numrows) >= s_num)
- break;
- (void)ex_printf(EXCOOKIE,
- "%*s", (int)(colwidth - cnt), "");
+ if (s_num > 0) {
+ /* Figure out the number of columns. */
+ numcols = (sp->cols - 1) / colwidth;
+ if (s_num > numcols) {
+ numrows = s_num / numcols;
+ if (s_num % numcols)
+ ++numrows;
+ } else
+ numrows = 1;
+
+ /* Display the options in sorted order. */
+ for (row = 0; row < numrows;) {
+ for (base = row, col = 0; col < numcols; ++col) {
+ cnt = opts_print(sp, &optlist[s_op[base]]);
+ if ((base += numrows) >= s_num)
+ break;
+ (void)ex_printf(EXCOOKIE,
+ "%*s", (int)(colwidth - cnt), "");
+ }
+ if (++row < numrows || b_num)
+ (void)ex_printf(EXCOOKIE, "\n");
}
- if (++row < numrows || b_num)
- (void)ex_printf(EXCOOKIE, "\n");
}
for (row = 0; row < b_num;) {
- (void)opts_print(sp, &optlist[b_op[row]], &sp->opts[b_op[row]]);
+ (void)opts_print(sp, &optlist[b_op[row]]);
if (++row < b_num)
(void)ex_printf(EXCOOKIE, "\n");
}
@@ -652,10 +688,9 @@ opts_dump(sp, type)
* Print out an option.
*/
static int
-opts_print(sp, op, spo)
+opts_print(sp, op)
SCR *sp;
OPTLIST const *op;
- OPTION *spo;
{
int curlen, offset;
@@ -688,12 +723,11 @@ opts_save(sp, fp)
SCR *sp;
FILE *fp;
{
- OPTION *spo;
OPTLIST const *op;
int ch, cnt;
char *p;
- for (spo = sp->opts, op = optlist; op->name; ++op) {
+ for (op = optlist; op->name != NULL; ++op) {
if (F_ISSET(op, OPT_NOSAVE))
continue;
cnt = op - optlist;
diff --git a/usr.bin/vi/options.h.stub b/usr.bin/vi/options.h.stub
index f5f52b52b3d3..cb2725075b9e 100644
--- a/usr.bin/vi/options.h.stub
+++ b/usr.bin/vi/options.h.stub
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)options.h.stub 8.14 (Berkeley) 12/20/93
+ * @(#)options.h.stub 8.18 (Berkeley) 3/17/94
*/
struct _option {
@@ -50,7 +50,7 @@ struct _optlist {
char *name; /* Name. */
/* Change function. */
int (*func) __P((SCR *, OPTION *, char *, u_long));
- /* Type of object. */
+ /* Type of object. */
enum { OPT_0BOOL, OPT_1BOOL, OPT_NUM, OPT_STR } type;
#define OPT_NEVER 0x01 /* Never display the option. */
@@ -81,6 +81,7 @@ int opts_set __P((SCR *, ARGS *[]));
/* Per-option change routines. */
int f_altwerase __P((SCR *, OPTION *, char *, u_long));
+int f_cdpath __P((SCR *, OPTION *, char *, u_long));
int f_columns __P((SCR *, OPTION *, char *, u_long));
int f_keytime __P((SCR *, OPTION *, char *, u_long));
int f_leftright __P((SCR *, OPTION *, char *, u_long));
@@ -91,7 +92,6 @@ int f_matchtime __P((SCR *, OPTION *, char *, u_long));
int f_mesg __P((SCR *, OPTION *, char *, u_long));
int f_modeline __P((SCR *, OPTION *, char *, u_long));
int f_number __P((SCR *, OPTION *, char *, u_long));
-int f_optimize __P((SCR *, OPTION *, char *, u_long));
int f_paragraph __P((SCR *, OPTION *, char *, u_long));
int f_readonly __P((SCR *, OPTION *, char *, u_long));
int f_ruler __P((SCR *, OPTION *, char *, u_long));
diff --git a/usr.bin/vi/options_f.c b/usr.bin/vi/options_f.c
index efd596f9585a..e2f0ed0e4ef2 100644
--- a/usr.bin/vi/options_f.c
+++ b/usr.bin/vi/options_f.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,21 +32,32 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)options_f.c 8.25 (Berkeley) 12/20/93";
+static char sccsid[] = "@(#)options_f.c 8.28 (Berkeley) 3/18/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "tag.h"
+static int opt_dup __P((SCR *, int, char *));
static int opt_putenv __P((char *));
#define DECL(f) \
@@ -72,15 +83,9 @@ DECL(f_altwerase)
return (0);
}
-DECL(f_ttywerase)
+DECL(f_cdpath)
{
- if (turnoff)
- O_CLR(sp, O_TTYWERASE);
- else {
- O_SET(sp, O_TTYWERASE);
- O_CLR(sp, O_ALTWERASE);
- }
- return (0);
+ return (opt_dup(sp, O_CDPATH, str));
}
DECL(f_columns)
@@ -280,12 +285,6 @@ DECL(f_number)
return (0);
}
-DECL(f_optimize)
-{
- msgq(sp, M_ERR, "The optimize option is not implemented.");
- return (0);
-}
-
DECL(f_paragraph)
{
if (strlen(str) & 1) {
@@ -293,15 +292,7 @@ DECL(f_paragraph)
"Paragraph options must be in sets of two characters.");
return (1);
}
-
- if (F_ISSET(&sp->opts[O_PARAGRAPHS], OPT_ALLOCATED))
- free(O_STR(sp, O_PARAGRAPHS));
- if ((O_STR(sp, O_PARAGRAPHS) = strdup(str)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- F_SET(&sp->opts[O_PARAGRAPHS], OPT_ALLOCATED | OPT_SET);
- return (0);
+ return (opt_dup(sp, O_PARAGRAPHS, str));
}
DECL(f_readonly)
@@ -334,15 +325,7 @@ DECL(f_section)
"Section options must be in sets of two characters.");
return (1);
}
-
- if (F_ISSET(&sp->opts[O_SECTIONS], OPT_ALLOCATED))
- free(O_STR(sp, O_SECTIONS));
- if ((O_STR(sp, O_SECTIONS) = strdup(str)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- F_SET(&sp->opts[O_SECTIONS], OPT_ALLOCATED | OPT_SET);
- return (0);
+ return (opt_dup(sp, O_SECTIONS, str));
}
DECL(f_shiftwidth)
@@ -412,32 +395,15 @@ DECL(f_tabstop)
DECL(f_tags)
{
- char *p;
-
- /* Copy for user display. */
- p = O_STR(sp, O_TAGS);
- if ((O_STR(sp, O_TAGS) = strdup(str)) == NULL) {
- O_STR(sp, O_TAGS) = p;
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- if (F_ISSET(&sp->opts[O_TAGS], OPT_ALLOCATED))
- FREE(p, strlen(p) + 1);
- F_SET(&sp->opts[O_TAGS], OPT_ALLOCATED | OPT_SET);
- return (0);
+ return (opt_dup(sp, O_TAGS, str));
}
DECL(f_term)
{
char buf[256];
- if (F_ISSET(&sp->opts[O_TERM], OPT_ALLOCATED))
- free(O_STR(sp, O_TERM));
- if ((O_STR(sp, O_TERM) = strdup(str)) == NULL) {
- msgq(sp, M_SYSERR, NULL);
+ if (opt_dup(sp, O_TERM, str))
return (1);
- }
- F_SET(&sp->opts[O_TERM], OPT_ALLOCATED | OPT_SET);
/* Set the terminal value in the environment for curses. */
(void)snprintf(buf, sizeof(buf), "TERM=%s", str);
@@ -449,6 +415,17 @@ DECL(f_term)
return (0);
}
+DECL(f_ttywerase)
+{
+ if (turnoff)
+ O_CLR(sp, O_TTYWERASE);
+ else {
+ O_SET(sp, O_TTYWERASE);
+ O_CLR(sp, O_ALTWERASE);
+ }
+ return (0);
+}
+
DECL(f_w300)
{
/* Historical behavior for w300 was < 1200. */
@@ -527,6 +504,36 @@ DECL(f_wrapmargin)
}
/*
+ * opt_dup --
+ * Copy a string value for user display.
+ */
+static int
+opt_dup(sp, opt, str)
+ SCR *sp;
+ int opt;
+ char *str;
+{
+ char *p;
+
+ /* Copy for user display. */
+ if ((p = strdup(str)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ /* Free the old contents. */
+ if (F_ISSET(&sp->opts[opt], OPT_ALLOCATED))
+ free(O_STR(sp, opt));
+
+ /* Note that it's set and allocated. */
+ F_SET(&sp->opts[opt], OPT_ALLOCATED | OPT_SET);
+
+ /* Assign new contents. */
+ O_STR(sp, opt) = p;
+ return (0);
+}
+
+/*
* opt_putenv --
* Put a value into the environment. We use putenv(3) because it's
* more portable. The following hack is because some moron decided
diff --git a/usr.bin/vi/pathnames.h b/usr.bin/vi/pathnames.h
index be6352b9dfc1..c6e6906dc63a 100644
--- a/usr.bin/vi/pathnames.h
+++ b/usr.bin/vi/pathnames.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)pathnames.h 8.5 (Berkeley) 12/21/93
+ * @(#)pathnames.h 8.6 (Berkeley) 3/16/94
*/
#define _PATH_BSHELL "/bin/sh"
diff --git a/usr.bin/vi/put.c b/usr.bin/vi/put.c
new file mode 100644
index 000000000000..5f680734e7f6
--- /dev/null
+++ b/usr.bin/vi/put.c
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)put.c 8.3 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * put --
+ * Put text buffer contents into the file.
+ *
+ * !!!
+ * Historically, pasting into a file with no lines in vi would preserve
+ * the single blank line. This is almost certainly a result of the fact
+ * that historic vi couldn't deal with a file that had no lines in it.
+ * This implementation treats that as a bug, and does not retain the blank
+ * line.
+ */
+int
+put(sp, ep, cbp, namep, cp, rp, append)
+ SCR *sp;
+ EXF *ep;
+ CB *cbp;
+ CHAR_T *namep;
+ MARK *cp, *rp;
+ int append;
+{
+ CHAR_T name;
+ TEXT *ltp, *tp;
+ recno_t lno;
+ size_t blen, clen, len;
+ char *bp, *p, *t;
+
+ if (cbp == NULL)
+ if (namep == NULL) {
+ cbp = sp->gp->dcbp;
+ if (cbp == NULL) {
+ msgq(sp, M_ERR, "The default buffer is empty.");
+ return (1);
+ }
+ } else {
+ name = *namep;
+ CBNAME(sp, cbp, name);
+ if (cbp == NULL) {
+ msgq(sp, M_ERR,
+ "Buffer %s is empty.", charname(sp, name));
+ return (1);
+ }
+ }
+ tp = cbp->textq.cqh_first;
+
+ /*
+ * It's possible to do a put into an empty file, meaning that the
+ * cut buffer simply becomes the file. It's a special case so
+ * that we can ignore it in general.
+ *
+ * Historical practice is that the cursor ends up on the first
+ * non-blank character of the first line inserted.
+ */
+ if (cp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ for (; tp != (void *)&cbp->textq;
+ ++lno, tp = tp->q.cqe_next)
+ if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
+ return (1);
+ rp->lno = 1;
+ rp->cno = 0;
+ (void)nonblank(sp, ep, rp->lno, &rp->cno);
+ goto ret;
+ }
+ }
+
+ /* If a line mode buffer, append each new line into the file. */
+ if (F_ISSET(cbp, CB_LMODE)) {
+ lno = append ? cp->lno : cp->lno - 1;
+ rp->lno = lno + 1;
+ for (; tp != (void *)&cbp->textq; ++lno, tp = tp->q.cqe_next)
+ if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
+ return (1);
+ rp->cno = 0;
+ (void)nonblank(sp, ep, rp->lno, &rp->cno);
+ goto ret;
+ }
+
+ /*
+ * If buffer was cut in character mode, replace the current line with
+ * one built from the portion of the first line to the left of the
+ * split plus the first line in the CB. Append each intermediate line
+ * in the CB. Append a line built from the portion of the first line
+ * to the right of the split plus the last line in the CB.
+ *
+ * Get the first line.
+ */
+ lno = cp->lno;
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+
+ GET_SPACE_RET(sp, bp, blen, tp->len + len + 1);
+ t = bp;
+
+ /* Original line, left of the split. */
+ if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) {
+ memmove(bp, p, clen);
+ p += clen;
+ t += clen;
+ }
+
+ /* First line from the CB. */
+ memmove(t, tp->lb, tp->len);
+ t += tp->len;
+
+ /* Calculate length left in original line. */
+ clen = len ? len - cp->cno - (append ? 1 : 0) : 0;
+
+ /*
+ * If no more lines in the CB, append the rest of the original
+ * line and quit. Otherwise, build the last line before doing
+ * the intermediate lines, because the line changes will lose
+ * the cached line.
+ */
+ if (tp->q.cqe_next == (void *)&cbp->textq) {
+ /*
+ * Historical practice is that if a non-line mode put
+ * is inside a single line, the cursor ends up on the
+ * last character inserted.
+ */
+ rp->lno = lno;
+ rp->cno = (t - bp) - 1;
+
+ if (clen > 0) {
+ memmove(t, p, clen);
+ t += clen;
+ }
+ if (file_sline(sp, ep, lno, bp, t - bp))
+ goto mem;
+ } else {
+ /*
+ * Have to build both the first and last lines of the
+ * put before doing any sets or we'll lose the cached
+ * line. Build both the first and last lines in the
+ * same buffer, so we don't have to have another buffer
+ * floating around.
+ *
+ * Last part of original line; check for space, reset
+ * the pointer into the buffer.
+ */
+ ltp = cbp->textq.cqh_last;
+ len = t - bp;
+ ADD_SPACE_RET(sp, bp, blen, ltp->len + clen);
+ t = bp + len;
+
+ /* Add in last part of the CB. */
+ memmove(t, ltp->lb, ltp->len);
+ if (clen)
+ memmove(t + ltp->len, p, clen);
+ clen += ltp->len;
+
+ /*
+ * Now: bp points to the first character of the first
+ * line, t points to the last character of the last
+ * line, t - bp is the length of the first line, and
+ * clen is the length of the last. Just figured you'd
+ * want to know.
+ *
+ * Output the line replacing the original line.
+ */
+ if (file_sline(sp, ep, lno, bp, t - bp))
+ goto mem;
+
+ /*
+ * Historical practice is that if a non-line mode put
+ * covers multiple lines, the cursor ends up on the
+ * first character inserted. (Of course.)
+ */
+ rp->lno = lno;
+ rp->cno = (t - bp) - 1;
+
+ /* Output any intermediate lines in the CB. */
+ for (tp = tp->q.cqe_next;
+ tp->q.cqe_next != (void *)&cbp->textq;
+ ++lno, tp = tp->q.cqe_next)
+ if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
+ goto mem;
+
+ if (file_aline(sp, ep, 1, lno, t, clen)) {
+mem: FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+ }
+ FREE_SPACE(sp, bp, blen);
+
+ /* Reporting... */
+ret: sp->rptlines[L_PUT] += lno - cp->lno;
+
+ return (0);
+}
diff --git a/usr.bin/vi/recover.c b/usr.bin/vi/recover.c
index f9a483236abe..01f94a1c5e7f 100644
--- a/usr.bin/vi/recover.c
+++ b/usr.bin/vi/recover.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,11 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)recover.c 8.40 (Berkeley) 12/21/93";
+static char sccsid[] = "@(#)recover.c 8.50 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/param.h>
+#include <queue.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -46,18 +47,26 @@ static char sccsid[] = "@(#)recover.c 8.40 (Berkeley) 12/21/93";
*/
#include <sys/file.h>
-#include <netdb.h> /* MAXHOSTNAMELEN on some systems. */
+#include <netdb.h> /* MAXHOSTNAMELEN on some systems. */
+#include <bitstring.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
#include "vi.h"
-#include "pathnames.h"
/*
* Recovery code.
@@ -92,7 +101,6 @@ static char sccsid[] = "@(#)recover.c 8.40 (Berkeley) 12/21/93";
#define VI_FHEADER "Vi-recover-file: "
#define VI_PHEADER "Vi-recover-path: "
-static void rcv_alrm __P((int));
static int rcv_mailfile __P((SCR *, EXF *));
static void rcv_syncit __P((SCR *, int));
@@ -125,7 +133,7 @@ rcv_tmp(sp, ep, name)
}
(void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
}
-
+
/* Newlines delimit the mail messages. */
for (p = name; *p; ++p)
if (*p == '\n') {
@@ -169,14 +177,16 @@ rcv_init(sp, ep)
SCR *sp;
EXF *ep;
{
- struct itimerval value;
- struct sigaction act;
recno_t lno;
+ int btear;
F_CLR(ep, F_FIRSTMODIFY | F_RCV_ON);
- /* Build file to mail to the user. */
- if (rcv_mailfile(sp, ep))
+ /*
+ * If not already recoverying a file, build a file to mail
+ * to the user.
+ */
+ if (ep->rcv_mpath == NULL && rcv_mailfile(sp, ep))
goto err;
/* Force read of entire file. */
@@ -184,32 +194,22 @@ rcv_init(sp, ep)
goto err;
/* Turn on a busy message, and sync it to backing store. */
- busy_on(sp, 1, "Copying file for recovery...");
+
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 :
+ !busy_on(sp, "Copying file for recovery...");
if (ep->db->sync(ep->db, R_RECNOSYNC)) {
msgq(sp, M_ERR, "Preservation failed: %s: %s",
ep->rcv_path, strerror(errno));
- busy_off(sp);
+ if (btear)
+ busy_off(sp);
goto err;
}
- busy_off(sp);
-
- if (!F_ISSET(sp->gp, G_RECOVER_SET)) {
- /* Install the recovery timer handler. */
- act.sa_handler = rcv_alrm;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- (void)sigaction(SIGALRM, &act, NULL);
-
- /* Start the recovery timer. */
- value.it_interval.tv_sec = value.it_value.tv_sec = RCV_PERIOD;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &value, NULL)) {
- msgq(sp, M_ERR,
- "Error: setitimer: %s", strerror(errno));
-err: msgq(sp, M_ERR,
- "Recovery after system crash not possible.");
- return (1);
- }
+ if (btear)
+ busy_off(sp);
+
+ if (!F_ISSET(sp->gp, G_RECOVER_SET) && rcv_on(sp, ep)) {
+err: msgq(sp, M_ERR, "Recovery after system crash not possible.");
+ return (1);
}
/* We believe the file is recoverable. */
@@ -218,17 +218,6 @@ err: msgq(sp, M_ERR,
}
/*
- * rcv_alrm --
- * Recovery timer interrupt handler.
- */
-static void
-rcv_alrm(signo)
- int signo;
-{
- F_SET(__global_list, G_SIGALRM);
-}
-
-/*
* rcv_mailfile --
* Build the file to mail to the user.
*/
@@ -265,15 +254,16 @@ rcv_mailfile(sp, ep)
* be recovered. There's an obvious window between the mkstemp call
* and the lock, but it's pretty small.
*/
- if ((ep->rcv_fd = dup(fd)) != -1)
- (void)flock(ep->rcv_fd, LOCK_EX | LOCK_NB);
+ if ((ep->rcv_fd = dup(fd)) == -1 ||
+ flock(ep->rcv_fd, LOCK_EX | LOCK_NB))
+ msgq(sp, M_SYSERR, "Unable to lock recovery file");
if ((ep->rcv_mpath = strdup(path)) == NULL) {
msgq(sp, M_SYSERR, NULL);
(void)fclose(fp);
return (1);
}
-
+
t = FILENAME(sp->frp);
if ((p = strrchr(t, '/')) == NULL)
p = t;
@@ -289,7 +279,7 @@ rcv_mailfile(sp, ep)
"To: ", pw->pw_name,
"Subject: Nvi saved the file ", p,
"Precedence: bulk"); /* For vacation(1). */
- (void)fprintf(fp, "%s%.24s%s%s\n%s%s",
+ (void)fprintf(fp, "%s%.24s%s%s\n%s%s",
"On ", ctime(&now),
", the user ", pw->pw_name,
"was editing a file named ", p);
@@ -307,6 +297,7 @@ rcv_mailfile(sp, ep)
(void)fclose(fp);
return (1);
}
+ (void)fclose(fp);
return (0);
}
@@ -319,15 +310,10 @@ rcv_sync(sp, ep)
SCR *sp;
EXF *ep;
{
- struct itimerval value;
-
if (ep->db->sync(ep->db, R_RECNOSYNC)) {
+ F_CLR(ep, F_RCV_ON);
msgq(sp, M_ERR, "Automatic file backup failed: %s: %s",
ep->rcv_path, strerror(errno));
- value.it_interval.tv_sec = value.it_interval.tv_usec = 0;
- value.it_value.tv_sec = value.it_value.tv_usec = 0;
- (void)setitimer(ITIMER_REAL, &value, NULL);
- F_CLR(ep, F_RCV_ON);
return (1);
}
return (0);
@@ -432,7 +418,7 @@ rcv_syncit(sp, email)
/*
* people making love
* never exactly the same
- * just like a snowflake
+ * just like a snowflake
*
* rcv_list --
* List the files that can be recovered by this user.
@@ -511,18 +497,20 @@ rcv_read(sp, name)
struct stat sb;
DIR *dirp;
FREF *frp;
- FILE *fp;
+ FILE *fp, *sv_fp;
time_t rec_mtime;
int found, requested;
char *p, *t, *recp, *pathp;
char recpath[MAXPATHLEN], file[MAXPATHLEN], path[MAXPATHLEN];
-
+
if ((dirp = opendir(O_STR(sp, O_RECDIR))) == NULL) {
msgq(sp, M_ERR,
"%s: %s", O_STR(sp, O_RECDIR), strerror(errno));
return (1);
}
+ sv_fp = NULL;
+ rec_mtime = 0;
recp = pathp = NULL;
for (found = requested = 0; (dp = readdir(dirp)) != NULL;) {
if (strncmp(dp->d_name, "recover.", 8))
@@ -590,9 +578,11 @@ rcv_read(sp, name)
FREE(t, strlen(t) + 1);
}
rec_mtime = sb.st_mtime;
- }
-
-next: (void)fclose(fp);
+ if (sv_fp != NULL)
+ (void)fclose(sv_fp);
+ sv_fp = fp;
+ } else
+next: (void)fclose(fp);
}
(void)closedir(dirp);
@@ -607,7 +597,7 @@ next: (void)fclose(fp);
"There are older versions of this file for you to recover.");
if (found > requested)
msgq(sp, M_INFO,
- "There are other files that you can recover.");
+ "There are other files for you to recover.");
}
/* Create the FREF structure, start the btree file. */
@@ -615,8 +605,18 @@ next: (void)fclose(fp);
file_init(sp, frp, pathp + sizeof(VI_PHEADER) - 1, 0)) {
FREE(recp, strlen(recp) + 1);
FREE(pathp, strlen(pathp) + 1);
+ (void)fclose(sv_fp);
return (1);
}
+
+ /*
+ * We keep an open lock on the file so that the recover option can
+ * distinguish between files that are live and those that need to
+ * be recovered. The lock is already acquired, so just get a copy.
+ */
+ if ((sp->ep->rcv_fd = dup(fileno(sv_fp))) != -1)
+ (void)fclose(sv_fp);
+
sp->ep->rcv_mpath = recp;
return (0);
}
diff --git a/usr.bin/vi/screen.c b/usr.bin/vi/screen.c
index e18bd02183dd..8664d02d7895 100644
--- a/usr.bin/vi/screen.c
+++ b/usr.bin/vi/screen.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)screen.c 8.51 (Berkeley) 1/11/94";
+static char sccsid[] = "@(#)screen.c 8.56 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "vcmd.h"
#include "excmd.h"
@@ -78,7 +88,6 @@ screen_init(orig, spp, flags)
/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
if (orig == NULL) {
sp->searchdir = NOTSET;
- sp->csearchdir = CNOTSET;
switch (flags & S_SCREENS) {
case S_EX:
@@ -113,8 +122,6 @@ screen_init(orig, spp, flags)
sp->subre = orig->subre;
}
sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD;
- sp->csearchdir = CNOTSET;
- sp->lastckey = orig->lastckey;
if (orig->matchsize) {
len = orig->matchsize * sizeof(regmatch_t);
@@ -153,10 +160,11 @@ mem: msgq(orig, M_SYSERR, "new screen attributes");
sp->s_bg = orig->s_bg;
sp->s_busy = orig->s_busy;
sp->s_change = orig->s_change;
- sp->s_chposition = orig->s_chposition;
sp->s_clear = orig->s_clear;
+ sp->s_colpos = orig->s_colpos;
sp->s_column = orig->s_column;
sp->s_confirm = orig->s_confirm;
+ sp->s_crel = orig->s_crel;
sp->s_down = orig->s_down;
sp->s_edit = orig->s_edit;
sp->s_end = orig->s_end;
@@ -170,9 +178,8 @@ mem: msgq(orig, M_SYSERR, "new screen attributes");
sp->s_optchange = orig->s_optchange;
sp->s_position = orig->s_position;
sp->s_rabs = orig->s_rabs;
+ sp->s_rcm = orig->s_rcm;
sp->s_refresh = orig->s_refresh;
- sp->s_relative = orig->s_relative;
- sp->s_rrel = orig->s_rrel;
sp->s_split = orig->s_split;
sp->s_suspend = orig->s_suspend;
sp->s_up = orig->s_up;
@@ -256,7 +263,7 @@ screen_end(sp)
/*
* Free the message chain last, so previous failures have a place
* to put messages. Copy messages to (in order) a related screen,
- * any screen, the global area.
+ * any screen, the global area.
*/
{ SCR *c_sp; MSG *mp, *next;
if ((c_sp = sp->q.cqe_prev) != (void *)&sp->gp->dq) {
diff --git a/usr.bin/vi/screen.h b/usr.bin/vi/screen.h
index d95179352b48..741c41f01d34 100644
--- a/usr.bin/vi/screen.h
+++ b/usr.bin/vi/screen.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)screen.h 8.81 (Berkeley) 12/29/93
+ * @(#)screen.h 8.92 (Berkeley) 3/23/94
*/
/*
@@ -51,6 +51,8 @@
enum operation { LINE_APPEND, LINE_DELETE, LINE_INSERT, LINE_RESET };
/* Position values. */
enum position { P_BOTTOM, P_FILL, P_MIDDLE, P_TOP };
+ /* Screen adjustment operations. */
+enum adjust { A_DECREASE, A_INCREASE, A_SET };
/*
* Structure for holding file references. Each SCR structure contains a
@@ -161,9 +163,12 @@ struct _scr {
SCRIPT *script; /* Vi: script mode information .*/
- char const *time_msg; /* ITIMER_REAL message. */
- struct itimerval time_value; /* ITIMER_REAL saved value. */
- struct sigaction time_handler; /* ITIMER_REAL saved handler. */
+ struct timeval busy_tod; /* ITIMER_REAL: busy time-of-day. */
+ char const *busy_msg; /* ITIMER_REAL: busy message. */
+
+ struct sigaction intr_act; /* Interrupt saved signal state. */
+ struct termios intr_term; /* Interrupt saved terminal state. */
+ int intr_level; /* 0-N: Interrupt level. */
void *vi_private; /* Vi private area. */
void *ex_private; /* Ex private area. */
@@ -177,8 +182,6 @@ struct _scr {
regex_t sre; /* Last search RE. */
regex_t subre; /* Last substitute RE. */
enum direction searchdir; /* File search direction. */
- enum cdirection csearchdir; /* Character search direction. */
- CHAR_T lastckey; /* Last search character. */
regmatch_t *match; /* Substitute match array. */
size_t matchsize; /* Substitute match array size. */
char *repl; /* Substitute replacement. */
@@ -197,60 +200,60 @@ struct _scr {
* A SCR * MUST be the first argument to these routines.
*/
/* Ring the screen bell. */
- void (*s_bell) __P((SCR *));
+ void (*s_bell) __P((SCR *));
/* Background the screen. */
- int (*s_bg) __P((SCR *));
+ int (*s_bg) __P((SCR *));
/* Put up a busy message. */
- int (*s_busy) __P((SCR *, char const *));
+ int (*s_busy) __P((SCR *, char const *));
/* Change a screen line. */
- int (*s_change) __P((SCR *, EXF *, recno_t, enum operation));
- /* Return column close to specified. */
- size_t (*s_chposition) __P((SCR *, EXF *, recno_t, size_t));
+ int (*s_change) __P((SCR *, EXF *, recno_t, enum operation));
/* Clear the screen. */
- int (*s_clear) __P((SCR *));
+ int (*s_clear) __P((SCR *));
+ /* Return column close to specified. */
+ size_t (*s_colpos) __P((SCR *, EXF *, recno_t, size_t));
/* Return the logical cursor column. */
- int (*s_column) __P((SCR *, EXF *, size_t *));
+ int (*s_column) __P((SCR *, EXF *, size_t *));
enum confirm /* Confirm an action with the user. */
- (*s_confirm) __P((SCR *, EXF *, MARK *, MARK *));
+ (*s_confirm) __P((SCR *, EXF *, MARK *, MARK *));
+ /* Change the relative screen size. */
+ int (*s_crel) __P((SCR *, long));
/* Move down the screen. */
- int (*s_down) __P((SCR *, EXF *, MARK *, recno_t, int));
+ int (*s_down) __P((SCR *, EXF *, MARK *, recno_t, int));
/* Edit a file. */
- int (*s_edit) __P((SCR *, EXF *));
+ int (*s_edit) __P((SCR *, EXF *));
/* End a screen. */
- int (*s_end) __P((SCR *));
+ int (*s_end) __P((SCR *));
/* Run a single ex command. */
- int (*s_ex_cmd) __P((SCR *, EXF *, EXCMDARG *, MARK *));
+ int (*s_ex_cmd) __P((SCR *, EXF *, EXCMDARG *, MARK *));
/* Run user's ex commands. */
- int (*s_ex_run) __P((SCR *, EXF *, MARK *));
+ int (*s_ex_run) __P((SCR *, EXF *, MARK *));
/* Screen's ex write function. */
- int (*s_ex_write) __P((void *, const char *, int));
+ int (*s_ex_write) __P((void *, const char *, int));
/* Foreground the screen. */
- int (*s_fg) __P((SCR *, CHAR_T *));
+ int (*s_fg) __P((SCR *, CHAR_T *));
/* Fill the screen's map. */
- int (*s_fill) __P((SCR *, EXF *, recno_t, enum position));
+ int (*s_fill) __P((SCR *, EXF *, recno_t, enum position));
enum input /* Get a line from the user. */
- (*s_get) __P((SCR *, EXF *, TEXTH *, int, u_int));
+ (*s_get) __P((SCR *, EXF *, TEXTH *, int, u_int));
enum input /* Get a key from the user. */
- (*s_key_read) __P((SCR *, int *, struct timeval *));
+ (*s_key_read) __P((SCR *, int *, struct timeval *));
/* Tell the screen an option changed. */
- int (*s_optchange) __P((SCR *, int));
+ int (*s_optchange) __P((SCR *, int));
/* Return column at screen position. */
- int (*s_position) __P((SCR *, EXF *,
- MARK *, u_long, enum position));
+ int (*s_position) __P((SCR *, EXF *,
+ MARK *, u_long, enum position));
/* Change the absolute screen size. */
- int (*s_rabs) __P((SCR *, long));
+ int (*s_rabs) __P((SCR *, long, enum adjust));
+ /* Return column close to selection. */
+ size_t (*s_rcm) __P((SCR *, EXF *, recno_t));
/* Refresh the screen. */
- int (*s_refresh) __P((SCR *, EXF *));
- /* Return column close to last char. */
- size_t (*s_relative) __P((SCR *, EXF *, recno_t));
- /* Change the relative screen size. */
- int (*s_rrel) __P((SCR *, long));
+ int (*s_refresh) __P((SCR *, EXF *));
/* Split the screen. */
- int (*s_split) __P((SCR *, ARGS *[]));
+ int (*s_split) __P((SCR *, ARGS *[]));
/* Suspend the screen. */
- int (*s_suspend) __P((SCR *));
+ int (*s_suspend) __P((SCR *));
/* Move up the screen. */
- int (*s_up) __P((SCR *, EXF *, MARK *, recno_t, int));
+ int (*s_up) __P((SCR *, EXF *, MARK *, recno_t, int));
/* Editor screens. */
#define S_EX 0x0000001 /* Ex screen. */
@@ -287,28 +290,38 @@ struct _scr {
#define S_SCRIPT 0x0080000 /* Window is a shell script. */
#define S_SRE_SET 0x0100000 /* The search RE has been set. */
#define S_SUBRE_SET 0x0200000 /* The substitute RE has been set. */
-#define S_TIMER_SET 0x0400000 /* If a busy timer is running. */
-#define S_UPDATE_MODE 0x0800000 /* Don't repaint modeline. */
- u_int flags;
+#define S_UPDATE_MODE 0x0400000 /* Don't repaint modeline. */
+#define S_VLITONLY 0x0800000 /* ^V literal next only. */
+ u_int32_t flags;
};
+/* Timers have no structure, so routines are here. */
+void h_alrm __P((int));
+int busy_on __P((SCR *, char const *));
+void busy_off __P((SCR *));
+int rcv_on __P((SCR *, EXF *));
+
+/* Interrupts have no structure, so routines are here. */
+void intr_end __P((SCR *));
+int intr_init __P((SCR *));
+
/* Generic routines to start/stop a screen. */
-int screen_end __P((SCR *));
-int screen_init __P((SCR *, SCR **, u_int));
+int screen_end __P((SCR *));
+int screen_init __P((SCR *, SCR **, u_int));
/* Public interfaces to the underlying screens. */
-int ex_screen_copy __P((SCR *, SCR *));
-int ex_screen_end __P((SCR *));
-int ex_screen_init __P((SCR *));
-int sex_screen_copy __P((SCR *, SCR *));
-int sex_screen_end __P((SCR *));
-int sex_screen_init __P((SCR *));
-int svi_screen_copy __P((SCR *, SCR *));
-int svi_screen_end __P((SCR *));
-int svi_screen_init __P((SCR *));
-int v_screen_copy __P((SCR *, SCR *));
-int v_screen_end __P((SCR *));
-int v_screen_init __P((SCR *));
-int xaw_screen_copy __P((SCR *, SCR *));
-int xaw_screen_end __P((SCR *));
-int xaw_screen_init __P((SCR *));
+int ex_screen_copy __P((SCR *, SCR *));
+int ex_screen_end __P((SCR *));
+int ex_screen_init __P((SCR *));
+int sex_screen_copy __P((SCR *, SCR *));
+int sex_screen_end __P((SCR *));
+int sex_screen_init __P((SCR *));
+int svi_screen_copy __P((SCR *, SCR *));
+int svi_screen_end __P((SCR *));
+int svi_screen_init __P((SCR *));
+int v_screen_copy __P((SCR *, SCR *));
+int v_screen_end __P((SCR *));
+int v_screen_init __P((SCR *));
+int xaw_screen_copy __P((SCR *, SCR *));
+int xaw_screen_end __P((SCR *));
+int xaw_screen_init __P((SCR *));
diff --git a/usr.bin/vi/search.c b/usr.bin/vi/search.c
index 22aadef48751..9ef1a836d92d 100644
--- a/usr.bin/vi/search.c
+++ b/usr.bin/vi/search.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,26 +32,34 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)search.c 8.32 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)search.c 8.40 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
-#include "interrupt.h"
static int check_delta __P((SCR *, EXF *, long, recno_t));
static int ctag_conv __P((SCR *, char **, int *));
static int get_delta __P((SCR *, char **, long *, u_int *));
static int resetup __P((SCR *, regex_t **, enum direction,
char *, char **, long *, u_int *));
-static void search_intr __P((int));
/*
* resetup --
@@ -213,7 +221,7 @@ ctag_conv(sp, ptrnp, replacedp)
/* The second character is a '^', and it's magic. */
if (p[0] == '^')
*t++ = *p++;
-
+
/*
* Escape every other magic character we can find, stripping the
* backslashes ctags inserts to escape the search delimiter
@@ -236,28 +244,6 @@ ctag_conv(sp, ptrnp, replacedp)
return (0);
}
-/*
- * search_intr --
- * Set the interrupt bit in any screen that is interruptible.
- *
- * XXX
- * In the future this may be a problem. The user should be able to move to
- * another screen and keep typing while this runs. If so, and the user has
- * more than one search/global (see ex/ex_global.c) running, it will be hard
- * to decide which one to stop.
- */
-static void
-search_intr(signo)
- int signo;
-{
- SCR *sp;
-
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_INTERRUPTIBLE))
- F_SET(sp, S_INTERRUPTED);
-}
-
#define EMPTYMSG "File empty; nothing to search."
#define EOFMSG "Reached end-of-file without finding the pattern."
#define NOTFOUND "Pattern not found."
@@ -272,14 +258,13 @@ f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
char *ptrn, **eptrn;
u_int *flagp;
{
- DECLARE_INTERRUPTS;
regmatch_t match[1];
regex_t *re, lre;
recno_t lno;
size_t coff, len;
long delta;
u_int flags;
- int eval, rval, wrapped;
+ int btear, eval, itear, rval, wrapped;
char *l;
if (file_lline(sp, ep, &lno))
@@ -327,16 +312,9 @@ f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
}
}
- /*
- * Set up busy message, interrupts.
- *
- * F_search is called from the ex_tagfirst() routine, which runs
- * before the screen really exists. Make sure we don't step on
- * anything.
- */
- if (sp->s_position != NULL)
- busy_on(sp, 1, "Searching...");
- SET_UP_INTERRUPTS(search_intr);
+ /* Set up busy message, interrupts. */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching...");
+ itear = !intr_init(sp);
for (rval = 1, wrapped = 0;; ++lno, coff = 0) {
if (F_ISSET(sp, S_INTERRUPTED)) {
@@ -381,7 +359,7 @@ f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
re_error(sp, eval, re);
break;
}
-
+
/* Warn if wrapped. */
if (wrapped && O_ISSET(sp, O_WARN) && LF_ISSET(SEARCH_MSG))
msgq(sp, M_INFO, WRAPMSG);
@@ -416,13 +394,11 @@ f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
break;
}
-interrupt_err:
-
/* Turn off busy message, interrupts. */
- if (sp->s_position != NULL)
+ if (btear)
busy_off(sp);
- TEAR_DOWN_INTERRUPTS;
-
+ if (itear)
+ intr_end(sp);
return (rval);
}
@@ -434,14 +410,13 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
char *ptrn, **eptrn;
u_int *flagp;
{
- DECLARE_INTERRUPTS;
regmatch_t match[1];
regex_t *re, lre;
recno_t lno;
size_t coff, len, last;
long delta;
u_int flags;
- int eval, rval, wrapped;
+ int btear, eval, itear, rval, wrapped;
char *l;
if (file_lline(sp, ep, &lno))
@@ -471,10 +446,8 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
lno = fm->lno;
/* Turn on busy message, interrupts. */
- busy_on(sp, 1, "Searching...");
-
- if (F_ISSET(sp->gp, G_ISFROMTTY))
- SET_UP_INTERRUPTS(search_intr);
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching...");
+ itear = !intr_init(sp);
for (rval = 1, wrapped = 0, coff = fm->cno;; --lno, coff = 0) {
if (F_ISSET(sp, S_INTERRUPTED)) {
@@ -509,7 +482,7 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
/* Set the termination. */
match[0].rm_so = 0;
- match[0].rm_eo = coff ? coff : len;
+ match[0].rm_eo = len;
#if defined(DEBUG) && 0
TRACE(sp, "B search: %lu from 0 to %qu\n", lno, match[0].rm_eo);
@@ -524,10 +497,14 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
break;
}
+ /* Check for a match starting past the cursor. */
+ if (coff != 0 && match[0].rm_so >= coff)
+ continue;
+
/* Warn if wrapped. */
if (wrapped && O_ISSET(sp, O_WARN) && LF_ISSET(SEARCH_MSG))
msgq(sp, M_INFO, WRAPMSG);
-
+
if (delta) {
if (check_delta(sp, ep, delta, lno))
break;
@@ -539,17 +516,17 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
match[0].rm_so, match[0].rm_eo);
#endif
/*
- * Find the last acceptable one in this line. This
- * is really painful, we need a cleaner interface to
- * regexec to make this possible.
+ * We now have the first match on the line. Step
+ * through the line character by character until we
+ * find the last acceptable match. This is painful,
+ * we need a better interface to regex to make this
+ * work.
*/
for (;;) {
- last = match[0].rm_so;
- match[0].rm_so = match[0].rm_eo + 1;
- if (match[0].rm_so >= len ||
- coff && match[0].rm_so >= coff)
+ last = match[0].rm_so++;
+ if (match[0].rm_so >= len)
break;
- match[0].rm_eo = coff ? coff : len;
+ match[0].rm_eo = len;
eval = regexec(re, l, 1, match,
(match[0].rm_so == 0 ? 0 : REG_NOTBOL) |
REG_STARTEND);
@@ -559,6 +536,8 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
re_error(sp, eval, re);
goto err;
}
+ if (coff && match[0].rm_so >= coff)
+ break;
}
rm->lno = lno;
@@ -573,11 +552,10 @@ b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
}
/* Turn off busy message, interrupts. */
-interrupt_err:
-err: busy_off(sp);
-
- if (F_ISSET(sp->gp, G_ISFROMTTY))
- TEAR_DOWN_INTERRUPTS;
+err: if (btear)
+ busy_off(sp);
+ if (itear)
+ intr_end(sp);
return (rval);
}
@@ -591,7 +569,7 @@ err: busy_off(sp);
* the global, search, and substitute patterns) work with POSIX RE's.
*
* 1: If O_MAGIC is not set, strip backslashes from the magic character
- * set (.[]*~) that have them, and add them to the ones that don't.
+ * set (.[]*~) that have them, and add them to the ones that don't.
* 2: If O_MAGIC is not set, the string "\~" is replaced with the text
* from the last substitute command's replacement string. If O_MAGIC
* is set, it's the string "~".
diff --git a/usr.bin/vi/search.h b/usr.bin/vi/search.h
index 00feff6027c8..1483a04c7b71 100644
--- a/usr.bin/vi/search.h
+++ b/usr.bin/vi/search.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)search.h 8.7 (Berkeley) 11/18/93
+ * @(#)search.h 8.9 (Berkeley) 3/16/94
*/
#define RE_WSTART "[[:<:]]" /* Not-in-word search patterns. */
@@ -46,7 +46,6 @@
#define SEARCH_TERM 0x080 /* Search pattern should terminate. */
enum direction { NOTSET, FORWARD, BACKWARD };
-enum cdirection { CNOTSET, FSEARCH, fSEARCH, TSEARCH, tSEARCH };
/* Search functions. */
int b_search __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *));
diff --git a/usr.bin/vi/seq.c b/usr.bin/vi/seq.c
index 4d6d44956b0e..119e0b9dd9a7 100644
--- a/usr.bin/vi/seq.c
+++ b/usr.bin/vi/seq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)seq.c 8.21 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)seq.c 8.26 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "seq.h"
@@ -51,54 +61,81 @@ static char sccsid[] = "@(#)seq.c 8.21 (Berkeley) 12/9/93";
* Internal version to enter a sequence.
*/
int
-seq_set(sp, name, nlen, input, ilen, output, olen, stype, userdef)
+seq_set(sp, name, nlen, input, ilen, output, olen, stype, flags)
SCR *sp;
char *name, *input, *output;
size_t nlen, ilen, olen;
enum seqtype stype;
- int userdef;
+ int flags;
{
SEQ *lastqp, *qp;
CHAR_T *p;
+ int sv_errno;
-#if defined(DEBUG) && 0
- TRACE(sp, "seq_set: name {%s} input {%s} output {%s}\n",
- name ? name : "", input, output);
-#endif
- /* Just replace the output field in any previous occurrence. */
+ /*
+ * An input string must always be present. The output string
+ * can be NULL, when set internally, that's how we throw away
+ * input.
+ *
+ * Just replace the output field if the string already set.
+ */
if ((qp = seq_find(sp, &lastqp, input, ilen, stype, NULL)) != NULL) {
- if ((p = v_strdup(sp, output, olen)) == NULL)
+ if (output == NULL || olen == 0) {
+ p = NULL;
+ olen = 0;
+ } else if ((p = v_strdup(sp, output, olen)) == NULL) {
+ sv_errno = errno;
goto mem1;
- FREE(qp->output, qp->olen);
+ }
+ if (qp->output != NULL)
+ free(qp->output);
qp->olen = olen;
qp->output = p;
return (0);
}
- /* Allocate and initialize space. */
+ /* Allocate and initialize SEQ structure. */
CALLOC(sp, qp, SEQ *, 1, sizeof(SEQ));
- if (qp == NULL)
+ if (qp == NULL) {
+ sv_errno = errno;
goto mem1;
- if (name == NULL)
+ }
+
+ /* Name. */
+ if (name == NULL || nlen == 0)
qp->name = NULL;
- else if ((qp->name = v_strdup(sp, name, nlen)) == NULL)
+ else if ((qp->name = v_strdup(sp, name, nlen)) == NULL) {
+ sv_errno = errno;
goto mem2;
- if ((qp->input = v_strdup(sp, input, ilen)) == NULL)
+ }
+ qp->nlen = nlen;
+
+ /* Input. */
+ if ((qp->input = v_strdup(sp, input, ilen)) == NULL) {
+ sv_errno = errno;
goto mem3;
- if ((qp->output = v_strdup(sp, output, olen)) == NULL) {
- FREE(qp->input, ilen);
+ }
+ qp->ilen = ilen;
+
+ /* Output. */
+ if (output == NULL) {
+ qp->output = NULL;
+ olen = 0;
+ } else if ((qp->output = v_strdup(sp, output, olen)) == NULL) {
+ sv_errno = errno;
+ free(qp->input);
mem3: if (qp->name != NULL)
- FREE(qp->name, nlen);
+ free(qp->name);
mem2: FREE(qp, sizeof(SEQ));
-mem1: msgq(sp, M_SYSERR, NULL);
+mem1: errno = sv_errno;
+ msgq(sp, M_SYSERR, NULL);
return (1);
}
+ qp->olen = olen;
+ /* Type, flags. */
qp->stype = stype;
- qp->nlen = nlen;
- qp->ilen = ilen;
- qp->olen = olen;
- qp->flags = userdef ? S_USERDEF : 0;
+ qp->flags = flags;
/* Link into the chain. */
if (lastqp == NULL) {
@@ -131,9 +168,10 @@ seq_delete(sp, input, ilen, stype)
LIST_REMOVE(qp, q);
if (qp->name != NULL)
- FREE(qp->name, qp->nlen);
- FREE(qp->input, qp->ilen);
- FREE(qp->output, qp->olen);
+ free(qp->name);
+ free(qp->input);
+ if (qp->output != NULL)
+ free(qp->output);
FREE(qp, sizeof(SEQ));
return (0);
}
@@ -159,7 +197,7 @@ seq_find(sp, lastqp, input, ilen, stype, ispartialp)
* Ispartialp is a location where we return if there was a
* partial match, i.e. if the string were extended it might
* match something.
- *
+ *
* XXX
* Overload the meaning of ispartialp; only the terminal key
* search doesn't want the search limited to complete matches,
@@ -221,28 +259,32 @@ seq_dump(sp, stype, isname)
{
CHNAME const *cname;
SEQ *qp;
- int cnt, len, olen, tablen;
+ int cnt, len, olen;
char *p;
cnt = 0;
cname = sp->gp->cname;
- tablen = O_VAL(sp, O_TABSTOP);
for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
if (stype != qp->stype)
continue;
++cnt;
for (p = qp->input,
- olen = qp->ilen, len = 0; olen > 0; --olen, ++len)
- (void)ex_printf(EXCOOKIE, "%s", cname[*p++].name);
- for (len = tablen - len % tablen; len; --len)
- (void)ex_printf(EXCOOKIE, " ");
+ olen = qp->ilen, len = 0; olen > 0; --olen)
+ len += ex_printf(EXCOOKIE, "%s", cname[*p++].name);
+ for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
+ len -= ex_printf(EXCOOKIE, " ");
- for (p = qp->output, olen = qp->olen; olen > 0; --olen)
- (void)ex_printf(EXCOOKIE, "%s", cname[*p++].name);
+ if (qp->output != NULL)
+ for (p = qp->output,
+ olen = qp->olen, len = 0; olen > 0; --olen)
+ len +=
+ ex_printf(EXCOOKIE, "%s", cname[*p++].name);
+ else
+ len = 0;
if (isname && qp->name != NULL) {
- for (len = tablen - len % tablen; len; --len)
- (void)ex_printf(EXCOOKIE, " ");
+ for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
+ len -= ex_printf(EXCOOKIE, " ");
for (p = qp->name, olen = qp->nlen; olen > 0; --olen)
(void)ex_printf(EXCOOKIE,
"%s", cname[*p++].name);
@@ -263,36 +305,34 @@ seq_save(sp, fp, prefix, stype)
char *prefix;
enum seqtype stype;
{
- CHAR_T esc;
SEQ *qp;
size_t olen;
int ch;
char *p;
/* Write a sequence command for all keys the user defined. */
- (void)term_key_ch(sp, K_VLNEXT, &esc);
for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
- if (!F_ISSET(qp, S_USERDEF))
- continue;
- if (stype != qp->stype)
+ if (!F_ISSET(qp, S_USERDEF) || stype != qp->stype)
continue;
if (prefix)
(void)fprintf(fp, "%s", prefix);
for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
ch = *p++;
- if (ch == esc || ch == '|' ||
+ if (ch == LITERAL_CH || ch == '|' ||
isblank(ch) || term_key_val(sp, ch) == K_NL)
- (void)putc(esc, fp);
+ (void)putc(LITERAL_CH, fp);
(void)putc(ch, fp);
}
(void)putc(' ', fp);
- for (p = qp->output, olen = qp->olen; olen > 0; --olen) {
- ch = *p++;
- if (ch == esc || ch == '|' ||
- term_key_val(sp, ch) == K_NL)
- (void)putc(esc, fp);
- (void)putc(ch, fp);
- }
+ if (qp->output != NULL)
+ for (p = qp->output,
+ olen = qp->olen; olen > 0; --olen) {
+ ch = *p++;
+ if (ch == LITERAL_CH || ch == '|' ||
+ term_key_val(sp, ch) == K_NL)
+ (void)putc(LITERAL_CH, fp);
+ (void)putc(ch, fp);
+ }
(void)putc('\n', fp);
}
return (0);
diff --git a/usr.bin/vi/seq.h b/usr.bin/vi/seq.h
index b9d9ac6cfd66..97f6e8ecd03c 100644
--- a/usr.bin/vi/seq.h
+++ b/usr.bin/vi/seq.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)seq.h 8.7 (Berkeley) 12/2/93
+ * @(#)seq.h 8.9 (Berkeley) 3/16/94
*/
/*
@@ -43,6 +43,9 @@
* starting with the corresponding character. This keeps us from walking
* the list unless it's necessary.
*
+ * The name and the output fields of a SEQ can be empty, i.e. NULL.
+ * Only the input field is required.
+ *
* XXX
* The fast-lookup bits are never turned off -- users don't usually unmap
* things, though, so it's probably not a big deal.
diff --git a/usr.bin/vi/sex/sex_confirm.c b/usr.bin/vi/sex/sex_confirm.c
index 8b55fadedaae..6fc11310cfd5 100644
--- a/usr.bin/vi/sex/sex_confirm.c
+++ b/usr.bin/vi/sex/sex_confirm.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_confirm.c 8.5 (Berkeley) 11/29/93";
+static char sccsid[] = "@(#)sex_confirm.c 8.6 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
diff --git a/usr.bin/vi/sex/sex_get.c b/usr.bin/vi/sex/sex_get.c
index 54b7343608d1..c0647e7af0d1 100644
--- a/usr.bin/vi/sex/sex_get.c
+++ b/usr.bin/vi/sex/sex_get.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_get.c 8.12 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)sex_get.c 8.19 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
-#include <stdlib.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -67,6 +77,9 @@ static void repaint __P((SCR *, int, char *, size_t));
(void)fprintf(stdout, "%s", "\b \b"); \
}
+#define TXT_VALID_EX \
+ (TXT_BEAUTIFY | TXT_CNTRLD | TXT_CR | TXT_NLECHO | TXT_PROMPT)
+
/*
* sex_get --
* Fill a buffer from the terminal for ex.
@@ -117,7 +130,7 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
} else
col = 0;
- iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
+ iflags = LF_ISSET(TXT_BEAUTIFY | TXT_MAPCOMMAND | TXT_MAPINPUT);
for (quoted = Q_NOTSET;;) {
(void)fflush(stdout);
@@ -133,6 +146,20 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
}
switch (ikey.value) {
+ case K_CNTRLD:
+ /*
+ * !!!
+ * Historically, ^D took (but then ignored) a count.
+ * For simplicity, we don't return unless it's the
+ * first character entered.
+ */
+ if (LF_ISSET(TXT_CNTRLD) && tp->len == 0) {
+ tp->len = 1;
+ tp->lb[0] = '\004';
+ tp->lb[1] = '\0';
+ return (INP_OK);
+ }
+ goto ins_ch;
case K_CNTRLZ:
sex_suspend(sp);
/* FALLTHROUGH */
@@ -146,7 +173,7 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
(void)putc('\n', stdout);
(void)fflush(stdout);
}
- /* Terminate with a newline, needed by filter. */
+ /* Terminate with a nul, needed by filter. */
tp->lb[tp->len] = '\0';
return (INP_OK);
case K_VERASE:
@@ -205,10 +232,8 @@ sex_get_notty(sp, ep, tiqh, prompt, flags)
u_int flags;
{
enum { Q_NOTSET, Q_THISCHAR } quoted;
- CHNAME const *cname; /* Character map. */
TEXT *tp; /* Input text structures. */
CH ikey; /* Input character. */
- size_t col; /* 0-N: screen column. */
u_int iflags; /* Input flags. */
int rval;
@@ -234,9 +259,6 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
}
- cname = sp->gp->cname;
- col = 0;
-
iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
for (quoted = Q_NOTSET;;) {
if (rval = term_key(sp, &ikey, iflags))
@@ -246,46 +268,40 @@ newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
BINC_RET(sp, tp->wd, tp->wd_len, tp->len + 1);
if (quoted == Q_THISCHAR)
- goto ins_ch;
+ goto insq_ch;
switch (ikey.value) {
- case K_CNTRLZ:
- sex_suspend(sp);
- /* FALLTHROUGH */
- case K_CNTRLR:
- break;
+ case K_CNTRLD:
+ /* See comment above, in sex_get(). */
+ if (LF_ISSET(TXT_CNTRLD) && tp->len == 1) {
+ tp->len = 1;
+ tp->lb[0] = '\004';
+ tp->lb[1] = '\0';
+ return (INP_OK);
+ }
+ goto ins_ch;
case K_CR:
case K_NL:
- /* Terminate with a newline, needed by filter. */
+ /* Terminate with a nul, needed by filter. */
tp->lb[tp->len] = '\0';
return (INP_OK);
- case K_VERASE:
- if (tp->len)
- --tp->len;
- break;
- case K_VKILL:
- tp->len = 0;
- break;
case K_VLNEXT:
quoted = Q_THISCHAR;
break;
- case K_VWERASE:
- /* Move to the last non-space character. */
- while (tp->len)
- if (!isblank(tp->lb[--tp->len])) {
- ++tp->len;
- break;
- }
-
- /* Move to the last space character. */
- while (tp->len)
- if (isblank(tp->lb[--tp->len])) {
- ++tp->len;
- break;
- }
- break;
default:
-ins_ch: tp->lb[tp->len] = ikey.ch;
+ /*
+ * See the discussion of TXT_BEAUTIFY in vi/v_ntext.c.
+ *
+ * Eliminate any unquoted, iscntrl() character that
+ * wasn't handled specially, except <tab> or <ff>.
+ */
+ins_ch: if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ikey.ch) &&
+ ikey.value != K_FORMFEED && ikey.value != K_TAB) {
+ msgq(sp, M_BERR,
+ "Illegal character; quote to enter.");
+ break;
+ }
+insq_ch: tp->lb[tp->len] = ikey.ch;
++tp->len;
quoted = Q_NOTSET;
break;
diff --git a/usr.bin/vi/sex/sex_refresh.c b/usr.bin/vi/sex/sex_refresh.c
index 0ba589299080..1b417de54dc6 100644
--- a/usr.bin/vi/sex/sex_refresh.c
+++ b/usr.bin/vi/sex/sex_refresh.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_refresh.c 8.5 (Berkeley) 11/18/93";
+static char sccsid[] = "@(#)sex_refresh.c 8.6 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "sex_screen.h"
diff --git a/usr.bin/vi/sex/sex_screen.c b/usr.bin/vi/sex/sex_screen.c
index d087d9f17476..9b87cbb73cd4 100644
--- a/usr.bin/vi/sex/sex_screen.c
+++ b/usr.bin/vi/sex/sex_screen.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_screen.c 8.30 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)sex_screen.c 8.36 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "sex_screen.h"
@@ -61,11 +71,12 @@ sex_screen_init(sp)
sp->s_bell = sex_bell;
sp->s_bg = (int (*)())sex_nope;
sp->s_busy = (int (*)())sex_busy;
- sp->s_change = (int (*)())sex_noop;
- sp->s_chposition = (size_t (*)())sex_abort;
- sp->s_clear = (int (*)())sex_noop;
+ sp->s_change = (int (*)())sex_noop;
+ sp->s_clear = (int (*)())sex_noop;
+ sp->s_colpos = (size_t (*)())sex_abort;
sp->s_column = (int (*)())sex_abort;
sp->s_confirm = sex_confirm;
+ sp->s_crel = (int (*)())sex_nope;
sp->s_down = (int (*)())sex_abort;
sp->s_edit = sex_screen_edit;
sp->s_end = (int (*)())sex_noop;
@@ -75,14 +86,13 @@ sex_screen_init(sp)
sp->s_fg = (int (*)())sex_nope;
sp->s_fill = (int (*)())sex_abort;
sp->s_get = F_ISSET(sp->gp,
- G_ISFROMTTY) ? sex_get : sex_get_notty;
+ G_STDIN_TTY) ? sex_get : sex_get_notty;
sp->s_key_read = sex_key_read;
sp->s_optchange = (int (*)())sex_noop;
sp->s_position = (int (*)())sex_abort;
sp->s_rabs = (int (*)())sex_nope;
+ sp->s_rcm = (size_t (*)())sex_abort;
sp->s_refresh = sex_refresh;
- sp->s_relative = (size_t (*)())sex_abort;
- sp->s_rrel = (int (*)())sex_nope;
sp->s_split = (int (*)())sex_nope;
sp->s_suspend = sex_suspend;
sp->s_up = (int (*)())sex_abort;
@@ -123,11 +133,10 @@ sex_screen_edit(sp, ep)
EXF *ep;
{
struct termios rawt, t;
- GS *saved_gp;
int force, rval;
/* Initialize the terminal state. */
- if (F_ISSET(sp->gp, G_ISFROMTTY))
+ if (F_ISSET(sp->gp, G_STDIN_TTY))
SEX_RAW(t, rawt);
/* Write to the terminal. */
@@ -151,8 +160,6 @@ sex_screen_edit(sp, ep)
break;
}
- saved_gp = sp->gp;
-
force = 0;
switch (F_ISSET(sp, S_MAJOR_CHANGE)) {
case S_EXIT_FORCE:
@@ -176,7 +183,7 @@ sex_screen_edit(sp, ep)
}
/* Reset the terminal state. */
-ret: if (F_ISSET(sp->gp, G_ISFROMTTY) && SEX_NORAW(t))
+ret: if (F_ISSET(sp->gp, G_STDIN_TTY) && SEX_NORAW(t))
rval = 1;
return (rval);
}
diff --git a/usr.bin/vi/sex/sex_term.c b/usr.bin/vi/sex/sex_term.c
index 4e3980f21efd..c69193d59dcb 100644
--- a/usr.bin/vi/sex/sex_term.c
+++ b/usr.bin/vi/sex/sex_term.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_term.c 8.24 (Berkeley) 12/20/93";
+static char sccsid[] = "@(#)sex_term.c 8.28 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/ioctl.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "excmd.h"
#include "script.h"
@@ -115,10 +125,10 @@ sigchk: while (F_ISSET(sp->gp,
* when trying to complete a map, but we're going to hang
* on the next read anyway.
*/
- if (!F_ISSET(sp->gp, G_ISFROMTTY)) {
+ if (!F_ISSET(sp->gp, G_STDIN_TTY)) {
if ((nr = read(STDIN_FILENO,
tty->ch + tty->next + tty->cnt,
- tty->len - (tty->next + tty->cnt))) > 0) {
+ tty->nelem - (tty->next + tty->cnt))) > 0) {
tty->cnt += *nrp = nr;
return (INP_OK);
}
@@ -185,7 +195,7 @@ sigchk: while (F_ISSET(sp->gp,
FD_CLR(sp->script->sh_master, &sp->rdfd);
maxfd = STDIN_FILENO;
}
-
+
switch (select(maxfd + 1, &sp->rdfd, NULL, NULL, tp)) {
case -1: /* Error or interrupt. */
if (errno == EINTR)
@@ -209,7 +219,7 @@ err: msgq(sp, M_SYSERR, "select");
switch (nr = read(STDIN_FILENO,
tty->ch + tty->next + tty->cnt,
- tty->len - (tty->next + tty->cnt))) {
+ tty->nelem - (tty->next + tty->cnt))) {
case 0: /* EOF. */
return (INP_EOF);
case -1: /* Error or interrupt. */
diff --git a/usr.bin/vi/sex/sex_util.c b/usr.bin/vi/sex/sex_util.c
index 25eb17f049c3..70d3d6b84774 100644
--- a/usr.bin/vi/sex/sex_util.c
+++ b/usr.bin/vi/sex/sex_util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sex_util.c 8.9 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)sex_util.c 8.11 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "sex_screen.h"
@@ -73,24 +82,27 @@ int
sex_suspend(sp)
SCR *sp;
{
+ GS *gp;
struct termios t;
int rval;
/* Save ex/vi terminal settings, and restore the original ones. */
- if (F_ISSET(sp->gp, G_ISFROMTTY)) {
+ gp = sp->gp;
+ if (F_ISSET(gp, G_STDIN_TTY)) {
(void)tcgetattr(STDIN_FILENO, &t);
- (void)tcsetattr(STDIN_FILENO,
- TCSADRAIN, &sp->gp->original_termios);
+ if (F_ISSET(gp, G_TERMIOS_SET))
+ (void)tcsetattr(STDIN_FILENO,
+ TCSADRAIN, &gp->original_termios);
}
/* Kill the process group. */
- F_SET(sp->gp, G_SLEEPING);
+ F_SET(gp, G_SLEEPING);
if (rval = kill(0, SIGTSTP))
msgq(sp, M_SYSERR, "SIGTSTP");
- F_CLR(sp->gp, G_SLEEPING);
+ F_CLR(gp, G_SLEEPING);
/* Restore ex/vi terminal settings. */
- if (F_ISSET(sp->gp, G_ISFROMTTY))
+ if (F_ISSET(gp, G_STDIN_TTY))
(void)tcsetattr(STDIN_FILENO, TCSADRAIN, &t);
return (rval);
diff --git a/usr.bin/vi/svi/svi_confirm.c b/usr.bin/vi/svi/svi_confirm.c
index 01546d7d7716..316c41ef0bdb 100644
--- a/usr.bin/vi/svi/svi_confirm.c
+++ b/usr.bin/vi/svi/svi_confirm.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_confirm.c 8.5 (Berkeley) 11/29/93";
+static char sccsid[] = "@(#)svi_confirm.c 8.6 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
diff --git a/usr.bin/vi/svi/svi_ex.c b/usr.bin/vi/svi/svi_ex.c
index 7a83d409b3cd..5403b89683b7 100644
--- a/usr.bin/vi/svi/svi_ex.c
+++ b/usr.bin/vi/svi/svi_ex.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,28 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_ex.c 8.36 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)svi_ex.c 8.39 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "vcmd.h"
#include "excmd.h"
@@ -154,7 +164,7 @@ svi_ex_run(sp, ep, rp)
*/
if (F_ISSET(sp, S_MAJOR_CHANGE))
break;
-
+
/*
* If continue not required, and one or no lines, and there
* are no waiting messages, don't wait, but don't overwrite
@@ -173,7 +183,7 @@ svi_ex_run(sp, ep, rp)
/* If the screen is trashed, go into ex mode. */
if (!in_exmode && F_ISSET(sp, S_REFRESH)) {
/* Initialize the terminal state. */
- if (F_ISSET(sp->gp, G_ISFROMTTY)) {
+ if (F_ISSET(sp->gp, G_STDIN_TTY)) {
SEX_RAW(t, rawt);
get = sex_get;
} else
@@ -181,7 +191,7 @@ svi_ex_run(sp, ep, rp)
flags = TXT_CR | TXT_NLECHO | TXT_PROMPT;
in_exmode = 1;
}
-
+
/*
* If the user hasn't already indicated that they're done,
* they may continue in ex mode by entering a ':'.
@@ -221,7 +231,7 @@ svi_ex_run(sp, ep, rp)
ret: if (in_exmode) {
/* Reset the terminal state. */
- if (F_ISSET(sp->gp, G_ISFROMTTY) && SEX_NORAW(t))
+ if (F_ISSET(sp->gp, G_STDIN_TTY) && SEX_NORAW(t))
rval = 1;
F_SET(sp, S_REFRESH);
} else
diff --git a/usr.bin/vi/svi/svi_get.c b/usr.bin/vi/svi/svi_get.c
index 46f5f0e240cb..cf988dfc605d 100644
--- a/usr.bin/vi/svi/svi_get.c
+++ b/usr.bin/vi/svi/svi_get.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_get.c 8.19 (Berkeley) 1/2/94";
+static char sccsid[] = "@(#)svi_get.c 8.22 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -60,8 +70,8 @@ svi_get(sp, ep, tiqh, prompt, flags)
{
MARK save;
SMAP *esmp;
- recno_t bot_lno, top_lno;
- size_t bot_off, cnt, top_off;
+ recno_t bot_lno;
+ size_t bot_off, cnt;
int eval;
/*
@@ -74,8 +84,6 @@ svi_get(sp, ep, tiqh, prompt, flags)
*/
bot_lno = TMAP->lno;
bot_off = TMAP->off;
- top_lno = HMAP->lno;
- top_off = HMAP->off;
save.lno = sp->lno;
save.cno = sp->cno;
@@ -140,11 +148,13 @@ svi_get(sp, ep, tiqh, prompt, flags)
return (INP_ERR);
/*
- * Invalidate the cursor, the line never really existed. This fixes
- * a bug where the user searches for the last line on the screen + 1
- * and the refresh routine thinks that's where we just were.
+ * Invalidate the cursor and the line size cache, the line never
+ * really existed. This fixes bugs where the user searches for
+ * the last line on the screen + 1 and the refresh routine thinks
+ * that's where we just were.
*/
F_SET(SVP(sp), SVI_CUR_INVALID);
+ SVI_SCR_CFLUSH(SVP(sp));
return (eval ? INP_ERR : INP_OK);
}
diff --git a/usr.bin/vi/svi/svi_line.c b/usr.bin/vi/svi/svi_line.c
index 2370a0f5eea8..58710cfa0502 100644
--- a/usr.bin/vi/svi/svi_line.c
+++ b/usr.bin/vi/svi/svi_line.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,23 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_line.c 8.18 (Berkeley) 1/22/94";
+static char sccsid[] = "@(#)svi_line.c 8.22 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
@@ -165,11 +175,23 @@ svi_line(sp, ep, smp, yp, xp)
smp->c_sboff = smp->c_eboff = 0;
smp->c_scoff = smp->c_eclen = 0;
- if (p == NULL) {
- if (smp->lno != 1)
- ADDCH(listset && skip_screens == 0 ? '$' : '~');
- } else if (listset && skip_screens == 0)
- ADDCH('$');
+ /* Lots of special cases for empty lines. */
+ if (skip_screens == 0)
+ if (p == NULL) {
+ if (smp->lno == 1) {
+ if (listset) {
+ ch = '$';
+ goto empty;
+ }
+ } else {
+ ch = '~';
+ goto empty;
+ }
+ } else
+ if (listset) {
+ ch = '$';
+empty: ADDCH(ch);
+ }
clrtoeol();
MOVEA(sp, oldy, oldx);
@@ -384,9 +406,8 @@ svi_number(sp, ep)
EXF *ep;
{
SMAP *smp;
- recno_t lno;
size_t oldy, oldx;
- char *lp, *p, nbuf[10];
+ char *lp, nbuf[10];
/*
* Try and avoid getting the last line in the file, by getting the
@@ -410,7 +431,7 @@ svi_number(sp, ep)
if (ISINFOLINE(sp, smp))
break;
if (smp->lno != 1 && lp == NULL &&
- (p = file_gline(sp, ep, smp->lno, NULL)) == NULL)
+ file_gline(sp, ep, smp->lno, NULL) == NULL)
break;
MOVE(sp, smp - HMAP, 0);
(void)snprintf(nbuf, sizeof(nbuf), O_NUMBER_FMT, smp->lno);
diff --git a/usr.bin/vi/svi/svi_refresh.c b/usr.bin/vi/svi/svi_refresh.c
index 353c08178e20..b7a1df8cad0d 100644
--- a/usr.bin/vi/svi/svi_refresh.c
+++ b/usr.bin/vi/svi/svi_refresh.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_refresh.c 8.43 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)svi_refresh.c 8.49 (Berkeley) 3/11/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
@@ -72,8 +82,8 @@ svi_refresh(sp, ep)
if (svi_curses_end(sp) || svi_curses_init(sp))
return (1);
- /* Lose any svi_screens() cached information. */
- SVP(sp)->ss_lno = OOBLNO;
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(SVP(sp));
/*
* Fill the map, incidentally losing any svi_line()
@@ -150,7 +160,7 @@ svi_paint(sp, ep)
SVI_PRIVATE *svp;
recno_t lastline, lcnt;
size_t cwtotal, cnt, len, x, y;
- int ch, didpaint;
+ int ch, didpaint, leftright_warp;
char *p;
#define LNO sp->lno
@@ -159,7 +169,7 @@ svi_paint(sp, ep)
#define OCNO svp->ocno
#define SCNO svp->sc_col
- didpaint = 0;
+ didpaint = leftright_warp = 0;
svp = SVP(sp);
/*
@@ -170,14 +180,14 @@ svi_paint(sp, ep)
* displayed if the leftright flag is set.
*/
if (F_ISSET(sp, S_REFORMAT)) {
- /* Toss svi_screens() cached information. */
- SVP(sp)->ss_lno = OOBLNO;
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(SVP(sp));
/* Toss svi_line() cached information. */
if (svi_sm_fill(sp, ep, HMAP->lno, P_TOP))
return (1);
if (O_ISSET(sp, O_LEFTRIGHT) &&
- (cnt = svi_screens(sp, ep, LNO, &CNO)) != 1)
+ (cnt = svi_opt_screens(sp, ep, LNO, &CNO)) != 1)
for (smp = HMAP; smp <= TMAP; ++smp)
smp->off = cnt;
F_CLR(sp, S_REFORMAT);
@@ -209,7 +219,7 @@ svi_paint(sp, ep)
if (svi_sm_fill(sp, ep, LNO, P_BOTTOM))
return (1);
if (sp->t_rows == 1) {
- HMAP->off = svi_screens(sp, ep, LNO, &CNO);
+ HMAP->off = svi_opt_screens(sp, ep, LNO, &CNO);
goto paint;
}
F_SET(sp, S_REDRAW);
@@ -288,15 +298,16 @@ small_fill: MOVE(sp, INFOLINE(sp), 0);
}
/*
- * 3a: Line down.
+ * 3a: Line down, or current screen.
*/
if (LNO >= HMAP->lno) {
+ /* Current screen. */
if (LNO <= TMAP->lno)
goto adjust;
/*
- * If less than half a screen away, scroll down until the
- * line is on the screen.
+ * If less than half a screen above the line, scroll down
+ * until the line is on the screen.
*/
lcnt = svi_sm_nlines(sp, ep, TMAP, LNO, HALFTEXT(sp));
if (lcnt < HALFTEXT(sp)) {
@@ -305,14 +316,31 @@ small_fill: MOVE(sp, INFOLINE(sp), 0);
return (1);
goto adjust;
}
+ goto bottom;
+ }
+ /*
+ * 3b: Line up.
+ */
+ lcnt = svi_sm_nlines(sp, ep, HMAP, LNO, HALFTEXT(sp));
+ if (lcnt < HALFTEXT(sp)) {
/*
- * If less than a full screen from the bottom of the file, put
- * the last line of the file on the bottom of the screen. The
- * calculation is safe because we know there's at least one
- * full screen of lines, otherwise couldn't have gotten here.
+ * If less than half a screen below the line, scroll up until
+ * the line is the first line on the screen. Special check so
+ * that if the screen has been emptied, we refill it.
*/
- if (file_lline(sp, ep, &lastline))
+ if (file_gline(sp, ep, HMAP->lno, &len) != NULL) {
+ while (lcnt--)
+ if (svi_sm_1down(sp, ep))
+ return (1);
+ goto adjust;
+ }
+
+ /*
+ * If less than a full screen from the bottom of the file,
+ * put the last line of the file on the bottom of the screen.
+ */
+bottom: if (file_lline(sp, ep, &lastline))
return (1);
tmp.lno = LNO;
tmp.off = 1;
@@ -323,29 +351,11 @@ small_fill: MOVE(sp, INFOLINE(sp), 0);
F_SET(sp, S_REDRAW);
goto adjust;
}
-
- /*
- * If more than a full screen from the last line of the file,
- * put the new line in the middle of the screen.
- */
+ /* It's not close, just put the line in the middle. */
goto middle;
}
/*
- * 3b: Line up.
- *
- * If less than half a screen away, scroll up until the line is
- * the first line on the screen.
- */
- lcnt = svi_sm_nlines(sp, ep, HMAP, LNO, HALFTEXT(sp));
- if (lcnt < HALFTEXT(sp)) {
- while (lcnt--)
- if (svi_sm_1down(sp, ep))
- return (1);
- goto adjust;
- }
-
- /*
* If less than half a screen from the top of the file, put the first
* line of the file at the top of the screen. Otherwise, put the line
* in the middle of the screen.
@@ -378,7 +388,7 @@ middle: if (svi_sm_fill(sp, ep, LNO, P_MIDDLE))
*/
adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
(LNO == HMAP->lno || LNO == TMAP->lno)) {
- cnt = svi_screens(sp, ep, LNO, &CNO);
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO);
if (LNO == HMAP->lno && cnt < HMAP->off)
if ((HMAP->off - cnt) > HALFTEXT(sp)) {
HMAP->off = cnt;
@@ -408,14 +418,10 @@ adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
*
* Decide cursor position. If the line has changed, the cursor has
* moved over a tab, or don't know where the cursor was, reparse the
- * line. Note, if we think that the cursor "hasn't moved", reparse
- * the line. This is 'cause if it hasn't moved, we've almost always
- * lost track of it.
- *
- * Otherwise, we've just moved over fixed-width characters, and can
- * calculate the left/right scrolling and cursor movement without
- * reparsing the line. Note that we don't know which (if any) of
- * the characters between the old and new cursor positions changed.
+ * line. Otherwise, we've just moved over fixed-width characters,
+ * and can calculate the left/right scrolling and cursor movement
+ * without reparsing the line. Note that we don't know which (if any)
+ * of the characters between the old and new cursor positions changed.
*
* XXX
* With some work, it should be possible to handle tabs quickly, at
@@ -477,7 +483,7 @@ adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
goto slow;
/*
- * Quit sanity check -- it's hard to figure out exactly when
+ * Quick sanity check -- it's hard to figure out exactly when
* we cross a screen boundary as we do in the cursor right
* movement. If cnt is so large that we're going to cross the
* boundary no matter what, stop now.
@@ -507,13 +513,19 @@ adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
cwtotal -= cname[ch].len - 1;
/*
- * If the new column moved us out of the current screen,
- * calculate a new screen.
+ * If the new column moved us off of the current logical line,
+ * calculate a new one. If doing leftright scrolling, we've
+ * moved off of the current screen, as well. Since most files
+ * don't have more than two screens, we optimize moving from
+ * screen 2 to screen 1.
*/
if (SCNO < cwtotal) {
lscreen: if (O_ISSET(sp, O_LEFTRIGHT)) {
+ cnt = HMAP->off == 2 ? 1 :
+ svi_opt_screens(sp, ep, LNO, &CNO);
for (smp = HMAP; smp <= TMAP; ++smp)
- --smp->off;
+ smp->off = cnt;
+ leftright_warp = 1;
goto paint;
}
goto slow;
@@ -546,15 +558,13 @@ lscreen: if (O_ISSET(sp, O_LEFTRIGHT)) {
*/
SCNO = cwtotal;
- /*
- * If the new column moved us out of the current screen,
- * calculate a new screen.
- */
+ /* See screen change comment in section 4a. */
if (SCNO >= SCREEN_COLS(sp)) {
if (O_ISSET(sp, O_LEFTRIGHT)) {
- SCNO -= SCREEN_COLS(sp);
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO);
for (smp = HMAP; smp <= TMAP; ++smp)
- ++smp->off;
+ smp->off = cnt;
+ leftright_warp = 1;
goto paint;
}
goto slow;
@@ -582,13 +592,15 @@ fast: getyx(stdscr, y, x);
*/
slow: for (smp = HMAP; smp->lno != LNO; ++smp);
if (O_ISSET(sp, O_LEFTRIGHT)) {
- cnt = svi_screens(sp, ep, LNO, &CNO) % SCREEN_COLS(sp);
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO) % SCREEN_COLS(sp);
if (cnt != HMAP->off) {
if (ISINFOLINE(sp, smp))
smp->off = cnt;
- else
+ else {
for (smp = HMAP; smp <= TMAP; ++smp)
smp->off = cnt;
+ leftright_warp = 1;
+ }
goto paint;
}
}
@@ -679,6 +691,16 @@ number: if (O_ISSET(sp, O_NUMBER) && F_ISSET(sp, S_RENUMBER) && !didpaint) {
/* Flush it all out. */
refresh();
+ /*
+ * XXX
+ * Recalculate the "most favorite" cursor position. Vi doesn't know
+ * that we've warped the screen and it's going to have a completely
+ * wrong idea about where the cursor should be. This is vi's problem,
+ * and fixing it here is a gross violation of layering.
+ */
+ if (leftright_warp)
+ (void)svi_column(sp, ep, &sp->rcm);
+
return (0);
}
@@ -721,7 +743,7 @@ lcont: /* Move to the message line and clear it. */
* Print up to the "more" message. Avoid the last character
* in the last line, some hardware doesn't like it.
*/
- if (svi_ncols(sp, p, mp->len, NULL) < sp->cols - 1)
+ if (svi_screens(sp, sp->ep, p, mp->len, 0, NULL) < sp->cols - 1)
len = sp->cols - 1;
else
len = (sp->cols - sizeof(MCONTMSG)) - 1;
diff --git a/usr.bin/vi/svi/svi_relative.c b/usr.bin/vi/svi/svi_relative.c
index 7daa972c8575..f57fb3e70823 100644
--- a/usr.bin/vi/svi/svi_relative.c
+++ b/usr.bin/vi/svi/svi_relative.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_relative.c 8.7 (Berkeley) 12/29/93";
+static char sccsid[] = "@(#)svi_relative.c 8.12 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
@@ -62,144 +72,270 @@ svi_column(sp, ep, cp)
}
/*
- * svi_relative --
- * Return the physical column from the line that will display a
- * character closest to the currently most attractive character
- * position. If it's not easy, uses the underlying routine that
- * really figures it out. It's broken into two parts because the
- * svi_lrelative routine handles "logical" offsets, which nobody
- * but the screen routines understand.
+ * svi_opt_screens --
+ * Return the screen columns necessary to display the line, or
+ * if specified, the physical character column within the line,
+ * including space required for the O_NUMBER and O_LIST options.
*/
size_t
-svi_relative(sp, ep, lno)
+svi_opt_screens(sp, ep, lno, cnop)
SCR *sp;
EXF *ep;
recno_t lno;
+ size_t *cnop;
{
- size_t cno;
+ size_t cols, screens;
- /* First non-blank character. */
- if (sp->rcmflags == RCM_FNB) {
- cno = 0;
- (void)nonblank(sp, ep, lno, &cno);
- return (cno);
- }
+ /*
+ * Check for a cached value. We maintain a cache because, if the
+ * line is large, this routine gets called repeatedly. One other
+ * hack, lots of time the cursor is on column one, which is an easy
+ * one.
+ */
+ if (cnop == NULL) {
+ if (SVP(sp)->ss_lno == lno)
+ return (SVP(sp)->ss_screens);
+ } else if (*cnop == 0)
+ return (1);
- /* First character is easy, and common. */
- if (sp->rcmflags != RCM_LAST && sp->rcm == 0)
- return (0);
+ /* Figure out how many columns the line/column needs. */
+ cols = svi_screens(sp, ep, NULL, 0, lno, cnop);
+
+ /* Leading number if O_NUMBER option set. */
+ if (O_ISSET(sp, O_NUMBER))
+ cols += O_NUMBER_LENGTH;
+
+ /* Trailing '$' if O_LIST option set. */
+ if (O_ISSET(sp, O_LIST) && cnop == NULL)
+ cols += sp->gp->cname['$'].len;
- return (svi_lrelative(sp, ep, lno, 1));
+ screens = (cols / sp->cols + (cols % sp->cols ? 1 : 0));
+ if (screens == 0)
+ screens = 1;
+
+ /* Cache the value. */
+ if (cnop == NULL) {
+ SVP(sp)->ss_lno = lno;
+ SVP(sp)->ss_screens = screens;
+ }
+ return (screens);
}
/*
- * svi_lrelative --
- * Return the physical column from the line that will display a
- * character closest to the currently most attractive character
- * position. The offset is for the commands that move logical
- * distances, i.e. if it's a logical scroll the closest physical
- * distance is based on the logical line, not the physical line.
+ * svi_screens --
+ * Return the screen columns necessary to display the line, or,
+ * if specified, the physical character column within the line.
*/
size_t
-svi_lrelative(sp, ep, lno, off)
+svi_screens(sp, ep, lp, llen, lno, cnop)
SCR *sp;
EXF *ep;
+ char *lp;
+ size_t llen;
recno_t lno;
- size_t off;
+ size_t *cnop;
{
CHNAME const *cname;
- size_t len, llen, scno;
+ size_t chlen, cno, len, scno, tab_off;
int ch, listset;
- char *lp, *p;
+ char *p;
/* Need the line to go any further. */
- if ((lp = file_gline(sp, ep, lno, &len)) == NULL)
- return (0);
+ if (lp == NULL)
+ lp = file_gline(sp, ep, lno, &llen);
- /* Empty lines are easy. */
- if (len == 0)
+ /* Missing or empty lines are easy. */
+ if (lp == NULL || llen == 0)
return (0);
- /* Last character is easy, and common. */
- if (sp->rcmflags == RCM_LAST)
- return (len - 1);
-
- /* Discard logical lines. */
cname = sp->gp->cname;
listset = O_ISSET(sp, O_LIST);
- for (scno = 0, p = lp, llen = len; --off;) {
- for (; len && scno < sp->cols; --len)
- SCNO_INCREMENT;
- if (len == 0)
- return (llen - 1);
- scno -= sp->cols;
- }
- /* Step through the line until reach the right character. */
- while (len--) {
- SCNO_INCREMENT;
- if (scno >= sp->rcm) {
- /* Get the offset of this character. */
- len = p - lp;
-
- /*
- * May be the next character, not this one,
- * so check to see if we've gone too far.
- */
- if (scno == sp->rcm)
- return (len < llen - 1 ? len : llen - 1);
- /* It's this character. */
- return (len - 1);
+#define SET_CHLEN { \
+ chlen = (ch = *(u_char *)p++) == '\t' && \
+ !listset ? TAB_OFF(sp, tab_off) : cname[ch].len; \
+}
+#define TAB_RESET { \
+ /* \
+ * If past the end of the screen, and the character was a tab, \
+ * reset the screen column to 0. Otherwise, display the rest \
+ * of the character on the next line. \
+ */ \
+ if ((tab_off += chlen) >= sp->cols) \
+ if (ch == '\t') { \
+ tab_off = 0; \
+ scno -= scno % sp->cols; \
+ } else \
+ tab_off -= sp->cols; \
+}
+ p = lp;
+ len = llen;
+ scno = tab_off = 0;
+ if (cnop == NULL)
+ while (len--) {
+ SET_CHLEN;
+ scno += chlen;
+ TAB_RESET;
+ }
+ else
+ for (cno = *cnop; len--; --cno) {
+ SET_CHLEN;
+ scno += chlen;
+ TAB_RESET;
+ if (cno == 0)
+ break;
}
+ return (scno);
+}
+
+/*
+ * svi_rcm --
+ * Return the physical column from the line that will display a
+ * character closest to the currently most attractive character
+ * position (which is stored as a screen column).
+ */
+size_t
+svi_rcm(sp, ep, lno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+{
+ size_t cno, len;
+
+ /* First non-blank character. */
+ if (sp->rcmflags == RCM_FNB) {
+ cno = 0;
+ (void)nonblank(sp, ep, lno, &cno);
+ return (cno);
}
- /* No such character; return start of last character. */
- return (llen - 1);
+
+ /* First character is easy, and common. */
+ if (sp->rcmflags != RCM_LAST && HMAP->off == 1 && sp->rcm == 0)
+ return (0);
+
+ /* Last character is easy, and common. */
+ if (sp->rcmflags == RCM_LAST)
+ return (file_gline(sp,
+ ep, lno, &len) == NULL || len == 0 ? 0 : len - 1);
+
+ /*
+ * Get svi_cm_private() to do the hard work. If doing leftright
+ * scrolling, we use the current screen offset, otherwise, use
+ * the first screen, i.e. an offset of 1.
+ *
+ * XXX
+ * I'm not sure that an offset of 1 is right. What happens is that
+ * the vi main loop calls us for the VM_RCM case. By using an offset
+ * of 1, we're assuming that every VM_RCM command changes lines, and
+ * that we want to position on the first screen for that line. This
+ * is currently the way it works, but it's not clean. I'd prefer it if
+ * we could find the SMAP entry the cursor references, and use that
+ * screen offset. Unfortunately, that's not going to be easy, as we
+ * don't keep that information around and it may be expensive to get.
+ */
+ return (svi_cm_private(sp, ep, lno,
+ O_ISSET(sp, O_LEFTRIGHT) ? HMAP->off : 1, sp->rcm));
}
/*
- * svi_chposition --
+ * svi_cm_public --
* Return the physical column from the line that will display a
- * character closest to the specified column.
+ * character closest to the specified screen column.
+ *
+ * The extra interface is because it's called by vi, which doesn't
+ * have a handle on the SMAP structure.
*/
size_t
-svi_chposition(sp, ep, lno, cno)
+svi_cm_public(sp, ep, lno, cno)
SCR *sp;
EXF *ep;
recno_t lno;
size_t cno;
{
+ return (svi_cm_private(sp, ep, lno, HMAP->off, cno));
+}
+
+/*
+ * svi_cm_private --
+ * Return the physical column from the line that will display a
+ * character closest to the specified screen column, taking into
+ * account the screen offset.
+ *
+ * The offset is for the commands that move logical distances, i.e.
+ * if it's a logical scroll the closest physical distance is based
+ * on the logical line, not the physical line.
+ */
+size_t
+svi_cm_private(sp, ep, lno, off, cno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ size_t off, cno;
+{
CHNAME const *cname;
- size_t len, llen, scno;
+ size_t chlen, len, llen, scno, tab_off;
int ch, listset;
char *lp, *p;
/* Need the line to go any further. */
- if ((lp = file_gline(sp, ep, lno, &llen)) == NULL)
- return (0);
+ lp = file_gline(sp, ep, lno, &llen);
- /* Empty lines are easy. */
- if (llen == 0)
+ /* Missing or empty lines are easy. */
+ if (lp == NULL || llen == 0)
return (0);
- /* Step through the line until reach the right character. */
cname = sp->gp->cname;
listset = O_ISSET(sp, O_LIST);
- for (scno = 0, len = llen, p = lp; len--;) {
- SCNO_INCREMENT;
- if (scno >= cno) {
- /* Get the offset of this character. */
- len = p - lp;
-
- /*
- * May be the next character, not this one,
- * so check to see if we've gone too far.
- */
- if (scno == cno)
- return (len < llen - 1 ? len : llen - 1);
- /* It's this character. */
- return (len - 1);
+
+ /* Discard screen (logical) lines. */
+ for (scno = 0, p = lp, len = llen; --off;) {
+ while (len-- && scno < sp->cols)
+ scno += (ch = *(u_char *)p++) == '\t' &&
+ !listset ? TAB_OFF(sp, scno) : cname[ch].len;
+
+ /*
+ * If reached the end of the physical line, return
+ * the last physical character in the line.
+ */
+ if (len == 0)
+ return (llen - 1);
+
+ /*
+ * If the character was a tab, reset the screen column to 0.
+ * Otherwise, the rest of the character is displayed on the
+ * next line.
+ */
+ if (ch == '\t')
+ scno = 0;
+ else
+ scno -= sp->cols;
+ }
+
+ /* Step through the line until reach the right character or EOL. */
+ for (tab_off = scno; len--;) {
+ SET_CHLEN;
+
+ /*
+ * If we've reached the specific character, there are three
+ * cases.
+ *
+ * 1: scno == cno, i.e. the current character ends at the
+ * screen character we care about.
+ * a: off < llen - 1, i.e. not the last character in
+ * the line, return the offset of the next character.
+ * b: else return the offset of the last character.
+ * 2: scno != cno, i.e. this character overruns the character
+ * we care about, return the offset of this character.
+ */
+ if ((scno += chlen) >= cno) {
+ off = p - lp;
+ return (scno == cno ?
+ (off < llen - 1 ? off : llen - 1) : off - 1);
}
+
+ TAB_RESET;
}
- /* No such character; return start of last character. */
+
+ /* No such character; return the start of the last character. */
return (llen - 1);
}
diff --git a/usr.bin/vi/svi/svi_screen.c b/usr.bin/vi/svi/svi_screen.c
index 16e2c36d8609..71f2d36818bb 100644
--- a/usr.bin/vi/svi/svi_screen.c
+++ b/usr.bin/vi/svi/svi_screen.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,27 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_screen.c 8.57 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)svi_screen.c 8.69 (Berkeley) 3/16/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "vcmd.h"
#include "excmd.h"
@@ -52,8 +61,6 @@ static char sccsid[] = "@(#)svi_screen.c 8.57 (Berkeley) 1/9/94";
static void d_to_h __P((SCR *, char *));
static int svi_initscr_kluge __P((SCR *, struct termios *));
-static void svi_keypad __P((SCR *, int));
-static void svi_keypad_pc __P((int));
/*
* svi_screen_init --
@@ -68,10 +75,11 @@ svi_screen_init(sp)
sp->s_bg = svi_bg;
sp->s_busy = svi_busy;
sp->s_change = svi_change;
- sp->s_chposition = svi_chposition;
sp->s_clear = svi_clear;
+ sp->s_colpos = svi_cm_public;
sp->s_column = svi_column;
sp->s_confirm = svi_confirm;
+ sp->s_crel = svi_crel;
sp->s_down = svi_sm_down;
sp->s_edit = svi_screen_edit;
sp->s_end = svi_screen_end;
@@ -85,9 +93,8 @@ svi_screen_init(sp)
sp->s_optchange = svi_optchange;
sp->s_position = svi_sm_position;
sp->s_rabs = svi_rabs;
+ sp->s_rcm = svi_rcm;
sp->s_refresh = svi_refresh;
- sp->s_relative = svi_relative;
- sp->s_rrel = svi_rrel;
sp->s_split = svi_split;
sp->s_suspend = svi_suspend;
sp->s_up = svi_sm_up;
@@ -110,8 +117,8 @@ svi_screen_copy(orig, sp)
sp->svi_private = nsvi;
/* INITIALIZED AT SCREEN CREATE. */
- /* Lose svi_screens() cached information. */
- nsvi->ss_lno = OOBLNO;
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(nsvi);
/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
if (orig == NULL) {
@@ -283,7 +290,7 @@ svi_curses_init(sp)
*/
if (svi_initscr_kluge(sp, &t))
return (1);
-
+
/*
* Start the screen. Initscr() doesn't provide useful error values
* or messages. Generally, either malloc failed or the terminal
@@ -293,18 +300,18 @@ svi_curses_init(sp)
errno = 0;
if (initscr() == NULL) {
if (errno)
- msgq(sp, M_SYSERR, "initscr failed");
+ msgq(sp, M_SYSERR, "Initscr failed");
else
- msgq(sp, M_ERR, "Error: initscr failed.");
- if ((p = getenv("TERM")) == NULL)
+ msgq(sp, M_ERR, "Initscr failed.");
+ if ((p = getenv("TERM")) == NULL || !strcmp(p, "unknown"))
msgq(sp, M_ERR,
- "Error: no terminal environment variable set.");
+ "No TERM environment variable set, or TERM set to \"unknown\".");
else if (tgetent(kbuf, p) != 1)
msgq(sp, M_ERR,
-"Error: %s: unknown terminal type, or terminal lacking necessary features.", p);
+"%s: unknown terminal type, or terminal lacks necessary features.", p);
else
msgq(sp, M_ERR,
- "Error: %s: terminal type lacking necessary features.", p);
+ "%s: terminal type lacks necessary features.", p);
return (1);
}
@@ -319,9 +326,9 @@ svi_curses_init(sp)
idlok(stdscr, 1); /* Use hardware insert/delete line. */
/*
- * Vi wants the cursor keys in application mode. The historic version
- * of curses had no way to do this, and the newer versions (System V)
- * only enable it through the wgetch() interface. Do it roughly, here.
+ * Put the cursor keys into application mode. Historic versions
+ * of curses had no way to do this, and the newer versions (SunOS,
+ * System V) only enable it through the wgetch() interface.
*/
svi_keypad(sp, 1);
@@ -375,11 +382,7 @@ svi_curses_init(sp)
sp->t_maxrows = sp->rows - 1;
/* Create the screen map. */
- if ((HMAP = malloc(SIZE_HMAP(sp) * sizeof(SMAP))) == NULL) {
- msgq(sp, M_SYSERR, NULL);
- return (1);
- }
- memset(HMAP, 0, SIZE_HMAP(sp) * sizeof(SMAP));
+ CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
TMAP = HMAP + (sp->t_rows - 1);
F_SET(sp->gp, G_CURSES_INIT); /* Curses initialized. */
@@ -388,11 +391,11 @@ svi_curses_init(sp)
}
/*
- * svi_rrel --
+ * svi_crel --
* Change the relative size of the current screen.
*/
int
-svi_rrel(sp, count)
+svi_crel(sp, count)
SCR *sp;
long count;
{
@@ -436,45 +439,13 @@ svi_curses_end(sp)
TCSASOFT | TCSADRAIN, &sp->gp->s5_curses_botch);
F_CLR(sp->gp, G_CURSES_S5CB);
+ /* Restore the cursor keys to normal mode. */
svi_keypad(sp, 0);
endwin();
return (0);
}
/*
- * svi_keypad --
- * Put the keypad/cursor arrows into or out of application mode.
- */
-static void
-svi_keypad(sp, on)
- SCR *sp;
- int on;
-{
- char *sbp, *t, kbuf[2048], sbuf[128];
-
- if (tgetent(kbuf, O_STR(sp, O_TERM)) != 1)
- return;
- sbp = sbuf;
- if ((t = tgetstr(on ? "ks" : "ke", &sbp)) == NULL)
- return;
- (void)tputs(t, 0, svi_keypad_pc);
-}
-
-/*
- * svi_keypad_pc --
- * putchar routine for tputs().
- */
-static void
-svi_keypad_pc(argch)
- int argch;
-{
- char ch;
-
- ch = argch;
- (void)write(STDOUT_FILENO, &ch, sizeof(ch));
-}
-
-/*
* svi_initscr_kluge --
* Read all of the waiting keys before calling initscr().
*/
@@ -520,8 +491,10 @@ d_to_h(sp, emsg)
for (hidden = 0;
(tsp = sp->gp->dq.cqh_first) != (void *)&sp->gp->dq; ++hidden) {
- if (_HMAP(tsp) != NULL)
+ if (_HMAP(tsp) != NULL) {
FREE(_HMAP(tsp), SIZE_HMAP(tsp) * sizeof(SMAP));
+ _HMAP(tsp) = NULL;
+ }
CIRCLEQ_REMOVE(&sp->gp->dq, tsp, q);
CIRCLEQ_INSERT_TAIL(&sp->gp->hq, tsp, q);
}
diff --git a/usr.bin/vi/svi/svi_screen.h b/usr.bin/vi/svi/svi_screen.h
index 4bf754473df9..05ae068ccbb8 100644
--- a/usr.bin/vi/svi/svi_screen.h
+++ b/usr.bin/vi/svi/svi_screen.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)svi_screen.h 8.30 (Berkeley) 12/22/93
+ * @(#)svi_screen.h 8.38 (Berkeley) 3/15/94
*/
/*
@@ -76,7 +76,8 @@ typedef struct _svi_private {
size_t extotalcount; /* Ex overwrite count. */
size_t exlcontinue; /* Ex line continue value. */
- /* svi_screens() cache information. */
+ /* svi_opt_screens() cache information. */
+#define SVI_SCR_CFLUSH(svp) svp->ss_lno = OOBLNO
recno_t ss_lno; /* 1-N: Line number. */
size_t ss_screens; /* Return value. */
@@ -124,14 +125,18 @@ typedef struct _svi_private {
/* Small screen test. */
#define ISSMALLSCREEN(sp) ((sp)->t_minrows != (sp)->t_maxrows)
- /* Next tab offset. */
+/*
+ * Next tab offset.
+ *
+ * !!!
+ * There are problems with how the historical vi handled tabs. For example,
+ * by doing "set ts=3" and building lines that fold, you can get it to step
+ * through tabs as if they were spaces and move inserted characters to new
+ * positions when <esc> is entered. I think that nvi does tabs correctly,
+ * but there may be some historical incompatibilities.
+ */
#define TAB_OFF(sp, c) (O_VAL(sp, O_TABSTOP) - (c) % O_VAL(sp, O_TABSTOP))
-
-#define SCNO_INCREMENT /* Step through line. */\
- scno += (ch = *(u_char *)p++) == '\t' && !listset ? \
- TAB_OFF(sp, scno) : cname[ch].len
-
/* Move in a screen (absolute), and fail if it doesn't work. */
#define MOVEA(sp, lno, cno) { \
if (move(lno, cno) == ERR) { \
@@ -186,11 +191,12 @@ void svi_bell __P((SCR *));
int svi_bg __P((SCR *));
int svi_busy __P((SCR *, char const *));
int svi_change __P((SCR *, EXF *, recno_t, enum operation));
-size_t svi_chposition __P((SCR *, EXF *, recno_t, size_t));
+size_t svi_cm_public __P((SCR *, EXF *, recno_t, size_t));
int svi_column __P((SCR *, EXF *, size_t *));
enum confirm
svi_confirm __P((SCR *, EXF *, MARK *, MARK *));
int svi_clear __P((SCR *));
+int svi_crel __P((SCR *, long));
int svi_ex_cmd __P((SCR *, EXF *, struct _excmdarg *, MARK *));
int svi_ex_run __P((SCR *, EXF *, MARK *));
int svi_ex_write __P((void *, const char *, int));
@@ -198,10 +204,9 @@ int svi_fg __P((SCR *, CHAR_T *));
enum input
svi_get __P((SCR *, EXF *, TEXTH *, int, u_int));
int svi_optchange __P((SCR *, int));
-int svi_rabs __P((SCR *, long));
+int svi_rabs __P((SCR *, long, enum adjust));
+size_t svi_rcm __P((SCR *, EXF *, recno_t));
int svi_refresh __P((SCR *, EXF *));
-size_t svi_relative __P((SCR *, EXF *, recno_t));
-int svi_rrel __P((SCR *, long));
int svi_screen_copy __P((SCR *, SCR *));
int svi_screen_edit __P((SCR *, EXF *));
int svi_screen_end __P((SCR *));
@@ -214,17 +219,19 @@ int svi_suspend __P((SCR *));
int svi_swap __P((SCR *, SCR **, char *));
/* Private routines. */
+size_t svi_cm_private __P((SCR *, EXF *, recno_t, size_t, size_t));
int svi_curses_end __P((SCR *));
int svi_curses_init __P((SCR *));
int svi_divider __P((SCR *));
int svi_init __P((SCR *));
int svi_join __P((SCR *, SCR **));
+void svi_keypad __P((SCR *, int));
int svi_line __P((SCR *, EXF *, SMAP *, size_t *, size_t *));
-size_t svi_lrelative __P((SCR *, EXF *, recno_t, size_t));
-size_t svi_ncols __P((SCR *, u_char *, size_t, size_t *));
int svi_number __P((SCR *, EXF *));
+size_t svi_opt_screens __P((SCR *, EXF *, recno_t, size_t *));
int svi_paint __P((SCR *, EXF *));
-size_t svi_screens __P((SCR *, EXF *, recno_t, size_t *));
+int svi_putchar __P((int));
+size_t svi_screens __P((SCR *, EXF *, char *, size_t, recno_t, size_t *));
int svi_sm_1down __P((SCR *, EXF *));
int svi_sm_1up __P((SCR *, EXF *));
int svi_sm_cursor __P((SCR *, EXF *, SMAP **));
diff --git a/usr.bin/vi/svi/svi_smap.c b/usr.bin/vi/svi/svi_smap.c
index 5bcb6e220f3d..3e2ac3812e89 100644
--- a/usr.bin/vi/svi/svi_smap.c
+++ b/usr.bin/vi/svi/svi_smap.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_smap.c 8.29 (Berkeley) 11/30/93";
+static char sccsid[] = "@(#)svi_smap.c 8.37 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -107,13 +117,13 @@ svi_change(sp, ep, lno, op)
F_SET(SVP(sp), SVI_SCREENDIRTY);
- /* Flush cached information from svi_screens(). */
- SVP(sp)->ss_lno = OOBLNO;
-
/* Invalidate the cursor, if it's on this line. */
if (sp->lno == lno)
F_SET(SVP(sp), SVI_CUR_INVALID);
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(SVP(sp));
+
getyx(stdscr, oldy, oldx);
switch (op) {
@@ -160,10 +170,10 @@ svi_sm_fill(sp, ep, lno, pos)
enum position pos;
{
SMAP *p, tmp;
-
+
/* Flush all cached information from the SMAP. */
for (p = HMAP; p <= TMAP; ++p)
- SMAP_FLUSH(p);
+ SMAP_FLUSH(p);
switch (pos) {
case P_FILL:
@@ -180,7 +190,7 @@ svi_sm_fill(sp, ep, lno, pos)
/* See if less than half a screen from the bottom. */
if (file_lline(sp, ep, &tmp.lno))
return (1);
- tmp.off = svi_screens(sp, ep, tmp.lno, NULL);
+ tmp.off = svi_opt_screens(sp, ep, tmp.lno, NULL);
if (svi_sm_nlines(sp, ep,
&tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) {
TMAP->lno = tmp.lno;
@@ -216,7 +226,7 @@ middle: p = HMAP + (TMAP - HMAP) / 2;
case P_BOTTOM:
if (lno != OOBLNO) {
TMAP->lno = lno;
- TMAP->off = svi_screens(sp, ep, lno, NULL);
+ TMAP->off = svi_opt_screens(sp, ep, lno, NULL);
}
/* If we fail, guess that the file is too small. */
bottom: for (p = TMAP; p > HMAP; --p)
@@ -278,9 +288,12 @@ svi_sm_delete(sp, ep, lno)
* Find the line in the map, and count the number of screen lines
* which display any part of the deleted line.
*/
- for (p = HMAP; p->lno != lno; ++p);
- for (cnt_orig = 1, t = p + 1;
- t <= TMAP && t->lno == lno; ++cnt_orig, ++t);
+ for (p = HMAP; p->lno != lno; ++p);
+ if (O_ISSET(sp, O_LEFTRIGHT))
+ cnt_orig = 1;
+ else
+ for (cnt_orig = 1, t = p + 1;
+ t <= TMAP && t->lno == lno; ++cnt_orig, ++t);
TOO_WEIRD;
@@ -288,7 +301,7 @@ svi_sm_delete(sp, ep, lno)
MOVE(sp, p - HMAP, 0);
if (svi_deleteln(sp, cnt_orig))
return (1);
-
+
/* Shift the screen map up. */
memmove(p, p + cnt_orig, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP));
@@ -326,8 +339,11 @@ svi_sm_insert(sp, ep, lno)
* Find the line in the map, find out how many screen lines
* needed to display the line.
*/
- for (p = HMAP; p->lno != lno; ++p);
- cnt_orig = svi_screens(sp, ep, lno, NULL);
+ for (p = HMAP; p->lno != lno; ++p);
+ if (O_ISSET(sp, O_LEFTRIGHT))
+ cnt_orig = 1;
+ else
+ cnt_orig = svi_opt_screens(sp, ep, lno, NULL);
TOO_WEIRD;
@@ -380,9 +396,15 @@ svi_sm_reset(sp, ep, lno)
* for the line is the same as the number needed for the new one.
* If so, repaint, otherwise do it the hard way.
*/
- for (p = HMAP; p->lno != lno; ++p);
- for (cnt_orig = 0, t = p; t <= TMAP && t->lno == lno; ++cnt_orig, ++t);
- cnt_new = svi_screens(sp, ep, lno, NULL);
+ for (p = HMAP; p->lno != lno; ++p);
+ if (O_ISSET(sp, O_LEFTRIGHT)) {
+ t = p;
+ cnt_orig = cnt_new = 1;
+ } else {
+ for (cnt_orig = 0,
+ t = p; t <= TMAP && t->lno == lno; ++cnt_orig, ++t);
+ cnt_new = svi_opt_screens(sp, ep, lno, NULL);
+ }
TOO_WEIRD;
@@ -431,7 +453,7 @@ svi_sm_reset(sp, ep, lno)
MOVE(sp, p - HMAP, 0);
if (svi_deleteln(sp, diff))
return (1);
-
+
/* Shift the screen map up. */
memmove(p, p + diff, (((TMAP - p) - diff) + 1) * sizeof(SMAP));
@@ -514,7 +536,7 @@ svi_sm_up(sp, ep, rp, count, cursor_move)
return (1);
if (tmp.lno > TMAP->lno &&
!file_gline(sp, ep, tmp.lno, NULL) ||
- tmp.off > svi_screens(sp, ep, tmp.lno, NULL)) {
+ tmp.off > svi_opt_screens(sp, ep, tmp.lno, NULL)) {
if (!cursor_move || ignore_cursor || p == TMAP) {
v_eof(sp, ep, NULL);
return (1);
@@ -522,12 +544,12 @@ svi_sm_up(sp, ep, rp, count, cursor_move)
if (svi_sm_next(sp, ep, p, &tmp))
return (1);
if (!file_gline(sp, ep, tmp.lno, NULL) ||
- tmp.off > svi_screens(sp, ep, tmp.lno, NULL)) {
+ tmp.off > svi_opt_screens(sp, ep, tmp.lno, NULL)) {
v_eof(sp, ep, NULL);
return (1);
}
}
-
+
/*
* Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
*
@@ -570,7 +592,7 @@ svi_sm_up(sp, ep, rp, count, cursor_move)
/* If the line doesn't exist, we're done. */
if (TMAP->lno != tmp.lno && !file_gline(sp, ep, tmp.lno, NULL))
break;
-
+
/* Scroll the screen cursor up one logical line. */
if (svi_sm_1up(sp, ep))
return (1);
@@ -616,7 +638,7 @@ svi_sm_up(sp, ep, rp, count, cursor_move)
*/
if (p->lno != svmap.lno || p->off != svmap.off) {
rp->lno = p->lno;
- rp->cno = svi_lrelative(sp, ep, p->lno, p->off);
+ rp->cno = svi_cm_private(sp, ep, p->lno, p->off, sp->rcm);
}
return (0);
}
@@ -762,7 +784,7 @@ svi_sm_down(sp, ep, rp, count, cursor_move)
/* If the line doesn't exist, we're done. */
if (HMAP->lno == 1 && HMAP->off == 1)
break;
-
+
/* Scroll the screen and cursor down one logical line. */
if (svi_sm_1down(sp, ep))
return (1);
@@ -804,7 +826,7 @@ svi_sm_down(sp, ep, rp, count, cursor_move)
*/
if (p->lno != svmap.lno || p->off != svmap.off) {
rp->lno = p->lno;
- rp->cno = svi_lrelative(sp, ep, p->lno, p->off);
+ rp->cno = svi_cm_private(sp, ep, p->lno, p->off, sp->rcm);
}
return (0);
}
@@ -876,7 +898,7 @@ svi_sm_next(sp, ep, p, t)
t->lno = p->lno + 1;
t->off = p->off;
} else {
- lcnt = svi_screens(sp, ep, p->lno, NULL);
+ lcnt = svi_opt_screens(sp, ep, p->lno, NULL);
if (lcnt == p->off) {
t->lno = p->lno + 1;
t->off = 1;
@@ -907,7 +929,7 @@ svi_sm_prev(sp, ep, p, t)
t->off = p->off - 1;
} else {
t->lno = p->lno - 1;
- t->off = svi_screens(sp, ep, t->lno, NULL);
+ t->off = svi_opt_screens(sp, ep, t->lno, NULL);
}
return (t->lno == 0);
}
@@ -969,34 +991,66 @@ svi_sm_position(sp, ep, rp, cnt, pos)
{
SMAP *smp;
recno_t last;
-
+
switch (pos) {
case P_TOP:
+ /*
+ * !!!
+ * Historically, an invalid count to the H command failed.
+ * We do nothing special here, just making sure that H in
+ * an empty screen works.
+ */
if (cnt > TMAP - HMAP)
- goto err;
+ goto sof;
smp = HMAP + cnt;
+ if (cnt && file_gline(sp, ep, smp->lno, NULL) == NULL) {
+sof: msgq(sp, M_BERR, "Movement past the end-of-screen.");
+ return (1);
+ }
break;
case P_MIDDLE:
- if (cnt > (TMAP - HMAP) / 2)
- goto err;
- smp = (HMAP + (TMAP - HMAP) / 2) + cnt;
- goto eof;
+ /*
+ * !!!
+ * Historically, a count to the M command was ignored.
+ * If the screen isn't filled, find the middle of what's
+ * real and move there.
+ */
+ if (file_gline(sp, ep, TMAP->lno, NULL) == NULL) {
+ if (file_lline(sp, ep, &last))
+ return (1);
+ for (smp = TMAP; smp->lno > last && smp > HMAP; --smp);
+ if (smp > HMAP)
+ smp -= (smp - HMAP) / 2;
+ } else
+ smp = (HMAP + (TMAP - HMAP) / 2) + cnt;
+ break;
case P_BOTTOM:
- if (cnt > TMAP - HMAP) {
-err: msgq(sp, M_BERR, "Movement past the end-of-screen.");
- return (1);
- }
+ /*
+ * !!!
+ * Historically, an invalid count to the L command failed.
+ * If the screen isn't filled, find the bottom of what's
+ * real and try to offset from there.
+ */
+ if (cnt > TMAP - HMAP)
+ goto eof;
smp = TMAP - cnt;
-eof: if (file_gline(sp, ep, smp->lno, NULL) == NULL) {
+ if (file_gline(sp, ep, smp->lno, NULL) == NULL) {
if (file_lline(sp, ep, &last))
return (1);
for (; smp->lno > last && smp > HMAP; --smp);
+ if (cnt > smp - HMAP) {
+eof: msgq(sp, M_BERR,
+ "Movement past the beginning-of-screen.");
+ return (1);
+ }
+ smp -= cnt;
}
break;
default:
abort();
}
+ /* Make sure that the cached information is valid. */
if (!SMAP_CACHE(smp) && svi_line(sp, ep, smp, NULL, NULL))
return (1);
rp->lno = smp->lno;
@@ -1030,12 +1084,12 @@ svi_sm_nlines(sp, ep, from_sp, to_lno, max)
if (from_sp->lno > to_lno) {
lcnt = from_sp->off - 1; /* Correct for off-by-one. */
for (lno = from_sp->lno; --lno >= to_lno && lcnt <= max;)
- lcnt += svi_screens(sp, ep, lno, NULL);
+ lcnt += svi_opt_screens(sp, ep, lno, NULL);
} else {
lno = from_sp->lno;
- lcnt = (svi_screens(sp, ep, lno, NULL) - from_sp->off) + 1;
+ lcnt = (svi_opt_screens(sp, ep, lno, NULL) - from_sp->off) + 1;
for (; ++lno < to_lno && lcnt <= max;)
- lcnt += svi_screens(sp, ep, lno, NULL);
+ lcnt += svi_opt_screens(sp, ep, lno, NULL);
}
return (lcnt);
}
diff --git a/usr.bin/vi/svi/svi_split.c b/usr.bin/vi/svi/svi_split.c
index f6be03d38365..2c1a6c063eac 100644
--- a/usr.bin/vi/svi/svi_split.c
+++ b/usr.bin/vi/svi/svi_split.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_split.c 8.29 (Berkeley) 12/22/93";
+static char sccsid[] = "@(#)svi_split.c 8.36 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "svi_screen.h"
@@ -72,7 +82,7 @@ svi_split(sp, argv)
/* Get a new screen. */
if (screen_init(sp, &tsp, 0))
return (1);
- MALLOC(sp, _HMAP(tsp), SMAP *, SIZE_HMAP(sp) * sizeof(SMAP));
+ CALLOC(sp, _HMAP(tsp), SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
if (_HMAP(tsp) == NULL)
return (1);
@@ -100,7 +110,7 @@ svi_split(sp, argv)
* The columns in the screen don't change.
*/
tsp->cols = sp->cols;
-
+
cnt = svi_sm_cursor(sp, sp->ep, &smp) ? 0 : smp - HMAP;
if (cnt <= half) { /* Parent is top half. */
/* Child. */
@@ -431,7 +441,7 @@ svi_swap(csp, nsp, name)
return (0);
}
*nsp = sp;
-
+
/* Save the old screen's cursor information. */
csp->frp->lno = csp->lno;
csp->frp->cno = csp->cno;
@@ -485,7 +495,7 @@ svi_swap(csp, nsp, name)
* a bunch of screens had to be hidden.
*/
if (HMAP == NULL)
- MALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp) * sizeof(SMAP));
+ CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
TMAP = HMAP + (sp->t_rows - 1);
/* Fill the map. */
@@ -510,9 +520,10 @@ svi_swap(csp, nsp, name)
* Change the absolute size of the current screen.
*/
int
-svi_rabs(sp, count)
+svi_rabs(sp, count, adj)
SCR *sp;
long count;
+ enum adjust adj;
{
SCR *g, *s;
@@ -522,8 +533,20 @@ svi_rabs(sp, count)
*/
if (count == 0)
return (0);
- if (count < 0) {
- count = -count;
+ if (adj == A_SET) {
+ if (sp->t_maxrows == count)
+ return (0);
+ if (sp->t_maxrows > count) {
+ adj = A_DECREASE;
+ count = sp->t_maxrows - count;
+ } else {
+ adj = A_INCREASE;
+ count = count - sp->t_maxrows;
+ }
+ }
+ if (adj == A_DECREASE) {
+ if (count < 0)
+ count = -count;
s = sp;
if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count)
goto toosmall;
@@ -545,7 +568,7 @@ svi_rabs(sp, count)
if (s == NULL) {
if ((s = sp->q.cqe_prev) == (void *)&sp->gp->dq) {
toobig: msgq(sp, M_BERR, "The screen cannot %s.",
- count < 0 ? "shrink" : "grow");
+ adj == A_DECREASE ? "shrink" : "grow");
return (1);
}
if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) {
@@ -558,24 +581,28 @@ toosmall: msgq(sp, M_BERR,
}
}
- /* Update the screens. */
+ /*
+ * Update the screens; we could optimize the reformatting of the
+ * screen, but this isn't likely to be a common enough operation
+ * to make it worthwhile.
+ */
g->rows += count;
g->t_rows += count;
if (g->t_minrows == g->t_maxrows)
g->t_minrows += count;
g->t_maxrows += count;
- _TMAP(g) = _HMAP(g) + (g->t_rows - 1);
+ _TMAP(g) += count;
(void)status(g, g->ep, g->lno, 0);
- F_SET(g, S_REDRAW);
+ F_SET(g, S_REFORMAT);
s->rows -= count;
s->t_rows -= count;
s->t_maxrows -= count;
if (s->t_minrows > s->t_maxrows)
s->t_minrows = s->t_maxrows;
- _TMAP(s) = _HMAP(s) + (s->t_rows - 1);
+ _TMAP(s) -= count;
(void)status(s, s->ep, s->lno, 0);
- F_SET(s, S_REDRAW);
+ F_SET(s, S_REFORMAT);
return (0);
}
diff --git a/usr.bin/vi/svi/svi_util.c b/usr.bin/vi/svi/svi_util.c
index 0da531d8db26..ac655007f58e 100644
--- a/usr.bin/vi/svi/svi_util.c
+++ b/usr.bin/vi/svi/svi_util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,115 +32,33 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)svi_util.c 8.26 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)svi_util.c 8.33 (Berkeley) 3/10/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
-#include "vcmd.h"
+#include "../vi/vcmd.h"
#include "excmd.h"
#include "svi_screen.h"
/*
- * svi_screens --
- * Return the number of screens required by the line, or,
- * if a column is specified, by the column within the line.
- */
-size_t
-svi_screens(sp, ep, lno, cnop)
- SCR *sp;
- EXF *ep;
- recno_t lno;
- size_t *cnop;
-{
- size_t cols, len, screens;
- char *p;
-
- /*
- * Check for single cached value. The cache is because, if
- * the line is large, this routine gets called repeatedly.
- * One other hack, lots of time the user is on column one,
- * which is an easy one.
- */
- if (cnop == NULL) {
- if (SVP(sp)->ss_lno == lno)
- return (SVP(sp)->ss_screens);
- } else if (*cnop == 0)
- return (1);
-
- /* Get a copy of the line. */
- if ((p = file_gline(sp, ep, lno, &len)) == NULL || len == 0)
- return (1);
-
- /* Figure out how many columns the line/column needs. */
- cols = svi_ncols(sp, p, len, cnop);
-
- /* Leading number if O_NUMBER option set. */
- if (O_ISSET(sp, O_NUMBER))
- cols += O_NUMBER_LENGTH;
-
- /* Trailing '$' if O_LIST option set. */
- if (O_ISSET(sp, O_LIST) && cnop == NULL)
- cols += sp->gp->cname['$'].len;
-
- screens = (cols / sp->cols + (cols % sp->cols ? 1 : 0));
- if (cnop == NULL) {
- SVP(sp)->ss_lno = lno;
- SVP(sp)->ss_screens = screens;
- }
- return (screens);
-}
-
-/*
- * svi_ncols --
- * Return the number of columns required by the line, or,
- * if a column is specified, by the column within the line.
- */
-size_t
-svi_ncols(sp, p, len, cnop)
- SCR *sp;
- u_char *p;
- size_t len, *cnop;
-{
- CHNAME const *cname;
- size_t cno_cnt, scno;
- int ch, listset;
-
- cname = sp->gp->cname;
- listset = O_ISSET(sp, O_LIST);
-
- if (cnop == NULL)
- for (scno = 0; len; --len)
- SCNO_INCREMENT;
- else
- for (cno_cnt = *cnop, scno = 0; len; --len) {
- SCNO_INCREMENT;
- if (cno_cnt == 0)
- break;
- --cno_cnt;
- }
- return (scno);
-}
-
-/*
- * bell_putchar --
- * Functional version of putchar, for tputs.
- */
-static void
-bell_putchar(ch)
- int ch;
-{
- (void)putchar(ch);
-}
-
-/*
* vbell --
* Set up the visual bell information. Broken out into a
* separate routine so don't allocate 4K every time we beep.
@@ -166,12 +84,15 @@ vbell(sp)
"No visual bell for %s terminal type", s);
return (1);
}
- len = t - b2;
+ if ((len = t - b2) == 0)
+ return (1);
+
+ /* Free the old one, save the new one. */
MALLOC_RET(sp, s, char *, len);
memmove(s, b2, len);
if (SVP(sp)->VB != NULL)
free(SVP(sp)->VB);
- SVP(sp)->VB = t;
+ SVP(sp)->VB = s;
return (0);
}
@@ -185,7 +106,7 @@ svi_bell(sp)
{
if (O_ISSET(sp, O_FLASH) && !F_ISSET(SVP(sp), SVI_NO_VBELL))
if (SVP(sp)->VB != NULL) {
- (void)tputs(SVP(sp)->VB, 1, bell_putchar);
+ (void)tputs(SVP(sp)->VB, 1, svi_putchar);
(void)fflush(stdout);
} else {
if (vbell(sp))
@@ -217,7 +138,7 @@ svi_optchange(sp, opt)
F_SET(sp, S_RESIZE);
break;
case O_WINDOW:
- if (svi_rrel(sp, O_VAL(sp, O_WINDOW)))
+ if (svi_crel(sp, O_VAL(sp, O_WINDOW)))
return (1);
break;
}
@@ -237,17 +158,44 @@ svi_busy(sp, msg)
SCR *sp;
char const *msg;
{
- MOVE(sp, INFOLINE(sp), 0);
- if (msg) {
- ADDSTR(msg);
- clrtoeol();
+ /*
+ * search.c:f_search() is called from ex/ex_tag.c:ex_tagfirst(),
+ * which runs before the screen really exists. Make sure we don't
+ * step on anything.
+ */
+ if (F_ISSET(sp->gp, G_CURSES_INIT)) {
+ MOVE(sp, INFOLINE(sp), 0);
+ if (msg) {
+ ADDSTR(msg);
+ clrtoeol();
+ }
+ refresh();
+ F_SET(SVP(sp), SVI_CUR_INVALID);
}
- refresh();
- F_SET(SVP(sp), SVI_CUR_INVALID);
return (0);
}
/*
+ * svi_keypad --
+ * Put the keypad/cursor arrows into or out of application mode.
+ */
+void
+svi_keypad(sp, on)
+ SCR *sp;
+ int on;
+{
+ char *sbp, *t, kbuf[2048], sbuf[128];
+
+ if (tgetent(kbuf, O_STR(sp, O_TERM)) != 1)
+ return;
+ sbp = sbuf;
+ if ((t = tgetstr(on ? "ks" : "ke", &sbp)) == NULL)
+ return;
+ (void)tputs(t, 0, svi_putchar);
+ (void)fflush(stdout);
+}
+
+/*
* svi_clear --
* Clear from the row down to the end of the screen.
*/
@@ -279,6 +227,9 @@ svi_suspend(sp)
struct termios t;
int rval;
+ /* Restore the cursor keys to normal mode. */
+ svi_keypad(sp, 0);
+
/*
* XXX
* See comment in svi_curses_init().
@@ -297,10 +248,24 @@ svi_suspend(sp)
if (F_ISSET(sp->gp, G_CURSES_S5CB))
(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
+ /* Put the cursor keys into application mode. */
+ svi_keypad(sp, 0);
+
return (rval);
}
/*
+ * svi_putchar --
+ * Functional version of putchar, for tputs.
+ */
+int
+svi_putchar(ch)
+ int ch;
+{
+ return putchar(ch);
+}
+
+/*
* svi_gdbrefresh --
* Stub routine so can flush out screen changes using gdb.
*/
diff --git a/usr.bin/vi/term.c b/usr.bin/vi/term.c
index d23fa80c4d45..ba7b016f3d85 100644
--- a/usr.bin/vi/term.c
+++ b/usr.bin/vi/term.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,23 +32,33 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)term.c 8.41 (Berkeley) 1/23/94";
+static char sccsid[] = "@(#)term.c 8.56 (Berkeley) 3/23/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "seq.h"
-static int keycmp __P((const void *, const void *));
+static int keycmp __P((const void *, const void *));
+static void termkeyset __P((GS *, int, int));
/*
* If we're reading less than 20 characters, up the size of the tty buffer.
@@ -56,39 +66,67 @@ static int keycmp __P((const void *, const void *));
* possible if a map is large enough.
*/
#define term_read_grow(sp, tty) \
- (tty)->len - (tty)->cnt >= 20 ? 0 : __term_read_grow(sp, tty)
-static int __term_read_grow __P((SCR *, IBUF *));
+ (tty)->nelem - (tty)->cnt >= 20 ? 0 : __term_read_grow(sp, tty, 64)
+static int __term_read_grow __P((SCR *, IBUF *, int));
/*
* XXX
* THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE.
*/
typedef struct _tklist {
- char *ts; /* Key's termcap string. */
- char *output; /* Corresponding vi command. */
- char *name; /* Name. */
+ char *ts; /* Key's termcap string. */
+ char *output; /* Corresponding vi command. */
+ char *name; /* Name. */
+ u_char value; /* Special value (for lookup). */
} TKLIST;
-static TKLIST const tklist[] = {
- {"kA", "O", "insert line"},
- {"kD", "x", "delete character"},
- {"kd", "j", "cursor down"},
- {"kE", "D", "delete to eol"},
- {"kF", "\004", "scroll down"},
- {"kH", "$", "go to eol"},
- {"kh", "^", "go to sol"},
- {"kI", "i", "insert at cursor"},
- {"kL", "dd", "delete line"},
- {"kl", "h", "cursor left"},
- {"kN", "\006", "page down"},
- {"kP", "\002", "page up"},
- {"kR", "\025", "scroll up"},
- {"kS", "dG", "delete to end of screen"},
- {"kr", "l", "cursor right"},
- {"ku", "k", "cursor up"},
+static TKLIST const c_tklist[] = { /* Command mappings. */
+ {"kA", "O", "insert line"},
+ {"kD", "x", "delete character"},
+ {"kd", "j", "cursor down"},
+ {"kE", "D", "delete to eol"},
+ {"kF", "\004", "scroll down"},
+ {"kH", "$", "go to eol"},
+ {"kh", "^", "go to sol"},
+ {"kI", "i", "insert at cursor"},
+ {"kL", "dd", "delete line"},
+ {"kl", "h", "cursor left"},
+ {"kN", "\006", "page down"},
+ {"kP", "\002", "page up"},
+ {"kR", "\025", "scroll up"},
+ {"kS", "dG", "delete to end of screen"},
+ {"kr", "l", "cursor right"},
+ {"ku", "k", "cursor up"},
+ {NULL},
+};
+static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */
+ {"kl", NULL, "cursor erase", K_VERASE},
+ {NULL},
+};
+static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */
+ {"kd", NULL, "cursor down"},
+ {"ku", NULL, "cursor up"},
+ {"kr", " ", "cursor space"},
{NULL},
};
/*
+ * !!!
+ * Historic ex/vi always used:
+ *
+ * ^D: autoindent deletion
+ * ^H: last character deletion
+ * ^W: last word deletion
+ * ^Q: quote the next character (if not used in flow control).
+ * ^V: quote the next character
+ *
+ * regardless of the user's choices for these characters. The user's erase
+ * and kill characters worked in addition to these characters. Ex was not
+ * completely consistent with this scheme, as it did map the scroll command
+ * to the user's current EOF character. This implementation wires down the
+ * above characters, but in addition uses the VERASE, VINTR, VKILL and VWERASE
+ * characters described by the user's termios structure. We don't do the EOF
+ * mapping for ex, but I think I'm unlikely to get caught on that one.
+ *
* XXX
* THIS REQUIRES THAT ALL SCREENS SHARE A SPECIAL KEY SET.
*/
@@ -97,26 +135,32 @@ typedef struct _keylist {
CHAR_T ch; /* Key. */
} KEYLIST;
static KEYLIST keylist[] = {
- {K_CARAT, '^'},
- {K_CNTRLR, '\022'},
- {K_CNTRLT, '\024'},
- {K_CNTRLZ, '\032'},
- {K_COLON, ':'},
- {K_CR, '\r'},
- {K_ESCAPE, '\033'},
- {K_FORMFEED, '\f'},
- {K_NL, '\n'},
- {K_RIGHTBRACE, '}'},
- {K_RIGHTPAREN, ')'},
- {K_TAB, '\t'},
- {K_VEOF, '\004'},
- {K_VERASE, '\b'},
- {K_VINTR, '\003'},
- {K_VKILL, '\025'},
- {K_VLNEXT, '\026'},
- {K_VWERASE, '\027'},
- {K_ZERO, '0'},
+ {K_CARAT, '^'}, /* ^ */
+ {K_CNTRLD, '\004'}, /* ^D */
+ {K_CNTRLR, '\022'}, /* ^R */
+ {K_CNTRLT, '\024'}, /* ^T */
+ {K_CNTRLZ, '\032'}, /* ^Z */
+ {K_COLON, ':'}, /* : */
+ {K_CR, '\r'}, /* \r */
+ {K_ESCAPE, '\033'}, /* ^[ */
+ {K_FORMFEED, '\f'}, /* \f */
+ {K_NL, '\n'}, /* \n */
+ {K_RIGHTBRACE, '}'}, /* } */
+ {K_RIGHTPAREN, ')'}, /* ) */
+ {K_TAB, '\t'}, /* \t */
+ {K_VERASE, '\b'}, /* \b */
+ {K_VINTR, '\003'}, /* ^C */
+ {K_VKILL, '\025'}, /* ^U */
+ {K_VLNEXT, '\021'}, /* ^Q */
+ {K_VLNEXT, '\026'}, /* ^V */
+ {K_VWERASE, '\027'}, /* ^W */
+ {K_ZERO, '0'}, /* 0 */
+ {K_NOTUSED, 0}, /* VERASE, VINTR, VKILL, VWERASE */
+ {K_NOTUSED, 0},
+ {K_NOTUSED, 0},
+ {K_NOTUSED, 0},
};
+static int nkeylist = (sizeof(keylist) / sizeof(keylist[0])) - 4;
/*
* term_init --
@@ -131,7 +175,6 @@ term_init(sp)
GS *gp;
KEYLIST *kp;
TKLIST const *tkp;
- cc_t ch;
int cnt;
char *sbp, *t, buf[2 * 1024], sbuf[128];
@@ -143,50 +186,31 @@ term_init(sp)
gp = sp->gp;
gp->cname = asciiname; /* XXX */
- /* Set keys found in the termios structure. */
-#define TERMSET(name, val) { \
- if ((ch = gp->original_termios.c_cc[name]) != _POSIX_VDISABLE) \
- for (kp = keylist;; ++kp) \
- if (kp->value == (val)) { \
- kp->ch = ch; \
- break; \
- } \
-}
-/*
- * VEOF, VERASE, VKILL are required by POSIX 1003.1-1990,
- * VWERASE is a 4.4BSD extension.
- */
-#ifdef VEOF
- TERMSET(VEOF, K_VEOF);
-#endif
#ifdef VERASE
- TERMSET(VERASE, K_VERASE);
+ termkeyset(gp, VERASE, K_VERASE);
#endif
#ifdef VINTR
- TERMSET(VINTR, K_VINTR);
+ termkeyset(gp, VINTR, K_VINTR);
#endif
#ifdef VKILL
- TERMSET(VKILL, K_VKILL);
+ termkeyset(gp, VKILL, K_VKILL);
#endif
#ifdef VWERASE
- TERMSET(VWERASE, K_VWERASE);
+ termkeyset(gp, VWERASE, K_VWERASE);
#endif
-
/* Sort the special key list. */
- qsort(keylist,
- sizeof(keylist) / sizeof(keylist[0]), sizeof(keylist[0]), keycmp);
+ qsort(keylist, nkeylist, sizeof(keylist[0]), keycmp);
/* Initialize the fast lookup table. */
CALLOC_RET(sp,
gp->special_key, u_char *, MAX_FAST_KEY + 1, sizeof(u_char));
- for (gp->max_special = 0, kp = keylist,
- cnt = sizeof(keylist) / sizeof(keylist[0]); cnt--; ++kp) {
+ for (gp->max_special = 0, kp = keylist, cnt = nkeylist; cnt--; ++kp) {
if (gp->max_special < kp->value)
gp->max_special = kp->value;
if (kp->ch <= MAX_FAST_KEY)
gp->special_key[kp->ch] = kp->value;
}
-
+
/* Set key sequences found in the termcap entry. */
switch (tgetent(buf, O_STR(sp, O_TERM))) {
case -1:
@@ -199,7 +223,8 @@ term_init(sp)
return (0);
}
- for (tkp = tklist; tkp->name != NULL; ++tkp) {
+ /* Command mappings. */
+ for (tkp = c_tklist; tkp->name != NULL; ++tkp) {
sbp = sbuf;
if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
continue;
@@ -207,55 +232,111 @@ term_init(sp)
tkp->output, strlen(tkp->output), SEQ_COMMAND, 0))
return (1);
}
+ /* Input mappings needing to be looked up. */
+ for (tkp = m1_tklist; tkp->name != NULL; ++tkp) {
+ sbp = sbuf;
+ if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
+ continue;
+ for (kp = keylist;; ++kp)
+ if (kp->value == tkp->value)
+ break;
+ if (kp == NULL)
+ continue;
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), &kp->ch, 1, SEQ_INPUT, 0))
+ return (1);
+ }
+ /* Input mappings that are already set or are text deletions. */
+ for (tkp = m2_tklist; tkp->name != NULL; ++tkp) {
+ sbp = sbuf;
+ if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
+ continue;
+ if (tkp->output == NULL) {
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), NULL, 0, SEQ_INPUT, 0))
+ return (1);
+ } else
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), tkp->output, strlen(tkp->output),
+ SEQ_INPUT, 0))
+ return (1);
+ }
return (0);
}
/*
+ * termkeyset --
+ * Set keys found in the termios structure. VERASE, VINTR and VKILL are
+ * required by POSIX 1003.1-1990, VWERASE is a 4.4BSD extension. We've
+ * left four open slots in the keylist table, if these values exist, put
+ * them into place. Note, they may reset (or duplicate) values already
+ * in the table, so we check for that first.
+ */
+static void
+termkeyset(gp, name, val)
+ GS *gp;
+ int name, val;
+{
+ KEYLIST *kp;
+ cc_t ch;
+
+ if (!F_ISSET(gp, G_TERMIOS_SET))
+ return;
+ if ((ch = gp->original_termios.c_cc[(name)]) == _POSIX_VDISABLE)
+ return;
+
+ /* Check for duplication. */
+ for (kp = keylist; kp->value != K_NOTUSED; ++kp)
+ if (kp->ch == ch) {
+ kp->value = val;
+ return;
+ }
+ /* Add a new entry. */
+ if (kp->value == K_NOTUSED) {
+ keylist[nkeylist].ch = ch;
+ keylist[nkeylist].value = val;
+ ++nkeylist;
+ }
+}
+
+/*
* term_push --
* Push keys onto the front of a buffer.
*
* There is a single input buffer in ex/vi. Characters are read onto the
* end of the buffer by the terminal input routines, and pushed onto the
- * front of the buffer various other functions in ex/vi. Each key has an
- * associated flag value, which indicates if it has already been quoted,
- * if it is the result of a mapping or an abbreviation.
- */
+ * front of the buffer by various other functions in ex/vi. Each key has
+ * an associated flag value, which indicates if it has already been quoted,
+ * if it is the result of a mapping or an abbreviation, as well as a count
+ * of the number of times it has been mapped.
+ */
int
-term_push(sp, s, len, cmap, flags)
+term_push(sp, s, nchars, cmap, flags)
SCR *sp;
CHAR_T *s; /* Characters. */
- size_t len; /* Number of chars. */
+ size_t nchars; /* Number of chars. */
u_int cmap; /* Map count. */
u_int flags; /* CH_* flags. */
{
IBUF *tty;
- size_t nlen;
/* If we have room, stuff the keys into the buffer. */
tty = sp->gp->tty;
- if (len <= tty->next ||
- (tty->ch != NULL && tty->cnt == 0 && len <= tty->len)) {
+ if (nchars <= tty->next ||
+ (tty->ch != NULL && tty->cnt == 0 && nchars <= tty->nelem)) {
if (tty->cnt != 0)
- tty->next -= len;
- tty->cnt += len;
- memmove(tty->ch + tty->next, s, len * sizeof(CHAR_T));
- memset(tty->chf + tty->next, flags, len);
- memset(tty->cmap + tty->next, cmap, len);
+ tty->next -= nchars;
+ tty->cnt += nchars;
+ MEMMOVE(tty->ch + tty->next, s, nchars);
+ MEMSET(tty->chf + tty->next, flags, nchars);
+ MEMSET(tty->cmap + tty->next, cmap, nchars);
return (0);
}
/* Get enough space plus a little extra. */
- nlen = tty->cnt + len;
- if (nlen > tty->len) {
- size_t olen;
-
- nlen += 64;
- olen = tty->len;
- BINC_RET(sp, tty->ch, olen, nlen * sizeof(tty->ch[0]));
- olen = tty->len;
- BINC_RET(sp, tty->chf, olen, nlen * sizeof(tty->chf[0]));
- BINC_RET(sp, tty->cmap, tty->len, nlen * sizeof(tty->cmap[0]));
- }
+ if (tty->cnt + nchars >= tty->nelem &&
+ __term_read_grow(sp, tty, MAX(nchars, 64)))
+ return (1);
/*
* If there are currently characters in the queue, shift them up,
@@ -263,26 +344,26 @@ term_push(sp, s, len, cmap, flags)
*/
#define TERM_PUSH_SHIFT 30
if (tty->cnt) {
- memmove(tty->ch + TERM_PUSH_SHIFT + len,
- tty->ch + tty->next, tty->cnt * sizeof(tty->ch[0]));
- memmove(tty->chf + TERM_PUSH_SHIFT + len,
- tty->chf + tty->next, tty->cnt * sizeof(tty->chf[0]));
- memmove(tty->cmap + TERM_PUSH_SHIFT + len,
- tty->cmap + tty->next, tty->cnt * sizeof(tty->cmap[0]));
+ MEMMOVE(tty->ch + TERM_PUSH_SHIFT + nchars,
+ tty->ch + tty->next, tty->cnt);
+ MEMMOVE(tty->chf + TERM_PUSH_SHIFT + nchars,
+ tty->chf + tty->next, tty->cnt);
+ MEMMOVE(tty->cmap + TERM_PUSH_SHIFT + nchars,
+ tty->cmap + tty->next, tty->cnt);
}
/* Put the new characters into the queue. */
tty->next = TERM_PUSH_SHIFT;
- tty->cnt += len;
- memmove(tty->ch + TERM_PUSH_SHIFT, s, len * sizeof(tty->ch[0]));
- memset(tty->chf + TERM_PUSH_SHIFT, flags, len * sizeof(tty->chf[0]));
- memset(tty->cmap + TERM_PUSH_SHIFT, cmap, len * sizeof(tty->cmap[0]));
+ tty->cnt += nchars;
+ MEMMOVE(tty->ch + TERM_PUSH_SHIFT, s, nchars);
+ MEMSET(tty->chf + TERM_PUSH_SHIFT, flags, nchars);
+ MEMSET(tty->cmap + TERM_PUSH_SHIFT, cmap, nchars);
return (0);
}
/*
- * Remove characters from the queue, simultaneously clearing the
- * flag and map counts.
+ * Remove characters from the queue, simultaneously clearing the flag
+ * and map counts.
*/
#define QREM_HEAD(q, len) { \
size_t __off = (q)->next; \
@@ -290,8 +371,8 @@ term_push(sp, s, len, cmap, flags)
tty->chf[__off] = 0; \
tty->cmap[__off] = 0; \
} else { \
- memset(tty->chf + __off, 0, len); \
- memset(tty->cmap + __off, 0, len); \
+ MEMSET(tty->chf + __off, 0, len); \
+ MEMSET(tty->cmap + __off, 0, len); \
} \
if (((q)->cnt -= len) == 0) \
(q)->next = 0; \
@@ -304,8 +385,8 @@ term_push(sp, s, len, cmap, flags)
tty->chf[__off] = 0; \
tty->cmap[__off] = 0; \
} else { \
- memset(tty->chf + __off, 0, len); \
- memset(tty->cmap + __off, 0, len); \
+ MEMSET(tty->chf + __off, 0, len); \
+ MEMSET(tty->cmap + __off, 0, len); \
} \
if (((q)->cnt -= len) == 0) \
(q)->next = 0; \
@@ -386,7 +467,7 @@ term_key(sp, chp, flags)
GS *gp;
IBUF *tty;
SEQ *qp;
- int cmap, ispartial, nr;
+ int cmap, ispartial, nr, itear;
gp = sp->gp;
tty = gp->tty;
@@ -410,6 +491,9 @@ loop: if (tty->cnt == 0) {
F_CLR(sp, S_UPDATE_MODE);
}
+ /* If no limit on remaps, set it up so the user can interrupt. */
+ itear = O_ISSET(sp, O_REMAPMAX) ? 0 : !intr_init(sp);
+
/* If the key is mappable and should be mapped, look it up. */
if (!(tty->chf[tty->next] & CH_NOMAP) &&
LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT)) {
@@ -437,10 +521,12 @@ remap: qp = seq_find(sp, NULL, &tty->ch[tty->next], tty->cnt,
* unmapped.
*/
if (ispartial) {
- if (term_read_grow(sp, tty))
- return (INP_ERR);
+ if (term_read_grow(sp, tty)) {
+ rval = INP_ERR;
+ goto ret;
+ }
if (rval = sp->s_key_read(sp, &nr, tp))
- return (rval);
+ goto ret;
if (nr)
goto remap;
goto nomap;
@@ -455,31 +541,45 @@ remap: qp = seq_find(sp, NULL, &tty->ch[tty->next], tty->cnt,
* character of the map is it, pretend we haven't seen the
* character.
*/
- if (LF_ISSET(TXT_MAPNODIGIT) && !isdigit(qp->output[0]))
+ if (LF_ISSET(TXT_MAPNODIGIT) &&
+ qp->output != NULL && !isdigit(qp->output[0]))
goto not_digit_ch;
/*
* Only permit a character to be remapped a certain number
* of times before we figure that it's not going to finish.
*/
- if ((cmap = tty->cmap[tty->next]) > MAX_MAP_COUNT) {
- term_map_flush(sp, "Character remapped too many times");
- return (INP_ERR);
- }
+ if (O_ISSET(sp, O_REMAPMAX)) {
+ if ((cmap = tty->cmap[tty->next]) > MAX_MAP_COUNT)
+ goto flush;
+ } else if (F_ISSET(sp, S_INTERRUPTED)) {
+flush: term_map_flush(sp, "Character remapped too many times");
+ rval = INP_ERR;
+ goto ret;
+ } else
+ cmap = 0;
/* Delete the mapped characters from the queue. */
QREM_HEAD(tty, qp->ilen);
+ /* If keys mapped to nothing, go get more. */
+ if (qp->output == NULL)
+ goto loop;
+
/* If remapping characters, push the character on the queue. */
if (O_ISSET(sp, O_REMAP)) {
- if (term_push(sp, qp->output, qp->olen, ++cmap, 0))
- return (INP_ERR);
+ if (term_push(sp, qp->output, qp->olen, ++cmap, 0)) {
+ rval = INP_ERR;
+ goto ret;
+ }
goto newmap;
}
/* Else, push the characters on the queue and return one. */
- if (term_push(sp, qp->output, qp->olen, 0, CH_NOMAP))
- return (INP_ERR);
+ if (term_push(sp, qp->output, qp->olen, 0, CH_NOMAP)) {
+ rval = INP_ERR;
+ goto ret;
+ }
}
nomap: ch = tty->ch[tty->next];
@@ -487,7 +587,8 @@ nomap: ch = tty->ch[tty->next];
not_digit_ch: chp->ch = NOT_DIGIT_CH;
chp->value = 0;
chp->flags = 0;
- return (INP_OK);
+ rval = INP_OK;
+ goto ret;
}
/* Fill in the return information. */
@@ -497,18 +598,11 @@ not_digit_ch: chp->ch = NOT_DIGIT_CH;
/* Delete the character from the queue. */
QREM_HEAD(tty, 1);
+ rval = INP_OK;
- /*
- * O_BEAUTIFY eliminates all control characters except
- * escape, form-feed, newline and tab.
- */
- if (isprint(ch) ||
- !LF_ISSET(TXT_BEAUTIFY) || !O_ISSET(sp, O_BEAUTIFY) ||
- chp->value == K_ESCAPE || chp->value == K_FORMFEED ||
- chp->value == K_NL || chp->value == K_TAB)
- return (INP_OK);
-
- goto loop;
+ret: if (itear)
+ intr_end(sp);
+ return (rval);
}
/*
@@ -529,8 +623,8 @@ term_ab_flush(sp, msg)
QREM_HEAD(tty, 1);
} while (tty->cnt && tty->chf[tty->next] & CH_ABBREVIATED);
msgq(sp, M_ERR, "%s: keys flushed.", msg);
-
}
+
/*
* term_map_flush --
* Flush any mapped keys.
@@ -549,7 +643,6 @@ term_map_flush(sp, msg)
QREM_HEAD(tty, 1);
} while (tty->cnt && tty->cmap[tty->next]);
msgq(sp, M_ERR, "%s: keys flushed.", msg);
-
}
/*
@@ -575,7 +668,7 @@ term_user_key(sp, chp)
/* Wait and read another key. */
if (rval = sp->s_key_read(sp, &nr, NULL))
return (rval);
-
+
/* Fill in the return information. */
tty = sp->gp->tty;
chp->ch = tty->ch[tty->next + (tty->cnt - 1)];
@@ -586,7 +679,7 @@ term_user_key(sp, chp)
return (INP_OK);
}
-/*
+/*
* term_key_queue --
* Read the keys off of the terminal queue until it's empty.
*/
@@ -613,26 +706,6 @@ term_key_queue(sp)
}
/*
- * term_key_ch --
- * Fill in the key for a value.
- */
-int
-term_key_ch(sp, val, chp)
- SCR *sp;
- int val;
- CHAR_T *chp;
-{
- KEYLIST *kp;
-
- for (kp = keylist;; ++kp)
- if (kp->value == val) {
- *chp = kp->ch;
- return (0);
- }
- /* NOTREACHED */
-}
-
-/*
* __term_key_val --
* Fill in the value for a key. This routine is the backup
* for the term_key_val() macro.
@@ -645,9 +718,8 @@ __term_key_val(sp, ch)
KEYLIST k, *kp;
k.ch = ch;
- kp = bsearch(&k, keylist,
- sizeof(keylist) / sizeof(keylist[0]), sizeof(keylist[0]), keycmp);
- return (kp == NULL ? 0 : kp->value);
+ kp = bsearch(&k, keylist, nkeylist, sizeof(keylist[0]), keycmp);
+ return (kp == NULL ? K_NOTUSED : kp->value);
}
/*
@@ -656,26 +728,24 @@ __term_key_val(sp, ch)
* the term_read_grow() macro.
*/
static int
-__term_read_grow(sp, tty)
+__term_read_grow(sp, tty, add)
SCR *sp;
IBUF *tty;
+ int add;
{
- size_t alen, len, nlen;
+ size_t new_nelem, olen;
- nlen = tty->len + 64;
- alen = tty->len - (tty->next + tty->cnt);
+ new_nelem = tty->nelem + add;
+ olen = tty->nelem * sizeof(tty->ch[0]);
+ BINC_RET(sp, tty->ch, olen, new_nelem * sizeof(tty->ch[0]));
- len = tty->len;
- BINC_RET(sp, tty->ch, len, nlen * sizeof(tty->ch[0]));
- memset(tty->ch + tty->next + tty->cnt, 0, alen * sizeof(tty->ch[0]));
+ olen = tty->nelem * sizeof(tty->chf[0]);
+ BINC_RET(sp, tty->chf, olen, new_nelem * sizeof(tty->chf[0]));
- len = tty->len;
- BINC_RET(sp, tty->chf, len, nlen * sizeof(tty->chf[0]));
- memset(tty->chf + tty->next + tty->cnt, 0, alen * sizeof(tty->chf[0]));
+ olen = tty->nelem * sizeof(tty->cmap[0]);
+ BINC_RET(sp, tty->cmap, olen, new_nelem * sizeof(tty->cmap[0]));
- BINC_RET(sp, tty->cmap, tty->len, nlen * sizeof(tty->cmap[0]));
- memset(tty->cmap +
- tty->next + tty->cnt, 0, alen * sizeof(tty->cmap[0]));
+ tty->nelem = new_nelem;
return (0);
}
diff --git a/usr.bin/vi/term.h b/usr.bin/vi/term.h
index 67f7f5d2822c..5b224cc01562 100644
--- a/usr.bin/vi/term.h
+++ b/usr.bin/vi/term.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,54 +30,69 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)term.h 8.26 (Berkeley) 1/7/94
+ * @(#)term.h 8.37 (Berkeley) 3/22/94
*/
+/*
+ * Fundamental character types.
+ *
+ * CHAR_T An integral type that can hold any character.
+ * ARG_CHAR_T The type of a CHAR_T when passed as an argument using
+ * traditional promotion rules. It should also be able
+ * to be compared against any CHAR_T for equality without
+ * problems.
+ * MAX_CHAR_T The maximum value of any character.
+ *
+ * If no integral type can hold a character, don't even try the port.
+ */
+typedef u_char CHAR_T;
+typedef u_int ARG_CHAR_T;
+#define MAX_CHAR_T 0xff
+
+/* The maximum number of columns any character can take up on a screen. */
+#define MAX_CHARACTER_COLUMNS 4
+
/* Structure to return a character and associated information. */
struct _ch {
CHAR_T ch; /* Character. */
+#define K_NOTUSED 0
#define K_CARAT 1
-#define K_CNTRLR 2
-#define K_CNTRLT 3
-#define K_CNTRLZ 4
-#define K_COLON 5
-#define K_CR 6
-#define K_ESCAPE 7
-#define K_FORMFEED 8
-#define K_NL 9
-#define K_RIGHTBRACE 10
-#define K_RIGHTPAREN 11
-#define K_TAB 12
-#define K_VEOF 13
+#define K_CNTRLD 2
+#define K_CNTRLR 3
+#define K_CNTRLT 4
+#define K_CNTRLZ 5
+#define K_COLON 6
+#define K_CR 7
+#define K_ESCAPE 8
+#define K_FORMFEED 9
+#define K_NL 10
+#define K_RIGHTBRACE 11
+#define K_RIGHTPAREN 12
+#define K_TAB 13
#define K_VERASE 14
#define K_VINTR 15
#define K_VKILL 16
#define K_VLNEXT 17
#define K_VWERASE 18
#define K_ZERO 19
- u_char value; /* Special character flag values. */
+ u_int8_t value; /* Special character flag values. */
#define CH_ABBREVIATED 0x01 /* Character from an abbreviation. */
#define CH_NOMAP 0x02 /* Do not attempt to map the character. */
#define CH_QUOTED 0x04 /* Character is already quoted. */
- u_char flags;
+ u_int8_t flags;
};
-/*
- * Structure for the key input buffer.
- *
- * MAX_MAP_COUNT was chosen based on the vi maze script, which remaps
- * characters roughly 250 times.
- */
+/* Structure for the key input buffer. */
struct _ibuf {
- CHAR_T *ch; /* Array of characters. */
- u_char *chf; /* Array of character flags (CH_*). */
-#define MAX_MAP_COUNT 270 /* Maximum times a character can remap. */
- u_char *cmap; /* Number of times character has been mapped. */
+ CHAR_T *ch; /* Array of characters. */
+ u_int8_t *chf; /* Array of character flags (CH_*). */
+#define MAX_MAP_COUNT 50 /* Infinite loop check. */
+ u_int8_t *cmap; /* Number of times character has been mapped. */
size_t cnt; /* Count of remaining characters. */
- size_t len; /* Array length. */
+ size_t nelem; /* Numer of array elements. */
size_t next; /* Offset of next array entry. */
};
/* Return if more keys in queue. */
@@ -91,7 +106,7 @@ struct _ibuf {
*/
struct _chname {
char *name; /* Character name. */
- u_char len; /* Length of the character name. */
+ u_int8_t len; /* Length of the character name. */
};
/*
@@ -130,53 +145,55 @@ enum confirm { CONF_NO, CONF_QUIT, CONF_YES };
#define isblank(ch) ((ch) == ' ' || (ch) == '\t')
#endif
+/* The "standard" tab width, for displaying things to users. */
+#define STANDARD_TAB 6
+
/* Various special characters, messages. */
#define CURSOR_CH ' ' /* Cursor character. */
#define END_CH '$' /* End of a range. */
#define HEX_CH 'x' /* Leading hex number. */
+#define LITERAL_CH '\026' /* Standard literal ^V. */
#define NOT_DIGIT_CH 'a' /* A non-isdigit() character. */
#define NO_CH 'n' /* No. */
#define QUIT_CH 'q' /* Quit. */
#define YES_CH 'y' /* Yes. */
+
#define CONFSTRING "confirm? [ynq]"
#define CONTMSG "Enter return to continue: "
#define CONTMSG_I "Enter return to continue [q to quit]: "
/* Flags describing how input is handled. */
-#define TXT_AICHARS 0x000001 /* Leading autoindent chars. */
-#define TXT_ALTWERASE 0x000002 /* Option: altwerase. */
-#define TXT_APPENDEOL 0x000004 /* Appending after EOL. */
-#define TXT_AUTOINDENT 0x000008 /* Autoindent set this line. */
-#define TXT_BEAUTIFY 0x000010 /* Only printable characters. */
-#define TXT_BS 0x000020 /* Backspace returns the buffer. */
-#define TXT_CNTRLT 0x000040 /* Control-T is an indent special. */
-#define TXT_CR 0x000080 /* CR returns the buffer. */
-#define TXT_EMARK 0x000100 /* End of replacement mark. */
-#define TXT_ESCAPE 0x000200 /* Escape returns the buffer. */
-#define TXT_INFOLINE 0x000400 /* Editing the info line. */
-#define TXT_MAPCOMMAND 0x000800 /* Apply the command map. */
-#define TXT_MAPINPUT 0x001000 /* Apply the input map. */
-#define TXT_MAPNODIGIT 0x002000 /* Return to a digit. */
-#define TXT_NLECHO 0x004000 /* Echo the newline. */
-#define TXT_OVERWRITE 0x008000 /* Overwrite characters. */
-#define TXT_PROMPT 0x010000 /* Display a prompt. */
-#define TXT_RECORD 0x020000 /* Record for replay. */
-#define TXT_REPLACE 0x040000 /* Replace; don't delete overwrite. */
-#define TXT_REPLAY 0x080000 /* Replay the last input. */
-#define TXT_RESOLVE 0x100000 /* Resolve the text into the file. */
-#define TXT_SHOWMATCH 0x200000 /* Option: showmatch. */
-#define TXT_TTYWERASE 0x400000 /* Option: ttywerase. */
-#define TXT_WRAPMARGIN 0x800000 /* Option: wrapmargin. */
-
-#define TXT_VALID_EX \
- (TXT_BEAUTIFY | TXT_CR | TXT_NLECHO | TXT_PROMPT)
+#define TXT_AICHARS 0x0000001 /* Leading autoindent chars. */
+#define TXT_ALTWERASE 0x0000002 /* Option: altwerase. */
+#define TXT_APPENDEOL 0x0000004 /* Appending after EOL. */
+#define TXT_AUTOINDENT 0x0000008 /* Autoindent set this line. */
+#define TXT_BEAUTIFY 0x0000010 /* Only printable characters. */
+#define TXT_BS 0x0000020 /* Backspace returns the buffer. */
+#define TXT_CNTRLD 0x0000040 /* Control-D is a special command. */
+#define TXT_CNTRLT 0x0000080 /* Control-T is an indent special. */
+#define TXT_CR 0x0000100 /* CR returns the buffer. */
+#define TXT_EMARK 0x0000200 /* End of replacement mark. */
+#define TXT_ESCAPE 0x0000400 /* Escape returns the buffer. */
+#define TXT_INFOLINE 0x0000800 /* Editing the info line. */
+#define TXT_MAPCOMMAND 0x0001000 /* Apply the command map. */
+#define TXT_MAPINPUT 0x0002000 /* Apply the input map. */
+#define TXT_MAPNODIGIT 0x0004000 /* Return to a digit. */
+#define TXT_NLECHO 0x0008000 /* Echo the newline. */
+#define TXT_OVERWRITE 0x0010000 /* Overwrite characters. */
+#define TXT_PROMPT 0x0020000 /* Display a prompt. */
+#define TXT_RECORD 0x0040000 /* Record for replay. */
+#define TXT_REPLACE 0x0080000 /* Replace; don't delete overwrite. */
+#define TXT_REPLAY 0x0100000 /* Replay the last input. */
+#define TXT_RESOLVE 0x0200000 /* Resolve the text into the file. */
+#define TXT_SHOWMATCH 0x0400000 /* Option: showmatch. */
+#define TXT_TTYWERASE 0x0800000 /* Option: ttywerase. */
+#define TXT_WRAPMARGIN 0x1000000 /* Option: wrapmargin. */
/* Support keyboard routines. */
int __term_key_val __P((SCR *, ARG_CHAR_T));
void term_ab_flush __P((SCR *, char *));
int term_init __P((SCR *));
enum input term_key __P((SCR *, CH *, u_int));
-int term_key_ch __P((SCR *, int, CHAR_T *));
int term_key_queue __P((SCR *));
void term_map_flush __P((SCR *, char *));
int term_push __P((SCR *, CHAR_T *, size_t, u_int, u_int));
diff --git a/usr.bin/vi/timer.c b/usr.bin/vi/timer.c
index e2bcfb1c8852..42d366384f67 100644
--- a/usr.bin/vi/timer.c
+++ b/usr.bin/vi/timer.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,135 +32,205 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)timer.c 8.7 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)timer.c 8.13 (Berkeley) 3/23/94";
#endif /* not lint */
+#include <queue.h>
#include <sys/time.h>
-#include "vi.h"
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
-static void busy_handler __P((int));
+#include "vi.h"
/*
- * XXX
- * There are two uses of timers in nvi. The first is to push the recovery
- * information out to disk at periodic intervals. The second is to display
- * a "busy" message if an operation takes too long. Rather than solve this
- * in a general fashion, we depend on the fact that only a single screen in
- * a window is active at a time, and that there are only two parts of the
- * systems that use timers.
+ * There are two uses of the ITIMER_REAL timer (SIGALRM) in nvi. The first
+ * is to push the recovery information out to disk at periodic intervals.
+ * The second is to display a "busy" message if an operation takes more time
+ * that users are willing to wait before seeing something happen. Each of
+ * these uses has a wall clock timer structure in each SCR structure. Since
+ * the busy timer has a much faster timeout than the recovery timer, most of
+ * the code ignores the recovery timer unless it's the only thing running.
*
- * It would be nice to reimplement this with multiple timers, a la POSIX
- * 1003.1, but not many systems offer them yet.
+ * XXX
+ * It would be nice to reimplement this with two timers, a la POSIX 1003.1,
+ * but not many systems offer them yet.
*/
-/*
+/*
* busy_on --
- * Display a message if too much time passes.
+ * Set a busy message timer.
*/
-void
-busy_on(sp, seconds, msg)
+int
+busy_on(sp, msg)
SCR *sp;
- int seconds;
char const *msg;
{
struct itimerval value;
- struct sigaction act;
+ struct timeval tod;
- /* No busy messages in batch mode. */
- if (F_ISSET(sp, S_EXSILENT))
- return;
+ /*
+ * Give the oldest busy message precedence, since it's
+ * the longer running operation.
+ */
+ if (sp->busy_msg != NULL)
+ return (1);
- /* Turn off the current timer, saving its current value. */
- value.it_interval.tv_sec = value.it_value.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &value, &sp->time_value))
- return;
+ /* Get the current time of day, and create a target time. */
+ if (gettimeofday(&tod, NULL))
+ return (1);
+#define USER_PATIENCE_USECS (8 * 100000L)
+ sp->busy_tod.tv_sec = tod.tv_sec;
+ sp->busy_tod.tv_usec = tod.tv_usec + USER_PATIENCE_USECS;
+
+ /* We depend on this being an atomic instruction. */
+ sp->busy_msg = msg;
/*
- * Decrement the original timer by the number of seconds
- * we're going to wait.
+ * Busy messages turn around fast. Reset the timer regardless
+ * of its current state.
*/
- if (sp->time_value.it_value.tv_sec > seconds)
- sp->time_value.it_value.tv_sec -= seconds;
- else
- sp->time_value.it_value.tv_sec = 1;
-
- /* Reset the handler, saving its current value. */
- act.sa_handler = busy_handler;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- (void)sigaction(SIGALRM, &act, &sp->time_handler);
-
- /* Reset the timer. */
- value.it_value.tv_sec = seconds;
+ value.it_value.tv_sec = 0;
+ value.it_value.tv_usec = USER_PATIENCE_USECS;
value.it_interval.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- (void)setitimer(ITIMER_REAL, &value, NULL);
-
- sp->time_msg = msg;
- F_SET(sp, S_TIMER_SET);
+ value.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &value, NULL))
+ msgq(sp, M_SYSERR, "timer: setitimer");
+ return (0);
}
/*
* busy_off --
- * Reset the timer handlers.
+ * Turn off a busy message timer.
*/
void
busy_off(sp)
SCR *sp;
{
- struct itimerval ovalue, value;
-
- /* No busy messages in batch mode. */
- if (F_ISSET(sp, S_EXSILENT))
- return;
-
- /* If the timer flag isn't set, it must have fired. */
- if (!F_ISSET(sp, S_TIMER_SET))
- return;
+ /* We depend on this being an atomic instruction. */
+ sp->busy_msg = NULL;
+}
- /* Ignore it if first on one of following system calls. */
- F_CLR(sp, S_TIMER_SET);
+/*
+ * rcv_on --
+ * Turn on recovery timer.
+ */
+int
+rcv_on(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct itimerval value;
+ struct timeval tod;
- /* Turn off the current timer. */
- value.it_interval.tv_sec = value.it_value.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &value, &ovalue))
- return;
+ /* Get the current time of day. */
+ if (gettimeofday(&tod, NULL))
+ return (1);
- /* If the timer wasn't running, we're done. */
- if (sp->time_handler.sa_handler == SIG_DFL)
- return;
+ /* Create target time of day. */
+ ep->rcv_tod.tv_sec = tod.tv_sec + RCV_PERIOD;
+ ep->rcv_tod.tv_usec = 0;
/*
- * Increment the old timer by the number of seconds
- * remaining in the new one.
+ * If there's a busy message happening, we're done, the
+ * interrupt handler will start our timer as necessary.
*/
- sp->time_value.it_value.tv_sec += ovalue.it_value.tv_sec;
-
- /* Reset the handler to the original handler. */
- (void)sigaction(SIGALRM, &sp->time_handler, NULL);
+ if (sp->busy_msg != NULL)
+ return (0);
- /* Reset the timer. */
- (void)setitimer(ITIMER_REAL, &sp->time_value, NULL);
+ value.it_value.tv_sec = RCV_PERIOD;
+ value.it_value.tv_usec = 0;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &value, NULL)) {
+ msgq(sp, M_SYSERR, "timer: setitimer");
+ return (1);
+ }
+ return (0);
}
/*
- * busy_handler --
- * Display a message when the timer goes off, and restore the
- * timer to its original values.
+ * h_alrm --
+ * Handle SIGALRM.
*/
-static void
-busy_handler(signo)
+void
+h_alrm(signo)
int signo;
{
+ struct itimerval value;
+ struct timeval ntod, tod;
SCR *sp;
+ EXF *ep;
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_TIMER_SET)) {
- sp->s_busy(sp, sp->time_msg);
- busy_off(sp);
+ /* XXX: Get the current time of day; if this fails, we're dead. */
+ if (gettimeofday(&tod, NULL))
+ return;
+
+ /*
+ * Fire any timers that are past due, or any that are due
+ * in a tenth of a second or less.
+ */
+ for (ntod.tv_sec = 0, sp = __global_list->dq.cqh_first;
+ sp != (void *)&__global_list->dq; sp = sp->q.cqe_next) {
+
+ /* Check the busy timer if the msg pointer is set. */
+ if (sp->busy_msg == NULL)
+ goto skip_busy;
+ if (sp->busy_tod.tv_sec > tod.tv_sec ||
+ sp->busy_tod.tv_sec == tod.tv_sec &&
+ sp->busy_tod.tv_usec > tod.tv_usec &&
+ sp->busy_tod.tv_usec - tod.tv_usec > 100000L) {
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > sp->busy_tod.tv_sec ||
+ ntod.tv_sec == sp->busy_tod.tv_sec &&
+ ntod.tv_usec > sp->busy_tod.tv_usec)
+ ntod = sp->busy_tod;
+ } else {
+ (void)sp->s_busy(sp, sp->busy_msg);
+ sp->busy_msg = NULL;
+ }
+
+ /*
+ * Check the recovery timer if there's an EXF structure
+ * and the recovery bit is set.
+ */
+skip_busy: if ((ep = sp->ep) == NULL || !F_ISSET(sp->ep, F_RCV_ON))
+ continue;
+ if (ep->rcv_tod.tv_sec > tod.tv_sec ||
+ ep->rcv_tod.tv_sec == tod.tv_sec &&
+ ep->rcv_tod.tv_usec > tod.tv_usec &&
+ ep->rcv_tod.tv_usec - tod.tv_usec > 100000L) {
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > ep->rcv_tod.tv_sec ||
+ ntod.tv_sec == ep->rcv_tod.tv_sec &&
+ ntod.tv_usec > ep->rcv_tod.tv_usec)
+ ntod = ep->rcv_tod;
+ } else {
+ F_SET(sp->gp, G_SIGALRM);
+ ep->rcv_tod = tod;
+ ep->rcv_tod.tv_sec += RCV_PERIOD;
+
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > ep->rcv_tod.tv_sec ||
+ ntod.tv_sec == ep->rcv_tod.tv_sec &&
+ ntod.tv_usec > ep->rcv_tod.tv_usec)
+ ntod = ep->rcv_tod;
}
+ }
+
+ if (ntod.tv_sec == 0)
+ return;
+
+ /* XXX: Set the timer; if this fails, we're dead. */
+ value.it_value.tv_sec = ntod.tv_sec - tod.tv_sec;
+ value.it_value.tv_usec = ntod.tv_usec - tod.tv_usec;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_usec = 0;
+ (void)setitimer(ITIMER_REAL, &value, NULL);
}
diff --git a/usr.bin/vi/trace.c b/usr.bin/vi/trace.c
index f97e47bdc7db..b090477b77fa 100644
--- a/usr.bin/vi/trace.c
+++ b/usr.bin/vi/trace.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,11 +30,22 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)trace.c 8.1 (Berkeley) 6/9/93
+ * @(#)trace.c 8.2 (Berkeley) 3/8/94
*/
#ifdef DEBUG
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
diff --git a/usr.bin/vi/util.c b/usr.bin/vi/util.c
index 79a06516af48..74a5380c0e58 100644
--- a/usr.bin/vi/util.c
+++ b/usr.bin/vi/util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,17 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)util.c 8.34 (Berkeley) 12/23/93";
+static char sccsid[] = "@(#)util.c 8.44 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/ioctl.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <curses.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
#ifdef __STDC__
@@ -51,6 +58,9 @@ static char sccsid[] = "@(#)util.c 8.34 (Berkeley) 12/23/93";
#include <varargs.h>
#endif
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
/*
@@ -84,14 +94,15 @@ msgq(sp, mt, fmt, va_alist)
*/
switch (mt) {
case M_BERR:
- if (sp != NULL && !O_ISSET(sp, O_VERBOSE)) {
+ if (sp != NULL && !F_ISSET(sp, S_EXSILENT) &&
+ F_ISSET(sp->gp, G_STDIN_TTY) && !O_ISSET(sp, O_VERBOSE)) {
F_SET(sp, S_BELLSCHED);
return;
}
mt = M_ERR;
break;
case M_VINFO:
- if (sp != NULL && !O_ISSET(sp, O_VERBOSE))
+ if (sp == NULL || !O_ISSET(sp, O_VERBOSE))
return;
mt = M_INFO;
/* FALLTHROUGH */
@@ -209,6 +220,13 @@ ret: reenter = 0;
* This isn't true -- edit a large file and do "100d|1". We don't implement
* this semantic as it would require that we track each line that changes
* during a command instead of just keeping count.
+ *
+ * Line counts weren't right in historic vi, either. For example, given the
+ * file:
+ * abc
+ * def
+ * the command 2d}, from the 'b' would report that two lines were deleted,
+ * not one.
*/
int
msg_rpt(sp, is_message)
@@ -216,7 +234,7 @@ msg_rpt(sp, is_message)
int is_message;
{
static const char *const action[] = {
- "added", "changed", "copied", "deleted", "joined", "moved",
+ "added", "changed", "copied", "deleted", "joined", "moved",
"put", "left shifted", "right shifted", "yanked", NULL,
};
recno_t total;
@@ -276,36 +294,45 @@ norpt: memset(sp->rptlines, 0, sizeof(sp->rptlines));
*/
int
binc(sp, argp, bsizep, min)
- SCR *sp; /* MAY BE NULL */
+ SCR *sp; /* sp MAY BE NULL!!! */
void *argp;
size_t *bsizep, min;
{
- void *bpp;
size_t csize;
+ void *bpp;
/* If already larger than the minimum, just return. */
- csize = *bsizep;
- if (min && csize >= min)
+ if (min && *bsizep >= min)
return (0);
- csize += MAX(min, 256);
+ /*
+ * If the initial pointer is null, use calloc (for non-ANSI
+ * C realloc implementations).
+ */
bpp = *(char **)argp;
+ csize = *bsizep + MAX(min, 256);
+ if (bpp == NULL) {
+ MALLOC(sp, bpp, void *, csize);
+ } else
+ REALLOC(sp, bpp, void *, csize);
- /* For non-ANSI C realloc implementations. */
- if (bpp == NULL)
- bpp = malloc(csize * sizeof(CHAR_T));
- else
- bpp = realloc(bpp, csize * sizeof(CHAR_T));
if (bpp == NULL) {
- msgq(sp, M_SYSERR, NULL);
+ /*
+ * Theoretically, realloc is supposed to leave any already
+ * held memory alone if it can't get more. Don't trust it.
+ */
*bsizep = 0;
return (1);
}
+ /*
+ * Memory is guaranteed to be zero-filled, various parts of
+ * nvi depend on this.
+ */
+ memset((char *)bpp + *bsizep, 0, csize - *bsizep);
*(char **)argp = bpp;
*bsizep = csize;
return (0);
}
-
/*
* nonblank --
* Set the column number of the first non-blank character
@@ -499,6 +526,9 @@ baud_from_bval(sp)
{
speed_t v;
+ if (!F_ISSET(sp->gp, G_TERMIOS_SET))
+ return (9600);
+
switch (v = cfgetospeed(&sp->gp->original_termios)) {
case B50:
return (50);
@@ -524,13 +554,37 @@ baud_from_bval(sp)
return (2400);
case B4800:
return (4800);
+#ifdef B7200
+ case B7200:
+ return (7200);
+#endif
case B0: /* Hangup -- ignore. */
case B9600:
return (9600);
+#ifdef B14400
+ case B14400:
+ return (14400);
+#endif
case B19200:
return (19200);
+#ifdef B28800
+ case B28800:
+ return (28800);
+#endif
case B38400:
return (38400);
+#ifdef B57600
+ case B57600:
+ return (57600);
+#endif
+#ifdef B115200
+ case B115200:
+ return (115200);
+#endif
+#ifdef B230400
+ case B230400:
+ return (230400);
+#endif
default:
/*
* EXTA and EXTB aren't required by POSIX 1003.1, and
@@ -545,14 +599,6 @@ baud_from_bval(sp)
if (v == EXTB)
return (38400);
#endif
-#ifdef B57600
- if (v == B57600)
- return (57600);
-#endif
-#ifdef B115200
- if (v == B115200)
- return (115200);
-#endif
msgq(sp, M_ERR, "Unknown terminal baud rate %u.\n", v);
return (9600);
}
diff --git a/usr.bin/vi/vi.h b/usr.bin/vi/vi.h
index a979925c2b05..5cf65a7ecb3d 100644
--- a/usr.bin/vi/vi.h
+++ b/usr.bin/vi/vi.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,25 +30,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)vi.h 8.33 (Berkeley) 1/9/94
+ * @(#)vi.h 8.39 (Berkeley) 3/23/94
*/
-/* System includes. */
-#include <queue.h> /* Required by screen.h. */
-#include <sys/time.h> /* Required by screen.h. */
-
-#include <bitstring.h> /* Required by screen.h. */
-#include <limits.h> /* Required by screen.h. */
-#include <signal.h> /* Required by screen.h. */
-#include <stdio.h> /* Required by screen.h. */
-#include <termios.h> /* Required by gs.h. */
-
-/*
- * Required by screen.h. This is the first include that can pull
- * in "compat.h". Should be after every other system include.
- */
-#include <regex.h>
-
/*
* Forward structure declarations. Not pretty, but the include files
* are far too interrelated for a clean solution.
@@ -61,6 +45,7 @@ typedef struct _exf EXF;
typedef struct _fref FREF;
typedef struct _gs GS;
typedef struct _ibuf IBUF;
+typedef struct _lmark LMARK;
typedef struct _mark MARK;
typedef struct _msg MSG;
typedef struct _option OPTION;
@@ -73,40 +58,20 @@ typedef struct _tagf TAGF;
typedef struct _text TEXT;
/*
- * Fundamental character types.
- *
- * CHAR_T An integral type that can hold any character.
- * ARG_CHAR_T The type of a CHAR_T when passed as an argument using
- * traditional promotion rules. It should also be able
- * to be compared against any CHAR_T for equality without
- * problems.
- * MAX_CHAR_T The maximum value of any character.
- *
- * If no integral type can hold a character, don't even try the port.
- */
-typedef u_char CHAR_T;
-typedef u_int ARG_CHAR_T;
-#define MAX_CHAR_T 0xff
-
-/* The maximum number of columns any character can take up on a screen. */
-#define MAX_CHARACTER_COLUMNS 4
-
-/*
* Local includes.
*/
-#include <db.h> /* Required by exf.h; includes compat.h. */
-
-#include "search.h" /* Required by screen.h. */
+#include "compat.h" /* typedef u_int8_t et al. */
+#include "term.h" /* Required by args.h. */
#include "args.h" /* Required by options.h. */
#include "options.h" /* Required by screen.h. */
-#include "term.h" /* Required by screen.h. */
+#include "search.h" /* Required by screen.h. */
#include "msg.h" /* Required by gs.h. */
#include "cut.h" /* Required by gs.h. */
#include "gs.h" /* Required by screen.h. */
#include "screen.h" /* Required by exf.h. */
#include "mark.h" /* Required by exf.h. */
-#include "exf.h"
+#include "exf.h"
#include "log.h"
#include "mem.h"
@@ -146,8 +111,6 @@ FILE *fwopen __P((SCR *, void *));
/* Function prototypes that don't seem to belong anywhere else. */
u_long baud_from_bval __P((SCR *));
char *charname __P((SCR *, ARG_CHAR_T));
-void busy_off __P((SCR *));
-void busy_on __P((SCR *, int, char const *));
int nonblank __P((SCR *, EXF *, recno_t, size_t *));
void set_alt_name __P((SCR *, char *));
int set_window_size __P((SCR *, u_int, int));
diff --git a/usr.bin/vi/nvi/getc.c b/usr.bin/vi/vi/getc.c
index d4ac2304b914..67aee2ff4692 100644
--- a/usr.bin/vi/nvi/getc.c
+++ b/usr.bin/vi/vi/getc.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)getc.c 8.6 (Berkeley) 10/26/93";
+static char sccsid[] = "@(#)getc.c 8.8 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -125,7 +135,8 @@ cs_next(sp, ep, csp)
else
csp->cs_ch = csp->cs_bp[++csp->cs_cno];
break;
- case CS_EOF: /* EOF; only returned once. */
+ case CS_EOF: /* EOF. */
+ break;
default:
abort();
/* NOTREACHED */
@@ -218,11 +229,15 @@ cs_prev(sp, ep, csp)
break;
case 0:
if (csp->cs_cno == 0)
- csp->cs_flags = CS_EOL;
+ if (csp->cs_lno == 1)
+ csp->cs_flags = CS_SOF;
+ else
+ csp->cs_flags = CS_EOL;
else
csp->cs_ch = csp->cs_bp[--csp->cs_cno];
break;
- case CS_SOF: /* SOF; only returned once. */
+ case CS_SOF: /* SOF. */
+ break;
default:
abort();
/* NOTREACHED */
diff --git a/usr.bin/vi/nvi/v_again.c b/usr.bin/vi/vi/v_again.c
index 7e9ea5650d83..a96ae8036f04 100644
--- a/usr.bin/vi/nvi/v_again.c
+++ b/usr.bin/vi/vi/v_again.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_again.c 8.2 (Berkeley) 11/13/93";
+static char sccsid[] = "@(#)v_again.c 8.4 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -48,14 +58,13 @@ static char sccsid[] = "@(#)v_again.c 8.2 (Berkeley) 11/13/93";
* Repeat the previous substitution.
*/
int
-v_again(sp, ep, vp, fm, tm, rp)
+v_again(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
- SETCMDARG(cmd, C_SUBAGAIN, 2, fm->lno, fm->lno, 1, "");
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ SETCMDARG(cmd, C_SUBAGAIN, 2, vp->m_start.lno, vp->m_start.lno, 1, "");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
diff --git a/usr.bin/vi/nvi/v_at.c b/usr.bin/vi/vi/v_at.c
index 3b21fc3186d5..c2d446843ca2 100644
--- a/usr.bin/vi/nvi/v_at.c
+++ b/usr.bin/vi/vi/v_at.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1991, 1993
+ * Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,30 +32,40 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_at.c 8.3 (Berkeley) 8/25/93";
+static char sccsid[] = "@(#)v_at.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
#include "vcmd.h"
+/*
+ * v_at -- @
+ * Execute a buffer.
+ */
int
-v_at(sp, ep, vp, fm, tm, rp)
+v_at(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
SETCMDARG(cmd, C_AT, 0, OOBLNO, OOBLNO, 0, NULL);
cmd.buffer = vp->buffer;
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
diff --git a/usr.bin/vi/nvi/v_ch.c b/usr.bin/vi/vi/v_ch.c
index 40807d1db6b1..69fbf6865c47 100644
--- a/usr.bin/vi/nvi/v_ch.c
+++ b/usr.bin/vi/vi/v_ch.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,50 +32,53 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_ch.c 8.2 (Berkeley) 12/20/93";
+static char sccsid[] = "@(#)v_ch.c 8.7 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
-#define NOPREV { \
- msgq(sp, M_BERR, "No previous F, f, T or t search."); \
- return (1); \
-}
-
-#define NOTFOUND(ch) { \
- msgq(sp, M_BERR, "%s not found.", charname(sp, ch)); \
- return (1); \
-}
+static void notfound __P((SCR *, ARG_CHAR_T));
+static void noprev __P((SCR *));
/*
* v_chrepeat -- [count];
* Repeat the last F, f, T or t search.
*/
int
-v_chrepeat(sp, ep, vp, fm, tm, rp)
+v_chrepeat(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- vp->character = sp->lastckey;
+ vp->character = VIP(sp)->lastckey;
- switch (sp->csearchdir) {
+ switch (VIP(sp)->csearchdir) {
case CNOTSET:
- NOPREV;
+ noprev(sp);
+ return (1);
case FSEARCH:
- return (v_chF(sp, ep, vp, fm, tm, rp));
+ return (v_chF(sp, ep, vp));
case fSEARCH:
- return (v_chf(sp, ep, vp, fm, tm, rp));
+ return (v_chf(sp, ep, vp));
case TSEARCH:
- return (v_chT(sp, ep, vp, fm, tm, rp));
+ return (v_chT(sp, ep, vp));
case tSEARCH:
- return (v_cht(sp, ep, vp, fm, tm, rp));
+ return (v_cht(sp, ep, vp));
default:
abort();
}
@@ -87,72 +90,74 @@ v_chrepeat(sp, ep, vp, fm, tm, rp)
* Repeat the last F, f, T or t search in the reverse direction.
*/
int
-v_chrrepeat(sp, ep, vp, fm, tm, rp)
+v_chrrepeat(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- int rval;
enum cdirection savedir;
+ int rval;
- vp->character = sp->lastckey;
- savedir = sp->csearchdir;
+ vp->character = VIP(sp)->lastckey;
+ savedir = VIP(sp)->csearchdir;
- switch (sp->csearchdir) {
+ switch (VIP(sp)->csearchdir) {
case CNOTSET:
- NOPREV;
+ noprev(sp);
+ return (1);
case FSEARCH:
- rval = v_chf(sp, ep, vp, fm, tm, rp);
+ rval = v_chf(sp, ep, vp);
break;
case fSEARCH:
- rval = v_chF(sp, ep, vp, fm, tm, rp);
+ rval = v_chF(sp, ep, vp);
break;
case TSEARCH:
- rval = v_cht(sp, ep, vp, fm, tm, rp);
+ rval = v_cht(sp, ep, vp);
break;
case tSEARCH:
- rval = v_chT(sp, ep, vp, fm, tm, rp);
+ rval = v_chT(sp, ep, vp);
break;
default:
abort();
}
- sp->csearchdir = savedir;
+ VIP(sp)->csearchdir = savedir;
return (rval);
}
/*
* v_cht -- [count]tc
* Search forward in the line for the next occurrence of the character.
- * Place the cursor on it if a motion command, to its left if its not.
+ * Place the cursor on it if it's a motion command, to its left if not.
*/
int
-v_cht(sp, ep, vp, fm, tm, rp)
+v_cht(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- int rval;
+ if (v_chf(sp, ep, vp))
+ return (1);
- rval = v_chf(sp, ep, vp, fm, tm, rp);
- if (!rval)
- --rp->cno; /* XXX: Motion interaction with v_chf. */
- sp->csearchdir = tSEARCH;
- return (rval);
+ /*
+ * v_chf places the cursor on the character, and the 't' command
+ * wants it to its left. We know this is safe since we had to
+ * have moved right for v_chf() to have succeeded.
+ */
+ --vp->m_stop.cno;
+
+ VIP(sp)->csearchdir = tSEARCH;
+ return (0);
}
-
+
/*
* v_chf -- [count]fc
* Search forward in the line for the next occurrence of the character.
- * Place the cursor to its right if a motion command, on it if its not.
*/
int
-v_chf(sp, ep, vp, fm, tm, rp)
+v_chf(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
size_t len;
recno_t lno;
@@ -162,39 +167,47 @@ v_chf(sp, ep, vp, fm, tm, rp)
/*
* !!!
- * If it's a dot command, it doesn't reset the key for which
- * we're searching, e.g. in "df1|f2|.|;", the ';' searches
- * for a '2'.
+ * If it's a dot command, it doesn't reset the key for which we're
+ * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'.
*/
key = vp->character;
if (!F_ISSET(vp, VC_ISDOT))
- sp->lastckey = key;
- sp->csearchdir = fSEARCH;
+ VIP(sp)->lastckey = key;
+ VIP(sp)->csearchdir = fSEARCH;
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
- if (lno == 0)
- NOTFOUND(key);
- GETLINE_ERR(sp, fm->lno);
+ if (lno == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
- if (len == 0)
- NOTFOUND(key);
+ if (len == 0) {
+ notfound(sp, key);
+ return (1);
+ }
- startp = p;
- endp = p + len;
- p += fm->cno;
+ endp = (startp = p) + len;
+ p += vp->m_start.cno;
for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
while (++p < endp && *p != key);
- if (p == endp)
- NOTFOUND(key);
+ if (p == endp) {
+ notfound(sp, key);
+ return (1);
+ }
}
- rp->lno = fm->lno;
- rp->cno = p - startp;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- ++rp->cno;
+
+ vp->m_stop.cno = p - startp;
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
return (0);
}
@@ -204,18 +217,23 @@ v_chf(sp, ep, vp, fm, tm, rp)
* Place the cursor to its right.
*/
int
-v_chT(sp, ep, vp, fm, tm, rp)
+v_chT(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- int rval;
+ if (v_chF(sp, ep, vp))
+ return (1);
+
+ /*
+ * v_chF places the cursor on the character, and the 'T' command
+ * wants it to its right. We know this is safe since we had to
+ * have moved left for v_chF() to have succeeded.
+ */
+ ++vp->m_stop.cno;
+ ++vp->m_final.cno;
- rval = v_chF(sp, ep, vp, fm, tm, rp);
- if (!rval)
- ++rp->cno;
- sp->csearchdir = TSEARCH;
+ VIP(sp)->csearchdir = TSEARCH;
return (0);
}
@@ -225,17 +243,16 @@ v_chT(sp, ep, vp, fm, tm, rp)
* Place the cursor on it.
*/
int
-v_chF(sp, ep, vp, fm, tm, rp)
+v_chF(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
size_t len;
u_long cnt;
int key;
- char *p, *endp;
+ char *endp, *p;
/*
* !!!
@@ -245,29 +262,60 @@ v_chF(sp, ep, vp, fm, tm, rp)
*/
key = vp->character;
if (!F_ISSET(vp, VC_ISDOT))
- sp->lastckey = key;
- sp->csearchdir = FSEARCH;
+ VIP(sp)->lastckey = key;
+ VIP(sp)->csearchdir = FSEARCH;
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
- if (lno == 0)
- NOTFOUND(key);
- GETLINE_ERR(sp, fm->lno);
+ if (lno == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
- if (len == 0)
- NOTFOUND(key);
+ if (len == 0) {
+ notfound(sp, key);
+ return (1);
+ }
endp = p - 1;
- p += fm->cno;
+ p += vp->m_start.cno;
for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
while (--p > endp && *p != key);
- if (p == endp)
- NOTFOUND(key);
+ if (p == endp) {
+ notfound(sp, key);
+ return (1);
+ }
}
- rp->lno = fm->lno;
- rp->cno = (p - endp) - 1;
+
+ vp->m_stop.cno = (p - endp) - 1;
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Motion
+ * commands adjust the starting point to the character before
+ * the current one.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
return (0);
}
+
+static void
+noprev(sp)
+ SCR *sp;
+{
+ msgq(sp, M_BERR, "No previous F, f, T or t search.");
+}
+
+static void
+notfound(sp, ch)
+ SCR *sp;
+ ARG_CHAR_T ch;
+{
+ msgq(sp, M_BERR, "%s not found.", charname(sp, ch));
+}
diff --git a/usr.bin/vi/nvi/v_delete.c b/usr.bin/vi/vi/v_delete.c
index 241ddf654f2e..46ce24d65d23 100644
--- a/usr.bin/vi/nvi/v_delete.c
+++ b/usr.bin/vi/vi/v_delete.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_delete.c 8.7 (Berkeley) 1/11/94";
+static char sccsid[] = "@(#)v_delete.c 8.10 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -45,39 +56,38 @@ static char sccsid[] = "@(#)v_delete.c 8.7 (Berkeley) 1/11/94";
* Delete line command.
*/
int
-v_Delete(sp, ep, vp, fm, tm, rp)
+v_Delete(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
size_t len;
- if (file_gline(sp, ep, fm->lno, &len) == NULL) {
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno == 0)
return (0);
- GETLINE_ERR(sp, fm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
if (len == 0)
return (0);
- tm->lno = fm->lno;
- tm->cno = len;
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno = len - 1;
/* Yank the lines. */
- if (cut(sp, ep, NULL,
- F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, CUT_DELETE))
+ if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, CUT_DELETE))
return (1);
- if (delete(sp, ep, fm, tm, 0))
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, 0))
return (1);
- rp->lno = fm->lno;
- rp->cno = fm->cno ? fm->cno - 1 : 0;
+ vp->m_final.lno = vp->m_start.lno;
+ vp->m_final.cno = vp->m_start.cno ? vp->m_start.cno - 1 : 0;
return (0);
}
@@ -86,62 +96,50 @@ v_Delete(sp, ep, vp, fm, tm, rp)
* Delete a range of text.
*/
int
-v_delete(sp, ep, vp, fm, tm, rp)
+v_delete(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t nlines;
size_t len;
int lmode;
-
+
/* Yank the lines. */
- lmode = F_ISSET(vp, VC_LMODE) ? CUT_LINEMODE : 0;
- if (cut(sp, ep, NULL,
- F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, lmode | CUT_DELETE))
+ lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0;
+ if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode | CUT_DELETE))
return (1);
- if (delete(sp, ep, fm, tm, lmode))
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, lmode))
return (1);
- /* Check for deleting the file. */
- if (file_lline(sp, ep, &nlines))
- return (1);
- if (nlines == 0) {
- rp->lno = 1;
- rp->cno = 0;
- return (0);
- }
-
/*
- * If deleting lines, leave the cursor at the lowest line deleted,
- * else, leave the cursor where it started. Always correct for EOL.
- *
- * The historic vi would delete the line the cursor was on (even if
- * not in line mode) if the motion from the cursor was past the EOF
- * and the cursor didn't originate on the last line of the file. A
- * strange special case. We never delete the line the cursor is on.
- * We'd have to pass a flag down to the delete() routine which would
- * have to special case it.
+ * Check for deletion of the entire file. Try to check a close
+ * by line so we don't go to the end of the file unnecessarily.
*/
- if (lmode) {
- rp->lno = MIN(fm->lno, tm->lno);
- if (rp->lno > nlines)
- rp->lno = nlines;
- rp->cno = 0;
- (void)nonblank(sp, ep, rp->lno, &rp->cno);
- return (0);
+ if (file_gline(sp, ep, vp->m_final.lno + 1, &len) == NULL) {
+ if (file_lline(sp, ep, &nlines))
+ return (1);
+ if (nlines == 0) {
+ vp->m_final.lno = 1;
+ vp->m_final.cno = 0;
+ return (0);
+ }
}
- rp->lno = fm->lno;
- if (file_gline(sp, ep, rp->lno, &len) == NULL) {
- GETLINE_ERR(sp, rp->lno);
- return (1);
+ /*
+ * One special correction, in case we've deleted the current line or
+ * character. We check it here instead of checking in every command
+ * that can be a motion component.
+ */
+ if (file_gline(sp, ep, vp->m_final.lno, &len) == NULL) {
+ if (file_gline(sp, ep, nlines, &len) == NULL) {
+ GETLINE_ERR(sp, nlines);
+ return (1);
+ }
+ vp->m_final.lno = nlines;
}
- if (fm->cno >= len)
- rp->cno = len ? len - 1 : 0;
- else
- rp->cno = fm->cno;
+ if (vp->m_final.cno >= len)
+ vp->m_final.cno = len ? len - 1 : 0;
return (0);
}
diff --git a/usr.bin/vi/nvi/v_exmode.c b/usr.bin/vi/vi/v_ex.c
index 150ec52ccf9c..49f688844efb 100644
--- a/usr.bin/vi/nvi/v_exmode.c
+++ b/usr.bin/vi/vi/v_ex.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,24 +32,47 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_exmode.c 8.3 (Berkeley) 11/13/93";
+static char sccsid[] = "@(#)v_ex.c 8.3 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
/*
- * v_exmode --
- * Put the editor in EX mode.
+ * v_ex -- :
+ * Execute a colon command line.
+ */
+int
+v_ex(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (sp->s_ex_run(sp, ep, &vp->m_final));
+}
+
+/*
+ * v_exmode -- Q
+ * Switch the editor into EX mode.
*/
int
-v_exmode(sp, ep, vp, fm, tm, rp)
+v_exmode(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
sp->saved_vi_mode = F_ISSET(sp, S_VI_CURSES | S_VI_XAW);
F_CLR(sp, S_SCREENS);
diff --git a/usr.bin/vi/nvi/v_filter.c b/usr.bin/vi/vi/v_filter.c
index 52ff2ae77b8d..39844a8a356e 100644
--- a/usr.bin/vi/nvi/v_filter.c
+++ b/usr.bin/vi/vi/v_filter.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_filter.c 8.10 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)v_filter.c 8.12 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -48,11 +58,10 @@ static char sccsid[] = "@(#)v_filter.c 8.10 (Berkeley) 12/2/93";
* Run range through shell commands, replacing text.
*/
int
-v_filter(sp, ep, vp, fm, tm, rp)
+v_filter(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
TEXT *tp;
@@ -65,7 +74,7 @@ v_filter(sp, ep, vp, fm, tm, rp)
* particular, note that we're manipulating the ex argument
* structures behind ex's back.
*/
- SETCMDARG(cmd, C_BANG, 2, fm->lno, tm->lno, 0, NULL);
+ SETCMDARG(cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0, NULL);
EXP(sp)->argsoff = 0; /* XXX */
if (F_ISSET(vp, VC_ISDOT)) {
if (argv_exp1(sp, ep, &cmd, "!", 1, 1))
@@ -88,5 +97,5 @@ v_filter(sp, ep, vp, fm, tm, rp)
}
cmd.argc = EXP(sp)->argsoff; /* XXX */
cmd.argv = EXP(sp)->args; /* XXX */
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
diff --git a/usr.bin/vi/nvi/v_increment.c b/usr.bin/vi/vi/v_increment.c
index dfae29ea463e..aee358922662 100644
--- a/usr.bin/vi/nvi/v_increment.c
+++ b/usr.bin/vi/vi/v_increment.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_increment.c 8.6 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)v_increment.c 8.8 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -62,11 +72,10 @@ static char * const fmt[] = {
* Increment/decrement a keyword number.
*/
int
-v_increment(sp, ep, vp, fm, tm, rp)
+v_increment(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
VI_PRIVATE *vip;
u_long ulval;
@@ -135,19 +144,19 @@ underflow: msgq(sp, M_ERR, "Resulting number too small.");
nlen = snprintf(nbuf, sizeof(nbuf), ntype, lval);
}
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- GETLINE_ERR(sp, fm->lno);
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
GET_SPACE_RET(sp, bp, blen, len + nlen);
- memmove(bp, p, fm->cno);
- memmove(bp + fm->cno, nbuf, nlen);
- memmove(bp + fm->cno + nlen,
- p + fm->cno + vp->klen, len - fm->cno - vp->klen);
+ memmove(bp, p, vp->m_start.cno);
+ memmove(bp + vp->m_start.cno, nbuf, nlen);
+ memmove(bp + vp->m_start.cno + nlen,
+ p + vp->m_start.cno + vp->klen, len - vp->m_start.cno - vp->klen);
len = len - vp->klen + nlen;
- rval = file_sline(sp, ep, fm->lno, bp, len);
+ rval = file_sline(sp, ep, vp->m_start.lno, bp, len);
FREE_SPACE(sp, bp, blen);
return (rval);
}
diff --git a/usr.bin/vi/nvi/v_init.c b/usr.bin/vi/vi/v_init.c
index f0d2facf4ea3..122c6c60e263 100644
--- a/usr.bin/vi/nvi/v_init.c
+++ b/usr.bin/vi/vi/v_init.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_init.c 8.18 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)v_init.c 8.21 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -64,6 +74,7 @@ v_screen_copy(orig, sp)
if (orig == NULL) {
nvip->inc_lastch = '+';
nvip->inc_lastval = 1;
+ nvip->csearchdir = CNOTSET;
} else {
ovip = VIP(orig);
@@ -84,6 +95,9 @@ v_screen_copy(orig, sp)
msgq(sp, M_SYSERR, NULL);
return (1);
}
+
+ nvip->lastckey = ovip->lastckey;
+ nvip->csearchdir = ovip->csearchdir;
}
return (0);
}
@@ -143,7 +157,6 @@ v_init(sp, ep)
}
} else if (sp->cno >= len)
sp->cno = 0;
-
} else {
sp->lno = 1;
sp->cno = 0;
diff --git a/usr.bin/vi/nvi/v_join.c b/usr.bin/vi/vi/v_join.c
index c3f81d6d1a5c..e7eeaa235d85 100644
--- a/usr.bin/vi/nvi/v_join.c
+++ b/usr.bin/vi/vi/v_join.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_join.c 8.3 (Berkeley) 8/29/93";
+static char sccsid[] = "@(#)v_join.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -48,11 +58,10 @@ static char sccsid[] = "@(#)v_join.c 8.3 (Berkeley) 8/29/93";
* Join lines together.
*/
int
-v_join(sp, ep, vp, fm, tm, rp)
+v_join(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
int lno;
@@ -66,10 +75,10 @@ v_join(sp, ep, vp, fm, tm, rp)
* we never test for EOF -- historically going past the end of file
* worked just fine.
*/
- lno = fm->lno + 1;
+ lno = vp->m_start.lno + 1;
if (F_ISSET(vp, VC_C1SET) && vp->count > 2)
- lno = fm->lno + (vp->count - 1);
+ lno = vp->m_start.lno + (vp->count - 1);
- SETCMDARG(cmd, C_JOIN, 2, fm->lno, lno, 0, NULL);
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ SETCMDARG(cmd, C_JOIN, 2, vp->m_start.lno, lno, 0, NULL);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
diff --git a/usr.bin/vi/vi/v_left.c b/usr.bin/vi/vi/v_left.c
new file mode 100644
index 000000000000..8c44657f0d20
--- /dev/null
+++ b/usr.bin/vi/vi/v_left.c
@@ -0,0 +1,286 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_left.c 8.8 (Berkeley) 3/10/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_left -- [count]^H, [count]h
+ * Move left by columns.
+ */
+int
+v_left(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t cnt;
+
+ /*
+ * !!!
+ * The ^H and h commands always failed in the first column.
+ */
+ if (vp->m_start.cno == 0) {
+ v_sol(sp);
+ return (1);
+ }
+
+ /* Find the end of the range. */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ if (vp->m_start.cno > cnt)
+ vp->m_stop.cno = vp->m_start.cno - cnt;
+ else
+ vp->m_stop.cno = 0;
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Motion
+ * commands adjust the starting point to the character before
+ * the current one.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
+
+/*
+ * v_cfirst -- [count]_
+ * Move to the first non-blank character in a line.
+ */
+int
+v_cfirst(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t cnt;
+
+ /*
+ * !!!
+ * If the _ is a motion component, it makes the command a line motion
+ * e.g. "d_" deletes the line. It also means that the cursor doesn't
+ * move.
+ *
+ * The _ command never failed in the first column.
+ */
+ if (ISMOTION(vp))
+ F_SET(vp, VM_LMODE);
+ /*
+ * !!!
+ * Historically a specified count makes _ move down count - 1
+ * rows, so, "3_" is the same as "2j_".
+ */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ if (cnt != 1) {
+ --vp->count;
+ return (v_down(sp, ep, vp));
+ }
+
+ /*
+ * Move to the first non-blank.
+ *
+ * Can't just use RCM_SET_FNB, in case _ is used as the motion
+ * component of another command.
+ */
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno))
+ return (1);
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_first -- ^
+ * Move to the first non-blank character in this line.
+ */
+int
+v_first(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * !!!
+ * Yielding to none in our quest for compatibility with every
+ * historical blemish of vi, no matter how strange it might be,
+ * we permit the user to enter a count and then ignore it.
+ */
+
+ /*
+ * Move to the first non-blank.
+ *
+ * Can't just use RCM_SET_FNB, in case ^ is used as the motion
+ * component of another command.
+ */
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno))
+ return (1);
+
+ /*
+ * !!!
+ * The ^ command succeeded if used as a command without a whitespace
+ * character preceding the cursor in the line, but failed if used as
+ * a motion component in the same situation.
+ */
+ if (ISMOTION(vp) && vp->m_start.cno <= vp->m_stop.cno) {
+ v_sol(sp);
+ return (1);
+ }
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Motion
+ * commands adjust the starting point to the character before
+ * the current one.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
+
+/*
+ * v_ncol -- [count]|
+ * Move to column count or the first column on this line. If the
+ * requested column is past EOL, move to EOL. The nasty part is
+ * that we have to know character column widths to make this work.
+ */
+int
+v_ncol(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (F_ISSET(vp, VC_C1SET) && vp->count > 1) {
+ --vp->count;
+ vp->m_stop.cno =
+ sp->s_colpos(sp, ep, vp->m_start.lno, (size_t)vp->count);
+ /*
+ * !!!
+ * The | command succeeded if used as a command and the cursor
+ * didn't move, but failed if used as a motion component in the
+ * same situation.
+ */
+ if (ISMOTION(vp) && vp->m_stop.cno == vp->m_start.cno) {
+ v_nomove(sp);
+ return (1);
+ }
+ } else {
+ /*
+ * !!!
+ * The | command succeeded if used as a command in column 0
+ * without a count, but failed if used as a motion component
+ * in the same situation.
+ */
+ if (ISMOTION(vp) && vp->m_start.cno == 0) {
+ v_sol(sp);
+ return (1);
+ }
+ vp->m_stop.cno = 0;
+ }
+
+ /*
+ * If moving right, non-motion commands move to the end of the range.
+ * VC_D and VC_Y stay at the start. If moving left, non-motion and
+ * VC_D commands move to the end of the range. VC_Y remains at the
+ * start. Ignore VC_C and VC_S. Motion left commands adjust the
+ * starting point to the character before the current one.
+ */
+ if (vp->m_start.cno < vp->m_stop.cno)
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ else {
+ vp->m_final = vp->m_stop;
+ if (ISMOTION(vp)) {
+ if (F_ISSET(vp, VC_Y))
+ vp->m_final = vp->m_start;
+ --vp->m_start.cno;
+ }
+ }
+ return (0);
+}
+
+/*
+ * v_zero -- 0
+ * Move to the first column on this line.
+ */
+int
+v_zero(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * !!!
+ * The 0 command succeeded if used as a command in the first column
+ * but failed if used as a motion component in the same situation.
+ */
+ if (ISMOTION(vp) && vp->m_start.cno == 0) {
+ v_sol(sp);
+ return (1);
+ }
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Motion
+ * commands adjust the starting point to the character before
+ * the current one.
+ */
+ vp->m_stop.cno = 0;
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
diff --git a/usr.bin/vi/nvi/v_left.c b/usr.bin/vi/vi/v_mark.c
index cc80b379b06d..ae0585d930ef 100644
--- a/usr.bin/vi/nvi/v_left.c
+++ b/usr.bin/vi/vi/v_mark.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,135 +32,125 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_left.c 8.3 (Berkeley) 12/16/93";
+static char sccsid[] = "@(#)v_mark.c 8.6 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
/*
- * v_left -- [count]^H, [count]h
- * Move left by columns.
+ * v_mark -- m[a-z]
+ * Set a mark.
*/
int
-v_left(sp, ep, vp, fm, tm, rp)
+v_mark(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- recno_t cnt;
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- if (fm->cno == 0) {
- msgq(sp, M_BERR, "Already in the first column.");
- return (1);
- }
-
- rp->lno = fm->lno;
- if (fm->cno > cnt)
- rp->cno = fm->cno - cnt;
- else
- rp->cno = 0;
- return (0);
+ return (mark_set(sp, ep, vp->character, &vp->m_start, 1));
}
+static int mark __P((SCR *, EXF *, VICMDARG *, enum direction));
+
/*
- * v_cfirst -- [count]_
+ * v_bmark -- `['`a-z]
+ * Move to a mark.
+ *
+ * Moves to a mark, setting both row and column.
*
- * Move to the first non-blank column on a line.
+ * !!!
+ * Although not commonly known, the "'`" and "'`" forms are historically
+ * valid. The behavior is determined by the first character, so "`'" is
+ * the same as "``". Remember this fact -- you'll be amazed at how many
+ * people don't know it and will be delighted that you are able to tell
+ * them.
*/
int
-v_cfirst(sp, ep, vp, fm, tm, rp)
+v_bmark(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- recno_t cnt;
-
- /*
- * A count moves down count - 1 rows, so, "3_" is the same as "2j_".
- *
- * !!!
- * Historically, if the _ is a motion, it is always a line motion,
- * and the line motion flag is set.
- */
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- if (cnt != 1) {
- --vp->count;
- if (v_down(sp, ep, vp, fm, tm, rp))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- F_SET(vp, VC_LMODE);
- } else
- rp->lno = fm->lno;
- rp->cno = 0;
- if (nonblank(sp, ep, rp->lno, &rp->cno))
- return (1);
- return (0);
+ return (mark(sp, ep, vp, BACKWARD));
}
/*
- * v_first -- ^
- * Move to the first non-blank column on this line.
+ * v_fmark -- '['`a-z]
+ * Move to a mark.
+ *
+ * Move to the first nonblank character of the line containing the mark.
*/
int
-v_first(sp, ep, vp, fm, tm, rp)
+v_fmark(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- /*
- * Yielding to none in our quest for compatibility with every
- * historical blemish of vi, no matter how strange it might be,
- * we permit the user to enter a count and then ignore it.
- */
- rp->cno = 0;
- if (nonblank(sp, ep, fm->lno, &rp->cno))
- return (1);
- rp->lno = fm->lno;
- return (0);
+ return (mark(sp, ep, vp, FORWARD));
}
-/*
- * v_ncol -- [count]|
- * Move to column count or the first column on this line. If the
- * requested column is past EOL, move to EOL. The nasty part is
- * that we have to know character column widths to make this work.
- */
-int
-v_ncol(sp, ep, vp, fm, tm, rp)
+static int
+mark(sp, ep, vp, dir)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
+ enum direction dir;
{
- if (F_ISSET(vp, VC_C1SET) && vp->count > 1)
- rp->cno =
- sp->s_chposition(sp, ep, fm->lno, (size_t)--vp->count);
- else
- rp->cno = 0;
- rp->lno = fm->lno;
- return (0);
-}
+ if (mark_get(sp, ep, vp->character, &vp->m_stop))
+ return (1);
-/*
- * v_zero -- 0
- * Move to the first column on this line.
- */
-int
-v_zero(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- rp->lno = fm->lno;
- rp->cno = 0;
+ /* Forward marks move to the first non-blank. */
+ if (dir == FORWARD) {
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno))
+ return (1);
+ }
+
+ /* Non-motion commands move to the end of the range. */
+ if (!ISMOTION(vp)) {
+ vp->m_final = vp->m_stop;
+ return (0);
+ }
+
+ /*
+ * !!!
+ * If a motion component, the cursor has to move.
+ */
+ if (vp->m_stop.lno == vp->m_start.lno &&
+ vp->m_stop.cno == vp->m_start.cno) {
+ v_nomove(sp);
+ return (1);
+ }
+
+ /*
+ * If moving right, VC_D and VC_Y stay at the start. If moving left,
+ * VC_D commands move to the end of the range and VC_Y remains at the
+ * start. Ignore VC_C and VC_S. Motion left commands adjust the
+ * starting point to the character before the current one.
+ */
+ if (vp->m_start.lno > vp->m_stop.lno ||
+ vp->m_start.lno == vp->m_stop.lno &&
+ vp->m_start.cno > vp->m_stop.cno) {
+ if (F_ISSET(vp, VC_D))
+ vp->m_final = vp->m_stop;
+ else
+ vp->m_final = vp->m_start;
+ --vp->m_start.cno;
+ } else
+ vp->m_final = vp->m_start;
return (0);
}
diff --git a/usr.bin/vi/nvi/v_match.c b/usr.bin/vi/vi/v_match.c
index 963cca551fe8..0e5642ef9c49 100644
--- a/usr.bin/vi/nvi/v_match.c
+++ b/usr.bin/vi/vi/v_match.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_match.c 8.7 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)v_match.c 8.10 (Berkeley) 3/10/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -47,33 +57,33 @@ static char sccsid[] = "@(#)v_match.c 8.7 (Berkeley) 12/9/93";
* Search to matching character.
*/
int
-v_match(sp, ep, vp, fm, tm, rp)
+v_match(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- register int cnt, matchc, startc;
VCS cs;
+ MARK *mp;
recno_t lno;
- size_t len, off;
- int (*gc)__P((SCR *, EXF *, VCS *));
+ size_t cno, len, off;
+ int cnt, matchc, startc, (*gc)__P((SCR *, EXF *, VCS *));
char *p;
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno == 0)
goto nomatch;
- GETLINE_ERR(sp, fm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
/*
* !!!
- * Historical practice was to search in the forward direction only.
+ * Historical practice was to search for the initial character
+ * in the forward direction only.
*/
- for (off = fm->cno;; ++off) {
+ for (off = vp->m_start.cno;; ++off) {
if (off >= len) {
nomatch: msgq(sp, M_BERR, "No match character on this line.");
return (1);
@@ -109,7 +119,7 @@ nomatch: msgq(sp, M_BERR, "No match character on this line.");
break;
}
- cs.cs_lno = fm->lno;
+ cs.cs_lno = vp->m_start.lno;
cs.cs_cno = off;
if (cs_init(sp, ep, &cs))
return (1);
@@ -130,23 +140,47 @@ nomatch: msgq(sp, M_BERR, "No match character on this line.");
msgq(sp, M_BERR, "Matching character not found.");
return (1);
}
- rp->lno = cs.cs_lno;
- rp->cno = cs.cs_cno;
+
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
/*
- * Movement commands go one space further. Increment the return
- * MARK or from MARK depending on the direction of the search.
+ * If moving right, non-motion commands move to the end of the range.
+ * VC_D and VC_Y stay at the start. If moving left, non-motion and
+ * VC_D commands move to the end of the range. VC_Y remains at the
+ * start. Ignore VC_C and VC_S.
+ *
+ * !!!
+ * Don't correct for leftward movement -- historic vi deleted the
+ * starting cursor position when deleting to a match.
*/
- if (F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- if (file_gline(sp, ep, rp->lno, &len) == NULL) {
- GETLINE_ERR(sp, rp->lno);
- return (1);
+ if (vp->m_start.lno < vp->m_stop.lno ||
+ vp->m_start.lno == vp->m_stop.lno &&
+ vp->m_start.cno < vp->m_stop.cno)
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ else
+ vp->m_final = ISMOTION(vp) &&
+ F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
+
+ /*
+ * !!!
+ * If the motion is across lines, and the earliest cursor position
+ * is at or before any non-blank characters in its line, i.e. the
+ * movement is cutting all of the line's text, the buffer is in line
+ * mode.
+ */
+ if (ISMOTION(vp) && vp->m_start.lno != vp->m_stop.lno) {
+ mp = vp->m_start.lno < vp->m_stop.lno ?
+ &vp->m_start : &vp->m_stop;
+ if (mp->cno == 0) {
+ F_SET(vp, VM_LMODE);
+ return (0);
}
- if (len)
- if (gc == cs_next)
- ++rp->cno;
- else
- ++fm->cno;
+ cno = 0;
+ if (nonblank(sp, ep, mp->lno, &cno))
+ return (1);
+ if (cno >= mp->cno)
+ F_SET(vp, VM_LMODE);
}
return (0);
}
diff --git a/usr.bin/vi/nvi/v_ntext.c b/usr.bin/vi/vi/v_ntext.c
index 1c17ffc5bdd0..e4060af97bc8 100644
--- a/usr.bin/vi/nvi/v_ntext.c
+++ b/usr.bin/vi/vi/v_ntext.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,33 +32,45 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_ntext.c 8.80 (Berkeley) 1/13/94";
+static char sccsid[] = "@(#)v_ntext.c 8.95 (Berkeley) 3/24/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "seq.h"
#include "vcmd.h"
#include "excmd.h"
-static int txt_abbrev __P((SCR *, TEXT *, ARG_CHAR_T, int, int *, int *));
+static int txt_abbrev __P((SCR *, TEXT *, CHAR_T *, int, int *, int *));
static void txt_ai_resolve __P((SCR *, TEXT *));
static TEXT *txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int));
static void txt_err __P((SCR *, EXF *, TEXTH *));
-static int txt_hex __P((SCR *, TEXT *, int *, ARG_CHAR_T));
+static int txt_hex __P((SCR *, TEXT *, int *, CHAR_T *));
static int txt_indent __P((SCR *, TEXT *));
-static int txt_margin __P((SCR *, TEXT *, int *, ARG_CHAR_T));
+static int txt_margin __P((SCR *, TEXT *, int *, CHAR_T *));
static int txt_outdent __P((SCR *, TEXT *));
static void txt_showmatch __P((SCR *, EXF *));
+static void txt_Rcleanup __P((SCR *,
+ TEXTH *, TEXT *, const char *, const size_t));
static int txt_resolve __P((SCR *, EXF *, TEXTH *));
+static void txt_unmap __P((SCR *, TEXT *, u_int *));
/* Cursor character (space is hard to track on the screen). */
#if defined(DEBUG) && 0
@@ -73,27 +85,10 @@ static int txt_resolve __P((SCR *, EXF *, TEXTH *));
}
/*
- * newtext --
+ * v_ntext --
* Read in text from the user.
*
* !!!
- * Historic vi always used:
- *
- * ^D: autoindent deletion
- * ^H: last character deletion
- * ^W: last word deletion
- * ^V: quote the next character
- *
- * regardless of the user's choices for these characters. The user's erase
- * and kill characters worked in addition to these characters. Ex was not
- * completely consistent with this, as it did map the scroll command to the
- * user's EOF character.
- *
- * This implementation does not use fixed characters, but uses whatever the
- * user specified as described by the termios structure. I'm getting away
- * with something here, but I think I'm unlikely to get caught.
- *
- * !!!
* Historic vi did a special screen optimization for tab characters. For
* the keystrokes "iabcd<esc>0C<tab>", the tab would overwrite the rest of
* the string when it was displayed. Because this implementation redisplays
@@ -118,7 +113,7 @@ v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
u_int flags; /* TXT_ flags. */
{
/* State of abbreviation checks. */
- enum { A_NOTSET, A_SPACE, A_NOTSPACE } abb;
+ enum { A_NOTSET, A_NOTWORD, A_INWORD } abb;
/* State of the "[^0]^D" sequences. */
enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;
/* State of the hex input character. */
@@ -127,7 +122,6 @@ v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;
CH ikey; /* Input character structure. */
CHAR_T ch; /* Input character. */
- GS *gp; /* Global pointer. */
TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
size_t rcol; /* 0-N: insert offset in the replay buffer. */
size_t col; /* Current column. */
@@ -139,6 +133,7 @@ v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
int showmatch; /* Showmatch set on this character. */
int testnr; /* Test first character for nul replay. */
int max, tmp;
+ int unmap_tst; /* Input map needs testing. */
char *p;
/*
@@ -149,7 +144,6 @@ v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
/* Local initialization. */
eval = 0;
- gp = sp->gp;
/*
* Get one TEXT structure with some initial buffer space, reusing
@@ -186,21 +180,21 @@ newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
*/
if (len) {
if (LF_ISSET(TXT_OVERWRITE)) {
- tp->owrite = tm->cno - sp->cno;
- tp->insert = len - tm->cno;
+ tp->owrite = (tm->cno - sp->cno) + 1;
+ tp->insert = (len - tm->cno) - 1;
} else
tp->insert = len - sp->cno;
if (LF_ISSET(TXT_EMARK))
- tp->lb[tm->cno - 1] = END_CH;
+ tp->lb[tm->cno] = END_CH;
}
/*
* Many of the special cases in this routine are to handle autoindent
* support. Somebody decided that it would be a good idea if "^^D"
* and "0^D" deleted all of the autoindented characters. In an editor
- * that takes single character input from the user, this wasn't a very
- * good idea. Note also that "^^D" resets the next lines' autoindent,
+ * that takes single character input from the user, this beggars the
+ * imagination. Note also, "^^D" resets the next lines' autoindent,
* but "0^D" doesn't.
*
* We assume that autoindent only happens on empty lines, so insert
@@ -272,8 +266,8 @@ newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
margin = sp->cols - margin;
/* Initialize abbreviations checks. */
- if (F_ISSET(gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {
- abb = A_NOTSPACE;
+ if (F_ISSET(sp->gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {
+ abb = A_INWORD;
ab_cnt = ab_turnoff = 0;
} else
abb = A_NOTSET;
@@ -315,8 +309,9 @@ nullreplay:
} else
testnr = 1;
+ unmap_tst = LF_ISSET(TXT_MAPINPUT) && LF_ISSET(TXT_INFOLINE);
iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
- for (gp, showmatch = 0,
+ for (showmatch = 0,
carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) {
/*
* Reset the line and update the screen. (The txt_showmatch()
@@ -335,7 +330,9 @@ nullreplay:
}
/* Get the next character. */
-next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
+next_ch: if (term_key(sp, &ikey, quoted == Q_THISCHAR ?
+ iflags & ~(TXT_MAPCOMMAND | TXT_MAPINPUT) :
+ iflags) != INP_OK)
goto err;
ch = ikey.ch;
@@ -350,7 +347,7 @@ next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
}
} else
ab_cnt = 0;
-
+
/*
* !!!
* Historic feature. If the first character of the input is
@@ -387,7 +384,7 @@ next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
* hex mode.
*/
if (ikey.flags & CH_QUOTED)
- goto ins_ch;
+ goto insq_ch;
if (quoted == Q_THISCHAR) {
--sp->cno;
++tp->owrite;
@@ -395,7 +392,7 @@ next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
if (ch == HEX_CH)
hex = H_NEXTCHAR;
- goto ins_ch;
+ goto insq_ch;
}
switch (ikey.value) {
@@ -406,8 +403,8 @@ next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
* Handle abbreviations. If there was one, \
* discard the replay characters. \
*/ \
- if (abb == A_NOTSPACE && !replay) { \
- if (txt_abbrev(sp, tp, ch, \
+ if (abb == A_INWORD && !replay) { \
+ if (txt_abbrev(sp, tp, &ch, \
LF_ISSET(TXT_INFOLINE), &tmp, \
&ab_turnoff)) \
goto err; \
@@ -418,28 +415,21 @@ next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
} \
} \
if (abb != A_NOTSET) \
- abb = A_SPACE; \
+ abb = A_NOTWORD; \
+ if (unmap_tst) \
+ txt_unmap(sp, tp, &iflags); \
/* Handle hex numbers. */ \
if (hex == H_INHEX) { \
- if (txt_hex(sp, tp, &tmp, ch)) \
+ if (txt_hex(sp, tp, &tmp, &ch)) \
goto err; \
if (tmp) { \
hex = H_NOTSET; \
goto next_ch; \
} \
} \
- /* \
- * The 'R' command returns any overwriteable \
- * characters in the first line to the original \
- * characters.
- */ \
- if (LF_ISSET(TXT_REPLACE) && tp->owrite && \
- tp == tiqh->cqh_first) { \
- memmove(tp->lb + sp->cno, \
- lp + sp->cno, tp->owrite); \
- tp->insert += tp->owrite; \
- tp->owrite = 0; \
- } \
+ /* Clean up for the 'R' command. */ \
+ if (LF_ISSET(TXT_REPLACE)) \
+ txt_Rcleanup(sp, tiqh, tp, lp, len); \
/* Delete any appended cursor. */ \
if (LF_ISSET(TXT_APPENDEOL)) { \
--tp->len; \
@@ -536,7 +526,7 @@ next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
/* New lines are TXT_APPENDEOL if nothing to insert. */
if (ntp->insert == 0) {
- TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
+ TBINC(sp, ntp->lb, ntp->lb_len, ntp->len + 1);
LF_SET(TXT_APPENDEOL);
ntp->lb[sp->cno] = CURSOR_CH;
++ntp->insert;
@@ -643,7 +633,7 @@ k_escape: if (tp->insert && tp->owrite)
if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
carat_st = C_ZEROSET;
goto ins_ch;
- case K_VEOF: /* Delete autoindent char. */
+ case K_CNTRLD: /* Delete autoindent char. */
/*
* If in the first column or no characters to erase,
* ignore the ^D (this matches historic practice). If
@@ -804,7 +794,7 @@ leftmargin: tp->lb[sp->cno - 1] = ' ';
* tty interface and the historic tty driver behavior,
* respectively, and the default is the same as the
* historic vi behavior.
- */
+ */
if (LF_ISSET(TXT_TTYWERASE))
while (sp->cno > max) {
--sp->cno;
@@ -887,7 +877,7 @@ leftmargin: tp->lb[sp->cno - 1] = ' ';
case K_VLNEXT: /* Quote the next character. */
/* If in hex mode, see if we've entered a hex value. */
if (hex == H_INHEX) {
- if (txt_hex(sp, tp, &tmp, ch))
+ if (txt_hex(sp, tp, &tmp, &ch))
goto err;
if (tmp) {
hex = H_NOTSET;
@@ -896,26 +886,51 @@ leftmargin: tp->lb[sp->cno - 1] = ' ';
}
ch = '^';
quoted = Q_NEXTCHAR;
- /* FALLTHROUGH */
+ goto insq_ch;
default: /* Insert the character. */
ins_ch: /*
- * If entering a space character after a word, check
+ * Historically, vi eliminated nul's out of hand. If
+ * the beautify option was set, it also deleted any
+ * unknown ASCII value less than space (040) and the
+ * del character (0177), except for tabs. Unknown is
+ * a key word here. Most vi documentation claims that
+ * it deleted everything but <tab>, <nl> and <ff>, as
+ * that's what the original 4BSD documentation said.
+ * This is obviously wrong, however, as <esc> would be
+ * included in that list. What we do is eliminate any
+ * unquoted, iscntrl() character that wasn't a replay
+ * and wasn't handled specially, except <tab> or <ff>.
+ */
+ if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ch) &&
+ ikey.value != K_FORMFEED && ikey.value != K_TAB) {
+ msgq(sp, M_BERR,
+ "Illegal character; quote to enter.");
+ break;
+ }
+insq_ch: /*
+ * If entering a non-word character after a word, check
* for abbreviations. If there was one, discard the
- * replay characters.
+ * replay characters. If entering a blank character,
+ * check for unmap commands, as well.
*/
- if (isblank(ch) && abb == A_NOTSPACE && !replay) {
- if (txt_abbrev(sp, tp, ch,
- LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff))
- goto err;
- if (tmp) {
- if (LF_ISSET(TXT_RECORD))
- rcol -= tmp;
- goto next_ch;
+ if (!inword(ch)) {
+ if (abb == A_INWORD && !replay) {
+ if (txt_abbrev(sp, tp, &ch,
+ LF_ISSET(TXT_INFOLINE),
+ &tmp, &ab_turnoff))
+ goto err;
+ if (tmp) {
+ if (LF_ISSET(TXT_RECORD))
+ rcol -= tmp;
+ goto next_ch;
+ }
}
+ if (isblank(ch) && unmap_tst)
+ txt_unmap(sp, tp, &iflags);
}
/* If in hex mode, see if we've entered a hex value. */
if (hex == H_INHEX && !isxdigit(ch)) {
- if (txt_hex(sp, tp, &tmp, ch))
+ if (txt_hex(sp, tp, &tmp, &ch))
goto err;
if (tmp) {
hex = H_NOTSET;
@@ -927,14 +942,14 @@ ins_ch: /*
if (sp->s_column(sp, ep, &col))
goto err;
if (col >= margin) {
- if (txt_margin(sp, tp, &tmp, ch))
+ if (txt_margin(sp, tp, &tmp, &ch))
goto err;
if (tmp)
goto next_ch;
}
}
if (abb != A_NOTSET)
- abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
+ abb = inword(ch) ? A_INWORD : A_NOTWORD;
if (tp->owrite) /* Overwrite a character. */
--tp->owrite;
@@ -996,10 +1011,10 @@ err: eval = 1;
* Handle abbreviations.
*/
static int
-txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
+txt_abbrev(sp, tp, pushcp, isinfoline, didsubp, turnoffp)
SCR *sp;
TEXT *tp;
- ARG_CHAR_T pushc;
+ CHAR_T *pushcp;
int isinfoline, *didsubp, *turnoffp;
{
CHAR_T ch;
@@ -1007,9 +1022,12 @@ txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
size_t len, off;
char *p;
- /* Find the beginning of this "word". */
+ /*
+ * Find the start of the "word". Historically, abbreviations
+ * could be preceded by any non-word character.
+ */
for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
- if (isblank(*p)) {
+ if (!inword(*p)) {
++p;
break;
}
@@ -1050,7 +1068,7 @@ txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
* string which is <blank> terminated and which starts at the beginning
* of the line, we check to see it is the abbreviate or unabbreviate
* commands. If it is, turn abbreviations off and return as if no
- * abbreviation was found. Not also, minor trickiness, so that if the
+ * abbreviation was found. Note also, minor trickiness, so that if the
* user erases the line and starts another command, we go ahead an turn
* abbreviations back on.
*
@@ -1090,7 +1108,7 @@ txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
* queue would have to be adjusted, and the line state when an initial
* abbreviated character was received would have to be saved.
*/
- ch = pushc;
+ ch = *pushcp;
if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))
return (1);
if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))
@@ -1119,6 +1137,50 @@ txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
return (0);
}
+/*
+ * txt_unmap --
+ * Handle the unmap command.
+ */
+static void
+txt_unmap(sp, tp, iflagsp)
+ SCR *sp;
+ TEXT *tp;
+ u_int *iflagsp;
+{
+ size_t len, off;
+ char *p;
+
+ /* Find the beginning of this "word". */
+ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
+ if (isblank(*p)) {
+ ++p;
+ break;
+ }
+ ++len;
+ if (off == tp->ai || off == tp->offset)
+ break;
+ }
+
+ /*
+ * !!!
+ * Historic vi exploded input mappings on the command line. See the
+ * txt_abbrev() routine for an explanation of the problems inherent
+ * in this.
+ *
+ * We make this work as follows. If we get a string which is <blank>
+ * terminated and which starts at the beginning of the line, we check
+ * to see it is the unmap command. If it is, we return that the input
+ * mapping should be turned off. Note also, minor trickiness, so that
+ * if the user erases the line and starts another command, we go ahead
+ * an turn mapping back on.
+ */
+ if ((off == tp->ai || off == tp->offset) && ex_is_unmap(p, len))
+ *iflagsp &= ~TXT_MAPINPUT;
+ else
+ *iflagsp |= TXT_MAPINPUT;
+}
+
+
/* Offset to next column of stop size. */
#define STOP_OFF(c, stop) (stop - (c) % stop)
@@ -1212,38 +1274,34 @@ txt_auto(sp, ep, lno, aitp, len, tp)
{
size_t nlen;
char *p, *t;
-
+
if (aitp == NULL) {
- if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
+ if ((t = file_gline(sp, ep, lno, &len)) == NULL)
return (0);
} else
- p = t = aitp->lb;
- for (nlen = 0; len; ++p) {
+ t = aitp->lb;
+
+ /* Count whitespace characters. */
+ for (p = t; len > 0; ++p, --len)
if (!isblank(*p))
break;
- /* If last character is a space, it counts. */
- if (--len == 0) {
- ++p;
- break;
- }
- }
- /* No indentation. */
- if (p == t)
+ /* Set count, check for no indentation. */
+ if ((nlen = (p - t)) == 0)
return (0);
- /* Set count. */
- nlen = p - t;
-
/* Make sure the buffer's big enough. */
BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
+ /* Copy the buffer's current contents up. */
+ if (tp->len != 0)
+ memmove(tp->lb + nlen, tp->lb, tp->len);
+ tp->len += nlen;
+
/* Copy the indentation into the new buffer. */
- memmove(tp->lb + nlen, tp->lb, tp->len);
memmove(tp->lb, t, nlen);
- tp->len += nlen;
- /* Return the additional length. */
+ /* Set the autoindent count. */
tp->ai = nlen;
return (0);
}
@@ -1353,11 +1411,11 @@ txt_err(sp, ep, tiqh)
* may not be able to enter.
*/
static int
-txt_hex(sp, tp, was_hex, pushc)
+txt_hex(sp, tp, was_hex, pushcp)
SCR *sp;
TEXT *tp;
int *was_hex;
- ARG_CHAR_T pushc;
+ CHAR_T *pushcp;
{
CHAR_T ch, savec;
size_t len, off;
@@ -1395,8 +1453,8 @@ nothex: tp->lb[sp->cno] = savec;
*was_hex = 0;
return (0);
}
-
- ch = pushc;
+
+ ch = *pushcp;
if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
return (1);
ch = value;
@@ -1676,11 +1734,11 @@ txt_showmatch(sp, ep)
* break the line. I don't, it tends to wake the cats.
*/
static int
-txt_margin(sp, tp, didbreak, pushc)
+txt_margin(sp, tp, didbreak, pushcp)
SCR *sp;
TEXT *tp;
int *didbreak;
- ARG_CHAR_T pushc;
+ CHAR_T *pushcp;
{
CHAR_T ch;
size_t len, off, tlen;
@@ -1712,7 +1770,7 @@ txt_margin(sp, tp, didbreak, pushc)
break;
}
- ch = pushc;
+ ch = *pushcp;
if (term_push(sp, &ch, 1, 0, CH_NOMAP))
return (1);
if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED))
@@ -1726,3 +1784,44 @@ txt_margin(sp, tp, didbreak, pushc)
*didbreak = 1;
return (0);
}
+
+/*
+ * txt_Rcleanup --
+ * Resolve the input line for the 'R' command.
+ */
+static void
+txt_Rcleanup(sp, tiqh, tp, lp, len)
+ SCR *sp;
+ TEXTH *tiqh;
+ TEXT *tp;
+ const char *lp;
+ const size_t len;
+{
+ size_t tmp;
+
+ /*
+ * The 'R' command restores any overwritable characters in the
+ * first line to the original characters. Check to make sure
+ * that the cursor hasn't moved beyond the end of the original
+ * line.
+ */
+ if (tp != tiqh->cqh_first || tp->owrite == 0 || sp->cno >= len)
+ return;
+
+ /* Restore whatever we can restore from the original line. */
+ tmp = MIN(tp->owrite, len - sp->cno);
+ memmove(tp->lb + sp->cno, lp + sp->cno, tmp);
+
+ /*
+ * There can be more overwrite characters if the user extended the
+ * line and then erased it. What we have to do is delete whatever
+ * the user inserted and then erased. Regardless, we increase the
+ * insert character count to make the TEXT structure look right.
+ * (There shouldn't be any insert characters as 'R' replaces the
+ * entire line; if there are, this code isn't going to work).
+ */
+ if (tp->owrite > tmp)
+ tp->len -= tp->owrite - tmp;
+ tp->owrite = 0;
+ tp->insert = tmp;
+}
diff --git a/usr.bin/vi/nvi/v_paragraph.c b/usr.bin/vi/vi/v_paragraph.c
index 00591cbe899e..ceed57c7613e 100644
--- a/usr.bin/vi/nvi/v_paragraph.c
+++ b/usr.bin/vi/vi/v_paragraph.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,21 +32,31 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_paragraph.c 8.4 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)v_paragraph.c 8.9 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
/*
- * Paragraphs are empty lines after text or values from the paragraph or
- * section options.
+ * Paragraphs are empty lines after text or values from the paragraph
+ * or section options.
*/
/*
@@ -54,25 +64,50 @@ static char sccsid[] = "@(#)v_paragraph.c 8.4 (Berkeley) 12/9/93";
* Move forward count paragraphs.
*/
int
-v_paragraphf(sp, ep, vp, fm, tm, rp)
+v_paragraphf(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
enum { P_INTEXT, P_INBLANK } pstate;
size_t lastlen, len;
recno_t cnt, lastlno, lno;
char *p, *lp;
+ /*
+ * !!!
+ * If the starting cursor position is at or before any non-blank
+ * characters in the line, i.e. the movement is cutting all of the
+ * line's text, the buffer is in line mode. It's a lot easier to
+ * check here, because we know that the end is going to be the start
+ * or end of a line.
+ *
+ * This was historical practice in vi, with a single exception. If
+ * the paragraph movement was from the start of the last line to EOF,
+ * then all the characters were deleted from the last line, but the
+ * line itself remained. If somebody complains, don't pause, don't
+ * hesitate, just hit them.
+ */
+ if (ISMOTION(vp))
+ if (vp->m_start.cno == 0)
+ F_SET(vp, VM_LMODE);
+ else {
+ vp->m_stop = vp->m_start;
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno))
+ return (1);
+ if (vp->m_start.cno <= vp->m_stop.cno)
+ F_SET(vp, VM_LMODE);
+ }
+
/* Figure out what state we're currently in. */
- lno = fm->lno;
+ lno = vp->m_start.lno;
if ((p = file_gline(sp, ep, lno, &len)) == NULL)
goto eof;
/*
- * If we start in text, we want to switch states 2 * N - 1
- * times, in non-text, 2 * N times.
+ * If we start in text, we want to switch states
+ * (2 * N - 1) times, in non-text, (2 * N) times.
*/
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
cnt *= 2;
@@ -110,16 +145,22 @@ v_paragraphf(sp, ep, vp, fm, tm, rp)
break;
}
/*
- * Historically, a motion command was up to the end
- * of the previous line, whereas the movement command
- * was to the start of the new "paragraph".
+ * !!!
+ * Non-motion commands move to the end of the range,
+ * VC_D and VC_Y stay at the start. Ignore VC_C and
+ * VC_S. Adjust end of the range for motion commands;
+ * historically, a motion component was to the end of
+ * the previous line, whereas the movement command was
+ * to the start of the new "paragraph".
*/
-found: if (F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- rp->lno = lastlno;
- rp->cno = lastlen ? lastlen + 1 : 0;
+found: if (ISMOTION(vp)) {
+ vp->m_stop.lno = lastlno;
+ vp->m_stop.cno = lastlen ? lastlen - 1 : 0;
+ vp->m_final = vp->m_start;
} else {
- rp->lno = lno;
- rp->cno = 0;
+ vp->m_stop.lno = lno;
+ vp->m_stop.cno = 0;
+ vp->m_final = vp->m_stop;
}
return (0);
default:
@@ -128,35 +169,49 @@ found: if (F_ISSET(vp, VC_C | VC_D | VC_Y)) {
}
/*
- * EOF is a movement sink, however, the } command historically
- * moved to the end of the last line if repeatedly invoked.
+ * !!!
+ * Adjust end of the range for motion commands; EOF is a movement
+ * sink. The } command historically moved to the end of the last
+ * line, not the beginning, from any position before the end of the
+ * last line.
*/
-eof: if (fm->lno != lno - 1) {
- rp->lno = lno - 1;
- rp->cno = len ? len - 1 : 0;
- return (0);
+eof: if (vp->m_start.lno == lno - 1) {
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ if (vp->m_start.cno == (len ? len - 1 : 0)) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
}
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL)
- GETLINE_ERR(sp, fm->lno);
- if (fm->cno != (len ? len - 1 : 0)) {
- rp->lno = lno - 1;
- rp->cno = len ? len - 1 : 0;
- return (0);
+ /*
+ * !!!
+ * Non-motion commands move to the end of the range, VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S.
+ *
+ * If deleting the line (which happens if deleting to EOF),
+ * then cursor movement is to the first nonblank.
+ */
+ if (F_ISSET(vp, VC_D)) {
+ F_CLR(vp, VM_RCM_MASK);
+ F_SET(vp, VM_RCM_SETFNB);
}
- v_eof(sp, ep, NULL);
- return (1);
+ vp->m_stop.lno = lno - 1;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
}
/*
* v_paragraphb -- [count]{
- * Move forward count paragraph.
+ * Move backward count paragraphs.
*/
int
-v_paragraphb(sp, ep, vp, fm, tm, rp)
+v_paragraphb(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
enum { P_INTEXT, P_INBLANK } pstate;
size_t len;
@@ -164,29 +219,45 @@ v_paragraphb(sp, ep, vp, fm, tm, rp)
char *p, *lp;
/*
+ * !!!
+ * Check for SOF. The historic vi didn't complain if users hit SOF
+ * repeatedly, unless it was part of a motion command. There is no
+ * question but that Emerson's editor of choice was vi.
+ *
* The { command historically moved to the beginning of the first
* line if invoked on the first line.
*
- * Check for SOF.
+ * !!!
+ * If the starting cursor position is in the first column (backward
+ * paragraph movements did NOT historically pay attention to non-blank
+ * characters) i.e. the movement is cutting the entire line, the buffer
+ * is in line mode. Cuts from the beginning of the line also did not
+ * cut the current line, but started at the previous EOL.
+ *
+ * Correct for a left motion component while we're thinking about it.
*/
- if (fm->lno <= 1) {
- if (fm->cno == 0) {
- v_sof(sp, NULL);
- return (1);
- }
- rp->lno = 1;
- rp->cno = 0;
- return (0);
- }
+ lno = vp->m_start.lno;
+ if (ISMOTION(vp))
+ if (vp->m_start.cno == 0) {
+ if (vp->m_start.lno == 1) {
+ v_sof(sp, &vp->m_start);
+ return (1);
+ } else
+ --vp->m_start.lno;
+ F_SET(vp, VM_LMODE);
+ } else
+ --vp->m_start.cno;
+
+ if (vp->m_start.lno <= 1)
+ goto sof;
/* Figure out what state we're currently in. */
- lno = fm->lno;
if ((p = file_gline(sp, ep, lno, &len)) == NULL)
goto sof;
/*
- * If we start in text, we want to switch states 2 * N - 1
- * times, in non-text, 2 * N times.
+ * If we start in text, we want to switch states
+ * (2 * N - 1) times, in non-text, (2 * N) times.
*/
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
cnt *= 2;
@@ -207,20 +278,17 @@ v_paragraphb(sp, ep, vp, fm, tm, rp)
if (lp[0] == p[1] &&
(lp[1] == ' ' || lp[1] == p[2]) &&
!--cnt)
- goto found;
+ goto ret;
if (len == 0 || v_isempty(p, len)) {
if (!--cnt)
- goto found;
+ goto ret;
pstate = P_INBLANK;
}
break;
case P_INBLANK:
if (len != 0 && !v_isempty(p, len)) {
- if (!--cnt) {
-found: rp->lno = lno;
- rp->cno = 0;
- return (0);
- }
+ if (!--cnt)
+ goto ret;
pstate = P_INTEXT;
}
break;
@@ -230,8 +298,16 @@ found: rp->lno = lno;
}
/* SOF is a movement sink. */
-sof: rp->lno = 1;
- rp->cno = 0;
+sof: lno = 1;
+
+ret: vp->m_stop.lno = lno;
+ vp->m_stop.cno = 0;
+
+ /*
+ * VC_D and non-motion commands move to the end of the range,
+ * VC_Y stays at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
return (0);
}
diff --git a/usr.bin/vi/nvi/v_put.c b/usr.bin/vi/vi/v_put.c
index 60227ea4ccfd..d427c332add5 100644
--- a/usr.bin/vi/nvi/v_put.c
+++ b/usr.bin/vi/vi/v_put.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_put.c 8.6 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)v_put.c 8.8 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -47,16 +58,16 @@ static void inc_buf __P((SCR *, VICMDARG *));
* Insert the contents of the buffer before the cursor.
*/
int
-v_Put(sp, ep, vp, fm, tm, rp)
+v_Put(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
if (F_ISSET(vp, VC_ISDOT))
inc_buf(sp, vp);
- return (put(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, rp, 0));
+
+ return (put(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_final, 0));
}
/*
@@ -64,20 +75,20 @@ v_Put(sp, ep, vp, fm, tm, rp)
* Insert the contents of the buffer after the cursor.
*/
int
-v_put(sp, ep, vp, fm, tm, rp)
+v_put(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
if (F_ISSET(vp, VC_ISDOT))
inc_buf(sp, vp);
- return (put(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, rp, 1));
+ return (put(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_final, 1));
}
/*
+ * !!!
* Historical whackadoo. The dot command `puts' the numbered buffer
* after the last one put. For example, `"4p.' would put buffer #4
* and buffer #5. If the user continued to enter '.', the #9 buffer
diff --git a/usr.bin/vi/nvi/v_redraw.c b/usr.bin/vi/vi/v_redraw.c
index fca5ba33b713..b124e4acae44 100644
--- a/usr.bin/vi/nvi/v_redraw.c
+++ b/usr.bin/vi/vi/v_redraw.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,24 +32,34 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_redraw.c 8.2 (Berkeley) 8/25/93";
+static char sccsid[] = "@(#)v_redraw.c 8.4 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
/*
- * v_redraw --
+ * v_redraw -- ^R
* Redraw the screen.
*/
int
-v_redraw(sp, ep, vp, fm, tm, rp)
+v_redraw(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
F_SET(sp, S_REFRESH);
return (0);
diff --git a/usr.bin/vi/nvi/v_replace.c b/usr.bin/vi/vi/v_replace.c
index f9378e7ac4ed..a9e7c470a270 100644
--- a/usr.bin/vi/nvi/v_replace.c
+++ b/usr.bin/vi/vi/v_replace.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,33 +32,44 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_replace.c 8.12 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)v_replace.c 8.15 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
/*
* v_replace -- [count]rc
- * The r command in historic vi was almost beautiful in its badness.
- * For example, "r<erase>" and "r<word erase>" beeped the terminal
- * and deleted a single character. "Nr<carriage return>", where N
- * was greater than 1, inserted a single carriage return. This may
- * not be right, but at least it's not insane.
+ *
+ * !!!
+ * The r command in historic vi was almost beautiful in its badness. For
+ * example, "r<erase>" and "r<word erase>" beeped the terminal and deleted
+ * a single character. "Nr<carriage return>", where N was greater than 1,
+ * inserted a single carriage return. This may not be right, but at least
+ * it's not insane.
*/
int
-v_replace(sp, ep, vp, fm, tm, rp)
+v_replace(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
CH ikey;
TEXT *tp;
@@ -78,35 +89,39 @@ v_replace(sp, ep, vp, fm, tm, rp)
* the end of the line, also work.
* 3: Replacing a newline has somewhat odd semantics.
*/
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
goto nochar;
}
if (len == 0) {
-nochar: msgq(sp, M_BERR, "No characters to replace");
+nochar: msgq(sp, M_BERR, "No characters to replace.");
return (1);
}
/*
- * Figure out how many characters to be replace; for no particular
- * reason other than that the semantics of replacing the newline
- * are confusing, only permit the replacement of the characters in
- * the current line. I suppose we could simply append the replacement
- * characters to the line, but I see no compelling reason to do so.
+ * Figure out how many characters to be replace. For no particular
+ * reason (other than that the semantics of replacing the newline
+ * are confusing) only permit the replacement of the characters in
+ * the current line. I suppose we could append replacement characters
+ * to the line, but I see no compelling reason to do so.
*/
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- rp->cno = fm->cno + cnt - 1;
- if (rp->cno > len - 1) {
- v_eol(sp, ep, fm);
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno = vp->m_start.cno + cnt - 1;
+ if (vp->m_stop.cno > len - 1) {
+ v_eol(sp, ep, &vp->m_start);
return (1);
}
- /* Get the character, literal escapes, escape terminates. */
+ /*
+ * Get the character. Literal escapes escape any character,
+ * single escapes return.
+ */
if (F_ISSET(vp, VC_ISDOT)) {
ikey.ch = VIP(sp)->rlast;
ikey.value = term_key_val(sp, ikey.ch);
@@ -115,7 +130,6 @@ nochar: msgq(sp, M_BERR, "No characters to replace");
return (1);
switch (ikey.value) {
case K_ESCAPE:
- *rp = *fm;
return (0);
case K_VLNEXT:
if (term_key(sp, &ikey, 0) != INP_OK)
@@ -132,10 +146,11 @@ nochar: msgq(sp, M_BERR, "No characters to replace");
if (ikey.value == K_CR || ikey.value == K_NL) {
/* Set return line. */
- rp->lno = fm->lno + cnt;
+ vp->m_stop.lno = vp->m_start.lno + cnt;
+ vp->m_stop.cno = 0;
/* The first part of the current line. */
- if (file_sline(sp, ep, fm->lno, p, fm->cno))
+ if (file_sline(sp, ep, vp->m_start.lno, p, vp->m_start.cno))
goto err_ret;
/*
@@ -144,33 +159,32 @@ nochar: msgq(sp, M_BERR, "No characters to replace");
* stripped, and autoindent is applied. Put the cursor on the
* last indent character as did historic vi.
*/
- for (p += fm->cno + cnt, len -= fm->cno + cnt;
+ for (p += vp->m_start.cno + cnt, len -= vp->m_start.cno + cnt;
len && isblank(*p); --len, ++p);
if ((tp = text_init(sp, p, len, len)) == NULL)
goto err_ret;
- if (txt_auto(sp, ep, fm->lno, NULL, 0, tp))
+ if (txt_auto(sp, ep, vp->m_start.lno, NULL, 0, tp))
goto err_ret;
- rp->cno = tp->ai ? tp->ai - 1 : 0;
- if (file_aline(sp, ep, 1, fm->lno, tp->lb, tp->len))
+ vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0;
+ if (file_aline(sp, ep, 1, vp->m_start.lno, tp->lb, tp->len))
goto err_ret;
text_free(tp);
-
+
rval = 0;
/* All of the middle lines. */
while (--cnt)
- if (file_aline(sp, ep, 1, fm->lno, "", 0)) {
+ if (file_aline(sp, ep, 1, vp->m_start.lno, "", 0)) {
err_ret: rval = 1;
break;
}
} else {
- memset(bp + fm->cno, ikey.ch, cnt);
- rval = file_sline(sp, ep, fm->lno, bp, len);
-
- rp->lno = fm->lno;
- rp->cno = fm->cno + cnt - 1;
+ memset(bp + vp->m_start.cno, ikey.ch, cnt);
+ rval = file_sline(sp, ep, vp->m_start.lno, bp, len);
}
FREE_SPACE(sp, bp, blen);
+
+ vp->m_final = vp->m_stop;
return (rval);
}
diff --git a/usr.bin/vi/nvi/v_right.c b/usr.bin/vi/vi/v_right.c
index 54b7be92d005..3d78e781400c 100644
--- a/usr.bin/vi/nvi/v_right.c
+++ b/usr.bin/vi/vi/v_right.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_right.c 8.3 (Berkeley) 12/16/93";
+static char sccsid[] = "@(#)v_right.c 8.6 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -43,47 +54,57 @@ static char sccsid[] = "@(#)v_right.c 8.3 (Berkeley) 12/16/93";
/*
* v_right -- [count]' ', [count]l
* Move right by columns.
- *
- * Special case: the 'c' and 'd' commands can move past the end of line.
*/
int
-v_right(sp, ep, vp, fm, tm, rp)
+v_right(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
- u_long cnt;
size_t len;
- if (file_gline(sp, ep, fm->lno, &len) == NULL) {
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno == 0)
v_eol(sp, ep, NULL);
else
- GETLINE_ERR(sp, fm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
-
- rp->lno = fm->lno;
- if (len == 0 || fm->cno == len - 1) {
- if (F_ISSET(vp, VC_C | VC_D | VC_Y)) {
- rp->cno = len;
- return (0);
- }
+
+ /* It's always illegal to move right on empty lines. */
+ if (len == 0) {
v_eol(sp, ep, NULL);
return (1);
}
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- rp->cno = fm->cno + cnt;
- if (rp->cno > len - 1)
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- rp->cno = len;
- else
- rp->cno = len - 1;
+ /*
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S. Adjust the
+ * end of the range for motion commands.
+ *
+ * !!!
+ * Historically, "[cdsy]l" worked at the end of a line. Also,
+ * EOL is a count sink.
+ */
+ vp->m_stop.cno = vp->m_start.cno +
+ (F_ISSET(vp, VC_C1SET) ? vp->count : 1);
+ if (vp->m_start.cno == len - 1) {
+ if (!ISMOTION(vp)) {
+ v_eol(sp, ep, NULL);
+ return (1);
+ }
+ vp->m_stop.cno = vp->m_start.cno;
+ } else if (vp->m_stop.cno > len - 1)
+ vp->m_stop.cno = len - 1;
+
+ if (ISMOTION(vp)) {
+ --vp->m_stop.cno;
+ vp->m_final = vp->m_start;
+ } else
+ vp->m_final = vp->m_stop;
return (0);
}
@@ -92,53 +113,51 @@ v_right(sp, ep, vp, fm, tm, rp)
* Move to the last column.
*/
int
-v_dollar(sp, ep, vp, fm, tm, rp)
+v_dollar(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
size_t len;
- u_long cnt;
/*
- * A count moves down count - 1 rows, so, "3$" is the same as "2j$".
- *
* !!!
- * Historically, if the $ is a motion, and deleting from at or before
- * the first non-blank of the line, it's a line motion, and the line
- * motion flag is set.
+ * A count moves down count - 1 rows, so, "3$" is the same as "2j$".
*/
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- if (cnt != 1) {
- --vp->count;
- if (v_down(sp, ep, vp, fm, tm, rp))
+ if ((F_ISSET(vp, VC_C1SET) ? vp->count : 1) != 1) {
+ /*
+ * !!!
+ * Historically, if the $ is a motion, and deleting from
+ * at or before the first non-blank of the line, it's a
+ * line motion, and the line motion flag is set.
+ */
+ vp->m_stop.cno = 0;
+ if (nonblank(sp, ep, vp->m_start.lno, &vp->m_stop.cno))
return (1);
- rp->cno = 0;
- if (nonblank(sp, ep, rp->lno, &rp->cno))
+ if (ISMOTION(vp) && vp->m_start.cno <= vp->m_stop.cno)
+ F_SET(vp, VM_LMODE);
+
+ --vp->count;
+ if (v_down(sp, ep, vp))
return (1);
- if (fm->cno <= rp->cno && F_ISSET(vp, VC_C | VC_D | VC_Y))
- F_SET(vp, VC_LMODE);
- } else
- rp->lno = fm->lno;
+ }
- if (file_gline(sp, ep, rp->lno, &len) == NULL) {
+ if (file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno == 0)
v_eol(sp, ep, NULL);
else
- GETLINE_ERR(sp, rp->lno);
- return (1);
- }
-
- if (len == 0) {
- v_eol(sp, ep, NULL);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
- /* If it's a motion component, move one past the end of the line. */
- rp->cno = F_ISSET(vp, VC_C | VC_D | VC_Y) ? len : len - 1;
+ /*
+ * Non-motion commands move to the end of the range.
+ * VC_D and VC_Y stay at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_stop.cno = len ? len - 1 : 0;
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
return (0);
}
diff --git a/usr.bin/vi/nvi/v_screen.c b/usr.bin/vi/vi/v_screen.c
index 986bfa4f29a2..0a4e8b009feb 100644
--- a/usr.bin/vi/nvi/v_screen.c
+++ b/usr.bin/vi/vi/v_screen.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,24 +32,34 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_screen.c 8.8 (Berkeley) 11/28/93";
+static char sccsid[] = "@(#)v_screen.c 8.10 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
/*
- * v_screen --
+ * v_screen -- ^W
* Switch screens.
*/
int
-v_screen(sp, ep, vp, fm, tm, rp)
+v_screen(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/*
* Try for the next lower screen, or, go back to the first
@@ -67,7 +77,7 @@ v_screen(sp, ep, vp, fm, tm, rp)
* Display the old screen's status line so the user can
* find the screen they want.
*/
- (void)status(sp, ep, fm->lno, 0);
+ (void)status(sp, ep, vp->m_start.lno, 0);
/* Save the old screen's cursor information. */
sp->frp->lno = sp->lno;
diff --git a/usr.bin/vi/nvi/v_scroll.c b/usr.bin/vi/vi/v_scroll.c
index f69ea0fb4e87..ec9c26dc2955 100644
--- a/usr.bin/vi/nvi/v_scroll.c
+++ b/usr.bin/vi/vi/v_scroll.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,17 +32,29 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_scroll.c 8.8 (Berkeley) 12/16/93";
+static char sccsid[] = "@(#)v_scroll.c 8.14 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
#include "vcmd.h"
+static void goto_adjust __P((VICMDARG *));
+
/*
* The historic vi had a problem in that all movements were by physical
* lines, not by logical, or screen lines. Arguments can be made that this
@@ -81,41 +93,44 @@ static char sccsid[] = "@(#)v_scroll.c 8.8 (Berkeley) 12/16/93";
* of the file by default.
*/
int
-v_lgoto(sp, ep, vp, fm, tm, rp)
+v_lgoto(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- recno_t last;
+ recno_t nlines;
- if (file_lline(sp, ep, &last))
- return (1);
if (F_ISSET(vp, VC_C1SET)) {
- if (last < vp->count) {
- v_eof(sp, ep, fm);
+ if (file_gline(sp, ep, vp->count, NULL) == NULL) {
+ v_eof(sp, ep, &vp->m_start);
return (1);
}
- rp->lno = vp->count;
- } else
- rp->lno = last ? last : 1;
+ vp->m_stop.lno = vp->count;
+ } else {
+ if (file_lline(sp, ep, &nlines))
+ return (1);
+ vp->m_stop.lno = nlines ? nlines : 1;
+ }
+ goto_adjust(vp);
return (0);
}
-/*
+/*
* v_home -- [count]H
* Move to the first non-blank character of the logical line
- * count from the top of the screen, 1 by default.
+ * count - 1 from the top of the screen, 0 by default.
*/
int
-v_home(sp, ep, vp, fm, tm, rp)
+v_home(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- return (sp->s_position(sp, ep, rp,
- F_ISSET(vp, VC_C1SET) ? vp->count : 0, P_TOP));
+ if (sp->s_position(sp, ep, &vp->m_stop,
+ F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_TOP))
+ return (1);
+ goto_adjust(vp);
+ return (0);
}
/*
@@ -124,34 +139,72 @@ v_home(sp, ep, vp, fm, tm, rp)
* in the middle of the screen.
*/
int
-v_middle(sp, ep, vp, fm, tm, rp)
+v_middle(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/*
* Yielding to none in our quest for compatibility with every
* historical blemish of vi, no matter how strange it might be,
* we permit the user to enter a count and then ignore it.
*/
- return (sp->s_position(sp, ep, rp, 0, P_MIDDLE));
+ if (sp->s_position(sp, ep, &vp->m_stop, 0, P_MIDDLE))
+ return (1);
+ goto_adjust(vp);
+ return (0);
}
/*
* v_bottom -- [count]L
* Move to the first non-blank character of the logical line
- * count from the bottom of the screen, 1 by default.
+ * count - 1 from the bottom of the screen, 0 by default.
*/
int
-v_bottom(sp, ep, vp, fm, tm, rp)
+v_bottom(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- return (sp->s_position(sp, ep,
- rp, F_ISSET(vp, VC_C1SET) ? vp->count : 0, P_BOTTOM));
+ if (sp->s_position(sp, ep, &vp->m_stop,
+ F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_BOTTOM))
+ return (1);
+ goto_adjust(vp);
+ return (0);
+}
+
+static void
+goto_adjust(vp)
+ VICMDARG *vp;
+{
+ /*
+ * !!!
+ * If it's not a yank to the current line or greater, and we've
+ * changed lines, move to the first non-blank of the line.
+ */
+ if (!F_ISSET(vp, VC_Y) || vp->m_stop.lno < vp->m_start.lno) {
+ F_CLR(vp, VM_RCM_MASK);
+ F_SET(vp, VM_RCM_SETLFNB);
+ }
+
+ /* Non-motion commands go to the end of the range. */
+ vp->m_final = vp->m_stop;
+ if (!ISMOTION(vp))
+ return;
+
+ /*
+ * If moving backward in the file, VC_D and VC_Y move to the end
+ * of the range, unless the line didn't change, in which case VC_Y
+ * doesn't move. If moving forward in the file, VC_D and VC_Y stay
+ * at the start of the range. Ignore VC_C and VC_S.
+ */
+ if (vp->m_stop.lno < vp->m_start.lno ||
+ vp->m_stop.lno == vp->m_start.lno &&
+ vp->m_stop.cno < vp->m_start.cno) {
+ if (F_ISSET(vp, VC_Y) && vp->m_stop.lno == vp->m_start.lno)
+ vp->m_final = vp->m_start;
+ } else
+ vp->m_final = vp->m_start;
}
/*
@@ -159,21 +212,20 @@ v_bottom(sp, ep, vp, fm, tm, rp)
* Move up by lines.
*/
int
-v_up(sp, ep, vp, fm, tm, rp)
+v_up(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
lno = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
-
- if (fm->lno <= lno) {
- v_sof(sp, fm);
+ if (vp->m_start.lno <= lno) {
+ v_sof(sp, &vp->m_start);
return (1);
}
- rp->lno = fm->lno - lno;
+ vp->m_stop.lno = vp->m_start.lno - lno;
+ vp->m_final = vp->m_stop;
return (0);
}
@@ -183,18 +235,17 @@ v_up(sp, ep, vp, fm, tm, rp)
* In a regular window, move down by lines.
*/
int
-v_cr(sp, ep, vp, fm, tm, rp)
+v_cr(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/*
* If it's a script window, exec the line,
* otherwise it's the same as v_down().
*/
return (F_ISSET(sp, S_SCRIPT) ?
- sscr_exec(sp, ep, fm->lno) : v_down(sp, ep, vp, fm, tm, rp));
+ sscr_exec(sp, ep, vp->m_start.lno) : v_down(sp, ep, vp));
}
/*
@@ -202,21 +253,20 @@ v_cr(sp, ep, vp, fm, tm, rp)
* Move down by lines.
*/
int
-v_down(sp, ep, vp, fm, tm, rp)
+v_down(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
- lno = fm->lno + (F_ISSET(vp, VC_C1SET) ? vp->count : 1);
-
+ lno = vp->m_start.lno + (F_ISSET(vp, VC_C1SET) ? vp->count : 1);
if (file_gline(sp, ep, lno, NULL) == NULL) {
- v_eof(sp, ep, fm);
+ v_eof(sp, ep, &vp->m_start);
return (1);
}
- rp->lno = lno;
+ vp->m_stop.lno = lno;
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
return (0);
}
@@ -225,23 +275,27 @@ v_down(sp, ep, vp, fm, tm, rp)
* Page up half screens.
*/
int
-v_hpageup(sp, ep, vp, fm, tm, rp)
+v_hpageup(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- /*
- * Half screens always succeed unless already at SOF. Half screens
- * set the scroll value, even if the command ultimately failed, in
- * historic vi. It's probably a don't care.
+ /*
+ * Half screens always succeed unless already at SOF.
+ *
+ * !!!
+ * Half screens set the scroll value, even if the command ultimately
+ * failed, in historic vi. Probably a don't care.
*/
if (F_ISSET(vp, VC_C1SET))
O_VAL(sp, O_SCROLL) = vp->count;
else
vp->count = O_VAL(sp, O_SCROLL);
- return (sp->s_down(sp, ep, rp, (recno_t)O_VAL(sp, O_SCROLL), 1));
+ if (sp->s_down(sp, ep, &vp->m_stop, (recno_t)O_VAL(sp, O_SCROLL), 1))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
}
/*
@@ -249,23 +303,27 @@ v_hpageup(sp, ep, vp, fm, tm, rp)
* Page down half screens.
*/
int
-v_hpagedown(sp, ep, vp, fm, tm, rp)
+v_hpagedown(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- /*
- * Half screens always succeed unless already at EOF. Half screens
- * set the scroll value, even if the command ultimately failed, in
- * historic vi. It's probably a don't care.
+ /*
+ * Half screens always succeed unless already at EOF.
+ *
+ * !!!
+ * Half screens set the scroll value, even if the command ultimately
+ * failed, in historic vi. Probably a don't care.
*/
if (F_ISSET(vp, VC_C1SET))
O_VAL(sp, O_SCROLL) = vp->count;
else
vp->count = O_VAL(sp, O_SCROLL);
- return (sp->s_up(sp, ep, rp, (recno_t)O_VAL(sp, O_SCROLL), 1));
+ if (sp->s_up(sp, ep, &vp->m_stop, (recno_t)O_VAL(sp, O_SCROLL), 1))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
}
/*
@@ -278,18 +336,17 @@ v_hpagedown(sp, ep, vp, fm, tm, rp)
* move to SOF in that case, making ^B more like the the historic ^U.
*/
int
-v_pageup(sp, ep, vp, fm, tm, rp)
+v_pageup(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- recno_t count;
-
/* Calculation from POSIX 1003.2/D8. */
- count = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (sp->t_rows - 1);
-
- return (sp->s_down(sp, ep, rp, count, 1));
+ if (sp->s_down(sp, ep, &vp->m_stop,
+ (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (sp->t_rows - 1), 1))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
}
/*
@@ -301,18 +358,17 @@ v_pageup(sp, ep, vp, fm, tm, rp)
* move to EOF in that case, making ^F more like the the historic ^D.
*/
int
-v_pagedown(sp, ep, vp, fm, tm, rp)
+v_pagedown(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- recno_t count;
-
/* Calculation from POSIX 1003.2/D8. */
- count = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (sp->t_rows - 1);
-
- return (sp->s_up(sp, ep, rp, count, 1));
+ if (sp->s_up(sp, ep, &vp->m_stop,
+ (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * (sp->t_rows - 1), 1))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
}
/*
@@ -320,18 +376,20 @@ v_pagedown(sp, ep, vp, fm, tm, rp)
* Page up by lines.
*/
int
-v_lineup(sp, ep, vp, fm, tm, rp)
+v_lineup(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/*
* The cursor moves down, staying with its original line, unless it
* reaches the bottom of the screen.
*/
- return (sp->s_down(sp, ep,
- rp, F_ISSET(vp, VC_C1SET) ? vp->count : 1, 0));
+ if (sp->s_down(sp, ep,
+ &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, 0))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
}
/*
@@ -339,16 +397,18 @@ v_lineup(sp, ep, vp, fm, tm, rp)
* Page down by lines.
*/
int
-v_linedown(sp, ep, vp, fm, tm, rp)
+v_linedown(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/*
* The cursor moves up, staying with its original line, unless it
* reaches the top of the screen.
*/
- return (sp->s_up(sp, ep,
- rp, F_ISSET(vp, VC_C1SET) ? vp->count : 1, 0));
+ if (sp->s_up(sp, ep,
+ &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, 0))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
}
diff --git a/usr.bin/vi/nvi/v_search.c b/usr.bin/vi/vi/v_search.c
index 25dcaf5e2e10..c6c950b88f81 100644
--- a/usr.bin/vi/nvi/v_search.c
+++ b/usr.bin/vi/vi/v_search.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,60 +32,44 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_search.c 8.16 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)v_search.c 8.22 (Berkeley) 3/17/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
-static int bcorrect __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, u_int));
-static int fcorrect __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, u_int));
+static int bcorrect __P((SCR *, EXF *, VICMDARG *, u_int));
+static int fcorrect __P((SCR *, EXF *, VICMDARG *, u_int));
static int getptrn __P((SCR *, EXF *, int, char **));
+static int search __P((SCR *, EXF *, VICMDARG *, char *, int, enum direction));
/*
* v_searchn -- n
* Repeat last search.
*/
int
-v_searchn(sp, ep, vp, fm, tm, rp)
+v_searchn(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- int flags;
-
- flags = SEARCH_MSG;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- flags |= SEARCH_EOL;
- switch (sp->searchdir) {
- case BACKWARD:
- if (b_search(sp, ep, fm, rp, NULL, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- bcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- break;
- case FORWARD:
- if (f_search(sp, ep, fm, rp, NULL, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y| VC_SH) &&
- fcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- break;
- case NOTSET:
- msgq(sp, M_ERR, "No previous search pattern.");
- return (1);
- default:
- abort();
- }
- return (0);
+ return (search(sp, ep, vp, NULL, SEARCH_MSG, sp->searchdir));
}
/*
@@ -93,71 +77,25 @@ v_searchn(sp, ep, vp, fm, tm, rp)
* Reverse last search.
*/
int
-v_searchN(sp, ep, vp, fm, tm, rp)
+v_searchN(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- int flags;
+ enum direction dir;
- flags = SEARCH_MSG;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- flags |= SEARCH_EOL;
switch (sp->searchdir) {
case BACKWARD:
- if (f_search(sp, ep, fm, rp, NULL, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- fcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
+ dir = FORWARD;
break;
case FORWARD:
- if (b_search(sp, ep, fm, rp, NULL, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- bcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
+ dir = BACKWARD;
+ break;
+ default: /* NOTSET handled in search(). */
+ dir = sp->searchdir;
break;
- case NOTSET:
- msgq(sp, M_ERR, "No previous search pattern.");
- return (1);
- default:
- abort();
}
- return (0);
-}
-
-/*
- * v_searchw -- [count]^A
- * Search for the word under the cursor.
- */
-int
-v_searchw(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- size_t blen, len;
- u_int flags;
- int rval;
- char *bp;
-
- len = vp->kbuflen + sizeof(RE_WSTART) + sizeof(RE_WSTOP);
- GET_SPACE_RET(sp, bp, blen, len);
- (void)snprintf(bp, blen, "%s%s%s", RE_WSTART, vp->keyword, RE_WSTOP);
-
- flags = SEARCH_MSG;
- rval = f_search(sp, ep, fm, rp, bp, NULL, &flags);
-
- FREE_SPACE(sp, bp, blen);
- if (rval)
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- fcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- return (0);
+ return (search(sp, ep, vp, NULL, SEARCH_MSG, dir));
}
/*
@@ -165,13 +103,11 @@ v_searchw(sp, ep, vp, fm, tm, rp)
* Search backward.
*/
int
-v_searchb(sp, ep, vp, fm, tm, rp)
+v_searchb(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- int flags;
char *ptrn;
if (F_ISSET(vp, VC_ISDOT))
@@ -179,19 +115,13 @@ v_searchb(sp, ep, vp, fm, tm, rp)
else {
if (getptrn(sp, ep, '?', &ptrn))
return (1);
- if (ptrn == NULL)
+ if (ptrn == NULL) {
+ F_SET(vp, VM_NOMOTION);
return (0);
+ }
}
-
- flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
- flags |= SEARCH_EOL;
- if (b_search(sp, ep, fm, rp, ptrn, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- bcorrect(sp, ep, vp, fm, rp, flags))
- return (1);
- return (0);
+ return (search(sp, ep, vp, ptrn,
+ SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM, BACKWARD));
}
/*
@@ -199,13 +129,11 @@ v_searchb(sp, ep, vp, fm, tm, rp)
* Search forward.
*/
int
-v_searchf(sp, ep, vp, fm, tm, rp)
+v_searchf(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- int flags;
char *ptrn;
if (F_ISSET(vp, VC_ISDOT))
@@ -213,18 +141,77 @@ v_searchf(sp, ep, vp, fm, tm, rp)
else {
if (getptrn(sp, ep, '/', &ptrn))
return (1);
- if (ptrn == NULL)
+ if (ptrn == NULL) {
+ F_SET(vp, VM_NOMOTION);
return (0);
+ }
}
+ return (search(sp, ep, vp, ptrn,
+ SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM, FORWARD));
+}
+
+/*
+ * v_searchw -- [count]^A
+ * Search for the word under the cursor.
+ */
+int
+v_searchw(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ size_t blen, len;
+ int rval;
+ char *bp;
+
+ len = vp->kbuflen + sizeof(RE_WSTART) + sizeof(RE_WSTOP);
+ GET_SPACE_RET(sp, bp, blen, len);
+ (void)snprintf(bp, blen, "%s%s%s", RE_WSTART, vp->keyword, RE_WSTOP);
+
+ rval = search(sp, ep, vp, bp, SEARCH_MSG, FORWARD);
+
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
- flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM;
- if (F_ISSET(vp, VC_C | VC_D | VC_Y))
+static int
+search(sp, ep, vp, ptrn, flags, dir)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ int flags;
+ char *ptrn;
+ enum direction dir;
+{
+ if (ISMOTION(vp))
flags |= SEARCH_EOL;
- if (f_search(sp, ep, fm, rp, ptrn, NULL, &flags))
- return (1);
- if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
- fcorrect(sp, ep, vp, fm, rp, flags))
+ switch (dir) {
+ case BACKWARD:
+ if (b_search(sp, ep,
+ &vp->m_start, &vp->m_stop, ptrn, NULL, &flags))
+ return (1);
+ /* Non-motion commands move to the end of the range. */
+ if (!ISMOTION(vp))
+ vp->m_final = vp->m_stop;
+ else if (bcorrect(sp, ep, vp, flags))
+ return (1);
+ break;
+ case FORWARD:
+ if (f_search(sp, ep,
+ &vp->m_start, &vp->m_stop, ptrn, NULL, &flags))
+ return (1);
+ /* Non-motion commands move to the end of the range. */
+ if (!ISMOTION(vp))
+ vp->m_final = vp->m_stop;
+ else if (fcorrect(sp, ep, vp, flags))
+ return (1);
+ break;
+ case NOTSET:
+ msgq(sp, M_ERR, "No previous search pattern.");
return (1);
+ default:
+ abort();
+ }
return (0);
}
@@ -269,7 +256,7 @@ getptrn(sp, ep, prompt, storep)
*
* placing the cursor on the 'A' and doing y?$ would so confuse it that 'h'
* 'k' and put would no longer work correctly. In any case, we try to do
- * the right thing, but it's not likely exactly match historic practice.
+ * the right thing, but it's not going to exactly match historic practice.
*/
/*
@@ -277,41 +264,52 @@ getptrn(sp, ep, prompt, storep)
* Handle command with a backward search as the motion.
*/
static int
-bcorrect(sp, ep, vp, fm, rp, flags)
+bcorrect(sp, ep, vp, flags)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *rp;
u_int flags;
{
size_t len;
- char *p;
+
+ /*
+ * VC_D commands move to the end of the range. VC_Y stays at the
+ * start unless the end of the range is on a different line, when
+ * it moves to the end of the range. Ignore VC_C and VC_S.
+ */
+ if (F_ISSET(vp, VC_D) ||
+ F_ISSET(vp, VC_Y) && vp->m_start.lno != vp->m_stop.lno)
+ vp->m_final = vp->m_stop;
+ else
+ vp->m_final = vp->m_start;
/*
* !!!
- * Correct backward searches which start at column 0 to be one
- * past the last column of the previous line.
+ * Correct backward searches which start at column 0 to be the last
+ * column of the previous line. Otherwise, adjust the starting point
+ * to the character before the current one.
*
* Backward searches become line mode operations if they start
* at column 0 and end at column 0 of another line.
*/
- if (fm->lno > rp->lno && fm->cno == 0) {
- if ((p = file_gline(sp, ep, --fm->lno, &len)) == NULL) {
- GETLINE_ERR(sp, rp->lno);
+ if (vp->m_start.lno > vp->m_stop.lno && vp->m_start.cno == 0) {
+ if (file_gline(sp, ep, --vp->m_start.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_stop.lno);
return (1);
}
- if (rp->cno == 0)
- F_SET(vp, VC_LMODE);
- fm->cno = len;
- }
+ if (vp->m_stop.cno == 0)
+ F_SET(vp, VM_LMODE);
+ vp->m_start.cno = len ? len - 1 : 0;
+ } else
+ --vp->m_start.cno;
/*
* !!!
- * Commands would become line mode operations if there was a delta
+ * Commands become line mode operations if there was a delta
* specified to the search pattern.
*/
if (LF_ISSET(SEARCH_DELTA)) {
- F_SET(vp, VC_LMODE);
+ F_SET(vp, VM_LMODE);
return (0);
}
return (0);
@@ -322,41 +320,44 @@ bcorrect(sp, ep, vp, fm, rp, flags)
* Handle command with a forward search as the motion.
*/
static int
-fcorrect(sp, ep, vp, fm, rp, flags)
+fcorrect(sp, ep, vp, flags)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *rp;
u_int flags;
{
size_t len;
- char *p;
+
+ /* VC_D and VC_Y commands stay at the start. Ignore VC_C and VC_S. */
+ vp->m_final = vp->m_start;
/*
* !!!
- * Correct forward searches which end at column 0 to be one
- * past the last column of the previous line.
+ * Correct forward searches which end at column 0 to be the last
+ * column of the previous line. Otherwise, adjust the ending
+ * point to the character before the current one.
*
* Forward searches become line mode operations if they start
* at column 0 and end at column 0 of another line.
*/
- if (fm->lno < rp->lno && rp->cno == 0) {
- if ((p = file_gline(sp, ep, --rp->lno, &len)) == NULL) {
- GETLINE_ERR(sp, rp->lno);
+ if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) {
+ if (file_gline(sp, ep, --vp->m_stop.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_stop.lno);
return (1);
}
- if (fm->cno == 0)
- F_SET(vp, VC_LMODE);
- rp->cno = len;
- }
+ if (vp->m_start.cno == 0)
+ F_SET(vp, VM_LMODE);
+ vp->m_stop.cno = len ? len - 1 : 0;
+ } else
+ --vp->m_stop.cno;
/*
* !!!
- * Commands would become line mode operations if there was a delta
+ * Commands become line mode operations if there was a delta
* specified to the search pattern.
*/
if (LF_ISSET(SEARCH_DELTA)) {
- F_SET(vp, VC_LMODE);
+ F_SET(vp, VM_LMODE);
return (0);
}
diff --git a/usr.bin/vi/vi/v_section.c b/usr.bin/vi/vi/v_section.c
new file mode 100644
index 000000000000..0ad8d76be282
--- /dev/null
+++ b/usr.bin/vi/vi/v_section.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_section.c 8.6 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * In historic vi, the section commands ignored empty lines, unlike the
+ * paragraph commands, which was probably okay. However, they also moved
+ * to the start of the last line when there where no more sections instead
+ * of the end of the last line like the paragraph commands. I've changed
+ * the latter behavior to match the paragraph commands.
+ *
+ * In historic vi, a "function" was defined as the first character of the
+ * line being an open brace, which could be followed by anything. This
+ * implementation follows that historic practice.
+ *
+ * !!!
+ * The historic vi documentation (USD:15-10) claimed:
+ * The section commands interpret a preceding count as a different
+ * window size in which to redraw the screen at the new location,
+ * and this window size is the base size for newly drawn windows
+ * until another size is specified. This is very useful if you are
+ * on a slow terminal ...
+ *
+ * I can't get the 4BSD vi to do this, it just beeps at me. For now, a
+ * count to the section commands simply repeats the command.
+ */
+
+static int section __P((SCR *, EXF *, VICMDARG *, int, enum direction));
+
+/*
+ * v_sectionf -- [count]]]
+ * Move forward count sections/functions.
+ */
+int
+v_sectionf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (section(sp, ep, vp, 1, FORWARD));
+}
+
+/*
+ * v_sectionb -- [count][[
+ * Move backward count sections/functions.
+ */
+int
+v_sectionb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* An empty file or starting from line 1 is always illegal. */
+ if (vp->m_start.lno <= 1) {
+ v_sof(sp, NULL);
+ return (1);
+ }
+ return (section(sp, ep, vp, -1, BACKWARD));
+}
+
+static int
+section(sp, ep, vp, off, dir)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ int off;
+ enum direction dir;
+{
+ size_t len;
+ recno_t cnt, lno;
+ int closeok;
+ char *p, *list, *lp;
+
+ /* Get the macro list. */
+ if ((list = O_STR(sp, O_SECTIONS)) == NULL)
+ return (1);
+
+ /*
+ * !!!
+ * Using ]] as a motion command was a bit special, historically.
+ * It could match } as well as the usual { and section values. If
+ * it matched a { or a section, it did NOT include the matched line.
+ * If it matched a }, it did include the line. Not a clue why.
+ */
+ closeok = ISMOTION(vp) && dir == FORWARD;
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ for (lno = vp->m_start.lno;
+ (p = file_gline(sp, ep, lno += off, &len)) != NULL;) {
+ if (len == 0)
+ continue;
+ if (p[0] == '{' || closeok && p[0] == '}') {
+ if (!--cnt) {
+ if (dir == FORWARD && ISMOTION(vp) &&
+ p[0] == '{' &&
+ file_gline(sp, ep, --lno, &len) == NULL)
+ return (1);
+ vp->m_stop.lno = lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ goto ret;
+ }
+ continue;
+ }
+ if (p[0] != '.' || len < 3)
+ continue;
+ for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
+ if (lp[0] == p[1] &&
+ (lp[1] == ' ' || lp[1] == p[2]) && !--cnt) {
+ if (dir == FORWARD && ISMOTION(vp) &&
+ file_gline(sp, ep, --lno, &len) == NULL)
+ return (1);
+ vp->m_stop.lno = lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ goto ret;
+ }
+ }
+
+ /*
+ * If moving forward, reached EOF, if moving backward, reached SOF.
+ * Both are movement sinks. The calling code has already checked
+ * for SOF, so all we check is EOF.
+ */
+ if (dir == FORWARD) {
+ if (vp->m_start.lno == lno - 1) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
+ vp->m_stop.lno = lno - 1;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ } else {
+ vp->m_stop.lno = 1;
+ vp->m_stop.cno = 0;
+ }
+
+ /*
+ * Non-motion commands go to the end of the range. If moving backward
+ * in the file, VC_D and VC_Y move to the end of the range. If moving
+ * forward in the file, VC_D and VC_Y stay at the start of the range.
+ * Ignore VC_C and VC_S.
+ *
+ * !!!
+ * Historic practice is the section cut was in line mode if it started
+ * from column 0 and was in the backward direction. I don't know why
+ * you'd want to cut an entire section in character mode, so I do it in
+ * line mode in both directions if the cut starts in column 0.
+ */
+ret: if (vp->m_start.cno == 0)
+ F_SET(vp, VM_LMODE);
+ vp->m_final = ISMOTION(vp) && dir == FORWARD ? vp->m_start : vp->m_stop;
+ return (0);
+}
diff --git a/usr.bin/vi/nvi/v_sentence.c b/usr.bin/vi/vi/v_sentence.c
index 684952124f14..678995b7057d 100644
--- a/usr.bin/vi/nvi/v_sentence.c
+++ b/usr.bin/vi/vi/v_sentence.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,17 +32,28 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_sentence.c 8.7 (Berkeley) 8/26/93";
+static char sccsid[] = "@(#)v_sentence.c 8.12 (Berkeley) 3/15/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
/*
+ * !!!
* In historic vi, a sentence was delimited by a '.', '?' or '!' character
* followed by TWO spaces or a newline. One or more empty lines was also
* treated as a separate sentence. The Berkeley documentation for historical
@@ -57,8 +68,8 @@ static char sccsid[] = "@(#)v_sentence.c 8.7 (Berkeley) 8/26/93";
*
* This implementation also permits a single tab to delimit sentences, and
* treats lines containing only white-space characters as empty lines.
- * And, tabs are eaten (along with spaces) when skipping to the start of the
- * text follow a "sentence".
+ * Finally, tabs are eaten (along with spaces) when skipping to the start
+ * of the text following a "sentence".
*/
/*
@@ -66,24 +77,25 @@ static char sccsid[] = "@(#)v_sentence.c 8.7 (Berkeley) 8/26/93";
* Move forward count sentences.
*/
int
-v_sentencef(sp, ep, vp, fm, tm, rp)
+v_sentencef(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
enum { BLANK, NONE, PERIOD } state;
VCS cs;
+ size_t len;
u_long cnt;
- cs.cs_lno = fm->lno;
- cs.cs_cno = fm->cno;
- if (cs_init(sp, ep, &cs))
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
return (1);
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
/*
+ * !!!
* If in white-space, the next start of sentence counts as one.
* This may not handle " . " correctly, but it's real unclear
* what correctly means in that case.
@@ -92,11 +104,13 @@ v_sentencef(sp, ep, vp, fm, tm, rp)
if (cs_fblank(sp, ep, &cs))
return (1);
if (--cnt == 0) {
- if (fm->lno != cs.cs_lno || fm->cno != cs.cs_cno)
+ if (vp->m_start.lno != cs.cs_lno ||
+ vp->m_start.cno != cs.cs_cno)
goto okret;
return (1);
}
}
+
for (state = NONE;;) {
if (cs_next(sp, ep, &cs))
return (1);
@@ -158,27 +172,42 @@ v_sentencef(sp, ep, vp, fm, tm, rp)
}
}
- /* EOF is a movement sink. */
- if (fm->lno != cs.cs_lno || fm->cno != cs.cs_cno)
- goto okret;
- v_eof(sp, ep, NULL);
- return (1);
+ /* EOF is a movement sink, but it's an error not to have moved. */
+ if (vp->m_start.lno == cs.cs_lno && vp->m_start.cno == cs.cs_cno) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
-okret: rp->lno = cs.cs_lno;
- rp->cno = cs.cs_cno;
+okret: vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
/*
+ * !!!
* Historic, uh, features, yeah, that's right, call 'em features.
- * If the sentence movement is cutting an entire line, the buffer
- * is in line mode. Reach up into the caller's VICMDARG structure,
- * and whack the flags.
+ * If the ending cursor position is at the first column in the
+ * line, i.e. the movement is cutting an entire line, the buffer
+ * is in line mode, and the ending position is the last character
+ * of the previous line.
+ *
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S. Adjust the
+ * end of the range for motion commands.
*/
- if (F_ISSET(vp, VC_C | VC_D | VC_Y) &&
- fm->cno == 0 && (rp->cno == 0 || cs.cs_flags != 0)) {
- if (rp->cno == 0)
- --rp->lno;
- F_SET(vp, VC_LMODE);
- }
+ if (ISMOTION(vp)) {
+ if (vp->m_start.cno == 0 &&
+ (cs.cs_flags != 0 || vp->m_stop.cno == 0)) {
+ if (file_gline(sp, ep,
+ --vp->m_stop.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_stop.lno);
+ return (1);
+ }
+ vp->m_stop.cno = len ? len - 1 : 0;
+ F_SET(vp, VM_LMODE);
+ } else
+ --vp->m_stop.cno;
+ vp->m_final = vp->m_start;
+ } else
+ vp->m_final = vp->m_stop;
return (0);
}
@@ -187,53 +216,66 @@ okret: rp->lno = cs.cs_lno;
* Move backward count sentences.
*/
int
-v_sentenceb(sp, ep, vp, fm, tm, rp)
+v_sentenceb(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
VCS cs;
recno_t slno;
size_t len, scno;
u_long cnt;
- int last1, last2;
+ int last;
- if (fm->lno == 1 && fm->cno == 0) {
- v_sof(sp, NULL);
- return (1);
- }
+ /*
+ * !!!
+ * Historic vi permitted the user to hit SOF repeatedly.
+ */
+ if (vp->m_start.lno == 1 && vp->m_start.cno == 0)
+ return (0);
- cs.cs_lno = fm->lno;
- cs.cs_cno = fm->cno;
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
if (cs_init(sp, ep, &cs))
return (1);
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
/*
- * If on an empty line, skip to the next previous
- * non-white-space character.
+ * !!!
+ * In empty lines, skip to the previous non-white-space character.
+ * If in text, skip to the prevous white-space character. Believe
+ * it or not, in the paragraph:
+ * ab cd.
+ * AB CD.
+ * if the cursor is on the 'A' or 'B', ( moves to the 'a'. If it
+ * is on the ' ', 'C' or 'D', it moves to the 'A'. Yes, Virginia,
+ * Berkeley was once a major center of drug activity.
*/
if (cs.cs_flags == CS_EMP) {
if (cs_bblank(sp, ep, &cs))
return (1);
for (;;) {
- if (cs_next(sp, ep, &cs))
+ if (cs_prev(sp, ep, &cs))
return (1);
if (cs.cs_flags != CS_EOL)
break;
}
- }
+ } else if (cs.cs_flags == 0 && !isblank(cs.cs_ch))
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ }
- for (last1 = last2 = 0;;) {
+ for (last = 0;;) {
if (cs_prev(sp, ep, &cs))
return (1);
if (cs.cs_flags == CS_SOF) /* SOF is a movement sink. */
break;
if (cs.cs_flags == CS_EOL) {
- last2 = last1;
- last1 = 1;
+ last = 1;
continue;
}
if (cs.cs_flags == CS_EMP) {
@@ -241,15 +283,15 @@ v_sentenceb(sp, ep, vp, fm, tm, rp)
goto ret;
if (cs_bblank(sp, ep, &cs))
return (1);
- last1 = last2 = 0;
+ last = 0;
continue;
}
switch (cs.cs_ch) {
case '.':
case '?':
case '!':
- if (!last1 || --cnt != 0) {
- last2 = last1 = 0;
+ if (!last || --cnt != 0) {
+ last = 0;
continue;
}
@@ -276,7 +318,8 @@ ret: slno = cs.cs_lno;
* beginning of a sentence preceded by an empty line,
* we can end up where we started. Fix it.
*/
- if (fm->lno != cs.cs_lno || fm->cno != cs.cs_cno)
+ if (vp->m_start.lno != cs.cs_lno ||
+ vp->m_start.cno != cs.cs_cno)
goto okret;
/*
@@ -299,30 +342,45 @@ ret: slno = cs.cs_lno;
++cnt;
cs.cs_lno = slno;
cs.cs_cno = scno;
- last2 = last1 = 0;
+ last = 0;
break;
case '\t':
- last1 = last2 = 1;
+ last = 1;
break;
default:
- last2 = last1;
- last1 =
+ last =
cs.cs_flags == CS_EOL || isblank(cs.cs_ch) ||
cs.cs_ch == ')' || cs.cs_ch == ']' ||
cs.cs_ch == '"' || cs.cs_ch == '\'' ? 1 : 0;
}
}
-okret: rp->lno = cs.cs_lno;
- rp->cno = cs.cs_cno;
+okret: vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
/*
- * See comment in v_sentencef(). Ignore errors, they should
- * never occur, and they'll get caught later.
+ * !!!
+ * If the starting and stopping cursor positions are at the first
+ * columns in the line, i.e. the movement is cutting an entire line,
+ * the buffer is in line mode, and the starting position is the last
+ * character of the previous line.
+ *
+ * VC_D and non-motion commands move to the end of the range.
+ * VC_Y stays at the start. Ignore VC_C and VC_S. Adjust the
+ * start of the range for motion commands.
*/
- if (F_ISSET(vp, VC_C | VC_D | VC_Y) && rp->cno == 0 &&
- file_gline(sp, ep, fm->lno, &len) != NULL && (len == 0 ||
- fm->cno == len - 1))
- F_SET(vp, VC_LMODE);
+ if (ISMOTION(vp))
+ if (vp->m_start.cno == 0 &&
+ (cs.cs_flags != 0 || vp->m_stop.cno == 0)) {
+ if (file_gline(sp, ep,
+ --vp->m_start.lno, &len) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ vp->m_start.cno = len ? len - 1 : 0;
+ F_SET(vp, VM_LMODE);
+ } else
+ --vp->m_start.cno;
+ vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop;
return (0);
}
diff --git a/usr.bin/vi/nvi/v_shift.c b/usr.bin/vi/vi/v_shift.c
index 2e984147a1c1..529e6d460e17 100644
--- a/usr.bin/vi/nvi/v_shift.c
+++ b/usr.bin/vi/vi/v_shift.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_shift.c 8.3 (Berkeley) 11/13/93";
+static char sccsid[] = "@(#)v_shift.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -48,16 +58,15 @@ static char sccsid[] = "@(#)v_shift.c 8.3 (Berkeley) 11/13/93";
* Shift lines left.
*/
int
-v_shiftl(sp, ep, vp, fm, tm, rp)
+v_shiftl(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
- SETCMDARG(cmd, C_SHIFTL, 2, fm->lno, tm->lno, 0, "<");
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ SETCMDARG(cmd, C_SHIFTL, 2, vp->m_start.lno, vp->m_stop.lno, 0, "<");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
/*
@@ -65,14 +74,13 @@ v_shiftl(sp, ep, vp, fm, tm, rp)
* Shift lines right.
*/
int
-v_shiftr(sp, ep, vp, fm, tm, rp)
+v_shiftr(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
- SETCMDARG(cmd, C_SHIFTR, 2, fm->lno, tm->lno, 0, ">");
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ SETCMDARG(cmd, C_SHIFTR, 2, vp->m_start.lno, vp->m_stop.lno, 0, ">");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
diff --git a/usr.bin/vi/nvi/v_status.c b/usr.bin/vi/vi/v_status.c
index 9109c0196a80..26cb191a06dc 100644
--- a/usr.bin/vi/nvi/v_status.c
+++ b/usr.bin/vi/vi/v_status.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_status.c 8.10 (Berkeley) 11/20/93";
+static char sccsid[] = "@(#)v_status.c 8.12 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/param.h>
+#include <queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "vcmd.h"
@@ -48,11 +58,10 @@ static char sccsid[] = "@(#)v_status.c 8.10 (Berkeley) 11/20/93";
* Show the file status.
*/
int
-v_status(sp, ep, vp, fm, tm, rp)
+v_status(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/*
@@ -60,7 +69,7 @@ v_status(sp, ep, vp, fm, tm, rp)
* non-blank character in the line. This doesn't seem of
* any usefulness whatsoever, so I don't bother.
*/
- return (status(sp, ep, fm->lno, 1));
+ return (status(sp, ep, vp->m_start.lno, 1));
}
int
diff --git a/usr.bin/vi/nvi/v_stop.c b/usr.bin/vi/vi/v_stop.c
index 2f64bfedf195..d6fee83cbb05 100644
--- a/usr.bin/vi/nvi/v_stop.c
+++ b/usr.bin/vi/vi/v_stop.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,23 +32,36 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_stop.c 8.5 (Berkeley) 10/28/93";
+static char sccsid[] = "@(#)v_stop.c 8.7 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
+/*
+ * v_stop -- ^Z
+ * Suspend vi.
+ */
int
-v_stop(sp, ep, vp, fm, tm, rp)
+v_stop(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/* If autowrite is set, write out the file. */
if (F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE)) {
diff --git a/usr.bin/vi/nvi/v_switch.c b/usr.bin/vi/vi/v_switch.c
index d0d000facb2b..abdd128f0936 100644
--- a/usr.bin/vi/nvi/v_switch.c
+++ b/usr.bin/vi/vi/v_switch.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_switch.c 8.5 (Berkeley) 11/23/93";
+static char sccsid[] = "@(#)v_switch.c 8.7 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -48,11 +58,10 @@ static char sccsid[] = "@(#)v_switch.c 8.5 (Berkeley) 11/23/93";
* Switch to the previous file.
*/
int
-v_switch(sp, ep, vp, fm, tm, rp)
+v_switch(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
char *name;
@@ -82,5 +91,5 @@ v_switch(sp, ep, vp, fm, tm, rp)
}
SETCMDARG(cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, name);
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
diff --git a/usr.bin/vi/nvi/v_tag.c b/usr.bin/vi/vi/v_tag.c
index 530e35279420..caa36f473bfc 100644
--- a/usr.bin/vi/nvi/v_tag.c
+++ b/usr.bin/vi/vi/v_tag.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,22 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_tag.c 8.2 (Berkeley) 12/3/93";
+static char sccsid[] = "@(#)v_tag.c 8.4 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
@@ -48,32 +58,29 @@ static char sccsid[] = "@(#)v_tag.c 8.2 (Berkeley) 12/3/93";
* Do a tag search on a the cursor keyword.
*/
int
-v_tagpush(sp, ep, vp, fm, tm, rp)
+v_tagpush(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
SETCMDARG(cmd, C_TAG, 0, OOBLNO, 0, 0, vp->keyword);
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
/*
* v_tagpop -- ^T
* Pop the tags stack.
*/
-/* ARGSUSED */
int
-v_tagpop(sp, ep, vp, fm, tm, rp)
+v_tagpop(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
EXCMDARG cmd;
SETCMDARG(cmd, C_TAGPOP, 0, OOBLNO, 0, 0, NULL);
- return (sp->s_ex_cmd(sp, ep, &cmd, rp));
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
}
diff --git a/usr.bin/vi/nvi/v_text.c b/usr.bin/vi/vi/v_text.c
index 083b5b248e22..01d17442fc00 100644
--- a/usr.bin/vi/nvi/v_text.c
+++ b/usr.bin/vi/vi/v_text.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_text.c 8.23 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)v_text.c 8.30 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -57,12 +67,14 @@ static char sccsid[] = "@(#)v_text.c 8.23 (Berkeley) 1/9/94";
*/
#define SET_TXT_STD(sp, f) { \
- LF_INIT((f) | TXT_BEAUTIFY | TXT_CNTRLT | TXT_ESCAPE | \
+ LF_INIT((f) | TXT_CNTRLT | TXT_ESCAPE | \
TXT_MAPINPUT | TXT_RECORD | TXT_RESOLVE); \
if (O_ISSET(sp, O_ALTWERASE)) \
LF_SET(TXT_ALTWERASE); \
if (O_ISSET(sp, O_AUTOINDENT)) \
LF_SET(TXT_AUTOINDENT); \
+ if (O_ISSET(sp, O_BEAUTIFY)) \
+ LF_SET(TXT_BEAUTIFY); \
if (O_ISSET(sp, O_SHOWMATCH)) \
LF_SET(TXT_SHOWMATCH); \
if (O_ISSET(sp, O_WRAPMARGIN)) \
@@ -73,7 +85,7 @@ static char sccsid[] = "@(#)v_text.c 8.23 (Berkeley) 1/9/94";
LF_SET(TXT_TTYWERASE); \
}
-/*
+/*
* !!!
* There's a problem with the way that we do logging for change commands with
* implied motions (e.g. A, I, O, cc, etc.). Since the main vi loop logs the
@@ -85,21 +97,31 @@ static char sccsid[] = "@(#)v_text.c 8.23 (Berkeley) 1/9/94";
* it fails is if the user entered 'o' from anywhere but the last character of
* the line, the undo returned the cursor to the start of the line. If the
* user was on the last character of the line, the cursor returned to that
- * position.)
+ * position.) We also check for mapped keys waiting, i.e. if we're in the
+ * middle of a map, don't bother logging the cursor.
*/
+#define LOG_CORRECT { \
+ if (!MAPPED_KEYS_WAITING(sp)) \
+ (void)log_cursor(sp, ep); \
+}
+#define LOG_CORRECT_FIRST { \
+ if (first == 1) { \
+ LOG_CORRECT; \
+ first = 0; \
+ } \
+}
-static int v_CS __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, MARK *, u_int));
+static int v_CS __P((SCR *, EXF *, VICMDARG *, u_int));
/*
* v_iA -- [count]A
* Append text to the end of the line.
*/
int
-v_iA(sp, ep, vp, fm, tm, rp)
+v_iA(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
u_long cnt;
@@ -111,7 +133,7 @@ v_iA(sp, ep, vp, fm, tm, rp)
SET_TXT_STD(sp, TXT_APPENDEOL);
if (F_ISSET(vp, VC_ISDOT))
LF_SET(TXT_REPLAY);
- for (first = 1, lno = fm->lno,
+ for (first = 1, lno = vp->m_start.lno,
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
/* Move the cursor to the end of the line + 1. */
if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
@@ -125,22 +147,23 @@ v_iA(sp, ep, vp, fm, tm, rp)
len = 0;
} else {
/* Correct logging for implied cursor motion. */
- sp->cno = len == 0 ? 0 : len - 1;
if (first == 1) {
- log_cursor(sp, ep);
+ sp->cno = len == 0 ? 0 : len - 1;
+ LOG_CORRECT;
first = 0;
}
+
/* Start the change after the line. */
sp->cno = len;
}
if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, OOBLNO, flags))
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
return (1);
SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
}
return (0);
}
@@ -150,11 +173,10 @@ v_iA(sp, ep, vp, fm, tm, rp)
* Append text to the cursor position.
*/
int
-v_ia(sp, ep, vp, fm, tm, rp)
+v_ia(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
u_long cnt;
@@ -165,7 +187,7 @@ v_ia(sp, ep, vp, fm, tm, rp)
SET_TXT_STD(sp, 0);
if (F_ISSET(vp, VC_ISDOT))
LF_SET(TXT_REPLAY);
- for (lno = fm->lno,
+ for (lno = vp->m_start.lno,
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
/*
* Move the cursor one column to the right and
@@ -191,12 +213,12 @@ v_ia(sp, ep, vp, fm, tm, rp)
LF_SET(TXT_APPENDEOL);
if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, OOBLNO, flags))
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
return (1);
SET_TXT_STD(sp, TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
}
return (0);
}
@@ -206,11 +228,10 @@ v_ia(sp, ep, vp, fm, tm, rp)
* Insert text at the first non-blank character in the line.
*/
int
-v_iI(sp, ep, vp, fm, tm, rp)
+v_iI(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
u_long cnt;
@@ -222,7 +243,7 @@ v_iI(sp, ep, vp, fm, tm, rp)
SET_TXT_STD(sp, 0);
if (F_ISSET(vp, VC_ISDOT))
LF_SET(TXT_REPLAY);
- for (first = 1, lno = fm->lno,
+ for (first = 1, lno = vp->m_start.lno,
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
/*
* Move the cursor to the start of the line and repaint
@@ -241,22 +262,20 @@ v_iI(sp, ep, vp, fm, tm, rp)
sp->cno = 0;
if (nonblank(sp, ep, lno, &sp->cno))
return (1);
+
/* Correct logging for implied cursor motion. */
- if (first == 1) {
- log_cursor(sp, ep);
- first = 0;
- }
+ LOG_CORRECT_FIRST;
}
if (len == 0)
LF_SET(TXT_APPENDEOL);
if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, OOBLNO, flags))
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
return (1);
SET_TXT_STD(sp, TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
}
return (0);
}
@@ -266,11 +285,10 @@ v_iI(sp, ep, vp, fm, tm, rp)
* Insert text at the cursor position.
*/
int
-v_ii(sp, ep, vp, fm, tm, rp)
+v_ii(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
u_long cnt;
@@ -281,13 +299,13 @@ v_ii(sp, ep, vp, fm, tm, rp)
SET_TXT_STD(sp, 0);
if (F_ISSET(vp, VC_ISDOT))
LF_SET(TXT_REPLAY);
- for (lno = fm->lno,
+ for (lno = vp->m_start.lno,
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
lno = 1;
@@ -298,7 +316,7 @@ v_ii(sp, ep, vp, fm, tm, rp)
LF_SET(TXT_APPENDEOL);
if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, OOBLNO, flags))
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
return (1);
/*
@@ -306,8 +324,8 @@ v_ii(sp, ep, vp, fm, tm, rp)
* by one (make it an append).
*/
SET_TXT_STD(sp, TXT_REPLAY);
- sp->lno = lno = rp->lno;
- if ((sp->cno = rp->cno) != 0)
+ sp->lno = lno = vp->m_final.lno;
+ if ((sp->cno = vp->m_final.cno) != 0)
++sp->cno;
}
return (0);
@@ -318,11 +336,10 @@ v_ii(sp, ep, vp, fm, tm, rp)
* Insert text above this line.
*/
int
-v_iO(sp, ep, vp, fm, tm, rp)
+v_iO(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t ai_line, lno;
size_t len;
@@ -346,11 +363,10 @@ v_iO(sp, ep, vp, fm, tm, rp)
} else {
insert: p = "";
sp->cno = 0;
+
/* Correct logging for implied cursor motion. */
- if (first == 1) {
- log_cursor(sp, ep);
- first = 0;
- }
+ LOG_CORRECT_FIRST;
+
if (file_iline(sp, ep, sp->lno, p, 0))
return (1);
if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) {
@@ -361,12 +377,12 @@ insert: p = "";
}
if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, ai_line, flags))
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, ai_line, flags))
return (1);
SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
}
return (0);
}
@@ -376,11 +392,10 @@ insert: p = "";
* Insert text after this line.
*/
int
-v_io(sp, ep, vp, fm, tm, rp)
+v_io(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t ai_line, lno;
size_t len;
@@ -405,11 +420,10 @@ v_io(sp, ep, vp, fm, tm, rp)
} else {
insert: p = "";
sp->cno = 0;
+
/* Correct logging for implied cursor motion. */
- if (first == 1) {
- log_cursor(sp, ep);
- first = 0;
- }
+ LOG_CORRECT_FIRST;
+
len = 0;
if (file_aline(sp, ep, 1, sp->lno, p, len))
return (1);
@@ -421,12 +435,12 @@ insert: p = "";
}
if (v_ntext(sp, ep,
- &sp->tiq, NULL, p, len, rp, 0, ai_line, flags))
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, ai_line, flags))
return (1);
SET_TXT_STD(sp, TXT_APPENDEOL | TXT_REPLAY);
- sp->lno = lno = rp->lno;
- sp->cno = rp->cno;
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
}
return (0);
}
@@ -436,13 +450,12 @@ insert: p = "";
* Change line command.
*/
int
-v_Change(sp, ep, vp, fm, tm, rp)
+v_Change(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- return (v_CS(sp, ep, vp, fm, tm, rp, 0));
+ return (v_CS(sp, ep, vp, 0));
}
/*
@@ -450,11 +463,10 @@ v_Change(sp, ep, vp, fm, tm, rp)
* Line substitute command.
*/
int
-v_Subst(sp, ep, vp, fm, tm, rp)
+v_Subst(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
u_int flags;
@@ -469,14 +481,14 @@ v_Subst(sp, ep, vp, fm, tm, rp)
*/
LF_INIT(0);
if (O_ISSET(sp, O_AUTOINDENT)) {
- fm->cno = 0;
- if (nonblank(sp, ep, fm->lno, &fm->cno))
+ vp->m_start.cno = 0;
+ if (nonblank(sp, ep, vp->m_start.lno, &vp->m_start.cno))
return (1);
LF_SET(TXT_AICHARS);
} else
- fm->cno = 0;
- sp->cno = fm->cno;
- return (v_CS(sp, ep, vp, fm, tm, rp, flags));
+ vp->m_start.cno = 0;
+ sp->cno = vp->m_start.cno;
+ return (v_CS(sp, ep, vp, flags));
}
/*
@@ -484,13 +496,13 @@ v_Subst(sp, ep, vp, fm, tm, rp)
* C and S commands.
*/
static int
-v_CS(sp, ep, vp, fm, tm, rp, iflags)
+v_CS(sp, ep, vp, iflags)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
u_int iflags;
{
+ MARK *tm;
recno_t lno;
size_t len;
char *p;
@@ -505,65 +517,74 @@ v_CS(sp, ep, vp, fm, tm, rp, iflags)
* mode change where we delete the lines and then insert text
* into a new line. Otherwise, we replace the current line.
*/
- tm->lno = fm->lno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0);
- if (fm->lno != tm->lno) {
+ vp->m_stop.lno =
+ vp->m_start.lno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0);
+ if (vp->m_start.lno != vp->m_stop.lno) {
/* Make sure that the to line is real. */
- if (file_gline(sp, ep, tm->lno, NULL) == NULL) {
- v_eof(sp, ep, fm);
+ if (file_gline(sp, ep,
+ vp->m_stop.lno, &vp->m_stop.cno) == NULL) {
+ v_eof(sp, ep, &vp->m_start);
return (1);
}
+ if (vp->m_stop.cno != 0)
+ --vp->m_stop.cno;
/* Cut the lines. */
if (cut(sp, ep,
NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, CUT_LINEMODE))
+ &vp->m_start, &vp->m_stop, CUT_LINEMODE))
return (1);
/* Insert a line while we still can... */
- if (file_iline(sp, ep, fm->lno, "", 0))
+ if (file_iline(sp, ep, vp->m_start.lno, "", 0))
return (1);
- ++fm->lno;
- ++tm->lno;
+ ++vp->m_start.lno;
+ ++vp->m_stop.lno;
/* Delete the lines. */
- if (delete(sp, ep, fm, tm, 1))
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, 1))
return (1);
/* Get the inserted line. */
- if ((p = file_gline(sp, ep, --fm->lno, &len)) == NULL) {
- GETLINE_ERR(sp, fm->lno);
+ if ((p = file_gline(sp, ep, --vp->m_start.lno, &len)) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
tm = NULL;
- sp->lno = fm->lno;
+ sp->lno = vp->m_start.lno;
sp->cno = 0;
LF_SET(TXT_APPENDEOL);
- } else {
+ } else {
/* The line may be empty, but that's okay. */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno != 0) {
- GETLINE_ERR(sp, tm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
- len = 0;
+ vp->m_stop.cno = len = 0;
LF_SET(TXT_APPENDEOL);
} else {
+ if (len == 0) {
+ vp->m_stop.cno = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else
+ vp->m_stop.cno = len - 1;
if (cut(sp, ep,
NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, CUT_LINEMODE))
+ &vp->m_start, &vp->m_stop, CUT_LINEMODE))
return (1);
- tm->cno = len;
- if (len == 0)
- LF_SET(TXT_APPENDEOL);
LF_SET(TXT_EMARK | TXT_OVERWRITE);
}
+ tm = &vp->m_stop;
}
+
/* Correct logging for implied cursor motion. */
- log_cursor(sp, ep);
+ LOG_CORRECT;
+
return (v_ntext(sp, ep,
- &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags));
+ &sp->tiq, tm, p, len, &vp->m_final, 0, OOBLNO, flags));
}
/*
@@ -571,11 +592,10 @@ v_CS(sp, ep, vp, fm, tm, rp, iflags)
* Change command.
*/
int
-v_change(sp, ep, vp, fm, tm, rp)
+v_change(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
size_t blen, len;
@@ -594,49 +614,49 @@ v_change(sp, ep, vp, fm, tm, rp)
* to make it just a bit more exciting, the initial space is handled
* as auto-indent characters.
*/
- lmode = F_ISSET(vp, VC_LMODE) ? CUT_LINEMODE : 0;
+ lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0;
if (lmode) {
- fm->cno = 0;
+ vp->m_start.cno = 0;
if (O_ISSET(sp, O_AUTOINDENT)) {
- if (nonblank(sp, ep, fm->lno, &fm->cno))
+ if (nonblank(sp, ep, vp->m_start.lno, &vp->m_start.cno))
return (1);
LF_SET(TXT_AICHARS);
}
}
- sp->lno = fm->lno;
- sp->cno = fm->cno;
+ sp->lno = vp->m_start.lno;
+ sp->cno = vp->m_start.cno;
/* Correct logging for implied cursor motion. */
- log_cursor(sp, ep);
+ LOG_CORRECT;
/*
* If changing within a single line, the line either currently has
* text or it doesn't. If it doesn't, just insert text. Otherwise,
* copy it and overwrite it.
*/
- if (fm->lno == tm->lno) {
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ if (vp->m_start.lno == vp->m_stop.lno) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (p == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
}
- len = 0;
+ vp->m_stop.cno = len = 0;
LF_SET(TXT_APPENDEOL);
} else {
if (cut(sp, ep,
NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- fm, tm, lmode))
+ &vp->m_start, &vp->m_stop, lmode))
return (1);
if (len == 0)
LF_SET(TXT_APPENDEOL);
LF_SET(TXT_EMARK | TXT_OVERWRITE);
}
- return (v_ntext(sp, ep,
- &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags));
+ return (v_ntext(sp, ep, &sp->tiq,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags));
}
/*
@@ -649,54 +669,52 @@ v_change(sp, ep, vp, fm, tm, rp)
*
* Copy the text.
*/
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, lmode))
+ if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode))
return (1);
/* If replacing entire lines and there's leading text. */
- if (lmode && fm->cno) {
+ if (lmode && vp->m_start.cno) {
/* Get a copy of the first line changed. */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- GETLINE_ERR(sp, fm->lno);
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
/* Copy the leading text elsewhere. */
- GET_SPACE_RET(sp, bp, blen, fm->cno);
- memmove(bp, p, fm->cno);
+ GET_SPACE_RET(sp, bp, blen, vp->m_start.cno);
+ memmove(bp, p, vp->m_start.cno);
} else
bp = NULL;
/* Delete the text. */
- if (delete(sp, ep, fm, tm, lmode))
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, lmode))
return (1);
/* If replacing entire lines, insert a replacement line. */
if (lmode) {
- if (file_iline(sp, ep, fm->lno, bp, fm->cno))
+ if (file_iline(sp, ep, vp->m_start.lno, bp, vp->m_start.cno))
return (1);
- sp->lno = fm->lno;
- len = sp->cno = fm->cno;
+ sp->lno = vp->m_start.lno;
+ len = sp->cno = vp->m_start.cno;
}
/* Get the line we're editing. */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
len = 0;
}
/* Check to see if we're appending to the line. */
- if (fm->cno >= len)
+ if (vp->m_start.cno >= len)
LF_SET(TXT_APPENDEOL);
- /* No to mark. */
- tm = NULL;
-
- rval = v_ntext(sp, ep, &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags);
+ rval = v_ntext(sp, ep,
+ &sp->tiq, NULL, p, len, &vp->m_final, 0, OOBLNO, flags);
if (bp != NULL)
FREE_SPACE(sp, bp, blen);
@@ -708,11 +726,10 @@ v_change(sp, ep, vp, fm, tm, rp)
* Overwrite multiple characters.
*/
int
-v_Replace(sp, ep, vp, fm, tm, rp)
+v_Replace(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
u_long cnt;
@@ -725,11 +742,11 @@ v_Replace(sp, ep, vp, fm, tm, rp)
LF_SET(TXT_REPLAY);
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- if ((p = file_gline(sp, ep, rp->lno, &len)) == NULL) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno != 0) {
- GETLINE_ERR(sp, rp->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
len = 0;
@@ -739,9 +756,10 @@ v_Replace(sp, ep, vp, fm, tm, rp)
LF_SET(TXT_APPENDEOL);
LF_SET(TXT_OVERWRITE | TXT_REPLACE);
}
- tm->lno = rp->lno;
- tm->cno = len ? len : 0;
- if (v_ntext(sp, ep, &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags))
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ if (v_ntext(sp, ep, &sp->tiq,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags))
return (1);
/*
@@ -751,29 +769,31 @@ v_Replace(sp, ep, vp, fm, tm, rp)
* This seems wrong, so this version counts R commands. There is some
* trickiness in moving back to where the user stopped replacing after
* each R command. Basically, if the user ended with a newline, we
- * want to use rp->cno (which will be 0). Otherwise, use the column
- * after the returned cursor, unless it would be past the end of the
- * line, in which case we append to the line.
+ * want to use vp->m_final.cno (which will be 0). Otherwise, use the
+ * column after the returned cursor, unless it would be past the end of
+ * the line, in which case we append to the line.
*/
while (--cnt) {
- if ((p = file_gline(sp, ep, rp->lno, &len)) == NULL)
- GETLINE_ERR(sp, rp->lno);
+ if ((p = file_gline(sp, ep, vp->m_final.lno, &len)) == NULL)
+ GETLINE_ERR(sp, vp->m_final.lno);
SET_TXT_STD(sp, TXT_REPLAY);
- sp->lno = rp->lno;
+ sp->lno = vp->m_final.lno;
- if (len == 0 || rp->cno == len - 1) {
+ if (len == 0 || vp->m_final.cno == len - 1) {
sp->cno = len;
LF_SET(TXT_APPENDEOL);
} else {
- sp->cno = rp->cno;
- if (rp->cno != 0)
+ sp->cno = vp->m_final.cno;
+ if (vp->m_final.cno != 0)
++sp->cno;
LF_SET(TXT_OVERWRITE | TXT_REPLACE);
}
- if (v_ntext(sp, ep,
- &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags))
+ vp->m_stop.lno = sp->lno;
+ vp->m_stop.cno = sp->cno;
+ if (v_ntext(sp, ep, &sp->tiq,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags))
return (1);
}
return (0);
@@ -784,11 +804,10 @@ v_Replace(sp, ep, vp, fm, tm, rp)
* Substitute characters.
*/
int
-v_subst(sp, ep, vp, fm, tm, rp)
+v_subst(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
size_t len;
@@ -798,11 +817,11 @@ v_subst(sp, ep, vp, fm, tm, rp)
SET_TXT_STD(sp, 0);
if (F_ISSET(vp, VC_ISDOT))
LF_SET(TXT_REPLAY);
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno != 0) {
- GETLINE_ERR(sp, fm->lno);
+ GETLINE_ERR(sp, vp->m_start.lno);
return (1);
}
len = 0;
@@ -813,15 +832,17 @@ v_subst(sp, ep, vp, fm, tm, rp)
LF_SET(TXT_EMARK | TXT_OVERWRITE);
}
- tm->lno = fm->lno;
- tm->cno = fm->cno + (F_ISSET(vp, VC_C1SET) ? vp->count : 1);
- if (tm->cno > len)
- tm->cno = len;
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno =
+ vp->m_start.cno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0);
+ if (vp->m_stop.cno > len - 1)
+ vp->m_stop.cno = len - 1;
- if (p != NULL && cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, 0))
+ if (p != NULL &&
+ cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
return (1);
- return (v_ntext(sp, ep,
- &sp->tiq, tm, p, len, rp, 0, OOBLNO, flags));
+ return (v_ntext(sp, ep, &sp->tiq,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags));
}
diff --git a/usr.bin/vi/nvi/v_ulcase.c b/usr.bin/vi/vi/v_ulcase.c
index 12fd1c6626b9..ab2ef1af4b19 100644
--- a/usr.bin/vi/nvi/v_ulcase.c
+++ b/usr.bin/vi/vi/v_ulcase.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_ulcase.c 8.3 (Berkeley) 12/9/93";
+static char sccsid[] = "@(#)v_ulcase.c 8.6 (Berkeley) 3/18/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -55,11 +65,10 @@ static char sccsid[] = "@(#)v_ulcase.c 8.3 (Berkeley) 12/9/93";
* it now.
*/
int
-v_ulcase(sp, ep, vp, fm, tm, rp)
+v_ulcase(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t lno;
size_t blen, lcnt, len;
@@ -67,41 +76,44 @@ v_ulcase(sp, ep, vp, fm, tm, rp)
int ch, change, rval;
char *bp, *p;
- /* Figure out what memory to use. */
+ /* Get some memory. */
GET_SPACE_RET(sp, bp, blen, 256);
/*
* !!!
- * Historic vi didn't permit ~ to cross newline boundaries.
- * I can think of no reason why it shouldn't, which at least
- * lets you auto-repeat through a paragraph.
+ * Historic vi didn't permit ~ to cross newline boundaries. I can
+ * think of no reason why it shouldn't, which at least lets the user
+ * auto-repeat through a paragraph.
*/
rval = 0;
for (change = -1, cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt;) {
/* Get the line; EOF is an infinite sink. */
- if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
- if (file_lline(sp, ep, &lno))
- return (1);
- if (lno >= fm->lno) {
- GETLINE_ERR(sp, fm->lno);
+ if ((p = file_gline(sp, ep, vp->m_stop.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno)) {
+ rval = 1;
+ goto ret;
+ }
+ if (lno >= vp->m_stop.lno) {
+ GETLINE_ERR(sp, vp->m_stop.lno);
rval = 1;
- break;
+ goto ret;
}
if (change == -1) {
v_eof(sp, ep, NULL);
- return (1);
+ rval = 1;
+ goto ret;
}
break;
}
/* Set current line number. */
- lno = fm->lno;
+ lno = vp->m_stop.lno;
/* Empty lines just decrement the count. */
if (len == 0) {
--cnt;
- ++fm->lno;
- fm->cno = 0;
+ ++vp->m_stop.lno;
+ vp->m_stop.cno = 0;
change = 0;
continue;
}
@@ -112,7 +124,7 @@ v_ulcase(sp, ep, vp, fm, tm, rp)
/* Set starting pointer. */
if (change == -1)
- p = bp + fm->cno;
+ p = bp + vp->m_stop.cno;
else
p = bp;
@@ -120,12 +132,12 @@ v_ulcase(sp, ep, vp, fm, tm, rp)
* Figure out how many characters get changed in this
* line. Set the final cursor column.
*/
- if (fm->cno + cnt >= len) {
- lcnt = len - fm->cno;
- ++fm->lno;
- fm->cno = 0;
+ if (vp->m_stop.cno + cnt >= len) {
+ lcnt = len - vp->m_stop.cno;
+ ++vp->m_stop.lno;
+ vp->m_stop.cno = 0;
} else
- fm->cno += lcnt = cnt;
+ vp->m_stop.cno += lcnt = cnt;
cnt -= lcnt;
/* Change the line. */
@@ -148,12 +160,13 @@ v_ulcase(sp, ep, vp, fm, tm, rp)
}
/* If changed lines, could be on an illegal line. */
- if (fm->lno != lno && file_gline(sp, ep, fm->lno, &len) == NULL) {
- --fm->lno;
- fm->cno = len ? len - 1 : 0;
+ if (vp->m_stop.lno != lno &&
+ file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) {
+ --vp->m_stop.lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
}
- *rp = *fm;
+ vp->m_final = vp->m_stop;
- FREE_SPACE(sp, bp, blen);
+ret: FREE_SPACE(sp, bp, blen);
return (rval);
}
diff --git a/usr.bin/vi/nvi/v_undo.c b/usr.bin/vi/vi/v_undo.c
index 87c749b38179..767be7fda304 100644
--- a/usr.bin/vi/nvi/v_undo.c
+++ b/usr.bin/vi/vi/v_undo.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,24 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_undo.c 8.6 (Berkeley) 1/8/94";
+static char sccsid[] = "@(#)v_undo.c 8.9 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -49,11 +59,10 @@ static char sccsid[] = "@(#)v_undo.c 8.6 (Berkeley) 1/8/94";
* Undo changes to this line.
*/
int
-v_Undo(sp, ep, vp, fm, tm, rp)
+v_Undo(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/*
* Historically, U reset the cursor to the first column in the line
@@ -62,8 +71,7 @@ v_Undo(sp, ep, vp, fm, tm, rp)
* else (including the cursor position stored in the logging records)
* is going to appear random.
*/
- rp->lno = fm->lno;
- rp->cno = 0;
+ vp->m_final.cno = 0;
/*
* !!!
@@ -80,17 +88,16 @@ v_Undo(sp, ep, vp, fm, tm, rp)
return (log_setline(sp, ep));
}
-
+
/*
* v_undo -- u
* Undo the last change.
*/
int
-v_undo(sp, ep, vp, fm, tm, rp)
+v_undo(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
/* Set the command count. */
VIP(sp)->u_ccnt = sp->ccnt;
@@ -126,9 +133,9 @@ v_undo(sp, ep, vp, fm, tm, rp)
switch (ep->lundo) {
case BACKWARD:
- return (log_backward(sp, ep, rp));
+ return (log_backward(sp, ep, &vp->m_final));
case FORWARD:
- return (log_forward(sp, ep, rp));
+ return (log_forward(sp, ep, &vp->m_final));
default:
abort();
}
diff --git a/usr.bin/vi/nvi/v_util.c b/usr.bin/vi/vi/v_util.c
index 83c4fb4ebbf6..8959b5618af6 100644
--- a/usr.bin/vi/nvi/v_util.c
+++ b/usr.bin/vi/vi/v_util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,26 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_util.c 8.5 (Berkeley) 11/15/93";
+static char sccsid[] = "@(#)v_util.c 8.8 (Berkeley) 3/14/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
#include "vcmd.h"
@@ -78,7 +88,7 @@ void
v_eol(sp, ep, mp)
SCR *sp;
EXF *ep;
- MARK *mp;
+ MARK *mp;
{
size_t len;
@@ -97,6 +107,17 @@ v_eol(sp, ep, mp)
}
/*
+ * v_nomove --
+ * Vi no cursor movement error.
+ */
+void
+v_nomove(sp)
+ SCR *sp;
+{
+ msgq(sp, M_BERR, "No cursor movement made.");
+}
+
+/*
* v_sof --
* Vi start-of-file error.
*/
@@ -112,10 +133,21 @@ v_sof(sp, mp)
}
/*
+ * v_sol --
+ * Vi start-of-line error.
+ */
+void
+v_sol(sp)
+ SCR *sp;
+{
+ msgq(sp, M_BERR, "Already in the first column.");
+}
+
+/*
* v_isempty --
* Return if the line contains nothing but white-space characters.
*/
-int
+int
v_isempty(p, len)
char *p;
size_t len;
diff --git a/usr.bin/vi/vi/v_word.c b/usr.bin/vi/vi/v_word.c
new file mode 100644
index 000000000000..63f0539618b0
--- /dev/null
+++ b/usr.bin/vi/vi/v_word.c
@@ -0,0 +1,569 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v_word.c 8.18 (Berkeley) 3/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * There are two types of "words". Bigwords are easy -- groups of anything
+ * delimited by whitespace. Normal words are trickier. They are either a
+ * group of characters, numbers and underscores, or a group of anything but,
+ * delimited by whitespace. When for a word, if you're in whitespace, it's
+ * easy, just remove the whitespace and go to the beginning or end of the
+ * word. Otherwise, figure out if the next character is in a different group.
+ * If it is, go to the beginning or end of that group, otherwise, go to the
+ * beginning or end of the current group. The historic version of vi didn't
+ * get this right, so, for example, there were cases where "4e" was not the
+ * same as "eeee" -- in particular, single character words, and commands that
+ * began in whitespace were almost always handled incorrectly. To get it right
+ * you have to resolve the cursor after each search so that the look-ahead to
+ * figure out what type of "word" the cursor is in will be correct.
+ *
+ * Empty lines, and lines that consist of only white-space characters count
+ * as a single word, and the beginning and end of the file counts as an
+ * infinite number of words.
+ *
+ * Movements associated with commands are different than movement commands.
+ * For example, in "abc def", with the cursor on the 'a', "cw" is from
+ * 'a' to 'c', while "w" is from 'a' to 'd'. In general, trailing white
+ * space is discarded from the change movement. Another example is that,
+ * in the same string, a "cw" on any white space character replaces that
+ * single character, and nothing else. Ain't nothin' in here that's easy.
+ *
+ * One historic note -- in the original vi, the 'w', 'W' and 'B' commands
+ * would treat groups of empty lines as individual words, i.e. the command
+ * would move the cursor to each new empty line. The 'e' and 'E' commands
+ * would treat groups of empty lines as a single word, i.e. the first use
+ * would move past the group of lines. The 'b' command would just beep at
+ * you, or, if you did it from the start of the line as part of a motion
+ * command, go absolutely nuts. If the lines contained only white-space
+ * characters, the 'w' and 'W' commands would just beep at you, and the 'B',
+ * 'b', 'E' and 'e' commands would treat the group as a single word, and
+ * the 'B' and 'b' commands will treat the lines as individual words. This
+ * implementation treats all of these cases as a single white-space word.
+ */
+
+enum which {BIGWORD, LITTLEWORD};
+
+static int bword __P((SCR *, EXF *, VICMDARG *, enum which));
+static int eword __P((SCR *, EXF *, VICMDARG *, enum which));
+static int fword __P((SCR *, EXF *, VICMDARG *, enum which));
+
+/*
+ * v_wordW -- [count]W
+ * Move forward a bigword at a time.
+ */
+int
+v_wordW(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (fword(sp, ep, vp, BIGWORD));
+}
+
+/*
+ * v_wordw -- [count]w
+ * Move forward a word at a time.
+ */
+int
+v_wordw(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (fword(sp, ep, vp, LITTLEWORD));
+}
+
+/*
+ * fword --
+ * Move forward by words.
+ */
+static int
+fword(sp, ep, vp, type)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ enum which type;
+{
+ enum { INWORD, NOTWORD } state;
+ VCS cs;
+ u_long cnt;
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+
+ /*
+ * If in white-space:
+ * If the count is 1, and it's a change command, we're done.
+ * Else, move to the first non-white-space character, which
+ * counts as a single word move. If it's a motion command,
+ * don't move off the end of the line.
+ */
+ if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
+ if (cs.cs_flags != CS_EMP && cnt == 1) {
+ if (F_ISSET(vp, VC_C))
+ return (0);
+ if (F_ISSET(vp, VC_D | VC_Y)) {
+ if (cs_fspace(sp, ep, &cs))
+ return (1);
+ goto ret;
+ }
+ }
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ --cnt;
+ }
+
+ /*
+ * Cyclically move to the next word -- this involves skipping
+ * over word characters and then any trailing non-word characters.
+ * Note, for the 'w' command, the definition of a word keeps
+ * switching.
+ */
+ if (type == BIGWORD)
+ while (cnt--) {
+ for (;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ }
+ /*
+ * If a motion command and we're at the end of the
+ * last word, we're done. Delete and yank eat any
+ * trailing blanks, but we don't move off the end
+ * of the line regardless.
+ */
+ if (cnt == 0 && ISMOTION(vp)) {
+ if (F_ISSET(vp, VC_D | VC_Y) &&
+ cs_fspace(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ }
+ else
+ while (cnt--) {
+ state = cs.cs_flags == 0 &&
+ inword(cs.cs_ch) ? INWORD : NOTWORD;
+ for (;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ if (state == INWORD) {
+ if (!inword(cs.cs_ch))
+ break;
+ } else
+ if (inword(cs.cs_ch))
+ break;
+ }
+ /* See comment above. */
+ if (cnt == 0 && ISMOTION(vp)) {
+ if (F_ISSET(vp, VC_D | VC_Y) &&
+ cs_fspace(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ }
+
+ /*
+ * If we didn't move, we must be at EOF.
+ *
+ * !!!
+ * That's okay for motion commands, however.
+ */
+ret: if (!ISMOTION(vp) &&
+ cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+
+ /* Adjust the end of the range for motion commands. */
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+ if (ISMOTION(vp) && cs.cs_flags == 0)
+ --vp->m_stop.cno;
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_wordE -- [count]E
+ * Move forward to the end of the bigword.
+ */
+int
+v_wordE(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (eword(sp, ep, vp, BIGWORD));
+}
+
+/*
+ * v_worde -- [count]e
+ * Move forward to the end of the word.
+ */
+int
+v_worde(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (eword(sp, ep, vp, LITTLEWORD));
+}
+
+/*
+ * eword --
+ * Move forward to the end of the word.
+ */
+static int
+eword(sp, ep, vp, type)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ enum which type;
+{
+ enum { INWORD, NOTWORD } state;
+ VCS cs;
+ u_long cnt;
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+
+ /*
+ * !!!
+ * If in whitespace, or the next character is whitespace, move past
+ * it. (This doesn't count as a word move.) Stay at the character
+ * past the current one, it sets word "state" for the 'e' command.
+ */
+ if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == 0 && !isblank(cs.cs_ch))
+ goto start;
+ }
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+
+ /*
+ * Cyclically move to the next word -- this involves skipping
+ * over word characters and then any trailing non-word characters.
+ * Note, for the 'e' command, the definition of a word keeps
+ * switching.
+ */
+start: if (type == BIGWORD)
+ while (cnt--) {
+ for (;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ }
+ /*
+ * When we reach the start of the word after the last
+ * word, we're done. If we changed state, back up one
+ * to the end of the previous word.
+ */
+ if (cnt == 0) {
+ if (cs.cs_flags == 0 && cs_prev(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ }
+ else
+ while (cnt--) {
+ state = cs.cs_flags == 0 &&
+ inword(cs.cs_ch) ? INWORD : NOTWORD;
+ for (;;) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ if (state == INWORD) {
+ if (!inword(cs.cs_ch))
+ break;
+ } else
+ if (inword(cs.cs_ch))
+ break;
+ }
+ /* See comment above. */
+ if (cnt == 0) {
+ if (cs.cs_flags == 0 && cs_prev(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOF)
+ goto ret;
+ }
+
+ /*
+ * If we didn't move, we must be at EOF.
+ *
+ * !!!
+ * That's okay for motion commands, however.
+ */
+ret: if (!ISMOTION(vp) &&
+ cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+
+ /* Set the end of the range for motion commands. */
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D and
+ * VC_Y stay at the start. Ignore VC_C and VC_S.
+ */
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_WordB -- [count]B
+ * Move backward a bigword at a time.
+ */
+int
+v_wordB(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (bword(sp, ep, vp, BIGWORD));
+}
+
+/*
+ * v_wordb -- [count]b
+ * Move backward a word at a time.
+ */
+int
+v_wordb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (bword(sp, ep, vp, LITTLEWORD));
+}
+
+/*
+ * bword --
+ * Move backward by words.
+ */
+static int
+bword(sp, ep, vp, type)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ enum which type;
+{
+ enum { INWORD, NOTWORD } state;
+ VCS cs;
+ u_long cnt;
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = vp->m_start.cno;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+
+ /*
+ * !!!
+ * If in whitespace, or the previous character is whitespace, move
+ * past it. (This doesn't count as a word move.) Stay at the
+ * character before the current one, it sets word "state" for the
+ * 'b' command.
+ */
+ if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == 0 && !isblank(cs.cs_ch))
+ goto start;
+ }
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+
+ /*
+ * Cyclically move to the beginning of the previous word -- this
+ * involves skipping over word characters and then any trailing
+ * non-word characters. Note, for the 'b' command, the definition
+ * of a word keeps switching.
+ */
+start: if (type == BIGWORD)
+ while (cnt--) {
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ }
+ /*
+ * When we reach the end of the word before the last
+ * word, we're done. If we changed state, move forward
+ * one to the end of the next word.
+ */
+ if (cnt == 0) {
+ if (cs.cs_flags == 0 && cs_next(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF)
+ goto ret;
+ }
+ else
+ while (cnt--) {
+ state = cs.cs_flags == 0 &&
+ inword(cs.cs_ch) ? INWORD : NOTWORD;
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF)
+ goto ret;
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ break;
+ if (state == INWORD) {
+ if (!inword(cs.cs_ch))
+ break;
+ } else
+ if (inword(cs.cs_ch))
+ break;
+ }
+ /* See comment above. */
+ if (cnt == 0) {
+ if (cs.cs_flags == 0 && cs_next(sp, ep, &cs))
+ return (1);
+ break;
+ }
+
+ /* Eat whitespace characters. */
+ if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_SOF)
+ goto ret;
+ }
+
+ /* If we didn't move, we must be at SOF. */
+ret: if (cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) {
+ v_sof(sp, &vp->m_start);
+ return (1);
+ }
+
+ /* Set the end of the range for motion commands. */
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * Non-motion commands move to the end of the range. VC_D commands
+ * move to the end of the range. VC_Y stays at the start unless the
+ * end of the range is on a different line, when it moves to the end
+ * of the range. Ignore VC_C and VC_S. Motion commands adjust the
+ * starting point to the character before the current one.
+ */
+ vp->m_final = vp->m_stop;
+ if (ISMOTION(vp)) {
+ --vp->m_start.cno;
+ if (F_ISSET(vp, VC_Y) && vp->m_start.lno == vp->m_stop.lno)
+ vp->m_final = vp->m_start;
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/nvi/v_xchar.c b/usr.bin/vi/vi/v_xchar.c
index 019862240f26..c788db4852b2 100644
--- a/usr.bin/vi/nvi/v_xchar.c
+++ b/usr.bin/vi/vi/v_xchar.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,104 +32,104 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_xchar.c 8.4 (Berkeley) 1/9/94";
+static char sccsid[] = "@(#)v_xchar.c 8.6 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
-#define NODEL(sp) { \
- msgq(sp, M_BERR, "No characters to delete."); \
- return (1); \
-}
-
/*
- * v_xchar --
+ * v_xchar -- [count]x
* Deletes the character(s) on which the cursor sits.
*/
int
-v_xchar(sp, ep, vp, fm, tm, rp)
+v_xchar(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- MARK m;
recno_t lno;
- u_long cnt;
size_t len;
- if (file_gline(sp, ep, fm->lno, &len) == NULL) {
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
if (file_lline(sp, ep, &lno))
return (1);
if (lno == 0)
- NODEL(sp);
- GETLINE_ERR(sp, fm->lno);
+ goto nodel;
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ if (len == 0) {
+nodel: msgq(sp, M_BERR, "No characters to delete.");
return (1);
}
-
- if (len == 0)
- NODEL(sp);
-
- cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
/*
- * Deleting from the cursor toward the end of line, w/o moving the
- * cursor. Note, "2x" at EOL isn't the same as "xx" because the
- * left movement of the cursor as part of the 'x' command isn't
- * taken into account. Historically correct.
+ * Delete from the cursor toward the end of line, w/o moving the
+ * cursor.
+ *
+ * !!!
+ * Note, "2x" at EOL isn't the same as "xx" because the left movement
+ * of the cursor as part of the 'x' command isn't taken into account.
+ * Historically correct.
*/
- tm->lno = fm->lno;
- if (cnt < len - fm->cno) {
- tm->cno = fm->cno + cnt;
- m = *fm;
- } else {
- tm->cno = len;
- m.lno = fm->lno;
- m.cno = fm->cno ? fm->cno - 1 : 0;
- }
-
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, 0))
- return (1);
- if (delete(sp, ep, fm, tm, 0))
+ if (F_ISSET(vp, VC_C1SET))
+ vp->m_stop.cno += vp->count - 1;
+ if (vp->m_stop.cno >= len - 1) {
+ vp->m_stop.cno = len - 1;
+ vp->m_final.cno = vp->m_start.cno ? vp->m_start.cno - 1 : 0;
+ } else
+ vp->m_final.cno = vp->m_start.cno;
+
+ if (cut(sp, ep, NULL,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
return (1);
-
- *rp = m;
- return (0);
+ return (delete(sp, ep, &vp->m_start, &vp->m_stop, 0));
}
/*
- * v_Xchar --
+ * v_Xchar -- [count]X
* Deletes the character(s) immediately before the current cursor
* position.
*/
int
-v_Xchar(sp, ep, vp, fm, tm, rp)
+v_Xchar(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
u_long cnt;
- if (fm->cno == 0) {
- msgq(sp, M_BERR, "Already at the left-hand margin.");
+ if (vp->m_start.cno == 0) {
+ v_sol(sp);
return (1);
}
- *tm = *fm;
cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
- fm->cno = cnt >= tm->cno ? 0 : tm->cno - cnt;
-
- if (cut(sp, ep,
- NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, fm, tm, 0))
+ if (cnt >= vp->m_start.cno)
+ vp->m_start.cno = 0;
+ else
+ vp->m_start.cno -= cnt;
+ --vp->m_stop.cno;
+ vp->m_final.cno = vp->m_start.cno;
+
+ if (cut(sp, ep, NULL,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
return (1);
- if (delete(sp, ep, fm, tm, 0))
- return (1);
-
- *rp = *fm;
- return (0);
+ return (delete(sp, ep, &vp->m_start, &vp->m_stop, 0));
}
diff --git a/usr.bin/vi/nvi/v_mark.c b/usr.bin/vi/vi/v_yank.c
index 714242d9331e..c5bce64dfbd8 100644
--- a/usr.bin/vi/nvi/v_mark.c
+++ b/usr.bin/vi/vi/v_yank.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,56 +32,61 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_mark.c 8.3 (Berkeley) 10/31/93";
+static char sccsid[] = "@(#)v_yank.c 8.13 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
/*
- * v_mark -- m[a-z]
- * Set a mark.
- */
-int
-v_mark(sp, ep, vp, fm, tm, rp)
- SCR *sp;
- EXF *ep;
- VICMDARG *vp;
- MARK *fm, *tm, *rp;
-{
- rp->lno = fm->lno;
- rp->cno = fm->cno;
- return (mark_set(sp, ep, vp->character, fm, 1));
-}
-
-/*
- * v_gomark -- '['`a-z], or `['`a-z]
- * Move to a mark.
- *
- * The single quote form moves to the first nonblank character of a line
- * containing a mark. The back quote form moves to a mark, setting both
- * row and column. We use a single routine for both forms, taking care
- * of the nonblank behavior using a flag for the command.
+ * v_yank -- [buffer][count]Y
+ * [buffer][count]y[count][motion]
+ * Yank text (or lines of text) into a cut buffer.
*
- * Although not commonly known, the "'`" and "'`" forms are historically
- * valid. The behavior is determined by the first character, so "`'" is
- * the same as "``". Remember this fact -- you'll be amazed at how many
- * people don't know it and will be delighted that you are able to tell
- * them.
+ * !!!
+ * Historic vi moved the cursor to the from MARK if it was before the current
+ * cursor and on a different line, e.g., "yj" moves the cursor but "yk" and
+ * "yh" do not. Unfortunately, it's too late to change this now. Matching
+ * the historic semantics isn't easy. The line number was always changed and
+ * column movement was usually relative. However, "y'a" moved the cursor to
+ * the first non-blank of the line marked by a, while "y`a" moved the cursor
+ * to the line and column marked by a. Hopefully, the motion component code
+ * got it right... Unlike delete, we make no adjustments here.
*/
int
-v_gomark(sp, ep, vp, fm, tm, rp)
+v_yank(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
- MARK *mp;
+ int lmode;
- if ((mp = mark_get(sp, ep, vp->character)) == NULL)
+ /* The line may not exist in line mode cuts, check to be sure. */
+ if (F_ISSET(vp, VM_LMODE)) {
+ if (file_gline(sp, ep, vp->m_stop.lno, NULL) == NULL) {
+ v_eof(sp, ep, &vp->m_start);
+ return (1);
+ }
+ lmode = CUT_LINEMODE;
+ } else
+ lmode = 0;
+ if (cut(sp, ep, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode))
return (1);
- *rp = *mp;
+
+ sp->rptlines[L_YANKED] += (vp->m_stop.lno - vp->m_start.lno) + 1;
return (0);
}
diff --git a/usr.bin/vi/nvi/v_z.c b/usr.bin/vi/vi/v_z.c
index 31937ffc951c..ebae985f99c7 100644
--- a/usr.bin/vi/nvi/v_z.c
+++ b/usr.bin/vi/vi/v_z.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_z.c 8.8 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)v_z.c 8.11 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -45,11 +56,10 @@ static char sccsid[] = "@(#)v_z.c 8.8 (Berkeley) 12/2/93";
* Move the screen.
*/
int
-v_z(sp, ep, vp, fm, tm, rp)
+v_z(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
recno_t last, lno;
u_int value;
@@ -65,11 +75,11 @@ v_z(sp, ep, vp, fm, tm, rp)
if (lno > last)
lno = last;
} else
- lno = fm->lno;
+ lno = vp->m_start.lno;
- /* Set return cursor values. */
- rp->lno = lno;
- rp->cno = fm->cno;
+ /* Set default return cursor values. */
+ vp->m_final.lno = lno;
+ vp->m_final.cno = vp->m_start.cno;
/*
* The second count is the displayed window size, i.e. the 'z'
@@ -81,7 +91,7 @@ v_z(sp, ep, vp, fm, tm, rp)
* of the O_WINDOW option, but that's not how it worked historically.
*/
if (F_ISSET(vp, VC_C2SET) &&
- vp->count2 != 0 && sp->s_rrel(sp, vp->count2))
+ vp->count2 != 0 && sp->s_crel(sp, vp->count2))
return (1);
switch (vp->character) {
@@ -119,9 +129,9 @@ v_z(sp, ep, vp, fm, tm, rp)
*/
if (sp->s_fill(sp, ep, lno, P_BOTTOM))
return (1);
- if (sp->s_down(sp, ep, rp, sp->t_maxrows - 1, 1))
+ if (sp->s_down(sp, ep, &vp->m_final, sp->t_maxrows - 1, 1))
return (1);
- if (sp->s_position(sp, ep, rp, 0, P_MIDDLE))
+ if (sp->s_position(sp, ep, &vp->m_final, 0, P_MIDDLE))
return (1);
break;
}
diff --git a/usr.bin/vi/nvi/v_exit.c b/usr.bin/vi/vi/v_zexit.c
index f308c480d3d7..053646e1383a 100644
--- a/usr.bin/vi/nvi/v_exit.c
+++ b/usr.bin/vi/vi/v_zexit.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,27 +32,36 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)v_exit.c 8.5 (Berkeley) 12/10/93";
+static char sccsid[] = "@(#)v_zexit.c 8.7 (Berkeley) 3/8/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "excmd.h"
#include "vcmd.h"
/*
- * v_exit -- ZZ
+ * v_zexit -- ZZ
* Save the file and exit.
*/
int
-v_exit(sp, ep, vp, fm, tm, rp)
+v_zexit(sp, ep, vp)
SCR *sp;
EXF *ep;
VICMDARG *vp;
- MARK *fm, *tm, *rp;
{
if (F_ISSET(ep, F_MODIFIED) &&
file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
@@ -63,8 +72,8 @@ v_exit(sp, ep, vp, fm, tm, rp)
* Historic practice: quit! or two quit's done in succession
* (where ZZ counts as a quit) didn't check for other files.
*
- * Also check for related screens; if they exist, quit, the
- * user will get the message on the last screen.
+ * Check for related screens; quit if they exist, the user will
+ * get a message on the last screen.
*/
if (sp->ccnt != sp->q_ccnt + 1 &&
ep->refcnt <= 1 && file_unedited(sp) != NULL) {
diff --git a/usr.bin/vi/nvi/vcmd.c b/usr.bin/vi/vi/vcmd.c
index d7f1caf81d0c..445f6507c4c3 100644
--- a/usr.bin/vi/nvi/vcmd.c
+++ b/usr.bin/vi/vi/vcmd.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)vcmd.c 8.22 (Berkeley) 1/8/94";
+static char sccsid[] = "@(#)vcmd.c 8.26 (Berkeley) 3/22/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -48,11 +59,11 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
/* 000 NUL -- The code in vi.c expects key 0 to be undefined. */
{NULL},
/* 001 ^A */
- {v_searchw, V_ABS|V_CNT|V_MOVE|V_KEYW|V_RCM_SET,
+ {v_searchw, V_ABS|V_CNT|V_MOVE|V_KEYW|VM_RCM_SET,
"[count]^A",
"^A search forward for cursor word"},
/* 002 ^B */
- {v_pageup, V_ABS|V_CNT|V_RCM_SETLFNB,
+ {v_pageup, V_ABS|V_CNT|VM_RCM_SETLFNB,
"[count]^B",
"^B page up by screens"},
/* 003 ^C */
@@ -60,7 +71,7 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
"^C",
"^C interrupt a search or global command"},
/* 004 ^D */
- {v_hpagedown, V_ABS|V_CNT|V_RCM_SETLFNB,
+ {v_hpagedown, V_ABS|V_CNT|VM_RCM_SETLFNB,
"[count]^D",
"^D page down by half screens (setting count)"},
/* 005 ^E */
@@ -68,7 +79,7 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
"[count]^E",
"^E page down by lines"},
/* 006 ^F */
- {v_pagedown, V_ABS|V_CNT|V_RCM_SETLFNB,
+ {v_pagedown, V_ABS|V_CNT|VM_RCM_SETLFNB,
"[count]^F",
"^F page down by screens"},
/* 007 ^G */
@@ -76,13 +87,13 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
"^G",
"^G file status"},
/* 010 ^H */
- {v_left, V_CNT|V_MOVE|V_RCM_SET,
+ {v_left, V_CNT|V_MOVE|VM_RCM_SET,
"[count]^H",
"^H move left by columns"},
/* 011 ^I */
{NULL},
/* 012 ^J */
- {v_down, V_CNT|V_LMODE|V_MOVE|V_RCM,
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
"[count]^J",
"^J move down by lines"},
/* 013 ^K */
@@ -92,17 +103,17 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
"^L",
"^L redraw screen"},
/* 015 ^M */
- {v_cr, V_CNT|V_LMODE|V_MOVE|V_RCM_SETFNB,
+ {v_cr, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
"[count]^M",
"^M move down by lines (to first non-blank)"},
/* 016 ^N */
- {v_down, V_CNT|V_LMODE|V_MOVE|V_RCM,
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
"[count]^N",
"^N move down by lines"},
/* 017 ^O */
{NULL},
/* 020 ^P */
- {v_up, V_CNT|V_LMODE|V_MOVE|V_RCM,
+ {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
"[count]^P",
"^P move up by lines"},
/* 021 ^Q -- not available, used for hardware flow control. */
@@ -114,11 +125,11 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
/* 023 ^S -- not available, used for hardware flow control. */
{NULL},
/* 024 ^T */
- {v_tagpop, V_RCM_SET,
+ {v_tagpop, VM_RCM_SET,
"^T",
"^T tag pop"},
/* 025 ^U */
- {v_hpageup, V_ABS|V_CNT|V_RCM_SETLFNB,
+ {v_hpageup, V_ABS|V_CNT|VM_RCM_SETLFNB,
"[count]^U",
"^U half page up (set count)"},
/* 026 ^V */
@@ -146,7 +157,7 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
/* 034 ^\ */
{NULL},
/* 035 ^] */
- {v_tagpush, V_KEYW|V_RCM_SET,
+ {v_tagpush, V_KEYW|VM_RCM_SET,
"^]",
"^] tag push cursor word"},
/* 036 ^^ */
@@ -156,25 +167,25 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
/* 037 ^_ */
{NULL},
/* 040 ' ' */
- {v_right, V_CNT|V_MOVE|V_RCM_SET,
+ {v_right, V_CNT|V_MOVE|VM_RCM_SET,
"[count]' '",
" <space> move right by columns"},
/* 041 ! */
- {v_filter, V_CNT|V_DOT|V_MOTION|V_RCM_SET,
+ {v_filter, V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
"[count]![count]motion command(s)",
" ! filter through command(s) to motion"},
/* 042 " */
{NULL},
/* 043 # */
- {v_increment, V_CHAR|V_CNT|V_DOT|V_KEYNUM|V_RCM_SET,
+ {v_increment, V_CHAR|V_CNT|V_DOT|V_KEYNUM|VM_RCM_SET,
"[count]#[#+-]",
" # number increment/decrement"},
/* 044 $ */
- {v_dollar, V_CNT|V_MOVE|V_RCM_SETLAST,
+ {v_dollar, V_CNT|V_MOVE|VM_RCM_SETLAST,
" [count]$",
" $ move to last column"},
/* 045 % */
- {v_match, V_ABS|V_MOVE|V_RCM_SET,
+ {v_match, V_ABS|V_MOVE|VM_RCM_SET,
"%",
" % move to match"},
/* 046 & */
@@ -182,29 +193,29 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
"&",
" & repeat substitution"},
/* 047 ' */
- {v_gomark, V_ABS|V_CHAR|V_LMODE|V_MOVE|V_RCM_SETFNB,
+ {v_fmark, V_ABS|V_CHAR|V_MOVE|VM_LMODE,
"'['a-z]",
" ' move to mark (to first non-blank)"},
/* 050 ( */
- {v_sentenceb, V_CNT|V_MOVE|V_RCM_SET,
+ {v_sentenceb, V_CNT|V_MOVE|VM_RCM_SET,
"[count](",
" ( move back sentence"},
/* 051 ) */
- {v_sentencef, V_ABS|V_CNT|V_MOVE|V_RCM_SET,
+ {v_sentencef, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
"[count])",
" ) move forward sentence"},
/* 052 * */
{NULL},
/* 053 + */
- {v_down, V_CNT|V_LMODE|V_MOVE|V_RCM_SETFNB,
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
"[count]+",
" + move down by lines (to first non-blank)"},
/* 054 , */
- {v_chrrepeat, V_CNT|V_MOVE|V_RCM_SET,
+ {v_chrrepeat, V_CNT|V_MOVE|VM_RCM_SET,
"[count],",
" , reverse last F, f, T or t search"},
/* 055 - */
- {v_up, V_CNT|V_LMODE|V_MOVE|V_RCM_SETFNB,
+ {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
"[count]-",
" - move up by lines (to first non-blank)"},
/* 056 . */
@@ -212,11 +223,11 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
".",
" . repeat the last command"},
/* 057 / */
- {v_searchf, V_ABS|V_MOVE|V_RCM_SET,
+ {v_searchf, V_ABS|V_MOVE|VM_RCM_SET,
"/RE[/ offset]",
" / search forward"},
/* 060 0 */
- {v_zero, V_MOVE|V_RCM_SET,
+ {v_zero, V_MOVE|VM_RCM_SET,
"0",
" 0 move to first character"},
/* 061 1 */
@@ -242,87 +253,87 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
":command [| command] ...",
" : ex command"},
/* 073 ; */
- {v_chrepeat, V_CNT|V_MOVE|V_RCM_SET,
+ {v_chrepeat, V_CNT|V_MOVE|VM_RCM_SET,
"[count];",
" ; repeat last F, f, T or t search"},
/* 074 < */
- {v_shiftl, V_CNT|V_DOT|V_MOTION|V_RCM_SET|VC_SH,
+ {v_shiftl, V_CNT|V_DOT|V_MOTION|VC_S|VM_RCM_SET,
"[count]<[count]motion",
" < shift lines left to motion"},
/* 075 = */
{NULL},
/* 076 > */
- {v_shiftr, V_CNT|V_DOT|V_MOTION|V_RCM_SET|VC_SH,
+ {v_shiftr, V_CNT|V_DOT|V_MOTION|VC_S|VM_RCM_SET,
"[count]>[count]motion",
" > shift lines right to motion"},
/* 077 ? */
- {v_searchb, V_ABS|V_MOVE|V_RCM_SET,
+ {v_searchb, V_ABS|V_MOVE|VM_RCM_SET,
"?RE[? offset]",
" ? search backward"},
/* 100 @ */
- {v_at, V_RBUF|V_RCM_SET,
+ {v_at, V_RBUF|VM_RCM_SET,
"@buffer",
" @ execute buffer"},
/* 101 A */
- {v_iA, V_CNT|V_DOT|V_RCM_SET,
+ {v_iA, V_CNT|V_DOT|VM_RCM_SET,
"[count]A",
" A append to the line"},
/* 102 B */
- {v_wordB, V_CNT|V_MOVE|V_RCM_SET,
+ {v_wordB, V_CNT|V_MOVE|VM_RCM_SET,
"[count]B",
" B move back bigword"},
/* 103 C */
- {v_Change, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
+ {v_Change, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
"[buffer][count]C",
" C change to end-of-line"},
/* 104 D */
- {v_Delete, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
+ {v_Delete, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
"[buffer][count]D",
" D delete to end-of-line"},
/* 105 E */
- {v_wordE, V_CNT|V_MOVE|V_RCM_SET,
+ {v_wordE, V_CNT|V_MOVE|VM_RCM_SET,
"[count]E",
" E move to end of bigword"},
/* 106 F */
- {v_chF, V_CHAR|V_CNT|V_MOVE|V_RCM_SET,
+ {v_chF, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
"[count]F character",
" F character in line backward search"},
/* 107 G */
- {v_lgoto, V_ABS|V_CNT|V_LMODE|V_MOVE|V_RCM_SETFNB,
+ {v_lgoto, V_ABS|V_CNT|V_MOVE|VM_LMODE,
"[count]G",
" G move to line"},
/* 110 H */
- {v_home, V_CNT|V_LMODE|V_MOVE|V_RCM_SETNNB,
+ {v_home, V_ABS|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
"[count]H",
" H move to count lines from screen top"},
/* 111 I */
- {v_iI, V_CNT|V_DOT|V_RCM_SET,
+ {v_iI, V_CNT|V_DOT|VM_RCM_SET,
"[count]I",
" I insert at line beginning"},
/* 112 J */
- {v_join, V_CNT|V_DOT|V_RCM_SET,
+ {v_join, V_CNT|V_DOT|VM_RCM_SET,
"[count]J",
" J join lines"},
/* 113 K */
{NULL},
/* 114 L */
- {v_bottom, V_CNT|V_LMODE|V_MOVE|V_RCM_SETNNB,
+ {v_bottom, V_ABS|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
"[count]L",
" L move to screen bottom"},
/* 115 M */
- {v_middle, V_CNT|V_LMODE|V_MOVE|V_RCM_SETNNB,
+ {v_middle, V_ABS|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
"M",
" M move to screen middle"},
/* 116 N */
- {v_searchN, V_ABS|V_MOVE|V_RCM_SET,
+ {v_searchN, V_ABS|V_MOVE|VM_RCM_SET,
"n",
" N reverse last search"},
/* 117 O */
- {v_iO, V_CNT|V_DOT|V_RCM_SET,
+ {v_iO, V_CNT|V_DOT|VM_RCM_SET,
"[count]O",
" O insert above line"},
/* 120 P */
- {v_Put, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
+ {v_Put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
"[buffer]P",
" P insert before cursor from buffer"},
/* 121 Q */
@@ -330,117 +341,114 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
"Q",
" Q switch to ex mode"},
/* 122 R */
- {v_Replace, V_CNT|V_DOT|V_RCM_SET,
+ {v_Replace, V_CNT|V_DOT|VM_RCM_SET,
"[count]R",
" R replace characters"},
/* 123 S */
- {v_Subst, V_CNT|V_DOT|V_LMODE|V_OBUF|V_RCM_SET,
+ {v_Subst, V_CNT|V_DOT|V_OBUF|VM_LMODE|VM_RCM_SET,
"[buffer][count]S",
" S substitute for the line(s)"},
/* 124 T */
- {v_chT, V_CHAR|V_CNT|V_MOVE|V_RCM_SET,
+ {v_chT, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
"[count]T character",
" T before character in line backward search"},
/* 125 U */
- {v_Undo, V_RCM_SET,
+ {v_Undo, VM_RCM_SET,
"U",
" U Restore the current line"},
/* 126 V */
{NULL},
/* 127 W */
- {v_wordW, V_CNT|V_MOVE|V_RCM_SET,
+ {v_wordW, V_CNT|V_MOVE|VM_RCM_SET,
"[count]W",
" W move to next bigword"},
/* 130 X */
- {v_Xchar, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
+ {v_Xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
"[buffer][count]X",
" X delete character before cursor"},
/* 131 Y */
- {v_Yank, V_CNT|V_LMODE|V_OBUF,
+ {v_yank, V_CNT|VM_LMODE|V_OBUF,
"[buffer][count]Y",
" Y copy line"},
/* 132 Z */
- {v_exit, 0,
+ {v_zexit, 0,
"ZZ",
"ZZ save file and exit"},
/* 133 [ */
- {v_sectionb, V_ABS|V_LMODE|V_MOVE|V_RCM_SET,
+ {v_sectionb, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
"[[",
"[[ move back section"},
/* 134 \ */
{NULL},
/* 135 ] */
- {v_sectionf, V_ABS|V_LMODE|V_MOVE|V_RCM_SET,
+ {v_sectionf, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
"]]",
"]] move forward section"},
/* 136 ^ */
/*
- * DON'T set the V_RCM_SETFNB flag, the function has to do
- * the work anyway, in case it's a motion component. DO set
- * V_RCM_SET, so that any motion that's part of a command is
- * preserved.
+ * DON'T set the VM_RCM_SETFNB flag, the function has to do the work
+ * anyway, in case it's a motion component. DO set VM_RCM_SET, so
+ * that any motion that's part of a command is preserved.
*/
- {v_first, V_CNT|V_MOVE|V_RCM_SET,
+ {v_first, V_CNT|V_MOVE|VM_RCM_SET,
"^",
" ^ move to first non-blank"},
/* 137 _ */
/*
- * DON'T set the V_RCM_SETFNB flag, the function has to do
- * the work anyway, in case it's a motion component. DO set
- * V_RCM_SET, so that any motion that's part of a command is
- * preserved.
+ * Needs both to set the VM_RCM_SETFNB flag, and to do the work
+ * in the function, in case it's a delete.
*/
- {v_cfirst, V_CNT|V_MOVE|V_RCM_SET,
+ {v_cfirst, V_CNT|V_MOVE|VM_RCM_SETFNB,
"_",
" _ move to first non-blank"},
/* 140 ` */
- {v_gomark, V_ABS|V_CHAR|V_MOVE|V_RCM_SET,
+ {v_bmark, V_ABS|V_CHAR|V_MOVE|VM_RCM_SET,
"`[`a-z]",
" ` move to mark"},
/* 141 a */
- {v_ia, V_CNT|V_DOT|V_RCM_SET,
+ {v_ia, V_CNT|V_DOT|VM_RCM_SET,
"[count]a",
" a append after cursor"},
/* 142 b */
- {v_wordb, V_CNT|V_MOVE|V_RCM_SET,
+ {v_wordb, V_CNT|V_MOVE|VM_RCM_SET,
"[count]b",
" b move back word"},
/* 143 c */
- {v_change, V_CNT|V_DOT|V_MOTION|V_OBUF|V_RCM_SET|VC_C,
+ {v_change, V_CNT|V_DOT|V_MOTION|V_OBUF|VC_C|VM_RCM_SET,
"[buffer][count]c[count]motion",
" c change to motion"},
/* 144 d */
- {v_delete, V_CNT|V_DOT|V_MOTION|V_OBUF|V_RCM_SET|VC_D,
+ {v_delete, V_CNT|V_DOT|V_MOTION|V_OBUF|VC_D|VM_RCM_SET,
"[buffer][count]d[count]motion",
" d delete to motion"},
/* 145 e */
- {v_worde, V_CNT|V_MOVE|V_RCM_SET,
+ {v_worde, V_CNT|V_MOVE|VM_RCM_SET,
"[count]e",
" e move to end of word"},
/* 146 f */
- {v_chf, V_CHAR|V_CNT|V_MOVE|V_RCM_SET,
+ {v_chf, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
"[count]f character",
" f character in line forward search"},
/* 147 g */
{NULL},
/* 150 h */
- {v_left, V_CNT|V_MOVE|V_RCM_SET,
+ {v_left, V_CNT|V_MOVE|VM_RCM_SET,
"[count]h",
" h move left by columns"},
/* 151 i */
- {v_ii, V_CNT|V_DOT|V_RCM_SET,
+ {v_ii, V_CNT|V_DOT|VM_RCM_SET,
"[count]i",
" i insert before cursor"},
/* 152 j */
- {v_down, V_CNT|V_LMODE|V_MOVE|V_RCM,
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
"[count]j",
" j move down by lines"},
/* 153 k */
- {v_up, V_CNT|V_LMODE|V_MOVE|V_RCM,
+ {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
"[count]k",
" k move up by lines"},
/* 154 l */
- {v_right, V_CNT|V_MOVE|V_RCM_SET,
+ {v_right, V_CNT|V_MOVE|VM_RCM_SET,
"[count]l",
" l move right by columns"},
/* 155 m */
@@ -448,29 +456,29 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
"m[a-z]",
" m set mark"},
/* 156 n */
- {v_searchn, V_ABS|V_MOVE|V_RCM_SET,
+ {v_searchn, V_ABS|V_MOVE|VM_RCM_SET,
"n",
" n repeat last search"},
/* 157 o */
- {v_io, V_CNT|V_DOT|V_RCM_SET,
+ {v_io, V_CNT|V_DOT|VM_RCM_SET,
"[count]o",
" o append after line"},
/* 160 p */
- {v_put, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
+ {v_put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
"[buffer]p",
" p insert after cursor from buffer"},
/* 161 q */
{NULL},
/* 162 r */
- {v_replace, V_CNT|V_DOT|V_RCM_SET,
+ {v_replace, V_CNT|V_DOT|VM_RCM_SET,
"[count]r character",
" r replace character"},
/* 163 s */
- {v_subst, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
+ {v_subst, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
"[buffer][count]s",
" s substitute character"},
/* 164 t */
- {v_cht, V_CHAR|V_CNT|V_MOVE|V_RCM_SET,
+ {v_cht, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
"[count]t character",
" t before character in line forward search"},
/* 165 u */
@@ -478,21 +486,21 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
* DON'T set the V_DOT flag, it' more complicated than that.
* See vi/vi.c for details.
*/
- {v_undo, V_RCM_SET,
+ {v_undo, VM_RCM_SET,
"u",
" u undo last change"},
/* 166 v */
{NULL},
/* 167 w */
- {v_wordw, V_CNT|V_MOVE|V_RCM_SET,
+ {v_wordw, V_CNT|V_MOVE|VM_RCM_SET,
"[count]w",
" w move to next word"},
/* 170 x */
- {v_xchar, V_CNT|V_DOT|V_OBUF|V_RCM_SET,
+ {v_xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
"[buffer][count]x",
" x delete character"},
/* 171 y */
- {v_yank, V_CNT|V_MOTION|V_OBUF|V_RCM_SET|VC_Y,
+ {v_yank, V_CNT|V_MOTION|V_OBUF|VC_Y|VM_RCM_SET,
"[buffer][count]y[count]motion",
" y copy text to motion into a cut buffer"},
/* 172 z */
@@ -500,23 +508,23 @@ VIKEYS const vikeys [MAXVIKEY + 1] = {
* DON'T set the V_CHAR flag, the char isn't required,
* so it's handled specially in getcmd().
*/
- {v_z, V_CNT|V_RCM_SETFNB,
+ {v_z, V_CNT|VM_RCM_SETFNB,
"[line]z[window_size][-|.|+|^|<CR>]",
" z redraw window"},
/* 173 { */
- {v_paragraphb, V_ABS|V_CNT|V_LMODE|V_MOVE|V_RCM_SET,
+ {v_paragraphb, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
"[count]{",
" { move back paragraph"},
/* 174 | */
- {v_ncol, V_ABS|V_CNT|V_MOVE|V_RCM_SET,
+ {v_ncol, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
"[count]|",
" | move to column"},
/* 175 } */
- {v_paragraphf, V_ABS|V_CNT|V_LMODE|V_MOVE|V_RCM_SET,
+ {v_paragraphf, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
"[count]}",
" } move forward paragraph"},
/* 176 ~ */
- {v_ulcase, V_CNT|V_DOT|V_RCM_SET,
+ {v_ulcase, V_CNT|V_DOT|VM_RCM_SET,
"[count]~",
" ~ reverse case"},
};
diff --git a/usr.bin/vi/vi/vcmd.h b/usr.bin/vi/vi/vcmd.h
new file mode 100644
index 000000000000..f469296c1822
--- /dev/null
+++ b/usr.bin/vi/vi/vcmd.h
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vcmd.h 8.27 (Berkeley) 3/17/94
+ */
+
+typedef struct _vikeys VIKEYS;
+
+/* Structure passed around to functions implementing vi commands. */
+typedef struct _vicmdarg {
+#define vp_startzero buffer /* START ZERO OUT. */
+ CHAR_T key; /* Command key. */
+ CHAR_T buffer; /* Buffer. */
+ CHAR_T character; /* Character. */
+ u_long count; /* Count. */
+ u_long count2; /* Second count (only used by z). */
+ VIKEYS const *kp; /* VIKEYS key. */
+ size_t klen; /* Keyword length. */
+
+ /*
+ * Historic vi allowed "dl" when the cursor was on the last column,
+ * deleting the last character, and similarly allowed "dw" when
+ * the cursor was on the last column of the file. It didn't allow
+ * "dh" when the cursor was on column 1, although these cases are
+ * not strictly analogous. The point is that some movements would
+ * succeed if they were associated with a motion command, and fail
+ * otherwise. This is part of the off-by-1 schizophrenia that
+ * plagued vi. Other examples are that "dfb" deleted everything
+ * up to and including the next 'b' character, while "d/b" deleted
+ * everything up to the next 'b' character. While this implementation
+ * regularizes the interface to the extent possible, there are many
+ * special cases that can't be fixed. The special cases are handled
+ * by setting flags per command so that the underlying motion routines
+ * know what's really going on.
+ *
+ * The VC_* and VM_* flags are set in the vikeys array, and the VM_*
+ * flags may be set by the underlying functions (motion component or
+ * command) as well. For this reason, the flags in the VICMDARG and
+ * VIKEYS structures live in the same name space.
+ */
+#define VC_C 0x00000001 /* The 'c' command. */
+#define VC_D 0x00000002 /* The 'd' command. */
+#define VC_S 0x00000004 /* The '>' command. */
+#define VC_Y 0x00000008 /* The 'y' command. */
+#define VC_COMMASK 0x0000000f /* Mask for special flags. */
+#define ISMOTION(vp) F_ISSET(vp, VC_COMMASK)
+
+ /*
+ * The VM_RCM_* flags are single usage, i.e. if you set one, you have
+ * to clear the others.
+ */
+#define VM_LMODE 0x00000010 /* Motion is line oriented. */
+#define VM_NOMOTION 0x00000020 /* Motion command not entered. */
+#define VM_RCM 0x00000040 /* Use relative cursor movment (RCM). */
+#define VM_RCM_SET 0x00000080 /* RCM: set to current position. */
+#define VM_RCM_SETFNB 0x00000100 /* RCM: set to first non-blank (FNB). */
+#define VM_RCM_SETLAST 0x00000200 /* RCM: set to last character. */
+#define VM_RCM_SETLFNB 0x00000400 /* RCM: set to FNB if cursor moved. */
+#define VM_RCM_SETNNB 0x00000800 /* RCM: set to next non-blank. */
+#define VM_RCM_MASK 0x00000fc0 /* Mask for RCM flags. */
+
+ /* Flags for the underlying function. */
+#define VC_BUFFER 0x00001000 /* The buffer was set. */
+#define VC_C1RESET 0x00002000 /* Reset C1SET flag for dot commands. */
+#define VC_C1SET 0x00004000 /* Count 1 was set. */
+#define VC_C2SET 0x00008000 /* Count 2 was set. */
+#define VC_ISDOT 0x00010000 /* Command was the dot command. */
+ u_int32_t flags;
+
+#define vp_endzero keyword /* END ZERO OUT. */
+ char *keyword; /* Keyword. */
+ size_t kbuflen; /* Keyword buffer length. */
+ /*
+ * There are four cursor locations that we worry about: the initial
+ * cursor position, the start of the range, the end of the range,
+ * and the final cursor position. The initial cursor position and
+ * the start of the range are both m_start, and are always the same.
+ * All locations are initialized to the starting cursor position by
+ * the main vi routines, and the underlying functions depend on this.
+ *
+ * Commands that can be motion components set the end of the range
+ * cursor position, m_stop. All commands must set the ending cursor
+ * position, m_final. The reason that m_stop isn't the same as m_final
+ * is that there are situations where the final position of the cursor
+ * is outside of the cut/delete range (e.g. 'd[[' from the first column
+ * of a line). The final cursor position often varies based on the
+ * direction of the movement, as well as the command. The only special
+ * case that the delete code handles is that it will make adjustments
+ * if the final cursor position is deleted.
+ *
+ * The reason for all of this is that the historic vi semantics were
+ * defined command-by-command. Every function has to roll its own
+ * starting and stopping positions, and adjust if it's being used as a
+ * motion component. The general rules are as follows:
+ * 1: If not a motion component, the final cursor is at the end
+ * of the range.
+ * 2: If moving backward in the file:
+ * a: VC_D moves to the end of the range.
+ * b: If the line hasn't changed, VC_Y doesn't move, else it
+ * moves to the end of the range.
+ * 3: If moving forward in the file, VC_D and VC_Y stay at the
+ * start of the range.
+ *
+ * Usually, if moving backward in the file and it's a motion component,
+ * the starting cursor is decremented by a single character (or, in a
+ * few cases, to the end of the previous line) so that the starting
+ * cursor character isn't cut or deleted. No cursor adjustment is
+ * needed for moving forward, because the cut/delete routines handle
+ * m_stop inclusively, i.e. the last character in the range is cut or
+ * deleted. This makes cutting to the EOF/EOL reasonable.
+ *
+ * We ignore VC_C and VC_S everywhere, because the text input routines
+ * always set the cursor to the last character inserted.
+ */
+ MARK m_start; /* mark: initial cursor, range start. */
+ MARK m_stop; /* mark: range end. */
+ MARK m_final; /* mark: final cursor position. */
+} VICMDARG;
+
+/* Vi command structure. */
+struct _vikeys { /* Underlying function. */
+ int (*func) __P((SCR *, EXF *, VICMDARG *));
+#define V_ABS 0x00020000 /* Absolute movement, set '' mark. */
+#define V_CHAR 0x00040000 /* Character (required, trailing). */
+#define V_CNT 0x00080000 /* Count (optional, leading). */
+#define V_DOT 0x00100000 /* On success, sets dot command. */
+#define V_KEYNUM 0x00200000 /* Cursor referenced number. */
+#define V_KEYW 0x00400000 /* Cursor referenced word. */
+#define V_MOTION 0x00800000 /* Motion (required, trailing). */
+#define V_MOVE 0x01000000 /* Command defines movement. */
+#define V_OBUF 0x02000000 /* Buffer (optional, leading). */
+#define V_RBUF 0x04000000 /* Buffer (required, trailing). */
+ u_int32_t flags;
+ char *usage; /* Usage line. */
+ char *help; /* Help line. */
+};
+#define MAXVIKEY 126 /* List of vi commands. */
+extern VIKEYS const vikeys[MAXVIKEY + 1];
+
+/* Definition of a vi "word". */
+#define inword(ch) (isalnum(ch) || (ch) == '_')
+
+/* Character stream structure, prototypes. */
+typedef struct _vcs {
+ recno_t cs_lno; /* Line. */
+ size_t cs_cno; /* Column. */
+ char *cs_bp; /* Buffer. */
+ size_t cs_len; /* Length. */
+ int cs_ch; /* Character. */
+#define CS_EMP 1 /* Empty line. */
+#define CS_EOF 2 /* End-of-file. */
+#define CS_EOL 3 /* End-of-line. */
+#define CS_SOF 4 /* Start-of-file. */
+ int cs_flags; /* Return flags. */
+} VCS;
+
+int cs_bblank __P((SCR *, EXF *, VCS *));
+int cs_fblank __P((SCR *, EXF *, VCS *));
+int cs_fspace __P((SCR *, EXF *, VCS *));
+int cs_init __P((SCR *, EXF *, VCS *));
+int cs_next __P((SCR *, EXF *, VCS *));
+int cs_prev __P((SCR *, EXF *, VCS *));
+
+ /* Character search information. */
+enum cdirection { CNOTSET, FSEARCH, fSEARCH, TSEARCH, tSEARCH };
+
+/* Vi private, per-screen memory. */
+typedef struct _vi_private {
+ VICMDARG sdot; /* Saved dot, motion command. */
+ VICMDARG sdotmotion;
+
+ CHAR_T rlast; /* Last 'r' command character. */
+
+ char *rep; /* Input replay buffer. */
+ size_t rep_len; /* Input replay buffer length. */
+ size_t rep_cnt; /* Input replay buffer characters. */
+
+ CHAR_T inc_lastch; /* Last increment character. */
+ long inc_lastval; /* Last increment value. */
+
+ char *paragraph; /* Paragraph search list. */
+ size_t paragraph_len; /* Paragraph search list length. */
+
+ u_long u_ccnt; /* Undo command count. */
+
+ CHAR_T lastckey; /* Last search character. */
+ enum cdirection csearchdir; /* Character search direction. */
+} VI_PRIVATE;
+
+#define VIP(sp) ((VI_PRIVATE *)((sp)->vi_private))
+
+/* Vi function prototypes. */
+int txt_auto __P((SCR *, EXF *, recno_t, TEXT *, size_t, TEXT *));
+int v_buildparagraph __P((SCR *));
+int v_end __P((SCR *));
+void v_eof __P((SCR *, EXF *, MARK *));
+void v_eol __P((SCR *, EXF *, MARK *));
+int v_exwrite __P((void *, const char *, int));
+int v_init __P((SCR *, EXF *));
+int v_isempty __P((char *, size_t));
+int v_msgflush __P((SCR *));
+void v_nomove __P((SCR *));
+int v_ntext __P((SCR *, EXF *, TEXTH *, MARK *,
+ const char *, const size_t, MARK *, int, recno_t, u_int));
+int v_optchange __P((SCR *, int));
+int v_screen_copy __P((SCR *, SCR *));
+int v_screen_end __P((SCR *));
+void v_sof __P((SCR *, MARK *));
+void v_sol __P((SCR *));
+int vi __P((SCR *, EXF *));
+
+#define VIPROTO(name) int name __P((SCR *, EXF *, VICMDARG *))
+VIPROTO(v_again);
+VIPROTO(v_at);
+VIPROTO(v_bmark);
+VIPROTO(v_bottom);
+VIPROTO(v_cfirst);
+VIPROTO(v_Change);
+VIPROTO(v_change);
+VIPROTO(v_chF);
+VIPROTO(v_chf);
+VIPROTO(v_chrepeat);
+VIPROTO(v_chrrepeat);
+VIPROTO(v_chT);
+VIPROTO(v_cht);
+VIPROTO(v_cr);
+VIPROTO(v_Delete);
+VIPROTO(v_delete);
+VIPROTO(v_dollar);
+VIPROTO(v_down);
+VIPROTO(v_ex);
+VIPROTO(v_exmode);
+VIPROTO(v_filter);
+VIPROTO(v_first);
+VIPROTO(v_fmark);
+VIPROTO(v_home);
+VIPROTO(v_hpagedown);
+VIPROTO(v_hpageup);
+VIPROTO(v_iA);
+VIPROTO(v_ia);
+VIPROTO(v_iI);
+VIPROTO(v_ii);
+VIPROTO(v_increment);
+VIPROTO(v_iO);
+VIPROTO(v_io);
+VIPROTO(v_join);
+VIPROTO(v_left);
+VIPROTO(v_lgoto);
+VIPROTO(v_linedown);
+VIPROTO(v_lineup);
+VIPROTO(v_mark);
+VIPROTO(v_match);
+VIPROTO(v_middle);
+VIPROTO(v_ncol);
+VIPROTO(v_pagedown);
+VIPROTO(v_pageup);
+VIPROTO(v_paragraphb);
+VIPROTO(v_paragraphf);
+VIPROTO(v_Put);
+VIPROTO(v_put);
+VIPROTO(v_redraw);
+VIPROTO(v_Replace);
+VIPROTO(v_replace);
+VIPROTO(v_right);
+VIPROTO(v_screen);
+VIPROTO(v_searchb);
+VIPROTO(v_searchf);
+VIPROTO(v_searchN);
+VIPROTO(v_searchn);
+VIPROTO(v_searchw);
+VIPROTO(v_sectionb);
+VIPROTO(v_sectionf);
+VIPROTO(v_sentenceb);
+VIPROTO(v_sentencef);
+VIPROTO(v_shiftl);
+VIPROTO(v_shiftr);
+VIPROTO(v_status);
+VIPROTO(v_stop);
+VIPROTO(v_Subst);
+VIPROTO(v_subst);
+VIPROTO(v_switch);
+VIPROTO(v_tagpop);
+VIPROTO(v_tagpush);
+VIPROTO(v_ulcase);
+VIPROTO(v_Undo);
+VIPROTO(v_undo);
+VIPROTO(v_up);
+VIPROTO(v_wordB);
+VIPROTO(v_wordb);
+VIPROTO(v_wordE);
+VIPROTO(v_worde);
+VIPROTO(v_wordW);
+VIPROTO(v_wordw);
+VIPROTO(v_Xchar);
+VIPROTO(v_xchar);
+VIPROTO(v_Yank);
+VIPROTO(v_yank);
+VIPROTO(v_z);
+VIPROTO(v_zero);
+VIPROTO(v_zexit);
diff --git a/usr.bin/vi/nvi/vi.c b/usr.bin/vi/vi/vi.c
index f969d78cfabf..67fac036e1a5 100644
--- a/usr.bin/vi/nvi/vi.c
+++ b/usr.bin/vi/vi/vi.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)vi.c 8.45 (Berkeley) 1/22/94";
+static char sccsid[] = "@(#)vi.c 8.57 (Berkeley) 3/18/94";
#endif /* not lint */
#include <sys/types.h>
+#include <queue.h>
+#include <sys/time.h>
+#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
#include "vi.h"
#include "vcmd.h"
@@ -52,8 +62,7 @@ static inline int
static inline int
getkey __P((SCR *, CH *, u_int));
static int getkeyword __P((SCR *, EXF *, VICMDARG *, u_int));
-static int getmotion __P((SCR *, EXF *,
- VICMDARG *, VICMDARG *, MARK *, MARK *));
+static int getmotion __P((SCR *, EXF *, VICMDARG *, VICMDARG *));
/*
* Side-effect:
@@ -72,16 +81,14 @@ vi(sp, ep)
SCR *sp;
EXF *ep;
{
- MARK abs, fm, tm, m;
+ MARK abs;
VICMDARG cmd, *vp;
u_int flags, saved_mode;
int comcount, eval;
- /* Start vi. */
+ /* Start vi and paint the screen. */
if (v_init(sp, ep))
return (1);
-
- /* Paint the screen. */
if (sp->s_refresh(sp, ep)) {
(void)v_end(sp);
return (1);
@@ -111,67 +118,66 @@ vi(sp, ep)
if (F_ISSET(vp, VC_ISDOT) && comcount)
DOTMOTION->count = 1;
+ /* Copy the key flags into the local structure. */
+ F_SET(vp, vp->kp->flags);
+
/* Get any associated keyword. */
- flags = vp->kp->flags;
- if (LF_ISSET(V_KEYNUM | V_KEYW) &&
- getkeyword(sp, ep, vp, flags))
+ if (F_ISSET(vp, V_KEYNUM | V_KEYW) &&
+ getkeyword(sp, ep, vp, vp->flags))
goto err;
/* If a non-relative movement, copy the future absolute mark. */
- if (LF_ISSET(V_ABS)) {
+ if (F_ISSET(vp, V_ABS)) {
abs.lno = sp->lno;
abs.cno = sp->cno;
}
/*
- * Do any required motion; getmotion sets the from MARK
- * and the line mode flag.
+ * Set the three cursor locations to the current cursor. The
+ * underlying routines don't bother if the cursor doesn't move.
+ * This also handles line commands (e.g. Y) defaulting to the
+ * current line.
*/
- if (LF_ISSET(V_MOTION)) {
- if (getmotion(sp, ep, DOTMOTION, vp, &fm, &tm))
- goto err;
- } else {
- /*
- * Set everything to the current cursor position.
- * Line commands (ex: Y) default to the current line.
- */
- tm.lno = fm.lno = sp->lno;
- tm.cno = fm.cno = sp->cno;
+ vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno;
+ vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno;
- /*
- * Set line mode flag, for example, "yy".
- *
- * If a count is set, we set the to MARK here relative
- * to the cursor/from MARK. This is done for commands
- * that take both counts and motions, i.e. "4yy" and
- * "y%" -- there's no way the command can known which
- * the user did, so we have to do it here. There are
- * other commands that are line mode commands and take
- * counts ("#G", "#H") and for which this calculation
- * is either meaningless or wrong. Each command must
- * do its own validity checking of the value.
- */
- if (F_ISSET(vp->kp, V_LMODE)) {
- F_SET(vp, VC_LMODE);
- if (F_ISSET(vp, VC_C1SET)) {
- tm.lno = sp->lno + vp->count - 1;
- tm.cno = sp->cno;
- }
- }
+ /*
+ * Do any required motion; getmotion sets the from MARK and the
+ * line mode flag. We save off the RCM mask and only restore
+ * it if it no RCM flags are set by the motion command. This
+ * means that the motion command is expected to determine where
+ * the cursor ends up!
+ */
+ if (F_ISSET(vp, V_MOTION)) {
+ flags = F_ISSET(vp, VM_RCM_MASK);
+ F_CLR(vp, VM_RCM_MASK);
+ if (getmotion(sp, ep, DOTMOTION, vp))
+ goto err;
+ if (F_ISSET(vp, VM_NOMOTION))
+ goto err;
+ if (!F_ISSET(vp, VM_RCM_MASK))
+ F_SET(vp, flags);
}
+ /*
+ * If a count is set and the command is line oriented, set the
+ * to MARK here relative to the cursor/from MARK. This is for
+ * commands that take both counts and motions, i.e. "4yy" and
+ * "y%". As there's no way the command can know which the user
+ * did, we have to do it here. (There are commands that are
+ * line oriented and that take counts ("#G", "#H"), for which
+ * this calculation is either completely meaningless or wrong.
+ * Each command must validate the value for itself.
+ */
+ if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE))
+ vp->m_stop.lno += vp->count - 1;
+
/* Increment the command count. */
++sp->ccnt;
- /*
- * Call the function. Set the return cursor to the current
- * cursor position first -- the underlying routines don't
- * bother to do the work if it doesn't move.
- */
- m.lno = sp->lno;
- m.cno = sp->cno;
+ /* Save the mode and call the function. */
saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
- if ((vp->kp->func)(sp, ep, vp, &fm, &tm, &m))
+ if ((vp->kp->func)(sp, ep, vp))
goto err;
#ifdef DEBUG
/* Make sure no function left the temporary space locked. */
@@ -187,13 +193,13 @@ vi(sp, ep)
*/
if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))
break;
-
+
/* Set the absolute mark. */
- if (LF_ISSET(V_ABS) && mark_set(sp, ep, ABSMARK1, &abs, 1))
+ if (F_ISSET(vp, V_ABS) && mark_set(sp, ep, ABSMARK1, &abs, 1))
goto err;
/* Set the dot command structure. */
- if (LF_ISSET(V_DOT)) {
+ if (F_ISSET(vp, V_DOT)) {
*DOT = cmd;
F_SET(DOT, VC_ISDOT);
/*
@@ -207,13 +213,13 @@ vi(sp, ep)
/*
* Some vi row movements are "attracted" to the last position
- * set, i.e. the V_RCM commands are moths to the V_RCM_SET
+ * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET
* commands' candle. It's broken into two parts. Here we deal
* with the command flags. In sp->relative(), we deal with the
* screen flags. If the movement is to the EOL the vi command
* handles it. If it's to the beginning, we handle it here.
*
- * Note, some commands (e.g. _, ^) don't set the V_RCM_SETFNB
+ * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB
* flag, but do the work themselves. The reason is that they
* have to modify the column in case they're being used as a
* motion component. Other similar commands (e.g. +, -) don't
@@ -225,38 +231,45 @@ vi(sp, ep)
* You betcha. As they say, if you think you understand it,
* you don't.
*/
- switch (LF_ISSET(V_RCM | V_RCM_SETFNB |
- V_RCM_SETLAST | V_RCM_SETLFNB | V_RCM_SETNNB)) {
+ switch (F_ISSET(vp, VM_RCM_MASK)) {
case 0:
+ case VM_RCM_SET:
break;
- case V_RCM:
- m.cno = sp->s_relative(sp, ep, m.lno);
+ case VM_RCM:
+ vp->m_final.cno = sp->s_rcm(sp, ep, vp->m_final.lno);
break;
- case V_RCM_SETLAST:
+ case VM_RCM_SETLAST:
sp->rcmflags = RCM_LAST;
break;
- case V_RCM_SETLFNB:
- if (fm.lno != m.lno) {
- if (nonblank(sp, ep, m.lno, &m.cno))
+ case VM_RCM_SETLFNB:
+ /*
+ * If we changed lines, move to the first non-blank.
+ * This is the hack that makes logical scrolling on
+ * really long lines work.
+ */
+ if (vp->m_start.lno != vp->m_final.lno) {
+ vp->m_final.cno = 0;
+ if (nonblank(sp, ep,
+ vp->m_final.lno, &vp->m_final.cno))
goto err;
sp->rcmflags = RCM_FNB;
}
break;
- case V_RCM_SETFNB:
- m.cno = 0;
+ case VM_RCM_SETFNB:
+ vp->m_final.cno = 0;
/* FALLTHROUGH */
- case V_RCM_SETNNB:
- if (nonblank(sp, ep, m.lno, &m.cno))
+ case VM_RCM_SETNNB:
+ if (nonblank(sp, ep, vp->m_final.lno, &vp->m_final.cno))
goto err;
sp->rcmflags = RCM_FNB;
break;
default:
abort();
}
-
+
/* Update the cursor. */
- sp->lno = m.lno;
- sp->cno = m.cno;
+ sp->lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
if (!MAPPED_KEYS_WAITING(sp)) {
(void)msg_rpt(sp, 1);
@@ -272,7 +285,7 @@ err: term_map_flush(sp, "Vi error");
}
/* Set the new favorite position. */
- if (LF_ISSET(V_RCM_SET)) {
+ if (F_ISSET(vp, VM_RCM_SET)) {
sp->rcmflags = 0;
(void)sp->s_column(sp, ep, &sp->rcm);
}
@@ -422,26 +435,29 @@ getcmd(sp, ep, dp, vp, ismotion, comcountp)
/* Required buffer. */
if (LF_ISSET(V_RBUF))
KEY(vp->buffer, 0);
+ }
- /*
- * Special case: '[', ']' and 'Z' commands. Doesn't the
- * fact that the *single* characters don't mean anything
- * but the *doubled* characters do just frost your shorts?
- */
- if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
- KEY(key, TXT_MAPCOMMAND);
- if (vp->key != key)
- goto usage;
+ /*
+ * Special case: '[', ']' and 'Z' commands. Doesn't the fact that
+ * the *single* characters don't mean anything but the *doubled*
+ * characters do just frost your shorts?
+ */
+ if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
+ KEY(key, TXT_MAPCOMMAND);
+ if (vp->key != key) {
+usage: msgq(sp, M_ERR, "Usage: %s", ismotion != NULL ?
+ vikeys[ismotion->key].usage : kp->usage);
+ return (1);
}
- /* Special case: 'z' command. */
- if (vp->key == 'z') {
+ }
+ /* Special case: 'z' command. */
+ if (vp->key == 'z') {
+ KEY(vp->character, 0);
+ if (isdigit(vp->character)) {
+ if (getcount(sp, vp->character, &vp->count2))
+ return (1);
+ F_SET(vp, VC_C2SET);
KEY(vp->character, 0);
- if (isdigit(vp->character)) {
- if (getcount(sp, vp->character, &vp->count2))
- return (1);
- F_SET(vp, VC_C2SET);
- KEY(vp->character, 0);
- }
}
}
@@ -449,9 +465,9 @@ getcmd(sp, ep, dp, vp, ismotion, comcountp)
* Commands that have motion components can be doubled to
* imply the current line.
*/
- else if (ismotion->key != key && !LF_ISSET(V_MOVE)) {
-usage: msgq(sp, M_ERR, "Usage: %s", ismotion != NULL ?
- vikeys[ismotion->key].usage : kp->usage);
+ if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
+ msgq(sp, M_ERR, "%s may not be used as a motion command.",
+ charname(sp, key));
return (1);
}
@@ -468,14 +484,14 @@ usage: msgq(sp, M_ERR, "Usage: %s", ismotion != NULL ?
* Get resulting motion mark.
*/
static int
-getmotion(sp, ep, dm, vp, fm, tm)
+getmotion(sp, ep, dm, vp)
SCR *sp;
EXF *ep;
VICMDARG *dm, *vp;
- MARK *fm, *tm;
{
MARK m;
VICMDARG motion;
+ size_t len;
u_long cnt;
int notused;
@@ -490,7 +506,7 @@ getmotion(sp, ep, dm, vp, fm, tm)
* A count may be provided both to the command and to the motion, in
* which case the count is multiplicative. For example, "3y4y" is the
* same as "12yy". This count is provided to the motion command and
- * not to the regular function.
+ * not to the regular function.
*/
cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
if (F_ISSET(vp, VC_C1SET)) {
@@ -513,29 +529,31 @@ getmotion(sp, ep, dm, vp, fm, tm)
* the resulting mark.
*/
if (vp->key == motion.key) {
- F_SET(vp, VC_LMODE);
+ F_SET(vp, VM_LMODE);
+
+ /* Set the origin of the command. */
+ vp->m_start.lno = sp->lno;
+ vp->m_start.cno = 0;
/*
- * Set the end of the command; the column is after the line.
+ * Set the end of the command.
*
* If the current line is missing, i.e. the file is empty,
* historic vi permitted a "cc" or "!!" command to insert
* text.
*/
- tm->lno = sp->lno + motion.count - 1;
- if (file_gline(sp, ep, tm->lno, &tm->cno) == NULL) {
- if (tm->lno != 1 || vp->key != 'c' && vp->key != '!') {
+ vp->m_stop.lno = sp->lno + motion.count - 1;
+ if (file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) {
+ if (vp->m_stop.lno != 1 ||
+ vp->key != 'c' && vp->key != '!') {
m.lno = sp->lno;
m.cno = sp->cno;
v_eof(sp, ep, &m);
return (1);
}
- tm->cno = 0;
- }
-
- /* Set the origin of the command. */
- fm->lno = sp->lno;
- fm->cno = 0;
+ vp->m_stop.cno = 0;
+ } else
+ vp->m_stop.cno = len ? len - 1 : 0;
} else {
/*
* Motion commands change the underlying movement (*snarl*).
@@ -544,56 +562,60 @@ getmotion(sp, ep, dm, vp, fm, tm)
*/
F_SET(&motion, vp->kp->flags & VC_COMMASK);
+ /* Copy the key flags into the local structure. */
+ F_SET(&motion, motion.kp->flags);
+
/*
- * Everything starts at the current position. This permits
- * commands like 'j' and 'k', that are line oriented motions
- * and have special cursor suck semantics when they are used
- * as standalone commands, to ignore column positioning.
+ * Set the three cursor locations to the current cursor. This
+ * permits commands like 'j' and 'k', that are line oriented
+ * motions and have special cursor suck semantics when they are
+ * used as standalone commands, to ignore column positioning.
*/
- fm->lno = tm->lno = sp->lno;
- fm->cno = tm->cno = sp->cno;
- if ((motion.kp->func)(sp, ep, &motion, fm, NULL, tm))
+ motion.m_final.lno =
+ motion.m_stop.lno = motion.m_start.lno = sp->lno;
+ motion.m_final.cno =
+ motion.m_stop.cno = motion.m_start.cno = sp->cno;
+
+ /* Run the function. */
+ if ((motion.kp->func)(sp, ep, &motion))
return (1);
/*
- * If the underlying motion was a line motion, set the flag
- * in the command structure. Underlying commands can also
- * flag the movement as a line motion (see v_sentence).
+ * Copy line mode and cursor position information from the
+ * motion command structure. The commands can flag the
+ * movement as a line motion (see v_sentence) as well as set
+ * the VM_RCM_* flags explicitly.
*/
- if (F_ISSET(motion.kp, V_LMODE) || F_ISSET(&motion, VC_LMODE))
- F_SET(vp, VC_LMODE);
+ F_SET(vp,
+ F_ISSET(&motion, VM_LMODE | VM_NOMOTION | VM_RCM_MASK));
/*
- * If the motion is in the reverse direction, switch the from
- * and to MARK's so that it's always in a forward direction.
- * Because the motion is always from the from MARK to, but not
- * including, the to MARK, the function may have modified the
- * from MARK, so that it gets the one-past-the-place semantics
- * we use; see v_match() for an example. Also set a flag so
- * that the underlying function knows that we did this; v_yank,
- * for example, has to know so it gets the return cursor right.
+ * Motion commands can reset all of the cursor information.
+ * If the motion is in the reverse direction, switch the
+ * from and to MARK's so that it's in a forward direction.
+ * Motions are from the from MARK to the to MARK (inclusive).
*/
- if (tm->lno < fm->lno ||
- tm->lno == fm->lno && tm->cno < fm->cno) {
- m = *fm;
- *fm = *tm;
- *tm = m;
- F_SET(vp, VC_REVMOVE);
+ if (motion.m_start.lno > motion.m_stop.lno ||
+ motion.m_start.lno == motion.m_stop.lno &&
+ motion.m_start.cno > motion.m_stop.cno) {
+ vp->m_start = motion.m_stop;
+ vp->m_stop = motion.m_start;
+ } else {
+ vp->m_start = motion.m_start;
+ vp->m_stop = motion.m_stop;
}
+ vp->m_final = motion.m_final;
}
/*
- * If the command sets dot, save the motion structure. The
- * motion count was changed above and needs to be reset, that's
- * why this is done here, and not in the calling routine.
+ * If the command sets dot, save the motion structure. The motion
+ * count was changed above and needs to be reset, that's why this
+ * is done here, and not in the calling routine.
*/
if (F_ISSET(vp->kp, V_DOT)) {
*dm = motion;
dm->count = cnt;
}
-
- /* Let the underlying function know what motion command was used. */
- vp->mkp = motion.kp;
return (0);
}
@@ -771,9 +793,8 @@ getkey(sp, ikeyp, map)
case INP_OK:
break;
case INP_EOF:
- F_SET(sp, S_EXIT_FORCE);
- /* FALLTHROUGH */
case INP_ERR:
+ F_SET(sp, S_EXIT_FORCE);
return (1);
}
return (ikeyp->value == K_ESCAPE);
diff --git a/usr.bin/vi/xaw/xaw_screen.c b/usr.bin/vi/xaw/xaw_screen.c
index ec76a0668cf9..c7660837d706 100644
--- a/usr.bin/vi/xaw/xaw_screen.c
+++ b/usr.bin/vi/xaw/xaw_screen.c
@@ -1,6 +1,6 @@
/*-
- * Copyright (c) 1993 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,9 +32,21 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)xaw_screen.c 8.4 (Berkeley) 1/11/94";
+static char sccsid[] = "@(#)xaw_screen.c 8.5 (Berkeley) 3/8/94";
#endif /* not lint */
+#include <queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
+
#include "vi.h"
/*