aboutsummaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/vi/Makefile3
-rw-r--r--usr.bin/vi/USD.doc/edit/Makefile18
-rw-r--r--usr.bin/vi/USD.doc/edit/edit.vindex115
-rw-r--r--usr.bin/vi/USD.doc/edit/edittut.ms2322
-rw-r--r--usr.bin/vi/USD.doc/exref/Makefile14
-rw-r--r--usr.bin/vi/USD.doc/exref/ex.rm2230
-rw-r--r--usr.bin/vi/USD.doc/exref/ex.summary734
-rw-r--r--usr.bin/vi/USD.doc/vi.man/Makefile14
-rw-r--r--usr.bin/vi/USD.doc/vi.man/vi.0798
-rw-r--r--usr.bin/vi/USD.doc/vi.man/vi.0.ps1063
-rw-r--r--usr.bin/vi/USD.doc/vi.man/vi.11294
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/Makefile25
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/ex.cmd.roff1776
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/merge.awk16
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/paper.ps30924
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/set.opt.roff949
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/spell.ok270
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/vi.cmd.roff2984
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/vi.ref1270
-rw-r--r--usr.bin/vi/USD.doc/vi.ref/vi.ref.txt5544
-rw-r--r--usr.bin/vi/USD.doc/vitut/Makefile17
-rw-r--r--usr.bin/vi/USD.doc/vitut/vi.apwh.ms1079
-rw-r--r--usr.bin/vi/USD.doc/vitut/vi.chars644
-rw-r--r--usr.bin/vi/USD.doc/vitut/vi.in2064
-rw-r--r--usr.bin/vi/USD.doc/vitut/vi.summary468
-rw-r--r--usr.bin/vi/common/Makefile98
-rw-r--r--usr.bin/vi/common/args.h53
-rw-r--r--usr.bin/vi/common/cut.c366
-rw-r--r--usr.bin/vi/common/cut.h96
-rw-r--r--usr.bin/vi/common/delete.c193
-rw-r--r--usr.bin/vi/common/exf.c830
-rw-r--r--usr.bin/vi/common/exf.h128
-rw-r--r--usr.bin/vi/common/gs.h107
-rw-r--r--usr.bin/vi/common/line.c492
-rw-r--r--usr.bin/vi/common/log.c698
-rw-r--r--usr.bin/vi/common/log.h53
-rw-r--r--usr.bin/vi/common/main.c711
-rw-r--r--usr.bin/vi/common/mark.c272
-rw-r--r--usr.bin/vi/common/mark.h73
-rw-r--r--usr.bin/vi/common/mem.h178
-rw-r--r--usr.bin/vi/common/msg.c427
-rw-r--r--usr.bin/vi/common/msg.h82
-rw-r--r--usr.bin/vi/common/options.awk9
-rw-r--r--usr.bin/vi/common/options.c890
-rw-r--r--usr.bin/vi/common/options.h.stub108
-rw-r--r--usr.bin/vi/common/options_f.c518
-rw-r--r--usr.bin/vi/common/pathnames.h45
-rw-r--r--usr.bin/vi/common/put.c254
-rw-r--r--usr.bin/vi/common/recover.c869
-rw-r--r--usr.bin/vi/common/screen.c309
-rw-r--r--usr.bin/vi/common/screen.h342
-rw-r--r--usr.bin/vi/common/search.c833
-rw-r--r--usr.bin/vi/common/search.h54
-rw-r--r--usr.bin/vi/common/seq.c350
-rw-r--r--usr.bin/vi/common/seq.h79
-rw-r--r--usr.bin/vi/common/signal.c569
-rw-r--r--usr.bin/vi/common/term.c732
-rw-r--r--usr.bin/vi/common/term.h205
-rw-r--r--usr.bin/vi/common/trace.c84
-rw-r--r--usr.bin/vi/common/util.c215
-rw-r--r--usr.bin/vi/common/vi.h124
-rw-r--r--usr.bin/vi/docs/README200
-rw-r--r--usr.bin/vi/docs/bugs.current47
-rw-r--r--usr.bin/vi/docs/changelog519
-rw-r--r--usr.bin/vi/docs/ev55
-rw-r--r--usr.bin/vi/docs/features92
-rw-r--r--usr.bin/vi/docs/internals/autowrite88
-rw-r--r--usr.bin/vi/docs/internals/context32
-rw-r--r--usr.bin/vi/docs/internals/gdb.script68
-rw-r--r--usr.bin/vi/docs/internals/input350
-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/tutorial/vi.advanced1458
-rw-r--r--usr.bin/vi/docs/tutorial/vi.beginner741
-rwxr-xr-xusr.bin/vi/docs/tutorial/vi.tut.csh24
-rw-r--r--usr.bin/vi/ex/ex.c1866
-rw-r--r--usr.bin/vi/ex/ex_abbrev.c129
-rw-r--r--usr.bin/vi/ex/ex_append.c220
-rw-r--r--usr.bin/vi/ex/ex_args.c263
-rw-r--r--usr.bin/vi/ex/ex_argv.c609
-rw-r--r--usr.bin/vi/ex/ex_at.c118
-rw-r--r--usr.bin/vi/ex/ex_bang.c242
-rw-r--r--usr.bin/vi/ex/ex_cd.c223
-rw-r--r--usr.bin/vi/ex/ex_delete.c92
-rw-r--r--usr.bin/vi/ex/ex_digraph.c324
-rw-r--r--usr.bin/vi/ex/ex_display.c169
-rw-r--r--usr.bin/vi/ex/ex_edit.c122
-rw-r--r--usr.bin/vi/ex/ex_equal.c86
-rw-r--r--usr.bin/vi/ex/ex_exit.c79
-rw-r--r--usr.bin/vi/ex/ex_file.c103
-rw-r--r--usr.bin/vi/ex/ex_global.c400
-rw-r--r--usr.bin/vi/ex/ex_init.c202
-rw-r--r--usr.bin/vi/ex/ex_join.c200
-rw-r--r--usr.bin/vi/ex/ex_map.c160
-rw-r--r--usr.bin/vi/ex/ex_mark.c66
-rw-r--r--usr.bin/vi/ex/ex_mkexrc.c130
-rw-r--r--usr.bin/vi/ex/ex_move.c222
-rw-r--r--usr.bin/vi/ex/ex_open.c75
-rw-r--r--usr.bin/vi/ex/ex_preserve.c128
-rw-r--r--usr.bin/vi/ex/ex_print.c212
-rw-r--r--usr.bin/vi/ex/ex_put.c78
-rw-r--r--usr.bin/vi/ex/ex_read.c300
-rw-r--r--usr.bin/vi/ex/ex_screen.c155
-rw-r--r--usr.bin/vi/ex/ex_script.c582
-rw-r--r--usr.bin/vi/ex/ex_set.c70
-rw-r--r--usr.bin/vi/ex/ex_shell.c150
-rw-r--r--usr.bin/vi/ex/ex_shift.c204
-rw-r--r--usr.bin/vi/ex/ex_source.c66
-rw-r--r--usr.bin/vi/ex/ex_stop.c76
-rw-r--r--usr.bin/vi/ex/ex_subst.c1001
-rw-r--r--usr.bin/vi/ex/ex_tag.c905
-rw-r--r--usr.bin/vi/ex/ex_undo.c103
-rw-r--r--usr.bin/vi/ex/ex_usage.c197
-rw-r--r--usr.bin/vi/ex/ex_util.c189
-rw-r--r--usr.bin/vi/ex/ex_version.c71
-rw-r--r--usr.bin/vi/ex/ex_visual.c137
-rw-r--r--usr.bin/vi/ex/ex_write.c327
-rw-r--r--usr.bin/vi/ex/ex_yank.c69
-rw-r--r--usr.bin/vi/ex/ex_z.c180
-rw-r--r--usr.bin/vi/ex/excmd.awk6
-rw-r--r--usr.bin/vi/ex/excmd.c458
-rw-r--r--usr.bin/vi/ex/excmd.h.stub285
-rw-r--r--usr.bin/vi/ex/filter.c414
-rw-r--r--usr.bin/vi/ex/script.h45
-rw-r--r--usr.bin/vi/ex/tag.h58
-rw-r--r--usr.bin/vi/install/recover.script32
-rw-r--r--usr.bin/vi/sex/sex_confirm.c86
-rw-r--r--usr.bin/vi/sex/sex_get.c514
-rw-r--r--usr.bin/vi/sex/sex_refresh.c140
-rw-r--r--usr.bin/vi/sex/sex_screen.c340
-rw-r--r--usr.bin/vi/sex/sex_screen.h79
-rw-r--r--usr.bin/vi/sex/sex_term.c217
-rw-r--r--usr.bin/vi/sex/sex_util.c148
-rw-r--r--usr.bin/vi/sex/sex_window.c194
-rw-r--r--usr.bin/vi/svi/svi_confirm.c95
-rw-r--r--usr.bin/vi/svi/svi_curses.c252
-rw-r--r--usr.bin/vi/svi/svi_ex.c650
-rw-r--r--usr.bin/vi/svi/svi_get.c161
-rw-r--r--usr.bin/vi/svi/svi_line.c441
-rw-r--r--usr.bin/vi/svi/svi_refresh.c818
-rw-r--r--usr.bin/vi/svi/svi_relative.c334
-rw-r--r--usr.bin/vi/svi/svi_screen.c332
-rw-r--r--usr.bin/vi/svi/svi_screen.h262
-rw-r--r--usr.bin/vi/svi/svi_smap.c1216
-rw-r--r--usr.bin/vi/svi/svi_split.c627
-rw-r--r--usr.bin/vi/svi/svi_term.c310
-rw-r--r--usr.bin/vi/svi/svi_util.c347
-rw-r--r--usr.bin/vi/vi/getc.c268
-rw-r--r--usr.bin/vi/vi/v_ch.c340
-rw-r--r--usr.bin/vi/vi/v_delete.c160
-rw-r--r--usr.bin/vi/vi/v_ex.c352
-rw-r--r--usr.bin/vi/vi/v_increment.c163
-rw-r--r--usr.bin/vi/vi/v_init.c256
-rw-r--r--usr.bin/vi/vi/v_left.c287
-rw-r--r--usr.bin/vi/vi/v_mark.c210
-rw-r--r--usr.bin/vi/vi/v_match.c198
-rw-r--r--usr.bin/vi/vi/v_ntext.c1899
-rw-r--r--usr.bin/vi/vi/v_paragraph.c370
-rw-r--r--usr.bin/vi/vi/v_put.c168
-rw-r--r--usr.bin/vi/vi/v_redraw.c67
-rw-r--r--usr.bin/vi/vi/v_replace.c194
-rw-r--r--usr.bin/vi/vi/v_right.c162
-rw-r--r--usr.bin/vi/vi/v_screen.c90
-rw-r--r--usr.bin/vi/vi/v_scroll.c486
-rw-r--r--usr.bin/vi/vi/v_search.c414
-rw-r--r--usr.bin/vi/vi/v_section.c280
-rw-r--r--usr.bin/vi/vi/v_sentence.c386
-rw-r--r--usr.bin/vi/vi/v_status.c73
-rw-r--r--usr.bin/vi/vi/v_stop.c75
-rw-r--r--usr.bin/vi/vi/v_text.c883
-rw-r--r--usr.bin/vi/vi/v_ulcase.c208
-rw-r--r--usr.bin/vi/vi/v_undo.c162
-rw-r--r--usr.bin/vi/vi/v_util.c159
-rw-r--r--usr.bin/vi/vi/v_word.c570
-rw-r--r--usr.bin/vi/vi/v_xchar.c136
-rw-r--r--usr.bin/vi/vi/v_yank.c94
-rw-r--r--usr.bin/vi/vi/v_z.c159
-rw-r--r--usr.bin/vi/vi/v_zexit.c82
-rw-r--r--usr.bin/vi/vi/vcmd.c533
-rw-r--r--usr.bin/vi/vi/vcmd.h346
-rw-r--r--usr.bin/vi/vi/vi.c937
-rw-r--r--usr.bin/vi/xaw/xaw_screen.c98
182 files changed, 103461 insertions, 0 deletions
diff --git a/usr.bin/vi/Makefile b/usr.bin/vi/Makefile
new file mode 100644
index 000000000000..9777077acf56
--- /dev/null
+++ b/usr.bin/vi/Makefile
@@ -0,0 +1,3 @@
+SUBDIR= common
+
+.include <bsd.subdir.mk>
diff --git a/usr.bin/vi/USD.doc/edit/Makefile b/usr.bin/vi/USD.doc/edit/Makefile
new file mode 100644
index 000000000000..3d30bc919644
--- /dev/null
+++ b/usr.bin/vi/USD.doc/edit/Makefile
@@ -0,0 +1,18 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= usd/11.edit
+SRCS= edittut.ms
+MACROS= -msU
+
+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/USD.doc/edit/edit.vindex b/usr.bin/vi/USD.doc/edit/edit.vindex
new file mode 100644
index 000000000000..2098f14ea190
--- /dev/null
+++ b/usr.bin/vi/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/USD.doc/edit/edittut.ms b/usr.bin/vi/USD.doc/edit/edittut.ms
new file mode 100644
index 000000000000..5f4c28cb6d2a
--- /dev/null
+++ b/usr.bin/vi/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/USD.doc/exref/Makefile b/usr.bin/vi/USD.doc/exref/Makefile
new file mode 100644
index 000000000000..11f4e6650dcc
--- /dev/null
+++ b/usr.bin/vi/USD.doc/exref/Makefile
@@ -0,0 +1,14 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= usd/13.ex
+SRCS= ex.rm
+MACROS= -msU
+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/USD.doc/exref/ex.rm b/usr.bin/vi/USD.doc/exref/ex.rm
new file mode 100644
index 000000000000..79670c2cf66b
--- /dev/null
+++ b/usr.bin/vi/USD.doc/exref/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/USD.doc/exref/ex.summary b/usr.bin/vi/USD.doc/exref/ex.summary
new file mode 100644
index 000000000000..618da07c7420
--- /dev/null
+++ b/usr.bin/vi/USD.doc/exref/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/USD.doc/vi.man/Makefile b/usr.bin/vi/USD.doc/vi.man/Makefile
new file mode 100644
index 000000000000..fd89b8e3169f
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.man/Makefile
@@ -0,0 +1,14 @@
+# @(#)Makefile 8.5 (Berkeley) 7/16/94
+
+SRCS= vi.1
+DOCS= vi.0 vi.0.ps
+
+all: ${DOCS}
+
+vi.0: vi.1
+ groff -man -Tascii < vi.1 > $@
+vi.0.ps: vi.1
+ groff -man < vi.1 > $@
+
+clean:
+ rm -f ${DOCS}
diff --git a/usr.bin/vi/USD.doc/vi.man/vi.0 b/usr.bin/vi/USD.doc/vi.man/vi.0
new file mode 100644
index 000000000000..e6d9972e390b
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.man/vi.0
@@ -0,0 +1,798 @@
+EX/VI(1) BSD Reference Manual EX/VI(1)
+
+NNAAMMEE
+ eexx,, vvii,, vviieeww - text editors
+
+SSYYNNOOPPSSIISS
+ eexx [--eeFFRRrrssvv] [--cc _c_m_d] [--tt _t_a_g] [--ww _s_i_z_e] [_f_i_l_e _._._.]
+ vvii [--eeFFRRrrvv] [--cc _c_m_d] [--tt _t_a_g] [--ww _s_i_z_e] [_f_i_l_e _._._.]
+ vviieeww [--eeFFRRrrvv] [--cc _c_m_d] [--tt _t_a_g] [--ww _s_i_z_e] [_f_i_l_e _._._.]
+
+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 manual page is the one provided with the nneexx//nnvvii versions of the
+ eexx//vvii text editors. NNeexx//nnvvii are intended as bug-for-bug compatible re-
+ placements for the original Fourth Berkeley Software Distribution (4BSD)
+ eexx and vvii programs. For the rest of this manual page, nneexx//nnvvii is used
+ only when it's necessary to distinguish it from the historic implementa-
+ tions of eexx//vvii.
+
+ This manual page is intended for users already familiar with eexx//vvii. Any-
+ one else should almost certainly read a good tutorial on the editor be-
+ fore this manual page. If you're in an unfamiliar environment, and you
+ absolutely have to get work done immediately, read the section after the
+ options description, entitled ``Fast Startup''. It's probably enough to
+ get you going.
+
+ The following options are available:
+
+ --cc Execute _c_m_d immediately after starting the edit session. Partic-
+ ularly useful for initial positioning in the file, however _c_m_d is
+ not limited to positioning commands. This is the POSIX 1003.2
+ interface for the historic ``+cmd'' syntax. NNeexx//nnvvii supports
+ both the old and new syntax.
+
+ --ee Start editing in ex mode, as if the command name were eexx.
+
+ --FF Don't copy the entire file when first starting to edit. (The de-
+ fault is to make a copy in case someone else modifies the file
+ during your edit session.)
+
+ --RR Start editing in read-only mode, as if the command name was vviieeww,
+ or the readonly option was set.
+
+ --rr Recover the specified files, or, if no files are specified, list
+ the files that could be recovered. If no recoverable files by
+ the specified name exist, the file is edited as if the --rr option
+ had not been specified.
+
+ --ss Enter batch mode; applicable only to eexx edit sessions. Batch
+ mode is useful when running eexx scripts. Prompts, informative
+ messages and other user oriented message are turned off, and no
+ startup files or environmental variables are read. This is the
+ POSIX 1003.2 interface for the historic ``-'' argument. NNeexx//nnvvii
+ supports both the old and new syntax.
+
+ --tt Start editing at the specified tag. (See ctags(1)).
+
+ --ww Set the initial window size to the specified number of lines.
+
+
+
+ --vv Start editing in vi mode, as if the command name was vvii or vviieeww.
+
+ --XX Reserved for X11 interfaces. _N_o _X_1_1 _s_u_p_p_o_r_t _i_s _c_u_r_r_e_n_t_l_y
+ _i_m_p_l_e_m_e_n_t_e_d_.
+
+ Command input for eexx//vvii is read from the standard input. In the vvii in-
+ terface, it is an error if standard input is not a terminal. In the eexx
+ interface, if standard input is not a terminal, eexx will read commands
+ from it regardless, however, the session will be a batch mode session,
+ exactly as if the --ss option had been specified.
+
+ EExx//vvii exits 0 on success, and greater than 0 if an error occurs.
+
+FFAASSTT SSTTAARRTTUUPP
+ This section will tell you the minimum amount that you need to do simple
+ editing tasks using vvii. If you've never used any screen editor before,
+ you're likely to have problems even with this simple introduction. In
+ that case you should find someone that already knows vvii and have them
+ walk you through this section.
+
+ VVii is a screen editor. This means that it takes up almost the entire
+ screen, displaying part of the file on each screen line, except for the
+ last line of the screen. The last line of the screen is used for you to
+ give commands to vvii, and for vvii to give information to you.
+
+ The other fact that you need to understand is that vvii is a modeful edi-
+ tor, i.e. you are either entering text or you are executing commands, and
+ you have to be in the right mode to do one or the other. You will be in
+ command mode when you first start editing a file. There are commands
+ that switch you into input mode. There is only one key that takes you
+ out of input mode, and that is the <escape> key. (Key names are written
+ using less-than and greater-than signs, e.g. <escape> means the
+ ``escape'' key, usually labeled ``esc'' on your terminal's keyboard.) If
+ you're ever confused as to which mode you're in, keep entering the <es-
+ cape> key until vvii beeps at you. (Generally, vvii will beep at you if you
+ try and do something that's not allowed. It will also display error mes-
+ sages.)
+
+ To start editing a file, enter the command ``vi file_name<carriage-
+ return>''. The command you should enter as soon as you start editing is
+ ``:set verbose showmode<carriage-return>''. This will make the editor
+ give you verbose error messages and display the current mode at the bot-
+ tom of the screen.
+
+ The commands to move around the file are:
+ hh Move the cursor left one character.
+ jj Move the cursor down one line.
+ kk Move the cursor up one line.
+ ll Move the cursor right one character.
+ <<ccuurrssoorr--aarrrroowwss>>
+ The cursor arrow keys should work, too.
+ //tteexxtt<<ccaarrrriiaaggee--rreettuurrnn>>
+ Search for the string ``text'' in the file, and move the cursor to
+ its first character.
+
+ The commands to enter new text are:
+ aa Append new text, _a_f_t_e_r the cursor.
+ ii Insert new text, _b_e_f_o_r_e the cursor.
+ oo Open a new line below the line the cursor is on, and start entering
+ text.
+ OO Open a new line above the line the cursor is on, and start entering
+ text.
+ <<eessccaappee>>
+ Once you've entered input mode using the one of the aa, ii, OO, or oo
+ commands, use <<eessccaappee>> to quit entering text and return to command
+ mode.
+
+ The commands to copy text are:
+ yyyy Copy the line the cursor is on.
+ pp Append the copied line after the line the cursor is on.
+
+ The commands to delete text are:
+ dddd Delete the line the cursor is on.
+ xx Delete the character the cursor is on.
+
+ The commands to write the file are:
+ ::ww<<ccaarrrriiaaggee--rreettuurrnn>>
+ Write the file back to the file with the name that you originally
+ used as an argument on the vvii command line.
+ ::ww ffiillee__nnaammee<<ccaarrrriiaaggee--rreettuurrnn>>
+ Write the file back to the file with the name ``file_name''.
+
+ The commands to quit editing and exit the editor are:
+ ::qq<<ccaarrrriiaaggee--rreettuurrnn>>
+ Quit editing and leave vi (if you've modified the file, but not
+ saved your changes, vvii will refuse to quit).
+ ::qq!!<<ccaarrrriiaaggee--rreettuurrnn>>
+ Quit, discarding any modifications that you may have made.
+
+ One final caution. Unusual characters can take up more than one column
+ on the screen, and long lines can take up more than a single screen line.
+ The above commands work on ``physical'' characters and lines, i.e. they
+ affect the entire line no matter how many screen lines it takes up and
+ the entire character no matter how many screen columns it takes up.
+
+VVII CCOOMMMMAANNDDSS
+ The following section describes the commands available in the command
+ mode of the vvii editor. In each entry below, the tag line is a usage syn-
+ opsis for the command character.
+
+ [[ccoouunntt]] <<ccoonnttrrooll--AA>>
+ Search forward count times for the current word.
+ [[ccoouunntt]] <<ccoonnttrrooll--BB>>
+ Page backwards count screens.
+ [[ccoouunntt]] <<ccoonnttrrooll--DD>>
+ Scroll forward count lines.
+ [[ccoouunntt]] <<ccoonnttrrooll--EE>>
+ Scroll forward count lines, leaving the current line and column as
+ is, if possible.
+ [[ccoouunntt]] <<ccoonnttrrooll--FF>>
+ Page forward count screens.
+ <<ccoonnttrrooll--GG>>
+ Display the file information.
+ <<ccoonnttrrooll--HH>>
+ [[ccoouunntt]] hh
+ Move the cursor back count characters in the current line.
+ [[ccoouunntt]] <<ccoonnttrrooll--JJ>>
+ [[ccoouunntt]] <<ccoonnttrrooll--NN>>
+ [[ccoouunntt]] jj
+ Move the cursor down count lines without changing the current col-
+ umn.
+ <<ccoonnttrrooll--LL>>
+ <<ccoonnttrrooll--RR>>
+ Repaint the screen.
+ [[ccoouunntt]] <<ccoonnttrrooll--MM>>
+ [[ccoouunntt]] ++
+ Move the cursor down count lines to the first nonblank character of
+ that line.
+ [[ccoouunntt]] <<ccoonnttrrooll--PP>>
+ [[ccoouunntt]] kk
+ Move the cursor up count lines, without changing the current col-
+
+ umn.
+ <<ccoonnttrrooll--TT>>
+ Return to the most recent tag context.
+ <<ccoonnttrrooll--UU>>
+ Scroll backwards count lines.
+ <<ccoonnttrrooll--WW>>
+ Switch to the next lower screen in the window, or, to the first
+ screen if there are no lower screens in the window.
+ <<ccoonnttrrooll--YY>>
+ Scroll backwards count lines, leaving the current line and column
+ as is, if possible.
+ <<ccoonnttrrooll--ZZ>>
+ Suspend the current editor session.
+ <<eessccaappee>>
+ Execute eexx commands or cancel partial commands.
+ <<ccoonnttrrooll--]]>>
+ Push a tag reference onto the tag stack.
+ <<ccoonnttrrooll--^^>>
+ Switch to the most recently edited file.
+ [[ccoouunntt]] <<ssppaaccee>>
+ [[ccoouunntt]] ll
+ Move the cursor forward count characters without changing the cur-
+ rent line.
+ [[ccoouunntt]] !! mmoottiioonn sshheellll--aarrgguummeenntt((ss))
+ Replace text with results from a shell command.
+ [[ccoouunntt]] ## ++||--||##
+ Increment or decrement the cursor number.
+ [[ccoouunntt]] $$
+ Move the cursor to the end of a line.
+ %% Move to the matching character.
+ && Repeat the previous substitution command on the current line.
+ ''<<cchhaarraacctteerr>>
+ ``<<cchhaarraacctteerr>>
+ Return to a context marked by the character <character>.
+ [[ccoouunntt]] ((
+ Back up count sentences.
+ [[ccoouunntt]] ))
+ Move forward count sentences.
+ [[ccoouunntt]] ,,
+ Reverse find character count times.
+ [[ccoouunntt]] --
+ Move to first nonblank of the previous line, count times.
+ [[ccoouunntt]] ..
+ Repeat the last vvii command that modified text.
+ //RREE<<ccaarrrriiaaggee--rreettuurrnn>>
+ //RREE// [[ooffffsseett]]<<ccaarrrriiaaggee--rreettuurrnn>>
+ ??RREE<<ccaarrrriiaaggee--rreettuurrnn>>
+ ??RREE?? [[ooffffsseett]]<<ccaarrrriiaaggee--rreettuurrnn>>
+ NN
+ nn Search forward or backward for a regular expression.
+ 00 Move to the first character in the current line.
+ : Execute an ex command.
+ [[ccoouunntt]] ;;
+ Repeat the last character find count times.
+ [[ccoouunntt]] << mmoottiioonn
+ [[ccoouunntt]] >> mmoottiioonn
+ Shift lines left or right.
+ @@ bbuuffffeerr
+ Execute a named buffer.
+ [[ccoouunntt]] AA
+ Enter input mode, appending the text after the end of the line.
+ [[ccoouunntt]] BB
+ Move backwards count bigwords.
+ [[bbuuffffeerr]] [[ccoouunntt]] CC
+
+
+ Change text from the current position to the end-of-line.
+ [[bbuuffffeerr]] DD
+ Delete text from the current position to the end-of-line.
+ [[ccoouunntt]] EE
+ Move forward count end-of-bigwords.
+ [[ccoouunntt]] FF <<cchhaarraacctteerr>>
+ Search count times backward through the current line for
+ <character>.
+ [[ccoouunntt]] GG
+ Move to line count, or the last line of the file if count not spec-
+ ified.
+ [[ccoouunntt]] HH
+ Move to the screen line count - 1 lines below the top of the
+ screen.
+ [[ccoouunntt]] II
+ Enter input mode, inserting the text at the beginning of the line.
+ [[ccoouunntt]] JJ
+ Join lines.
+ [[ccoouunntt]] LL
+ Move to the screen line count - 1 lines above the bottom of the
+ screen.
+ MM Move to the screen line in the middle of the screen.
+ [[ccoouunntt]] OO
+ Enter input mode, appending text in a new line above the current
+ line.
+ [[bbuuffffeerr]] PP
+ Insert text from a buffer.
+ QQ Exit vvii (or visual) mode and switch to eexx mode.
+ [[ccoouunntt]] RR
+ Enter input mode, replacing the characters in the current line.
+ [[bbuuffffeerr]] [[ccoouunntt]] SS
+ Substitute count lines.
+ [[ccoouunntt]] TT <<cchhaarraacctteerr>>
+ Search backwards, count times, through the current line for the
+ character _a_f_t_e_r the specified <character>.
+ UU Restore the current line to its state before the cursor last moved
+ to it.
+ [[ccoouunntt]] WW
+ Move forward count bigwords.
+ [[bbuuffffeerr]] [[ccoouunntt]] XX
+ Delete count characters before the cursor.
+ [[bbuuffffeerr]] [[ccoouunntt]] YY
+ Copy (or ``yank'') count lines into the specified buffer.
+ ZZZZ Write the file and exit vvii.
+ [[ccoouunntt]] [[[[
+ Back up count section boundaries.
+ [[ccoouunntt]] ]]]]
+ Move forward count section boundaries.
+ ^^ Move to first nonblank character on the current line.
+ [[ccoouunntt]] __
+ Move down count - 1 lines, to the first nonblank character.
+ [[ccoouunntt]] aa
+ Enter input mode, appending the text after the cursor.
+ [[ccoouunntt]] bb
+ Move backwards count words.
+ [[bbuuffffeerr]] [[ccoouunntt]] cc mmoottiioonn
+ Change a region of text.
+ [[bbuuffffeerr]] [[ccoouunntt]] dd mmoottiioonn
+ Delete a region of text.
+ [[ccoouunntt]] ee
+ Move forward count end-of-words.
+ [[ccoouunntt]] ff<<cchhaarraacctteerr>>
+ Search forward, count times, through the rest of the current line
+ for <character>.
+ [[ccoouunntt]] ii
+
+ Enter input mode, inserting the text before the cursor.
+ mm <<cchhaarraacctteerr>>
+ Save the current context (line and column) as <character>.
+ [[ccoouunntt]] oo
+ Enter input mode, appending text in a new line under the current
+ line.
+ [[bbuuffffeerr]] pp
+ Append text from a buffer.
+ [[ccoouunntt]] rr <<cchhaarraacctteerr>>
+ Replace count characters.
+ [[bbuuffffeerr]] [[ccoouunntt]] ss
+ Substitute count characters in the current line starting with the
+ current character.
+ [[ccoouunntt]] tt <<cchhaarraacctteerr>>
+ Search forward, count times, through the current line for the char-
+ acter immediately _b_e_f_o_r_e <character>.
+ uu Undo the last change made to the file.
+ [[ccoouunntt]] ww
+ Move forward count words.
+ [[bbuuffffeerr]] [[ccoouunntt]] xx
+ Delete count characters.
+ [[bbuuffffeerr]] [[ccoouunntt]] yy mmoottiioonn
+ Copy (or ``yank'') a text region specified by the count and motion
+ into a buffer.
+ [[ccoouunntt11]] zz [[ccoouunntt22]] --||..||++||^^||<<ccaarrrriiaaggee--rreettuurrnn>>
+ Redraw, optionally repositioning and resizing the screen.
+ [[ccoouunntt]] {{
+ Move backward count paragraphs.
+ [[ccoouunntt]] ||
+ Move to a specific _c_o_l_u_m_n position on the current line.
+ [[ccoouunntt]] }}
+ Move forward count paragraphs.
+ [[ccoouunntt]] ~~
+ Reverse the case of the next count character(s).
+ [[ccoouunntt]] ~~ mmoottiioonn
+ Reverse the case of the characters in a text region specified by
+ the count and motion.
+ <<iinntteerrrruupptt>>
+ Interrupt the current operation.
+
+VVII TTEEXXTT IINNPPUUTT CCOOMMMMAANNDDSS
+ The following section describes the commands available in the text input
+ mode of the vvii editor.
+
+ <<nnuull>>
+ Replay the previous input.
+ <<ccoonnttrrooll--DD>>
+ Erase the previous autoindent character.
+ ^^<<ccoonnttrrooll--DD>>
+ Erase all of the autoindent characters, and reset the autoindent
+ level.
+ 00<<ccoonnttrrooll--DD>>
+ Erase all of the autoindent characters.
+ <<ccoonnttrrooll--TT>>
+ Insert sufficient <tab> and <space> characters to move the cursor
+ forward to a column immediately after the next column which is an
+ even multiple of the sshhiiffttwwiiddtthh option.
+ <<eerraassee>>
+ <<ccoonnttrrooll--HH>>
+ Erase the last character.
+ <<lliitteerraall nneexxtt>>
+ Quote the next character.
+ <<eessccaappee>>
+ Resolve all text input into the file, and return to command mode.
+ <<lliinnee eerraassee>>
+
+ Erase the current line.
+ <<ccoonnttrrooll--WW>>
+ <<wwoorrdd eerraassee>>
+ Erase the last word. The definition of word is dependent on the
+ aallttwweerraassee and ttttyywweerraassee options.
+ <<ccoonnttrrooll--XX>>[[00--99AA--FFaa--ff]]**
+ Insert a character with the specified hexadecimal value into the
+ text.
+ <<iinntteerrrruupptt>>
+ Interrupt text input mode, returning to command mode.
+
+EEXX CCOOMMMMAANNDDSS
+ The following section describes the commands available in the eexx editor.
+ In each entry below, the tag line is a usage synopsis for the command.
+
+ <<eenndd--ooff--ffiillee>>
+ Scroll the screen.
+ !! aarrgguummeenntt((ss))
+ [[rraannggee]]!! aarrgguummeenntt((ss))
+ Execute a shell command, or filter lines through a shell command.
+ "" A comment.
+ [[rraannggee]] nnuu[[mmbbeerr]] [[ccoouunntt]] [[ffllaaggss]]
+ [[rraannggee]] ## [[ccoouunntt]] [[ffllaaggss]]
+ Display the selected lines, each preceded with its line number.
+ @@ bbuuffffeerr
+ ** bbuuffffeerr
+ Execute a buffer.
+ [[rraannggee]] dd[[eelleettee]] [[bbuuffffeerr]] [[ccoouunntt]] [[ffllaaggss]]
+ Delete the lines from the file.
+ ddii[[ssppllaayy]] bb[[uuffffeerrss]] || ss[[ccrreeeennss]] || tt[[aaggss]]
+ Display buffers, screens or tags.
+ ee[[ddiitt]][[!!]] [[++ccmmdd]] [[ffiillee]]
+ eexx[[!!]] [[++ccmmdd]] [[ffiillee]]
+ Edit a different file.
+ eexxuu[[ssaaggee]] [[ccoommmmaanndd]]
+ Display usage for an eexx command.
+ ff[[iillee]] [[ffiillee]]
+ Display and optionally change the file name.
+ ffgg [[nnaammee]]
+ VVii mode only. Foreground the specified screen.
+ [[rraannggee]] gg[[lloobbaall]] //ppaatttteerrnn// [[ccoommmmaannddss]]
+ [[rraannggee]] vv //ppaatttteerrnn// [[ccoommmmaannddss]]
+ Apply commands to lines matching (or not matching) a pattern.
+ hhee[[llpp]]
+ Display a help message.
+ [[lliinnee]] ii[[nnsseerrtt]][[!!]]
+ The input text is inserted before the specified line.
+ [[rraannggee]] jj[[ooiinn]][[!!]] [[ccoouunntt]] [[ffllaaggss]]
+ Join lines of text together.
+ [[rraannggee]] ll[[iisstt]] [[ccoouunntt]] [[ffllaaggss]]
+ Display the lines unambiguously.
+ mmaapp[[!!]] [[llhhss rrhhss]]
+ Define or display maps (for vvii only).
+ [[lliinnee]] mmaa[[rrkk]] <<cchhaarraacctteerr>>
+ [[lliinnee]] kk <<cchhaarraacctteerr>>
+ Mark the line with the mark <character>.
+ [[rraannggee]] mm[[oovvee]] lliinnee
+ Move the specified lines after the target line.
+ mmkk[[eexxrrcc]][[!!]] ffiillee
+ Write the abbreviations, editor options and maps to the specified
+ file.
+ nn[[eexxtt]][[!!]] [[ffiillee ......]]
+ Edit the next file from the argument list.
+ [[lliinnee]] oo[[ppeenn]] //ppaatttteerrnn// [[ffllaaggss]]
+
+
+ Enter open mode.
+ pprree[[sseerrvvee]]
+ Save the file in a form that can later be recovered using the eexx --rr
+ option.
+ pprreevv[[iioouuss]][[!!]]
+ Edit the previous file from the argument list.
+ [[rraannggee]] pp[[rriinntt]] [[ccoouunntt]] [[ffllaaggss]]
+ Display the specified lines.
+ [[lliinnee]] ppuu[[tt]] [[bbuuffffeerr]]
+ Append buffer contents to the current line.
+ qq[[uuiitt]][[!!]]
+ End the editing session.
+ [[lliinnee]] rr[[eeaadd]][[!!]] [[ffiillee]]
+ Read a file.
+ rreecc[[oovveerr]] ffiillee
+ Recover file if it was previously saved.
+ rreess[[iizzee]] [[++||--]]ssiizzee
+ VVii mode only. Grow or shrink the current screen.
+ rreeww[[iinndd]][[!!]]
+ Rewind the argument list.
+ ssee[[tt]] [[ooppttiioonn[[==[[vvaalluuee]]]] ......]] [[nnooooppttiioonn ......]] [[ooppttiioonn?? ......]] [[aallll]]
+ Display or set editor options.
+ sshh[[eellll]]
+ Run a shell program.
+ ssoo[[uurrccee]] ffiillee
+ Read and execute eexx commands from a file.
+ sspp[[lliitt]] [[ffiillee ......]]
+ VVii mode only. Split the screen.
+ [[rraannggee]] ss[[uubbssttiittuuttee]] [[//ppaatttteerrnn//rreeppllaaccee//]] [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]]
+ [[rraannggee]] && [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]]
+ [[rraannggee]] ~~ [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]]
+ Make substitutions.
+ ssuu[[ssppeenndd]][[!!]]
+ sstt[[oopp]][[!!]]
+ <<ssuussppeenndd>>
+ Suspend the edit session.
+ ttaa[[gg]][[!!]] ttaaggssttrriinngg
+ Edit the file containing the specified tag.
+ ttaaggpp[[oopp]][[!!]] [[ffiillee || nnuummbbeerr]]
+ Pop to the specified tag in the tags stack.
+ uunnmm[[aapp]][[!!]] llhhss
+ Unmap a mapped string.
+ vvee[[rrssiioonn]]
+ Display the version of the eexx//vvii editor.
+ [[lliinnee]] vvii[[ssuuaall]] [[ttyyppee]] [[ccoouunntt]] [[ffllaaggss]]
+ EExx mode only. Enter vvii.
+ vvii[[ssuuaall]][[!!]] [[++ccmmdd]] [[ffiillee]]
+ VVii mode only. Edit a new file.
+ vviiuu[[ssaaggee]] [[ccoommmmaanndd]]
+ Display usage for a vvii command.
+ [[rraannggee]] ww[[rriittee]][[!!]] [[>>>>]] [[ffiillee]]
+ [[rraannggee]] ww[[rriittee]] [[!!]] [[ffiillee]]
+ [[rraannggee]] wwnn[[!!]] [[>>>>]] [[ffiillee]]
+ [[rraannggee]] wwqq[[!!]] [[>>>>]] [[ffiillee]]
+ Write the file.
+ [[rraannggee]] xx[[iitt]][[!!]] [[ffiillee]]
+ Write the file if it has been modified.
+ [[rraannggee]] yyaa[[nnkk]] [[bbuuffffeerr]] [[ccoouunntt]]
+ Copy the specified lines to a buffer.
+ [[lliinnee]] zz [[ttyyppee]] [[ccoouunntt]] [[ffllaaggss]]
+ Adjust the window.
+
+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. 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.
+
+ Options apply to both eexx and vvii modes, unless otherwise specified.
+
+ aallttwweerraassee [[ooffff]]
+ VVii only. Select an alternate word erase algorithm.
+ aauuttooiinnddeenntt,, aaii [[ooffff]]
+ Automatically indent new lines.
+ aauuttoopprriinntt,, aapp [[ooffff]]
+ EExx only. Display the current line automatically.
+ aauuttoowwrriittee,, aaww [[ooffff]]
+ Write modified files automatically when changing files.
+ bbeeaauuttiiffyy,, bbff [[ooffff]]
+ Discard control characters.
+ ccddppaatthh [[eennvviirroonnmmeenntt vvaarriiaabbllee CCDDPPAATTHH,, oorr ccuurrrreenntt ddiirreeccttoorryy]]
+ The directory paths used as path prefixes for the ccdd command.
+ ccoolluummnnss,, ccoo [[8800]]
+ Set the number of columns in the screen.
+ ccoommmmeenntt [[ooffff]]
+ VVii only. Skip leading comments in files.
+ ddiirreeccttoorryy,, ddiirr [[eennvviirroonnmmeenntt vvaarriiaabbllee TTMMPPDDIIRR,, oorr //ttmmpp]]
+ The directory where temporary files are created.
+ eeddccoommppaattiibbllee,, eedd [[ooffff]]
+ Remember the values of the ``c'' and ``g'' suffices to the
+ ssuubbssttiittuuttee commands, instead of initializing them as unset for each
+ new command.
+ eerrrroorrbbeellllss,, eebb [[ooffff]]
+ EExx only. Announce error messages with a bell.
+ eexxrrcc,, eexx [[ooffff]]
+ Never read startup files in the local directory.
+ eexxtteennddeedd [[ooffff]]
+ Regular expressions are extended (i.e. egrep(1) style) expres-
+ sions.
+ ffllaasshh [[oonn]]
+ Flash the screen instead of beeping the keyboard on error.
+ hhaarrddttaabbss,, hhtt [[88]]
+ Set the spacing between hardware tab settings.
+ iiggnnoorreeccaassee,, iicc [[ooffff]]
+ Ignore case differences in regular expressions.
+ kkeeyyttiimmee [[66]]
+ The 10th's of a second eexx//vvii waits for a subsequent key to complete
+ a key mapping.
+ lleeffttrriigghhtt [[ooffff]]
+ VVii only. Do left-right scrolling.
+ lliinneess,, llii [[2244]]
+ VVii only. Set the number of lines in the screen.
+ lliisspp [[ooffff]]
+ VVii only. Modify various search commands and options to work with
+ 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_.
+ lliisstt [[ooffff]]
+ Display lines in an unambiguous fashion.
+ mmaaggiicc [[oonn]]
+ Treat certain characters specially in regular expressions.
+ mmaattcchhttiimmee [[77]]
+ VVii only. The 10th's of a second eexx//vvii pauses on the matching char-
+ acter when the sshhoowwmmaattcchh option is set.
+ mmeessgg [[oonn]]
+
+
+ Permit messages from other users.
+ mmooddeelliinneess,, mmooddeelliinnee [[ooffff]]
+ Read the first and last few lines of each file for eexx commands.
+
+ _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_.
+ nnuummbbeerr,, nnuu [[ooffff]]
+ Precede each line displayed with its current line number.
+ ooccttaall [[ooffff]]
+ Display unknown characters as octal numbers, instead of the default
+ hexadecimal.
+ ooppeenn [[oonn]]
+ EExx only. If this option is not set, the ooppeenn and vviissuuaall commands
+ are disallowed.
+ ooppttiimmiizzee,, oopptt [[oonn]]
+ VVii only. Optimize text throughput to dumb terminals.
+
+ _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_.
+ ppaarraaggrraapphhss,, ppaarraa [[IIPPLLPPPPPPQQPPPP LLIIppppllppiippbbpp]]
+ VVii only. Define additional paragraph boundaries for the {{ and }}
+ commands.
+ pprroommpptt [[oonn]]
+ EExx only. Display a command prompt.
+ rreeaaddoonnllyy,, rroo [[ooffff]]
+ Mark the file as read-only.
+ rreeccddiirr [[//vvaarr//ttmmpp//vvii..rreeccoovveerr]]
+ The directory where recovery files are stored.
+ rreeddrraaww,, rree [[ooffff]]
+ VVii only. Simulate an intelligent terminal on a dumb one.
+
+ _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_.
+ rreemmaapp [[oonn]]
+ Remap keys until resolved.
+ rreeppoorrtt [[55]]
+ Set the number of lines about which the editor reports changes or
+ yanks.
+ rruulleerr [[ooffff]]
+ VVii only. Display a row/column ruler on the colon command line.
+ ssccrroollll,, ssccrr [[wwiinnddooww // 22]]
+ Set the number of lines scrolled.
+ sseeccttiioonnss,, sseecctt [[NNHHSSHHHH HHUUnnhhsshh]]
+ VVii only. Define additional section boundaries for the [[[[ and ]]]]
+ commands.
+ sshheellll,, sshh [[eennvviirroonnmmeenntt vvaarriiaabbllee SSHHEELLLL,, oorr //bbiinn//sshh]]
+ Select the shell used by the editor.
+ sshhiiffttwwiiddtthh,, ssww [[88]]
+ Set the autoindent and shift command indentation width.
+ sshhoowwddiirrttyy [[ooffff]]
+ VVii only. Display an asterisk on the colon command line if the file
+ has been modified.
+ sshhoowwmmaattcchh,, ssmm [[ooffff]]
+ VVii only. Note matching ``{'' and ``('' for ``}'' and ``)'' charac-
+ ters.
+ sshhoowwmmooddee [[ooffff]]
+ VVii only. Display the current editor mode (command or input).
+ ssiiddeessccrroollll [[1166]]
+ VVii only. Set the amount a left-right scroll will shift.
+ sslloowwooppeenn,, ssllooww [[ooffff]]
+ Delay display updating during text input.
+
+ _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_.
+ ssoouurrcceeaannyy [[ooffff]]
+ Read startup files not owned by the current user.
+
+ _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_.
+ ttaabbssttoopp,, ttss [[88]]
+
+ This option sets tab widths for the editor display.
+ ttaagglleennggtthh,, ttll [[00]]
+ Set the number of significant characters in tag names.
+ ttaaggss,, ttaagg [[ttaaggss //vvaarr//ddbb//lliibbcc..ttaaggss //ssyyss//kkeerrnn//ttaaggss]]
+ Set the list of tags files.
+ tteerrmm,, ttttyyttyyppee,, ttttyy [[eennvviirroonnmmeenntt vvaarriiaabbllee TTEERRMM]]
+ Set the terminal type.
+ tteerrssee [[ooffff]]
+ This option has historically made editor messages less verbose. It
+ has no effect in this implementation.
+ ttiillddeeoopp
+ Modify the ~~ command to take an associated motion.
+ ttiimmeeoouutt,, ttoo [[oonn]]
+ Time out on keys which may be mapped.
+ ttttyywweerraassee [[ooffff]]
+ VVii only. Select an alternate erase algorithm.
+ vveerrbboossee [[ooffff]]
+ only. Display an error message for every error.
+ ww330000 [[nnoo ddeeffaauulltt]]
+ VVii only. Set the window size if the baud rate is less than 1200
+ baud.
+ ww11220000 [[nnoo ddeeffaauulltt]]
+ VVii only. Set the window size if the baud rate is equal to 1200
+ baud.
+ ww99660000 [[nnoo ddeeffaauulltt]]
+ VVii only. Set the window size if the baud rate is greater than 1200
+ baud.
+ wwaarrnn [[oonn]]
+ 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.
+ wwiinnddooww,, ww,, wwii [[eennvviirroonnmmeenntt vvaarriiaabbllee LLIINNEESS]]
+ Set the window size for the screen.
+ wwrraappmmaarrggiinn,, wwmm [[00]]
+ VVii only. Break lines automatically when they reach the right-hand
+ margin.
+ wwrraappssccaann,, wwss [[oonn]]
+ Set searches to wrap around the end or beginning of the file.
+ wwrriitteeaannyy,, wwaa [[ooffff]]
+ Turn off file-overwriting checks.
+
+EENNVVIIRROONNMMEENNTTAALL VVAARRIIAABBLLEESS
+ COLUMNS The number of columns on the screen. This value overrides any
+ system or terminal specific values. If the COLUMNS environ-
+ mental variable is not set when eexx//vvii runs, or the ccoolluummnnss op-
+ tion is explicitly reset by the user, eexx//vvii enters the value
+ into the environment.
+ EXINIT A list of eexx startup commands, read if the variable NEXINIT is
+ not set.
+ HOME The user's home directory, used as the initial directory path
+ for the startup _$_H_O_M_E_/_._n_e_x_r_c and _$_H_O_M_E_/_._e_x_r_c files. This val-
+ ue is also used as the default directory for the vvii ccdd com-
+ mand.
+ LINES The number of rows on the screen. This value overrides any
+ system or terminal specific values. If the LINES environmen-
+ tal variable is not set when eexx//vvii runs, or the lliinneess option
+ is explicitly reset by the user, eexx//vvii enters the value into
+ the environment.
+ NEXINIT A list of eexx startup commands.
+ SHELL The user's shell of choice (see also the sshheellll option).
+ TERM The user's terminal type. The default is the type
+ ``unknown''. If the TERM environmental variable is not set
+ when eexx//vvii runs, or the tteerrmm option is explicitly reset by the
+ user, eexx//vvii enters the value into the environment.
+ TMPDIR The location used to stored temporary files (see also the
+ ddiirreeccttoorryy option).
+
+AASSYYNNCCHHRROONNOOUUSS EEVVEENNTTSS
+ SIGALRM VVii//eexx uses this signal for periodic backups of file modifica-
+ tions and to display ``busy'' messages when operations are
+ likely to take a long time.
+ SIGHUP
+ SIGTERM If the current buffer has changed since it was last written
+ in its entirety, the editor attempts to save the modified
+ file so it can be later recovered. See the vvii//eexx Reference
+ manual section entitled ``Recovery'' for more information.
+ SIGINT When an interrupt occurs, the current operation is halted,
+ and the editor returns to the command level. If interrupted
+ during text input, the text already input is resolved into
+ the file as if the text input had been normally terminated.
+ SIGWINCH The screen is resized. See the vvii//eexx Reference manual sec-
+ tion entitled ``Sizing the Screen'' for more information.
+ SIGCONT
+ SIGQUIT
+ SIGTSTP VVii//eexx ignores these signals.
+
+BBUUGGSS
+ See the file _n_v_i_/_d_o_c_s_/_b_u_g_s_._c_u_r_r_e_n_t for a list of the known bugs in this
+ version.
+
+FFIILLEESS
+ /bin/sh The default user shell.
+ /etc/vi.exrc System-wide vi startup file.
+ /tmp Temporary file directory.
+ /var/tmp/vi.recover The default recovery file directory.
+ $HOME/.nexrc 1st choice for user's home directory startup file.
+ $HOME/.exrc 2nd choice for user's home directory startup file.
+ .nexrc 1st choice for local directory startup file.
+ .exrc 2nd choice for local directory startup file.
+
+SSEEEE AALLSSOO
+ ctags(1), more(1), curses(3), dbopen(3)
+
+ The ``Vi Quick Reference'' card.
+
+ ``An Introduction to Display Editing with Vi'', found in the ``UNIX
+ User's Manual Supplementary Documents'' section of both the 4.3BSD and
+ 4.4BSD manual sets. This document is the closest thing available to an
+ introduction to the vvii screen editor.
+
+ ``Ex Reference Manual (Version 3.7)'', found in the ``UNIX User's Manual
+ Supplementary Documents'' section of both the 4.3BSD and 4.4BSD manual
+ sets. This document is the final reference for the eexx editor, as dis-
+ tributed in most historic 4BSD and System V systems.
+
+ ``Edit: A tutorial'', found in the ``UNIX User's Manual Supplementary
+ Documents'' section of the 4.3BSD manual set. This document is an intro-
+ duction to a simple version of the eexx screen editor.
+
+ ``Ex/Vi Reference Manual'', found in the ``UNIX User's Manual
+ Supplementary Documents'' section of the 4.4BSD manual set. This docu-
+ ment is the final reference for the nneexx//nnvvii text editors, as distributed
+ in 4.4BSD and 4.4BSD-Lite.
+
+ RRooffff source for all of these documents is distributed with nneexx//nnvvii in the
+ _n_v_i_/_U_S_D_._d_o_c directory of the nneexx//nnvvii source code.
+
+ The files ``autowrite'', ``input'', ``quoting'', and ``structures'',
+ found in the _n_v_i_/_d_o_c_s_/_i_n_t_e_r_n_a_l_s directory of the nneexx//nnvvii source code.
+
+HHIISSTTOORRYY
+ The nneexx//nnvvii replacements for the eexx//vvii editor first appeared in 4.4BSD.
+
+SSTTAANNDDAARRDDSS
+ NNeexx//nnvvii is close to IEEE Std1003.2 (``POSIX''). That document differs
+ from historical eexx//vvii practice in several places; there are changes to be
+ made on both sides.
+
+4.4BSD July 15, 1994 13
diff --git a/usr.bin/vi/USD.doc/vi.man/vi.0.ps b/usr.bin/vi/USD.doc/vi.man/vi.0.ps
new file mode 100644
index 000000000000..f6cfc03ea937
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.man/vi.0.ps
@@ -0,0 +1,1063 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Courier-Bold
+%%+ font Courier-Oblique
+%%+ font Courier
+%%+ font Times-Italic
+%%+ font Symbol
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 14
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Courier-Bold
+%%IncludeResource: font Courier-Oblique
+%%IncludeResource: font Courier
+%%IncludeResource: font Times-Italic
+%%IncludeResource: font Symbol
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Courier@0 ENC0/Courier RE/Courier-Oblique@0 ENC0/Courier-Oblique RE
+/Courier-Bold@0 ENC0/Courier-Bold RE/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Bold@0 SF -.2(NA)72
+108 S(ME).2 E/F2 10/Courier-Bold@0 SF(ex, vi, view)102 120 Q F0 2.5<ad74>2.5 G
+-.15(ex)187.42 120 S 2.5(te).15 G(ditors)206.43 120 Q F1(SYNOPSIS)72 144 Q F2
+(ex)102 156 Q F0([)3.333 E F2(\255eFRrsv)2.499 E F0 3.333(][).833 G F2<ad63>
+-.834 E/F3 10/Courier-Oblique@0 SF(cmd)6 E F0 3.333(][).833 G F2<ad74>-.834 E
+F3(tag)6 E F0 3.333(][).833 G F2<ad77>-.834 E F3(size)6 E F0 3.333(][).833 G F3
+(file ...)330.796 156 Q F0(]).833 E F2(vi)102 168 Q F0([)3.333 E F2(\255eFRrv)
+2.499 E F0 3.333(][).833 G F2<ad63>-.834 E F3(cmd)6 E F0 3.333(][).833 G F2
+<ad74>-.834 E F3(tag)6 E F0 3.333(][).833 G F2<ad77>-.834 E F3(size)6 E F0
+3.333(][).833 G F3(file ...)324.796 168 Q F0(]).833 E F2(view)102 180 Q F0([)
+3.333 E F2(\255eFRrv)2.499 E F0 3.333(][).833 G F2<ad63>-.834 E F3(cmd)6 E F0
+3.333(][).833 G F2<ad74>-.834 E F3(tag)6 E F0 3.333(][).833 G F2<ad77>-.834 E
+F3(size)6 E F0 3.333(][).833 G F3(file ...)336.796 180 Q F0(]).833 E F1
+(DESCRIPTION)72 204 Q F2(Vi)102 216 Q F0 .176(is a screen oriented te)2.676 F
+.176(xt editor)-.15 F(.)-.55 E F2(Ex)5.176 E F0 .176(is a line-oriented te)
+2.676 F .175(xt editor)-.15 F(.)-.55 E F2(Ex)5.175 E F0(and)2.675 E F2(vi)2.675
+E F0 .175(are dif)2.675 F .175(ferent interf)-.25 F .175(aces to the)-.1 F .56
+(same program, and it is possible to switch back and forth during an edit sess\
+ion.)102 228 R F2(View)5.561 E F0 .561(is the equi)3.061 F -.25(va)-.25 G .561
+(lent of).25 F(using the)102 240 Q F2<ad52>4.166 E F0(\(read-only\) option of)
+2.5 E F2(vi)2.5 E F0(.)A .216(This manual page is the one pro)102 258 R .215
+(vided with the)-.15 F F2(nex/nvi)2.715 E F0 -.15(ve)2.715 G .215
+(rsions of the).15 F F2(ex/vi)2.715 E F0(te)2.715 E .215(xt editors.)-.15 F F2
+(Nex/nvi)5.215 E F0(are)2.715 E 1.937(intended as b)102 270 R(ug-for)-.2 E(-b)
+-.2 E 1.937(ug compatible replacements for the original F)-.2 F 1.938
+(ourth Berk)-.15 F(ele)-.1 E 4.438(yS)-.15 G(oftw)456.982 270 Q 1.938
+(are Distrib)-.1 F(ution)-.2 E(\(4BSD\))102 282 Q F2(ex)3.008 E F0(and)3.008 E
+F2(vi)3.008 E F0 3.008(programs. F)3.008 F .508
+(or the rest of this manual page,)-.15 F F2(nex/nvi)3.008 E F0 .507
+(is used only when it')3.008 F 3.007(sn)-.55 G(ecessary)506.13 282 Q
+(to distinguish it from the historic implementations of)102 294 Q F2(ex/vi)2.5
+E F0(.)A .961(This manual page is intended for users already f)102 312 R .961
+(amiliar with)-.1 F F2(ex/vi)3.461 E F0 3.462(.A)C -.15(ny)397.982 312 S .962
+(one else should almost certainly).15 F .582
+(read a good tutorial on the editor before this manual page.)102 324 R .582
+(If you')5.582 F .581(re in an unf)-.5 F .581(amiliar en)-.1 F .581
+(vironment, and you)-.4 F .799(absolutely ha)102 336 R 1.099 -.15(ve t)-.2 H
+3.299(og).15 G .799(et w)184.317 336 R .799(ork done immediately)-.1 F 3.299
+(,r)-.65 G .8(ead the section after the options description, entitled `)299.803
+336 R(`F)-.74 E(ast)-.15 E(Startup')102 348 Q('. It')-.74 E 2.5(sp)-.55 G
+(robably enough to get you going.)162.09 348 Q(The follo)102 366 Q
+(wing options are a)-.25 E -.25(va)-.2 G(ilable:).25 E F2<ad63>103.666 384 Q F0
+(Ex)137 384 Q(ecute)-.15 E F3(cmd)2.675 E F0 .175
+(immediately after starting the edit session.)2.675 F -.15(Pa)5.175 G .174
+(rticularly useful for initial positioning in).15 F .624(the \214le, ho)137 396
+R(we)-.25 E -.15(ve)-.25 G(r).15 E F3(cmd)3.124 E F0 .625
+(is not limited to positioning commands.)3.124 F .625
+(This is the POSIX 1003.2 interf)5.625 F(ace)-.1 E(for the historic `)137 408 Q
+(`+cmd')-.74 E 2.5('s)-.74 G(yntax.)239.47 408 Q F2(Nex/nvi)5 E F0
+(supports both the old and ne)2.5 E 2.5(ws)-.25 G(yntax.)440.1 408 Q F2<ad65>
+103.666 426 Q F0(Start editing in e)137 426 Q 2.5(xm)-.15 G
+(ode, as if the command name were)218.52 426 Q F2(ex)2.5 E F0(.)A F2<ad46>
+103.666 444 Q F0(Don')137 444 Q 2.677(tc)-.18 G(op)167.267 444 Q 2.677(yt)-.1 G
+.177(he entire \214le when \214rst starting to edit.)187.624 444 R .177
+(\(The def)5.177 F .177(ault is to mak)-.1 F 2.677(eac)-.1 G(op)456.532 444 Q
+2.676(yi)-.1 G 2.676(nc)476.888 444 S .176(ase someone)489.004 444 R
+(else modi\214es the \214le during your edit session.\))137 456 Q F2<ad52>
+103.666 474 Q F0 .184
+(Start editing in read-only mode, as if the command name w)137 474 R(as)-.1 E
+F2(view)2.685 E F0 2.685(,o)C 2.685(rt)421.415 474 S .185(he readonly option w)
+430.21 474 R .185(as set.)-.1 F F2<ad72>103.666 492 Q F0(Reco)137 492 Q -.15
+(ve)-.15 G 2.627(rt).15 G .127(he speci\214ed \214les, or)175.427 492 R 2.627
+(,i)-.4 G 2.627(fn)263.305 492 S 2.627<6f8c>274.262 492 S .127
+(les are speci\214ed, list the \214les that could be reco)287.449 492 R -.15
+(ve)-.15 G 2.626(red. If).15 F .126(no re-)2.626 F(co)137 504 Q -.15(ve)-.15 G
+.4(rable \214les by the speci\214ed name e).15 F .401
+(xist, the \214le is edited as if the)-.15 F F2<ad72>4.567 E F0 .401
+(option had not been speci-)2.901 F(\214ed.)137 516 Q F2<ad73>103.666 534 Q F0
+1.621(Enter batch mode; applicable only to)137 534 R F2(ex)4.121 E F0 1.621
+(edit sessions.)4.121 F 1.62(Batch mode is useful when running)6.621 F F2(ex)
+4.12 E F0 2.647(scripts. Prompts,)137 546 R(informati)2.647 E .447 -.15(ve m)
+-.25 H .147(essages and other user oriented message are turned of).15 F .148
+(f, and no start-)-.25 F .067(up \214les or en)137 558 R .067(vironmental v)-.4
+F .066(ariables are read.)-.25 F .066(This is the POSIX 1003.2 interf)5.066 F
+.066(ace for the historic `)-.1 F(`\255')-.74 E(')-.74 E(ar)137 570 Q(gument.)
+-.18 E F2(Nex/nvi)5 E F0(supports both the old and ne)2.5 E 2.5(ws)-.25 G
+(yntax.)353 570 Q F2<ad74>103.666 588 Q F0
+(Start editing at the speci\214ed tag.)137 588 Q(\(See)5 E/F4 10/Courier@0 SF
+(ctags)2.5 E F0(\(1\)\).)A F2<ad77>103.666 606 Q F0(Set the initial windo)137
+606 Q 2.5(ws)-.25 G(ize to the speci\214ed number of lines.)231.2 606 Q F2
+<ad76>103.666 624 Q F0(Start editing in vi mode, as if the command name w)137
+624 Q(as)-.1 E F2(vi)2.5 E F0(or)2.5 E F2(view)2.5 E F0(.)A F2<ad58>103.666 642
+Q F0(Reserv)137 642 Q(ed for X11 interf)-.15 E(aces.)-.1 E/F5 10/Times-Italic@0
+SF(No X11 support is curr)5 E(ently implemented.)-.37 E F0 .35
+(Command input for)102 660 R F2(ex/vi)2.85 E F0 .35
+(is read from the standard input.)2.85 F .35(In the)5.35 F F2(vi)2.85 E F0
+(interf)2.85 E .35(ace, it is an error if standard in-)-.1 F .343
+(put is not a terminal.)102 672 R .343(In the)5.343 F F2(ex)2.843 E F0(interf)
+2.843 E .343(ace, if standard input is not a terminal,)-.1 F F2(ex)2.843 E F0
+.342(will read commands from it)2.843 F(re)102 684 Q -.05(ga)-.15 G .137
+(rdless, ho).05 F(we)-.25 E -.15(ve)-.25 G .937 -.4(r, t).15 H .137
+(he session will be a batch mode session, e).4 F .138(xactly as if the)-.15 F
+F2<ad73>4.304 E F0 .138(option had been speci\214ed.)2.638 F 172.465
+(4.4BSD July)72 750 R(15, 1994)2.5 E(1)535 750 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Courier-Bold@0 SF(Ex/vi)102
+96 Q F0 -.15(ex)2.5 G(its 0 on success, and greater than 0 if an error occurs.)
+.15 E/F2 10/Times-Bold@0 SF -.9(FA)72 120 S 1.666(ST ST).9 F(AR)-.9 E(TUP)-.4 E
+F0 .467(This section will tell you the minimum amount that you need to do simp\
+le editing tasks using)102 132 R F1(vi)2.966 E F0 2.966(.I)C 2.966(fy)506.584
+132 S(ou')517.88 132 Q -.15(ve)-.5 G(ne)102 144 Q -.15(ve)-.25 G 3.453(ru).15 G
+.953(sed an)132.263 144 R 3.453(ys)-.15 G .953(creen editor before, you')
+170.679 144 R .953(re lik)-.5 F .953(ely to ha)-.1 F 1.253 -.15(ve p)-.2 H .953
+(roblems e).15 F -.15(ve)-.25 G 3.453(nw).15 G .953
+(ith this simple introduction.)412.286 144 R(In)5.954 E
+(that case you should \214nd someone that already kno)102 156 Q(ws)-.25 E F1
+(vi)2.5 E F0(and ha)2.5 E .3 -.15(ve t)-.2 H(hem w).15 E
+(alk you through this section.)-.1 E F1(Vi)102 174 Q F0 .294
+(is a screen editor)2.794 F 5.294(.T)-.55 G .294(his means that it tak)198.51
+174 R .293
+(es up almost the entire screen, displaying part of the \214le on each)-.1 F
+.001(screen line, e)102 186 R .001(xcept for the last line of the screen.)-.15
+F .002(The last line of the screen is used for you to gi)5.001 F .302 -.15
+(ve c)-.25 H(ommands).15 E(to)102 198 Q F1(vi)2.5 E F0 2.5(,a)C(nd for)133.72
+198 Q F1(vi)2.5 E F0(to gi)2.5 E .3 -.15(ve i)-.25 H(nformation to you.).15 E
+.585(The other f)102 216 R .585(act that you need to understand is that)-.1 F
+F1(vi)3.085 E F0 .585(is a modeful editor)3.085 F 3.085(,i)-.4 G .584
+(.e. you are either entering te)406.125 216 R .584(xt or)-.15 F .836(you are e)
+102 228 R -.15(xe)-.15 G .836(cuting commands, and you ha).15 F 1.137 -.15
+(ve t)-.2 H 3.337(ob).15 G 3.337(ei)301.062 228 S 3.337(nt)311.619 228 S .837
+(he right mode to do one or the other)322.736 228 R 5.837(.Y)-.55 G .837
+(ou will be in)487.209 228 R 1.094
+(command mode when you \214rst start editing a \214le.)102 240 R 1.093
+(There are commands that switch you into input mode.)6.094 F .084
+(There is only one k)102 252 R .384 -.15(ey t)-.1 H .085(hat tak).15 F .085
+(es you out of input mode, and that is the <escape> k)-.1 F -.15(ey)-.1 G 5.085
+(.\()-.5 G -2.15 -.25(Ke y)449.895 252 T .085(names are written)2.835 F 1.473
+(using less-than and greater)102 264 R 1.473(-than signs, e.g.)-.2 F 1.473
+(<escape> means the `)6.473 F(`escape')-.74 E 3.973('k)-.74 G -.15(ey)420.59
+264 S 3.973(,u)-.5 G 1.473(sually labeled `)440.703 264 R(`esc')-.74 E 3.972
+('o)-.74 G(n)535 264 Q .553(your terminal')102 276 R 3.053(sk)-.55 G -.15(ey)
+171.336 276 S 3.053(board.\) If).15 F(you')3.053 E .554(re e)-.5 F -.15(ve)-.25
+G 3.054(rc).15 G .554(onfused as to which mode you')277.45 276 R .554(re in, k)
+-.5 F .554(eep entering the <escape>)-.1 F -.1(ke)102 288 S 2.615(yu)-.05 G
+(ntil)123.805 288 Q F1(vi)2.615 E F0 .115(beeps at you.)2.615 F(\(Generally)
+5.115 E(,)-.65 E F1(vi)2.615 E F0 .115
+(will beep at you if you try and do something that')2.615 F 2.614(sn)-.55 G
+.114(ot allo)484.472 288 R 2.614(wed. It)-.25 F
+(will also display error messages.\))102 300 Q 2.057 -.8(To s)102 318 T .457
+(tart editing a \214le, enter the command `).8 F(`)-.74 E/F3 10/Courier@0 SF
+.458(vi file_name<carriage-return>)B F0 -.74('')C 2.958(.T).74 G .458
+(he command you)470.204 318 R .333
+(should enter as soon as you start editing is `)102 330 R(`)-.74 E F3 .333
+(:set verbose showmode<carriage-return>)B F0 -.74('')C 2.833(.T).74 G(his)
+528.33 330 Q 1.441(will mak)102 342 R 3.941(et)-.1 G 1.441(he editor gi)149.782
+342 R 1.741 -.15(ve y)-.25 H 1.441(ou v).15 F 1.441
+(erbose error messages and display the current mode at the bottom of the)-.15 F
+(screen.)102 354 Q(The commands to mo)102 372 Q .3 -.15(ve a)-.15 H
+(round the \214le are:).15 E F2(h)102 384 Q F0(Mo)131 384 Q .3 -.15(ve t)-.15 H
+(he cursor left one character).15 E(.)-.55 E F2(j)102 396 Q F0(Mo)131 396 Q .3
+-.15(ve t)-.15 H(he cursor do).15 E(wn one line.)-.25 E F2(k)102 408 Q F0(Mo)
+131 408 Q .3 -.15(ve t)-.15 H(he cursor up one line.).15 E F2(l)102 420 Q F0
+(Mo)131 420 Q .3 -.15(ve t)-.15 H(he cursor right one character).15 E(.)-.55 E
+F2(<cursor)102 432 Q(-arr)-.37 E -.1(ow)-.18 G(s>).1 E F0(The cursor arro)131
+444 Q 2.5(wk)-.25 G -.15(ey)207.01 444 S 2.5(ss).15 G(hould w)226.58 444 Q
+(ork, too.)-.1 E F2(/text<carriage-r)102 456 Q(etur)-.18 E(n>)-.15 E F0
+(Search for the string `)131 468 Q(`te)-.74 E(xt')-.15 E 2.5('i)-.74 G 2.5(nt)
+246.84 468 S(he \214le, and mo)257.12 468 Q .3 -.15(ve t)-.15 H
+(he cursor to its \214rst character).15 E(.)-.55 E(The commands to enter ne)102
+486 Q 2.5(wt)-.25 G -.15(ex)220.34 486 S 2.5(ta).15 G(re:)239.35 486 Q F2(a)102
+498 Q F0(Append ne)131 498 Q 2.5(wt)-.25 G -.15(ex)186.85 498 S(t,).15 E/F4 10
+/Times-Italic@0 SF(after)2.5 E F0(the cursor)2.5 E(.)-.55 E F2(i)102 510 Q F0
+(Insert ne)131 510 Q 2.5(wt)-.25 G -.15(ex)177.96 510 S(t,).15 E F4(befor)2.5 E
+(e)-.37 E F0(the cursor)2.5 E(.)-.55 E F2(o)102 522 Q F0(Open a ne)131 522 Q
+2.5(wl)-.25 G(ine belo)183.79 522 Q 2.5(wt)-.25 G
+(he line the cursor is on, and start entering te)227.98 522 Q(xt.)-.15 E F2(O)
+102 534 Q F0(Open a ne)131 534 Q 2.5(wl)-.25 G(ine abo)183.79 534 Q .3 -.15
+(ve t)-.15 H(he line the cursor is on, and start entering te).15 E(xt.)-.15 E
+F2(<escape>)102 546 Q F0 .744(Once you')131 558 R 1.044 -.15(ve e)-.5 H .744
+(ntered input mode using the one of the).15 F F2(a)3.244 E F0(,)A F2(i)3.244 E
+F0(,)A F2(O)3.244 E F0 3.244(,o)C(r)390.542 558 Q F2(o)3.243 E F0 .743
+(commands, use)3.243 F F2(<escape>)3.243 E F0 .743(to quit)3.243 F(entering te)
+131 570 Q(xt and return to command mode.)-.15 E(The commands to cop)102 588 Q
+2.5(yt)-.1 G -.15(ex)200.78 588 S 2.5(ta).15 G(re:)219.79 588 Q F2(yy)102 600 Q
+F0(Cop)131 600 Q 2.5(yt)-.1 G(he line the cursor is on.)157.85 600 Q F2(p)102
+612 Q F0(Append the copied line after the line the cursor is on.)131 612 Q
+(The commands to delete te)102 630 Q(xt are:)-.15 E F2(dd)102 642 Q F0
+(Delete the line the cursor is on.)131 642 Q F2(x)102 654 Q F0
+(Delete the character the cursor is on.)131 654 Q
+(The commands to write the \214le are:)102 672 Q F2(:w<carriage-r)102 684 Q
+(etur)-.18 E(n>)-.15 E F0 .528(Write the \214le back to the \214le with the na\
+me that you originally used as an ar)131 696 R .528(gument on the)-.18 F F1(vi)
+3.028 E F0(com-)3.028 E 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(2)535 750 Q
+EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(mand line.)131 96 Q/F1 10
+/Times-Bold@0 SF(:w \214le_name<carriage-r)102 108 Q(etur)-.18 E(n>)-.15 E F0
+(Write the \214le back to the \214le with the name `)131 120 Q(`\214le_name')
+-.74 E('.)-.74 E(The commands to quit editing and e)102 138 Q
+(xit the editor are:)-.15 E F1(:q<carriage-r)102 150 Q(etur)-.18 E(n>)-.15 E F0
+.848(Quit editing and lea)131 162 R 1.148 -.15(ve v)-.2 H 3.348(i\().15 G .848
+(if you')239.6 162 R 1.148 -.15(ve m)-.5 H .848(odi\214ed the \214le, b).15 F
+.848(ut not sa)-.2 F -.15(ve)-.2 G 3.348(dy).15 G .848(our changes,)415.454 162
+R/F2 10/Courier-Bold@0 SF(vi)3.347 E F0 .847(will refuse to)3.347 F(quit\).)131
+174 Q F1(:q!<carriage-r)102 186 Q(etur)-.18 E(n>)-.15 E F0(Quit, discarding an)
+131 198 Q 2.5(ym)-.15 G(odi\214cations that you may ha)222.51 198 Q .3 -.15
+(ve m)-.2 H(ade.).15 E .686(One \214nal caution.)102 216 R .686
+(Unusual characters can tak)5.686 F 3.187(eu)-.1 G 3.187(pm)302.483 216 S .687
+(ore than one column on the screen, and long lines can)318.45 216 R(tak)102 228
+Q 3.129(eu)-.1 G 3.129(pm)126.689 228 S .629(ore than a single screen line.)
+142.598 228 R .629(The abo)5.629 F .929 -.15(ve c)-.15 H .629(ommands w).15 F
+.629(ork on `)-.1 F(`ph)-.74 E(ysical')-.05 E 3.129('c)-.74 G .628
+(haracters and lines, i.e.)446.476 228 R(the)102 240 Q 2.74(ya)-.15 G -.25(ff)
+126.25 240 S .24(ect the entire line no matter ho).25 F 2.74(wm)-.25 G(an)
+273.79 240 Q 2.74(ys)-.15 G .241(creen lines it tak)294.71 240 R .241
+(es up and the entire character no matter ho)-.1 F(w)-.25 E(man)102 252 Q 2.5
+(ys)-.15 G(creen columns it tak)130.46 252 Q(es up.)-.1 E F1 1.666(VI COMMANDS)
+72 276 R F0 .186(The follo)102 288 R .186
+(wing section describes the commands a)-.25 F -.25(va)-.2 G .186
+(ilable in the command mode of the).25 F F2(vi)2.686 E F0(editor)2.686 E 5.186
+(.I)-.55 G 2.685(ne)498.54 288 S .185(ach en-)510.665 288 R(try belo)102 300 Q
+1.3 -.65(w, t)-.25 H(he tag line is a usage synopsis for the command character)
+.65 E(.)-.55 E F1([count] <contr)102 324 Q(ol-A>)-.18 E F0(Search forw)131 336
+Q(ard)-.1 E/F3 10/Courier@0 SF(count)2.5 E F0(times for the current w)2.5 E
+(ord.)-.1 E F1([count] <contr)102 348 Q(ol-B>)-.18 E F0 -.15(Pa)131 360 S
+(ge backw).15 E(ards)-.1 E F3(count)2.5 E F0(screens.)2.5 E F1([count] <contr)
+102 372 Q(ol-D>)-.18 E F0(Scroll forw)131 384 Q(ard)-.1 E F3(count)2.5 E F0
+(lines.)2.5 E F1([count] <contr)102 396 Q(ol-E>)-.18 E F0(Scroll forw)131 408 Q
+(ard)-.1 E F3(count)2.5 E F0(lines, lea)2.5 E
+(ving the current line and column as is, if possible.)-.2 E F1([count] <contr)
+102 420 Q(ol-F>)-.18 E F0 -.15(Pa)131 432 S(ge forw).15 E(ard)-.1 E F3(count)
+2.5 E F0(screens.)2.5 E F1(<contr)102 444 Q(ol-G>)-.18 E F0
+(Display the \214le information.)131 456 Q F1(<contr)102 468 Q(ol-H>)-.18 E
+([count] h)102 480 Q F0(Mo)131 492 Q .3 -.15(ve t)-.15 H(he cursor back).15 E
+F3(count)2.5 E F0(characters in the current line.)2.5 E F1([count] <contr)102
+504 Q(ol-J>)-.18 E([count] <contr)102 516 Q(ol-N>)-.18 E([count] j)102 528 Q F0
+(Mo)131 540 Q .3 -.15(ve t)-.15 H(he cursor do).15 E(wn)-.25 E F3(count)2.5 E
+F0(lines without changing the current column.)2.5 E F1(<contr)102 552 Q(ol-L>)
+-.18 E(<contr)102 564 Q(ol-R>)-.18 E F0(Repaint the screen.)131 576 Q F1
+([count] <contr)102 588 Q(ol-M>)-.18 E([count] +)102 600 Q F0(Mo)131 612 Q .3
+-.15(ve t)-.15 H(he cursor do).15 E(wn)-.25 E F3(count)2.5 E F0
+(lines to the \214rst nonblank character of that line.)2.5 E F1([count] <contr)
+102 624 Q(ol-P>)-.18 E([count] k)102 636 Q F0(Mo)131 648 Q .3 -.15(ve t)-.15 H
+(he cursor up).15 E F3(count)2.5 E F0
+(lines, without changing the current column.)2.5 E F1(<contr)102 660 Q(ol-T>)
+-.18 E F0(Return to the most recent tag conte)131 672 Q(xt.)-.15 E F1(<contr)
+102 684 Q(ol-U>)-.18 E F0 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(3)535 750
+Q EP
+%%Page: 4 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Scroll backw)131 96 Q(ards)-.1 E
+/F1 10/Courier@0 SF(count)2.5 E F0(lines.)2.5 E/F2 10/Times-Bold@0 SF(<contr)
+102 108 Q(ol-W>)-.18 E F0 .635(Switch to the ne)131 120 R .635(xt lo)-.15 F
+.635(wer screen in the windo)-.25 F 1.935 -.65(w, o)-.25 H 1.435 -.4(r, t).65 H
+3.135(ot).4 G .635(he \214rst screen if there are no lo)353.205 120 R .635
+(wer screens in)-.25 F(the windo)131 132 Q -.65(w.)-.25 G F2(<contr)102 144 Q
+(ol-Y>)-.18 E F0(Scroll backw)131 156 Q(ards)-.1 E F1(count)2.5 E F0
+(lines, lea)2.5 E(ving the current line and column as is, if possible.)-.2 E F2
+(<contr)102 168 Q(ol-Z>)-.18 E F0(Suspend the current editor session.)131 180 Q
+F2(<escape>)102 192 Q F0(Ex)131 204 Q(ecute)-.15 E/F3 10/Courier-Bold@0 SF(ex)
+2.5 E F0(commands or cancel partial commands.)2.5 E F2(<contr)102 216 Q(ol-]>)
+-.18 E F0(Push a tag reference onto the tag stack.)131 228 Q F2(<contr)102 240
+Q(ol-^>)-.18 E F0(Switch to the most recently edited \214le.)131 252 Q F2
+([count] <space>)102 264 Q([count] l)102 276 Q F0(Mo)131 288 Q .3 -.15(ve t)
+-.15 H(he cursor forw).15 E(ard)-.1 E F1(count)2.5 E F0
+(characters without changing the current line.)2.5 E F2
+([count] ! motion shell-ar)102 300 Q(gument\(s\))-.1 E F0(Replace te)131 312 Q
+(xt with results from a shell command.)-.15 E F2([count] # +|-|#)102 324 Q F0
+(Increment or decrement the cursor number)131 336 Q(.)-.55 E F2([count] $)102
+348 Q F0(Mo)131 360 Q .3 -.15(ve t)-.15 H(he cursor to the end of a line.).15 E
+F2(%)102 372 Q F0(Mo)131 372 Q .3 -.15(ve t)-.15 H 2.5(ot).15 G
+(he matching character)169.59 372 Q(.)-.55 E F2(&)102 384 Q F0(Repeat the pre)
+131 384 Q(vious substitution command on the current line.)-.25 E F2
+('<character>)102 396 Q(`<character>)102 408 Q F0(Return to a conte)131 420 Q
+(xt mark)-.15 E(ed by the character)-.1 E F1(<character>)2.5 E F0(.)A F2
+([count] \()102 432 Q F0(Back up)131 444 Q F1(count)2.5 E F0(sentences.)2.5 E
+F2([count] \))102 456 Q F0(Mo)131 468 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E
+F1(count)2.5 E F0(sentences.)2.5 E F2([count] ,)102 480 Q F0(Re)131 492 Q -.15
+(ve)-.25 G(rse \214nd character).15 E F1(count)2.5 E F0(times.)2.5 E F2
+([count] -)102 504 Q F0(Mo)131 516 Q .3 -.15(ve t)-.15 H 2.5<6f8c>.15 G
+(rst nonblank of the pre)172.37 516 Q(vious line,)-.25 E F1(count)2.5 E F0
+(times.)2.5 E F2([count] .)102 528 Q F0(Repeat the last)131 540 Q F3(vi)2.5 E
+F0(command that modi\214ed te)2.5 E(xt.)-.15 E F2(/RE<carriage-r)102 552 Q
+(etur)-.18 E(n>)-.15 E(/RE/ [offset]<carriage-r)102 564 Q(etur)-.18 E(n>)-.15 E
+(?RE<carriage-r)102 576 Q(etur)-.18 E(n>)-.15 E(?RE? [offset]<carriage-r)102
+588 Q(etur)-.18 E(n>)-.15 E(N)102 600 Q(n)102 612 Q F0(Search forw)131 612 Q
+(ard or backw)-.1 E(ard for a re)-.1 E(gular e)-.15 E(xpression.)-.15 E F2(0)
+102 624 Q F0(Mo)131 624 Q .3 -.15(ve t)-.15 H 2.5(ot).15 G
+(he \214rst character in the current line.)169.59 624 Q 26.22(:E)102 636 S -.15
+(xe)137.11 636 S(cute an e).15 E 2.5(xc)-.15 G(ommand.)193.73 636 Q F2
+([count] ;)102 648 Q F0(Repeat the last character \214nd)131 660 Q F1(count)2.5
+E F0(times.)2.5 E F2([count] < motion)102 672 Q F0 172.465(4.4BSD July)72 750 R
+(15, 1994)2.5 E(4)535 750 Q EP
+%%Page: 5 5
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Bold@0 SF
+([count] > motion)102 96 Q F0(Shift lines left or right.)131 108 Q F1 2.5(@b)
+102 120 S(uffer)119.16 120 Q F0(Ex)131 132 Q(ecute a named b)-.15 E(uf)-.2 E
+(fer)-.25 E(.)-.55 E F1([count] A)102 144 Q F0
+(Enter input mode, appending the te)131 156 Q(xt after the end of the line.)
+-.15 E F1([count] B)102 168 Q F0(Mo)131 180 Q .3 -.15(ve b)-.15 H(ackw).15 E
+(ards)-.1 E/F2 10/Courier@0 SF(count)2.5 E F0(bigw)2.5 E(ords.)-.1 E F1([b)102
+192 Q(uffer] [count] C)-.2 E F0(Change te)131 204 Q
+(xt from the current position to the end-of-line.)-.15 E F1([b)102 216 Q
+(uffer] D)-.2 E F0(Delete te)131 228 Q
+(xt from the current position to the end-of-line.)-.15 E F1([count] E)102 240 Q
+F0(Mo)131 252 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E F2(count)2.5 E F0
+(end-of-bigw)2.5 E(ords.)-.1 E F1([count] F <character>)102 264 Q F0(Search)131
+276 Q F2(count)2.5 E F0(times backw)2.5 E(ard through the current line for)-.1
+E F2(<character>)2.5 E F0(.)A F1([count] G)102 288 Q F0(Mo)131 300 Q .3 -.15
+(ve t)-.15 H 2.5(ol).15 G(ine)169.59 300 Q F2(count)2.5 E F0 2.5(,o)C 2.5(rt)
+224.31 300 S(he last line of the \214le if)232.92 300 Q F2(count)2.5 E F0
+(not speci\214ed.)2.5 E F1([count] H)102 312 Q F0(Mo)131 324 Q .3 -.15(ve t)
+-.15 H 2.5(ot).15 G(he screen line)169.59 324 Q F2(count - 1)2.5 E F0
+(lines belo)2.5 E 2.5(wt)-.25 G(he top of the screen.)334.43 324 Q F1
+([count] I)102 336 Q F0(Enter input mode, inserting the te)131 348 Q
+(xt at the be)-.15 E(ginning of the line.)-.15 E F1([count] J)102 360 Q F0
+(Join lines.)131 372 Q F1([count] L)102 384 Q F0(Mo)131 396 Q .3 -.15(ve t)-.15
+H 2.5(ot).15 G(he screen line)169.59 396 Q F2(count - 1)2.5 E F0(lines abo)2.5
+E .3 -.15(ve t)-.15 H(he bottom of the screen.).15 E F1(M)102 408 Q F0(Mo)131
+408 Q .3 -.15(ve t)-.15 H 2.5(ot).15 G
+(he screen line in the middle of the screen.)169.59 408 Q F1([count] O)102 420
+Q F0(Enter input mode, appending te)131 432 Q(xt in a ne)-.15 E 2.5(wl)-.25 G
+(ine abo)305.86 432 Q .3 -.15(ve t)-.15 H(he current line.).15 E F1([b)102 444
+Q(uffer] P)-.2 E F0(Insert te)131 456 Q(xt from a b)-.15 E(uf)-.2 E(fer)-.25 E
+(.)-.55 E F1(Q)102 468 Q F0(Exit)131 468 Q/F3 10/Courier-Bold@0 SF(vi)2.5 E F0
+(\(or visual\) mode and switch to)2.5 E F3(ex)2.5 E F0(mode.)2.5 E F1
+([count] R)102 480 Q F0
+(Enter input mode, replacing the characters in the current line.)131 492 Q F1
+([b)102 504 Q(uffer] [count] S)-.2 E F0(Substitute)131 516 Q F2(count)2.5 E F0
+(lines.)2.5 E F1([count] T <character>)102 528 Q F0 2.78(Search backw)131 540 R
+(ards,)-.1 E F2(count)5.28 E F0 2.779
+(times, through the current line for the character)5.28 F/F4 10/Times-Italic@0
+SF(after)5.279 E F0 2.779(the speci\214ed)5.279 F F2(<character>)131 552 Q F0
+(.)A F1(U)102 564 Q F0
+(Restore the current line to its state before the cursor last mo)131 564 Q -.15
+(ve)-.15 G 2.5(dt).15 G 2.5(oi)388.99 564 S(t.)399.27 564 Q F1([count] W)102
+576 Q F0(Mo)131 588 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E F2(count)2.5 E F0
+(bigw)2.5 E(ords.)-.1 E F1([b)102 600 Q(uffer] [count] X)-.2 E F0(Delete)131
+612 Q F2(count)2.5 E F0(characters before the cursor)2.5 E(.)-.55 E F1([b)102
+624 Q(uffer] [count] Y)-.2 E F0(Cop)131 636 Q 2.5(y\()-.1 G(or `)158.4 636 Q
+(`yank')-.74 E('\))-.74 E F2(count)2.5 E F0(lines into the speci\214ed b)2.5 E
+(uf)-.2 E(fer)-.25 E(.)-.55 E F1(ZZ)102 648 Q F0(Write the \214le and e)131 648
+Q(xit)-.15 E F3(vi)2.5 E F0(.)A F1([count] [[)102 660 Q F0(Back up)131 672 Q F2
+(count)2.5 E F0(section boundaries.)2.5 E F1([count] ]])102 684 Q F0 172.465
+(4.4BSD July)72 750 R(15, 1994)2.5 E(5)535 750 Q EP
+%%Page: 6 6
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Mo)131 96 Q .3 -.15(ve f)-.15 H
+(orw).15 E(ard)-.1 E/F1 10/Courier@0 SF(count)2.5 E F0(section boundaries.)2.5
+E/F2 10/Times-Bold@0 SF(^)102 108 Q F0(Mo)131 108 Q .3 -.15(ve t)-.15 H 2.5
+<6f8c>.15 G(rst nonblank character on the current line.)172.37 108 Q F2
+([count] _)102 120 Q F0(Mo)131 132 Q .3 -.15(ve d)-.15 H -.25(ow).15 G(n).25 E
+F1(count - 1)2.5 E F0(lines, to the \214rst nonblank character)2.5 E(.)-.55 E
+F2([count] a)102 144 Q F0(Enter input mode, appending the te)131 156 Q
+(xt after the cursor)-.15 E(.)-.55 E F2([count] b)102 168 Q F0(Mo)131 180 Q .3
+-.15(ve b)-.15 H(ackw).15 E(ards)-.1 E F1(count)2.5 E F0 -.1(wo)2.5 G(rds.).1 E
+F2([b)102 192 Q(uffer] [count] c motion)-.2 E F0(Change a re)131 204 Q
+(gion of te)-.15 E(xt.)-.15 E F2([b)102 216 Q(uffer] [count] d motion)-.2 E F0
+(Delete a re)131 228 Q(gion of te)-.15 E(xt.)-.15 E F2([count] e)102 240 Q F0
+(Mo)131 252 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E F1(count)2.5 E F0
+(end-of-w)2.5 E(ords.)-.1 E F2([count] f<character>)102 264 Q F0(Search forw)
+131 276 Q(ard,)-.1 E F1(count)2.5 E F0
+(times, through the rest of the current line for)2.5 E F1(<character>)2.5 E F0
+(.)A F2([count] i)102 288 Q F0(Enter input mode, inserting the te)131 300 Q
+(xt before the cursor)-.15 E(.)-.55 E F2 2.5(m<)102 312 S(character>)118.53 312
+Q F0(Sa)131 324 Q .3 -.15(ve t)-.2 H(he current conte).15 E
+(xt \(line and column\) as)-.15 E F1(<character>)2.5 E F0(.)A F2([count] o)102
+336 Q F0(Enter input mode, appending te)131 348 Q(xt in a ne)-.15 E 2.5(wl)-.25
+G(ine under the current line.)305.86 348 Q F2([b)102 360 Q(uffer] p)-.2 E F0
+(Append te)131 372 Q(xt from a b)-.15 E(uf)-.2 E(fer)-.25 E(.)-.55 E F2
+([count] r <character>)102 384 Q F0(Replace)131 396 Q F1(count)2.5 E F0
+(characters.)2.5 E F2([b)102 408 Q(uffer] [count] s)-.2 E F0(Substitute)131 420
+Q F1(count)2.5 E F0
+(characters in the current line starting with the current character)2.5 E(.)
+-.55 E F2([count] t <character>)102 432 Q F0 3.435(Search forw)131 444 R(ard,)
+-.1 E F1(count)5.935 E F0 3.435
+(times, through the current line for the character immediately)5.935 F/F3 10
+/Times-Italic@0 SF(befor)5.935 E(e)-.37 E F1(<character>)131 456 Q F0(.)A F2(u)
+102 468 Q F0(Undo the last change made to the \214le.)131 468 Q F2([count] w)
+102 480 Q F0(Mo)131 492 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E F1(count)2.5
+E F0 -.1(wo)2.5 G(rds.).1 E F2([b)102 504 Q(uffer] [count] x)-.2 E F0(Delete)
+131 516 Q F1(count)2.5 E F0(characters.)2.5 E F2([b)102 528 Q
+(uffer] [count] y motion)-.2 E F0(Cop)131 540 Q 2.5(y\()-.1 G(or `)158.4 540 Q
+(`yank')-.74 E('\) a te)-.74 E(xt re)-.15 E(gion speci\214ed by the)-.15 E F1
+(count)2.5 E F0(and motion into a b)2.5 E(uf)-.2 E(fer)-.25 E(.)-.55 E F2
+([count1] z [count2] -|.|+|^|<carriage-r)102 552 Q(etur)-.18 E(n>)-.15 E F0
+(Redra)131 564 Q 1.3 -.65(w, o)-.15 H
+(ptionally repositioning and resizing the screen.).65 E F2([count] {)102 576 Q
+F0(Mo)131 588 Q .3 -.15(ve b)-.15 H(ackw).15 E(ard)-.1 E F1(count)2.5 E F0
+(paragraphs.)2.5 E F2([count] |)102 600 Q F0(Mo)131 612 Q .3 -.15(ve t)-.15 H
+2.5(oas).15 G(peci\214c)177.64 612 Q F3(column)2.5 E F0
+(position on the current line.)2.5 E F2([count] })102 624 Q F0(Mo)131 636 Q .3
+-.15(ve f)-.15 H(orw).15 E(ard)-.1 E F1(count)2.5 E F0(paragraphs.)2.5 E F2
+([count] ~)102 648 Q F0(Re)131 660 Q -.15(ve)-.25 G(rse the case of the ne).15
+E(xt)-.15 E F1(count)2.5 E F0(character\(s\).)2.5 E F2([count] ~ motion)102 672
+Q F0 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(6)535 750 Q EP
+%%Page: 7 7
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Re)131 96 Q -.15(ve)-.25 G
+(rse the case of the characters in a te).15 E(xt re)-.15 E
+(gion speci\214ed by the)-.15 E/F1 10/Courier@0 SF(count)2.5 E F0(and)2.5 E F1
+(motion)2.5 E F0(.)A/F2 10/Times-Bold@0 SF(<interrupt>)102 108 Q F0
+(Interrupt the current operation.)131 120 Q F2 1.666(VI TEXT INPUT COMMANDS)72
+144 R F0(The follo)102 156 Q(wing section describes the commands a)-.25 E -.25
+(va)-.2 G(ilable in the te).25 E(xt input mode of the)-.15 E/F3 10
+/Courier-Bold@0 SF(vi)2.5 E F0(editor)2.5 E(.)-.55 E F2(<nul>)102 174 Q F0
+(Replay the pre)131 186 Q(vious input.)-.25 E F2(<contr)102 198 Q(ol-D>)-.18 E
+F0(Erase the pre)131 210 Q(vious autoindent character)-.25 E(.)-.55 E F2
+(^<contr)102 222 Q(ol-D>)-.18 E F0
+(Erase all of the autoindent characters, and reset the autoindent le)131 234 Q
+-.15(ve)-.25 G(l.).15 E F2(0<contr)102 246 Q(ol-D>)-.18 E F0
+(Erase all of the autoindent characters.)131 258 Q F2(<contr)102 270 Q(ol-T>)
+-.18 E F0 .076(Insert suf)131 282 R(\214cient)-.25 E F1(<tab>)2.576 E F0(and)
+2.576 E F1(<space>)2.576 E F0 .076(characters to mo)2.576 F .376 -.15(ve t)-.15
+H .076(he cursor forw).15 F .075(ard to a column immediate-)-.1 F
+(ly after the ne)131 294 Q(xt column which is an e)-.15 E -.15(ve)-.25 G 2.5
+(nm).15 G(ultiple of the)305.7 294 Q F2(shiftwidth)2.5 E F0(option.)2.5 E F2
+(<erase>)102 306 Q(<contr)102 318 Q(ol-H>)-.18 E F0(Erase the last character)
+131 330 Q(.)-.55 E F2(<literal next>)102 342 Q F0(Quote the ne)131 354 Q
+(xt character)-.15 E(.)-.55 E F2(<escape>)102 366 Q F0(Resolv)131 378 Q 2.5(ea)
+-.15 G(ll te)170.01 378 Q
+(xt input into the \214le, and return to command mode.)-.15 E F2(<line erase>)
+102 390 Q F0(Erase the current line.)131 402 Q F2(<contr)102 414 Q(ol-W>)-.18 E
+(<w)102 426 Q(ord erase>)-.1 E F0(Erase the last w)131 438 Q 2.5(ord. The)-.1 F
+(de\214nition of w)2.5 E(ord is dependent on the)-.1 E F2(altwerase)2.5 E F0
+(and)2.5 E F2(ttywerase)2.5 E F0(options.)2.5 E F2(<contr)102 450 Q
+(ol-X>[0-9A-F)-.18 E(a-f])-.25 E/F4 10/Symbol SF(*)A F0
+(Insert a character with the speci\214ed he)131 462 Q(xadecimal v)-.15 E
+(alue into the te)-.25 E(xt.)-.15 E F2(<interrupt>)102 474 Q F0(Interrupt te)
+131 486 Q(xt input mode, returning to command mode.)-.15 E F2 1.666
+(EX COMMANDS)72 510 R F0 .163(The follo)102 522 R .163
+(wing section describes the commands a)-.25 F -.25(va)-.2 G .163(ilable in the)
+.25 F F3(ex)2.663 E F0(editor)2.663 E 5.163(.I)-.55 G 2.663(ne)405.333 522 S
+.164(ach entry belo)417.436 522 R 1.464 -.65(w, t)-.25 H .164(he tag line is)
+.65 F 2.5(au)102 534 S(sage synopsis for the command.)113.94 534 Q F2
+(<end-of-\214le>)102 558 Q F0(Scroll the screen.)131 570 Q F2 2.5(!a)102 582 S
+-.1(rg)112.83 582 S(ument\(s\)).1 E([range]! ar)102 594 Q(gument\(s\))-.1 E F0
+(Ex)131 606 Q
+(ecute a shell command, or \214lter lines through a shell command.)-.15 E F2(")
+102 618 Q F0 2.5(Ac)131 618 S(omment.)145.16 618 Q F2
+([range] nu[mber] [count] [\215ags])102 630 Q([range] # [count] [\215ags])102
+642 Q F0(Display the selected lines, each preceded with its line number)131 654
+Q(.)-.55 E F2 2.5(@b)102 666 S(uffer)119.16 666 Q F4(*)102 678 Q F2 -.2(bu)2.5
+G(ffer).2 E F0 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(7)535 750 Q EP
+%%Page: 8 8
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Ex)131 96 Q(ecute a b)-.15 E(uf)
+-.2 E(fer)-.25 E(.)-.55 E/F1 10/Times-Bold@0 SF([range] d[elete] [b)102 108 Q
+(uffer] [count] [\215ags])-.2 E F0(Delete the lines from the \214le.)131 120 Q
+F1(di[splay] b[uffers] | s[cr)102 132 Q(eens] | t[ags])-.18 E F0(Display b)131
+144 Q(uf)-.2 E(fers, screens or tags.)-.25 E F1(e[dit][!] [+cmd] [\214le])102
+156 Q(ex[!] [+cmd] [\214le])102 168 Q F0(Edit a dif)131 180 Q(ferent \214le.)
+-.25 E F1(exu[sage] [command])102 192 Q F0(Display usage for an)131 204 Q/F2 10
+/Courier-Bold@0 SF(ex)2.5 E F0(command.)2.5 E F1(f[ile] [\214le])102 216 Q F0
+(Display and optionally change the \214le name.)131 228 Q F1(fg [name])102 240
+Q F2(Vi)131 252 Q F0(mode only)2.5 E 5(.F)-.65 G(ore)200.26 252 Q
+(ground the speci\214ed screen.)-.15 E F1([range] g[lobal] /patter)102 264 Q
+(n/ [commands])-.15 E([range] v /patter)102 276 Q(n/ [commands])-.15 E F0
+(Apply commands to lines matching \(or not matching\) a pattern.)131 288 Q F1
+(he[lp])102 300 Q F0(Display a help message.)131 312 Q F1([line] i[nsert][!])
+102 324 Q F0(The input te)131 336 Q
+(xt is inserted before the speci\214ed line.)-.15 E F1
+([range] j[oin][!] [count] [\215ags])102 348 Q F0(Join lines of te)131 360 Q
+(xt together)-.15 E(.)-.55 E F1([range] l[ist] [count] [\215ags])102 372 Q F0
+(Display the lines unambiguously)131 384 Q(.)-.65 E F1(map[!] [lhs rhs])102 396
+Q F0(De\214ne or display maps \(for)131 408 Q F2(vi)2.5 E F0(only\).)2.5 E F1
+([line] ma[rk] <character>)102 420 Q([line] k <character>)102 432 Q F0
+(Mark the line with the mark)131 444 Q/F3 10/Courier@0 SF(<character>)2.5 E F0
+(.)A F1([range] m[o)102 456 Q -.1(ve)-.1 G 2.5(]l).1 G(ine)170.11 456 Q F0(Mo)
+131 468 Q .3 -.15(ve t)-.15 H(he speci\214ed lines after the tar).15 E
+(get line.)-.18 E F1(mk[exr)102 480 Q(c][!] \214le)-.18 E F0(Write the abbre)
+131 492 Q(viations, editor options and maps to the speci\214ed \214le.)-.25 E
+F1(n[ext][!] [\214le ...])102 504 Q F0(Edit the ne)131 516 Q
+(xt \214le from the ar)-.15 E(gument list.)-.18 E F1([line] o[pen] /patter)102
+528 Q(n/ [\215ags])-.15 E F0(Enter open mode.)131 540 Q F1(pr)102 552 Q(e[ser)
+-.18 E -.1(ve)-.1 G(]).1 E F0(Sa)131 564 Q .3 -.15(ve t)-.2 H
+(he \214le in a form that can later be reco).15 E -.15(ve)-.15 G(red using the)
+.15 E F2 -1.834(ex \255r)2.5 F F0(option.)2.5 E F1(pr)102 576 Q -.15(ev)-.18 G
+([ious][!]).15 E F0(Edit the pre)131 588 Q(vious \214le from the ar)-.25 E
+(gument list.)-.18 E F1([range] p[rint] [count] [\215ags])102 600 Q F0
+(Display the speci\214ed lines.)131 612 Q F1([line] pu[t] [b)102 624 Q(uffer])
+-.2 E F0(Append b)131 636 Q(uf)-.2 E(fer contents to the current line.)-.25 E
+F1(q[uit][!])102 648 Q F0(End the editing session.)131 660 Q F1
+([line] r[ead][!] [\214le])102 672 Q F0 172.465(4.4BSD July)72 750 R(15, 1994)
+2.5 E(8)535 750 Q EP
+%%Page: 9 9
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Read a \214le.)131 96 Q/F1 10
+/Times-Bold@0 SF -.18(re)102 108 S(c[o).18 E -.1(ve)-.1 G(r] \214le).1 E F0
+(Reco)131 120 Q -.15(ve)-.15 G(r).15 E/F2 10/Courier@0 SF(file)2.5 E F0
+(if it w)2.5 E(as pre)-.1 E(viously sa)-.25 E -.15(ve)-.2 G(d.).15 E F1 -.18
+(re)102 132 S(s[ize] [+|-]size).18 E/F3 10/Courier-Bold@0 SF(Vi)131 144 Q F0
+(mode only)2.5 E 5(.G)-.65 G(ro)202.07 144 Q 2.5(wo)-.25 G 2.5(rs)224.87 144 S
+(hrink the current screen.)234.59 144 Q F1 -.18(re)102 156 S(w[ind][!]).18 E F0
+(Re)131 168 Q(wind the ar)-.25 E(gument list.)-.18 E F1(se[t] [option[=[v)102
+180 Q(alue]] ...] [nooption ...] [option? ...] [all])-.1 E F0
+(Display or set editor options.)131 192 Q F1(sh[ell])102 204 Q F0
+(Run a shell program.)131 216 Q F1(so[ur)102 228 Q(ce] \214le)-.18 E F0
+(Read and e)131 240 Q -.15(xe)-.15 G(cute).15 E F3(ex)2.5 E F0
+(commands from a \214le.)2.5 E F1(sp[lit] [\214le ...])102 252 Q F3(Vi)131 264
+Q F0(mode only)2.5 E 5(.S)-.65 G(plit the screen.)200.41 264 Q F1
+([range] s[ubstitute] [/patter)102 276 Q(n/r)-.15 E
+(eplace/] [options] [count] [\215ags])-.18 E
+([range] & [options] [count] [\215ags])102 288 Q
+([range] ~ [options] [count] [\215ags])102 300 Q F0(Mak)131 312 Q 2.5(es)-.1 G
+(ubstitutions.)160.06 312 Q F1(su[spend][!])102 324 Q(st[op][!])102 336 Q
+(<suspend>)102 348 Q F0(Suspend the edit session.)131 360 Q F1
+(ta[g][!] tagstring)102 372 Q F0
+(Edit the \214le containing the speci\214ed tag.)131 384 Q F1
+(tagp[op][!] [\214le | number])102 396 Q F0
+(Pop to the speci\214ed tag in the tags stack.)131 408 Q F1(unm[ap][!] lhs)102
+420 Q F0(Unmap a mapped string.)131 432 Q F1 -.1(ve)102 444 S([rsion]).1 E F0
+(Display the v)131 456 Q(ersion of the)-.15 E F3(ex/vi)2.5 E F0(editor)2.5 E(.)
+-.55 E F1([line] vi[sual] [type] [count] [\215ags])102 468 Q F3(Ex)131 480 Q F0
+(mode only)2.5 E 5(.E)-.65 G(nter)200.96 480 Q F3(vi)2.5 E F0(.)A F1
+(vi[sual][!] [+cmd] [\214le])102 492 Q F3(Vi)131 504 Q F0(mode only)2.5 E 5(.E)
+-.65 G(dit a ne)200.96 504 Q 2.5<778c>-.25 G(le.)245.43 504 Q F1
+(viu[sage] [command])102 516 Q F0(Display usage for a)131 528 Q F3(vi)2.5 E F0
+(command.)2.5 E F1([range] w[rite][!] [>>] [\214le])102 540 Q
+([range] w[rite] [!] [\214le])102 552 Q([range] wn[!] [>>] [\214le])102 564 Q
+([range] wq[!] [>>] [\214le])102 576 Q F0(Write the \214le.)131 588 Q F1
+([range] x[it][!] [\214le])102 600 Q F0
+(Write the \214le if it has been modi\214ed.)131 612 Q F1([range] ya[nk] [b)102
+624 Q(uffer] [count])-.2 E F0(Cop)131 636 Q 2.5(yt)-.1 G
+(he speci\214ed lines to a b)157.85 636 Q(uf)-.2 E(fer)-.25 E(.)-.55 E F1
+([line] z [type] [count] [\215ags])102 648 Q F0(Adjust the windo)131 660 Q -.65
+(w.)-.25 G 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(9)535 750 Q EP
+%%Page: 10 10
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Bold@0 SF 1.666
+(SET OPTIONS)72 96 R F0 .519(There are a lar)102 108 R .518
+(ge number of options that may be set \(or unset\) to change the editor')-.18 F
+3.018(sb)-.55 G(eha)453.614 108 Q(vior)-.2 E 5.518(.T)-.55 G .518(his section)
+496.982 108 R(describes the options, their abbre)102 120 Q
+(viations and their def)-.25 E(ault v)-.1 E(alues.)-.25 E .095
+(In each entry belo)102 138 R 1.395 -.65(w, t)-.25 H .095
+(he \214rst part of the tag line is the full name of the option, follo).65 F
+.095(wed by an)-.25 F 2.595(ye)-.15 G(qui)487.915 138 Q -.25(va)-.25 G .095
+(lent ab-).25 F(bre)102 150 Q 3.034(viations. The)-.25 F .534
+(part in square brack)3.034 F .533(ets is the def)-.1 F .533(ault v)-.1 F .533
+(alue of the option.)-.25 F .533(Most of the options are boolean,)5.533 F
+(i.e. the)102 162 Q 2.5(ya)-.15 G(re either on or of)140.73 162 Q
+(f, and do not ha)-.25 E .3 -.15(ve a)-.2 H 2.5(na).15 G(ssociated v)298.14 162
+Q(alue.)-.25 E(Options apply to both)102 180 Q/F2 10/Courier-Bold@0 SF(ex)2.5 E
+F0(and)2.5 E F2(vi)2.5 E F0(modes, unless otherwise speci\214ed.)2.5 E F1
+(altwerase [off])102 204 Q F2(Vi)131 216 Q F0(only)2.5 E 5(.S)-.65 G
+(elect an alternate w)175.69 216 Q(ord erase algorithm.)-.1 E F1
+(autoindent, ai [off])102 228 Q F0(Automatically indent ne)131 240 Q 2.5(wl)
+-.25 G(ines.)239.91 240 Q F1(autoprint, ap [off])102 252 Q F2(Ex)131 264 Q F0
+(only)2.5 E 5(.D)-.65 G(isplay the current line automatically)177.35 264 Q(.)
+-.65 E F1(auto)102 276 Q(write, aw [off])-.1 E F0
+(Write modi\214ed \214les automatically when changing \214les.)131 288 Q F1
+(beautify)102 300 Q 2.5(,b)-.55 G 2.5(f[)147.01 300 S(off])156.17 300 Q F0
+(Discard control characters.)131 312 Q F1(cdpath [en)102 324 Q(vir)-.4 E
+(onment v)-.18 E(ariable CDP)-.1 E -.95(AT)-.74 G(H, or curr).95 E(ent dir)-.18
+E(ectory])-.18 E F0(The directory paths used as path pre\214x)131 336 Q
+(es for the)-.15 E F1(cd)2.5 E F0(command.)2.5 E F1(columns, co [80])102 348 Q
+F0(Set the number of columns in the screen.)131 360 Q F1(comment [off])102 372
+Q F2(Vi)131 384 Q F0(only)2.5 E 5(.S)-.65 G(kip leading comments in \214les.)
+175.69 384 Q F1(dir)102 396 Q(ectory)-.18 E 2.5(,d)-.55 G(ir [en)151.26 396 Q
+(vir)-.4 E(onment v)-.18 E(ariable TMPDIR, or /tmp])-.1 E F0
+(The directory where temporary \214les are created.)131 408 Q F1
+(edcompatible, ed [off])102 420 Q F0 .279(Remember the v)131 432 R .279
+(alues of the `)-.25 F(`c')-.74 E 2.779('a)-.74 G .279(nd `)270.344 432 R(`g')
+-.74 E 2.779('s)-.74 G(uf)306.632 432 Q .279(\214ces to the)-.25 F F1
+(substitute)2.78 E F0 .28(commands, instead of initializing)2.78 F
+(them as unset for each ne)131 444 Q 2.5(wc)-.25 G(ommand.)246.27 444 Q F1(err)
+102 456 Q(orbells, eb [off])-.18 E F2(Ex)131 468 Q F0(only)2.5 E 5(.A)-.65 G
+(nnounce error messages with a bell.)177.35 468 Q F1(exr)102 480 Q(c, ex [off])
+-.18 E F0(Ne)131 492 Q -.15(ve)-.25 G 2.5(rr).15 G
+(ead startup \214les in the local directory)160.86 492 Q(.)-.65 E F1
+(extended [off])102 504 Q F0(Re)131 516 Q(gular e)-.15 E(xpressions are e)-.15
+E(xtended \(i.e.)-.15 E/F3 10/Courier@0 SF(egrep)5 E F0(\(1\) style\) e)A
+(xpressions.)-.15 E F1(\215ash [on])102 528 Q F0
+(Flash the screen instead of beeping the k)131 540 Q -.15(ey)-.1 G
+(board on error).15 E(.)-.55 E F1(hardtabs, ht [8])102 552 Q F0
+(Set the spacing between hardw)131 564 Q(are tab settings.)-.1 E F1(ignor)102
+576 Q(ecase, ic [off])-.18 E F0(Ignore case dif)131 588 Q(ferences in re)-.25 E
+(gular e)-.15 E(xpressions.)-.15 E F1 -.1(ke)102 600 S(ytime [6]).1 E F0
+(The 10th')131 612 Q 2.5(so)-.55 G 2.5(fas)181 612 S(econd)197.66 612 Q F2
+(ex/vi)2.5 E F0 -.1(wa)2.5 G(its for a subsequent k).1 E .3 -.15(ey t)-.1 H 2.5
+(oc).15 G(omplete a k)379.5 612 Q .3 -.15(ey m)-.1 H(apping.).15 E F1
+(leftright [off])102 624 Q F2(Vi)131 636 Q F0(only)2.5 E 5(.D)-.65 G 2.5(ol)
+177.35 636 S(eft-right scrolling.)187.63 636 Q F1(lines, li [24])102 648 Q F2
+(Vi)131 660 Q F0(only)2.5 E 5(.S)-.65 G(et the number of lines in the screen.)
+175.69 660 Q F1(lisp [off])102 672 Q F2(Vi)131 684 Q F0(only)2.5 E 5(.M)-.65 G
+(odify v)179.02 684 Q(arious search commands and options to w)-.25 E
+(ork with Lisp.)-.1 E 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(10)530 750 Q
+EP
+%%Page: 11 11
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Italic@0 SF
+(This option is not yet implemented.)131 96 Q/F2 10/Times-Bold@0 SF(list [off])
+102 108 Q F0(Display lines in an unambiguous f)131 120 Q(ashion.)-.1 E F2
+(magic [on])102 132 Q F0 -.35(Tr)131 144 S
+(eat certain characters specially in re).35 E(gular e)-.15 E(xpressions.)-.15 E
+F2(matchtime [7])102 156 Q/F3 10/Courier-Bold@0 SF(Vi)131 168 Q F0(only)2.885 E
+5.385(.T)-.65 G .385(he 10th')177.01 168 R 2.885(so)-.55 G 2.885(fas)221.67 168
+S(econd)239.1 168 Q F3(ex/vi)2.884 E F0 .384
+(pauses on the matching character when the)2.884 F F2(sho)2.884 E(wmatch)-.1 E
+F0(op-)2.884 E(tion is set.)131 180 Q F2(mesg [on])102 192 Q F0
+(Permit messages from other users.)131 204 Q F2(modelines, modeline [off])102
+216 Q F0(Read the \214rst and last fe)131 228 Q 2.5(wl)-.25 G
+(ines of each \214le for)240.18 228 Q F3(ex)2.5 E F0(commands.)2.5 E F1
+(This option will ne)131 246 Q(ver be implemented.)-.15 E F2(number)102 258 Q
+2.5(,n)-.92 G 2.5(u[)145.53 258 S(off])156.92 258 Q F0
+(Precede each line displayed with its current line number)131 270 Q(.)-.55 E F2
+(octal [off])102 282 Q F0(Display unkno)131 294 Q
+(wn characters as octal numbers, instead of the def)-.25 E(ault he)-.1 E
+(xadecimal.)-.15 E F2(open [on])102 306 Q F3(Ex)131 318 Q F0(only)2.5 E 5(.I)
+-.65 G 2.5(ft)173.46 318 S(his option is not set, the)182.07 318 Q F2(open)2.5
+E F0(and)2.5 E F2(visual)2.5 E F0(commands are disallo)2.5 E(wed.)-.25 E F2
+(optimize, opt [on])102 330 Q F3(Vi)131 342 Q F0(only)2.5 E 5(.O)-.65 G
+(ptimize te)177.35 342 Q(xt throughput to dumb terminals.)-.15 E F1
+(This option is not yet implemented.)131 360 Q F2
+(paragraphs, para [IPLPPPQPP LIpplpipbp])102 372 Q F3(Vi)131 384 Q F0(only)2.5
+E 5(.D)-.65 G(e\214ne additional paragraph boundaries for the)177.35 384 Q F2
+({)2.5 E F0(and)2.5 E F2(})2.5 E F0(commands.)2.5 E F2(pr)102 396 Q(ompt [on])
+-.18 E F3(Ex)131 408 Q F0(only)2.5 E 5(.D)-.65 G(isplay a command prompt.)
+177.35 408 Q F2 -.18(re)102 420 S(adonly).18 E 2.5(,r)-.55 G 2.5(o[)148.31 420
+S(off])159.14 420 Q F0(Mark the \214le as read-only)131 432 Q(.)-.65 E F2 -.18
+(re)102 444 S(cdir [/v).18 E(ar/tmp/vi.r)-.1 E(eco)-.18 E -.1(ve)-.1 G(r]).1 E
+F0(The directory where reco)131 456 Q -.15(ve)-.15 G(ry \214les are stored.).15
+E F2 -.18(re)102 468 S(draw).18 E 2.5(,r)-.55 G 2.5(e[)141.63 468 S(off])151.9
+468 Q F3(Vi)131 480 Q F0(only)2.5 E 5(.S)-.65 G
+(imulate an intelligent terminal on a dumb one.)175.69 480 Q F1
+(This option is not yet implemented.)131 498 Q F2 -.18(re)102 510 S(map [on])
+.18 E F0(Remap k)131 522 Q -.15(ey)-.1 G 2.5(su).15 G(ntil resolv)187.41 522 Q
+(ed.)-.15 E F2 -.18(re)102 534 S(port [5]).18 E F0
+(Set the number of lines about which the editor reports changes or yanks.)131
+546 Q F2(ruler [off])102 558 Q F3(Vi)131 570 Q F0(only)2.5 E 5(.D)-.65 G
+(isplay a ro)177.35 570 Q(w/column ruler on the colon command line.)-.25 E F2
+(scr)102 582 Q(oll, scr [windo)-.18 E 2.5(w/2)-.1 G(])194.77 582 Q F0
+(Set the number of lines scrolled.)131 594 Q F2(sections, sect [NHSHH HUnhsh])
+102 606 Q F3(Vi)131 618 Q F0(only)2.5 E 5(.D)-.65 G
+(e\214ne additional section boundaries for the)177.35 618 Q F2([[)2.5 E F0(and)
+2.5 E F2(]])2.5 E F0(commands.)2.5 E F2(shell, sh [en)102 630 Q(vir)-.4 E
+(onment v)-.18 E(ariable SHELL, or /bin/sh])-.1 E F0
+(Select the shell used by the editor)131 642 Q(.)-.55 E F2(shiftwidth, sw [8])
+102 654 Q F0(Set the autoindent and shift command indentation width.)131 666 Q
+F2(sho)102 678 Q(wdirty [off])-.1 E F0 172.465(4.4BSD July)72 750 R(15, 1994)
+2.5 E(11)530 750 Q EP
+%%Page: 12 12
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Courier-Bold@0 SF(Vi)131 96
+Q F0(only)2.5 E 5(.D)-.65 G(isplay an asterisk on the colon command line if th\
+e \214le has been modi\214ed.)177.35 96 Q/F2 10/Times-Bold@0 SF(sho)102 108 Q
+(wmatch, sm [off])-.1 E F1(Vi)131 120 Q F0(only)2.5 E 5(.N)-.65 G
+(ote matching `)177.35 120 Q(`{')-.74 E 2.5('a)-.74 G(nd `)255.37 120 Q(`\(')
+-.74 E 2.5('f)-.74 G(or `)288.87 120 Q(`}')-.74 E 2.5('a)-.74 G(nd `)323.28 120
+Q(`\)')-.74 E 2.5('c)-.74 G(haracters.)357.89 120 Q F2(sho)102 132 Q
+(wmode [off])-.1 E F1(Vi)131 144 Q F0(only)2.5 E 5(.D)-.65 G
+(isplay the current editor mode \(command or input\).)177.35 144 Q F2(sidescr)
+102 156 Q(oll [16])-.18 E F1(Vi)131 168 Q F0(only)2.5 E 5(.S)-.65 G
+(et the amount a left-right scroll will shift.)175.69 168 Q F2(slo)102 180 Q
+-.1(wo)-.1 G(pen, slo).1 E 2.5(w[)-.1 G(off])170.87 180 Q F0
+(Delay display updating during te)131 192 Q(xt input.)-.15 E/F3 10
+/Times-Italic@0 SF(This option is not yet implemented.)131 210 Q F2(sour)102
+222 Q(ceany [off])-.18 E F0(Read startup \214les not o)131 234 Q
+(wned by the current user)-.25 E(.)-.55 E F3(This option will ne)131 252 Q
+(ver be implemented.)-.15 E F2(tabstop, ts [8])102 264 Q F0
+(This option sets tab widths for the editor display)131 276 Q(.)-.65 E F2
+(taglength, tl [0])102 288 Q F0
+(Set the number of signi\214cant characters in tag names.)131 300 Q F2
+(tags, tag [tags /v)102 312 Q(ar/db/libc.tags /sys/k)-.1 E(er)-.1 E(n/tags])
+-.15 E F0(Set the list of tags \214les.)131 324 Q F2(term, ttytype, tty [en)102
+336 Q(vir)-.4 E(onment v)-.18 E(ariable TERM])-.1 E F0(Set the terminal type.)
+131 348 Q F2(terse [off])102 360 Q F0 .759
+(This option has historically made editor messages less v)131 372 R 3.259
+(erbose. It)-.15 F .76(has no ef)3.259 F .76(fect in this implementa-)-.25 F
+(tion.)131 384 Q F2(tildeop)102 396 Q F0(Modify the)131 408 Q F2(~)2.5 E F0
+(command to tak)2.5 E 2.5(ea)-.1 G 2.5(na)259.77 408 S(ssociated motion.)271.71
+408 Q F2(timeout, to [on])102 420 Q F0 -.35(Ti)131 432 S(me out on k).35 E -.15
+(ey)-.1 G 2.5(sw).15 G(hich may be mapped.)209.84 432 Q F2(ttywerase [off])102
+444 Q F1(Vi)131 456 Q F0(only)2.5 E 5(.S)-.65 G
+(elect an alternate erase algorithm.)175.69 456 Q F2 -.1(ve)102 468 S
+(rbose [off]).1 E F0(only)131 480 Q 5(.D)-.65 G(isplay an error message for e)
+162.85 480 Q -.15(ve)-.25 G(ry error).15 E(.)-.55 E F2(w300 [no default])102
+492 Q F1(Vi)131 504 Q F0(only)2.5 E 5(.S)-.65 G(et the windo)175.69 504 Q 2.5
+(ws)-.25 G(ize if the baud rate is less than 1200 baud.)238.49 504 Q F2
+(w1200 [no default])102 516 Q F1(Vi)131 528 Q F0(only)2.5 E 5(.S)-.65 G
+(et the windo)175.69 528 Q 2.5(ws)-.25 G
+(ize if the baud rate is equal to 1200 baud.)238.49 528 Q F2
+(w9600 [no default])102 540 Q F1(Vi)131 552 Q F0(only)2.5 E 5(.S)-.65 G
+(et the windo)175.69 552 Q 2.5(ws)-.25 G
+(ize if the baud rate is greater than 1200 baud.)238.49 552 Q F2(war)102 564 Q
+2.5(n[)-.15 G(on])129.9 564 Q F1(Ex)131 576 Q F0(only)2.979 E 5.479(.T)-.65 G
+.479(his option causes a w)177.198 576 R .479
+(arning message to the terminal if the \214le has been modi\214ed, since it)-.1
+F -.1(wa)131 588 S 2.5(sl).1 G(ast written, before a)151.73 588 Q F2(!)2.5 E F0
+(command.)2.5 E F2(windo)102 600 Q 1.1 -.55(w, w, w)-.1 H 2.5(i[).55 G(en)
+167.19 600 Q(vir)-.4 E(onment v)-.18 E(ariable LINES])-.1 E F0(Set the windo)
+131 612 Q 2.5(ws)-.25 G(ize for the screen.)199.36 612 Q F2(wrapmar)102 624 Q
+(gin, wm [0])-.1 E F1(Vi)131 636 Q F0(only)2.5 E 5(.B)-.65 G
+(reak lines automatically when the)176.8 636 Q 2.5(yr)-.15 G
+(each the right-hand mar)321.9 636 Q(gin.)-.18 E F2(wrapscan, ws [on])102 648 Q
+F0(Set searches to wrap around the end or be)131 660 Q(ginning of the \214le.)
+-.15 E F2(writeany)102 672 Q 2.5(,w)-.55 G 2.5(a[)151.44 672 S(off])162.27 672
+Q F0 -.45(Tu)131 684 S(rn of).45 E 2.5<668c>-.25 G(le-o)171.96 684 Q -.15(ve)
+-.15 G(rwriting checks.).15 E 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(12)
+530 750 Q EP
+%%Page: 13 13
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Bold@0 SF(ENVIR)72 96
+Q(ONMENT)-.3 E 1.666(AL V)-.9 F(ARIABLES)-1.35 E/F2 10/Courier@0 SF(COLUMNS)102
+108 Q F0 .895(The number of columns on the screen.)161 108 R .896(This v)5.896
+F .896(alue o)-.25 F -.15(ve)-.15 G .896(rrides an).15 F 3.396(ys)-.15 G .896
+(ystem or terminal speci\214c)433.712 108 R -.25(va)161 120 S 5.317(lues. If)
+.25 F 2.816(the COLUMNS en)5.317 F 2.816(vironmental v)-.4 F 2.816
+(ariable is not set when)-.25 F/F3 10/Courier-Bold@0 SF(ex/vi)5.316 E F0 2.816
+(runs, or the)5.316 F F1(columns)161 132 Q F0(option is e)2.5 E
+(xplicitly reset by the user)-.15 E(,)-.4 E F3(ex/vi)2.5 E F0(enters the v)2.5
+E(alue into the en)-.25 E(vironment.)-.4 E F2(EXINIT)102 144 Q F0 2.5(Al)161
+144 S(ist of)173.5 144 Q F3(ex)2.5 E F0(startup commands, read if the v)2.5 E
+(ariable)-.25 E F2(NEXINIT)2.5 E F0(is not set.)2.5 E F2(HOME)102 156 Q F0 .677
+(The user')161 156 R 3.177(sh)-.55 G .677(ome directory)211.234 156 R 3.177(,u)
+-.65 G .678(sed as the initial directory path for the startup)277.758 156 R F2
+($HOME/.nexrc)3.178 E F0(and)161 168 Q F2($HOME/.exrc)2.865 E F0 2.865
+(\214les. This)2.865 F -.25(va)2.865 G .365(lue is also used as the def).25 F
+.365(ault directory for the)-.1 F F3(vi)2.865 E F1(cd)2.865 E F0(com-)2.865 E
+(mand.)161 180 Q F2(LINES)102 192 Q F0 .629(The number of ro)161 192 R .629
+(ws on the screen.)-.25 F .629(This v)5.629 F .629(alue o)-.25 F -.15(ve)-.15 G
+.629(rrides an).15 F 3.13(ys)-.15 G .63(ystem or terminal speci\214c v)416.08
+192 R(al-)-.25 E 3.123(ues. If)161 204 R .623(the LINES en)3.123 F .623
+(vironmental v)-.4 F .623(ariable is not set when)-.25 F F3(ex/vi)3.122 E F0
+.622(runs, or the)3.122 F F1(lines)3.122 E F0 .622(option is)3.122 F -.15(ex)
+161 216 S(plicitly reset by the user).15 E(,)-.4 E F3(ex/vi)2.5 E F0
+(enters the v)2.5 E(alue into the en)-.25 E(vironment.)-.4 E F2(NEXINIT)102 228
+Q F0 2.5(Al)161 228 S(ist of)173.5 228 Q F3(ex)2.5 E F0(startup commands.)2.5 E
+F2(SHELL)102 240 Q F0(The user')161 240 Q 2.5(ss)-.55 G
+(hell of choice \(see also the)208.77 240 Q F1(shell)2.5 E F0(option\).)2.5 E
+F2(TERM)102 252 Q F0 1.338(The user')161 252 R 3.838(st)-.55 G 1.338
+(erminal type.)210.336 252 R 1.338(The def)6.338 F 1.338(ault is the type `)-.1
+F(`unkno)-.74 E(wn')-.25 E 1.339('. If the TERM en)-.74 F(vironmental)-.4 E
+-.25(va)161 264 S .106(riable is not set when).25 F F3(ex/vi)2.606 E F0 .105
+(runs, or the)2.605 F F1(term)2.605 E F0 .105(option is e)2.605 F .105
+(xplicitly reset by the user)-.15 F(,)-.4 E F3(ex/vi)2.605 E F0(enters the v)
+161 276 Q(alue into the en)-.25 E(vironment.)-.4 E F2(TMPDIR)102 288 Q F0
+(The location used to stored temporary \214les \(see also the)161 288 Q F1(dir)
+2.5 E(ectory)-.18 E F0(option\).)2.5 E F1(ASYNCHR)72 312 Q 1.666(ONOUS EVENTS)
+-.3 F F0(SIGALRM)102 324 Q F3(Vi/ex)167 324 Q F0 1.58(uses this signal for per\
+iodic backups of \214le modi\214cations and to display `)4.08 F(`b)-.74 E(usy')
+-.2 E(')-.74 E(messages when operations are lik)167 336 Q(ely to tak)-.1 E 2.5
+(eal)-.1 G(ong time.)354.54 336 Q(SIGHUP)102 348 Q 18.61(SIGTERM If)102 360 R
+.12(the current b)2.62 F(uf)-.2 E .12(fer has changed since it w)-.25 F .12
+(as last written in its entirety)-.1 F 2.62(,t)-.65 G .12
+(he editor attempts to)457.7 360 R(sa)167 372 Q .493 -.15(ve t)-.2 H .193
+(he modi\214ed \214le so it can be later reco).15 F -.15(ve)-.15 G 2.693
+(red. See).15 F(the)2.694 E F3(vi/ex)2.694 E F0 .194(Reference manual section)
+2.694 F(entitled `)167 384 Q(`Reco)-.74 E -.15(ve)-.15 G(ry').15 E 2.5('f)-.74
+G(or more information.)255.19 384 Q 29.73(SIGINT When)102 396 R .594(an interr\
+upt occurs, the current operation is halted, and the editor returns to the com\
+-)3.094 F .364(mand le)167 408 R -.15(ve)-.25 G 2.864(l. If).15 F .364
+(interrupted during te)2.864 F .364(xt input, the te)-.15 F .364
+(xt already input is resolv)-.15 F .365(ed into the \214le as)-.15 F(if the te)
+167 420 Q(xt input had been normally terminated.)-.15 E 12.51(SIGWINCH The)102
+432 R 2.772(screen is resized.)5.272 F 2.772(See the)7.772 F F3(vi/ex)5.272 E
+F0 2.771(Reference manual section entitled `)5.272 F 2.771(`Sizing the)-.74 F
+(Screen')167 444 Q 2.5('f)-.74 G(or more information.)205.96 444 Q(SIGCONT)102
+456 Q(SIGQ)102 468 Q(UIT)-.1 E(SIGTSTP)102 480 Q F3(Vi/ex)167 480 Q F0
+(ignores these signals.)2.5 E F1 -.1(BU)72 504 S(GS).1 E F0(See the \214le)102
+516 Q F2(nvi/docs/bugs.current)2.5 E F0(for a list of the kno)2.5 E(wn b)-.25 E
+(ugs in this v)-.2 E(ersion.)-.15 E F1(FILES)72 540 Q F2(/bin/sh)102 552 Q F0
+(The def)221 552 Q(ault user shell.)-.1 E F2(/etc/vi.exrc)102 564 Q F0
+(System-wide vi startup \214le.)221 564 Q F2(/tmp)102 576 Q F0 -.7(Te)221 576 S
+(mporary \214le directory).7 E(.)-.65 E F2(/var/tmp/vi.recover)102 588 Q F0
+(The def)5 E(ault reco)-.1 E -.15(ve)-.15 G(ry \214le directory).15 E(.)-.65 E
+F2($HOME/.nexrc)102 600 Q F0(1st choice for user')221 600 Q 2.5(sh)-.55 G
+(ome directory startup \214le.)308.76 600 Q F2($HOME/.exrc)102 612 Q F0
+(2nd choice for user')221 612 Q 2.5(sh)-.55 G(ome directory startup \214le.)
+312.09 612 Q F2(.nexrc)102 624 Q F0
+(1st choice for local directory startup \214le.)221 624 Q F2(.exrc)102 636 Q F0
+(2nd choice for local directory startup \214le.)221 636 Q F1 1.666(SEE ALSO)72
+660 R F2(ctags)102 672 Q F0(\(1\),)A F2(more)5 E F0(\(1\),)A F2(curses)5 E F0
+(\(3\),)A F2(dbopen)5 E F0(\(3\))A(The `)102 696 Q(`V)-.74 E 2.5(iQ)-.6 G
+(uick Reference')145.09 696 Q 2.5('c)-.74 G(ard.)218.2 696 Q 172.465
+(4.4BSD July)72 750 R(15, 1994)2.5 E(13)530 750 Q EP
+%%Page: 14 14
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R -.74(``)102 96 S
+(An Introduction to Display Editing with V).74 E(i')-.6 E(', found in the `)
+-.74 E(`UNIX User')-.74 E 2.5(sM)-.55 G(anual Supplementary)412.2 96 Q
+(Documents')102 108 Q 2.5('s)-.74 G
+(ection of both the 4.3BSD and 4.4BSD manual sets.)159.86 108 Q
+(This document is the closest thing a)5 E -.25(va)-.2 G(il-).25 E
+(able to an introduction to the)102 120 Q/F1 10/Courier-Bold@0 SF(vi)2.5 E F0
+(screen editor)2.5 E(.)-.55 E -.74(``)102 144 S(Ex Reference Manual \(V).74 E
+(ersion 3.7\)')-1.11 E(', found in the `)-.74 E(`UNIX User')-.74 E 2.5(sM)-.55
+G(anual Supplementary Documents')381.92 144 Q 2.5('s)-.74 G(ec-)526.99 144 Q
+(tion of both the 4.3BSD and 4.4BSD manual sets.)102 156 Q
+(This document is the \214nal reference for the)5 E F1(ex)2.5 E F0(editor)2.5 E
+2.5(,a)-.4 G(s)528 156 Q(distrib)102 168 Q
+(uted in most historic 4BSD and System V systems.)-.2 E -.74(``)102 192 S
+(Edit: A tutorial').74 E(', found in the `)-.74 E(`UNIX User')-.74 E 2.5(sM)
+-.55 G(anual Supplementary Documents')300.58 192 Q 2.5('s)-.74 G
+(ection of the 4.3BSD)445.65 192 Q(manual set.)102 204 Q
+(This document is an introduction to a simple v)5 E(ersion of the)-.15 E F1(ex)
+2.5 E F0(screen editor)2.5 E(.)-.55 E -.74(``)102 228 S(Ex/V).74 E 2.5(iR)-.6 G
+(eference Manual')140.38 228 Q(', found in the `)-.74 E(`UNIX User')-.74 E 2.5
+(sM)-.55 G(anual Supplementary Documents')339.39 228 Q 2.5('s)-.74 G
+(ection of the)484.46 228 Q(4.4BSD manual set.)102 240 Q
+(This document is the \214nal reference for the)5 E F1(nex/nvi)2.5 E F0(te)2.5
+E(xt editors, as distrib)-.15 E(uted in)-.2 E(4.4BSD and 4.4BSD-Lite.)102 252 Q
+F1(Roff)102 270 Q F0(source for all of these documents is distrib)2.5 E
+(uted with)-.2 E F1(nex/nvi)2.5 E F0(in the)2.5 E/F2 10/Courier@0 SF
+(nvi/USD.doc)2.5 E F0(directory of the)2.5 E F1(nex/nvi)102 282 Q F0
+(source code.)2.5 E(The \214les `)102 306 Q(`auto)-.74 E(write')-.25 E(', `)
+-.74 E(`input')-.74 E(', `)-.74 E(`quoting')-.74 E(', and `)-.74 E
+(`structures')-.74 E(', found in the)-.74 E F2(nvi/docs/internals)2.5 E F0
+(direc-)2.5 E(tory of the)102 318 Q F1(nex/nvi)2.5 E F0(source code.)2.5 E/F3
+10/Times-Bold@0 SF(HIST)72 342 Q(OR)-.18 E(Y)-.35 E F0(The)102 354 Q F1
+(nex/nvi)2.5 E F0(replacements for the)2.5 E F1(ex/vi)2.5 E F0
+(editor \214rst appeared in 4.4BSD.)2.5 E F3(ST)72 378 Q(AND)-.9 E(ARDS)-.35 E
+F1(Nex/nvi)102 390 Q F0 .1(is close to IEEE Std1003.2 \(`)2.6 F(`POSIX')-.74 E
+2.6('\). That)-.74 F .1(document dif)2.6 F .1(fers from historical)-.25 F F1
+(ex/vi)2.6 E F0 .1(practice in)2.6 F(se)102 402 Q -.15(ve)-.25 G
+(ral places; there are changes to be made on both sides.).15 E 172.465
+(4.4BSD July)72 750 R(15, 1994)2.5 E(14)530 750 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/usr.bin/vi/USD.doc/vi.man/vi.1 b/usr.bin/vi/USD.doc/vi.man/vi.1
new file mode 100644
index 000000000000..25f2a2ce0f3b
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.man/vi.1
@@ -0,0 +1,1294 @@
+.\" 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.1 8.12 (Berkeley) 7/15/94
+.\"
+.Dd "July 15, 1994"
+.Dt EX/VI 1
+.Os
+.Sh NAME
+.Nm ex, vi, view
+.Nd text editors
+.Sh SYNOPSIS
+.Nm \&ex
+.Op Fl eFRrsv
+.Op Fl c Ar cmd
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.\".Op Fl X Ar \&aw
+.Op Ar "file ..."
+.Nm \&vi
+.Op Fl eFRrv
+.Op Fl c Ar cmd
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.\".Op Fl X Ar \&aw
+.Op Ar "file ..."
+.Nm view
+.Op Fl eFRrv
+.Op Fl c Ar cmd
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.\".Op Fl X Ar \&aw
+.Op Ar "file ..."
+.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 manual page is the one provided with the
+.Nm nex/nvi
+versions of the
+.Nm ex/vi
+text editors.
+.Nm Nex/nvi
+are intended as bug-for-bug compatible replacements for the original
+Fourth Berkeley Software Distribution (4BSD)
+.Nm \&ex
+and
+.Nm \&vi
+programs.
+For the rest of this manual page,
+.Nm nex/nvi
+is used only when it's necessary to distinguish it from the historic
+implementations of
+.Nm ex/vi .
+.Pp
+This manual page is intended for users already familiar with
+.Nm ex/vi .
+Anyone else should almost certainly read a good tutorial on the
+editor before this manual page.
+If you're in an unfamiliar environment, and you absolutely have to
+get work done immediately, read the section after the options
+description, entitled
+.Dq "Fast Startup" .
+It's probably enough to get you going.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl c
+Execute
+.Ar cmd
+immediately after starting the edit session.
+Particularly useful for initial positioning in the file, however
+.Ar cmd
+is not limited to positioning commands.
+This is the POSIX 1003.2 interface for the historic
+.Dq "+cmd"
+syntax.
+.Nm Nex/nvi
+supports both the old and new syntax.
+.It Fl e
+Start editing in ex mode, as if the command name were
+.Nm \&ex .
+.It Fl F
+Don't copy the entire file when first starting to edit.
+(The default is to make a copy in case someone else modifies
+the file during your edit session.)
+.It Fl R
+Start editing in read-only mode, as if the command name was
+.Nm view ,
+or the readonly option was set.
+.It Fl r
+Recover the specified files, or, if no files are specified,
+list the files that could be recovered.
+If no recoverable files by the specified name exist,
+the file is edited as if the
+.Fl r
+option had not been specified.
+.It Fl s
+Enter batch mode; applicable only to
+.Nm \&ex
+edit sessions.
+Batch mode is useful when running
+.Nm \&ex
+scripts.
+Prompts, informative messages and other user oriented message
+are turned off,
+and no startup files or environmental variables are read.
+This is the POSIX 1003.2 interface for the historic
+.Dq \&\-
+argument.
+.Nm \&Nex/nvi
+supports both the old and new syntax.
+.It Fl t
+Start editing at the specified tag.
+(See
+.Xr ctags 1 ).
+.It Fl w
+Set the initial window size to the specified number of lines.
+.It Fl v
+Start editing in vi mode, as if the command name was
+.Nm \&vi
+or
+.Nm view .
+.It Fl X
+Reserved for X11 interfaces.
+.Em "No X11 support is currently implemented."
+.El
+.Pp
+Command input for
+.Nm ex/vi
+is read from the standard input.
+In the
+.Nm \&vi
+interface, it is an error if standard input is not a terminal.
+In the
+.Nm \&ex
+interface, if standard input is not a terminal,
+.Nm \&ex
+will read commands from it regardless, however, the session will be a
+batch mode session, exactly as if the
+.Fl s
+option had been specified.
+.Pp
+.Nm Ex/vi
+exits 0 on success, and greater than 0 if an error occurs.
+.Sh FAST STARTUP
+This section will tell you the minimum amount that you need to
+do simple editing tasks using
+.Nm \&vi .
+If you've never used any screen editor before, you're likely to have
+problems even with this simple introduction.
+In that case you should find someone that already knows
+.Nm \&vi
+and have them walk you through this section.
+.Pp
+.Nm \&Vi
+is a screen editor.
+This means that it takes up almost the entire screen, displaying part
+of the file on each screen line, except for the last line of the screen.
+The last line of the screen is used for you to give commands to
+.Nm \&vi ,
+and for
+.Nm \&vi
+to give information to you.
+.Pp
+The other fact that you need to understand is that
+.Nm \&vi
+is a modeful editor, i.e. you are either entering text or you
+are executing commands, and you have to be in the right mode
+to do one or the other.
+You will be in command mode when you first start editing a file.
+There are commands that switch you into input mode.
+There is only one key that takes you out of input mode,
+and that is the <escape> key.
+(Key names are written using less-than and greater-than signs, e.g.
+<escape> means the
+.Dq escape
+key, usually labeled
+.Dq esc
+on your terminal's keyboard.)
+If you're ever confused as to which mode you're in,
+keep entering the <escape> key until
+.Nm \&vi
+beeps at you.
+(Generally,
+.Nm \&vi
+will beep at you if you try and do something that's not allowed.
+It will also display error messages.)
+.Pp
+To start editing a file, enter the command
+.Dq Li "vi file_name<carriage-return>" .
+The command you should enter as soon as you start editing is
+.Dq Li ":set verbose showmode<carriage-return>" .
+This will make the editor give you verbose error messages and display
+the current mode at the bottom of the screen.
+.Pp
+The commands to move around the file are:
+.Bl -tag -width XXXX -compact
+.It Sy h
+Move the cursor left one character.
+.It Sy j
+Move the cursor down one line.
+.It Sy k
+Move the cursor up one line.
+.It Sy l
+Move the cursor right one character.
+.It Sy <cursor-arrows>
+The cursor arrow keys should work, too.
+.It Sy /text<carriage-return>
+Search for the string
+.Dq text
+in the file, and move the cursor to its first character.
+.El
+.Pp
+The commands to enter new text are:
+.Bl -tag -width XXXX -compact
+.It Sy a
+Append new text,
+.Em after
+the cursor.
+.It Sy i
+Insert new text,
+.Em before
+the cursor.
+.It Sy o
+Open a new line below the line the cursor is on, and start
+entering text.
+.It Sy O
+Open a new line above the line the cursor is on, and start
+entering text.
+.It Sy <escape>
+Once you've entered input mode using the one of the
+.Sy \&a ,
+.Sy \&i ,
+.Sy \&O ,
+or
+.Sy \&o
+commands, use
+.Sy <escape>
+to quit entering text and return to command mode.
+.El
+.Pp
+The commands to copy text are:
+.Bl -tag -width XXXX -compact
+.It Sy yy
+Copy the line the cursor is on.
+.It Sy p
+Append the copied line after the line the cursor is on.
+.El
+.Pp
+The commands to delete text are:
+.Bl -tag -width XXXX -compact
+.It Sy dd
+Delete the line the cursor is on.
+.It Sy x
+Delete the character the cursor is on.
+.El
+.Pp
+The commands to write the file are:
+.Bl -tag -width XXXX -compact
+.It Sy :w<carriage-return>
+Write the file back to the file with the name that you originally used
+as an argument on the
+.Nm \&vi
+command line.
+.It Sy :w file_name<carriage-return>
+Write the file back to the file with the name
+.Dq file_name .
+.El
+.Pp
+The commands to quit editing and exit the editor are:
+.Bl -tag -width XXXX -compact
+.It Sy :q<carriage-return>
+Quit editing and leave vi (if you've modified the file, but not
+saved your changes,
+.Nm \&vi
+will refuse to quit).
+.It Sy :q!<carriage-return>
+Quit, discarding any modifications that you may have made.
+.El
+.Pp
+One final caution.
+Unusual characters can take up more than one column on the screen,
+and long lines can take up more than a single screen line.
+The above commands work on
+.Dq physical
+characters and lines, i.e. they affect the entire line no matter
+how many screen lines it takes up and the entire character no matter
+how many screen columns it takes up.
+.Sh VI COMMANDS
+The following section describes the commands available in the command
+mode of the
+.Nm \&vi
+editor.
+In each entry below, the tag line is a usage synopsis for the command
+character.
+.sp
+.Bl -tag -width "XXXX" -compact
+.It Sy "[count] <control-A>"
+Search forward
+.Li count
+times for the current word.
+.It Sy "[count] <control-B>"
+Page backwards
+.Li count
+screens.
+.It Sy "[count] <control-D>"
+Scroll forward
+.Li count
+lines.
+.It Sy "[count] <control-E>"
+Scroll forward
+.Li count
+lines, leaving the current line and column as is, if possible.
+.It Sy "[count] <control-F>"
+Page forward
+.Li count
+screens.
+.It Sy "<control-G>"
+Display the file information.
+.It Sy "<control-H>"
+.It Sy "[count] h"
+Move the cursor back
+.Li count
+characters in the current line.
+.It Sy "[count] <control-J>"
+.It Sy "[count] <control-N>"
+.It Sy "[count] j"
+Move the cursor down
+.Li count
+lines without changing the current column.
+.It Sy "<control-L>"
+.It Sy "<control-R>"
+Repaint the screen.
+.It Sy "[count] <control-M>"
+.It Sy "[count] +"
+Move the cursor down
+.Li count
+lines to the first nonblank character of that line.
+.It Sy "[count] <control-P>"
+.It Sy "[count] k"
+Move the cursor up
+.Li count
+lines, without changing the current column.
+.It Sy "<control-T>"
+Return to the most recent tag context.
+.It Sy "<control-U>"
+Scroll backwards
+.Li count
+lines.
+.It Sy "<control-W>"
+Switch to the next lower screen in the window, or, to the first
+screen if there are no lower screens in the window.
+.It Sy "<control-Y>"
+Scroll backwards
+.Li count
+lines, leaving the current line and column as is, if possible.
+.It Sy "<control-Z>"
+Suspend the current editor session.
+.It Sy "<escape>"
+Execute
+.Nm \&ex
+commands or cancel partial commands.
+.It Sy "<control-]>"
+Push a tag reference onto the tag stack.
+.It Sy "<control-^>"
+Switch to the most recently edited file.
+.It Sy "[count] <space>"
+.It Sy "[count] l"
+Move the cursor forward
+.Li count
+characters without changing the current line.
+.It Sy "[count] ! motion shell-argument(s)"
+Replace text with results from a shell command.
+.It Sy "[count] # +|-|#"
+Increment or decrement the cursor number.
+.It Sy "[count] $"
+Move the cursor to the end of a line.
+.It Sy "%"
+Move to the matching character.
+.It Sy "&"
+Repeat the previous substitution command on the current line.
+.It Sy "'<character>"
+.It Sy "`<character>"
+Return to a context marked by the character
+.Li <character> .
+.It Sy "[count] ("
+Back up
+.Li count
+sentences.
+.It Sy "[count] )"
+Move forward
+.Li count
+sentences.
+.It Sy "[count] ,"
+Reverse find character
+.Li count
+times.
+.It Sy "[count] -"
+Move to first nonblank of the previous line,
+.Li count
+times.
+.It Sy "[count] ."
+Repeat the last
+.Nm \&vi
+command that modified text.
+.It Sy "/RE<carriage-return>"
+.It Sy "/RE/ [offset]<carriage-return>"
+.It Sy "?RE<carriage-return>"
+.It Sy "?RE? [offset]<carriage-return>"
+.It Sy "N"
+.It Sy "n"
+Search forward or backward for a regular expression.
+.It Sy "0"
+Move to the first character in the current line.
+.It Sy ":"
+Execute an ex command.
+.It Sy "[count] ;"
+Repeat the last character find
+.Li count
+times.
+.It Sy "[count] < motion"
+.It Sy "[count] > motion"
+Shift lines left or right.
+.It Sy "@ buffer"
+Execute a named buffer.
+.It Sy "[count] A"
+Enter input mode, appending the text after the end of the line.
+.It Sy "[count] B"
+Move backwards
+.Li count
+bigwords.
+.It Sy "[buffer] [count] C"
+Change text from the current position to the end-of-line.
+.It Sy "[buffer] D"
+Delete text from the current position to the end-of-line.
+.It Sy "[count] E"
+Move forward
+.Li count
+end-of-bigwords.
+.It Sy "[count] F <character>"
+Search
+.Li count
+times backward through the current line for
+.Li <character> .
+.It Sy "[count] G"
+Move to line
+.Li count ,
+or the last line of the file if
+.Li count
+not specified.
+.It Sy "[count] H"
+Move to the screen line
+.Li "count - 1"
+lines below the top of the screen.
+.It Sy "[count] I"
+Enter input mode, inserting the text at the beginning of the line.
+.It Sy "[count] J"
+Join lines.
+.It Sy "[count] L"
+Move to the screen line
+.Li "count - 1"
+lines above the bottom of the screen.
+.It Sy " M"
+Move to the screen line in the middle of the screen.
+.It Sy "[count] O"
+Enter input mode, appending text in a new line above the current line.
+.It Sy "[buffer] P"
+Insert text from a buffer.
+.It Sy "Q"
+Exit
+.Nm \&vi
+(or visual) mode and switch to
+.Nm \&ex
+mode.
+.It Sy "[count] R"
+Enter input mode, replacing the characters in the current line.
+.It Sy "[buffer] [count] S"
+Substitute
+.Li count
+lines.
+.It Sy "[count] T <character>"
+Search backwards,
+.Li count
+times,
+through the current line for the character
+.Em after
+the specified
+.Li <character> .
+.It Sy "U"
+Restore the current line to its state before the cursor last
+moved to it.
+.It Sy "[count] W"
+Move forward
+.Li count
+bigwords.
+.It Sy "[buffer] [count] X"
+Delete
+.Li count
+characters before the cursor.
+.It Sy "[buffer] [count] Y"
+Copy (or
+.Dq yank )
+.Li count
+lines into the specified buffer.
+.It Sy "ZZ"
+Write the file and exit
+.Nm \&vi .
+.It Sy "[count] [["
+Back up
+.Li count
+section boundaries.
+.It Sy "[count] ]]"
+Move forward
+.Li count
+section boundaries.
+.It Sy "\&^"
+Move to first nonblank character on the current line.
+.It Sy "[count] _"
+Move down
+.Li "count - 1"
+lines, to the first nonblank character.
+.It Sy "[count] a"
+Enter input mode, appending the text after the cursor.
+.It Sy "[count] b"
+Move backwards
+.Li count
+words.
+.It Sy "[buffer] [count] c motion"
+Change a region of text.
+.It Sy "[buffer] [count] d motion"
+Delete a region of text.
+.It Sy "[count] e"
+Move forward
+.Li count
+end-of-words.
+.It Sy "[count] f<character>"
+Search forward,
+.Li count
+times, through the rest of the current line for
+.Li <character> .
+.It Sy "[count] i"
+Enter input mode, inserting the text before the cursor.
+.It Sy "m <character>"
+Save the current context (line and column) as
+.Li <character> .
+.It Sy "[count] o"
+Enter input mode, appending text in a new line under the current line.
+.It Sy "[buffer] p"
+Append text from a buffer.
+.It Sy "[count] r <character>
+Replace
+.Li count
+characters.
+.It Sy "[buffer] [count] s"
+Substitute
+.Li count
+characters in the current line starting with the current character.
+.It Sy "[count] t <character>"
+Search forward,
+.Li count
+times, through the current line for the character immediately
+.Em before
+.Li <character> .
+.It Sy "u"
+Undo the last change made to the file.
+.It Sy "[count] w"
+Move forward
+.Li count
+words.
+.It Sy "[buffer] [count] x"
+Delete
+.Li count
+characters.
+.It Sy "[buffer] [count] y motion"
+Copy (or
+.Dq yank )
+a text region specified by the
+.Li count
+and motion into a buffer.
+.It Sy "[count1] z [count2] -|.|+|^|<carriage-return>"
+Redraw, optionally repositioning and resizing the screen.
+.It Sy "[count] {"
+Move backward
+.Li count
+paragraphs.
+.It Sy "[count] |"
+Move to a specific
+.Em column
+position on the current line.
+.It Sy "[count] }"
+Move forward
+.Li count
+paragraphs.
+.It Sy "[count] ~"
+Reverse the case of the next
+.Li count
+character(s).
+.It Sy "[count] ~ motion"
+Reverse the case of the characters in a text region specified by the
+.Li count
+and
+.Li motion .
+.It Sy "<interrupt>"
+Interrupt the current operation.
+.El
+.Sh VI TEXT INPUT COMMANDS
+The following section describes the commands available in the text
+input mode of the
+.Nm \&vi
+editor.
+.Pp
+.Bl -tag -width "XXXX" -compact
+.It Sy "<nul>"
+Replay the previous input.
+.It Sy "<control-D>"
+Erase the previous autoindent character.
+.It Sy "^<control-D>"
+Erase all of the autoindent characters, and reset the autoindent level.
+.It Sy "0<control-D>"
+Erase all of the autoindent characters.
+.It Sy "<control-T>"
+Insert sufficient
+.Li <tab>
+and
+.Li <space>
+characters to move the cursor forward to a column immediately
+after the next column which is an even multiple of the
+.Sy shiftwidth
+option.
+.It Sy "<erase>
+.It Sy "<control-H>"
+Erase the last character.
+.It Sy "<literal next>"
+Quote the next character.
+.It Sy "<escape>
+Resolve all text input into the file, and return to command mode.
+.It Sy "<line erase>
+Erase the current line.
+.It Sy "<control-W>"
+.It Sy "<word erase>
+Erase the last word.
+The definition of word is dependent on the
+.Sy altwerase
+and
+.Sy ttywerase
+options.
+.It Sy "<control-X>[0-9A-Fa-f]*"
+Insert a character with the specified hexadecimal value into the text.
+.It Sy "<interrupt>"
+Interrupt text input mode, returning to command mode.
+.El
+.Sh EX COMMANDS
+The following section describes the commands available in the
+.Nm \&ex
+editor.
+In each entry below, the tag line is a usage synopsis for the command.
+.sp
+.Bl -tag -width "XXXX" -compact
+.It Sy "<end-of-file>"
+Scroll the screen.
+.It Sy "! argument(s)"
+.It Sy "[range]! argument(s)"
+Execute a shell command, or filter lines through a shell command.
+.It Sy \&"
+A comment.
+.It Sy "[range] nu[mber] [count] [flags]"
+.It Sy "[range] # [count] [flags]"
+Display the selected lines, each preceded with its line number.
+.It Sy "@ buffer"
+.It Sy "* buffer"
+Execute a buffer.
+.It Sy "[range] d[elete] [buffer] [count] [flags]"
+Delete the lines from the file.
+.It Sy "di[splay] b[uffers] | s[creens] | t[ags]"
+Display buffers, screens or tags.
+.It Sy "e[dit][!] [+cmd] [file]"
+.It Sy "ex[!] [+cmd] [file]"
+Edit a different file.
+.It Sy "exu[sage] [command]"
+Display usage for an
+.Nm \&ex
+command.
+.It Sy "f[ile] [file]"
+Display and optionally change the file name.
+.It Sy "fg [name]"
+.Nm \&Vi
+mode only.
+Foreground the specified screen.
+.It Sy "[range] g[lobal] /pattern/ [commands]"
+.It Sy "[range] v /pattern/ [commands]
+Apply commands to lines matching (or not matching) a pattern.
+.It Sy "he[lp]"
+Display a help message.
+.It Sy "[line] i[nsert][!]"
+The input text is inserted before the specified line.
+.It Sy "[range] j[oin][!] [count] [flags]"
+Join lines of text together.
+.It Sy "[range] l[ist] [count] [flags]"
+Display the lines unambiguously.
+.It Sy "map[!] [lhs rhs]"
+Define or display maps (for
+.Nm \&vi
+only).
+.It Sy "[line] ma[rk] <character>"
+.It Sy "[line] k <character>"
+Mark the line with the mark
+.Li <character> .
+.It Sy "[range] m[ove] line"
+Move the specified lines after the target line.
+.It Sy "mk[exrc][!] file"
+Write the abbreviations, editor options and maps to the specified
+file.
+.It Sy "n[ext][!] [file ...]"
+Edit the next file from the argument list.
+.It Sy "[line] o[pen] /pattern/ [flags]"
+Enter open mode.
+.It Sy "pre[serve]"
+Save the file in a form that can later be recovered using the
+.Nm \&ex
+.Fl r
+option.
+.It Sy "prev[ious][!]"
+Edit the previous file from the argument list.
+.It Sy "[range] p[rint] [count] [flags]"
+Display the specified lines.
+.It Sy "[line] pu[t] [buffer]"
+Append buffer contents to the current line.
+.It Sy "q[uit][!]"
+End the editing session.
+.It Sy "[line] r[ead][!] [file]"
+Read a file.
+.It Sy "rec[over] file"
+Recover
+.Li file
+if it was previously saved.
+.It Sy "res[ize] [+|-]size"
+.Nm \&Vi
+mode only.
+Grow or shrink the current screen.
+.It Sy "rew[ind][!]"
+Rewind the argument list.
+.It Sy "se[t] [option[=[value]] ...] [nooption ...] [option? ...] [all]"
+Display or set editor options.
+.It Sy "sh[ell]"
+Run a shell program.
+.It Sy "so[urce] file"
+Read and execute
+.Nm \&ex
+commands from a file.
+.It Sy "sp[lit] [file ...]"
+.Nm \&Vi
+mode only.
+Split the screen.
+.It Sy "[range] s[ubstitute] [/pattern/replace/] [options] [count] [flags]"
+.It Sy "[range] & [options] [count] [flags]"
+.It Sy "[range] ~ [options] [count] [flags]"
+Make substitutions.
+.It Sy "su[spend][!]"
+.It Sy "st[op][!]"
+.It Sy <suspend>
+Suspend the edit session.
+.It Sy "ta[g][!] tagstring"
+Edit the file containing the specified tag.
+.It Sy "tagp[op][!] [file | number]"
+Pop to the specified tag in the tags stack.
+.It Sy "unm[ap][!] lhs"
+Unmap a mapped string.
+.It Sy "ve[rsion]"
+Display the version of the
+.Nm \&ex/vi
+editor.
+.It Sy "[line] vi[sual] [type] [count] [flags]"
+.Nm \&Ex
+mode only.
+Enter
+.Nm \&vi .
+.It Sy "vi[sual][!] [+cmd] [file]"
+.Nm \&Vi
+mode only.
+Edit a new file.
+.It Sy "viu[sage] [command]"
+Display usage for a
+.Nm \&vi
+command.
+.It Sy "[range] w[rite][!] [>>] [file]"
+.It Sy "[range] w[rite] [!] [file]"
+.It Sy "[range] wn[!] [>>] [file]"
+.It Sy "[range] wq[!] [>>] [file]"
+Write the file.
+.It Sy "[range] x[it][!] [file]"
+Write the file if it has been modified.
+.It Sy "[range] ya[nk] [buffer] [count]"
+Copy the specified lines to a buffer.
+.It Sy "[line] z [type] [count] [flags]"
+Adjust the window.
+.El
+.Sh SET OPTIONS
+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.
+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.
+.sp
+.Bl -tag -width "XXXX" -compact
+.It Sy "altwerase [off]"
+.Nm \&Vi
+only.
+Select an alternate word erase algorithm.
+.It Sy "autoindent, ai [off]"
+Automatically indent new lines.
+.It Sy "autoprint, ap [off]"
+.Nm \&Ex
+only.
+Display the current line automatically.
+.It Sy "autowrite, aw [off]"
+Write modified files automatically when changing files.
+.It Sy "beautify, bf [off]"
+Discard control characters.
+.It Sy "cdpath [environment variable CDPATH, or current directory]"
+The directory paths used as path prefixes for the
+.Sy cd
+command.
+.It Sy "columns, co [80]"
+Set the number of columns in the screen.
+.It Sy "comment [off]"
+.Nm \&Vi
+only.
+Skip leading comments in files.
+.It Sy "directory, dir [environment variable TMPDIR, or /tmp]"
+The directory where temporary files are created.
+.It Sy "edcompatible, ed [off]"
+Remember the values of the
+.Dq \&c
+and
+.Dq \&g
+suffices to the
+.Sy substitute
+commands, instead of initializing them as unset for each new
+command.
+.It Sy "errorbells, eb [off]"
+.Nm \&Ex
+only.
+Announce error messages with a bell.
+.It Sy "exrc, ex [off]"
+Never read startup files in the local directory.
+.It Sy "extended [off]"
+Regular expressions are extended (i.e.
+.Xr egrep 1
+style) expressions.
+.It Sy "flash [on]"
+Flash the screen instead of beeping the keyboard on error.
+.It Sy "hardtabs, ht [8]"
+Set the spacing between hardware tab settings.
+.It Sy "ignorecase, ic [off]"
+Ignore case differences in regular expressions.
+.It Sy "keytime [6]"
+The 10th's of a second
+.Nm ex/vi
+waits for a subsequent key to complete a key mapping.
+.It Sy "leftright [off]"
+.Nm \&Vi
+only.
+Do left-right scrolling.
+.It Sy "lines, li [24]"
+.Nm \&Vi
+only.
+Set the number of lines in the screen.
+.It Sy "lisp [off]"
+.Nm \&Vi
+only.
+Modify various search commands and options to work with Lisp.
+.Pp
+.Em "This option is not yet implemented."
+.It Sy "list [off]"
+Display lines in an unambiguous fashion.
+.It Sy "magic [on]"
+Treat certain characters specially in regular expressions.
+.It Sy "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 Sy "mesg [on]"
+Permit messages from other users.
+.It Sy "modelines, modeline [off]"
+Read the first and last few lines of each file for
+.Nm ex
+commands.
+.Pp
+.Em "This option will never be implemented."
+.It Sy "number, nu [off]"
+Precede each line displayed with its current line number.
+.It Sy "octal [off]"
+Display unknown characters as octal numbers, instead of the default
+hexadecimal.
+.It Sy "open [on]"
+.Nm \&Ex
+only.
+If this option is not set, the
+.Sy open
+and
+.Sy visual
+commands are disallowed.
+.It Sy "optimize, opt [on]"
+.Nm \&Vi
+only.
+Optimize text throughput to dumb terminals.
+.Pp
+.Em "This option is not yet implemented."
+.It Sy "paragraphs, para [IPLPPPQPP LIpplpipbp]"
+.Nm \&Vi
+only.
+Define additional paragraph boundaries for the
+.Sy \&{
+and
+.Sy \&}
+commands.
+.It Sy "prompt [on]"
+.Nm \&Ex
+only.
+Display a command prompt.
+.It Sy "readonly, ro [off]"
+Mark the file as read-only.
+.It Sy "recdir [/var/tmp/vi.recover]"
+The directory where recovery files are stored.
+.It Sy "redraw, re [off]"
+.Nm \&Vi
+only.
+Simulate an intelligent terminal on a dumb one.
+.Pp
+.Em "This option is not yet implemented."
+.It Sy "remap [on]"
+Remap keys until resolved.
+.It Sy "report [5]"
+Set the number of lines about which the editor reports changes
+or yanks.
+.It Sy "ruler [off]"
+.Nm \&Vi
+only.
+Display a row/column ruler on the colon command line.
+.It Sy "scroll, scr [window / 2]"
+Set the number of lines scrolled.
+.It Sy "sections, sect [NHSHH HUnhsh]"
+.Nm \&Vi
+only.
+Define additional section boundaries for the
+.Sy \&[[
+and
+.Sy \&]]
+commands.
+.It Sy "shell, sh [environment variable SHELL, or /bin/sh]"
+Select the shell used by the editor.
+.It Sy "shiftwidth, sw [8]"
+Set the autoindent and shift command indentation width.
+.It Sy "showdirty [off]"
+.Nm \&Vi
+only.
+Display an asterisk on the colon command line if the file has been modified.
+.It Sy "showmatch, sm [off]"
+.Nm \&Vi
+only.
+Note matching
+.Dq \&{
+and
+.Dq \&(
+for
+.Dq \&}
+and
+.Dq \&)
+characters.
+.It Sy "showmode [off]"
+.Nm \&Vi
+only.
+Display the current editor mode (command or input).
+.It Sy "sidescroll [16]"
+.Nm \&Vi
+only.
+Set the amount a left-right scroll will shift.
+.It Sy "slowopen, slow [off]"
+Delay display updating during text input.
+.Pp
+.Em "This option is not yet implemented."
+.It Sy "sourceany [off]"
+Read startup files not owned by the current user.
+.Pp
+.Em "This option will never be implemented."
+.It Sy "tabstop, ts [8]"
+This option sets tab widths for the editor display.
+.It Sy "taglength, tl [0]"
+Set the number of significant characters in tag names.
+.It Sy "tags, tag [tags /var/db/libc.tags /sys/kern/tags]"
+Set the list of tags files.
+.It Sy "term, ttytype, tty [environment variable TERM]"
+Set the terminal type.
+.It Sy "terse [off]"
+This option has historically made editor messages less verbose.
+It has no effect in this implementation.
+.It Sy "tildeop"
+Modify the
+.Sy \&~
+command to take an associated motion.
+.It Sy "timeout, to [on]"
+Time out on keys which may be mapped.
+.It Sy "ttywerase [off]"
+.Nm \&Vi
+only.
+Select an alternate erase algorithm.
+.It Sy "verbose [off]"
+.NM \&Vi
+only.
+Display an error message for every error.
+.It Sy "w300 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is less than 1200 baud.
+.It Sy "w1200 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is equal to 1200 baud.
+.It Sy "w9600 [no default]"
+.Nm \&Vi
+only.
+Set the window size if the baud rate is greater than 1200 baud.
+.It Sy "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 Sy "window, w, wi [environment variable LINES]"
+Set the window size for the screen.
+.It Sy "wrapmargin, wm [0]"
+.Nm \&Vi
+only.
+Break lines automatically when they reach the right-hand margin.
+.It Sy "wrapscan, ws [on]"
+Set searches to wrap around the end or beginning of the file.
+.It Sy "writeany, wa [off]"
+Turn off file-overwriting checks.
+.El
+.Sh ENVIRONMENTAL VARIABLES
+.Bl -tag -width "COLUMNSXX" -compact
+.It Ev COLUMNS
+The number of columns on the screen.
+This value overrides any system or terminal specific values.
+If the COLUMNS environmental variable is not set when
+.Nm ex/vi
+runs, or the
+.Sy columns
+option is explicitly reset by the user,
+.Nm ex/vi
+enters the value into the environment.
+.It Ev EXINIT
+A list of
+.Nm \&ex
+startup commands, read if the variable
+.Ev NEXINIT
+is not set.
+.It Ev HOME
+The user's home directory, used as the initial directory path
+for the startup
+.Pa $HOME/.nexrc
+and
+.Pa $HOME/.exrc
+files.
+This value is also used as the default directory for the
+.Nm \&vi
+.Sy \&cd
+command.
+.It Ev LINES
+The number of rows on the screen.
+This value overrides any system or terminal specific values.
+If the LINES environmental variable is not set when
+.Nm ex/vi
+runs, or the
+.Sy lines
+option is explicitly reset by the user,
+.Nm ex/vi
+enters the value into the environment.
+.It Ev NEXINIT
+A list of
+.Nm \&ex
+startup commands.
+.It Ev SHELL
+The user's shell of choice (see also the
+.Sy shell
+option).
+.It Ev TERM
+The user's terminal type.
+The default is the type
+.Dq unknown .
+If the TERM environmental variable is not set when
+.Nm ex/vi
+runs, or the
+.Sy term
+option is explicitly reset by the user,
+.Nm ex/vi
+enters the value into the environment.
+.It Ev TMPDIR
+The location used to stored temporary files (see also the
+.Sy directory
+option).
+.El
+.Sh ASYNCHRONOUS EVENTS
+.Bl -tag -width "SIGWINCHXX" -compact
+.It SIGALRM
+.Nm \&Vi/ex
+uses this signal for periodic backups of file modifications
+and to display
+.Dq busy
+messages when operations are likely to take a long time.
+.It SIGHUP
+.It SIGTERM
+If the current buffer has changed since it was last written in its
+entirety, the editor attempts to save the modified file so it can
+be later recovered.
+See the
+.Nm \&vi/ex
+Reference manual section entitled
+.Dq Recovery
+for more information.
+.It SIGINT
+When an interrupt occurs,
+the current operation is halted,
+and the editor returns to the command level.
+If interrupted during text input,
+the text already input is resolved into the file as if the text
+input had been normally terminated.
+.It SIGWINCH
+The screen is resized.
+See the
+.Nm \&vi/ex
+Reference manual section entitled
+.Dq "Sizing the Screen"
+for more information.
+.It SIGCONT
+.It SIGQUIT
+.It SIGTSTP
+.Nm \&Vi/ex
+ignores these signals.
+.El
+.Sh BUGS
+See the file
+.Pa nvi/docs/bugs.current
+for a list of the known bugs in this version.
+.Sh FILES
+.Bl -tag -width /var/tmp/vi.recover -compact
+.It Pa /bin/sh
+The default user shell.
+.It Pa /etc/vi.exrc
+System-wide vi startup file.
+.It Pa /tmp
+Temporary file directory.
+.It Pa /var/tmp/vi.recover
+The default recovery file directory.
+.It Pa $HOME/.nexrc
+1st choice for user's home directory startup file.
+.It Pa $HOME/.exrc
+2nd choice for user's home directory startup file.
+.It Pa .nexrc
+1st choice for local directory startup file.
+.It Pa .exrc
+2nd choice for local directory startup file.
+.El
+.Sh SEE ALSO
+.Xr ctags 1 ,
+.Xr more 1 ,
+.Xr curses 3 ,
+.Xr dbopen 3
+.sp
+The
+.Dq "Vi Quick Reference"
+card.
+.sp
+.Dq "\&An Introduction to Display Editing with Vi" ,
+found in the
+.Dq "UNIX User's Manual Supplementary Documents"
+section of both the 4.3BSD and 4.4BSD manual sets.
+This document is the closest thing available to an introduction to the
+.Nm \&vi
+screen editor.
+.sp
+.Dq "\&Ex Reference Manual (Version 3.7)" ,
+found in the
+.Dq "UNIX User's Manual Supplementary Documents"
+section of both the 4.3BSD and 4.4BSD manual sets.
+This document is the final reference for the
+.Nm \&ex
+editor, as distributed in most historic 4BSD and System V systems.
+.sp
+.Dq "Edit: A tutorial" ,
+found in the
+.Dq "UNIX User's Manual Supplementary Documents"
+section of the 4.3BSD manual set.
+This document is an introduction to a simple version of the
+.Nm \&ex
+screen editor.
+.sp
+.Dq "\&Ex/Vi Reference Manual" ,
+found in the
+.Dq "UNIX User's Manual Supplementary Documents"
+section of the 4.4BSD manual set.
+This document is the final reference for the
+.Nm \&nex/nvi
+text editors, as distributed in 4.4BSD and 4.4BSD-Lite.
+.Pp
+.Nm Roff
+source for all of these documents is distributed with
+.Nm nex/nvi
+in the
+.Pa nvi/USD.doc
+directory of the
+.Nm nex/nvi
+source code.
+.sp
+The files
+.Dq autowrite ,
+.Dq input ,
+.Dq quoting ,
+and
+.Dq structures ,
+found in the
+.Pa nvi/docs/internals
+directory of the
+.Nm nex/nvi
+source code.
+.Sh HISTORY
+The
+.Nm nex/nvi
+replacements for the
+.Nm ex/vi
+editor first appeared in 4.4BSD.
+.Sh STANDARDS
+.Nm \&Nex/nvi
+is close to IEEE Std1003.2 (``POSIX'').
+That document differs from historical
+.Nm ex/vi
+practice in several places; there are changes to be made on both sides.
diff --git a/usr.bin/vi/USD.doc/vi.ref/Makefile b/usr.bin/vi/USD.doc/vi.ref/Makefile
new file mode 100644
index 000000000000..2690f86edc70
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/Makefile
@@ -0,0 +1,25 @@
+# @(#)Makefile 8.16 (Berkeley) 8/15/94
+
+DIR= usd/13.viref
+SRCS= vi.ref ex.cmd.roff set.opt.roff vi.cmd.roff ref.so
+MACROS= -me
+CLEANFILES+=vi.ref.txt index index.so
+
+paper.ps: vi.ref index.so
+ soelim vi.ref | ${TBL} | ${ROFF} > ${.TARGET}
+
+vi.ref.txt: vi.ref index.so
+ soelim vi.ref | ${TBL} | groff ${MACROS} -Tascii > $@
+
+index.so: vi.ref
+ # Build index.so, side-effect of building the paper.
+ soelim vi.ref | ${TBL} | ${ROFF} > /dev/null
+ sed -e 's/MINUSSIGN/\\-/' \
+ -e 's/DOUBLEQUOTE/""/' \
+ -e "s/SQUOTE/'/" \
+ -e 's/ /__SPACE/g' < index | \
+ sort -u '-t ' +0 -1 +1n | awk -f merge.awk | \
+ sed -e 's/__SPACE/ /g' > index.so
+ rm -f index
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/vi/USD.doc/vi.ref/ex.cmd.roff b/usr.bin/vi/USD.doc/vi.ref/ex.cmd.roff
new file mode 100644
index 000000000000..a9cba6ae336d
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/ex.cmd.roff
@@ -0,0 +1,1776 @@
+.\" 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.
+.\"
+.\" @(#)ex.cmd.roff 8.24 (Berkeley) 7/17/94
+.\"
+.SH 1 "Ex Description"
+.pp
+The following words have special meanings for
+.CO ex
+commands.
+.KY "<eof>"
+.IP "<eof>"
+The end-of-file character is used to scroll the screen in the
+.CO ex
+editor.
+This character is normally
+.LI <control-D> ,
+however, whatever character is set for the current terminal is used.
+.KY "line"
+.IP "line"
+A single-line address, given in any of the forms described in the
+section entitled
+.QB "Ex Addressing" .
+The default for
+.LI line
+is the current line.
+.KY "range"
+.IP "range"
+A line, or a pair of line addresses, separated by a comma or semicolon.
+(See the section entitled
+.QB "Ex Addressing"
+for more information.)
+The default for range is the current line
+.i only ,
+i.e.
+.QT \&.,. .
+A percent sign
+.PQ %
+stands for the range
+.QT 1,$ .
+The starting address must be less than, or equal to, the ending address.
+.KY "count"
+.IP "count"
+A positive integer, specifying the number of lines to be affected by
+the command; the default is 1.
+Generally, a count past the end-of-file may be specified, e.g. the
+command
+.QT "p 3000"
+in a 10 line file is acceptable, and will print from the current line
+through the last line in the file.
+.KY "flags"
+.IP "flags"
+One or more of the characters
+.QQ # ,
+.QQ p ,
+and
+.QQ l .
+When a command that accepts these flags completes, the addressed line(s)
+are written out as if by the corresponding
+.CO # ,
+.CO l
+or
+.CO p
+commands.
+In addition, any number of
+.QT +
+or
+.QT \-
+characters can be specified before, after, or during the flags, in which
+case the line written is not necessarily the one affected by the command,
+but rather the line addressed by the offset address specified.
+The default for
+.LI flags
+is none.
+.KY "file"
+.IP "file"
+A pattern used to derive a pathname; the default is the current file.
+File names are subjected to normal
+.XR sh 1
+word expansions.
+.pp
+Anywhere a file name is specified, it is also possible to use
+the special string
+.QT /tmp .
+This will be replaced with a temporary file name which can be used
+for temporary work, e.g.
+.QT ":e /tmp"
+creates and edits a new file.
+.pp
+If both a count and a range are specified for commands that use either,
+the starting line for the command is the
+.i last
+line addressed by the range, and
+.LI count - 1
+subsequent lines are affected by the command, e.g. the command
+.QT 2,3p4
+prints out lines 3, 4, 5 and 6.
+.pp
+When only a line or range is specified, with no command, the implied
+command is either a
+.CO list ,
+.CO number
+or
+.CO print
+command.
+The command used is the most recent of the three commands to have been
+used (including any use as a flag).
+If none of these commands have been used before, the
+.CO print
+command is the implied command.
+When no range or count is specified and the command line is a blank line,
+the current line is incremented by 1 and then the current line is displayed.
+.pp
+Zero or more whitespace characters may precede or follow the addresses,
+count, flags, or command name.
+Any object following a command name (such as buffer, file, etc.),
+that begins with an alphabetic character,
+should be separated from the command name by at least one whitespace
+character.
+.pp
+Any character, including
+.LI <carriage-return> ,
+.QT %
+and
+.QT #
+retain their literal value when preceded by a backslash.
+.SH 1 "Ex Commands"
+.pp
+The following section describes the commands available in the
+.CO ex
+editor.
+In each entry below, the tag line is a usage synopsis for the command.
+.pp
+Each command can be entered as the abbreviation
+(those characters in the synopsis command word preceding the
+.QQ [
+character),
+the full command (all characters shown for the command word,
+omitting the
+.QQ [
+and
+.QQ ]
+characters),
+or any leading subset of the full command down to the abbreviation.
+For example, the args command (shown as
+.QT ar[gs]
+in the synopsis)
+can be entered as
+.QT ar ,
+.QT arg
+or
+.QT args .
+.pp
+Each
+.CO ex
+command described below notes the new current line after it
+is executed, as well as any options that affect the command.
+.KY DOUBLEQUOTE
+.IP """"
+A comment.
+Command lines beginning with the double-quote character
+.PQ """"
+are ignored.
+This permits comments in editor scripts and startup files.
+.KY "<end-of-file>"
+.IP "<end-of-file>"
+Scroll the screen.
+Write the next N lines, where N is the value of the
+.OP scroll
+option.
+The command is the end-of-file terminal character, which may be
+different on different terminals.
+Traditionally, it is the
+.LI <control-D>
+key.
+.sp
+Historically, the
+.CO eof
+command ignored any preceding count, and the
+.LI <end-of-file>
+character was ignored unless it was entered as the first character
+of the command.
+This implementation treats it as a command
+.i only
+if entered as the first character of the command line, and otherwise
+treats it as any other character.
+.SS
+.SP Line:
+Set to the last line written.
+.SP Options:
+None.
+.SE
+.KY "!"
+.IP "! argument(s)"
+.Ip "[range]! argument(s)"
+Execute a shell command, or filter lines through a shell command.
+In the first synopsis, the remainder of the line after the
+.QT !
+character is passed to the program named by the
+.OP shell
+option, as a single argument.
+.sp
+Within the rest of the line,
+.QT %
+and
+.QT #
+are expanded into the current and alternate pathnames, respectively.
+The character
+.QT !
+is expanded with the command text of the previous
+.CO !
+command.
+(Therefore, the command
+.CO !!
+repeats the previous
+.CO !
+command.)
+The special meanings of
+.QT % ,
+.QT # ,
+and
+.QT !
+can be overridden by escaping them with a backslash.
+If no
+.CO !
+or
+.CO :!
+command has yet been executed, it is an error to use an unescaped
+.QT !
+character.
+The
+.CO !
+command does
+.i not
+do shell expansion on the strings provided as arguments.
+If any of the above expansions change the command the user entered,
+the command is redisplayed at the bottom of the screen.
+.sp
+.CO Ex
+then executes the program named by the
+.OP shell
+option, with a
+.b \-c
+flag followed by the arguments (which are bundled into a single argument).
+.sp
+The
+.CO !
+command is permitted in an empty file.
+.sp
+If the file has been modified since it was last completely written,
+the
+.Co !
+command will warn you.
+.sp
+A single
+.QT !
+character is displayed when the command completes.
+.sp
+In the second form of the
+.CO !
+command, the remainder of the line after the
+.QT !
+is passed to the program named by the
+.OP shell
+option, as described above.
+The specified lines are passed to the program as standard input,
+and the standard and standard error output of the program replace
+the original lines.
+.SS
+.SP Line:
+Unchanged if no range was specified, otherwise set to the first
+line of the range.
+.SP Options:
+Affected by the
+.OP autowrite
+and
+.OP writeany
+options.
+.SE
+.KY "number"
+.IP "[range] nu[mber] [count] [flags]"
+.KY "#"
+.Ip "[range] # [count] [flags]"
+Display the selected lines, each preceded with its line number.
+.sp
+The line number format is
+.QQ %6d ,
+followed by two spaces.
+.SS
+.SP Line:
+Set to the last line displayed.
+.SP Options:
+None.
+.SE
+.KY "@"
+.IP "@ buffer"
+.KY "*"
+.Ip "* buffer"
+Execute a buffer.
+Each line in the named buffer is executed as an
+.CO ex
+command.
+If no buffer is specified, or if the specified buffer is
+.QT @
+or
+.QT * ,
+the last buffer executed is used.
+.KY <
+.IP "[range] <[< ...] [count] [flags]"
+Shift lines left or right.
+The specified lines are shifted to the left (for the
+.CO <
+command) or right (for the
+.CO >
+command), by the number of columns specified by the
+.OP shiftwidth
+option.
+Only leading whitespace characters are deleted when shifting left;
+once the first column of the line contains a nonblank character,
+the
+.CO shift
+command will succeed, but the line will not be modified.
+.sp
+If the command character
+.CO <
+or
+.CO >
+is repeated more than once, the command is repeated once for each
+additional command character.
+.SS
+.SP Line:
+If the current line is set to one of the lines that are affected
+by the command, it is unchanged.
+Otherwise, it is set to the first nonblank character of the lowest
+numbered line shifted.
+.SP Options:
+Affected by the
+.OP shiftwidth
+option.
+.SE
+.KY =
+.IP "[line] = [flags]"
+Display the line number.
+Display the line number of
+.LI line
+(which defaults to the last line in the file).
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY >
+.IP "[range] >[> ...] [count] [flags]"
+Shift right.
+The specified lines are shifted to the right by the number of columns
+specified by the
+.OP shiftwidth
+option, by inserting tab and space characters.
+Empty lines are not changed.
+.sp
+If the command character
+.QT >
+is repeated more than once, the command is repeated once for each
+additional command character.
+.SS
+.SP Line:
+Set to the last line modified by the command.
+.SP Options:
+None.
+.SE
+.KY abbrev
+.IP "ab[brev] lhs rhs"
+Add an abbreviation to the current abbreviation list.
+In
+.CO vi ,
+if
+.LI lhs
+is entered such that it is preceded and followed by characters
+that cannot be part of a word, it is replaced by the string
+.LI rhs .
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY append
+.IP "[line] a[ppend][!]"
+The input text is appended to the specified line.
+If line 0 is specified, the text is inserted at the beginning of the file.
+Set to the last line input.
+If no lines are input, then set to
+.LI line ,
+or to the first line of the file if a
+.LI line
+of 0 was specified.
+Following the command name with a
+.QT !
+character causes the
+.OP autoindent
+option to be toggled for the duration of the command.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY args
+.IP "ar[gs]"
+Display the argument list.
+The current argument is displayed inside of
+.QT [
+and
+.QT ]
+characters.
+The argument list is the list of operands specified on startup,
+which can be replaced using the
+.CO next
+command.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY bg
+.IP bg
+.CO Vi
+mode only.
+Background the current screen.
+.SS
+.SP Line:
+Set to the current line when the screen was last edited.
+.SP Options:
+None.
+.SE
+.KY change
+.IP "[range] c[hange][!] [count]"
+Replace the lines with input text.
+Following the command name with a
+.QT !
+character causes the
+.OP autoindent
+option to be toggled for the duration of the command.
+.SS
+.SP Line:
+Set to the last line input, or, if no lines were input,
+set to the line before the target line, or to the first
+line of the file if there are no lines preceding the target line.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY cd
+.KY chdir
+.IP "chd[ir][!] [directory]"
+.Ip "cd[!] [directory]"
+Change the current working directory.
+The
+.LI directory
+argument is subjected to
+.XR sh 1
+word expansions.
+When invoked with no directory argument and the
+.LI HOME
+environment variable is set, the directory named by the
+.LI HOME
+environment variable becomes the new current directory.
+Otherwise, the new current directory becomes the directory returned
+by the
+.XR getpwent 3
+routine.
+.sp
+The
+.CO chdir
+command will fail if the file has been modified since the last complete
+write of the file.
+You can override this check by appending a
+.QT !
+character to the command.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+Affected by the
+.OP cdpath
+option.
+.SE
+.KY copy
+.KY t
+.IP "[range] co[py] line [flags]"
+.Ip "[range] t line [flags]"
+Copy the specified lines (range) after the destination line.
+Line 0 may be specified to insert the lines at the beginning of
+the file.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY delete
+.IP "[range] d[elete] [buffer] [count] [flags]"
+Delete the lines from the file.
+The deleted text is saved in the specified buffer, or, if no buffer
+is specified, in the unnamed buffer.
+If the command name is followed by a letter that could be interpreted
+as either a buffer name or a flag value (because neither a
+.LI count
+or
+.LI flags
+values were given),
+.CO ex
+treats the letter as a
+.LI flags
+value if the letter immediately follows the command name,
+without any whitespace separation.
+If the letter is preceded by whitespace characters,
+it treats it as a buffer name.
+.SS
+.SP Line:
+Set to the line following the deleted lines,
+or to the last line if the deleted lines were at the end.
+.SP Options:
+None.
+.SE
+.KY display
+.IP "di[splay] b[uffers] | s[creens] | t[ags]"
+Display buffers, screens or tags.
+The
+.CO display
+command takes one of three additional arguments, which are as follows:
+.SS
+.SP b[uffers]
+Display all buffers (including named, unnamed, and numeric)
+that contain text.
+.SP s[creens]
+Display the file names of all background screens.
+.SP t[ags]
+Display the tags stack.
+.SE
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY edit
+.IP "e[dit][!] [+cmd] [file]"
+.Ip "ex[!] [+cmd] [file]"
+Edit a different file.
+If the current buffer has been modified since the last complete write,
+the command will fail.
+You can override this by appending a
+.QT !
+character to the command name.
+.sp
+If the
+.QT +cmd
+option is specified, that
+.CO ex
+command will be executed in the new file.
+Any
+.CO ex
+command may be used, although the most common use of this feature is
+to specify a line number or search pattern to set the initial location
+in the new file.
+.SS
+.SP Line:
+If you have previously edited the file, the current line will be set
+to your last position in the file.
+If that position does not exist, or you have not previously edited the
+file, the current line will be set to the first line of the file if
+you are in
+.CO vi
+mode, and the last line of the file if you are in
+.CO ex .
+.SP Options:
+Affected by the
+.OP autowrite
+and
+.OP writeany
+options.
+.SE
+.KY exusage
+.IP "exu[sage] [command]"
+Display usage for an
+.CO ex
+command.
+If
+.LI command
+is specified, a usage statement for that command is displayed.
+Otherwise, usage statements for all
+.CO ex
+commands are displayed.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY file
+.IP "f[ile] [file]"
+Display and optionally change the file name.
+If a file name is specified, the current pathname is changed to the
+specified name.
+The current pathname, the number of lines, and the current position
+in the file are displayed.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY fg
+.IP "fg [name]"
+.CO Vi
+mode only.
+Foreground the specified screen.
+Swap the current screen with the specified backgrounded screen.
+If no screen is specified, the first background screen is foregrounded.
+.SS
+.SP Line:
+Set to the current line when the screen was last edited.
+.SP Options:
+None.
+.SE
+.KY global
+.IP "[range] g[lobal] /pattern/ [commands]"
+.KY v
+.Ip "[range] v /pattern/ [commands]"
+Apply commands to lines matching (or not matching) a pattern.
+The lines within the given range that match
+.PQ g[lobal] ,
+or do not match
+.PQ v
+the given pattern are selected.
+Then, the specified
+.CO ex
+command(s) are executed with the current line
+.PQ \&.
+set to each selected line.
+If no range is specified, the entire file is searched for matching,
+or not matching, lines.
+.sp
+Multiple commands can be specified, one per line, by escaping each
+.LI <newline>
+character with a backslash, or by separating commands with a
+.QT |
+character.
+If no commands are specified, the command defaults to the
+.CO print
+command.
+.sp
+For the
+.CO append ,
+.CO change
+and
+.CO insert
+commands, the input text must be part of the global command line.
+In this case, the terminating period can be omitted if it ends the commands.
+.sp
+The
+.CO visual
+command may also be specified as one of the
+.CO ex
+commands.
+In this mode, input is taken from the terminal.
+Entering a
+.CO Q
+command in
+.CO vi
+mode causes the next line matching the pattern to be selected and
+.CO vi
+to be reentered, until the list is exhausted.
+.sp
+The
+.CO global ,
+.CO v
+and
+.CO undo
+commands cannot be used as part of these commands.
+.sp
+The editor options
+.OP autoprint ,
+.OP autoindent ,
+and
+.OP report
+are turned off for the duration of the
+.CO global
+and
+.CO v
+commands.
+.SS
+.SP Line:
+The last line modified.
+.SP Options:
+None.
+.SE
+.KY help
+.IP "he[lp]"
+Display a help message.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY insert
+.IP "[line] i[nsert][!]"
+The input text is inserted before the specified line.
+Following the command name with a
+.QT !
+character causes the
+.OP autoindent
+option setting to be toggled for the duration of this command.
+.SS
+.SP Line:
+Set to the last line input; if no lines were input,
+set to the line before the target line, or to the first line
+of the file if there are no lines preceding the target line.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY join
+.IP "[range] j[oin][!] [count] [flags]"
+Join lines of text together.
+.sp
+A
+.LI count
+specified to the
+.Sy join
+command specifies that the last line of the
+.LI range
+plus
+.LI count
+subsequent lines will be joined.
+(Note, this differs by one from the general rule where only
+.LI count - 1
+subsequent lines are affected.)
+.sp
+If the current line ends with a whitespace character, all whitespace
+is stripped from the next line.
+Otherwise, if the next line starts with a open parenthesis
+.PQ ( ,
+do nothing.
+Otherwise, if the current line ends with a question mark
+.PQ ? ,
+period
+.PQ \&.
+or exclamation point
+.PQ ! ,
+insert two spaces.
+Otherwise, insert a single space.
+.sp
+Appending a
+.QT !
+character to the command name causes a simpler join with no
+white-space processing.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY list
+.IP "[range] l[ist] [count] [flags]"
+Display the lines unambiguously.
+Tabs are displayed as
+.QT ^I ,
+and the end of the line is marked with a
+.QT $
+character.
+.SS
+.SP Line:
+Set to the last line displayed.
+.SP Options:
+None.
+.SE
+.KY map
+.IP "map[!] [lhs rhs]"
+Define or display maps (for
+.CO vi
+only).
+.sp
+If
+.QT lhs
+and
+.QT rhs
+are not specified, the current set of command mode maps are displayed.
+If a
+.QT !
+character is appended to to the command,
+the text input mode maps are displayed.
+.sp
+Otherwise, when the
+.QT lhs
+character sequence is entered in
+.CO vi ,
+the action is as if the corresponding
+.QT rhs
+had been entered.
+If a
+.QT !
+character is appended to the command name,
+the mapping is effective during text input mode,
+otherwise, it is effective during command mode.
+This allows
+.QT lhs
+to have two different macro definitions at the same time: one for command
+mode and one for input mode.
+.sp
+Whitespace characters require escaping with a
+.LI <literal next>
+character to be entered in the
+.LI lhs
+string in visual mode.
+.sp
+Normally, keys in the
+.LI rhs
+string are remapped (see the
+.OP remap
+option),
+and it is possible to create infinite loops.
+However, keys which map to themselves are not further remapped,
+regardless of the setting of the
+.OP remap
+option.
+For example, the command
+.QT ":map n nz."
+maps the
+.QT n
+key to the
+.CO n
+and
+.CO z
+commands.
+.sp
+To exit an infinitely looping map, use the terminal
+.LI <interrupt>
+character.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY mark
+.KY k
+.IP "[line] ma[rk] <character>"
+.Ip "[line] k <character>"
+Mark the line with the mark
+.LI <character> .
+The expressions
+.QT '<character>
+and
+.QT `<character>
+can then be used as an address in any command that uses one.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY move
+.IP "[range] m[ove] line"
+Move the specified lines after the target line.
+A target line of 0 places the lines at the beginning of the file.
+.SS
+.SP Line:
+Set to the first of the moved lines.
+.SP Options:
+None.
+.SE
+.KY mkexrc
+.IP "mk[exrc][!] file"
+Write the abbreviations, editor options and maps to the specified
+file.
+Information is written in a form which can later be read back in
+using the
+.CO ex
+.CO source
+command.
+If
+.LI file
+already exists, the
+.CO mkexrc
+command will fail.
+This check can be overridden by appending a
+.QT !
+character to the command.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY next
+.IP "n[ext][!] [file ...]"
+Edit the next file from the argument list.
+The
+.CO next
+command will fail if the file has been modified since the last complete
+write.
+This check can be overridden by appending the
+.QT !
+character to the command name.
+The argument list can optionally be replaced by specifying a new one
+as arguments to this command.
+In this case, editing starts with the first file on the new list.
+.SS
+.SP Line:
+Set as described for the
+.CO edit
+command.
+.SP Options:
+Affected by the options
+.OP autowrite
+and
+.OP writeany .
+.SE
+.KY open
+.IP "[line] o[pen] /pattern/ [flags]"
+Enter open mode.
+Open mode is the same as being in
+.CO vi ,
+but with a one-line window.
+All the standard
+.CO vi
+commands are available.
+If a match is found for the optional RE argument,
+the cursor is set to the start of the matching pattern.
+.sp
+.i "This command is not yet implemented."
+.SS
+.SP Line:
+Unchanged, unless the optional RE is specified, in which case it is
+set to the line where the matching pattern is found.
+.SP Options:
+Affected by the
+.OP open
+option.
+.SE
+.KY preserve
+.IP "pre[serve]"
+Save the file in a form that can later be recovered using the
+.CO ex
+.b \-r
+option.
+When the file is preserved, an email message is sent to the user.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY previous
+.IP "prev[ious][!]"
+Edit the previous file from the argument list.
+The
+.CO previous
+command will fail if the file has been modified since the last complete
+write.
+This check can be overridden by appending the
+.QT !
+character to the command name.
+.SS
+.SP Line:
+Set as described for the
+.CO edit
+command.
+.SP Options:
+Affected by the options
+.OP autowrite
+and
+.OP writeany .
+None.
+.SE
+.KY print
+.IP "[range] p[rint] [count] [flags]"
+Display the specified lines.
+.SS
+.SP Line:
+Set to the last line displayed.
+.SP Options:
+None.
+.SE
+.KY put
+.IP "[line] pu[t] [buffer]"
+Append buffer contents to the current line.
+If a buffer is specified, its contents are appended to the line,
+otherwise, the contents of the unnamed buffer are used.
+.SS
+.SP Line:
+Set to the line after the current line.
+.SP Options:
+None.
+.SE
+.KY quit
+.IP "q[uit][!]"
+End the editing session.
+If the file has been modified since the last complete write, the
+.CO quit
+command will fail.
+This check may be overridden by appending a
+.QT !
+character to the command.
+.sp
+If there are more files to edit, the
+.CO quit
+command will fail.
+Appending a
+.QT !
+character to the command name or entering two
+.CO quit
+commands (i.e.
+.CO wq ,
+.CO quit ,
+.CO xit
+or
+.CO ZZ )
+in a row) will override this check and the editor will exit.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY read
+.IP "[line] r[ead][!] [file]"
+Read a file.
+A copy of the specified file is appended to the line.
+If
+.LI line
+is 0, the copy is inserted at the beginning of the file.
+If no file is specified, the current file is read; if there is no
+current file, then
+.LI file
+becomes the current file.
+If there is no current file and no
+.LI file
+is specified, then the
+.CO read
+command will fail.
+.sp
+If
+.LI file
+is preceded by a
+.QT !
+character,
+.LI file
+is treated as if it were a shell command, and passed to the program
+named by the
+.LI SHELL
+environment variable.
+The standard and standard error outputs of that command are read into
+the file after the specified line.
+The special meaning of the
+.QT !
+character can be overridden by escaping it with a backslash
+.PQ \e
+character.
+.SS
+.SP Line:
+When executed from
+.CO ex ,
+the current line is set to the last line read.
+When executed from
+.CO vi ,
+the current line is set to the first line read.
+.SP Options:
+None.
+.SE
+.KY recover
+.IP "rec[over] file"
+Recover
+.LI file
+if it was previously saved.
+If no saved file by that name exists, the
+.CO recover
+command behaves similarly to the
+.CO edit
+command.
+.SS
+.SP Line:
+Set as described for the
+.CO edit
+command.
+.SP Options:
+None.
+.SE
+.KY resize
+.IP "res[ize] [+|-]size"
+.CO Vi
+mode only.
+Grow or shrink the current screen.
+If
+.LI size
+is a positive, signed number, the current screen is grown by that many lines.
+If
+.LI size
+is a negative, signed number, the current screen is shrunk by that many lines.
+If
+.LI size
+is not signed, the current screen is set to the specified
+.LI size .
+Applicable only to split screens.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY rewind
+.IP "rew[ind][!]"
+Rewind the argument list.
+If the current file has been modified since the last complete write,
+the
+.CO rewind
+command will fail.
+This check may be overridden by appending the
+.QT !
+character to the command.
+.sp
+Otherwise, the current file is set to the first file in the argument
+list.
+.SS
+.SP Line:
+Set as described for the
+.CO edit
+command.
+.SP Options:
+Affected by the
+.OP autowrite
+and
+.OP writeany
+options.
+.SE
+.KY set
+.IP "se[t] [option[=[value]] ...] [nooption ...] [option? ...] [all]"
+Display or set editor options.
+When no arguments are specified, the editor option
+.OP term ,
+and any editor options whose values have been changed from the
+default settings are displayed.
+If the argument
+.LI all
+is specified, the values of all of editor options are displayed.
+.sp
+Specifying an option name followed by the character
+.QT ?
+causes the current value of that option to be displayed.
+The
+.QT ?
+can be separated from the option name by whitespace characters.
+The
+.QT ?
+is necessary only for Boolean valued options.
+Boolean options can be given values by the form
+.QT "set option"
+to turn them on, or
+.QT "set nooption"
+to turn them off.
+String and numeric options can be assigned by the form
+.QT "set option=value" .
+Any whitespace characters in strings can be included literally by preceding
+each with a backslash.
+More than one option can be set or listed by a single set command,
+by specifying multiple arguments, each separated from the next by
+whitespace characters.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY shell
+.IP "sh[ell]"
+Run a shell program.
+The program named by the
+.OP shell
+option is run with a
+.b \-i
+(for interactive) flag.
+Editing is resumed when that program exits.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY source
+.IP "so[urce] file"
+Read and execute
+.CO ex
+commands from a file.
+.CO Source
+commands may be nested.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY split
+.IP "sp[lit] [file ...]"
+.CO Vi
+mode only.
+Split the screen.
+The current screen is split into two screens, of approximately equal size.
+If the cursor is in the lower half of the screen, the screen will split
+up, i.e. the new screen will be above the old one.
+If the cursor is in the upper half of the screen, the new screen will be
+below the old one.
+.sp
+If
+.LI file
+is specified, the new screen is editing that file, otherwise, both
+screens are editing the same file, and changes in each will be
+be reflected in the other.
+The argument list for the new screen consists of the list of files
+specified as arguments to this command, or, the current pathname if
+no files are specified.
+.SS
+.SP Line:
+If
+.LI file
+is specified, set as for the
+.CO edit
+command, otherwise unchanged.
+.SP Options:
+None.
+.SE
+.KY substitute
+.IP "[range] s[ubstitute] [/pattern/replace/] [options] [count] [flags]"
+.KY &
+.Ip "[range] & [options] [count] [flags]"
+.KY ~
+.Ip "[range] ~ [options] [count] [flags]"
+Make substitutions.
+Replace the first instance of
+.LI pattern
+with the string
+.LI replace
+on the specified line(s).
+If the
+.QT /pattern/repl/
+argument is not specified, the
+.QT /pattern/repl/
+from the previous
+.CO substitute
+command is used.
+.sp
+If
+.LI options
+includes the letter
+.QT c
+(confirm), you will be prompted for confirmation before each replacement
+is done.
+An affirmative response (in English, a
+.QT y
+character) causes the replacement to be made.
+A quit response (in English, a
+.QT q
+character) causes the
+.CO substitute
+command to be terminated.
+Any other response causes the replacement not to be made, and the
+.CO substitute
+command continues.
+If
+.LI options
+includes the letter
+.QT g
+(global), all nonoverlapping instances of
+.LI pattern
+in the line are replaced.
+.sp
+The
+.CO &
+version of the command is the same as not specifying a pattern
+or replacement string to the
+.CO substitute
+command, and the
+.QT &
+is replaced by the pattern and replacement information from the
+previous substitute command.
+.sp
+The
+.CO ~
+version of the command is the same as
+.CO &
+and
+.CO s ,
+except that the search pattern used is the last RE used in
+.i any
+command, not necessarily the one used in the last
+.CO substitute
+command.
+.sp
+For example, in the sequence
+.ft C
+.(b
+s/red/blue/
+/green
+~
+.)b
+.ft R
+the
+.QT ~
+is equivalent to
+.QT s/green/blue/ .
+.sp
+The
+.CO substitute
+command may be interrupted, using the terminal interrupt character.
+All substitutions completed before the interrupt are retained.
+.SS
+.SP Line:
+Set to the last line upon which a substitution was made.
+.SP Options:
+None.
+.SE
+.KY suspend
+.IP "su[spend][!]"
+.KY stop
+.Ip "st[op][!]"
+.KY <control-Z>
+.Ip <control-Z>
+Suspend the edit session.
+Appending a
+.QT !
+character to these commands turns off the
+.OP autowrite
+option for the command.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+Affected by the
+.OP autowrite
+option.
+.SE
+.KY tag
+.IP "ta[g][!] tagstring"
+Edit the file containing the specified tag.
+Search for the tagstring, which can be in a different file.
+If the tag is in a different file, then the new file is edited.
+If the current file has been modified since the last complete write,
+the
+.CO tag
+command will fail.
+This check can be overridden by appending the
+.QT !
+character to the command name.
+.sp
+The
+.CO tag
+command searches for
+.LI tagstring
+in the tags file(s) specified by the
+.Op tags
+option.
+(See
+.XR ctags 1
+for more information on tags files.)
+.SS
+.SP Line:
+Set to the line indicated by the tag.
+.SP Options:
+Affected by the
+.OP autowrite ,
+.OP taglength ,
+.OP tags
+and
+.OP writeany
+options.
+.SE
+.KY tagpop
+.IP "tagp[op][!] [file | number]"
+Pop to the specified tag in the tags stack.
+If neither
+.LI file
+or
+.LI number
+is specified, the
+.CO tagpop
+command pops to the most recent entry on the tags stack.
+If
+.LI file
+or
+.LI number
+is specified, the
+.CO tagpop
+command pops to the most recent entry in the tags stack for that file,
+or numbered entry in the tags stack, respectively.
+(See the
+.CO display
+command for information on displaying the tags stack.)
+.sp
+If the file has been modified since the last complete write, the
+.CO tagpop
+command will fail.
+This check may be overridden by appending a
+.QT !
+character to the command name.
+.SS
+.SP Line:
+Set to the line indicated by the tag.
+.SP Options:
+Affected by the
+.OP autowrite ,
+and
+.OP writeany
+options.
+.SE
+.KY tagtop
+.IP "tagt[op][!]"
+Pop to the least recent tag on the tags stack, clearing the tags stack.
+.sp
+If the file has been modified since the last complete write, the
+.CO tagpop
+command will fail.
+This check may be overridden by appending a
+.QT !
+character to the command name.
+.SS
+.SP Line:
+Set to the line indicated by the tag.
+.SP Options:
+Affected by the
+.OP autowrite ,
+and
+.OP writeany
+options.
+.SE
+.KY unabbrev
+.IP "una[bbrev] lhs"
+Delete an abbreviation.
+Delete
+.LI lhs
+from the current list of abbreviations.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY undo
+.IP "u[ndo]"
+Undo the last change made to the file.
+Changes made by
+.CO global ,
+.CO v ,
+.CO visual
+and map sequences are considered a single command.
+If repeated, the
+.CO u
+command alternates between these two states, and is its own inverse.
+.SS
+.SP Line:
+Set to the last line modified by the command.
+.SP Options:
+None.
+.SE
+.KY unmap
+.IP "unm[ap][!] lhs"
+Unmap a mapped string.
+Delete the command mode map definition for
+.LI lhs .
+If a
+.QT !
+character is appended to the command name, delete the text input mode
+map definition instead.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY version
+.IP "ve[rsion]"
+Display the version of the
+.CO ex/vi
+editor.
+.KY visual
+.IP "[line] vi[sual] [type] [count] [flags]"
+.CO Ex
+mode only.
+Enter
+.CO vi .
+The
+.LI type
+is optional, and can be
+.QT \- ,
+.QT +
+or
+.QT ^ ,
+as in the
+.CO ex
+.CO z
+command, to specify the the position of the specified line in the screen
+window.
+(The default is to place the line at the top of the screen window.)
+A
+.LI count
+specifies the number of lines that will initially be displayed.
+(The default is the value of the
+.OP window
+editor option.)
+.SS
+.SP Line:
+Unchanged unless
+.LI line
+is specified, in which case it is set to that line.
+.SP Options:
+None.
+.SE
+.KY visual
+.IP "vi[sual][!] [+cmd] [file]"
+.CO Vi
+mode only.
+Edit a new file.
+Identical to the
+.QT "edit[!] [+cmd] [file]"
+command.
+.KY viusage
+.IP "viu[sage] [command]"
+Display usage for a
+.CO vi
+command.
+If
+.LI command
+is specified, a usage statement for that command is displayed.
+Otherwise, usage statements for all
+.CO vi
+commands are displayed.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY write
+.IP "[range] w[rite][!] [>>] [file]"
+.Ip "[range] w[rite] [!] [file]"
+.KY wn
+.Ip "[range] wn[!] [>>] [file]"
+.KY wq
+.Ip "[range] wq[!] [>>] [file]"
+Write the file.
+The specified lines (the entire file, if no range is given) is written
+to
+.LI file .
+If
+.LI file
+is not specified, the current pathname is used.
+If
+.LI file
+is specified, and it exists, or if the current pathname was set using the
+.CO file
+command, and the file already exists, these commands will fail.
+Appending a
+.QT !
+character to the command name will override this check and the write
+will be attempted, regardless.
+.sp
+Specifying the optional
+.QT >>
+string will cause the write to be appended to the file, in which case
+no tests are made for the file already existing.
+.sp
+If the file is preceded by a
+.QT !
+character, the program named in the SHELL environment variable is
+invoked with file as its second argument, and the specified lines
+are passed as standard input to that command.
+The
+.QT !
+in this usage must be separated from command name by at least one
+whitespace character.
+The special meaning of the
+.QT !
+may be overridden by escaping it with a backslash
+.PQ \e
+character.
+.sp
+The
+.CO wq
+version of the write command will exit the editor after writing the file,
+if there are no further files to edit.
+Appending a
+.QT !
+character to the command name or entering two
+.QQ quit
+commands (i.e.
+.CO wq ,
+.CO quit ,
+.CO xit
+or
+.CO ZZ )
+in a row) will override this check and the editor will exit,
+ignoring any files that have not yet been edited.
+.sp
+The
+.CO wn
+version of the write command will move to the next file after writing
+the file, unless the write fails.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+Affected by the
+.OP readonly
+and
+.OP writeany
+options.
+.SE
+.KY xit
+.IP "[range] x[it][!] [file]"
+Write the file if it has been modified.
+The specified lines are written to
+.LI file ,
+if the file has been modified since the last complete write to any
+file.
+If no
+.LI range
+is specified, the entire file is written.
+.sp
+The
+.CO xit
+command will exit the editor after writing the file,
+if there are no further files to edit.
+Appending a
+.QT !
+character to the command name or entering two
+.QQ quit
+commands (i.e.
+.CO wq ,
+.CO quit ,
+.CO xit
+or
+.CO ZZ )
+in a row) will override this check and the editor will exit,
+ignoring any files that have not yet been edited.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+Affected by the
+.OP readonly
+and
+.OP writeany
+options.
+.SE
+.KY yank
+.IP "[range] ya[nk] [buffer] [count]"
+Copy the specified lines to a buffer.
+If no buffer is specified, the unnamed buffer is used.
+.SS
+.SP Line:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY z
+.IP "[line] z [type] [count] [flags]"
+Adjust the window.
+If no
+.LI type
+is specified, then
+.LI count
+lines following the specified line are displayed.
+The default
+.LI count
+is the value of the
+.OP window
+option.
+The
+.LI type
+argument changes the position at which
+.LI line
+is displayed on the screen by changing the number of lines
+displayed before and after
+.LI line .
+The following
+.LI type
+characters may be used:
+.SS
+.SP \-
+Place the line at the bottom of the screen.
+.SP +
+Place the line at the top of the screen.
+.SP \&.
+Place the line in the middle of the screen.
+.SP ^
+Write out count lines starting
+.LI "count * 2"
+lines before
+.LI line ;
+the net effect of this is that a
+.QT z^
+command following a
+.CO z
+command writes the previous page.
+.SP =
+Center
+.LI line
+on the screen with a line of hyphens displayed immediately before and
+after it.
+The number of preceding and following lines of text displayed are
+reduced to account for those lines.
+.SE
+.SS
+.SP Line:
+Set to the last line displayed, with the exception of the
+.Dq Li \&=
+.LI type ,
+where the current line is set to the line specified by the command.
+.SP Options:
+Affected by the
+.Sy window
+option.
+.SE
diff --git a/usr.bin/vi/USD.doc/vi.ref/merge.awk b/usr.bin/vi/USD.doc/vi.ref/merge.awk
new file mode 100644
index 000000000000..16b51520a778
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/merge.awk
@@ -0,0 +1,16 @@
+# @(#)merge.awk 8.3 (Berkeley) 5/26/94
+#
+# merge index entries into one line per label
+$1 == prev {
+ printf ", %s", $2;
+ next;
+}
+{
+ if (NR != 1)
+ printf "\n";
+ printf "%s \t%s", $1, $2;
+ prev = $1;
+}
+END {
+ printf "\n"
+}
diff --git a/usr.bin/vi/USD.doc/vi.ref/paper.ps b/usr.bin/vi/USD.doc/vi.ref/paper.ps
new file mode 100644
index 000000000000..e429d56ba11f
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/paper.ps
@@ -0,0 +1,30924 @@
+%!PS-Adobe-1.0
+%%Creator: python.bostic.com:root (Charlie,458E,7750)
+%%Title: stdin (ditroff)
+%%CreationDate: Mon Aug 15 14:24:12 1994
+%%EndComments
+% @(#)psdit.pro 1.6 11/6/90
+% lib/psdit.pro -- prolog for psdit (ditroff) files
+% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved.
+% last edit: shore Sat Nov 23 20:28:03 1985
+% RCSID: $Header: psdit.pro,v 2.1 85/11/24 12:19:43 shore Rel $
+
+% Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics,
+% 17 Feb, 87.
+
+/$DITroff 140 dict def $DITroff begin
+/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def
+/xi{0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto
+ /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F}def
+/PB{save /psv exch def currentpoint translate
+ resolution 72 div dup neg scale 0 0 moveto}def
+/PE{psv restore}def
+/arctoobig 90 def /arctoosmall .05 def
+/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def
+/tan{dup sin exch cos div}def
+/point{resolution 72 div mul}def
+/dround {transform round exch round exch itransform}def
+/xT{/devname exch def}def
+/xr{/mh exch def /my exch def /resolution exch def}def
+/xp{}def
+/xs{docsave restore end}def
+/xt{}def
+/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not
+ {fonts slotno fontname findfont put fontnames slotno fontname put}if}def
+/xH{/fontheight exch def F}def
+/xS{/fontslant exch def F}def
+/s{/fontsize exch def /fontheight fontsize def F}def
+/f{/fontnum exch def F}def
+/F{fontheight 0 le{/fontheight fontsize def}if
+ fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore
+ fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if
+ makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def
+/X{exch currentpoint exch pop moveto show}def
+/N{3 1 roll moveto show}def
+/Y{exch currentpoint pop exch moveto show}def
+/S{show}def
+/ditpush{}def/ditpop{}def
+/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def
+/AN{4 2 roll moveto 0 exch ashow}def
+/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def
+/AS{0 exch ashow}def
+/MX{currentpoint exch pop moveto}def
+/MY{currentpoint pop exch moveto}def
+/MXY{moveto}def
+/cb{pop}def % action on unknown char -- nothing for now
+/n{}def/w{}def
+/p{pop showpage xi}def
+/Dt{/Dlinewidth exch def}def 1 Dt
+/Ds{/Ddash exch def}def -1 Ds
+/i{/Dstipple exch def}def 1 i
+/Dsetlinewidth{2 Dlinewidth mul setlinewidth}def
+/Dsetdash{Ddash 4 eq{[8 12]}{Ddash 16 eq{[32 36]}
+ {Ddash 20 eq{[32 12 8 12]}{[]}ifelse}ifelse}ifelse 0 setdash}def
+/Dstroke{gsave Dsetlinewidth Dsetdash 1 setlinecap stroke grestore
+ currentpoint newpath moveto}def
+/Dl{rlineto Dstroke}def
+/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop
+ currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def
+ currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def
+/Dc{dup arcellipse Dstroke}def
+/De{arcellipse Dstroke}def
+/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def
+ /cradius centerv centerv mul centerh centerh mul add sqrt def
+ /eradius endv endv mul endh endh mul add sqrt def
+ /endang endv endh atan def
+ /startang centerv neg centerh neg atan def
+ /sweep startang endang sub dup 0 lt{360 add}if def
+ sweep arctoobig gt
+ {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def
+ /midh midang cos midrad mul def /midv midang sin midrad mul def
+ midh neg midv neg endh endv centerh centerv midh midv Da
+ Da}
+ {sweep arctoosmall ge
+ {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def
+ centerv neg controldelt mul centerh controldelt mul
+ endv neg controldelt mul centerh add endh add
+ endh controldelt mul centerv add endv add
+ centerh endh add centerv endv add rcurveto Dstroke}
+ {centerh endh add centerv endv add rlineto Dstroke}
+ ifelse}
+ ifelse}def
+/Dpatterns[
+[%cf[widthbits]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000103810000000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000001038100000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0042660000246600>]
+[8<0000990000990000>]
+[8<0804020180402010>]
+[8<2418814242811824>]
+[8<6699996666999966>]
+[8<8000000008000000>]
+[8<00001c3e363e1c00>]
+[8<0000000000000000>]
+[32<00000040000000c00000004000000040000000e0000000000000000000000000>]
+[32<00000000000060000000900000002000000040000000f0000000000000000000>]
+[32<000000000000000000e0000000100000006000000010000000e0000000000000>]
+[32<00000000000000002000000060000000a0000000f00000002000000000000000>]
+[32<0000000e0000000000000000000000000000000f000000080000000e00000001>]
+[32<0000090000000600000000000000000000000000000007000000080000000e00>]
+[32<00010000000200000004000000040000000000000000000000000000000f0000>]
+[32<0900000006000000090000000600000000000000000000000000000006000000>]]
+[%ug
+[8<0000020000000000>]
+[8<0000020000002000>]
+[8<0004020000002000>]
+[8<0004020000402000>]
+[8<0004060000402000>]
+[8<0004060000406000>]
+[8<0006060000406000>]
+[8<0006060000606000>]
+[8<00060e0000606000>]
+[8<00060e000060e000>]
+[8<00070e000060e000>]
+[8<00070e000070e000>]
+[8<00070e020070e000>]
+[8<00070e020070e020>]
+[8<04070e020070e020>]
+[8<04070e024070e020>]
+[8<04070e064070e020>]
+[8<04070e064070e060>]
+[8<06070e064070e060>]
+[8<06070e066070e060>]
+[8<06070f066070e060>]
+[8<06070f066070f060>]
+[8<060f0f066070f060>]
+[8<060f0f0660f0f060>]
+[8<060f0f0760f0f060>]
+[8<060f0f0760f0f070>]
+[8<0e0f0f0760f0f070>]
+[8<0e0f0f07e0f0f070>]
+[8<0e0f0f0fe0f0f070>]
+[8<0e0f0f0fe0f0f0f0>]
+[8<0f0f0f0fe0f0f0f0>]
+[8<0f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f1f9>]
+[8<bf8f1f9ff9f8f1f9>]
+[8<bf8f1f9ffbf8f1f9>]
+[8<bf8f1fdffbf8f1f9>]
+[8<bf8f1fdffbf8f1fd>]
+[8<ff8f1fdffbf8f1fd>]
+[8<ff8f1fdffff8f1fd>]
+[8<ff8f1ffffff8f1fd>]
+[8<ff8f1ffffff8f1ff>]
+[8<ff9f1ffffff8f1ff>]
+[8<ff9f1ffffff9f1ff>]
+[8<ff9f9ffffff9f1ff>]
+[8<ff9f9ffffff9f9ff>]
+[8<ffbf9ffffff9f9ff>]
+[8<ffbf9ffffffbf9ff>]
+[8<ffbfdffffffbf9ff>]
+[8<ffbfdffffffbfdff>]
+[8<ffffdffffffbfdff>]
+[8<ffffdffffffffdff>]
+[8<fffffffffffffdff>]
+[8<ffffffffffffffff>]]
+[%mg
+[8<8000000000000000>]
+[8<0822080080228000>]
+[8<0204081020408001>]
+[8<40e0400000000000>]
+[8<66999966>]
+[8<8001000010080000>]
+[8<81c36666c3810000>]
+[8<f0e0c08000000000>]
+[16<07c00f801f003e007c00f800f001e003c007800f001f003e007c00f801f003e0>]
+[16<1f000f8007c003e001f000f8007c003e001f800fc007e003f001f8007c003e00>]
+[8<c3c300000000c3c3>]
+[16<0040008001000200040008001000200040008000000100020004000800100020>]
+[16<0040002000100008000400020001800040002000100008000400020001000080>]
+[16<1fc03fe07df0f8f8f07de03fc01f800fc01fe03ff07df8f87df03fe01fc00f80>]
+[8<80>]
+[8<8040201000000000>]
+[8<84cc000048cc0000>]
+[8<9900009900000000>]
+[8<08040201804020100800020180002010>]
+[8<2418814242811824>]
+[8<66999966>]
+[8<8000000008000000>]
+[8<70f8d8f870000000>]
+[8<0814224180402010>]
+[8<aa00440a11a04400>]
+[8<018245aa45820100>]
+[8<221c224180808041>]
+[8<88000000>]
+[8<0855800080550800>]
+[8<2844004482440044>]
+[8<0810204080412214>]
+[8<00>]]]def
+/Dfill{
+ save 6 1 roll
+ transform /maxy exch def /maxx exch def
+ transform /miny exch def /minx exch def
+ minx maxx gt{/minx maxx /maxx minx def def}if
+ miny maxy gt{/miny maxy /maxy miny def def}if
+ Dpatterns Dstipple 1 sub get exch 1 sub get
+ aload pop /stip exch def /stipw exch def /stiph 128 def
+ /imatrix[stipw 0 0 stiph 0 0]def
+ /tmatrix[stipw 0 0 stiph 0 0]def
+ /minx minx cvi stiph idiv stiph mul def
+ /miny miny cvi stipw idiv stipw mul def
+ eoclip 0 setgray
+ miny stiph maxy{
+ tmatrix exch 5 exch put
+ minx stipw maxx{
+ tmatrix exch 4 exch put tmatrix setmatrix
+ stipw stiph true imatrix {stip} imagemask
+ }for
+ }for
+ restore
+}def
+/Dp{Dfill Dstroke}def
+/DP{Dfill currentpoint newpath moveto}def
+end
+
+/ditstart{$DITroff begin
+ /nfonts 60 def % NFONTS makedev/ditroff dependent!
+ /fonts[nfonts{0}repeat]def
+ /fontnames[nfonts{()}repeat]def
+/docsave save def
+}def
+
+% character outcalls
+/oc{
+ /pswid exch def /cc exch def /name exch def
+ /ditwid pswid fontsize mul resolution mul 72000 div def
+ /ditsiz fontsize resolution mul 72 div def
+ ocprocs name known{ocprocs name get exec}{name cb}ifelse
+}def
+/fractm [.65 0 0 .6 0 0] def
+/fraction{
+ /fden exch def /fnum exch def gsave /cf currentfont def
+ cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto
+ fnum show rmoveto currentfont cf setfont(\244)show setfont fden show
+ grestore ditwid 0 rmoveto
+}def
+/oce{grestore ditwid 0 rmoveto}def
+/dm{ditsiz mul}def
+/ocprocs 50 dict def ocprocs begin
+(14){(1)(4)fraction}def
+(12){(1)(2)fraction}def
+(34){(3)(4)fraction}def
+(13){(1)(3)fraction}def
+(23){(2)(3)fraction}def
+(18){(1)(8)fraction}def
+(38){(3)(8)fraction}def
+(58){(5)(8)fraction}def
+(78){(7)(8)fraction}def
+(sr){gsave 0 .06 dm rmoveto(\326)show oce}def
+(is){gsave 0 .15 dm rmoveto(\362)show oce}def
+(->){gsave 0 .02 dm rmoveto(\256)show oce}def
+(<-){gsave 0 .02 dm rmoveto(\254)show oce}def
+(==){gsave 0 .05 dm rmoveto(\272)show oce}def
+(uc){gsave currentpoint 400 .009 dm mul add translate
+ 8 -8 scale ucseal oce}def
+end
+
+% an attempt at a PostScript FONT to implement ditroff special chars
+% this will enable us to
+% cache the little buggers
+% generate faster, more compact PS out of psdit
+% confuse everyone (including myself)!
+50 dict dup begin
+/FontType 3 def
+/FontName /DIThacks def
+/FontMatrix [.001 0 0 .001 0 0] def
+/FontBBox [-260 -260 900 900] def% a lie but ...
+/Encoding 256 array def
+0 1 255{Encoding exch /.notdef put}for
+Encoding
+ dup 8#040/space put %space
+ dup 8#110/rc put %right ceil
+ dup 8#111/lt put %left top curl
+ dup 8#112/bv put %bold vert
+ dup 8#113/lk put %left mid curl
+ dup 8#114/lb put %left bot curl
+ dup 8#115/rt put %right top curl
+ dup 8#116/rk put %right mid curl
+ dup 8#117/rb put %right bot curl
+ dup 8#120/rf put %right floor
+ dup 8#121/lf put %left floor
+ dup 8#122/lc put %left ceil
+ dup 8#140/sq put %square
+ dup 8#141/bx put %box
+ dup 8#142/ci put %circle
+ dup 8#143/br put %box rule
+ dup 8#144/rn put %root extender
+ dup 8#145/vr put %vertical rule
+ dup 8#146/ob put %outline bullet
+ dup 8#147/bu put %bullet
+ dup 8#150/ru put %rule
+ dup 8#151/ul put %underline
+ pop
+/DITfd 100 dict def
+/BuildChar{0 begin
+ /cc exch def /fd exch def
+ /charname fd /Encoding get cc get def
+ /charwid fd /Metrics get charname get def
+ /charproc fd /CharProcs get charname get def
+ charwid 0 fd /FontBBox get aload pop setcachedevice
+ 2 setlinejoin 40 setlinewidth
+ newpath 0 0 moveto gsave charproc grestore
+ end}def
+/BuildChar load 0 DITfd put
+/CharProcs 50 dict def
+CharProcs begin
+/space{}def
+/.notdef{}def
+/ru{500 0 rls}def
+/rn{0 840 moveto 500 0 rls}def
+/vr{0 800 moveto 0 -770 rls}def
+/bv{0 800 moveto 0 -1000 rls}def
+/br{0 840 moveto 0 -1000 rls}def
+/ul{0 -140 moveto 500 0 rls}def
+/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def
+/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def
+/sq{80 0 rmoveto currentpoint dround newpath moveto
+ 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def
+/bx{80 0 rmoveto currentpoint dround newpath moveto
+ 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def
+/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc
+ 50 setlinewidth stroke}def
+
+/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def
+/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def
+/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def
+/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def
+/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub
+ 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub
+ 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def
+/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def
+/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def
+/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def
+end
+
+/Metrics 50 dict def Metrics begin
+/.notdef 0 def
+/space 500 def
+/ru 500 def
+/br 0 def
+/lt 416 def
+/lb 416 def
+/rt 416 def
+/rb 416 def
+/lk 416 def
+/rk 416 def
+/rc 416 def
+/lc 416 def
+/rf 416 def
+/lf 416 def
+/bv 416 def
+/ob 350 def
+/bu 350 def
+/ci 750 def
+/bx 750 def
+/sq 750 def
+/rn 500 def
+/ul 500 def
+/vr 0 def
+end
+
+DITfd begin
+/s2 500 def /s4 250 def /s3 333 def
+/a4p{arcto pop pop pop pop}def
+/2cx{2 copy exch}def
+/rls{rlineto stroke}def
+/currx{currentpoint pop}def
+/dround{transform round exch round exch itransform} def
+end
+end
+/DIThacks exch definefont pop
+ditstart
+(psc)xT
+576 1 1 xr
+1(Times-Roman)xf 1 f
+2(Times-Italic)xf 2 f
+3(Times-Bold)xf 3 f
+4(Times-BoldItalic)xf 4 f
+5(Helvetica)xf 5 f
+6(Helvetica-Bold)xf 6 f
+7(Courier)xf 7 f
+8(Courier-Bold)xf 8 f
+9(Symbol)xf 9 f
+10(DIThacks)xf 10 f
+10 s
+1 f
+xi
+%%EndProlog
+
+%%Page: 1 1
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+12 s
+1796 795(Ex/Vi)N
+2055(Reference)X
+2491(Manual)X
+2 f
+10 s
+2107 975(Keith)N
+2300(Bostic)X
+1 f
+1861 1155(Computer)N
+2201(Science)X
+2471(Division)X
+1328 1245(Department)N
+1727(of)X
+1814(Electrical)X
+2142(Engineering)X
+2554(and)X
+2690(Computer)X
+3030(Science)X
+1754 1335(University)N
+2112(of)X
+2199(California,)X
+2564(Berkeley)X
+1856 1425(Berkeley,)N
+2186(California)X
+2551(94720)X
+2038 1605(August)N
+2289(15,)X
+2409(1994)X
+2 f
+2168 1965(Abstract)N
+1 f
+776 2244(This)N
+948(document)X
+1294(is)X
+1377(the)X
+1505 0.4531(reference)AX
+1836(guide)X
+2045(for)X
+2170(the)X
+2299(4.4BSD)X
+2585(implementations)X
+3149(of)X
+3 f
+3247(nex)X
+1 f
+(/)S
+3 f
+3389(nvi)X
+1 f
+3495(,)X
+3546(which)X
+3773(are)X
+576 2334(reimplementations)N
+1192(of)X
+1279(the)X
+1397(historic)X
+1657(Berkeley)X
+3 f
+1967(ex)X
+1 f
+2043(/)X
+3 f
+2065(vi)X
+1 f
+2147(editors.)X
+2 f
+1996 2778(Acknowledgements)N
+1 f
+776 3063(Bruce)N
+1005(Englar)X
+1256(encouraged)X
+1664(the)X
+1799(early)X
+1997(development)X
+2448(of)X
+2552(the)X
+2687(historic)X
+3 f
+2965(ex)X
+1 f
+3041(/)X
+3 f
+3063(vi)X
+1 f
+3163(editor.)X
+3428(Peter)X
+3631(Kessler)X
+576 3153(helped)N
+811(bring)X
+1001(sanity)X
+1213(to)X
+1296(version)X
+1553(2's)X
+1672(command)X
+2009(layout.)X
+2270(Bill)X
+2410(Joy)X
+2541(wrote)X
+2744(versions)X
+3031(1)X
+3091(and)X
+3227(2.0)X
+3347(through)X
+3616(2.7,)X
+3756(and)X
+576 3243(created)N
+842(the)X
+973(framework)X
+1359(that)X
+1512(users)X
+1710(see)X
+1846(in)X
+1941(the)X
+2072(present)X
+2337(editor.)X
+2597(Mark)X
+2804(Horton)X
+3065(added)X
+3291(macros)X
+3557(and)X
+3707(other)X
+576 3333(features)N
+851(and)X
+987(made)X
+3 f
+1181(ex)X
+1 f
+1257(/)X
+3 f
+1279(vi)X
+1 f
+1361(work)X
+1546(on)X
+1646(a)X
+1702(large)X
+1883(number)X
+2148(of)X
+2235(terminals)X
+2553(and)X
+2689(Unix)X
+2869(systems.)X
+3 f
+776 3456(Nvi)N
+1 f
+918(is)X
+993(originally)X
+1326(derived)X
+1589(from)X
+1767(software)X
+2066(contributed)X
+2454(to)X
+2539(the)X
+2660(University)X
+3021(of)X
+3111(California,)X
+3479(Berkeley)X
+3792(by)X
+576 3546(Steve)N
+774(Kirkendall,)X
+1157(the)X
+1275(author)X
+1500(of)X
+1587(the)X
+3 f
+1705(vi)X
+1 f
+1787(clone)X
+3 f
+1981(elvis)X
+1 f
+2132(.)X
+776 3669(IEEE)N
+992(Standard)X
+1319(Portable)X
+1628(Operating)X
+1991(System)X
+2268(Interface)X
+2597(for)X
+2733(Computer)X
+3095(Environments)X
+3587(\(POSIX\))X
+576 3759(1003.2)N
+816(style)X
+987(Regular)X
+1261(Expression)X
+1637(support)X
+1897(was)X
+2042(done)X
+2218(by)X
+2318(Henry)X
+2539(Spencer.)X
+776 3882(The)N
+930(curses)X
+1161(library)X
+1405(was)X
+1560(originally)X
+1901(done)X
+2087(by)X
+2197(Ken)X
+2361(Arnold.)X
+2658(Scrolling)X
+2981(and)X
+3127(reworking)X
+3487(for)X
+3 f
+3611(nvi)X
+1 f
+3747(was)X
+576 3972(done)N
+752(by)X
+852(Elan)X
+1019(Amir.)X
+776 4095(The)N
+923(Institute)X
+1207(of)X
+1296(Electrical)X
+1626(and)X
+1764(Electronics)X
+2147(Engineers)X
+2490(has)X
+2619(given)X
+2820(us)X
+2914(permission)X
+3288(to)X
+3373(reprint)X
+3610(portions)X
+576 4185(of)N
+682(their)X
+868(documentation.)X
+1423(Portions)X
+1728(of)X
+1834(this)X
+1987(document)X
+2341(are)X
+2478(reprinted)X
+2806(and)X
+2960(reproduced)X
+3360(from)X
+3554(IEEE)X
+3766(Std)X
+576 4275(1003.2-1992,)N
+1031(IEEE)X
+1233(Standard)X
+1546(Portable)X
+1841(Operating)X
+2190(System)X
+2453(Interface)X
+2768(for)X
+2890(Computer)X
+3238(Environments)X
+3716(\(PO-)X
+576 4365(SIX\),)N
+772(copyright)X
+1099(1992)X
+1279(by)X
+1379(the)X
+1497(Institute)X
+1779(of)X
+1866(Electrical)X
+2194(and)X
+2330(Electronics)X
+2711(Engineers,)X
+3072(Inc.)X
+776 4488(The)N
+921(\256nancial)X
+1217(support)X
+1477(of)X
+1564(UUNET)X
+1856(Communications)X
+2422(Services)X
+2714(is)X
+2787(gratefully)X
+3119(acknowledged.)X
+
+3 p
+%%Page: 3 2
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3698(USD:13-3)X
+576 762(1.)N
+676(Description)X
+1 f
+3 f
+776 885(Vi)N
+1 f
+876(is)X
+949(a)X
+1005(screen)X
+1231(oriented)X
+1514(text)X
+1654(editor.)X
+3 f
+1902(Ex)X
+1 f
+2016(is)X
+2090(a)X
+2147(line-oriented)X
+2578(text)X
+2719(editor.)X
+3 f
+2967(Ex)X
+1 f
+3081(and)X
+3 f
+3218(vi)X
+1 f
+3301(are)X
+3421(different)X
+3719(interfaces)X
+576 975(to)N
+674(the)X
+808(same)X
+1009(program,)X
+1336(and)X
+1487(it)X
+1566(is)X
+1654(possible)X
+1951(to)X
+2048(switch)X
+2292(back)X
+2479(and)X
+2630(forth)X
+2821(during)X
+3065(an)X
+3176(edit)X
+3331(session.)X
+3 f
+3637(View)X
+1 f
+3846(is)X
+3934(the)X
+576 1065(equivalent)N
+930(of)X
+1017(using)X
+1210(the)X
+3 f
+9 f
+1328(-)X
+1330(-)X
+3 f
+1374(R)X
+1 f
+1452(\(read-only\))X
+1834(option)X
+2058(of)X
+3 f
+2145(vi)X
+1 f
+2207(.)X
+776 1188(This)N
+957 0.4531(reference)AX
+1297(manual)X
+1572(is)X
+1664(the)X
+1801(one)X
+1956(provided)X
+2280(with)X
+2461(the)X
+3 f
+2598(nex)X
+1 f
+(/)S
+3 f
+2740(nvi)X
+1 f
+2885(versions)X
+3191(of)X
+3297(the)X
+3 f
+3434(ex)X
+1 f
+3510(/)X
+3 f
+3532(vi)X
+1 f
+3634(text)X
+3794(editors.)X
+3 f
+576 1278(Nex)N
+1 f
+710(/)X
+3 f
+732(nvi)X
+1 f
+868(are)X
+997(intended)X
+1302(as)X
+1398(bug-for-bug)X
+1815(compatible)X
+2200(replacements)X
+2653(for)X
+2776(the)X
+2903(original)X
+3181(Fourth)X
+3423(Berkeley)X
+3742(Software)X
+576 1368(Distribution)N
+987(\(4BSD\))X
+3 f
+1261(ex)X
+1 f
+1337(/)X
+3 f
+1359(vi)X
+1 f
+1446(programs.)X
+1814(This)X
+1981 0.4531(reference)AX
+2307(manual)X
+2568(is)X
+2646(accompanied)X
+3095(by)X
+3201(a)X
+3263(traditional-style)X
+3796(manual)X
+576 1458(page.)N
+798(That)X
+975(manual)X
+1241(page)X
+1423(describes)X
+1752(the)X
+1880(functionality)X
+2319(found)X
+2536(in)X
+3 f
+2627(ex)X
+1 f
+2703(/)X
+3 f
+2725(vi)X
+1 f
+2816(in)X
+2907(far)X
+3026(less)X
+3175(detail)X
+3382(than)X
+3549(the)X
+3676(description)X
+576 1548(here.)N
+781(In)X
+874(addition,)X
+1182(it)X
+1252(describes)X
+1578(the)X
+1703(system)X
+1952(interface)X
+2261(to)X
+3 f
+2350(ex)X
+1 f
+2426(/)X
+3 f
+2448(vi)X
+1 f
+2510(,)X
+2557(e.g.)X
+2700(command)X
+3043(line)X
+3190(options,)X
+3472(session)X
+3730(recovery,)X
+576 1638(signals,)N
+838(environmental)X
+1321(variables,)X
+1651(and)X
+1787(similar)X
+2029(things.)X
+776 1761(This)N
+939 0.4531(reference)AX
+1261(is)X
+1336(intended)X
+1634(for)X
+1750(users)X
+1937(already)X
+2196(familiar)X
+2472(with)X
+3 f
+2636(ex)X
+1 f
+2712(/)X
+3 f
+2734(vi)X
+1 f
+2796(.)X
+2858(Anyone)X
+3134(else)X
+3281(should)X
+3516(almost)X
+3751(certainly)X
+576 1851(read)N
+737(a)X
+795(good)X
+977(tutorial)X
+1230(on)X
+1332(the)X
+1452(editor)X
+1661(\256rst.)X
+1847(If)X
+1923(you)X
+2065(are)X
+2186(in)X
+2270(an)X
+2368(unfamiliar)X
+2723(environment,)X
+3169(and)X
+3306(you)X
+3447(absolutely)X
+3797(have)X
+3970(to)X
+576 1941(get)N
+702(work)X
+895(done)X
+1079(immediately,)X
+1527(see)X
+1658(the)X
+1784(section)X
+2039(entitled)X
+2308(``)X
+3 f
+2362(Fast)X
+2538(Startup)X
+1 f
+2800('')X
+2883(in)X
+2974(the)X
+3101(manual)X
+3366(page.)X
+3587(It)X
+3665(is)X
+3747(probably)X
+576 2031(enough)N
+832(to)X
+914(get)X
+1032(you)X
+1172(started.)X
+776 2154(There)N
+984(are)X
+1103(a)X
+1159(few)X
+1300(features)X
+1575(in)X
+3 f
+1657(nex)X
+1 f
+(/)S
+3 f
+1799(nvi)X
+1 f
+1925(that)X
+2065(are)X
+2185(not)X
+2308(found)X
+2516(in)X
+2599(historic)X
+2860(versions)X
+3148(of)X
+3 f
+3236(ex)X
+1 f
+3312(/)X
+3 f
+3334(vi)X
+1 f
+3396(.)X
+3457(Some)X
+3660(of)X
+3748(the)X
+3867(more)X
+576 2244(interesting)N
+941(of)X
+1035(those)X
+1231(features)X
+1513(are)X
+1639(brie\257y)X
+1875(described)X
+2210(in)X
+2299(the)X
+2424(section)X
+2678(entitled)X
+2945(``)X
+3 f
+2999(Additional)X
+3389(Features)X
+1 f
+3688('')X
+3769(near)X
+3934(the)X
+576 2334(end)N
+719(of)X
+813(this)X
+955(document.)X
+1338(For)X
+1476(the)X
+1601(rest)X
+1744(of)X
+1838(this)X
+1980(document,)X
+3 f
+2343(nex)X
+1 f
+(/)S
+3 f
+2485(nvi)X
+1 f
+2618(is)X
+2698(used)X
+2872(only)X
+3042(when)X
+3244(it)X
+3316(is)X
+3397(necessary)X
+3738(to)X
+3828(distin-)X
+576 2424(guish)N
+769(it)X
+833(from)X
+1009(the)X
+1127(historic)X
+1387(implementations)X
+1940(of)X
+3 f
+2027(ex)X
+1 f
+2103(/)X
+3 f
+2125(vi)X
+1 f
+2187(.)X
+776 2547(Future)N
+1012(versions)X
+1306(of)X
+1400(this)X
+1542(software)X
+1846(will)X
+1997(be)X
+2100(periodically)X
+2510(made)X
+2712(available)X
+3030(by)X
+3138(anonymous)X
+3535(ftp,)X
+3672(and)X
+3816(can)X
+3956(be)X
+576 2637(retrieved)N
+882(from)X
+7 f
+1058(ftp.cs.berkeley.edu)X
+1 f
+(,)S
+2010(in)X
+2092(the)X
+2210(directory)X
+7 f
+2520(ucb/4bsd)X
+1 f
+(.)S
+3 f
+576 2823(2.)N
+676(Startup)X
+958(Information)X
+1 f
+3 f
+776 2946(Ex)N
+1 f
+869(/)X
+3 f
+891(vi)X
+1 f
+981(interprets)X
+1312(one)X
+1456(of)X
+1551(two)X
+1699(possible)X
+1989(environmental)X
+2480(variables)X
+2798(and)X
+2942(reads)X
+3140(up)X
+3248(to)X
+3338(three)X
+3527(of)X
+3622(\256ve)X
+3770(possible)X
+576 3036(\256les)N
+737(during)X
+974(startup.)X
+1260(The)X
+1413(variables)X
+1731(and)X
+1875(\256les)X
+2036(are)X
+2163(expected)X
+2477(to)X
+2567(contain)X
+3 f
+2831(ex)X
+1 f
+2935(commands,)X
+3330(not)X
+3 f
+3460(vi)X
+1 f
+3550(commands.)X
+3965(In)X
+576 3126(addition,)N
+879(they)X
+1038(are)X
+1158(interpreted)X
+2 f
+1527(before)X
+1 f
+1753(the)X
+1872(\256le)X
+1996(to)X
+2080(be)X
+2178(edited)X
+2396(is)X
+2471(read,)X
+2652(and)X
+2790(therefore)X
+3103(many)X
+3 f
+3303(ex)X
+1 f
+3401(commands)X
+3770(may)X
+3930(not)X
+576 3216(be)N
+683(used.)X
+901(Generally,)X
+1269(any)X
+1416(command)X
+1763(that)X
+1914(requires)X
+2204(output)X
+2439(to)X
+2532(the)X
+2660(screen)X
+2896(or)X
+2993(that)X
+3143(needs)X
+3356(a)X
+3422(\256le)X
+3554(upon)X
+3744(which)X
+3970(to)X
+576 3306(operate,)N
+853(will)X
+997(cause)X
+1196(an)X
+1292(error)X
+1469(if)X
+1538(included)X
+1834(in)X
+1916(a)X
+1972(startup)X
+2210(\256le)X
+2332(or)X
+2419(environmental)X
+2902(variable.)X
+776 3429(Because)N
+1071(the)X
+3 f
+1197(ex)X
+1 f
+1301(command)X
+1645(set)X
+1762(supported)X
+2106(by)X
+3 f
+2214(nex)X
+1 f
+(/)S
+3 f
+2356(nvi)X
+1 f
+2490(is)X
+2571(a)X
+2635(superset)X
+2926(of)X
+3021(the)X
+3147(command)X
+3491(set)X
+3608(supported)X
+3952(by)X
+576 3519(most)N
+753(historical)X
+1073(implementations)X
+1628(of)X
+3 f
+1717(ex)X
+1 f
+1793(,)X
+3 f
+1835(nex)X
+1 f
+(/)S
+3 f
+1977(nvi)X
+1 f
+2105(can)X
+2238(use)X
+2366(the)X
+2485(startup)X
+2724(\256les)X
+2878(created)X
+3132(for)X
+3247(the)X
+3366(historical)X
+3685(implemen-)X
+576 3609(tations,)N
+829(but)X
+951(the)X
+1069(converse)X
+1375(may)X
+1533(not)X
+1655(be)X
+1751(true.)X
+776 3732(If)N
+852(the)X
+3 f
+9 f
+973(-)X
+975(-)X
+3 f
+1019(s)X
+1 f
+1073(\(the)X
+1221(historic)X
+9 f
+1484(-)X
+1 f
+1551(option\))X
+1805(is)X
+1881(speci\256ed,)X
+2209(or)X
+2299(if)X
+2371(standard)X
+2666(input)X
+2853(is)X
+2929(redirected)X
+3274(from)X
+3453(a)X
+3512(\256le,)X
+3657(all)X
+3760(environ-)X
+576 3822(mental)N
+814(variables)X
+1124(and)X
+1260(startup)X
+1498(\256les)X
+1651(are)X
+1770(ignored.)X
+776 3945(Otherwise,)N
+1146(startup)X
+1384(\256les)X
+1537(and)X
+1673(environmental)X
+2156(variables)X
+2466(are)X
+2585(handled)X
+2859(in)X
+2941(the)X
+3059(following)X
+3390(order:)X
+616 4068(\(1\))N
+830(The)X
+975(\256le)X
+7 f
+1097(/etc/vi.exrc)X
+1 f
+1693(is)X
+1766(read,)X
+1945(as)X
+2032(long)X
+2194(as)X
+2281(it)X
+2345(is)X
+2418(owned)X
+2652(by)X
+2752(root)X
+2901(or)X
+2988(the)X
+3106(effective)X
+3408(user)X
+3562(ID)X
+3667(of)X
+3754(the)X
+3872(user.)X
+616 4191(\(2\))N
+830(The)X
+981(environmental)X
+1471(variable)X
+7 f
+1757(NEXINIT)X
+1 f
+2120(\(or)X
+2241(the)X
+2366(variable)X
+7 f
+2652(EXINIT)X
+1 f
+(,)S
+2987(if)X
+7 f
+3063(NEXINIT)X
+1 f
+3426(is)X
+3506(not)X
+3635(set\))X
+3778(is)X
+3858(inter-)X
+830 4281(preted.)N
+616 4404(\(3\))N
+830(If)X
+918(neither)X
+7 f
+1175(NEXINIT)X
+1 f
+1545(or)X
+7 f
+1646(EXINIT)X
+1 f
+1968(was)X
+2127(set,)X
+2270(and)X
+2420(the)X
+7 f
+2552(HOME)X
+1 f
+2778(environmental)X
+3275(variable)X
+3568(is)X
+3655(set,)X
+3798(the)X
+3930(\256le)X
+7 f
+830 4494($HOME/.nexrc)N
+1 f
+1430(\(or)X
+1548(the)X
+1670(\256le)X
+7 f
+1796($HOME/.exrc)X
+1 f
+(,)S
+2368(if)X
+7 f
+2441($HOME/.nexrc)X
+1 f
+3041(does)X
+3212(not)X
+3338(exist\))X
+3540(is)X
+3617(read,)X
+3800(as)X
+3890(long)X
+830 4584(as)N
+917(the)X
+1035(effective)X
+1337(user)X
+1491(ID)X
+1596(of)X
+1683(the)X
+1801(user)X
+1955(is)X
+2028(root)X
+2177(or)X
+2264(is)X
+2337(the)X
+2455(same)X
+2640(as)X
+2727(the)X
+2845(owner)X
+3066(of)X
+3153(the)X
+3271(\256le.)X
+616 4707(\(4\))N
+830(If)X
+921(the)X
+3 f
+1056(exrc)X
+1 f
+1241(option)X
+1482(was)X
+1644(turned)X
+1886(on)X
+2003(by)X
+2120(one)X
+2273(of)X
+2377(the)X
+2512(previous)X
+2825(startup)X
+3080(information)X
+3495(sources,)X
+3794(the)X
+3930(\256le)X
+7 f
+830 4797(.nexrc)N
+1 f
+1142(\(or)X
+1260(the)X
+1382(\256le)X
+7 f
+1508(.exrc)X
+1 f
+(,)S
+1792(if)X
+7 f
+1864(.nexrc)X
+1 f
+2175(does)X
+2345(not)X
+2470(exist\))X
+2671(is)X
+2747(read,)X
+2929(as)X
+3019(long)X
+3184(as)X
+3274(the)X
+3395(effective)X
+3700(user)X
+3857(ID)X
+3965(of)X
+830 4887(the)N
+948(user)X
+1102(is)X
+1175(the)X
+1293(same)X
+1478(as)X
+1565(the)X
+1683(owner)X
+1904(of)X
+1991(the)X
+2109(\256le.)X
+776 5010(No)N
+894(startup)X
+1132(\256le)X
+1254(is)X
+1327(read)X
+1486(if)X
+1555(it)X
+1619(is)X
+1692(writable)X
+1975(by)X
+2075(anyone)X
+2327(other)X
+2512(than)X
+2670(its)X
+2765(owner.)X
+776 5133(It)N
+845(is)X
+918(not)X
+1040(an)X
+1136(error)X
+1313(for)X
+1427(any)X
+1563(of)X
+1650(the)X
+1768(startup)X
+2006(environmental)X
+2489(variables)X
+2799(or)X
+2886(\256les)X
+3039(not)X
+3161(to)X
+3243(exist.)X
+776 5256(Once)N
+978(all)X
+1090(environmental)X
+1585(variables)X
+1907(are)X
+2038(interpreted,)X
+2438(and)X
+2586(all)X
+2698(startup)X
+2948(\256les)X
+3114(are)X
+3246(read,)X
+3438(the)X
+3569(\256rst)X
+3726(\256le)X
+3861(to)X
+3956(be)X
+576 5346(edited)N
+800(is)X
+881(read)X
+1048(in)X
+1138(\(or)X
+1260(a)X
+1324(temporary)X
+1682(\256le)X
+1812(is)X
+1893(created\).)X
+2221(Then,)X
+2434(any)X
+2578(commands)X
+2953(speci\256ed)X
+3266(using)X
+3467(the)X
+3 f
+9 f
+3593(-)X
+3595(-)X
+3 f
+3639(c)X
+1 f
+3702(option)X
+3933(are)X
+576 5436(executed,)N
+902(in)X
+984(the)X
+1102(context)X
+1358(of)X
+1445(that)X
+1585(\256le.)X
+
+4 p
+%%Page: 4 3
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-4)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+576 762(3.)N
+676(Recovery)X
+1 f
+776 885(There)N
+991(is)X
+1071(no)X
+1178(recovery)X
+1487(program)X
+1786(for)X
+3 f
+1907(nex)X
+1 f
+(/)S
+3 f
+2049(nvi)X
+1 f
+2155(,)X
+2202(nor)X
+2336(does)X
+3 f
+2510(nex)X
+1 f
+(/)S
+3 f
+2652(nvi)X
+1 f
+2785(run)X
+2919(setuid.)X
+3177(Recovery)X
+3512(\256les)X
+3672(are)X
+3799(created)X
+576 975(readable)N
+887(and)X
+1041(writable)X
+1342(by)X
+1460(the)X
+1596(owner)X
+1835(only.)X
+2055(Users)X
+2276(may)X
+2452(recover)X
+2732(any)X
+2886(\256le)X
+3026(which)X
+3260(they)X
+3436(can)X
+3585(read,)X
+3781(and)X
+3934(the)X
+576 1065(superuser)N
+904(may)X
+1062(recover)X
+1324(any)X
+1460(edit)X
+1600(session.)X
+776 1188(Edit)N
+952(sessions)X
+1257(are)X
+1399(backed)X
+1670(by)X
+1793(\256les)X
+1969(in)X
+2074(the)X
+2215(directory)X
+2548(named)X
+2805(by)X
+2929(the)X
+3 f
+3071(recdir)X
+1 f
+3325(option)X
+3573(\(the)X
+3742(directory)X
+7 f
+576 1278(/var/tmp/vi.recover)N
+1 f
+1508(by)X
+1608(default\),)X
+1898(and)X
+2034(are)X
+2153(named)X
+2387(``)X
+3 f
+2441(vi.XXXXXX)X
+1 f
+2871('',)X
+2965(where)X
+3182(``)X
+3 f
+3236(XXXXXX)X
+1 f
+3584('')X
+3658(is)X
+3731(a)X
+3787(number)X
+576 1368(related)N
+816(to)X
+899(the)X
+1018(process)X
+1281(ID.)X
+1428(When)X
+1642(a)X
+1700(\256le)X
+1824(is)X
+1899(\256rst)X
+2045(modi\256ed,)X
+2371(a)X
+2429(second)X
+2674(recovery)X
+2978(\256le)X
+3102(containing)X
+3462(an)X
+3560(email)X
+3760(message)X
+576 1458(for)N
+691(the)X
+810(user)X
+965(is)X
+1039(created,)X
+1313(and)X
+1450(is)X
+1524(named)X
+1759(``)X
+3 f
+1813 0.3077(recover.XXXXXX)AX
+1 f
+2441('',)X
+2536(where,)X
+2774(again,)X
+2989(``)X
+3 f
+3043(XXXXXX)X
+1 f
+3391('')X
+3466(is)X
+3540(associated)X
+3890(with)X
+576 1548(the)N
+698(process)X
+963(ID.)X
+1112(Both)X
+1291(\256les)X
+1448(are)X
+1571(removed)X
+1876(at)X
+1958(the)X
+2080(end)X
+2220(of)X
+2311(a)X
+2371(normal)X
+2622(edit)X
+2766(session,)X
+3041(but)X
+3168(will)X
+3317(remain)X
+3565(if)X
+3639(the)X
+3762(edit)X
+3907(ses-)X
+576 1638(sion)N
+729(is)X
+802(abnormally)X
+1187(terminated)X
+1550(or)X
+1637(the)X
+1755(user)X
+1909(runs)X
+2067(the)X
+3 f
+2185(ex)X
+2281(preserve)X
+1 f
+2596(command.)X
+776 1761(The)N
+3 f
+935(recdir)X
+1 f
+1180(option)X
+1419(may)X
+1592(be)X
+1703(set)X
+1827(in)X
+1924(either)X
+2142(the)X
+2275(user's)X
+2502(or)X
+2604(system's)X
+2919(startup)X
+3172(information,)X
+3605(changing)X
+3934(the)X
+576 1851(recovery)N
+887(directory.)X
+1246(\(Note,)X
+1478(however,)X
+1804(that)X
+1953(if)X
+2031(a)X
+2096(memory)X
+2392(based)X
+2604(\256le)X
+2735(system)X
+2985(is)X
+3066(used)X
+3241(as)X
+3336(the)X
+3462(backup)X
+3722(directory,)X
+576 1941(each)N
+752(system)X
+1002(reboot)X
+1235(will)X
+1388(delete)X
+1609(all)X
+1718(of)X
+1814(the)X
+1941(recovery)X
+2252(\256les!)X
+2461(The)X
+2615(same)X
+2809(caution)X
+3074(applies)X
+3330(to)X
+3421(directories)X
+3789(such)X
+3965(as)X
+7 f
+576 2031(/tmp)N
+1 f
+792(which)X
+1012(are)X
+1135(cleared)X
+1392(of)X
+1483(their)X
+1654(contents)X
+1945(by)X
+2049(a)X
+2108(system)X
+2353(reboot,)X
+2601(or)X
+7 f
+2691(/usr/tmp)X
+1 f
+3098(which)X
+3317(is)X
+3393(periodically)X
+3799(cleared)X
+576 2121(of)N
+663(old)X
+785(\256les)X
+938(on)X
+1038(many)X
+1236(systems.\))X
+776 2244(The)N
+926(recovery)X
+1233(directory)X
+1548(should)X
+1786(be)X
+1887(owned)X
+2126(by)X
+2231(root,)X
+2405(or)X
+2497(at)X
+2580(least)X
+2752(by)X
+2857(a)X
+2918(pseudo-user.)X
+3371(In)X
+3463(addition,)X
+3770(if)X
+3844(direc-)X
+576 2334(tory)N
+727(``sticky-bit'')X
+1159(semantics)X
+1497(are)X
+1618(available,)X
+1950(the)X
+2070(directory)X
+2382(should)X
+2617(have)X
+2791(the)X
+2911(sticky-bit)X
+3234(set)X
+3344(so)X
+3436(that)X
+3577(\256les)X
+3731(may)X
+3890(only)X
+576 2424(be)N
+676(removed)X
+981(by)X
+1085(their)X
+1256(owners.)X
+1552(The)X
+1702(recovery)X
+2009(directory)X
+2324(must)X
+2504(be)X
+2605(read,)X
+2789(write,)X
+2999(and)X
+3140(executable)X
+3509(by)X
+3614(any)X
+3755(user,)X
+3934(i.e.)X
+576 2514(mode)N
+774(1777.)X
+776 2637(If)N
+850(the)X
+968(recovery)X
+1270(directory)X
+1581(does)X
+1749(not)X
+1872(exist,)X
+3 f
+2064(ex)X
+1 f
+2140(/)X
+3 f
+2162(vi)X
+1 f
+2245(will)X
+2390(attempt)X
+2651(to)X
+2734(create)X
+2948(it.)X
+3053(This)X
+3216(can)X
+3349(result)X
+3548(in)X
+3631(the)X
+3750(recovery)X
+576 2727(directory)N
+895(being)X
+1102(owned)X
+1345(by)X
+1454(a)X
+1518(normal)X
+1773(user,)X
+1955(which)X
+2179(means)X
+2412(that)X
+2560(that)X
+2708(user)X
+2870(will)X
+3022(be)X
+3126(able)X
+3288(to)X
+3378(remove)X
+3647(other)X
+3840(user's)X
+576 2817(recovery)N
+880(and)X
+1018(backup)X
+1272(\256les.)X
+1467(This)X
+1631(is)X
+1706(annoying,)X
+2046(but)X
+2170(is)X
+2245(not)X
+2369(a)X
+2427(security)X
+2703(issue)X
+2886(as)X
+2976(the)X
+3097(user)X
+3254(cannot)X
+3491(otherwise)X
+3826(access)X
+576 2907(or)N
+663(modify)X
+914(the)X
+1032(\256les.)X
+776 3030(The)N
+924(recovery)X
+1229(\256le)X
+1354(has)X
+1484(all)X
+1587(of)X
+1677(the)X
+1798(necessary)X
+2134(information)X
+2535(in)X
+2621(it)X
+2689(to)X
+2775(enable)X
+3009(the)X
+3131(user)X
+3289(to)X
+3375(recover)X
+3641(the)X
+3763(edit)X
+3907(ses-)X
+576 3120(sion.)N
+774(In)X
+866(addition,)X
+1173(it)X
+1242(has)X
+1374(all)X
+1479(of)X
+1571(the)X
+1694(necessary)X
+2032(email)X
+2235(headers)X
+2505(for)X
+2 f
+2623(sendmail)X
+1 f
+2912(\(8\).)X
+3070(When)X
+3286(the)X
+3408(system)X
+3654(is)X
+3731(rebooted,)X
+576 3210(all)N
+677(of)X
+765(the)X
+884(\256les)X
+1038(in)X
+7 f
+1121(/var/tmp/vi.recover)X
+1 f
+2054(named)X
+2289(``)X
+3 f
+2343 0.3077(recover.XXXXXX)AX
+1 f
+2971('')X
+3046(should)X
+3280(be)X
+3377(sent)X
+3527(to)X
+3611(their)X
+3780(owners,)X
+576 3300(by)N
+684(email,)X
+910(using)X
+1111(the)X
+3 f
+9 f
+1237(-)X
+1239(-)X
+3 f
+1283(t)X
+1 f
+1338(option)X
+1570(of)X
+3 f
+1665(sendmail)X
+1 f
+1999(\(or)X
+2121(a)X
+2185(similar)X
+2434(mechanism)X
+2826(in)X
+2915(other)X
+3107(mailers\).)X
+3437(If)X
+3 f
+3518(ex)X
+1 f
+3594(/)X
+3 f
+3616(vi)X
+1 f
+3705(receives)X
+3996(a)X
+576 3390(hangup)N
+839(\(SIGHUP\))X
+1209(signal,)X
+1447(or)X
+1541(the)X
+1666(user)X
+1828(executes)X
+2133(the)X
+3 f
+2259(ex)X
+2363(preserve)X
+1 f
+2686(command,)X
+3 f
+3050(ex)X
+1 f
+3126(/)X
+3 f
+3148(vi)X
+1 f
+3238(will)X
+3390(automatically)X
+3854(email)X
+576 3480(the)N
+694(recovery)X
+996(information)X
+1394(to)X
+1476(the)X
+1594(user.)X
+776 3603(If)N
+853(your)X
+1023(system)X
+1268(does)X
+1438(not)X
+1564(have)X
+1740(the)X
+3 f
+1862(sendmail)X
+1 f
+2192(utility)X
+2406(\(or)X
+2524(a)X
+2584(mailer)X
+2813(program)X
+3109(which)X
+3329(supports)X
+3624(its)X
+3723(interface\))X
+576 3693(the)N
+700(source)X
+936(\256le)X
+7 f
+1063(nvi/common/recover.c)X
+1 f
+2048(will)X
+2197(have)X
+2374(to)X
+2461(be)X
+2562(modi\256ed)X
+2871(to)X
+2958(use)X
+3090(your)X
+3262(local)X
+3443(mail)X
+3610(delivery)X
+3898(pro-)X
+576 3783(grams.)N
+833(Note,)X
+1030(if)X
+3 f
+1100(nex)X
+1 f
+(/)S
+3 f
+1242(nvi)X
+1 f
+1369(is)X
+1443(changed)X
+1732(to)X
+1815(use)X
+1944(another)X
+2207(mailer,)X
+2454(it)X
+2520(is)X
+2595(important)X
+2928(to)X
+3012(remember)X
+3360(that)X
+3502(the)X
+3622(owner)X
+3845(of)X
+3934(the)X
+576 3873(\256le)N
+708(given)X
+916(to)X
+1008(the)X
+1136(mailer)X
+1371(is)X
+1454(the)X
+3 f
+1582(nex)X
+1 f
+(/)S
+3 f
+1724(nvi)X
+1 f
+1860(user,)X
+2044(so)X
+2145(nothing)X
+2419(in)X
+2511(the)X
+2638(\256le)X
+2769(should)X
+3011(be)X
+3116(trusted)X
+3363(as)X
+3459(it)X
+3532(may)X
+3699(have)X
+3880(been)X
+576 3963(modi\256ed)N
+880(in)X
+962(an)X
+1058(effort)X
+1257(to)X
+1339(compromise)X
+1755(the)X
+1873(system.)X
+776 4086(Finally,)N
+1046(the)X
+1168(owner)X
+1393(execute)X
+1663(bit)X
+1771(is)X
+1848(set)X
+1961(on)X
+2065(backup)X
+2321(\256les)X
+2478(when)X
+2676(they)X
+2838(are)X
+2961(created,)X
+3238(and)X
+3378(unset)X
+3571(when)X
+3770(they)X
+3933(are)X
+576 4176(\256rst)N
+724(modi\256ed,)X
+1052(e.g.)X
+1192(backup)X
+1448(\256les)X
+1605(that)X
+1749(have)X
+1925(no)X
+2029(associated)X
+2383(email)X
+2585(recovery)X
+2891(\256le)X
+3017(will)X
+3165(have)X
+3341(this)X
+3480(bit)X
+3588(set.)X
+3741(\(There)X
+3979(is)X
+576 4266(also)N
+735(a)X
+801(small)X
+1004(window)X
+1292(where)X
+1519(empty)X
+1749(\256les)X
+1912(can)X
+2054(be)X
+2160(created)X
+2424(and)X
+2571(not)X
+2704(yet)X
+2833(have)X
+3016(this)X
+3162(bit)X
+3277(set.)X
+3437(This)X
+3610(is)X
+3694(due)X
+3841(to)X
+3934(the)X
+576 4356(method)N
+836(in)X
+918(which)X
+1134(the)X
+1252(\256les)X
+1405(are)X
+1524(created.\))X
+1844(Such)X
+2024(\256les)X
+2177(should)X
+2410(be)X
+2506(deleted)X
+2758(when)X
+2952(the)X
+3070(system)X
+3312(reboots.)X
+776 4479(A)N
+884(simple)X
+1147(way)X
+1331(to)X
+1443(do)X
+1573(this)X
+1738(cleanup)X
+2038(is)X
+2141(to)X
+2253(insert)X
+2481(the)X
+2630(following)X
+2992(Bourne)X
+3279(shell)X
+3481(script)X
+3710(into)X
+3885(your)X
+7 f
+576 4569(/etc/rc.local)N
+1 f
+1224(\(or)X
+1342(other)X
+1531(startup\))X
+1800(\256le.)X
+1966(The)X
+2115(script)X
+2316(should)X
+2552(work)X
+2740(with)X
+2905(the)X
+3026(historic)X
+3289(Bourne)X
+3548(shell,)X
+3742(a)X
+3801(POSIX)X
+576 4659(1003.2)N
+818(shell)X
+991(or)X
+1080(the)X
+1201(Korn)X
+1389(shell.)X
+1603(\(A)X
+1711(copy)X
+1890(of)X
+1980(this)X
+2118(script)X
+2319(is)X
+2395(included)X
+2694(as)X
+7 f
+2784(nvi/install/recover.script)X
+1 f
+576 4749(in)N
+658(the)X
+3 f
+776(nex)X
+1 f
+(/)S
+3 f
+918(nvi)X
+1 f
+1044(distribution.\))X
+
+5 p
+%%Page: 5 4
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3698(USD:13-5)X
+7 f
+896 762(#)N
+1184(@\(#\)recover.script)X
+2336(8.4)X
+2528(\(Berkeley\))X
+3056(8/13/94)X
+896 852(#)N
+896 942(#)N
+992(Recover)X
+1376(nvi)X
+1568(editor)X
+1904(files:)X
+896 1032(RECDIR=/var/tmp/vi.recover)N
+896 1122(SENDMAIL=/usr/lib/sendmail)N
+896 1212(echo)N
+1136('Recovering)X
+1712(nvi)X
+1904(editor)X
+2240(sessions.')X
+896 1392(#)N
+992(Unmodified)X
+1520(nvi)X
+1712(editor)X
+2048(backup)X
+2384(files)X
+2672(are)X
+2864(either)X
+3200(zero)X
+3440(length)X
+3776(or)X
+896 1482(#)N
+992(have)X
+1232(the)X
+1424(execute)X
+1808(bit)X
+2000(set.)X
+2288(Delete)X
+2624(both)X
+2864(cases.)X
+896 1572(vibackup=`echo)N
+1616($RECDIR/vi.*`)X
+896 1662(if)N
+1040([)X
+1136("$vibackup")X
+1712(!=)X
+1856("$RECDIR/vi.*")X
+2576(];)X
+2720(then)X
+1184 1752(for)N
+1376(i)X
+1472(in)X
+1616($vibackup;)X
+2144(do)X
+1472 1842(if)N
+1616(test)X
+1856(-x)X
+2000($i)X
+2144(-o)X
+2288(!)X
+2384(-s)X
+2528($i;)X
+2720(then)X
+1760 1932(rm)N
+1904($i)X
+1472 2022(fi)N
+1184 2112(done)N
+896 2202(fi)N
+896 2382(#)N
+992(It)X
+1136(is)X
+1280(possible)X
+1712(to)X
+1856(get)X
+2048(incomplete)X
+2576(recovery)X
+3008(files,)X
+3344(if)X
+3488(the)X
+3680(editor)X
+896 2472(#)N
+992(crashes)X
+1376(at)X
+1520(the)X
+1712(right)X
+2000(time.)X
+2336(Delete)X
+2672(any)X
+2864(recovery)X
+3296(files)X
+3584(without)X
+896 2562(#)N
+992(corresponding)X
+1664(backup)X
+2000(files,)X
+2336(otherwise)X
+2816(send)X
+3056(mail)X
+3296(to)X
+3440(the)X
+3632(user.)X
+896 2652(virecovery=`echo)N
+1712($RECDIR/recover.*`)X
+896 2742(if)N
+1040([)X
+1136("$virecovery")X
+1808(!=)X
+1952("$RECDIR/recover.*")X
+2912(];)X
+3056(then)X
+1184 2832(for)N
+1376(i)X
+1472(in)X
+1616($virecovery;)X
+2240(do)X
+1472 2922(recfile=`awk)N
+2096('/\303X-vi-recover-path:/{print)X
+3488($2}')X
+3728(<)X
+3824($i`)X
+1472 3012(if)N
+1616(test)X
+1856(!)X
+1952(-n)X
+2096($recfile)X
+2528(-a)X
+2672(-s)X
+2816($recfile;)X
+3296(then)X
+1760 3102($SENDMAIL)N
+2240(-t)X
+2384(<)X
+2480($i)X
+1472 3192(else)N
+1760 3282(rm)N
+1904($i)X
+1472 3372(fi)N
+1184 3462(done)N
+896 3552(fi)N
+1 f
+776 3798(If)N
+859(you)X
+1008(are)X
+1136(not)X
+1267(using)X
+1469(the)X
+1596(default)X
+1848(value)X
+2051(for)X
+2174(the)X
+3 f
+2301(recdir)X
+1 f
+2540(option,)X
+2793(be)X
+2898(sure)X
+3062(to)X
+3154(substitute)X
+3490(the)X
+3618(value)X
+3822(you're)X
+576 3888(using)N
+769(for)X
+883(the)X
+7 f
+1001(RECDIR)X
+1 f
+1309(value)X
+1503(in)X
+1585(the)X
+1703(recovery)X
+2005(script.)X
+776 4011(If)N
+882(the)X
+1032(path)X
+1222(of)X
+1341(your)X
+1540(system's)X
+3 f
+1872(sendmail)X
+1 f
+2230(program)X
+2555(\(or)X
+2702(whatever)X
+3050(mailer)X
+3308(you're)X
+3571(using\))X
+3824(is)X
+3930(not)X
+7 f
+576 4101(/usr/lib/sendmail)N
+1 f
+(,)S
+1451(be)X
+1566(sure)X
+1739(to)X
+1840(substitute)X
+2184(the)X
+2320(correct)X
+2582(pathname)X
+2932(for)X
+3064(the)X
+7 f
+3200(SENDMAIL)X
+1 f
+3622(value)X
+3834(in)X
+3934(the)X
+576 4191(recovery)N
+878(script.)X
+1116(Consult)X
+1384(the)X
+1502(manual)X
+1758(page)X
+1930(for)X
+2044(details)X
+2273(on)X
+2373(recovering)X
+2737(preserved)X
+3070(or)X
+3157(aborted)X
+3418(editing)X
+3660(sessions.)X
+3 f
+576 4377(4.)N
+676(Sizing)X
+904(the)X
+1031(Screen)X
+1 f
+776 4500(The)N
+926(size)X
+1076(of)X
+1168(the)X
+1291(screen)X
+1522(can)X
+1659(be)X
+1760(set)X
+1874(in)X
+1961(a)X
+2022(number)X
+2292(of)X
+2384(ways.)X
+3 f
+2614(Ex)X
+1 f
+2707(/)X
+3 f
+2729(vi)X
+1 f
+2817(takes)X
+3008(the)X
+3132(following)X
+3469(steps)X
+3655(until)X
+3827(values)X
+576 4590(are)N
+695(obtained)X
+991(for)X
+1105(both)X
+1267(the)X
+1385(number)X
+1650(of)X
+1737(rows)X
+1913(and)X
+2049(number)X
+2314(of)X
+2401(columns)X
+2692(in)X
+2774(the)X
+2892(screen.)X
+616 4713(\(1\))N
+830(If)X
+904(the)X
+1022(environmental)X
+1505(variable)X
+7 f
+1784(LINES)X
+1 f
+2044(exists,)X
+2266(it)X
+2330(is)X
+2403(used)X
+2570(to)X
+2652(specify)X
+2904(the)X
+3022(number)X
+3287(of)X
+3374(rows)X
+3550(in)X
+3632(the)X
+3750(screen.)X
+616 4836(\(2\))N
+830(If)X
+909(the)X
+1032(environmental)X
+1520(variable)X
+7 f
+1804(COLUMNS)X
+1 f
+2165(exists,)X
+2393(it)X
+2463(is)X
+2542(used)X
+2715(to)X
+2803(specify)X
+3061(the)X
+3185(number)X
+3456(of)X
+3549(columns)X
+3846(in)X
+3934(the)X
+830 4926(screen.)N
+616 5049(\(3\))N
+830(The)X
+975(TIOCGWINSZ)X
+2 f
+1494(ioctl)X
+1 f
+1636(\(2\))X
+1750(is)X
+1823(attempted)X
+2159(on)X
+2259(the)X
+2377(standard)X
+2669(error)X
+2846(\256le)X
+2968(descriptor.)X
+616 5172(\(4\))N
+830(The)X
+978(termcap)X
+1260(entry)X
+1448(\(or)X
+1565(terminfo)X
+1864(entry)X
+2053(on)X
+2157(System)X
+2416(V)X
+2498(machines\))X
+2852(is)X
+2929(checked)X
+3217(for)X
+3335(the)X
+3457(``li'')X
+3633(entry)X
+3822(\(rows\))X
+830 5262(and)N
+966(the)X
+1084(``co'')X
+1288(entry)X
+1473(\(columns\).)X
+616 5385(\(5\))N
+830(The)X
+975(number)X
+1240(of)X
+1327(rows)X
+1503(is)X
+1576(set)X
+1685(to)X
+1767(24,)X
+1887(and)X
+2023(the)X
+2141(number)X
+2406(of)X
+2493(columns)X
+2784(is)X
+2857(set)X
+2966(to)X
+3048(80.)X
+776 5508(If)N
+851(a)X
+908(window)X
+1187(change)X
+1436(size)X
+1582(signal)X
+1794(\(SIGWINCH\))X
+2270(is)X
+2344(received,)X
+2658(the)X
+2777(new)X
+2932(window)X
+3211(size)X
+3357(is)X
+3431(retrieved)X
+3739(using)X
+3934(the)X
+576 5598(TIOCGWINSZ)N
+2 f
+1095(ioctl)X
+1 f
+1237(\(2\))X
+1351(call,)X
+1507(and)X
+1643(all)X
+1743(other)X
+1928(information)X
+2326(is)X
+2399(ignored.)X
+
+6 p
+%%Page: 6 5
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-6)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+576 762(5.)N
+676(Character)X
+1049(Display)X
+1 f
+776 885(In)N
+865(both)X
+3 f
+1030(ex)X
+1 f
+1129(and)X
+3 f
+1268(vi)X
+1 f
+1353(printable)X
+1661(characters)X
+2011(as)X
+2101(de\256ned)X
+2360(by)X
+2 f
+2463(isprint)X
+1 f
+2671(\(3\))X
+2788(are)X
+2910(displayed)X
+3240(using)X
+3436(the)X
+3557(local)X
+3736(character)X
+576 975(set.)N
+776 1098(Non-printable)N
+1255(characters,)X
+1631(for)X
+1754(which)X
+2 f
+1980(iscntrl)X
+1 f
+2184(\(3\))X
+2308(returns)X
+2561(true,)X
+2736(and)X
+2882(which)X
+3108(are)X
+3237(less)X
+3387(than)X
+3555(octal)X
+3741(\\076,)X
+3933(are)X
+576 1188(displayed)N
+915(as)X
+1014(the)X
+1144(string)X
+1357(``)X
+7 f
+1411(\303<character>)X
+1 f
+('',)S
+2092(where)X
+7 f
+2320(<character>)X
+1 f
+2879(is)X
+2963(the)X
+3092(character)X
+3419(that)X
+3570(is)X
+3654(the)X
+3783(original)X
+576 1278 0.3250(character's)AN
+961(value)X
+1166(offset)X
+1380(from)X
+1568(the)X
+1698(``)X
+7 f
+1752(@)X
+1 f
+('')S
+1886(character.)X
+2254(For)X
+2397(example,)X
+2721(the)X
+2851(octal)X
+3039(character)X
+3367(\\001)X
+3541(is)X
+3626(displayed)X
+3965(as)X
+576 1368(``)N
+7 f
+630(\303A)X
+1 f
+(''.)S
+845(If)X
+2 f
+924(iscntrl)X
+1 f
+1128(\(3\))X
+1247(returns)X
+1495(true)X
+1645(for)X
+1764(the)X
+1887(octal)X
+2068(character)X
+2389(\\177,)X
+2576(it)X
+2645(is)X
+2723(displayed)X
+3054(as)X
+3145(the)X
+3267(string)X
+3473(``)X
+7 f
+3527(\303?)X
+1 f
+(''.)S
+3741(All)X
+3867(other)X
+576 1458(characters)N
+947(are)X
+1090(displayed)X
+1441(as)X
+1552(either)X
+1779(hexadecimal)X
+2229(values,)X
+2498(in)X
+2604(the)X
+2746(form)X
+2946(``)X
+7 f
+3000(0x<high-halfbyte>)X
+3888(...)X
+576 1548(0x<low-halfbyte>)N
+1 f
+('',)S
+1469(or)X
+1587(as)X
+1705(octal)X
+1911(values,)X
+2186(in)X
+2298(the)X
+2446(form)X
+2652(``)X
+7 f
+2706(\\<high-one-or-two-bits>)X
+3888(...)X
+576 1638(\\<low-three-bits>)N
+1 f
+(''.)S
+1506(The)X
+1651(display)X
+1902(of)X
+1989(unknown)X
+2307(characters)X
+2654(is)X
+2727(based)X
+2930(on)X
+3030(the)X
+3148(value)X
+3342(of)X
+3429(the)X
+3 f
+3547(octal)X
+1 f
+3732(option.)X
+776 1761(In)N
+3 f
+864(vi)X
+1 f
+947(command)X
+1285(mode,)X
+1505(the)X
+1625(cursor)X
+1848(is)X
+1923(always)X
+2168(positioned)X
+2523(on)X
+2625(the)X
+2745(last)X
+2878(column)X
+3140(of)X
+3229(characters)X
+3578(which)X
+3796(take)X
+3952(up)X
+576 1851(more)N
+765(than)X
+927(one)X
+1067(column)X
+1331(on)X
+1435(the)X
+1557(screen.)X
+1827(In)X
+3 f
+1918(vi)X
+1 f
+2003(text)X
+2146(input)X
+2333(mode,)X
+2554(the)X
+2675(cursor)X
+2899(is)X
+2975(positioned)X
+3331(on)X
+3434(the)X
+3555(\256rst)X
+3702(column)X
+3965(of)X
+576 1941(characters)N
+923(which)X
+1139(take)X
+1293(up)X
+1393(more)X
+1578(than)X
+1736(one)X
+1872(column)X
+2132(on)X
+2232(the)X
+2350(screen.)X
+3 f
+576 2127(6.)N
+676(Multiple)X
+989(Screens)X
+1 f
+3 f
+776 2250(Nvi)N
+1 f
+916(supports)X
+1207(multiple)X
+1493(screens)X
+1750(by)X
+1851(dividing)X
+2138(the)X
+2257(window)X
+2536(into)X
+2681(regions.)X
+2978(It)X
+3048(also)X
+3198(supports)X
+3490(stacks)X
+3707(of)X
+3795(screens)X
+576 2340(by)N
+676(permitting)X
+1029(the)X
+1147(user)X
+1301(to)X
+1383(change)X
+1631(the)X
+1749(set)X
+1858(of)X
+1945(screens)X
+2202(that)X
+2342(are)X
+2461(currently)X
+2771(displayed.)X
+776 2463(The)N
+924(command)X
+3 f
+1263(split)X
+1 f
+1432(divides)X
+1686(the)X
+1807(current)X
+2058(screen)X
+2287(into)X
+2434(two)X
+2577(regions)X
+2836(of)X
+2926(approximately)X
+3412(equal)X
+3609(size.)X
+3797(If)X
+3875(a)X
+3935(list)X
+576 2553(of)N
+668(\256les)X
+826(are)X
+950(speci\256ed)X
+1260(as)X
+1352(arguments)X
+1711(to)X
+1798(the)X
+3 f
+1921(split)X
+1 f
+2092(command,)X
+2452(the)X
+2574(list)X
+2695(of)X
+2786(\256les)X
+2943(to)X
+3029(be)X
+3129(edited)X
+3349(is)X
+3426(initialized)X
+3770(as)X
+3861(if)X
+3934(the)X
+3 f
+576 2643(next)N
+1 f
+747(command)X
+1087(had)X
+1227(been)X
+1403(used.)X
+1614(If)X
+1692(no)X
+1796(\256les)X
+1953(are)X
+2076(speci\256ed,)X
+2405(the)X
+2527(new)X
+2685(screen)X
+2915(will)X
+3063(begin)X
+3265(by)X
+3370(editing)X
+3617(the)X
+3740(same)X
+3930(\256le)X
+576 2733(as)N
+663(the)X
+781(previous)X
+1077(screen.)X
+776 2856(When)N
+992(more)X
+1181(than)X
+1343(one)X
+1483(screen)X
+1713(is)X
+1790(editing)X
+2036(a)X
+2097(\256le,)X
+2244(changes)X
+2528(in)X
+2615(any)X
+2756(screen)X
+2987(are)X
+3111(re\257ected)X
+3413(in)X
+3500(all)X
+3605(other)X
+3795(screens)X
+576 2946(editing)N
+820(the)X
+940(same)X
+1127(\256le.)X
+1291(Exiting)X
+1548(any)X
+1686(screen)X
+1914(without)X
+2180(saving)X
+2410(any)X
+2547(changes)X
+2827(\(or)X
+2942(explicitly)X
+3265(discarding)X
+3620(them\))X
+3828(is)X
+3902(per-)X
+576 3036(mitted)N
+800(until)X
+966(the)X
+1084(last)X
+1215(screen)X
+1441(editing)X
+1683(the)X
+1801(\256le)X
+1923(is)X
+1996(exited.)X
+776 3159(The)N
+3 f
+923(resize)X
+1 f
+1142(command)X
+1480(permits)X
+1742(resizing)X
+2018(of)X
+2107(individual)X
+2453(screens.)X
+2752(Screens)X
+3024(may)X
+3184(be)X
+3282(grown,)X
+3529(shrunk)X
+3769(or)X
+3858(set)X
+3970(to)X
+576 3249(an)N
+672(absolute)X
+959(number)X
+1224(of)X
+1311(rows.)X
+776 3372(The)N
+3 f
+921(\303W)X
+1 f
+1048(command)X
+1384(is)X
+1457(used)X
+1624(to)X
+1706(switch)X
+1935(between)X
+2223(screens.)X
+2520(Each)X
+3 f
+2701(\303W)X
+1 f
+2829(moves)X
+3059(to)X
+3142(the)X
+3261(next)X
+3420(lower)X
+3624(screen)X
+3851(in)X
+3934(the)X
+576 3462(window,)N
+874(or)X
+961(to)X
+1043(the)X
+1161(\256rst)X
+1305(screen)X
+1531(in)X
+1613(the)X
+1731(window)X
+2009(if)X
+2078(there)X
+2259(are)X
+2378(no)X
+2478(lower)X
+2681(screens.)X
+776 3585(The)N
+3 f
+925(bg)X
+1 f
+1033(command)X
+1374(``backgrounds'')X
+1917(the)X
+2040(current)X
+2293(screen.)X
+2564(The)X
+2714(screen)X
+2945(disappears)X
+3309(from)X
+3490(the)X
+3613(window,)X
+3916(and)X
+576 3675(the)N
+702(rows)X
+886(it)X
+958(occupied)X
+1276(are)X
+1403(taken)X
+1605(over)X
+1776(by)X
+1884(a)X
+1948(neighboring)X
+2363(screen.)X
+2637(It)X
+2714(is)X
+2795(an)X
+2899(error)X
+3083(to)X
+3172(attempt)X
+3439(to)X
+3528(background)X
+3934(the)X
+576 3765(only)N
+738(screen)X
+964(in)X
+1046(the)X
+1164(window.)X
+776 3888(The)N
+3 f
+935(display)X
+1212(screens)X
+1 f
+1496(command)X
+1846(displays)X
+2142(the)X
+2274(names)X
+2513(of)X
+2614(the)X
+2747(\256les)X
+2915(associated)X
+3280(with)X
+3457(the)X
+3590(current)X
+3853(back-)X
+576 3978(grounded)N
+899(screens)X
+1156(in)X
+1238(the)X
+1356(window.)X
+776 4101(The)N
+3 f
+932(fg)X
+1031([\256le])X
+1 f
+1219(command)X
+1567(``foregrounds'')X
+2095(the)X
+2225(\256rst)X
+2381(screen)X
+2619(in)X
+2713(the)X
+2843(list)X
+2972(of)X
+3071(backgrounded)X
+3558(screens)X
+3827(that)X
+3979(is)X
+576 4191(associated)N
+934(with)X
+1103(its)X
+1205(argument.)X
+1575(If)X
+1656(no)X
+1763(\256le)X
+1892(argument)X
+2222(is)X
+2302(speci\256ed,)X
+2634(the)X
+2759(\256rst)X
+2910(screen)X
+3143(on)X
+3250(the)X
+3375(list)X
+3499(is)X
+3579(foregrounded.)X
+576 4281(Foregrounding)N
+1072(consists)X
+1345(of)X
+1432(backgrounding)X
+1933(the)X
+2051(current)X
+2299(screen,)X
+2545(and)X
+2681(replacing)X
+3000(its)X
+3095(space)X
+3294(in)X
+3376(the)X
+3494(window)X
+3772(with)X
+3934(the)X
+576 4371(foregrounded)N
+1029(screen.)X
+776 4494(If)N
+852(the)X
+972(last)X
+1105(screen)X
+1333(in)X
+1417(the)X
+1537(window)X
+1817(is)X
+1892(exited,)X
+2131(and)X
+2270(there)X
+2454(are)X
+2576(backgrounded)X
+3054(screens,)X
+3334(the)X
+3455(\256rst)X
+3602(screen)X
+3831(on)X
+3934(the)X
+576 4584(list)N
+693(of)X
+780(backgrounded)X
+1255(screens)X
+1512(takes)X
+1697(over)X
+1860(the)X
+1978(window.)X
+3 f
+576 4770(7.)N
+676(Regular)X
+972(Expressions)X
+1400(and)X
+1548(Replacement)X
+2014(Strings)X
+1 f
+776 4893(Regular)N
+1050(expressions)X
+1444(are)X
+1563(used)X
+1730(in)X
+1812(line)X
+1952(addresses,)X
+2301(as)X
+2389(the)X
+2508(\256rst)X
+2653(part)X
+2799(of)X
+2887(the)X
+3 f
+3006(ex)X
+3103(substitute)X
+1 f
+3436(,)X
+3 f
+3477(global)X
+1 f
+3685(,)X
+3726(and)X
+3 f
+3863(vglo-)X
+576 4983(bal)N
+1 f
+702(commands,)X
+1089(and)X
+1225(in)X
+1307(search)X
+1533(patterns.)X
+776 5106(The)N
+927(regular)X
+1181(expressions)X
+1581(supported)X
+1923(by)X
+3 f
+2030(ex)X
+1 f
+2106(/)X
+3 f
+2128(vi)X
+1 f
+2217(are,)X
+2363(by)X
+2470(default,)X
+2740(the)X
+2865(Basic)X
+3070(Regular)X
+3351(Expressions)X
+3765(\(BRE's\))X
+576 5196(described)N
+909(in)X
+996(the)X
+1119(IEEE)X
+1318(POSIX)X
+1574(Standard)X
+1884(1003.2.)X
+2169(The)X
+3 f
+2319(extended)X
+1 f
+2651(option)X
+2880(causes)X
+3115(all)X
+3220(regular)X
+3472(expressions)X
+3870(to)X
+3956(be)X
+576 5286(interpreted)N
+976(as)X
+1095(the)X
+1245(Extended)X
+1600(Regular)X
+1906(Expressions)X
+2345(\(ERE's\))X
+2661(described)X
+3022(by)X
+3155(the)X
+3306(same)X
+3524(standard.)X
+3889(\(See)X
+2 f
+576 5376(re_format)N
+1 f
+(\(7\))S
+1025(for)X
+1154(more)X
+1354(information.\))X
+1834(Generally)X
+2186(speaking,)X
+2526(BRE's)X
+2774(are)X
+2908(the)X
+3040(Regular)X
+3328(Expressions)X
+3749(found)X
+3970(in)X
+2 f
+576 5466(ed)N
+1 f
+652(\(1\))X
+766(and)X
+2 f
+902(grep)X
+1 f
+1049(\(1\),)X
+1183(and)X
+1319(ERE's)X
+1548(are)X
+1667(the)X
+1785(Regular)X
+2059(Expressions)X
+2466(found)X
+2673(in)X
+2 f
+2755(egrep)X
+1 f
+2938(\(1\).)X
+776 5589(The)N
+922(following)X
+1254(is)X
+1328(not)X
+1451(intended)X
+1748(to)X
+1831(provide)X
+2097(a)X
+2154(description)X
+2532(of)X
+2621(Regular)X
+2897(Expressions.)X
+3346(The)X
+3493(information)X
+3893(here)X
+576 5679(only)N
+742(describes)X
+1065(strings)X
+1302(and)X
+1442(characters)X
+1793(which)X
+2013(have)X
+2189(special)X
+2436(meanings)X
+2766(in)X
+2851(the)X
+3 f
+2972(ex)X
+1 f
+3048(/)X
+3 f
+3070(vi)X
+1 f
+3155(version)X
+3414(of)X
+3504(RE's,)X
+3707(or)X
+3797(options)X
+576 5769(which)N
+792(change)X
+1040(the)X
+1158(meanings)X
+1485(of)X
+1572(characters)X
+1919(that)X
+2059(normally)X
+2368(have)X
+2540(special)X
+2783(meanings)X
+3110(in)X
+3192(RE's.)X
+
+7 p
+%%Page: 7 6
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3698(USD:13-7)X
+1 f
+616 762(\(1\))N
+830(An)X
+948(empty)X
+1168(RE)X
+1290(\(e.g.)X
+1473(``)X
+7 f
+1527(//)X
+1 f
+('')S
+1697(or)X
+1784(``)X
+7 f
+1838(??)X
+1 f
+('')S
+2028(is)X
+2101(equivalent)X
+2455(to)X
+2537(the)X
+2655(last)X
+2786(RE)X
+2908(used.)X
+616 885(\(2\))N
+830(The)X
+975(construct)X
+1289(``)X
+7 f
+1343(\\<)X
+1 f
+('')S
+1513(matches)X
+1796(the)X
+1914(beginning)X
+2254(of)X
+2341(a)X
+2397(word.)X
+616 1008(\(3\))N
+830(The)X
+975(construct)X
+1289(``)X
+7 f
+1343(\\>)X
+1 f
+('')S
+1513(matches)X
+1796(the)X
+1914(end)X
+2050(of)X
+2137(a)X
+2193(word.)X
+616 1131(\(4\))N
+830(The)X
+975(character)X
+1291(``)X
+7 f
+1345(\304)X
+1 f
+('')S
+1467(matches)X
+1750(the)X
+1868(replacement)X
+2281(part)X
+2426(of)X
+2513(the)X
+2631(last)X
+3 f
+2762(substitute)X
+1 f
+3115(command.)X
+776 1254(When)N
+992(the)X
+3 f
+1114(magic)X
+1 f
+1343(option)X
+1571(is)X
+2 f
+1648(not)X
+1 f
+1774(set,)X
+1907(the)X
+2029(only)X
+2195(characters)X
+2546(with)X
+2712(special)X
+2959(meanings)X
+3290(are)X
+3413(a)X
+3473(``)X
+7 f
+3527(\303)X
+1 f
+('')S
+3653(character)X
+3974(at)X
+576 1344(the)N
+698(beginning)X
+1042(of)X
+1133(an)X
+1233(RE,)X
+1379(a)X
+1439(``)X
+7 f
+1493($)X
+1 f
+('')S
+1619(character)X
+1939(at)X
+2021(the)X
+2143(end)X
+2282(of)X
+2372(an)X
+2471(RE,)X
+2616(and)X
+2755(the)X
+2876(escaping)X
+3180(character)X
+3499(``)X
+7 f
+3553(\\)X
+1 f
+(''.)S
+3718(The)X
+3866(char-)X
+576 1434(acters)N
+788(``)X
+7 f
+842(.)X
+1 f
+('',)S
+988(``)X
+7 f
+1042(*)X
+1 f
+('',)S
+1188(``)X
+7 f
+1242([)X
+1 f
+('')S
+1368(and)X
+1508(``)X
+7 f
+1562(\304)X
+1 f
+('')S
+1688(are)X
+1811(treated)X
+2054(as)X
+2145(ordinary)X
+2441(characters)X
+2793(unless)X
+3018(preceded)X
+3334(by)X
+3439(a)X
+3500(``)X
+7 f
+3554(\\)X
+1 f
+('';)S
+3703(when)X
+3902(pre-)X
+576 1524(ceded)N
+784(by)X
+884(a)X
+940(``)X
+7 f
+994(\\)X
+1 f
+('')S
+1116(they)X
+1274(regain)X
+1495(their)X
+1662(special)X
+1905(meaning.)X
+776 1647(Replacement)N
+1215(strings)X
+1448(are)X
+1567(the)X
+1685(second)X
+1928(part)X
+2073(of)X
+2160(a)X
+3 f
+2216(substitute)X
+1 f
+2569(command.)X
+776 1770(The)N
+924(character)X
+1243(``)X
+7 f
+1297(&)X
+1 f
+('')S
+1422(\(or)X
+1539(``)X
+7 f
+1593(\\&)X
+1 f
+('')S
+1766(if)X
+1839(the)X
+3 f
+1961(magic)X
+1 f
+2190(option)X
+2418(is)X
+2 f
+2495(not)X
+1 f
+2621(set\))X
+2761(in)X
+2847(the)X
+2969(replacement)X
+3386(string)X
+3592(stands)X
+3816(for)X
+3934(the)X
+576 1860(text)N
+717(matched)X
+1010(by)X
+1111(the)X
+1230(RE)X
+1353(that)X
+1494(is)X
+1568(being)X
+1767(replaced.)X
+2101(The)X
+2247(character)X
+2564(``)X
+7 f
+2618(\304)X
+1 f
+('')S
+2741(\(or)X
+2856(``)X
+7 f
+2910(\\\304)X
+1 f
+('')S
+3081(if)X
+3151(the)X
+3 f
+3270(magic)X
+1 f
+3496(option)X
+3721(is)X
+2 f
+3794(not)X
+1 f
+3916(set\))X
+576 1950(stands)N
+806(for)X
+931(the)X
+1060(replacement)X
+1484(part)X
+1640(of)X
+1738(the)X
+1867(previous)X
+3 f
+2174(substitute)X
+1 f
+2538(command.)X
+2925(It)X
+3005(is)X
+3089(only)X
+3262(valid)X
+3453(after)X
+3632(a)X
+3 f
+3699(substitute)X
+1 f
+576 2040(command)N
+912(has)X
+1039(been)X
+1211(performed.)X
+776 2163(The)N
+922(string)X
+1125(``)X
+7 f
+1179(\\#)X
+1 f
+('',)S
+1370(where)X
+1588(``)X
+7 f
+1642(#)X
+1 f
+('')S
+1765(is)X
+1839(an)X
+1936(integer)X
+2180(value)X
+2376(from)X
+2554(1)X
+2616(to)X
+2700(9,)X
+2782(stands)X
+3004(for)X
+3120(the)X
+3240(text)X
+3382(matched)X
+3676(by)X
+3778(the)X
+3898(por-)X
+576 2253(tion)N
+728(of)X
+823(the)X
+949(RE)X
+1079(enclosed)X
+1388(in)X
+1478(the)X
+1604(``)X
+7 f
+1658(#)X
+1 f
+('''th)S
+1877(set)X
+1994(of)X
+2089(escaped)X
+2372(parentheses,)X
+2794(e.g.)X
+2957(``)X
+7 f
+3011(\\\()X
+1 f
+('')S
+3188(and)X
+3331(``)X
+7 f
+3385(\\\))X
+1 f
+(''.)S
+3602(For)X
+3740(example,)X
+576 2343(``)N
+7 f
+630(s/abc\\\(.*\\\)def/\\1/)X
+1 f
+('')S
+1568(deletes)X
+1811(the)X
+1929(strings)X
+2162(``)X
+7 f
+2216(abc)X
+1 f
+('')S
+2434(and)X
+2570(``)X
+7 f
+2624(def)X
+1 f
+('')S
+2842(from)X
+3018(the)X
+3136(matched)X
+3428(pattern.)X
+776 2466(The)N
+934(strings)X
+1180(``)X
+7 f
+1234(\\l)X
+1 f
+('',)S
+1437(``)X
+7 f
+1491(\\u)X
+1 f
+('',)S
+1694(``)X
+7 f
+1748(\\L)X
+1 f
+('')S
+1931(and)X
+2080(``)X
+7 f
+2134(\\U)X
+1 f
+('')S
+2317(can)X
+2462(be)X
+2571(used)X
+2752(to)X
+2848(modify)X
+3113(the)X
+3245(case)X
+3418(of)X
+3519(elements)X
+3838(in)X
+3934(the)X
+576 2556(replacement)N
+999(string.)X
+1251(The)X
+1406(string)X
+1618(``)X
+7 f
+1672(\\l)X
+1 f
+('')S
+1852(causes)X
+2092(the)X
+2220(next)X
+2388(character)X
+2714(to)X
+2806(be)X
+2912(converted)X
+3259(to)X
+3350(lowercase;)X
+3723(the)X
+3850(string)X
+576 2646(``)N
+7 f
+630(\\u)X
+1 f
+('')S
+815(behaves)X
+1109(similarly,)X
+1448(but)X
+1585(converts)X
+1892(to)X
+1989(uppercase)X
+2346(\(e.g.)X
+7 f
+2544(s/abc/\\U&/)X
+1 f
+3059(replaces)X
+3358(the)X
+3492(string)X
+7 f
+3710(abc)X
+1 f
+3890(with)X
+7 f
+576 2736(ABC)N
+1 f
+(\).)S
+810(The)X
+958(strings)X
+1194(``)X
+7 f
+1248(\\L)X
+1 f
+('')S
+1421(causes)X
+1654(characters)X
+2004(up)X
+2107(to)X
+2192(the)X
+2313(end)X
+2452(of)X
+2541(the)X
+2661(string)X
+2865(or)X
+2954(the)X
+3074(next)X
+3234 0.3611(occurrence)AX
+3610(of)X
+3699(the)X
+3819(strings)X
+576 2826(``)N
+7 f
+630(\\e)X
+1 f
+('')S
+806(or)X
+899(``)X
+7 f
+953(\\E)X
+1 f
+('')S
+1129(to)X
+1217(be)X
+1319(converted)X
+1663(to)X
+1752(lowercase;)X
+2123(the)X
+2248(string)X
+2457(``)X
+7 f
+2511(\\U)X
+1 f
+('')S
+2688(behaves)X
+2974(similarly,)X
+3305(but)X
+3434(converts)X
+3733(to)X
+3822(upper-)X
+576 2916(case.)N
+776 3039(If)N
+850(the)X
+968(entire)X
+1171(replacement)X
+1584(pattern)X
+1827(is)X
+1900(``)X
+7 f
+1954(%)X
+1 f
+('',)S
+2096(then)X
+2254(the)X
+2372(last)X
+2503(replacement)X
+2916(pattern)X
+3159(is)X
+3232(used)X
+3399(again.)X
+776 3162(In)N
+3 f
+867(vi)X
+1 f
+929(,)X
+973(inserting)X
+1278(a)X
+7 f
+1339(<control-M>)X
+1 f
+1892(into)X
+2041(the)X
+2164(replacement)X
+2582(string)X
+2789(will)X
+2938(cause)X
+3142(the)X
+3265(matched)X
+3562(line)X
+3707(to)X
+3794(be)X
+3895(split)X
+576 3252(into)N
+720(two)X
+860(lines)X
+1031(at)X
+1109(that)X
+1249(point.)X
+1473(\(The)X
+7 f
+1645(<control-M>)X
+1 f
+2193(will)X
+2337(be)X
+2433(discarded.\))X
+3 f
+576 3438(8.)N
+676(General)X
+972(Editor)X
+1214(Description)X
+1 f
+776 3561(When)N
+3 f
+989(ex)X
+1 f
+1086(or)X
+3 f
+1174(vi)X
+1 f
+1257(are)X
+1377(executed,)X
+1704(the)X
+1823(text)X
+1964(of)X
+2052(a)X
+2109(\256le)X
+2232(is)X
+2306(read)X
+2466(\(or)X
+2581(a)X
+2638(temporary)X
+2989(\256le)X
+3112(is)X
+3186(created\),)X
+3487(and)X
+3624(then)X
+3783(all)X
+3885(edit-)X
+576 3651(ing)N
+700(changes)X
+981(happen)X
+1235(within)X
+1461(the)X
+1581(context)X
+1838(of)X
+1926(the)X
+2045(copy)X
+2222(of)X
+2310(the)X
+2429(\256le.)X
+2 f
+2592(No)X
+2706(changes)X
+2990(affect)X
+3189(the)X
+3308(actual)X
+3529(\256le)X
+3648(until)X
+3815(the)X
+3934(\256le)X
+576 3741(is)N
+662(written)X
+921(out)X
+1 f
+1023(,)X
+1076(either)X
+1293(using)X
+1500(a)X
+1570(write)X
+1769(command)X
+2119(or)X
+2220(another)X
+2495(command)X
+2845(which)X
+3075(is)X
+3162(affected)X
+3456(by)X
+3570(the)X
+3 f
+3702(autowrite)X
+1 f
+576 3831(option.)N
+776 3954(All)N
+898(\256les)X
+1052(are)X
+1172(locked)X
+1407(\(using)X
+1628(the)X
+2 f
+1747(\257ock)X
+1 f
+1899(\(2\))X
+2014(or)X
+2 f
+2102(fcntl)X
+1 f
+2244(\(2\))X
+2359(interfaces\))X
+2720(during)X
+2950(the)X
+3069(edit)X
+3210(session,)X
+3482(to)X
+3565(avoid)X
+3764(inadver-)X
+576 4044(tently)N
+781(making)X
+1044(modi\256cations)X
+1502(to)X
+1587(multiple)X
+1876(copies)X
+2104(of)X
+2194(the)X
+2315(\256le.)X
+2480(If)X
+2557(a)X
+2616(lock)X
+2777(cannot)X
+3014(be)X
+3113(obtained)X
+3412(for)X
+3529(a)X
+3587(\256le)X
+3711(because)X
+3988(it)X
+576 4134(is)N
+657(locked)X
+899(by)X
+1007(another)X
+1276(process,)X
+1565(the)X
+1691(edit)X
+1840(session)X
+2100(is)X
+2182(read-only)X
+2519(\(as)X
+2642(if)X
+2720(the)X
+3 f
+2847(readonly)X
+1 f
+3178(option)X
+3411(or)X
+3507(the)X
+3 f
+9 f
+3634(-)X
+3636(-)X
+3 f
+3680(R)X
+1 f
+3767(\257ag)X
+3916(had)X
+576 4224(been)N
+754(speci\256ed\).)X
+1132(If)X
+1212(a)X
+1274(lock)X
+1438(cannot)X
+1678(be)X
+1780(obtained)X
+2082(for)X
+2202(other)X
+2393(reasons,)X
+2680(the)X
+2804(edit)X
+2950(session)X
+3207(will)X
+3357(continue,)X
+3679(but)X
+3807(the)X
+3930(\256le)X
+576 4314(status)N
+778(information)X
+1176(\(see)X
+1326(the)X
+3 f
+1444(<control-G>)X
+1 f
+1890(command\))X
+2253(will)X
+2397(re\257ect)X
+2618(this)X
+2753(fact.)X
+776 4437(Both)N
+3 f
+955(ex)X
+1 f
+1055(and)X
+3 f
+1195(vi)X
+1 f
+1281(are)X
+1405(modeful)X
+1697(editors,)X
+1960(i.e.)X
+2083(they)X
+2246(have)X
+2423(two)X
+2568(modes,)X
+2822(``command'')X
+3271(mode)X
+3474(and)X
+3615(``text)X
+3814(input'')X
+576 4527(mode.)N
+817(The)X
+965(former)X
+1207(is)X
+1283(intended)X
+1582(to)X
+1667(permit)X
+1898(you)X
+2040(to)X
+2124(enter)X
+2307(commands)X
+2676(which)X
+2894(modi\256es)X
+3191(already)X
+3450(existing)X
+3725(text.)X
+3907(The)X
+576 4617(latter)N
+762(is)X
+836(intended)X
+1133(to)X
+1216(permit)X
+1446(you)X
+1588(to)X
+1672(enter)X
+1855(new)X
+2011(text.)X
+2193(When)X
+3 f
+2407(ex)X
+1 f
+2505(\256rst)X
+2651(starts)X
+2842(running,)X
+3133(it)X
+3199(is)X
+3274(in)X
+3358(command)X
+3696(mode,)X
+3916(and)X
+576 4707(usually)N
+838(displays)X
+1131(a)X
+1198(prompt)X
+1460(\(see)X
+1621(the)X
+3 f
+1750(prompt)X
+1 f
+2039(option)X
+2274(for)X
+2398(more)X
+2593(information\).)X
+3068(The)X
+3223(prompt)X
+3484(is)X
+3567(a)X
+3633(single)X
+3854(colon)X
+576 4797(\(``)N
+7 f
+657(:)X
+1 f
+(''\))S
+817(character.)X
+1184(There)X
+1403(are)X
+1533(three)X
+1725(commands)X
+2103(that)X
+2255(switch)X
+3 f
+2496(ex)X
+1 f
+2604(into)X
+2760(text)X
+2912(input)X
+3108(mode:)X
+3 f
+3340(append)X
+1 f
+3592(,)X
+3 f
+3644(change)X
+1 f
+3916(and)X
+3 f
+576 4887(insert)N
+1 f
+772(.)X
+840(Once)X
+1038(in)X
+1128(input)X
+1320(mode,)X
+1546(entering)X
+1837(a)X
+1901(line)X
+2049(containing)X
+2415(only)X
+2585(a)X
+2649(single)X
+2868(period)X
+3101(\(``)X
+7 f
+3182(.)X
+1 f
+(''\))S
+3359(terminates)X
+3721(text)X
+3868(input)X
+576 4977(mode)N
+774(and)X
+910(returns)X
+1153(to)X
+1235(command)X
+1571(mode,)X
+1789(where)X
+2006(the)X
+2124(prompt)X
+2375(is)X
+2448(redisplayed.)X
+776 5100(When)N
+3 f
+989(vi)X
+1 f
+1072(\256rst)X
+1217(starts)X
+1407(running,)X
+1697(it)X
+1763(is)X
+1838(in)X
+1922(command)X
+2260(mode)X
+2460(as)X
+2549(well.)X
+2749(There)X
+2959(are)X
+3080(eleven)X
+3312(commands)X
+3681(that)X
+3823(switch)X
+3 f
+576 5190(vi)N
+1 f
+659(into)X
+804(text)X
+945(input)X
+1130(mode:)X
+3 f
+1351(A)X
+1 f
+1409(,)X
+3 f
+1450(a)X
+1 f
+(,)S
+3 f
+1531(C)X
+1 f
+1589(,)X
+3 f
+1629(c)X
+1 f
+1665(,)X
+3 f
+1705(I)X
+1 f
+1736(,)X
+3 f
+1776(i)X
+1 f
+1798(,)X
+3 f
+1838(O)X
+1 f
+1900(,)X
+3 f
+1940(o)X
+1 f
+(,)S
+3 f
+2020(R)X
+1 f
+2078(,)X
+3 f
+2118(S)X
+1 f
+2182(and)X
+3 f
+2318(s)X
+1 f
+2349(.)X
+2409(Once)X
+2599(in)X
+2681(input)X
+2865(mode,)X
+3083(entering)X
+3366(an)X
+7 f
+3462(<escape>)X
+1 f
+3866(char-)X
+576 5280(acter)N
+753(terminates)X
+1107(text)X
+1247(input)X
+1431(mode)X
+1629(and)X
+1765(returns)X
+2008(to)X
+2090(command)X
+2426(mode.)X
+776 5403(The)N
+921(following)X
+1252(words)X
+1468(have)X
+1640(special)X
+1883(meanings)X
+2210(in)X
+2292(both)X
+2454(the)X
+3 f
+2572(ex)X
+1 f
+2668(and)X
+3 f
+2804(vi)X
+1 f
+2886(command)X
+3222(descriptions:)X
+3 f
+576 5583(<interrupt>)N
+1 f
+776 5673(The)N
+927(interrupt)X
+1229(character)X
+1551(is)X
+1630(used)X
+1803(to)X
+1891(interrupt)X
+2193(the)X
+2317(current)X
+2571(operation.)X
+2940(Normally)X
+7 f
+3274(<control-C>)X
+1 f
+(,)S
+3849(what-)X
+776 5763(ever)N
+935(character)X
+1251(is)X
+1324(set)X
+1433(for)X
+1547(the)X
+1665(current)X
+1913(terminal)X
+2200(is)X
+2273(used.)X
+
+8 p
+%%Page: 8 7
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-8)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+576 762(<literal)N
+847(next>)X
+1 f
+776 852(The)N
+923(literal)X
+1132(next)X
+1292(character)X
+1610(is)X
+1685(used)X
+1854(to)X
+1938(escape)X
+2175(the)X
+2295(subsequent)X
+2673(character)X
+2991(from)X
+3169(any)X
+3307(special)X
+3552(meaning.)X
+3890(This)X
+776 942(character)N
+1102(is)X
+1185(always)X
+7 f
+1438(<control-V>)X
+1 f
+(.)S
+2036(If)X
+2120(the)X
+2248(terminal)X
+2545(is)X
+2627(not)X
+2758(set)X
+2876(up)X
+2985(to)X
+3076(do)X
+3185(XON/XOFF)X
+3614(\257ow)X
+3785(control,)X
+776 1032(then)N
+7 f
+934(<control-Q>)X
+1 f
+1482(is)X
+1555(used)X
+1722(to)X
+1804(mean)X
+1998(literal)X
+2205(next)X
+2363(as)X
+2450(well.)X
+3 f
+576 1212(current)N
+855(pathname)X
+1 f
+776 1302(The)N
+923(pathname)X
+1257(of)X
+1346(the)X
+1467(\256le)X
+1592(currently)X
+1905(being)X
+2106(edited)X
+2325(by)X
+2428(vi.)X
+2553(When)X
+2768(the)X
+2889(percent)X
+3149(character)X
+3468(\(``)X
+7 f
+3549(%)X
+1 f
+(''\))S
+3701(appears)X
+3970(in)X
+776 1392(a)N
+833(\256le)X
+956(name)X
+1151(entered)X
+1409(as)X
+1497(part)X
+1643(of)X
+1731(an)X
+3 f
+1828(ex)X
+1 f
+1925(command)X
+2262(argument,)X
+2606(it)X
+2671(is)X
+2745(replaced)X
+3039(by)X
+3140(the)X
+3259(current)X
+3508(pathname.)X
+3880(\(The)X
+776 1482(``)N
+7 f
+830(%)X
+1 f
+('')S
+952(character)X
+1268(can)X
+1400(be)X
+1496(escaped)X
+1771(by)X
+1871(preceding)X
+2208(it)X
+2272(with)X
+2434(a)X
+2490(backslash.\))X
+3 f
+576 1662(alternate)N
+904(pathname)X
+1 f
+776 1752(The)N
+921(name)X
+1115(of)X
+1202(the)X
+1320(last)X
+1451(\256le)X
+1573(name)X
+1767(mentioned)X
+2125(in)X
+2207(an)X
+3 f
+2304(ex)X
+1 f
+2401(command,)X
+2758(or,)X
+2866(the)X
+2985(previous)X
+3282(current)X
+3531(pathname)X
+3864(if)X
+3934(the)X
+776 1842(last)N
+913(\256le)X
+1041(mentioned)X
+1404(becomes)X
+1710(the)X
+1833(current)X
+2086(\256le.)X
+2253(When)X
+2470(the)X
+2593(hash)X
+2765(mark)X
+2955(character)X
+3276(\(``)X
+7 f
+3357(#)X
+1 f
+(''\))S
+3511(appears)X
+3782(in)X
+3869(a)X
+3930(\256le)X
+776 1932(name)N
+979(entered)X
+1245(as)X
+1341(part)X
+1495(of)X
+1591(an)X
+3 f
+1696(ex)X
+1 f
+1801(command)X
+2146(argument,)X
+2498(it)X
+2571(is)X
+2653(replaced)X
+2955(by)X
+3064(the)X
+3191(alternate)X
+3498(pathname.)X
+3880(\(The)X
+776 2022(``)N
+7 f
+830(#)X
+1 f
+('')S
+952(character)X
+1268(can)X
+1400(be)X
+1496(escaped)X
+1771(by)X
+1871(preceding)X
+2208(it)X
+2272(with)X
+2434(a)X
+2490(backslash.\))X
+3 f
+576 2202(buffer)N
+1 f
+776 2292(One)N
+931(of)X
+1019(a)X
+1076(number)X
+1342(of)X
+1430(named)X
+1665(areas)X
+1852(for)X
+1968(saving)X
+2199(copies)X
+2426(of)X
+2515(text.)X
+2697(Commands)X
+3083(that)X
+3225(change)X
+3475(or)X
+3564(delete)X
+3778(text)X
+3920(can)X
+776 2382(save)N
+941(the)X
+1061(changed)X
+1351(or)X
+1440(deleted)X
+1693(text)X
+1834(into)X
+1979(a)X
+2036(speci\256c)X
+2302(buffer,)X
+2540(for)X
+2655(later)X
+2819(use,)X
+2967(if)X
+3037(the)X
+3156(command)X
+3493(allows)X
+3723(it)X
+3788(\(i.e.)X
+3934(the)X
+3 f
+776 2472(ex)N
+872(change)X
+1 f
+1132(command)X
+1468(cannot)X
+1702(save)X
+1866(the)X
+1985(changed)X
+2274(text)X
+2415(in)X
+2498(a)X
+2555(named)X
+2790(buffer\).)X
+3075(Buffers)X
+3337(are)X
+3457(named)X
+3692(with)X
+3855(a)X
+3912(sin-)X
+776 2562(gle)N
+895(character,)X
+1232(preceded)X
+1544(by)X
+1645(a)X
+1702(double)X
+1941(quote,)X
+2160(e.g.)X
+7 f
+2317("<character>)X
+1 f
+(.)S
+2954(Historic)X
+3232(implementations)X
+3785(of)X
+3 f
+3872(ex)X
+1 f
+3948(/)X
+3 f
+3970(vi)X
+1 f
+776 2652(limited)N
+7 f
+1022(<character>)X
+1 f
+1570(to)X
+1652(the)X
+1770(alphanumeric)X
+2227(characters;)X
+3 f
+2596(nex)X
+1 f
+(/)S
+3 f
+2738(nvi)X
+1 f
+2864(permits)X
+3124(the)X
+3242(use)X
+3369(of)X
+3456(any)X
+3592(character.)X
+776 2832(Buffers)N
+1041(named)X
+1279(by)X
+1383(uppercase)X
+1729(characters)X
+2080(are)X
+2203(the)X
+2325(same)X
+2514(as)X
+2605(buffers)X
+2857(named)X
+3095(by)X
+3199(lowercase)X
+3545(characters,)X
+3916(e.g.)X
+776 2922(the)N
+904(buffer)X
+1131(named)X
+1375(by)X
+1485(the)X
+1613(English)X
+1887(character)X
+2213(``)X
+7 f
+2267(A)X
+1 f
+('')S
+2399(is)X
+2482(the)X
+2610(same)X
+2805(as)X
+2902(the)X
+3030(buffer)X
+3257(named)X
+3500(by)X
+3609(the)X
+3736(character)X
+776 3012(``)N
+7 f
+830(a)X
+1 f
+('',)S
+977(with)X
+1144(the)X
+1267(exception)X
+1604(that,)X
+1769(if)X
+1843(the)X
+1966(buffer)X
+2188(contents)X
+2480(are)X
+2604(being)X
+2807(changed)X
+3100(\(as)X
+3219(with)X
+3386(a)X
+3447(text)X
+3593(deletion)X
+3877(or)X
+3 f
+3970(vi)X
+776 3102(change)N
+1 f
+1036(command\),)X
+1419(the)X
+1537(text)X
+1677(is)X
+2 f
+1750(appended)X
+1 f
+2082(to)X
+2164(the)X
+2282(buffer,)X
+2519(instead)X
+2766(of)X
+2853(replacing)X
+3172(the)X
+3290(current)X
+3538(contents.)X
+776 3282(The)N
+925(buffers)X
+1177(named)X
+1415(by)X
+1519(the)X
+1641(numeric)X
+1928(characters)X
+2279(\(in)X
+2392(English,)X
+2680(``)X
+7 f
+2734(1)X
+1 f
+('')S
+2860(through)X
+3133(``)X
+7 f
+3187(9)X
+1 f
+(''\),)S
+3360(are)X
+3483(special,)X
+3751(in)X
+3838(that)X
+3983(if)X
+776 3372(at)N
+864(least)X
+1041(one)X
+1187(line)X
+1337(is)X
+1420(changed)X
+1718(or)X
+1814(deleted)X
+2075(in)X
+2166(the)X
+2293(\256le,)X
+2444(\(or)X
+2567(a)X
+2632(command)X
+2977(changes)X
+3265(or)X
+3361(deletes)X
+3613(a)X
+3678(region)X
+3912(that)X
+776 3462(crosses)N
+1032(a)X
+1093(line)X
+1238(boundary\))X
+1593(a)X
+1654(copy)X
+1835(of)X
+1927(the)X
+2050(text)X
+2195(is)X
+2273(placed)X
+2508(into)X
+2657(the)X
+2780(numeric)X
+3068(buffer)X
+3290(``)X
+7 f
+3344(1)X
+1 f
+('',)S
+3491(regardless)X
+3842(of)X
+3934(the)X
+776 3552(user)N
+933(specifying)X
+1290(another)X
+1553(buffer)X
+1772(in)X
+1856(which)X
+2074(to)X
+2158(save)X
+2323(it.)X
+2429(Before)X
+2670(this)X
+2807(copy)X
+2985(is)X
+3060(done,)X
+3258(the)X
+3378(previous)X
+3676(contents)X
+3965(of)X
+776 3642(buffer)N
+1000(``)X
+7 f
+1054(1)X
+1 f
+('')S
+1183(are)X
+1309(moved)X
+1555(into)X
+1707(buffer)X
+1932(``)X
+7 f
+1986(2)X
+1 f
+('',)S
+2136(``)X
+7 f
+2190(2)X
+1 f
+('')S
+2320(into)X
+2472(buffer)X
+2697(``)X
+7 f
+2751(3)X
+1 f
+('',)S
+2901(and)X
+3045(so)X
+3144(on.)X
+3292(The)X
+3445(contents)X
+3740(of)X
+3835(buffer)X
+776 3732(``)N
+7 f
+830(9)X
+1 f
+('')S
+961(are)X
+1089(discarded.)X
+1466(In)X
+3 f
+1562(vi)X
+1 f
+1624(,)X
+1672(text)X
+1820(may)X
+1986(be)X
+2090(explicitly)X
+2420(stored)X
+2644(into)X
+2796(the)X
+2922(numeric)X
+3213(buffers.)X
+3509(In)X
+3604(this)X
+3747(case,)X
+3934(the)X
+776 3822(buffer)N
+995(rotation)X
+1266(described)X
+1596(above)X
+1810(occurs)X
+2042(before)X
+2270(the)X
+2390(replacement)X
+2805(of)X
+2894(the)X
+3014(buffer's)X
+3291(contents.)X
+3621(\(Text)X
+3818(cannot)X
+776 3912(be)N
+874(explicitly)X
+1198(stored)X
+1416(into)X
+1562(the)X
+1682(numeric)X
+1966(buffers)X
+2215(in)X
+3 f
+2298(ex)X
+1 f
+2395(because)X
+2671(of)X
+2759(ambiguities)X
+3153(that)X
+3294(this)X
+3430(would)X
+3651(cause)X
+3851(in)X
+3934(the)X
+3 f
+776 4002(ex)N
+1 f
+872(command)X
+1208(syntax.\))X
+776 4182(When)N
+991(a)X
+3 f
+1051(vi)X
+1 f
+1137(command)X
+1477(synopsis)X
+1776(shows)X
+2000(both)X
+2166(a)X
+7 f
+2226([buffer])X
+1 f
+2634(and)X
+2774(a)X
+7 f
+2834([count])X
+1 f
+(,)S
+3214(they)X
+3376(may)X
+3538(be)X
+3638(presented)X
+3970(in)X
+776 4272(any)N
+912(order.)X
+776 4452(Finally,)N
+1052(all)X
+1162(buffers)X
+1420(are)X
+1549(either)X
+1762(``line'')X
+2020(or)X
+2117 0.3750(``character'')AX
+2551(oriented.)X
+2884(All)X
+3 f
+3016(ex)X
+1 f
+3122(commands)X
+3499(which)X
+3725(store)X
+3912(text)X
+776 4542(into)N
+922(buffers)X
+1172(are)X
+1293(line)X
+1435(oriented.)X
+1760(Some)X
+3 f
+1964(vi)X
+1 f
+2048(commands)X
+2417(which)X
+2635(store)X
+2813(text)X
+2955(into)X
+3101(buffers)X
+3351(are)X
+3471(line)X
+3612(oriented,)X
+3916(and)X
+776 4632(some)N
+980(are)X
+1114(character)X
+1445(oriented;)X
+1765(the)X
+1898(description)X
+2289(for)X
+2418(each)X
+2601(applicable)X
+3 f
+2966(vi)X
+1 f
+3063(command)X
+3414(notes)X
+3618(whether)X
+3912(text)X
+776 4722(copied)N
+1020(into)X
+1174(buffers)X
+1432(using)X
+1635(the)X
+1762(command)X
+2107(is)X
+2189(line)X
+2338(or)X
+2434(character)X
+2759(oriented.)X
+3091(In)X
+3187(addition,)X
+3498(the)X
+3 f
+3625(vi)X
+1 f
+3716(command)X
+3 f
+776 4812(display)N
+1053(buffers)X
+1 f
+1332(displays)X
+1628(the)X
+1760(current)X
+2023(orientation)X
+2405(for)X
+2534(each)X
+2717(buffer.)X
+2989(Generally,)X
+3361(the)X
+3494(only)X
+3671(importance)X
+776 4902(attached)N
+1074(to)X
+1166(this)X
+1311(orientation)X
+1688(is)X
+1771(that)X
+1921(if)X
+2000(the)X
+2128(buffer)X
+2355(is)X
+2438(subsequently)X
+2886(inserted)X
+3170(into)X
+3324(the)X
+3451(text,)X
+3620(line)X
+3769(oriented)X
+776 4992(buffers)N
+1027(create)X
+1243(new)X
+1400(lines)X
+1574(for)X
+1691(each)X
+1862(of)X
+1952(the)X
+2073(lines)X
+2247(they)X
+2408(contain,)X
+2687(and)X
+2826(character)X
+3145(oriented)X
+3431(buffers)X
+3682(create)X
+3898(new)X
+776 5082(lines)N
+951(for)X
+1069(any)X
+1209(lines)X
+2 f
+1384(other)X
+1 f
+1577(than)X
+1739(the)X
+1860(\256rst)X
+2007(and)X
+2146(last)X
+2280(lines)X
+2454(they)X
+2615(contain.)X
+2914(The)X
+3062(\256rst)X
+3209(and)X
+3348(last)X
+3482(lines)X
+3656(are)X
+3778(inserted)X
+776 5172(into)N
+927(the)X
+1052(text)X
+1199(at)X
+1284(the)X
+1409(current)X
+1664(cursor)X
+1892(position,)X
+2196(becoming)X
+2539(part)X
+2691(of)X
+2785(the)X
+2910(current)X
+3165(line.)X
+3352(If)X
+3433(there)X
+3621(is)X
+3701(more)X
+3894(than)X
+776 5262(one)N
+912(line)X
+1052(in)X
+1134(the)X
+1252(buffer,)X
+1489(however,)X
+1806(the)X
+1924(current)X
+2172(line)X
+2312(itself)X
+2492(will)X
+2636(be)X
+2732(split.)X
+3 f
+576 5442(unnamed)N
+915(buffer)X
+1 f
+776 5532(The)N
+924(unnamed)X
+1241(buffer)X
+1461(is)X
+1537(a)X
+1596(text)X
+1739(storage)X
+1994(area)X
+2152(which)X
+2371(is)X
+2447(used)X
+2617(by)X
+2720(commands)X
+3090(that)X
+3233(take)X
+3390(a)X
+3450(buffer)X
+3671(as)X
+3762(an)X
+3862(argu-)X
+776 5622(ment,)N
+976(when)X
+1170(no)X
+1270(buffer)X
+1487(is)X
+1560(speci\256ed)X
+1865(by)X
+1965(the)X
+2083(user.)X
+2277(There)X
+2485(is)X
+2558(no)X
+2658(way)X
+2812(to)X
+2894(explicitly)X
+3216 0.4531(reference)AX
+3537(this)X
+3672(buffer.)X
+
+9 p
+%%Page: 9 8
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3698(USD:13-9)X
+576 762(9.)N
+676(Vi)X
+776(Description)X
+1 f
+3 f
+776 885(Vi)N
+1 f
+879(takes)X
+1067(up)X
+1170(the)X
+1291(entire)X
+1497(screen)X
+1727(to)X
+1813(display)X
+2068(the)X
+2190(edited)X
+2410(\256le,)X
+2556(except)X
+2790(for)X
+2908(the)X
+3030(bottom)X
+3280(line)X
+3424(of)X
+3515(the)X
+3637(screen.)X
+3907(The)X
+576 975(bottom)N
+824(line)X
+966(of)X
+1055(the)X
+1175(screen)X
+1403(is)X
+1478(used)X
+1647(to)X
+1731(enter)X
+3 f
+1914(ex)X
+1 f
+2012(commands,)X
+2401(and)X
+2539(for)X
+3 f
+2655(vi)X
+1 f
+2739(error)X
+2918(and)X
+3056(informational)X
+3513(messages.)X
+3877(If)X
+3952(no)X
+576 1065(other)N
+777(information)X
+1191(is)X
+1281(being)X
+1496(displayed,)X
+1860(the)X
+1995(default)X
+2255(display)X
+2523(can)X
+2672(show)X
+2878(the)X
+3013(current)X
+3278(cursor)X
+3516(row)X
+3678(and)X
+3831(cursor)X
+576 1155(column,)N
+863(an)X
+966(indication)X
+1313(of)X
+1407(whether)X
+1693(the)X
+1818(\256le)X
+1947(has)X
+2081(been)X
+2260(modi\256ed,)X
+2591(and)X
+2734(the)X
+2859(current)X
+3114(mode)X
+3319(of)X
+3413(the)X
+3538(editor.)X
+3792(See)X
+3934(the)X
+3 f
+576 1245(ruler)N
+1 f
+750(,)X
+3 f
+790(showdirty)X
+1 f
+1152(and)X
+3 f
+1288(showmode)X
+1 f
+1668(options)X
+1923(for)X
+2037(more)X
+2222(information.)X
+776 1368(Empty)N
+1012(lines)X
+1186(do)X
+1289(not)X
+1414(have)X
+1589(any)X
+1729(special)X
+1976(representation)X
+2455(on)X
+2559(the)X
+2681(screen,)X
+2931(but)X
+3057(lines)X
+3232(on)X
+3336(the)X
+3458(screen)X
+3688(that)X
+3832(would)X
+576 1458(logically)N
+886(come)X
+1090(after)X
+1268(the)X
+1396(end)X
+1542(of)X
+1639(the)X
+1767(\256le)X
+1899(are)X
+2028(displayed)X
+2365(as)X
+2461(a)X
+2526(single)X
+2746(tilde)X
+2917(\(``)X
+7 f
+2998(\304)X
+1 f
+(''\))S
+3156(character.)X
+3521(To)X
+3639(differentiate)X
+576 1548(between)N
+871(empty)X
+1098(lines)X
+1276(and)X
+1419(lines)X
+1597(consisting)X
+1948(of)X
+2042(only)X
+2211(whitespace)X
+2596(characters,)X
+2971(use)X
+3106(the)X
+3 f
+3232(list)X
+1 f
+3362(option.)X
+3634(Historically,)X
+576 1638(implementations)N
+1130(of)X
+3 f
+1218(vi)X
+1 f
+1301(have)X
+1474(also)X
+1624(displayed)X
+1952(some)X
+2141(lines)X
+2312(as)X
+2399(single)X
+2610(asterisk)X
+2875(\(``)X
+7 f
+2956(@)X
+1 f
+(''\))S
+3105(characters.)X
+3492(These)X
+3704(were)X
+3881(lines)X
+576 1728(that)N
+717(were)X
+895(not)X
+1018(correctly)X
+1326(displayed,)X
+1675(i.e.)X
+1795(lines)X
+1968(on)X
+2070(the)X
+2190(screen)X
+2418(that)X
+2560(did)X
+2684(not)X
+2808(correspond)X
+3187(to)X
+3271(lines)X
+3444(in)X
+3528(the)X
+3648(\256le,)X
+3792(or)X
+3881(lines)X
+576 1818(that)N
+716(did)X
+838(not)X
+960(\256t)X
+1046(on)X
+1146(the)X
+1264(current)X
+1512(screen.)X
+3 f
+1778(Nvi)X
+1 f
+1918(never)X
+2117(displays)X
+2399(lines)X
+2570(in)X
+2652(this)X
+2787(fashion.)X
+3 f
+776 1941(Vi)N
+1 f
+881(is)X
+959(a)X
+1020(modeful)X
+1312(editor,)X
+1544(i.e.)X
+1667(it)X
+1736(has)X
+1868(two)X
+2013(modes,)X
+2268(``command'')X
+2718(mode)X
+2922(and)X
+3064(``text)X
+3264(input'')X
+3508(mode.)X
+3752(When)X
+3 f
+3970(vi)X
+1 f
+576 2031(\256rst)N
+724(starts,)X
+937(it)X
+1005(is)X
+1082(in)X
+1168(command)X
+1508(mode.)X
+1750(There)X
+1962(are)X
+2085(several)X
+2337(commands)X
+2708(that)X
+2852(change)X
+3 f
+3104(vi)X
+1 f
+3189(into)X
+3336(text)X
+3479(input)X
+3666(mode.)X
+3907(The)X
+7 f
+576 2121(<escape>)N
+1 f
+980(character)X
+1296(is)X
+1369(used)X
+1536(to)X
+1618(resolve)X
+1870(the)X
+1988(text)X
+2128(input)X
+2312(into)X
+2456(the)X
+2574(\256le,)X
+2716(and)X
+2852(exit)X
+2992(back)X
+3164(into)X
+3308(command)X
+3644(mode.)X
+3882(In)X
+3 f
+3970(vi)X
+1 f
+576 2211(command)N
+916(mode,)X
+1138(the)X
+1260(cursor)X
+1485(is)X
+1562(always)X
+1809(positioned)X
+2166(on)X
+2269(the)X
+2390(last)X
+2524(column)X
+2787(of)X
+2877(characters)X
+3227(which)X
+3446(take)X
+3603(up)X
+3706(more)X
+3894(than)X
+576 2301(one)N
+714(column)X
+976(on)X
+1078(the)X
+1198(screen.)X
+1466(In)X
+3 f
+1555(vi)X
+1 f
+1639(text)X
+1782(insert)X
+1983(mode,)X
+2204(the)X
+2325(cursor)X
+2549(is)X
+2625(positioned)X
+2981(on)X
+3084(the)X
+3205(\256rst)X
+3352(column)X
+3615(of)X
+3705(characters)X
+576 2391(which)N
+792(take)X
+946(up)X
+1046(more)X
+1231(than)X
+1389(one)X
+1525(column)X
+1785(on)X
+1885(the)X
+2003(screen.)X
+776 2514(Generally,)N
+1138(if)X
+1212(the)X
+1335(cursor)X
+1561(line)X
+1707(and)X
+1849(cursor)X
+2076(column)X
+2342(are)X
+2467(not)X
+2595(on)X
+2701(the)X
+2825(screen,)X
+3077(then)X
+3241(the)X
+3365(screen)X
+3597(is)X
+3676(scrolled)X
+3956(\(if)X
+576 2604(the)N
+695(target)X
+899(cursor)X
+1121(is)X
+1195(close\))X
+1407(or)X
+1494(repainted)X
+1813(\(if)X
+1909(the)X
+2027(target)X
+2230(cursor)X
+2451(is)X
+2524(far)X
+2634(away\))X
+2851(so)X
+2942(that)X
+3082(the)X
+3200(cursor)X
+3421(is)X
+3494(on)X
+3594(the)X
+3712(screen.)X
+3978(If)X
+576 2694(the)N
+699(screen)X
+930(is)X
+1009(scrolled,)X
+1309(it)X
+1379(is)X
+1458(moved)X
+1702(a)X
+1764(minimal)X
+2056(amount,)X
+2342(and)X
+2484(the)X
+2608(cursor)X
+2835(line)X
+2981(will)X
+3131(usually)X
+3388(appear)X
+3629(at)X
+3713(the)X
+3837(top)X
+3965(or)X
+576 2784(bottom)N
+832(of)X
+929(the)X
+1057(screen.)X
+1333(In)X
+1430(the)X
+1558(screen)X
+1794(is)X
+1877(repainted,)X
+2226(the)X
+2354(cursor)X
+2585(line)X
+2735(will)X
+2889(appear)X
+3134(in)X
+3226(the)X
+3354(center)X
+3581(of)X
+3678(the)X
+3806(screen,)X
+576 2874(unless)N
+799(the)X
+920(cursor)X
+1144(is)X
+1220(suf\256ciently)X
+1603(close)X
+1791(to)X
+1876(the)X
+1997(beginning)X
+2340(or)X
+2430(end)X
+2569(of)X
+2660(the)X
+2782(\256le)X
+2908(that)X
+3052(this)X
+3191(is)X
+3268(not)X
+3394(possible.)X
+3720(If)X
+3798(the)X
+3 f
+3920(lef-)X
+576 2964(tright)N
+1 f
+794(option)X
+1020(is)X
+1095(set,)X
+1226(the)X
+1346(screen)X
+1574(may)X
+1734(be)X
+1832(scrolled)X
+2108(or)X
+2197(repainted)X
+2518(in)X
+2602(a)X
+2660(horizontal)X
+3007(direction)X
+3314(as)X
+3403(well)X
+3563(as)X
+3651(in)X
+3734(a)X
+3791(vertical)X
+576 3054(one.)N
+776 3177(A)N
+869(major)X
+1091(difference)X
+1453(between)X
+1756(the)X
+1889(historical)X
+3 f
+2222(vi)X
+1 f
+2319(presentation)X
+2746(and)X
+3 f
+2897(nvi)X
+1 f
+3038(is)X
+3126(in)X
+3224(the)X
+3358(scrolling)X
+3674(and)X
+3826(screen)X
+576 3267(oriented)N
+893(position)X
+1204(commands,)X
+3 f
+1625(<control-B>)X
+1 f
+2042(,)X
+3 f
+2116(<control-D>)X
+1 f
+2538(,)X
+3 f
+2612(<control-E>)X
+1 f
+3029(,)X
+3 f
+3103(<control-F>)X
+1 f
+3516(,)X
+3 f
+3590(<control-U>)X
+1 f
+4012(,)X
+3 f
+576 3357(<control-Y>)N
+1 f
+998(,)X
+3 f
+1049(H)X
+1 f
+1111(,)X
+3 f
+1162(L)X
+1 f
+1246(and)X
+3 f
+1394(M)X
+1 f
+1470(.)X
+1542(In)X
+1641(historical)X
+1971(implementations)X
+2536(of)X
+3 f
+2635(vi)X
+1 f
+2697(,)X
+2749(these)X
+2946(commands)X
+3325(acted)X
+3527(on)X
+3639(physical)X
+3938(\(as)X
+576 3447(opposed)N
+877(to)X
+973(logical,)X
+1245(or)X
+1346(screen\))X
+1613(lines.)X
+1838(For)X
+1982(lines)X
+2166(that)X
+2319(were)X
+2509(suf\256ciently)X
+2902(long)X
+3077(in)X
+3172(relation)X
+3450(to)X
+3545(the)X
+3676(size)X
+3834(of)X
+3934(the)X
+576 3537(screen,)N
+822(this)X
+957(meant)X
+1174(that)X
+1315(single)X
+1527(line)X
+1668(scroll)X
+1867(commands)X
+2235(might)X
+2442(repaint)X
+2686(the)X
+2805(entire)X
+3009(screen,)X
+3256(scrolling)X
+3557(or)X
+3645(screen)X
+3872(posi-)X
+576 3627(tioning)N
+823(command)X
+1160(might)X
+1367(not)X
+1489(change)X
+1737(the)X
+1855(screen)X
+2081(or)X
+2168(move)X
+2366(the)X
+2484(cursor)X
+2705(at)X
+2783(all,)X
+2903(and)X
+3039(some)X
+3228(lines)X
+3399(simply)X
+3636(could)X
+3834(not)X
+3956(be)X
+576 3717(displayed,)N
+927(even)X
+1104(though)X
+3 f
+1351(vi)X
+1 f
+1438(would)X
+1663(edit)X
+1808(the)X
+1931(\256le)X
+2058(that)X
+2203(contained)X
+2540(them.)X
+2765(In)X
+3 f
+2857(nvi)X
+1 f
+2963(,)X
+3008(these)X
+3198(commands)X
+3570(act)X
+3689(on)X
+3794(logical,)X
+576 3807(i.e.)N
+718(screen)X
+968(lines.)X
+1203(You)X
+1385(are)X
+1528(unlikely)X
+1834(to)X
+1939(notice)X
+2178(any)X
+2337(difference)X
+2707(unless)X
+2950(you)X
+3113(are)X
+3255(editing)X
+3520(\256les)X
+3696(with)X
+3881(lines)X
+576 3897(signi\256cantly)N
+991(longer)X
+1216(than)X
+1374(a)X
+1430(screen)X
+1656(width.)X
+3 f
+776 4020(Vi)N
+1 f
+883(keeps)X
+1094(track)X
+1283(of)X
+1378(the)X
+1504(currently)X
+1822(``most)X
+2059(attractive'')X
+2440(cursor)X
+2669(position.)X
+2994(Each)X
+3183(command)X
+3527(description)X
+3911(\(for)X
+576 4110(commands)N
+945(that)X
+1087(can)X
+1221(change)X
+1471(the)X
+1591(current)X
+1841(cursor)X
+2064(position\),)X
+2390(speci\256es)X
+2688(if)X
+2759(the)X
+2879(cursor)X
+3101(is)X
+3175(set)X
+3285(to)X
+3368(a)X
+3425(speci\256c)X
+3691(location)X
+3970(in)X
+576 4200(the)N
+705(line,)X
+876(or)X
+974(if)X
+1054(it)X
+1129(is)X
+1213(moved)X
+1462(to)X
+1555(the)X
+1685(``most)X
+1926(attractive)X
+2257(cursor)X
+2490(position''.)X
+2873(The)X
+3030(latter)X
+3227(means)X
+3464(that)X
+3616(the)X
+3746(cursor)X
+3979(is)X
+576 4290(moved)N
+825(to)X
+918(the)X
+1047(cursor)X
+1279(position)X
+1567(that)X
+1717(is)X
+1800(vertically)X
+2133(as)X
+2230(close)X
+2425(as)X
+2522(possible)X
+2814(to)X
+2906(the)X
+3034(current)X
+3292(cursor)X
+3523(position.)X
+3850(If)X
+3934(the)X
+576 4380(current)N
+826(line)X
+968(is)X
+1043(shorter)X
+1288(than)X
+1448(the)X
+1568(cursor)X
+1791(position)X
+3 f
+2070(vi)X
+1 f
+2154(would)X
+2376(select,)X
+2601(the)X
+2722(cursor)X
+2946(is)X
+3022(positioned)X
+3378(on)X
+3481(the)X
+3602(last)X
+3736(character)X
+576 4470(in)N
+666(the)X
+792(line.)X
+980(\(If)X
+1089(the)X
+1215(line)X
+1363(is)X
+1444(empty,)X
+1692(the)X
+1818(cursor)X
+2047(is)X
+2128(positioned)X
+2489(on)X
+2596(the)X
+2721(\256rst)X
+2872(column)X
+3139(of)X
+3233(the)X
+3358(line.\))X
+3572(If)X
+3653(a)X
+3716(command)X
+576 4560(moves)N
+810(the)X
+933(cursor)X
+1159(to)X
+1246(the)X
+1369(most)X
+1549(attractive)X
+1873(position,)X
+2175(it)X
+2245(does)X
+2418(not)X
+2546(alter)X
+2715(the)X
+2839(current)X
+3093(cursor)X
+3320(position,)X
+3623(and)X
+3765(a)X
+3827(subse-)X
+576 4650(quent)N
+775(movement)X
+1134(will)X
+1279(again)X
+1474(attempt)X
+1735(to)X
+1818(move)X
+2017(the)X
+2136(cursor)X
+2358(to)X
+2441(that)X
+2581(position.)X
+2898(Therefore,)X
+3256(although)X
+3556(a)X
+3612(movement)X
+3970(to)X
+576 4740(a)N
+640(line)X
+788(shorter)X
+1039(than)X
+1205(the)X
+1331(currently)X
+1649(most)X
+1832(attractive)X
+2159(position)X
+2444(will)X
+2596(cause)X
+2803(the)X
+2929(cursor)X
+3158(to)X
+3248(move)X
+3454(to)X
+3544(the)X
+3671(end)X
+3816(of)X
+3912(that)X
+576 4830(line,)N
+737(a)X
+794(subsequent)X
+1171(movement)X
+1530(to)X
+1613(a)X
+1670(longer)X
+1896(line)X
+2037(will)X
+2182(cause)X
+2382(the)X
+2501(cursor)X
+2723(to)X
+2806(move)X
+3005(back)X
+3178(to)X
+3260(the)X
+3378(most)X
+3553(attractive)X
+3872(posi-)X
+576 4920(tion.)N
+776 5043(In)N
+864(addition,)X
+1167(the)X
+3 f
+1286($)X
+1 f
+1347(command)X
+1684(makes)X
+1910(the)X
+2029(end)X
+2166(of)X
+2254(each)X
+2423(line)X
+2564(the)X
+2684(most)X
+2861(attractive)X
+3182(cursor)X
+3405(position)X
+3684(rather)X
+3894(than)X
+576 5133(a)N
+632(speci\256c)X
+897(column.)X
+776 5256(Each)N
+3 f
+958(vi)X
+1 f
+1042(command)X
+1380(described)X
+1710(below)X
+1928(notes)X
+2119(where)X
+2338(the)X
+2458(cursor)X
+2681(ends)X
+2850(up)X
+2952(after)X
+3122(it)X
+3188(is)X
+3263(executed.)X
+3611(This)X
+3775(position)X
+576 5346(is)N
+653(described)X
+985(in)X
+1071(terms)X
+1273(of)X
+1364(characters)X
+1715(on)X
+1819(the)X
+1940(line,)X
+2103(i.e.)X
+2244(``the)X
+2419(previous)X
+2718 0.3409(character'',)AX
+3111(or,)X
+3221(``the)X
+3396(last)X
+3530(character)X
+3849(in)X
+3934(the)X
+576 5436(line''.)N
+810(This)X
+972(is)X
+1045(to)X
+1127(avoid)X
+1325(needing)X
+1599(to)X
+1681(continually)X
+2061(refer)X
+2234(to)X
+2316(on)X
+2416(what)X
+2592(part)X
+2737(of)X
+2824(the)X
+2942(character)X
+3258(the)X
+3376(cursor)X
+3597(rests.)X
+776 5559(The)N
+921(following)X
+1252(words)X
+1468(have)X
+1640(special)X
+1883(meaning)X
+2179(for)X
+3 f
+2293(vi)X
+1 f
+2375(commands.)X
+
+10 p
+%%Page: 10 9
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-10)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+576 762(previous)N
+889(context)X
+1 f
+776 852(The)N
+927(position)X
+1210(of)X
+1303(the)X
+1427(cursor)X
+1654(before)X
+1886(the)X
+2010(command)X
+2352(which)X
+2574(caused)X
+2819(the)X
+2944(last)X
+3082(absolute)X
+3376(movement)X
+3741(was)X
+3893(exe-)X
+776 942(cuted.)N
+1012(Each)X
+3 f
+1195(vi)X
+1 f
+1279(command)X
+1617(described)X
+1947(in)X
+2031(the)X
+2151(next)X
+2311(section)X
+2559(that)X
+2700(is)X
+2774(considered)X
+3143(an)X
+3240(absolute)X
+3528(movement)X
+3887(is)X
+3961(so)X
+776 1032(noted.)N
+1014(In)X
+1101(addition,)X
+1403(specifying)X
+2 f
+1757(any)X
+1 f
+1893(address)X
+2154(to)X
+2236(an)X
+3 f
+2332(ex)X
+1 f
+2428(command)X
+2764(is)X
+2837(considered)X
+3205(an)X
+3301(absolute)X
+3588(movement.)X
+3 f
+576 1212(motion)N
+1 f
+776 1302(A)N
+863(second)X
+3 f
+1115(vi)X
+1 f
+1206(command)X
+1551(can)X
+1693(be)X
+1799(used)X
+1976(as)X
+2073(an)X
+2179(optional)X
+2471(trailing)X
+2732(argument)X
+3065(to)X
+3157(the)X
+3 f
+3285(vi)X
+3377(!)X
+1 f
+3404(,)X
+3 f
+3454(<)X
+1 f
+3500(,)X
+3 f
+3550(>)X
+1 f
+3596(,)X
+3 f
+3646(c)X
+1 f
+3682(,)X
+3 f
+3732(d)X
+1 f
+3776(,)X
+3 f
+3826(y)X
+1 f
+(,)S
+3916(and)X
+776 1392(\(depending)N
+1158(on)X
+1259(the)X
+3 f
+1378(tildeop)X
+1 f
+1633(option\))X
+3 f
+1884(\304)X
+1 f
+1931(commands.)X
+2338(This)X
+2500(command)X
+2836(indicates)X
+3141(the)X
+3259(end)X
+3395(of)X
+3482(the)X
+3600(region)X
+3825(of)X
+3912(text)X
+776 1482(that's)N
+993(affected)X
+1292(by)X
+1411(the)X
+1548(command.)X
+1943(The)X
+2107(motion)X
+2372(command)X
+2727(may)X
+2904(be)X
+3019(either)X
+3242(the)X
+3380(command)X
+3736(character)X
+776 1572(repeated)N
+1070(\(in)X
+1180(which)X
+1397(case)X
+1557(it)X
+1622(means)X
+1848(the)X
+1967(current)X
+2216(line\))X
+2384(or)X
+2472(a)X
+2528(cursor)X
+2749(movement)X
+3107(command.)X
+3483(In)X
+3570(the)X
+3688(latter)X
+3873(case,)X
+776 1662(the)N
+894(region)X
+1119(affected)X
+1399(by)X
+1499(the)X
+1617(command)X
+1953(is)X
+2026(from)X
+2202(the)X
+2320(starting)X
+2581(or)X
+2669(stopping)X
+2965(cursor)X
+3187(position)X
+3465(which)X
+3682(comes)X
+3908(\256rst)X
+776 1752(in)N
+859(the)X
+978(\256le,)X
+1120(to)X
+1202(immediately)X
+1622(before)X
+1848(the)X
+1966(starting)X
+2226(or)X
+2313(stopping)X
+2608(cursor)X
+2829(position)X
+3106(which)X
+3322(comes)X
+3547(later)X
+3710(in)X
+3792(the)X
+3910(\256le.)X
+776 1842(Commands)N
+1166(that)X
+1313(operate)X
+1577(on)X
+1684(lines)X
+1862(instead)X
+2116(of)X
+2210(using)X
+2410(beginning)X
+2757(and)X
+2900(ending)X
+3145(cursor)X
+3373(positions)X
+3688(operate)X
+3952(on)X
+776 1932(all)N
+880(of)X
+971(the)X
+1093(lines)X
+1268(that)X
+1412(are)X
+1535(wholly)X
+1781(or)X
+1872(partially)X
+2163(in)X
+2248(the)X
+2369(region.)X
+2637(In)X
+2727(addition,)X
+3032(some)X
+3224(other)X
+3412(commands)X
+3782(become)X
+776 2022(line)N
+922(oriented)X
+1211(depending)X
+1571(on)X
+1677(where)X
+1900(in)X
+1988(the)X
+2112(text)X
+2258(they)X
+2422(are)X
+2548(used.)X
+2762(The)X
+2914(command)X
+3257(descriptions)X
+3671(below)X
+3894(note)X
+776 2112(these)N
+961(special)X
+1204(cases.)X
+776 2292(The)N
+921(following)X
+1252(commands)X
+1619(may)X
+1777(all)X
+1877(be)X
+1973(used)X
+2140(as)X
+2227(motion)X
+2473(components)X
+2880(for)X
+3 f
+2994(vi)X
+1 f
+3076(commands:)X
+7 f
+776 2505(<control-A>)N
+1472(<control-H>)X
+2120(<control-J>)X
+2768(<control-M>)X
+776 2595(<control-N>)N
+1472(<control-P>)X
+2312(<space>)X
+3248($)X
+1256 2685(%)N
+1424('<character>)X
+2600(\()X
+3248(\))X
+1256 2775(+)N
+1952(,)X
+2600(-)X
+3248(/)X
+1256 2865(0)N
+1952(;)X
+2600(?)X
+3248(B)X
+1256 2955(E)N
+1952(F)X
+2600(G)X
+3248(H)X
+1256 3045(L)N
+1952(M)X
+2600(N)X
+3248(T)X
+1256 3135(W)N
+1904([[)X
+2552(]])X
+3248(\303)X
+1256 3225(_)N
+1424(`<character>)X
+2600(b)X
+3248(e)X
+1256 3315(f)N
+1952(h)X
+2600(j)X
+3248(k)X
+1256 3405(l)N
+1952(n)X
+2600(t)X
+3248(w)X
+1256 3495({)N
+1952(|)X
+2600(})X
+1 f
+776 3708(The)N
+923(optional)X
+1207(count)X
+1407(pre\256x)X
+1617(available)X
+1930(for)X
+2047(some)X
+2239(of)X
+2329(the)X
+3 f
+2450(vi)X
+1 f
+2535(commands)X
+2905(that)X
+3048(take)X
+3205(motion)X
+3454(commands,)X
+3844(or)X
+3934(the)X
+776 3798(count)N
+975(pre\256x)X
+1183(available)X
+1494(for)X
+1609(the)X
+3 f
+1728(vi)X
+1 f
+1811(commands)X
+2179(that)X
+2320(are)X
+2439(used)X
+2606(as)X
+2693(motion)X
+2939(components,)X
+3366(may)X
+3524(be)X
+3620(included)X
+3916(and)X
+776 3888(is)N
+2 f
+850(always)X
+1 f
+1093(considered)X
+1463(part)X
+1610(of)X
+1699(the)X
+1819(motion)X
+2067(argument.)X
+2432(For)X
+2565(example,)X
+2879(the)X
+2999(commands)X
+3368(``)X
+7 f
+3422(c2w)X
+1 f
+('')S
+3642(and)X
+3780(``)X
+7 f
+3834(2cw)X
+1 f
+('')S
+776 3978(are)N
+903(equivalent,)X
+1285(and)X
+1429(the)X
+1555(region)X
+1788(affected)X
+2076(by)X
+2184(the)X
+3 f
+2310(c)X
+1 f
+2374(command)X
+2718(is)X
+2799(two)X
+2947(words)X
+3171(of)X
+3266(text.)X
+3454(In)X
+3549(addition,)X
+3858(if)X
+3934(the)X
+776 4068(optional)N
+1066(count)X
+1272(pre\256x)X
+1487(is)X
+1568(speci\256ed)X
+1881(for)X
+2003(both)X
+2173(the)X
+3 f
+2299(vi)X
+1 f
+2389(command)X
+2733(and)X
+2877(its)X
+2980(motion)X
+3234(component,)X
+3639(the)X
+3766(effect)X
+3979(is)X
+776 4158(multiplicative)N
+1246(and)X
+1388(is)X
+1467(considered)X
+1841(part)X
+1992(of)X
+2085(the)X
+2209(motion)X
+2461(argument.)X
+2830(For)X
+2967(example,)X
+3285(the)X
+3408(commands)X
+3780(``)X
+7 f
+3834(4cw)X
+1 f
+('')S
+776 4248(and)N
+912(``)X
+7 f
+966(2c2w)X
+1 f
+('')S
+1232(are)X
+1351(equivalent,)X
+1725(and)X
+1861(the)X
+1979(region)X
+2204(affected)X
+2484(by)X
+2584(the)X
+3 f
+2702(c)X
+1 f
+2758(command)X
+3094(is)X
+3167(four)X
+3321(words)X
+3537(of)X
+3624(text.)X
+3 f
+576 4428(count)N
+1 f
+776 4518(A)N
+859(positive)X
+1137(number)X
+1407(used)X
+1579(as)X
+1671(an)X
+1772(optional)X
+2059(argument)X
+2387(to)X
+2474(most)X
+2654(commands,)X
+3046(either)X
+3254(to)X
+3341(give)X
+3504(a)X
+3566(size)X
+3717(or)X
+3810(a)X
+3872(posi-)X
+776 4608(tion)N
+930(\(for)X
+1081(display)X
+1342(or)X
+1439(movement)X
+1807(commands\),)X
+2231(or)X
+2328(as)X
+2425(a)X
+2491(repeat)X
+2718(count)X
+2926(\(for)X
+3077(commands)X
+3454(that)X
+3604(modify)X
+3865(text\).)X
+776 4698(The)N
+932(count)X
+1141(argument)X
+1475(is)X
+1559(always)X
+1813(optional)X
+2106(and)X
+2254(defaults)X
+2540(to)X
+2634(1)X
+2706(unless)X
+2938(otherwise)X
+3282(noted)X
+3492(in)X
+3586(the)X
+3716(command)X
+776 4788(description.)N
+776 4968(When)N
+995(a)X
+3 f
+1059(vi)X
+1 f
+1149(command)X
+1493(synopsis)X
+1796(shows)X
+2024(both)X
+2194(a)X
+7 f
+2258([buffer])X
+1 f
+2670(and)X
+7 f
+2814([count])X
+1 f
+(,)S
+3198(they)X
+3364(may)X
+3530(be)X
+3634(presented)X
+3970(in)X
+776 5058(any)N
+912(order.)X
+3 f
+576 5238(bigword)N
+1 f
+776 5328(A)N
+854(set)X
+963(of)X
+1050(non-whitespace)X
+1575(characters)X
+1923(preceded)X
+2235(and)X
+2372(followed)X
+2678(by)X
+2779(whitespace)X
+3157(characters)X
+3505(or)X
+3593(the)X
+3712(beginning)X
+776 5418(or)N
+863(end)X
+999(of)X
+1086(the)X
+1204(\256le)X
+1326(or)X
+1413(line.)X
+776 5598(Groups)N
+1040(of)X
+1135(empty)X
+1363(lines)X
+1542(\(or)X
+1664(lines)X
+1843(containing)X
+2209(only)X
+2379(whitespace)X
+2764 0.3250(characters\))AX
+3146(are)X
+3274(treated)X
+3522(as)X
+3618(a)X
+3683(single)X
+3903(big-)X
+776 5688(word.)N
+
+11 p
+%%Page: 11 10
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-11)X
+576 762(word)N
+1 f
+776 852(Generally,)N
+1133(in)X
+1215(languages)X
+1556(where)X
+1773(it)X
+1837(is)X
+1910(applicable,)X
+3 f
+2280(vi)X
+1 f
+2362(recognizes)X
+2726(two)X
+2866(kinds)X
+3060(of)X
+3148(words.)X
+3405(First,)X
+3592(a)X
+3649(sequence)X
+3965(of)X
+776 942(letters,)N
+1027(digits)X
+1239(and)X
+1390(underscores,)X
+1829(delimited)X
+2166(at)X
+2259(both)X
+2435(ends)X
+2616(by:)X
+2752(characters)X
+3113(other)X
+3312(than)X
+3484(letters,)X
+3734(digits,)X
+3965(or)X
+776 1032(underscores;)N
+1206(the)X
+1328(beginning)X
+1672(or)X
+1763(end)X
+1903(of)X
+1994(a)X
+2054(line;)X
+2220(the)X
+2343(beginning)X
+2688(or)X
+2780(end)X
+2921(of)X
+3013(the)X
+3136(\256le.)X
+3303(Second,)X
+3584(a)X
+3645(sequence)X
+3965(of)X
+776 1122(characters)N
+1126(other)X
+1313(than)X
+1473(letters,)X
+1711(digits,)X
+1930(underscores,)X
+2356(or)X
+2445(whitespace)X
+2824(characters,)X
+3193(delimited)X
+3517(at)X
+3597(both)X
+3761(ends)X
+3930(by:)X
+776 1212(a)N
+838(letter,)X
+1049(digit,)X
+1241(underscore,)X
+1640(or)X
+1733(whitespace)X
+2116(character;)X
+2460(the)X
+2584(beginning)X
+2930(or)X
+3024(end)X
+3167(of)X
+3261(a)X
+3324(line;)X
+3493(the)X
+3618(beginning)X
+3965(or)X
+776 1302(end)N
+912(of)X
+999(the)X
+1117(\256le.)X
+776 1482(Groups)N
+1032(of)X
+1119(empty)X
+1339(lines)X
+1510(\(or)X
+1624(lines)X
+1795(containing)X
+2153(only)X
+2315(whitespace)X
+2692 0.3250(characters\))AX
+3066(are)X
+3185(treated)X
+3424(as)X
+3511(a)X
+3567(single)X
+3778(word.)X
+3 f
+576 1662(paragraph)N
+1 f
+776 1752(An)N
+898(area)X
+1057(of)X
+1148(text)X
+1292(that)X
+1436(begins)X
+1670(with)X
+1837(either)X
+2045(the)X
+2168(beginning)X
+2513(of)X
+2605(a)X
+2666(\256le,)X
+2813(an)X
+2914(empty)X
+3139(line,)X
+3304(or)X
+3396(a)X
+3457(section)X
+3709(boundary,)X
+776 1842(and)N
+912(continues)X
+1239(until)X
+1405(either)X
+1608(an)X
+1704(empty)X
+1924(line,)X
+2084(section)X
+2331(boundary,)X
+2674(or)X
+2761(the)X
+2879(end)X
+3015(of)X
+3102(the)X
+3220(\256le.)X
+776 2022(Groups)N
+1037(of)X
+1129(empty)X
+1355(lines)X
+1532(\(or)X
+1652(lines)X
+1829(containing)X
+2193(only)X
+2361(whitespace)X
+2744 0.3250(characters\))AX
+3124(are)X
+3249(treated)X
+3494(as)X
+3587(a)X
+3649(single)X
+3866(para-)X
+776 2112(graph.)N
+776 2292(Additional)N
+1138(paragraph)X
+1480(boundaries)X
+1852(can)X
+1984(be)X
+2080(de\256ned)X
+2336(using)X
+2529(the)X
+3 f
+2647(paragraph)X
+1 f
+3031(option.)X
+3 f
+576 2472(section)N
+1 f
+776 2562(An)N
+903(area)X
+1067(of)X
+1163(text)X
+1312(that)X
+1461(starts)X
+1659(with)X
+1830(the)X
+1957(beginning)X
+2306(of)X
+2402(the)X
+2529(\256le)X
+2660(or)X
+2756(a)X
+2822(line)X
+2972(whose)X
+3207(\256rst)X
+3361(character)X
+3687(is)X
+3770(an)X
+3876(open)X
+776 2652(brace)N
+971(\(``)X
+7 f
+1052({)X
+1 f
+(''\))S
+1201(and)X
+1337(continues)X
+1664(until)X
+1830(the)X
+1948(next)X
+2106(section)X
+2353(or)X
+2440(the)X
+2558(end)X
+2694(of)X
+2781(the)X
+2899(\256le.)X
+776 2832(Additional)N
+1138(section)X
+1385(boundaries)X
+1757(can)X
+1889(be)X
+1985(de\256ned)X
+2241(using)X
+2434(the)X
+3 f
+2552(sections)X
+1 f
+2839(option.)X
+3 f
+576 3012(sentence)N
+1 f
+776 3102(An)N
+895(area)X
+1051(of)X
+1139(text)X
+1280(that)X
+1421(begins)X
+1651(with)X
+1814(either)X
+2018(the)X
+2137(beginning)X
+2478(of)X
+2566(the)X
+2685(\256le)X
+2808(or)X
+2896(the)X
+3015(\256rst)X
+3160(nonblank)X
+3479(character)X
+3796(follow-)X
+776 3192(ing)N
+901(the)X
+1022(previous)X
+1321(sentence,)X
+1641(paragraph,)X
+2006(or)X
+2096(section)X
+2346(boundary)X
+2672(and)X
+2811(continues)X
+3141(until)X
+3310(the)X
+3431(end)X
+3570(of)X
+3660(the)X
+3781(\256le)X
+3906(or)X
+3996(a)X
+776 3282(or)N
+866(a)X
+926(period)X
+1155(\(``)X
+7 f
+1236(.)X
+1 f
+(''\))S
+1409(exclamation)X
+1825(point)X
+2013(\(``)X
+7 f
+2094(!)X
+1 f
+(''\))S
+2267(or)X
+2358(question)X
+2653(mark)X
+2842(\(``)X
+7 f
+2923(?)X
+1 f
+(''\))S
+3096(character,)X
+3436(followed)X
+3745(by)X
+3849(either)X
+776 3372(an)N
+882(end-of-line)X
+1269(or)X
+1366(two)X
+1516(whitespace)X
+1903(characters.)X
+2300(Any)X
+2468(number)X
+2743(of)X
+2840(closing)X
+3101(parentheses)X
+3505(\(``)X
+7 f
+3586(\))X
+1 f
+(''\),)S
+3764(brackets)X
+776 3462(\(``)N
+7 f
+857(])X
+1 f
+(''\))S
+1007(or)X
+1095(double-quote)X
+1540(\(``)X
+7 f
+1621(")X
+1 f
+(''\))S
+1772(characters)X
+2121(can)X
+2255(appear)X
+2492(between)X
+2782(the)X
+2902(period,)X
+3149(exclamation)X
+3563(point,)X
+3769(or)X
+3858(ques-)X
+776 3552(tion)N
+920(mark)X
+1105(and)X
+1241(the)X
+1359(whitespace)X
+1736(characters)X
+2083(or)X
+2170(end-of-line.)X
+776 3732(Groups)N
+1040(of)X
+1135(empty)X
+1363(lines)X
+1542(\(or)X
+1664(lines)X
+1843(containing)X
+2209(only)X
+2379(whitespace)X
+2764 0.3250(characters\))AX
+3146(are)X
+3273(treated)X
+3520(as)X
+3615(a)X
+3679(single)X
+3898(sen-)X
+776 3822(tence.)N
+3 f
+576 4008(10.)N
+716(Vi)X
+816(Commands)X
+1 f
+776 4131(The)N
+926(following)X
+1262(section)X
+1514(describes)X
+1838(the)X
+1961(commands)X
+2333(available)X
+2649(in)X
+2737(the)X
+2861(command)X
+3203(mode)X
+3407(of)X
+3500(the)X
+3 f
+3624(vi)X
+1 f
+3712(editor.)X
+3965(In)X
+576 4221(each)N
+745(entry)X
+931(below,)X
+1168(the)X
+1287(tag)X
+1406(line)X
+1547(is)X
+1621(a)X
+1678(usage)X
+1882(synopsis)X
+2178(for)X
+2293(the)X
+2412(command)X
+2749(character.)X
+3106(In)X
+3194(addition,)X
+3496(the)X
+3614(\256nal)X
+3776(line)X
+3916(and)X
+576 4311(column)N
+836(the)X
+954(cursor)X
+1175(rests)X
+1342(upon,)X
+1542(and)X
+1678(any)X
+1814(options)X
+2069(which)X
+2285(affect)X
+2489(the)X
+2607(command)X
+2943(are)X
+3062(noted.)X
+3 f
+576 4491([count])N
+841(<control-A>)X
+1 f
+776 4581(Search)N
+1034(forward)X
+7 f
+1328(count)X
+1 f
+1607(times)X
+1819(for)X
+1952(the)X
+2089(current)X
+2356(word.)X
+2600(The)X
+2764(current)X
+3031(word)X
+3236(begins)X
+3485(at)X
+3583(the)X
+3721(\256rst)X
+3885(non-)X
+776 4671(whitespace)N
+1164(character)X
+1491(on)X
+1602(or)X
+1699(after)X
+1877(the)X
+2005(current)X
+2263(cursor)X
+2494(position,)X
+2801(and)X
+2947(extends)X
+3222(up)X
+3332(to)X
+3424(the)X
+3552(next)X
+3720(non-word)X
+776 4761(character)N
+1095(or)X
+1185(the)X
+1306(end)X
+1445(of)X
+1535(the)X
+1656(line.)X
+1839(The)X
+1987(search)X
+2216(is)X
+2292(literal,)X
+2522(i.e.)X
+2643(no)X
+2746(characters)X
+3096(in)X
+3182(the)X
+3304(word)X
+3493(have)X
+3669(any)X
+3809(special)X
+776 4851(meaning)N
+1076(in)X
+1162(terms)X
+1364(of)X
+1455(Regular)X
+1733(Expressions.)X
+2184(It)X
+2257(is)X
+2334(an)X
+2434(error)X
+2615(if)X
+2687(no)X
+2790(matching)X
+3111(pattern)X
+3357(is)X
+3433(found)X
+3643(between)X
+3934(the)X
+776 4941(starting)N
+1036(position)X
+1313(and)X
+1449(the)X
+1567(end)X
+1703(of)X
+1790(the)X
+1908(\256le.)X
+776 5121(The)N
+3 f
+926(<control-A>)X
+1 f
+1373(command)X
+1714(is)X
+1792(an)X
+1893(absolute)X
+2185(movement.)X
+2588(The)X
+3 f
+2738(<control-A>)X
+1 f
+3185(command)X
+3526(may)X
+3690(be)X
+3792(used)X
+3965(as)X
+776 5211(the)N
+896(motion)X
+1144(component)X
+1522(of)X
+1611(other)X
+3 f
+1798(vi)X
+1 f
+1881(commands,)X
+2269(in)X
+2352(which)X
+2569(case)X
+2729(any)X
+2866(text)X
+3007(copied)X
+3242(into)X
+3387(a)X
+3444(buffer)X
+3662(is)X
+3736(character)X
+776 5301(oriented.)N
+776 5481(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(where)X
+1815(the)X
+1933(word)X
+2118(is)X
+2191(found.)X
+776 5571(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(character)X
+1918(of)X
+2005(the)X
+2123(word.)X
+776 5661(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(extended)X
+1 f
+1963(,)X
+3 f
+2003(ignorecase)X
+1 f
+2384(and)X
+3 f
+2520(wrapscan)X
+1 f
+2869(options.)X
+
+12 p
+%%Page: 12 11
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-12)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+576 762([count])N
+841(<control-B>)X
+1 f
+776 852(Page)N
+965(backward)X
+7 f
+1311(count)X
+1 f
+1585(screens.)X
+1896(Two)X
+2077(lines)X
+2262(of)X
+2363(overlap)X
+2638(are)X
+2771(maintained)X
+3161(by)X
+3275(displaying)X
+3642(the)X
+3774(window)X
+776 942(starting)N
+1042(at)X
+1126(line)X
+7 f
+1272(\(top_line)X
+1758(-)X
+1860(count)X
+2154(*)X
+2256(window_size\))X
+2886(+)X
+2988(2)X
+1 f
+(,)S
+3081(where)X
+7 f
+3303(window_size)X
+1 f
+3856(is)X
+3934(the)X
+776 1032(value)N
+973(of)X
+1063(the)X
+3 f
+1184(window)X
+1 f
+1473(option.)X
+1741(\(In)X
+1859(the)X
+1981(case)X
+2144(of)X
+2235(split)X
+2396(screens,)X
+2677(this)X
+2816(size)X
+2965(is)X
+3042(corrected)X
+3366(to)X
+3452(the)X
+3574(current)X
+3826(screen)X
+776 1122(size.\))N
+988(This)X
+1150(is)X
+1223(an)X
+1319(error)X
+1496(if)X
+1565(the)X
+1683(movement)X
+2041(is)X
+2114(past)X
+2263(the)X
+2381(beginning)X
+2721(of)X
+2808(the)X
+2926(\256le.)X
+776 1302(The)N
+3 f
+921(<control-B>)X
+1 f
+1358(command)X
+1694(is)X
+1767(an)X
+1863(absolute)X
+2150(movement.)X
+776 1482(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(of)X
+1816(text)X
+1956(displayed)X
+2283(on)X
+2383(the)X
+2501(screen.)X
+776 1572(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2441(line.)X
+776 1662(Options:)N
+1136(None.)X
+3 f
+576 1842([count])N
+841(<control-D>)X
+1 f
+776 1932(Scroll)N
+990(forward)X
+7 f
+1268(count)X
+1 f
+1531(lines.)X
+1745(If)X
+7 f
+1822(count)X
+1 f
+2085(is)X
+2161(not)X
+2286(speci\256ed,)X
+2614(scroll)X
+2815(forward)X
+3093(the)X
+3214(number)X
+3482(of)X
+3572(lines)X
+3747(speci\256ed)X
+776 2022(by)N
+881(the)X
+1004(last)X
+3 f
+1140(<control-D>)X
+1 f
+1587(or)X
+3 f
+1679(<control-U>)X
+1 f
+2126(command.)X
+2507(If)X
+2586(this)X
+2726(is)X
+2803(the)X
+2925(\256rst)X
+3 f
+3073(<control-D>)X
+1 f
+3519(or)X
+3 f
+3610(<control-U>)X
+1 f
+776 2112(command,)N
+1141(scroll)X
+1348(forward)X
+1632(half)X
+1786(the)X
+1913(number)X
+2188(of)X
+2285(lines)X
+2466(in)X
+2558(the)X
+2686(screen.)X
+2962(\(In)X
+3086(the)X
+3214(case)X
+3383(of)X
+3480(split)X
+3647(screens,)X
+3934(the)X
+776 2202(default)N
+1026(scrolling)X
+1333(distance)X
+1623(is)X
+1703(corrected)X
+2029(to)X
+2117(half)X
+2268(the)X
+2392(current)X
+2646(screen)X
+2878(size.\))X
+3096(This)X
+3264(is)X
+3343(an)X
+3445(error)X
+3628(if)X
+3703(the)X
+3827(move-)X
+776 2292(ment)N
+956(is)X
+1029(past)X
+1178(the)X
+1296(end)X
+1432(of)X
+1519(the)X
+1637(\256le.)X
+776 2472(The)N
+3 f
+921(<control-D>)X
+1 f
+1363(command)X
+1699(is)X
+1772(an)X
+1868(absolute)X
+2155(movement.)X
+776 2652(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(current)X
+1706(line)X
+1846(plus)X
+1999(the)X
+2117(number)X
+2382(of)X
+2469(lines)X
+2640(scrolled.)X
+776 2742(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2441(line.)X
+776 2832(Options:)N
+1136(None.)X
+3 f
+576 3012([count])N
+841(<control-E>)X
+1 f
+776 3102(Scroll)N
+987(forward)X
+7 f
+1262(count)X
+1 f
+1522(lines,)X
+1713(leaving)X
+1969(the)X
+2087(cursor)X
+2308(on)X
+2408(the)X
+2526(current)X
+2774(line)X
+2914(and)X
+3050(column,)X
+3330(if)X
+3399(possible.)X
+3721(This)X
+3883(is)X
+3956(an)X
+776 3192(error)N
+953(if)X
+1022(the)X
+1140(movement)X
+1498(is)X
+1571(past)X
+1720(the)X
+1838(end)X
+1974(of)X
+2061(the)X
+2179(\256le.)X
+776 3372(Line:)N
+1136(Unchanged)X
+1524(unless)X
+1747(the)X
+1868(current)X
+2119(line)X
+2262(scrolls)X
+2494(off)X
+2611(the)X
+2732(screen,)X
+2981(in)X
+3066(which)X
+3285(case)X
+3447(it)X
+3514(is)X
+3590(set)X
+3702(to)X
+3787(the)X
+3908(\256rst)X
+1136 3462(line)N
+1276(on)X
+1376(the)X
+1494(screen.)X
+776 3552(Column:)N
+1136(Unchanged)X
+1523(unless)X
+1744(the)X
+1863(current)X
+2112(line)X
+2253(scrolls)X
+2483(off)X
+2598(the)X
+2717(screen,)X
+2964(in)X
+3047(which)X
+3264(case)X
+3424(it)X
+3489(is)X
+3563(set)X
+3673(to)X
+3757(the)X
+3877(most)X
+1136 3642(attractive)N
+1455(cursor)X
+1676(position.)X
+776 3732(Options:)N
+1136(None.)X
+3 f
+576 3912([count])N
+841(<control-F>)X
+1 f
+776 4002(Page)N
+955(forward)X
+7 f
+1233(count)X
+1 f
+1496(screens.)X
+1797(Two)X
+1968(lines)X
+2143(of)X
+2234(overlap)X
+2499(are)X
+2622(maintained)X
+3002(by)X
+3106(displaying)X
+3463(the)X
+3585(window)X
+3867(start-)X
+776 4092(ing)N
+900(at)X
+980(line)X
+7 f
+1122(top_line)X
+1556(+)X
+1654(count)X
+1944(*)X
+2042(window_size)X
+2620(-)X
+2718(2)X
+1 f
+(,)S
+2808(where)X
+7 f
+3027(window_size)X
+1 f
+3577(is)X
+3651(the)X
+3770(value)X
+3965(of)X
+776 4182(the)N
+3 f
+903(window)X
+1 f
+1198(option.)X
+1471(\(In)X
+1594(the)X
+1721(case)X
+1889(of)X
+1985(split)X
+2151(screens,)X
+2437(this)X
+2581(size)X
+2735(is)X
+2817(corrected)X
+3146(to)X
+3238(the)X
+3366(current)X
+3624(screen)X
+3860(size.\))X
+776 4272(This)N
+938(is)X
+1011(an)X
+1107(error)X
+1284(if)X
+1353(the)X
+1471(movement)X
+1829(is)X
+1902(past)X
+2051(the)X
+2169(end)X
+2305(of)X
+2392(the)X
+2510(\256le.)X
+776 4452(The)N
+3 f
+921(<control-F>)X
+1 f
+1354(command)X
+1690(is)X
+1763(an)X
+1859(absolute)X
+2146(movement.)X
+776 4632(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(line)X
+1742(on)X
+1842(the)X
+1960(screen.)X
+776 4722(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2441(current)X
+2689(line.)X
+776 4812(Options:)N
+1136(None.)X
+3 f
+576 4992(<control-G>)N
+1 f
+776 5082(Display)N
+1055(the)X
+1183(\256le)X
+1315(information.)X
+1763(The)X
+1918(information)X
+2326(includes)X
+2624(the)X
+2753(current)X
+3012(pathname,)X
+3375(the)X
+3504(current)X
+3763(line,)X
+3934(the)X
+776 5172(number)N
+1043(of)X
+1132(total)X
+1296(lines)X
+1469(in)X
+1553(the)X
+1673(\256le,)X
+1817(the)X
+1937(current)X
+2187(line)X
+2329(as)X
+2418(a)X
+2476(percentage)X
+2847(of)X
+2936(the)X
+3056(total)X
+3220(lines)X
+3393(in)X
+3477(the)X
+3597(\256le,)X
+3741(if)X
+3811(the)X
+3930(\256le)X
+776 5262(has)N
+905(been)X
+1079(modi\256ed,)X
+1405(was)X
+1552(able)X
+1708(to)X
+1792(be)X
+1890(locked,)X
+2146(if)X
+2217(the)X
+2337(\256le's)X
+2519(name)X
+2715(has)X
+2844(been)X
+3018(changed,)X
+3328(and)X
+3466(if)X
+3537(the)X
+3658(edit)X
+3801(session)X
+776 5352(is)N
+849(read-only.)X
+776 5532(Line:)N
+1136(Unchanged.)X
+776 5622(Column:)N
+1136(Unchanged.)X
+776 5712(Options:)N
+1136(None.)X
+
+13 p
+%%Page: 13 12
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-13)X
+576 762(<control-H>)N
+576 852([count])N
+841(h)X
+1 f
+776 942(Move)N
+989(the)X
+1113(cursor)X
+1340(back)X
+7 f
+1518(count)X
+1 f
+1784(characters)X
+2137(in)X
+2225(the)X
+2349(current)X
+2603(line.)X
+2789(This)X
+2957(is)X
+3036(an)X
+3138(error)X
+3321(if)X
+3396(the)X
+3520(cursor)X
+3747(is)X
+3827(on)X
+3934(the)X
+776 1032(\256rst)N
+920(character)X
+1236(in)X
+1318(the)X
+1436(line.)X
+776 1212(The)N
+3 f
+923(<control-H>)X
+1 f
+1372(and)X
+3 f
+1511(h)X
+1 f
+1578(commands)X
+1948(may)X
+2109(be)X
+2208(used)X
+2378(as)X
+2468(the)X
+2589(motion)X
+2838(component)X
+3217(of)X
+3307(other)X
+3 f
+3495(vi)X
+1 f
+3580(commands,)X
+3970(in)X
+776 1302(which)N
+992(case)X
+1151(any)X
+1287(text)X
+1427(copied)X
+1661(into)X
+1805(a)X
+1861(buffer)X
+2078(is)X
+2151(character)X
+2467(oriented.)X
+776 1482(Line:)N
+1136(Unchanged.)X
+776 1572(Column:)N
+1136(Set)X
+1263(to)X
+1350(the)X
+7 f
+1473(current)X
+1862(-)X
+1963(count)X
+1 f
+2229(character,)X
+2571(or,)X
+2684(the)X
+2808(\256rst)X
+2958(character)X
+3280(in)X
+3368(the)X
+3492(line)X
+3638(if)X
+7 f
+3713(count)X
+1 f
+3979(is)X
+1136 1662(greater)N
+1380(than)X
+1538(or)X
+1625(equal)X
+1819(to)X
+1901(the)X
+2019(number)X
+2284(of)X
+2371(characters)X
+2718(in)X
+2800(the)X
+2918(line)X
+3058(before)X
+3284(the)X
+3402(cursor.)X
+776 1752(Options:)N
+1136(None.)X
+3 f
+576 1932([count])N
+841(<control-J>)X
+576 2022([count])N
+841(<control-N>)X
+576 2112([count])N
+841(j)X
+1 f
+776 2202(Move)N
+993(the)X
+1121(cursor)X
+1352(down)X
+7 f
+1560(count)X
+1 f
+1830(lines)X
+2011(without)X
+2285(changing)X
+2609(the)X
+2737(current)X
+2995(column.)X
+3305(This)X
+3477(is)X
+3560(an)X
+3666(error)X
+3854(if)X
+3934(the)X
+776 2292(movement)N
+1134(is)X
+1207(past)X
+1356(the)X
+1474(end)X
+1610(of)X
+1697(the)X
+1815(\256le.)X
+776 2472(The)N
+3 f
+927(<control-J>)X
+1 f
+1331(,)X
+3 f
+1377(<control-N>)X
+1 f
+1825(and)X
+3 f
+1967(j)X
+1 f
+2020(commands)X
+2393(may)X
+2557(be)X
+2659(used)X
+2832(as)X
+2925(the)X
+3049(motion)X
+3301(component)X
+3684(of)X
+3778(other)X
+3 f
+3970(vi)X
+1 f
+776 2562(commands,)N
+1163(in)X
+1245(which)X
+1461(case)X
+1620(any)X
+1756(text)X
+1896(copied)X
+2130(into)X
+2274(a)X
+2330(buffer)X
+2547(is)X
+2620(line)X
+2760(oriented.)X
+776 2742(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(current)X
+1706(line)X
+1846(plus)X
+7 f
+1999(count)X
+1 f
+(.)S
+776 2832(Column:)N
+1136(The)X
+1281(most)X
+1456(attractive)X
+1775(cursor)X
+1996(position.)X
+776 2922(Options:)N
+1136(None.)X
+3 f
+576 3102(<control-L>)N
+576 3192(<control-R>)N
+1 f
+776 3282(Repaint)N
+1045(the)X
+1163(screen.)X
+776 3462(Line:)N
+1136(Unchanged.)X
+776 3552(Column:)N
+1136(Unchanged.)X
+776 3642(Options:)N
+1136(None.)X
+3 f
+576 3822([count])N
+841(<control-M>)X
+576 3912([count])N
+841(+)X
+1 f
+776 4002(Move)N
+984(the)X
+1103(cursor)X
+1325(down)X
+7 f
+1524(count)X
+1 f
+1785(lines)X
+1957(to)X
+2040(the)X
+2159(\256rst)X
+2304(nonblank)X
+2623(character)X
+2940(of)X
+3028(that)X
+3169(line.)X
+3350(This)X
+3513(is)X
+3587(an)X
+3684(error)X
+3863(if)X
+3934(the)X
+776 4092(movement)N
+1134(is)X
+1207(past)X
+1356(the)X
+1474(end)X
+1610(of)X
+1697(the)X
+1815(\256le.)X
+776 4272(The)N
+3 f
+922(<control-M>)X
+1 f
+1384(and)X
+3 f
+1522(+)X
+1 f
+1590(commands)X
+1959(may)X
+2119(be)X
+2217(used)X
+2386(as)X
+2475(the)X
+2595(motion)X
+2843(component)X
+3221(of)X
+3310(other)X
+3 f
+3497(vi)X
+1 f
+3581(commands,)X
+3970(in)X
+776 4362(which)N
+992(case)X
+1151(any)X
+1287(text)X
+1427(copied)X
+1661(into)X
+1805(a)X
+1861(buffer)X
+2078(is)X
+2151(line)X
+2291(oriented.)X
+776 4542(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(current)X
+1706(line)X
+1846(plus)X
+7 f
+1999(count)X
+1 f
+(.)S
+776 4632(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 4722(Options:)N
+1136(None.)X
+3 f
+576 4902([count])N
+841(<control-P>)X
+576 4992([count])N
+841(k)X
+1 f
+776 5082(Move)N
+983(the)X
+1101(cursor)X
+1323(up)X
+7 f
+1424(count)X
+1 f
+1685(lines,)X
+1877(without)X
+2142(changing)X
+2457(the)X
+2576(current)X
+2825(column.)X
+3126(This)X
+3289(is)X
+3363(an)X
+3460(error)X
+3638(if)X
+3708(the)X
+3827(move-)X
+776 5172(ment)N
+956(is)X
+1029(past)X
+1178(the)X
+1296(beginning)X
+1636(of)X
+1723(the)X
+1841(\256le.)X
+776 5352(The)N
+3 f
+924(<control-P>)X
+1 f
+1360(and)X
+3 f
+1499(k)X
+1 f
+1566(commands)X
+1937(may)X
+2099(be)X
+2199(used)X
+2370(as)X
+2461(the)X
+2583(motion)X
+2833(component)X
+3213(of)X
+3304(other)X
+3 f
+3493(vi)X
+1 f
+3579(commands,)X
+3970(in)X
+776 5442(which)N
+992(case)X
+1151(any)X
+1287(text)X
+1427(copied)X
+1661(into)X
+1805(a)X
+1861(buffer)X
+2078(is)X
+2151(line)X
+2291(oriented.)X
+776 5622(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(current)X
+1706(line)X
+1846(minus)X
+2061(count.)X
+776 5712(Column:)N
+1136(The)X
+1281(most)X
+1456(attractive)X
+1775(cursor)X
+1996(position.)X
+
+14 p
+%%Page: 14 13
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-14)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+1 f
+776 762(Options:)N
+1136(None.)X
+3 f
+576 942(<control-T>)N
+1 f
+776 1032(Return)N
+1014(to)X
+1096(the)X
+1214(most)X
+1389(recent)X
+1606(tag)X
+1724(context.)X
+2020(The)X
+3 f
+2165(<control-T>)X
+1 f
+2602(command)X
+2938(is)X
+3011(an)X
+3107(absolute)X
+3394(movement.)X
+776 1212(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(context)X
+1714(of)X
+1801(the)X
+1919(previous)X
+2215(tag)X
+2333(command.)X
+776 1302(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(context)X
+1714(of)X
+1801(the)X
+1919(previous)X
+2215(tag)X
+2333(command.)X
+776 1392(Options:)N
+1136(None.)X
+3 f
+576 1572(<control-U>)N
+1 f
+776 1662(Scroll)N
+1003(backward)X
+7 f
+1352(count)X
+1 f
+1628(lines.)X
+1856(If)X
+7 f
+1947(count)X
+1 f
+2224(is)X
+2314(not)X
+2453(speci\256ed,)X
+2795(scroll)X
+3010(backward)X
+3360(the)X
+3495(number)X
+3777(of)X
+3881(lines)X
+776 1752(speci\256ed)N
+1096(by)X
+1211(the)X
+1344(last)X
+3 f
+1490(<control-D>)X
+1 f
+1947(or)X
+3 f
+2049(<control-U>)X
+1 f
+2505(command.)X
+2895(If)X
+2983(this)X
+3132(is)X
+3219(the)X
+3351(\256rst)X
+3 f
+3509(<control-D>)X
+1 f
+3965(or)X
+3 f
+776 1842(<control-U>)N
+1 f
+1221(command,)X
+1580(scroll)X
+1781(backward)X
+2117(half)X
+2266(the)X
+2388(number)X
+2657(of)X
+2748(lines)X
+2923(in)X
+3009(the)X
+3131(screen.)X
+3401(\(In)X
+3519(the)X
+3641(case)X
+3804(of)X
+3895(split)X
+776 1932(screens,)N
+1057(the)X
+1179(default)X
+1426(scrolling)X
+1729(distance)X
+2015(is)X
+2091(corrected)X
+2414(to)X
+2499(half)X
+2647(the)X
+2768(current)X
+3019(screen)X
+3248(size.\))X
+3463(This)X
+3628(is)X
+3704(an)X
+3803(error)X
+3983(if)X
+776 2022(the)N
+894(movement)X
+1252(is)X
+1325(past)X
+1474(the)X
+1592(beginning)X
+1932(of)X
+2019(the)X
+2137(\256le.)X
+776 2202(The)N
+3 f
+921(<control-U>)X
+1 f
+1363(command)X
+1699(is)X
+1772(an)X
+1868(absolute)X
+2155(movement.)X
+776 2382(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(current)X
+1706(line)X
+1846(minus)X
+2061(the)X
+2179(amount)X
+2439(scrolled.)X
+776 2472(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 2562(Options:)N
+1136(None.)X
+3 f
+576 2742(<control-W>)N
+1 f
+776 2832(Switch)N
+1021(to)X
+1106(the)X
+1227(next)X
+1388(lower)X
+1594(screen)X
+1823(in)X
+1908(the)X
+2029(window,)X
+2330(or,)X
+2440(to)X
+2525(the)X
+2646(\256rst)X
+2793(screen)X
+3022(if)X
+3094(there)X
+3278(are)X
+3400(no)X
+3503(lower)X
+3709(screens)X
+3970(in)X
+776 2922(the)N
+894(window.)X
+776 3102(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(previous)X
+1754(cursor)X
+1975(position)X
+2252(in)X
+2334(the)X
+2452(window.)X
+776 3192(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(previous)X
+1754(cursor)X
+1975(position)X
+2252(in)X
+2334(the)X
+2452(window.)X
+776 3282(Options:)N
+1136(None.)X
+3 f
+576 3462(<control-Y>)N
+1 f
+776 3552(Scroll)N
+989(backward)X
+7 f
+1324(count)X
+1 f
+1586(lines,)X
+1779(leaving)X
+2037(the)X
+2157(current)X
+2407(line)X
+2550(and)X
+2689(column)X
+2952(as)X
+3042(is,)X
+3138(if)X
+3210(possible.)X
+3535(This)X
+3700(is)X
+3776(an)X
+3875(error)X
+776 3642(if)N
+845(the)X
+963(movement)X
+1321(is)X
+1394(past)X
+1543(the)X
+1661(beginning)X
+2001(of)X
+2088(the)X
+2206(\256le.)X
+776 3822(Line:)N
+1136(Unchanged)X
+1525(unless)X
+1748(the)X
+1869(current)X
+2120(line)X
+2263(scrolls)X
+2496(off)X
+2614(the)X
+2736(screen,)X
+2986(in)X
+3072(which)X
+3292(case)X
+3455(it)X
+3523(is)X
+3600(set)X
+3713(to)X
+3799(the)X
+3921(last)X
+1136 3912(line)N
+1276(of)X
+1363(text)X
+1503(displayed)X
+1830(on)X
+1930(the)X
+2048(screen.)X
+776 4002(Column:)N
+1136(Unchanged)X
+1536(unless)X
+1770(the)X
+1902(current)X
+2164(line)X
+2318(scrolls)X
+2561(off)X
+2689(the)X
+2821(screen,)X
+3081(in)X
+3177(which)X
+3407(case)X
+3580(it)X
+3658(is)X
+3745(the)X
+3877(most)X
+1136 4092(attractive)N
+1455(cursor)X
+1676(position.)X
+776 4182(Options:)N
+1136(None.)X
+3 f
+576 4362(<control-Z>)N
+1 f
+776 4452(Suspend)N
+1069(the)X
+1189(current)X
+1439(editor)X
+1648(session.)X
+1941(If)X
+2017(the)X
+2137(\256le)X
+2261(has)X
+2390(been)X
+2564(modi\256ed)X
+2870(since)X
+3057(it)X
+3124(was)X
+3272(last)X
+3406(completely)X
+3785(written,)X
+776 4542(and)N
+914(the)X
+3 f
+1034(autowrite)X
+1 f
+1386(option)X
+1612(is)X
+1687(set,)X
+1817(the)X
+1936(\256le)X
+2059(is)X
+2133(written)X
+2381(before)X
+2608(the)X
+2727(editor)X
+2935(session)X
+3187(is)X
+3261(suspended.)X
+3656(If)X
+3731(this)X
+3867(write)X
+776 4632(fails,)N
+954(the)X
+1072(editor)X
+1279(session)X
+1530(is)X
+1603(not)X
+1725(suspended.)X
+776 4812(Line:)N
+1136(Unchanged.)X
+776 4902(Column:)N
+1136(Unchanged.)X
+776 4992(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(autowrite)X
+1 f
+2006(option.)X
+3 f
+576 5172(<escape>)N
+1 f
+776 5262(Execute)N
+3 f
+1055(ex)X
+1 f
+1151(commands)X
+1518(or)X
+1605(cancel)X
+1831(partial)X
+2056(commands.)X
+2463(If)X
+2537(an)X
+3 f
+2633(ex)X
+1 f
+2729(command)X
+3065(is)X
+3138(being)X
+3336(entered)X
+3593(\(e.g.)X
+3 f
+3776(/)X
+1 f
+3798(,)X
+3 f
+3838(?)X
+1 f
+(,)S
+3 f
+3918(:)X
+1 f
+3965(or)X
+3 f
+776 5352(!)N
+1 f
+803(\),)X
+877(the)X
+1002(command)X
+1345(is)X
+1425(executed.)X
+1778(If)X
+1859(a)X
+1922(partial)X
+2154(command)X
+2497(has)X
+2631(been)X
+2810(entered,)X
+3093(e.g.)X
+3255(or)X
+3348(the)X
+3472(command)X
+3814(is)X
+3893(can-)X
+776 5442(celled.)N
+1028(Otherwise,)X
+1398(it)X
+1462(is)X
+1535(an)X
+1631(error.)X
+776 5622(Line:)N
+1136(When)X
+1350(an)X
+3 f
+1448(ex)X
+1 f
+1546(command)X
+1884(is)X
+1959(being)X
+2159(executed,)X
+2487(the)X
+2607(current)X
+2857(line)X
+2999(is)X
+3074(set)X
+3186(as)X
+3276(described)X
+3607(for)X
+3724(that)X
+3867(com-)X
+1136 5712(mand.)N
+1374(Otherwise,)X
+1744(unchanged.)X
+
+15 p
+%%Page: 15 14
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-15)X
+1 f
+776 762(Column:)N
+1136(When)X
+1354(an)X
+3 f
+1456(ex)X
+1 f
+1558(command)X
+1901(is)X
+1981(being)X
+2186(executed,)X
+2519(the)X
+2644(current)X
+2899(column)X
+3166(is)X
+3246(set)X
+3362(as)X
+3456(described)X
+3791(for)X
+3912(that)X
+1136 852(command.)N
+1512(Otherwise,)X
+1882(unchanged.)X
+776 942(Options:)N
+1136(None.)X
+3 f
+576 1122(<control-]>)N
+1 f
+776 1212(Push)N
+953(a)X
+1011(tag)X
+1131 0.4531(reference)AX
+1454(onto)X
+1618(the)X
+1738(tag)X
+1858(stack.)X
+2085(The)X
+2232(tags)X
+2383(\256les)X
+2538(\(see)X
+2691(the)X
+3 f
+2812(tags)X
+1 f
+2973(option)X
+3200(for)X
+3317(more)X
+3505(information\))X
+3933(are)X
+776 1302(searched)N
+1086(for)X
+1207(a)X
+1270(tag)X
+1395(matching)X
+1720(the)X
+1845(current)X
+2100(word.)X
+2332(The)X
+2484(current)X
+2739(word)X
+2931(begins)X
+3167(at)X
+3252(the)X
+3377(\256rst)X
+3528(non-whitespace)X
+776 1392(character)N
+1092(on)X
+1192(or)X
+1279(after)X
+1447(the)X
+1565(current)X
+1813(cursor)X
+2034(position,)X
+2331(and)X
+2468(extends)X
+2734(up)X
+2835(to)X
+2918(the)X
+3037(next)X
+3196(non-word)X
+3529(character)X
+3846(or)X
+3934(the)X
+776 1482(end)N
+914(of)X
+1003(the)X
+1123(line.)X
+1305(If)X
+1381(a)X
+1439(matching)X
+1759(tag)X
+1879(is)X
+1954(found,)X
+2183(the)X
+2302(current)X
+2551(\256le)X
+2674(is)X
+2748(discarded)X
+3077(and)X
+3214(the)X
+3333(\256le)X
+3456(containing)X
+3815(the)X
+3934(tag)X
+776 1572 0.4531(reference)AN
+1097(is)X
+1170(edited.)X
+776 1752(If)N
+851(the)X
+971(current)X
+1221(\256le)X
+1345(has)X
+1474(been)X
+1648(modi\256ed)X
+1954(since)X
+2141(it)X
+2207(was)X
+2354(last)X
+2487(completely)X
+2865(written,)X
+3134(the)X
+3254(command)X
+3592(will)X
+3738(fail.)X
+3907(The)X
+3 f
+776 1842(<control-]>)N
+1 f
+1187(command)X
+1523(is)X
+1596(an)X
+1692(absolute)X
+1979(movement.)X
+776 2022(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(matching)X
+2392(tag)X
+2510(string.)X
+776 2112(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(start)X
+1616(of)X
+1703(the)X
+1821(matching)X
+2139(tag)X
+2257(string.)X
+776 2202(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(tags)X
+1 f
+1814(and)X
+3 f
+1950(taglength)X
+1 f
+2290(options.)X
+3 f
+576 2382(<control-\303>)N
+1 f
+776 2472(Switch)N
+1018(to)X
+1100(the)X
+1218(most)X
+1393(recently)X
+1672(edited)X
+1888(\256le.)X
+776 2652(If)N
+852(the)X
+972(\256le)X
+1096(has)X
+1225(been)X
+1399(modi\256ed)X
+1705(since)X
+1892(it)X
+1958(was)X
+2105(last)X
+2238(completely)X
+2616(written,)X
+2886(and)X
+3025(the)X
+3 f
+3146(autowrite)X
+1 f
+3499(option)X
+3726(is)X
+3802(set,)X
+3934(the)X
+776 2742(\256le)N
+905(is)X
+984(written)X
+1237(out.)X
+1405(If)X
+1485(this)X
+1626(write)X
+1817(fails,)X
+2001(the)X
+2125(command)X
+2467(will)X
+2617(fail.)X
+2790(Otherwise,)X
+3166(if)X
+3241(the)X
+3365(current)X
+3619(\256le)X
+3747(has)X
+3880(been)X
+776 2832(modi\256ed)N
+1080(since)X
+1265(it)X
+1329(was)X
+1474(last)X
+1605(completely)X
+1981(written,)X
+2248(the)X
+2366(command)X
+2702(will)X
+2846(fail.)X
+776 3012(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(the)X
+1716(cursor)X
+1937(was)X
+2082(on)X
+2182(when)X
+2376(the)X
+2494(\256le)X
+2616(was)X
+2761(last)X
+2892(edited.)X
+776 3102(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(column)X
+1718(the)X
+1836(cursor)X
+2057(was)X
+2202(on)X
+2302(when)X
+2496(the)X
+2614(\256le)X
+2736(was)X
+2881(last)X
+3012(edited.)X
+776 3192(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(autowrite)X
+1 f
+2006(option.)X
+3 f
+576 3372([count])N
+841(<space>)X
+576 3462([count])N
+841(l)X
+1 f
+776 3552(Move)N
+984(the)X
+1103(cursor)X
+1325(forward)X
+7 f
+1602(count)X
+1 f
+1864(characters)X
+2213(without)X
+2479(changing)X
+2795(the)X
+2915(current)X
+3165(line.)X
+3347(This)X
+3511(is)X
+3586(an)X
+3684(error)X
+3863(if)X
+3934(the)X
+776 3642(cursor)N
+997(is)X
+1070(on)X
+1170(the)X
+1288(last)X
+1419(character)X
+1735(in)X
+1817(the)X
+1935(line.)X
+776 3822(The)N
+3 f
+921(<space>)X
+1 f
+1220(and)X
+3 f
+1356(l)X
+1 f
+1398(commands)X
+1765(may)X
+1923(be)X
+2019(used)X
+2186(as)X
+2273(the)X
+2391(motion)X
+2637(component)X
+3013(of)X
+3100(other)X
+3 f
+3285(vi)X
+1 f
+3367(commands,)X
+3754(in)X
+3836(which)X
+776 3912(case)N
+937(any)X
+1075(text)X
+1217(copied)X
+1453(into)X
+1599(a)X
+1657(buffer)X
+1876(is)X
+1951(character)X
+2269(oriented.)X
+2594(In)X
+2683(addition,)X
+2987(these)X
+3173(commands)X
+3541(may)X
+3700(be)X
+3797(used)X
+3965(as)X
+776 4002(the)N
+908(motion)X
+1168(components)X
+1589(of)X
+1690(other)X
+1889(commands)X
+2271(when)X
+2480(the)X
+2613(cursor)X
+2849(is)X
+2937(on)X
+3052(the)X
+3185(last)X
+3331(character)X
+3662(in)X
+3759(the)X
+3892(line,)X
+776 4092(without)N
+1040(error.)X
+776 4272(Line:)N
+1136(Unchanged.)X
+776 4362(Column:)N
+1136(Set)X
+1259(to)X
+1342(the)X
+1461(current)X
+1710(character)X
+2027(plus)X
+2181(the)X
+2300(next)X
+7 f
+2459(count)X
+1 f
+2720(characters,)X
+3088(or)X
+3177(to)X
+3261(the)X
+3381(last)X
+3514(character)X
+3832(on)X
+3934(the)X
+1136 4452(line)N
+1278(if)X
+7 f
+1349(count)X
+1 f
+1611(is)X
+1686(greater)X
+1932(than)X
+2092(the)X
+2212(number)X
+2478(of)X
+2566(characters)X
+2914(in)X
+2997(the)X
+3116(line)X
+3257(after)X
+3426(the)X
+3545(current)X
+3794(charac-)X
+1136 4542(ter.)N
+776 4632(Options:)N
+1136(None.)X
+3 f
+576 4812([count])N
+841(!)X
+888(motion)X
+1148(shell-argument\(s\))X
+1 f
+776 4902(Replace)N
+1055(text)X
+1195(with)X
+1357(results)X
+1586(from)X
+1762(a)X
+1818(shell)X
+1989(command.)X
+2366(Pass)X
+2529(the)X
+2648(lines)X
+2820(speci\256ed)X
+3126(by)X
+3227(the)X
+7 f
+3346(count)X
+1 f
+3607(and)X
+7 f
+3744(motion)X
+1 f
+776 4992(arguments)N
+1136(as)X
+1229(standard)X
+1527(input)X
+1717(to)X
+1805(the)X
+1928(program)X
+2225(named)X
+2464(by)X
+2569(the)X
+3 f
+2692(shell)X
+1 f
+2872(option,)X
+3121(and)X
+3262(replace)X
+3520(those)X
+3714(lines)X
+3890(with)X
+776 5082(the)N
+894(output)X
+1118(\(both)X
+1307(standard)X
+1599(error)X
+1776(and)X
+1912(standard)X
+2204(output\))X
+2455(of)X
+2542(that)X
+2682(command.)X
+776 5262(After)N
+966(the)X
+1084(motion)X
+1330(is)X
+1403(entered,)X
+3 f
+1680(vi)X
+1 f
+1762(prompts)X
+2044(for)X
+2158(arguments)X
+2512(to)X
+2594(the)X
+2712(shell)X
+2883(command.)X
+776 5442(Within)N
+1026(those)X
+1223(arguments,)X
+1605(``)X
+7 f
+1659(%)X
+1 f
+('')S
+1790(and)X
+1935(``)X
+7 f
+1989(#)X
+1 f
+('')S
+2120(characters)X
+2476(are)X
+2604(expanded)X
+2941(to)X
+3032(the)X
+3159(current)X
+3416(and)X
+3561(alternate)X
+3867(path-)X
+776 5532(names,)N
+1024(respectively.)X
+1475(The)X
+1623(``)X
+7 f
+1677(!)X
+1 f
+('')S
+1822(character)X
+2141(is)X
+2217(expanded)X
+2548(with)X
+2713(the)X
+2833(command)X
+3171(text)X
+3313(of)X
+3402(the)X
+3522(previous)X
+3 f
+3820(!)X
+1 f
+3889(or)X
+3 f
+3978(:!)X
+1 f
+776 5622(commands.)N
+1183 0.3125(\(Therefore,)AX
+1568(the)X
+1686(command)X
+3 f
+2022(!!)X
+1 f
+2116(repeats)X
+2364(the)X
+2482(previous)X
+3 f
+2778(!)X
+1 f
+2845(command.\))X
+3248(The)X
+3393(special)X
+3637(meanings)X
+3965(of)X
+776 5712(``)N
+7 f
+830(%)X
+1 f
+('',)S
+975(``)X
+7 f
+1029(#)X
+1 f
+('')S
+1154(and)X
+1293(``)X
+7 f
+1347(!)X
+1 f
+('')S
+1492(can)X
+1627(be)X
+1726(overridden)X
+2097(by)X
+2200(escaping)X
+2504(them)X
+2687(with)X
+2852(a)X
+2910(backslash.)X
+3284(If)X
+3360(no)X
+3 f
+3462(!)X
+1 f
+3531(or)X
+3 f
+3620(:!)X
+1 f
+3716(command)X
+776 5802(has)N
+907(yet)X
+1029(been)X
+1205(executed,)X
+1535(it)X
+1603(is)X
+1680(an)X
+1780(error)X
+1961(to)X
+2047(use)X
+2178(an)X
+2278(unescaped)X
+2637(``)X
+7 f
+2691(!)X
+1 f
+('')S
+2837(character.)X
+3197(The)X
+3 f
+3346(!)X
+1 f
+3417(command)X
+3758(does)X
+2 f
+3930(not)X
+
+16 p
+%%Page: 16 15
+10 s 10 xH 0 xS 2 f 1 i
+3 f
+576 474(USD:13-16)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+1 f
+776 762(do)N
+880(shell)X
+1055(expansion)X
+1404(on)X
+1508(the)X
+1630(strings)X
+1867(provided)X
+2175(as)X
+2265(arguments.)X
+2662(If)X
+2739(any)X
+2878(of)X
+2968(the)X
+3089(above)X
+3304(expansions)X
+3683(change)X
+3934(the)X
+776 852(arguments)N
+1130(the)X
+1248(user)X
+1402(entered,)X
+1679(the)X
+1797(command)X
+2133(is)X
+2206(redisplayed)X
+2596(at)X
+2674(the)X
+2792(bottom)X
+3038(of)X
+3125(the)X
+3243(screen.)X
+3 f
+776 1032(Vi)N
+1 f
+882(then)X
+1046(executes)X
+1349(the)X
+1473(program)X
+1771(named)X
+2011(by)X
+2117(the)X
+3 f
+2241(shell)X
+1 f
+2422(option,)X
+2672(with)X
+2840(a)X
+3 f
+9 f
+2902(-)X
+2904(-)X
+3 f
+2948(c)X
+1 f
+3010(\257ag)X
+3156(followed)X
+3467(by)X
+3573(the)X
+3698(arguments)X
+776 1122(\(which)N
+1019(are)X
+1138(bundled)X
+1416(into)X
+1560(a)X
+1616(single)X
+1827(argument\).)X
+776 1302(The)N
+3 f
+921(!)X
+1 f
+988(command)X
+1324(is)X
+1397(permitted)X
+1724(in)X
+1806(an)X
+1902(empty)X
+2122(\256le.)X
+776 1482(If)N
+850(the)X
+968(\256le)X
+1090(has)X
+1217(been)X
+1389(modi\256ed)X
+1693(since)X
+1878(it)X
+1942(was)X
+2087(last)X
+2218(completely)X
+2594(written,)X
+2861(the)X
+3 f
+2979(!)X
+1 f
+3046(command)X
+3382(will)X
+3526(warn)X
+3707(you.)X
+776 1662(Line:)N
+1136(The)X
+1281(\256rst)X
+1425(line)X
+1565(of)X
+1652(the)X
+1770(replaced)X
+2063(text.)X
+776 1752(Column:)N
+1136(The)X
+1281(\256rst)X
+1425(column)X
+1685(of)X
+1772(the)X
+1890(replaced)X
+2183(text.)X
+776 1842(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(shell)X
+1 f
+1831(option.)X
+3 f
+576 2022([count])N
+841(#)X
+901(+|-|#)X
+1 f
+776 2112(Increment)N
+1135(or)X
+1235(decrement)X
+1603(the)X
+1734(current)X
+1996(number.)X
+2315(The)X
+2474(current)X
+2736(number)X
+3015(begins)X
+3258(at)X
+3350(the)X
+3482(\256rst)X
+3640(non-number)X
+776 2202(character)N
+1095(on)X
+1198(or)X
+1288(before)X
+1517(the)X
+1638(current)X
+1889(cursor)X
+2113(position,)X
+2413(or)X
+2503(the)X
+2624(beginning)X
+2967(of)X
+3057(the)X
+3178(line,)X
+3341(and)X
+3480(extends)X
+3748(up)X
+3850(to)X
+3934(the)X
+776 2292(\256rst)N
+920(non-number)X
+1332(character)X
+1649(on)X
+1750(or)X
+1838(after)X
+2007(the)X
+2126(current)X
+2375(cursor)X
+2597(position)X
+2875(or)X
+2963(the)X
+3082(end)X
+3219(of)X
+3307(the)X
+3426(line.)X
+3607(If)X
+3682(the)X
+3801(trailing)X
+776 2382(character)N
+1094(is)X
+1169(a)X
+7 f
+1227(+)X
+1 f
+(,)S
+1317(the)X
+1437(number)X
+1704(is)X
+1779(incremented)X
+2198(by)X
+7 f
+2300(count)X
+1 f
+(.)S
+2602(If)X
+2678(the)X
+2798(trailing)X
+3051(character)X
+3369(is)X
+3444(a)X
+7 f
+3502(-)X
+1 f
+(,)S
+3592(the)X
+3712(number)X
+3979(is)X
+776 2472(decremented)N
+1220(by)X
+7 f
+1333(count)X
+1 f
+(.)S
+1646(If)X
+1733(the)X
+1864(trailing)X
+2128(character)X
+2457(is)X
+2543(a)X
+7 f
+2612(#)X
+1 f
+(,)S
+2713(the)X
+2844(previous)X
+3154(increment)X
+3509(or)X
+3610(decrement)X
+3979(is)X
+776 2562(repeated.)N
+776 2742(The)N
+927(format)X
+1167(of)X
+1260(the)X
+1384(number)X
+1656(\(decimal,)X
+1984(hexadecimal,)X
+2437(and)X
+2580(octal,)X
+2783(and)X
+2926(leading)X
+3189(0's\))X
+3341(is)X
+3421(retained)X
+3707(unless)X
+3934(the)X
+776 2832(new)N
+930(value)X
+1124(cannot)X
+1358(be)X
+1454(represented)X
+1845(in)X
+1927(the)X
+2045(previous)X
+2341(format.)X
+776 3012(Line:)N
+1136(Unchanged.)X
+776 3102(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(character)X
+1918(in)X
+2000(the)X
+2118(cursor)X
+2339(word.)X
+776 3192(Options:)N
+1136(None.)X
+3 f
+576 3372([count])N
+841($)X
+1 f
+776 3462(Move)N
+989(the)X
+1113(cursor)X
+1340(to)X
+1428(the)X
+1552(end)X
+1694(of)X
+1787(a)X
+1849(line.)X
+2035(If)X
+7 f
+2115(count)X
+1 f
+2381(is)X
+2460(speci\256ed,)X
+2792(the)X
+2917(cursor)X
+3145(moves)X
+3381(down)X
+7 f
+3586(count)X
+3881(-)X
+3984(1)X
+1 f
+776 3552(lines.)N
+776 3732(It)N
+845(is)X
+918(not)X
+1040(an)X
+1136(error)X
+1313(to)X
+1395(use)X
+1522(the)X
+3 f
+1640($)X
+1 f
+1700(command)X
+2036(when)X
+2230(the)X
+2348(cursor)X
+2569(is)X
+2642(on)X
+2742(the)X
+2860(last)X
+2991(character)X
+3308(in)X
+3391(the)X
+3510(line)X
+3651(or)X
+3739(when)X
+3934(the)X
+776 3822(line)N
+916(is)X
+989(empty.)X
+776 4002(The)N
+3 f
+921($)X
+1 f
+981(command)X
+1317(may)X
+1475(be)X
+1571(used)X
+1739(as)X
+1827(the)X
+1946(motion)X
+2193(component)X
+2570(of)X
+2658(other)X
+3 f
+2844(vi)X
+1 f
+2927(commands,)X
+3315(in)X
+3398(which)X
+3615(case)X
+3775(any)X
+3912(text)X
+776 4092(copied)N
+1014(into)X
+1161(a)X
+1220(buffer)X
+1440(is)X
+1516(character)X
+1835(oriented,)X
+2141(unless)X
+2364(the)X
+2485(cursor)X
+2709(is)X
+2785(at,)X
+2886(or)X
+2976(before)X
+3205(the)X
+3326(\256rst)X
+3473(nonblank)X
+3794(charac-)X
+776 4182(ter)N
+885(in)X
+971(the)X
+1093(line,)X
+1257(in)X
+1343(which)X
+1563(case)X
+1726(it)X
+1794(is)X
+1871(line)X
+2015(oriented.)X
+2343(It)X
+2417(is)X
+2495(not)X
+2622(an)X
+2723(error)X
+2905(to)X
+2992(use)X
+3124(the)X
+3 f
+3247($)X
+1 f
+3312(command)X
+3653(as)X
+3745(a)X
+3806(motion)X
+776 4272(component)N
+1154(when)X
+1350(the)X
+1470(cursor)X
+1693(is)X
+1768(on)X
+1870(the)X
+1990(last)X
+2123(character)X
+2441(in)X
+2525(the)X
+2645(line,)X
+2807(although)X
+3109(it)X
+3175(is)X
+3249(an)X
+3346(error)X
+3524(when)X
+3719(the)X
+3838(line)X
+3979(is)X
+776 4362(empty.)N
+776 4542(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(current)X
+1706(line)X
+1846(plus)X
+7 f
+1999(count)X
+1 f
+2259(minus)X
+2474(1.)X
+776 4632(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(in)X
+1987(the)X
+2105(line.)X
+776 4722(Options:)N
+1136(None.)X
+3 f
+576 4902(%)N
+1 f
+776 4992(Move)N
+986(to)X
+1071(the)X
+1192(matching)X
+1513(character.)X
+1872(The)X
+2020(cursor)X
+2244(moves)X
+2477(to)X
+2563(the)X
+2685(parenthesis)X
+3070(or)X
+3161(curly)X
+3350(brace)X
+3549(which)X
+2 f
+3769(matches)X
+1 f
+776 5082(the)N
+900(parenthesis)X
+1287(or)X
+1380(curly)X
+1570(brace)X
+1770(found)X
+1982(at)X
+2065(the)X
+2188(current)X
+2441(cursor)X
+2667(position)X
+2949(or)X
+3041(which)X
+3262(is)X
+3340(the)X
+3463(closest)X
+3706(one)X
+3847(to)X
+3934(the)X
+776 5172(right)N
+964(of)X
+1068(the)X
+1203(cursor)X
+1441(on)X
+1558(the)X
+1693(line.)X
+1890(It)X
+1976(is)X
+2066(an)X
+2179(error)X
+2373(to)X
+2472(execute)X
+2756(the)X
+3 f
+2892(%)X
+1 f
+3010(command)X
+3364(on)X
+3482(a)X
+3556(line)X
+3714(without)X
+3996(a)X
+776 5262(parenthesis)N
+1157(or)X
+1244(curly)X
+1429(brace.)X
+1664(Historically,)X
+2082(any)X
+7 f
+2218(count)X
+1 f
+2478(speci\256ed)X
+2783(to)X
+2865(the)X
+3 f
+2983(%)X
+1 f
+3083(command)X
+3419(was)X
+3564(ignored.)X
+776 5442(The)N
+3 f
+921(%)X
+1 f
+1021(command)X
+1357(is)X
+1430(an)X
+1527(absolute)X
+1815(movement.)X
+2214(The)X
+3 f
+2360(%)X
+1 f
+2461(command)X
+2798(may)X
+2957(be)X
+3054(used)X
+3222(as)X
+3310(the)X
+3429(motion)X
+3676(component)X
+776 5532(of)N
+871(other)X
+3 f
+1064(vi)X
+1 f
+1153(commands,)X
+1547(in)X
+1636(which)X
+1859(case)X
+2025(any)X
+2168(text)X
+2315(copied)X
+2556(into)X
+2707(a)X
+2770(buffer)X
+2994(is)X
+3074(character)X
+3397(oriented,)X
+3707(unless)X
+3934(the)X
+776 5622(starting)N
+1036(point)X
+1220(of)X
+1307(the)X
+1425(region)X
+1650(is)X
+1723(at)X
+1801(or)X
+1888(before)X
+2115(the)X
+2234(\256rst)X
+2379(nonblank)X
+2698(character)X
+3015(on)X
+3116(its)X
+3212(line,)X
+3373(and)X
+3510(the)X
+3629(ending)X
+3868(point)X
+776 5712(is)N
+849(at)X
+927(or)X
+1014(after)X
+1182(the)X
+1300(last)X
+1431(nonblank)X
+1749(character)X
+2065(on)X
+2165(its)X
+2260(line,)X
+2420(in)X
+2502(which)X
+2718(case)X
+2877(it)X
+2941(is)X
+3014(line)X
+3154(oriented.)X
+
+17 p
+%%Page: 17 16
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-17)X
+1 f
+776 762(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(matching)X
+2392(character.)X
+776 852(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(matching)X
+1776(character.)X
+776 942(Options:)N
+1136(None.)X
+3 f
+576 1122(&)N
+1 f
+776 1212(Repeat)N
+1019(the)X
+1137(previous)X
+1433(substitution)X
+1825(command)X
+2161(on)X
+2261(the)X
+2379(current)X
+2627(line.)X
+776 1392(Historically,)N
+1194(any)X
+7 f
+1330(count)X
+1 f
+1590(speci\256ed)X
+1895(to)X
+1977(the)X
+3 f
+2095(&)X
+1 f
+2182(command)X
+2518(was)X
+2663(ignored.)X
+776 1572(Line:)N
+1136(Unchanged.)X
+776 1662(Column:)N
+1136(Unchanged)X
+1531(if)X
+1609(the)X
+1736(cursor)X
+1966(was)X
+2120(on)X
+2229(the)X
+2356(last)X
+2496(character)X
+2821(in)X
+2912(the)X
+3039(line,)X
+3208(otherwise,)X
+3569(set)X
+3688(to)X
+3780(the)X
+3908(\256rst)X
+1136 1752(nonblank)N
+1454(character)X
+1770(in)X
+1852(the)X
+1970(line.)X
+776 1842(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(edcompatible)X
+1 f
+2114(,)X
+3 f
+2154(extended)X
+1 f
+2461(,)X
+3 f
+2501(ignorecase)X
+1 f
+2882(and)X
+3 f
+3018(magic)X
+1 f
+3243(options.)X
+3 f
+576 2022 0.3182(\302<character>)AN
+576 2112 0.3182(`<character>)AN
+1 f
+776 2202(Return)N
+1014(to)X
+1096(a)X
+1152(context)X
+1408(marked)X
+1669(by)X
+1769(the)X
+1888(character)X
+7 f
+2205(<character>)X
+1 f
+(.)S
+2794(If)X
+7 f
+2869(<character>)X
+1 f
+3418(is)X
+3492(the)X
+3611(``)X
+7 f
+3665(')X
+1 f
+('')S
+3788(or)X
+3876(``)X
+7 f
+3930(`)X
+1 f
+('')S
+776 2292(character,)N
+1113(return)X
+1326(to)X
+1409(the)X
+1528(previous)X
+1825(context.)X
+2122(If)X
+7 f
+2197(<character>)X
+1 f
+2746(is)X
+2820(any)X
+2956(other)X
+3141(character,)X
+3477(return)X
+3689(to)X
+3771(the)X
+3889(con-)X
+776 2382(text)N
+921(marked)X
+1187(by)X
+1292(that)X
+1437(character)X
+1759(\(see)X
+1915(the)X
+3 f
+2039(m)X
+1 f
+2132(command)X
+2474(for)X
+2594(more)X
+2785(information\).)X
+3256(If)X
+3336(the)X
+3460(command)X
+3802(is)X
+3881(the)X
+3 f
+4005(\302)X
+1 f
+776 2472(command,)N
+1137(only)X
+1304(the)X
+1427(line)X
+1572(value)X
+1771(is)X
+1848(restored,)X
+2151(and)X
+2291(the)X
+2413(cursor)X
+2638(is)X
+2715(placed)X
+2949(on)X
+3053(the)X
+3175(\256rst)X
+3323(nonblank)X
+3645(character)X
+3965(of)X
+776 2562(that)N
+916(line.)X
+1096(If)X
+1170(the)X
+1288(command)X
+1624(is)X
+1697(the)X
+3 f
+1815(`)X
+1 f
+1862(command,)X
+2218(both)X
+2380(the)X
+2498(line)X
+2638(and)X
+2774(column)X
+3034(values)X
+3259(are)X
+3378(restored.)X
+776 2742(It)N
+849(is)X
+926(an)X
+1026(error)X
+1207(if)X
+1280(the)X
+1402(context)X
+1662(no)X
+1766(longer)X
+1995(exists)X
+2202(because)X
+2482(of)X
+2574(line)X
+2719(deletion.)X
+3042(\(Contexts)X
+3378(follow)X
+3612(lines)X
+3788(that)X
+3933(are)X
+776 2832(moved,)N
+1034(or)X
+1121(which)X
+1337(are)X
+1456(deleted)X
+1708(and)X
+1844(then)X
+2002(restored.\))X
+776 3012(The)N
+3 f
+924(\302)X
+1 f
+974(and)X
+3 f
+1113(`)X
+1 f
+1163(commands)X
+1533(are)X
+1655(both)X
+1820(absolute)X
+2110(movements.)X
+2542(They)X
+2730(may)X
+2891(be)X
+2990(used)X
+3160(as)X
+3250(a)X
+3309(motion)X
+3558(component)X
+3938(for)X
+776 3102(other)N
+3 f
+962(vi)X
+1 f
+1045(commands.)X
+1453(For)X
+1585(the)X
+3 f
+1704(\302)X
+1 f
+1752(command,)X
+2108(any)X
+2244(text)X
+2384(copied)X
+2618(into)X
+2762(a)X
+2818(buffer)X
+3035(is)X
+3108(line)X
+3248(oriented.)X
+3571(For)X
+3702(the)X
+3 f
+3820(`)X
+1 f
+3867(com-)X
+776 3192(mand,)N
+1002(any)X
+1146(text)X
+1294(copied)X
+1536(into)X
+1688(a)X
+1752(buffer)X
+1977(is)X
+2058(character)X
+2382(oriented,)X
+2693(unless)X
+2921(it)X
+2993(both)X
+3163(starts)X
+3360(and)X
+3504(stops)X
+3696(at)X
+3782(the)X
+3908(\256rst)X
+776 3282(character)N
+1099(in)X
+1188(the)X
+1313(line,)X
+1480(in)X
+1569(which)X
+1792(case)X
+1958(it)X
+2029(is)X
+2109(line)X
+2255(oriented.)X
+2584(In)X
+2677(addition,)X
+2985(when)X
+3185(using)X
+3384(the)X
+3 f
+3508(`)X
+1 f
+3561(command)X
+3903(as)X
+3996(a)X
+776 3372(motion)N
+1025(component,)X
+1424(commands)X
+1794(which)X
+2013(move)X
+2214(backward)X
+2550(and)X
+2689(started)X
+2926(at)X
+3007(the)X
+3128(\256rst)X
+3275(character)X
+3594(in)X
+3679(the)X
+3801(line,)X
+3965(or)X
+776 3462(move)N
+983(forward)X
+1267(and)X
+1412(ended)X
+1633(at)X
+1719(the)X
+1845(\256rst)X
+1997(character)X
+2321(in)X
+2411(the)X
+2537(line,)X
+2705(are)X
+2832(corrected)X
+3160(to)X
+3250(the)X
+3376(last)X
+3515(character)X
+3839(of)X
+3934(the)X
+776 3552(starting)N
+1036(and)X
+1172(ending)X
+1410(lines,)X
+1601(respectively.)X
+776 3732(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(from)X
+1774(the)X
+1892(context.)X
+776 3822(Column:)N
+1136(Set)X
+1261(to)X
+1346(the)X
+1467(\256rst)X
+1614(nonblank)X
+1935(character)X
+2254(in)X
+2340(the)X
+2462(line,)X
+2626(for)X
+2744(the)X
+3 f
+2866(\302)X
+1 f
+2917(command,)X
+3277(and)X
+3417(set)X
+3530(to)X
+3616(the)X
+3738(context's)X
+1136 3912(column)N
+1396(for)X
+1510(the)X
+3 f
+1628(`)X
+1 f
+1675(command.)X
+776 4002(Options:)N
+1136(None.)X
+3 f
+576 4182([count])N
+841(\()X
+1 f
+776 4272(Back)N
+961(up)X
+7 f
+1061(count)X
+1 f
+1321(sentences.)X
+776 4452(The)N
+3 f
+922(\()X
+1 f
+970(command)X
+1307(is)X
+1382(an)X
+1480(absolute)X
+1769(movement.)X
+2169(The)X
+3 f
+2316(\()X
+1 f
+2365(command)X
+2703(may)X
+2863(be)X
+2961(used)X
+3130(as)X
+3219(the)X
+3339(motion)X
+3587(component)X
+3965(of)X
+776 4542(other)N
+3 f
+963(vi)X
+1 f
+1047(commands,)X
+1436(in)X
+1520(which)X
+1738(case)X
+1899(any)X
+2036(text)X
+2177(copied)X
+2412(into)X
+2557(a)X
+2614(buffer)X
+2832(is)X
+2906(character)X
+3223(oriented,)X
+3527(unless)X
+3748(the)X
+3867(start-)X
+776 4632(ing)N
+913(and)X
+1064(stopping)X
+1374(points)X
+1604(of)X
+1706(the)X
+1839(region)X
+2079(are)X
+2213(the)X
+2346(\256rst)X
+2505(character)X
+2836(in)X
+2933(the)X
+3066(line,)X
+3241(in)X
+3338(which)X
+3569(case)X
+3743(it)X
+3823(is)X
+3912(line)X
+776 4722(oriented.)N
+1111(In)X
+1210(the)X
+1340(latter)X
+1537(case,)X
+1728(the)X
+1858(stopping)X
+2165(point)X
+2361(of)X
+2460(the)X
+2590(region)X
+2827(is)X
+2911(adjusted)X
+3209(to)X
+3302(be)X
+3409(the)X
+3538(end)X
+3685(of)X
+3783(the)X
+3912(line)X
+776 4812(immediately)N
+1196(before)X
+1422(it,)X
+1506(and)X
+1642(not)X
+1764(the)X
+1882(original)X
+2151(cursor)X
+2372(position.)X
+776 4992(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(beginning)X
+2414(of)X
+2501(the)X
+2619(sentence.)X
+776 5082(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2441(sentence.)X
+776 5172(Options:)N
+1136(None.)X
+3 f
+576 5352([count])N
+841(\))X
+1 f
+776 5442(Move)N
+983(forward)X
+7 f
+1258(count)X
+1 f
+1518(sentences.)X
+776 5622(The)N
+3 f
+922(\))X
+1 f
+970(command)X
+1307(is)X
+1382(an)X
+1480(absolute)X
+1769(movement.)X
+2169(The)X
+3 f
+2316(\))X
+1 f
+2365(command)X
+2703(may)X
+2863(be)X
+2961(used)X
+3130(as)X
+3219(the)X
+3339(motion)X
+3587(component)X
+3965(of)X
+776 5712(other)N
+3 f
+963(vi)X
+1 f
+1047(commands,)X
+1436(in)X
+1520(which)X
+1738(case)X
+1899(any)X
+2036(text)X
+2177(copied)X
+2412(into)X
+2557(a)X
+2614(buffer)X
+2832(is)X
+2906(character)X
+3223(oriented,)X
+3527(unless)X
+3748(the)X
+3867(start-)X
+776 5802(ing)N
+901(point)X
+1088(of)X
+1179(the)X
+1301(region)X
+1530(is)X
+1607(the)X
+1729(\256rst)X
+1877(character)X
+2197(in)X
+2283(the)X
+2405(line,)X
+2569(in)X
+2655(which)X
+2875(case)X
+3038(it)X
+3106(is)X
+3183(line)X
+3327(oriented.)X
+3654(In)X
+3745(the)X
+3867(latter)X
+
+18 p
+%%Page: 18 17
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-18)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+1 f
+776 762(case,)N
+961(if)X
+1036(the)X
+1160(stopping)X
+1461(point)X
+1651(of)X
+1744(the)X
+1868(region)X
+2099(is)X
+2178(also)X
+2333(the)X
+2457(\256rst)X
+2607(character)X
+2929(in)X
+3017(the)X
+3141(line,)X
+3307(it)X
+3376(is)X
+3454(adjusted)X
+3746(to)X
+3833(be)X
+3934(the)X
+776 852(end)N
+912(of)X
+999(the)X
+1117(line)X
+1257(immediately)X
+1677(before)X
+1903(it.)X
+776 1032(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(beginning)X
+2414(of)X
+2501(the)X
+2619(sentence.)X
+776 1122(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2441(sentence.)X
+776 1212(Options:)N
+1136(None.)X
+3 f
+576 1392([count])N
+841(,)X
+1 f
+776 1482(Reverse)N
+1055(\256nd)X
+1199(character)X
+7 f
+1515(count)X
+1 f
+1775(times.)X
+2008(Reverse)X
+2288(the)X
+2407(last)X
+3 f
+2539(F)X
+1 f
+2588(,)X
+3 f
+2629(f)X
+1 f
+2656(,)X
+3 f
+2697(T)X
+1 f
+2771(or)X
+3 f
+2859(t)X
+1 f
+2907(command,)X
+3264(searching)X
+3593(the)X
+3712(other)X
+3898(way)X
+776 1572(in)N
+858(the)X
+976(line,)X
+7 f
+1136(count)X
+1 f
+1396(times.)X
+776 1752(The)N
+3 f
+922(,)X
+1 f
+963(command)X
+1300(may)X
+1460(be)X
+1558(used)X
+1727(as)X
+1816(the)X
+1936(motion)X
+2184(component)X
+2562(of)X
+2651(other)X
+3 f
+2838(vi)X
+1 f
+2922(commands,)X
+3311(in)X
+3395(which)X
+3613(case)X
+3774(any)X
+3912(text)X
+776 1842(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 2022(Line:)N
+1136(Unchanged.)X
+776 2112(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458 0.3068(searched-for)AX
+1881(character.)X
+776 2202(Options:)N
+1136(None.)X
+3 f
+576 2382([count])N
+9 f
+841(-)X
+843(-)X
+1 f
+776 2472(Move)N
+983(to)X
+1065(\256rst)X
+1209(nonblank)X
+1527(of)X
+1614(the)X
+1732(previous)X
+2028(line,)X
+7 f
+2188(count)X
+1 f
+2448(times.)X
+776 2652(This)N
+938(is)X
+1011(an)X
+1107(error)X
+1284(if)X
+1353(the)X
+1471(movement)X
+1829(is)X
+1902(past)X
+2051(the)X
+2169(beginning)X
+2509(of)X
+2596(the)X
+2714(\256le.)X
+776 2832(The)N
+3 f
+922(-)X
+1 f
+970(command)X
+1307(may)X
+1466(be)X
+1563(used)X
+1731(as)X
+1819(the)X
+1938(motion)X
+2185(component)X
+2562(of)X
+2651(other)X
+3 f
+2838(vi)X
+1 f
+2922(commands,)X
+3311(in)X
+3395(which)X
+3613(case)X
+3774(any)X
+3912(text)X
+776 2922(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(line)X
+1640(oriented.)X
+776 3102(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(current)X
+1706(line)X
+1846(minus)X
+7 f
+2061(count)X
+1 f
+(.)S
+776 3192(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 3282(Options:)N
+1136(None.)X
+3 f
+576 3462([count])N
+841(.)X
+1 f
+776 3552(Repeat)N
+1031(the)X
+1161(last)X
+3 f
+1304(vi)X
+1 f
+1398(command)X
+1746(that)X
+1898(modi\256ed)X
+2214(text.)X
+2406(The)X
+2563(repeated)X
+2869(command)X
+3218(may)X
+3389(be)X
+3498(a)X
+3567(command)X
+3916(and)X
+776 3642(motion)N
+1030(component)X
+1413(combination.)X
+1880(If)X
+7 f
+1961(count)X
+1 f
+2228(is)X
+2308(speci\256ed,)X
+2640(it)X
+2711(replaces)X
+2 f
+3002(both)X
+1 f
+3171(the)X
+3296(count)X
+3501(speci\256ed)X
+3813(for)X
+3934(the)X
+776 3732(repeated)N
+1093(command,)X
+1473(and,)X
+1653(if)X
+1746(applicable,)X
+2140(for)X
+2278(the)X
+2420(repeated)X
+2737(motion)X
+3007(component.)X
+3448(If)X
+7 f
+3547(count)X
+1 f
+3832(is)X
+3930(not)X
+776 3822(speci\256ed,)N
+1101(the)X
+1219(counts)X
+1448(originally)X
+1779(speci\256ed)X
+2084(to)X
+2166(the)X
+2284(command)X
+2620(being)X
+2818(repeated)X
+3111(are)X
+3230(used)X
+3397(again.)X
+776 4002(As)N
+887(a)X
+945(special)X
+1190(case,)X
+1371(if)X
+1442(the)X
+3 f
+1562(.)X
+1 f
+1624(command)X
+1962(is)X
+2037(executed)X
+2345(immediately)X
+2767(after)X
+2937(the)X
+3 f
+3057(u)X
+1 f
+3123(command,)X
+3482(the)X
+3603(change)X
+3854(log)X
+3979(is)X
+776 4092(rolled)N
+983(forward)X
+1258(or)X
+1345(backward,)X
+1698(depending)X
+2052(on)X
+2152(the)X
+2270(action)X
+2486(of)X
+2573(the)X
+3 f
+2691(u)X
+1 f
+2755(command.)X
+776 4272(Line:)N
+1136(Set)X
+1258(as)X
+1345(described)X
+1673(for)X
+1787(the)X
+1905(repeated)X
+2198(command.)X
+776 4362(Column:)N
+1136(Set)X
+1258(as)X
+1345(described)X
+1673(for)X
+1787(the)X
+1905(repeated)X
+2198(command.)X
+776 4452(Options:)N
+1136(None.)X
+3 f
+576 4632 0.1776(/RE<carriage-return>)AN
+576 4722(/RE/)N
+751 0.2500([offset]<carriage-return>)AX
+576 4812 0.1908(?RE<carriage-return>)AN
+576 4902(?RE?)N
+787 0.2500([offset]<carriage-return>)AX
+576 4992(N)N
+576 5082(n)N
+1 f
+776 5172(Search)N
+1017(forward)X
+1295(or)X
+1385(backward)X
+1721(for)X
+1838(a)X
+1897(regular)X
+2148(expression.)X
+2554(The)X
+2702(commands)X
+3072(beginning)X
+3415(with)X
+3580(a)X
+3639(slash)X
+3822(\(``)X
+7 f
+3903(/)X
+1 f
+(''\))S
+776 5262(character)N
+1095(are)X
+1217(forward)X
+1495(searches,)X
+1811(the)X
+1932(commands)X
+2302(beginning)X
+2644(with)X
+2808(a)X
+2866(question)X
+3159(mark)X
+3346(\(``)X
+7 f
+3427(?)X
+1 f
+(''\))S
+3598(are)X
+3719(backward)X
+776 5352(searches.)N
+3 f
+1117(Vi)X
+1 f
+1225(prompts)X
+1515(with)X
+1685(the)X
+1811(leading)X
+2075(character)X
+2399(on)X
+2507(the)X
+2633(last)X
+2772(line)X
+2920(of)X
+3015(the)X
+3142(screen)X
+3377(for)X
+3500(a)X
+3565(string.)X
+3816(It)X
+3894(then)X
+776 5442(searches)N
+1071(forward)X
+1348(or)X
+1437(backward)X
+1772(in)X
+1856(the)X
+1976(\256le)X
+2100(for)X
+2216(the)X
+2336(next)X
+2496 0.3611(occurrence)AX
+2872(of)X
+2961(the)X
+3081(string,)X
+3305(which)X
+3522(is)X
+3596(interpreted)X
+3965(as)X
+776 5532(a)N
+832(Basic)X
+1030(Regular)X
+1304(Expression.)X
+776 5712(The)N
+3 f
+928(/)X
+1 f
+977(and)X
+3 f
+1120(?)X
+1 f
+1207(commands)X
+1581(are)X
+1707(absolute)X
+2001(movements.)X
+2437(They)X
+2630(may)X
+2796(be)X
+2900(used)X
+3075(as)X
+3170(the)X
+3296(motion)X
+3550(components)X
+3965(of)X
+776 5802(other)N
+3 f
+974(vi)X
+1 f
+1069(commands,)X
+1469(in)X
+1564(which)X
+1793(case)X
+1965(any)X
+2114(text)X
+2267(copied)X
+2514(into)X
+2671(a)X
+2740(buffer)X
+2970(is)X
+3056(character)X
+3385(oriented,)X
+3701(unless)X
+3934(the)X
+
+19 p
+%%Page: 19 18
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-19)X
+1 f
+776 762(search)N
+1007(started)X
+1246(and)X
+1387(ended)X
+1604(on)X
+1709(the)X
+1832(\256rst)X
+1981(column)X
+2246(of)X
+2338(a)X
+2399(line,)X
+2564(in)X
+2651(which)X
+2872(case)X
+3036(it)X
+3105(is)X
+3183(line)X
+3328(oriented.)X
+3657(In)X
+3750(addition,)X
+776 852(forward)N
+1056(searches)X
+1354(ending)X
+1597(at)X
+1680(the)X
+1803(\256rst)X
+1951(character)X
+2271(of)X
+2362(a)X
+2422(line,)X
+2586(and)X
+2726(backward)X
+3063(searches)X
+3360(beginning)X
+3704(at)X
+3786(the)X
+3908(\256rst)X
+776 942(character)N
+1098(in)X
+1186(the)X
+1310(line,)X
+1476(are)X
+1601(corrected)X
+1927(to)X
+2015(begin)X
+2219(or)X
+2312(end)X
+2454(at)X
+2538(the)X
+2662(last)X
+2799(character)X
+3121(of)X
+3214(the)X
+3339(previous)X
+3642(line.)X
+3829(\(Note,)X
+776 1032(forward)N
+1061(and)X
+1207(backward)X
+1550(searches)X
+1853(can)X
+1995(occur)X
+2204(for)X
+2328(both)X
+3 f
+2500(/)X
+1 f
+2552(and)X
+3 f
+2698(?)X
+1 f
+2787(commands,)X
+3183(if)X
+3261(the)X
+3 f
+3388(wrapscan)X
+1 f
+3746(option)X
+3979(is)X
+776 1122(set.\))N
+776 1302(If)N
+852(an)X
+950(offset)X
+1155(from)X
+1333(the)X
+1453(matched)X
+1747(line)X
+1889(is)X
+1964(speci\256ed)X
+2271(\(i.e.)X
+2418(a)X
+2476(trailing)X
+2729(``)X
+7 f
+2783(/)X
+1 f
+('')S
+2907(or)X
+2996(``)X
+7 f
+3050(?)X
+1 f
+('')S
+3194(character)X
+3512(is)X
+3587(followed)X
+3894(by)X
+3996(a)X
+776 1392(signed)N
+1009(offset\),)X
+1263(the)X
+1385(buffer)X
+1606(will)X
+1754(always)X
+2001(be)X
+2100(line)X
+2243(oriented)X
+2529(\(e.g.)X
+2715(``)X
+7 f
+2769(/string/+0)X
+1 f
+('')S
+3326(will)X
+3473(always)X
+3719(guarantee)X
+776 1482(a)N
+832(line)X
+972(orientation\).)X
+776 1662(The)N
+3 f
+921(n)X
+1 f
+985(command)X
+1321(repeats)X
+1569(the)X
+1687(previous)X
+1983(search.)X
+776 1842(The)N
+3 f
+921(N)X
+1 f
+999(command)X
+1335(repeats)X
+1583(the)X
+1701(previous)X
+1997(search,)X
+2243(but)X
+2365(in)X
+2447(the)X
+2565(reverse)X
+2818(direction.)X
+776 2022(Missing)N
+1194(RE's)X
+1515(\(e.g.)X
+1839(``)X
+7 f
+1893(//<carriage-return>)X
+1 f
+('',)S
+3040(``)X
+7 f
+3094(/<carriage-return>)X
+1 f
+('',)S
+776 2112(``)N
+7 f
+830(??<carriage-return>)X
+1 f
+('',)S
+1847(or)X
+1945(``)X
+7 f
+1999(?<carriage-return>)X
+1 f
+('')S
+2948(search)X
+3185(for)X
+3310(the)X
+3439(last)X
+3581(search)X
+3818(RE,)X
+3970(in)X
+776 2202(the)N
+894(indicated)X
+1208(direction.)X
+776 2382(Searches)N
+1082(may)X
+1240(be)X
+1336(interrupted)X
+1708(using)X
+1901(the)X
+7 f
+2019(<interrupt>)X
+1 f
+2567(character.)X
+776 2562(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(in)X
+1680(which)X
+1896(the)X
+2014(match)X
+2230(occurred.)X
+776 2652(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(character)X
+1918(of)X
+2005(the)X
+2123(matched)X
+2415(string.)X
+776 2742(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(edcompatible)X
+1 f
+2114(,)X
+3 f
+2154(extended)X
+1 f
+2461(,)X
+3 f
+2501(ignorecase)X
+1 f
+2862(,)X
+3 f
+2902(magic)X
+1 f
+3107(,)X
+3147(and)X
+3 f
+3283(wrapscan)X
+1 f
+3632(options.)X
+3 f
+576 2922(0)N
+1 f
+776 3012(Move)N
+985(to)X
+1069(the)X
+1189(\256rst)X
+1335(character)X
+1654(in)X
+1739(the)X
+1860(current)X
+2111(line.)X
+2294(It)X
+2366(is)X
+2442(not)X
+2567(an)X
+2666(error)X
+2846(to)X
+2931(use)X
+3061(the)X
+3 f
+3182(0)X
+1 f
+3245(command)X
+3584(when)X
+3781(the)X
+3902(cur-)X
+776 3102(sor)N
+894(is)X
+967(on)X
+1067(the)X
+1185(\256rst)X
+1329(character)X
+1645(in)X
+1727(the)X
+1845(line,)X
+776 3282(The)N
+3 f
+923(0)X
+1 f
+986(command)X
+1325(may)X
+1486(be)X
+1585(used)X
+1755(as)X
+1845(the)X
+1966(motion)X
+2215(component)X
+2594(of)X
+2684(other)X
+3 f
+2872(vi)X
+1 f
+2957(commands,)X
+3347(in)X
+3432(which)X
+3651(case)X
+3813(it)X
+3880(is)X
+3956(an)X
+776 3372(error)N
+953(if)X
+1022(the)X
+1140(cursor)X
+1361(is)X
+1434(on)X
+1534(the)X
+1652(\256rst)X
+1796(character)X
+2112(in)X
+2194(the)X
+2312(line.)X
+776 3552(Line:)N
+1136(Unchanged.)X
+776 3642(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(character)X
+1918(in)X
+2000(the)X
+2118(line.)X
+776 3732(Options:)N
+1136(None.)X
+3 f
+576 3912(:)N
+1 f
+776 4002(Execute)N
+1055(an)X
+1152(ex)X
+1249(command.)X
+3 f
+1626(Vi)X
+1 f
+1727(prompts)X
+2010(for)X
+2125(an)X
+3 f
+2222(ex)X
+1 f
+2319(command)X
+2656(on)X
+2757(the)X
+2876(last)X
+3008(line)X
+3149(of)X
+3237(the)X
+3356(screen,)X
+3603(using)X
+3797(a)X
+3854(colon)X
+776 4092(\(``)N
+7 f
+857(:)X
+1 f
+(''\))S
+1029(character.)X
+1408(The)X
+1575(command)X
+1933(is)X
+2028(terminated)X
+2413(by)X
+2535(a)X
+7 f
+2613(<carriage-return>)X
+1 f
+(,)S
+7 f
+3491(<newline>)X
+1 f
+3965(or)X
+7 f
+776 4182(<escape>)N
+1 f
+1184(character;)X
+1526(all)X
+1630(of)X
+1721(these)X
+1910(characters)X
+2261(may)X
+2423(be)X
+2523(escaped)X
+2802(by)X
+2906(using)X
+3103(a)X
+7 f
+3164(<literal)X
+3601(next>)X
+1 f
+3866(char-)X
+776 4272(acter.)N
+993(The)X
+1138(command)X
+1474(is)X
+1547(then)X
+1705(executed.)X
+776 4452(If)N
+850(the)X
+3 f
+968(ex)X
+1 f
+1064(command)X
+1400(writes)X
+1616(to)X
+1698(the)X
+1816(screen,)X
+3 f
+2063(vi)X
+1 f
+2146(will)X
+2291(prompt)X
+2543(the)X
+2662(user)X
+2817(for)X
+2932(a)X
+7 f
+2989(<carriage-return>)X
+1 f
+3826(before)X
+776 4542(continuing)N
+1144(when)X
+1344(the)X
+3 f
+1468(ex)X
+1 f
+1570(command)X
+1912(\256nishes.)X
+2222(Large)X
+2436(amounts)X
+2733(of)X
+2826(output)X
+3056(from)X
+3238(the)X
+3 f
+3362(ex)X
+1 f
+3464(command)X
+3806(will)X
+3956(be)X
+776 4632(paged)N
+994(for)X
+1114(the)X
+1238(user,)X
+1418(and)X
+1560(the)X
+1684(user)X
+1844(prompted)X
+2177(for)X
+2297(a)X
+7 f
+2359(<carriage-return>)X
+1 f
+3201(or)X
+7 f
+3294(<space>)X
+1 f
+3657(key)X
+3800(to)X
+3889(con-)X
+776 4722(tinue.)N
+999(In)X
+1089(some)X
+1281(cases,)X
+1494(a)X
+1553(quit)X
+1700(\(normally)X
+2039(a)X
+2098(``q'')X
+2269 0.3750(character\))AX
+2615(or)X
+7 f
+2705(<interrupt>)X
+1 f
+3256(may)X
+3417(be)X
+3515(entered)X
+3774(to)X
+3858(inter-)X
+776 4812(rupt)N
+925(the)X
+3 f
+1043(ex)X
+1 f
+1139(command.)X
+776 4992(When)N
+988(the)X
+3 f
+1106(ex)X
+1 f
+1202(command)X
+1538(\256nishes,)X
+1822(and)X
+1958(the)X
+2076(user)X
+2230(is)X
+2303(prompted)X
+2631(to)X
+2714(resume)X
+2967(visual)X
+3179(mode,)X
+3398(it)X
+3463(is)X
+3537(also)X
+3687(possible)X
+3970(to)X
+776 5082(enter)N
+957(another)X
+1218(``)X
+7 f
+1272(:)X
+1 f
+('')S
+1394(character)X
+1710(followed)X
+2015(by)X
+2115(another)X
+3 f
+2376(ex)X
+1 f
+2472(command.)X
+776 5262(Line:)N
+1136(The)X
+1281(current)X
+1529(line)X
+1669(is)X
+1742(set)X
+1851(as)X
+1938(described)X
+2266(for)X
+2380(the)X
+3 f
+2498(ex)X
+1 f
+2594(command.)X
+776 5352(Column:)N
+1136(The)X
+1281(current)X
+1529(column)X
+1789(is)X
+1862(set)X
+1971(as)X
+2058(described)X
+2386(for)X
+2500(the)X
+3 f
+2618(ex)X
+1 f
+2714(command.)X
+776 5442(Options:)N
+1136(None.)X
+3 f
+576 5622([count])N
+841(;)X
+1 f
+776 5712(Repeat)N
+1025(the)X
+1149(last)X
+1286(character)X
+1608(\256nd)X
+7 f
+1758(count)X
+1 f
+2024(times.)X
+2263(The)X
+2415(last)X
+2553(character)X
+2876(\256nd)X
+3027(is)X
+3107(one)X
+3250(of)X
+3344(the)X
+3 f
+3469(F)X
+1 f
+3518(,)X
+3 f
+3565(f)X
+1 f
+3592(,)X
+3 f
+3639(T)X
+1 f
+3719(or)X
+3 f
+3813(t)X
+1 f
+3867(com-)X
+776 5802(mands.)N
+
+20 p
+%%Page: 20 19
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-20)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+1 f
+776 762(The)N
+3 f
+922(;)X
+1 f
+970(command)X
+1307(may)X
+1466(be)X
+1563(used)X
+1731(as)X
+1819(the)X
+1938(motion)X
+2185(component)X
+2562(of)X
+2651(other)X
+3 f
+2838(vi)X
+1 f
+2922(commands,)X
+3311(in)X
+3395(which)X
+3613(case)X
+3774(any)X
+3912(text)X
+776 852(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 1032(Line:)N
+1136(Unchanged.)X
+776 1122(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458 0.3068(searched-for)AX
+1881(character.)X
+776 1212(Options:)N
+1136(None.)X
+3 f
+576 1392([count])N
+841(<)X
+907(motion)X
+576 1482([count])N
+841(>)X
+907(motion)X
+1 f
+776 1572(Shift)N
+956(lines)X
+1132(left)X
+1264(or)X
+1357(right.)X
+1574(Shift)X
+1755(the)X
+1879(number)X
+2150(of)X
+2243(lines)X
+2420(in)X
+2508(the)X
+2632(region)X
+2863(speci\256ed)X
+3174(by)X
+3280(the)X
+3404(motion)X
+3656(component,)X
+776 1662(times)N
+7 f
+980(count)X
+1 f
+(,)S
+1271(left)X
+1409(\(for)X
+1561(the)X
+3 f
+1690(<)X
+1 f
+1767(command\))X
+2141(or)X
+2239(right)X
+2421(\(for)X
+2573(the)X
+3 f
+2702(>)X
+1 f
+2778(command\))X
+3151(by)X
+3261(the)X
+3389(number)X
+3664(of)X
+3761(columns)X
+776 1752(speci\256ed)N
+1086(by)X
+1191(the)X
+3 f
+1314(shiftwidth)X
+1 f
+1685(option.)X
+1954(Only)X
+2139(whitespace)X
+2521(characters)X
+2873(are)X
+2997(deleted)X
+3255(when)X
+3455(shifting)X
+3725(left;)X
+3880(once)X
+776 1842(the)N
+901(\256rst)X
+1052(character)X
+1375(in)X
+1464(the)X
+1589(line)X
+1736(contains)X
+2030(a)X
+2092(nonblank)X
+2416(character,)X
+2758(the)X
+3 f
+2882(shift)X
+1 f
+3059(will)X
+3209(succeed,)X
+3510(but)X
+3638(the)X
+3762(line)X
+3908(will)X
+776 1932(not)N
+898(be)X
+994(modi\256ed.)X
+776 2112(Line:)N
+1136(Unchanged.)X
+776 2202(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 2292(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(shiftwidth)X
+1 f
+2022(option.)X
+3 f
+576 2472(@)N
+670(buffer)X
+1 f
+776 2562(Execute)N
+1065(a)X
+1131(named)X
+1375(buffer.)X
+1642(Execute)X
+1931(the)X
+2059(named)X
+2303(buffer)X
+2530(as)X
+3 f
+2627(vi)X
+1 f
+2719(commands.)X
+3136(The)X
+3292(buffer)X
+3520(may)X
+3689(include)X
+3 f
+3956(ex)X
+1 f
+776 2652(commands,)N
+1170(too,)X
+1319(but)X
+1448(they)X
+1613(must)X
+1795(be)X
+1898(expressed)X
+2241(as)X
+2334(a)X
+3 f
+2396(:)X
+1 f
+2449(command.)X
+2831(If)X
+2911(the)X
+3035(buffer)X
+3258(is)X
+3337(line)X
+3483(oriented,)X
+7 f
+3792(<new-)X
+776 2742(line>)N
+1 f
+1054(characters)X
+1419(are)X
+1556(logically)X
+1874(appended)X
+2220(to)X
+2320(each)X
+2506(line)X
+2664(of)X
+2769(the)X
+2905(buffer.)X
+3180(If)X
+3272(the)X
+3408(buffer)X
+3644(is)X
+3736(character)X
+776 2832(oriented,)N
+7 f
+1079(<newline>)X
+1 f
+1531(characters)X
+1878(are)X
+1997(logically)X
+2297(appended)X
+2625(to)X
+2707(all)X
+2807(but)X
+2929(the)X
+3047(last)X
+3178(line)X
+3318(in)X
+3400(the)X
+3518(buffer.)X
+776 3012(If)N
+861(the)X
+990(buffer)X
+1218(name)X
+1423(is)X
+1507(``)X
+7 f
+1561(@)X
+1 f
+('',)S
+1714(or)X
+1812(``)X
+7 f
+1866(*)X
+1 f
+('',)S
+2019(then)X
+2188(the)X
+2317(last)X
+2459(buffer)X
+2687(executed)X
+3004(shall)X
+3186(be)X
+3293(used.)X
+3511(It)X
+3591(is)X
+3675(an)X
+3782(error)X
+3970(to)X
+776 3102(specify)N
+1033(``)X
+7 f
+1087(@@)X
+1 f
+('')S
+1262(or)X
+1354(``)X
+7 f
+1408(**)X
+1 f
+('')S
+1583(if)X
+1657(there)X
+1843(were)X
+2025(no)X
+2130(buffer)X
+2351(previous)X
+2651(executions.)X
+3058(The)X
+3207(text)X
+3351(of)X
+3442(a)X
+3502(macro)X
+3727(may)X
+3889(con-)X
+776 3192(tain)N
+919(an)X
+3 f
+1019(@)X
+1 f
+1117(command,)X
+1477(and)X
+1617(it)X
+1685(is)X
+1762(possible)X
+2048(to)X
+2134(create)X
+2351(in\256nite)X
+2601(loops)X
+2798(in)X
+2884(this)X
+3023(manner.)X
+3328(\(The)X
+7 f
+3504(<interrupt>)X
+1 f
+776 3282(character)N
+1092(may)X
+1250(be)X
+1346(used)X
+1513(to)X
+1595(interrupt)X
+1891(the)X
+2009(loop.\))X
+776 3462(Line:)N
+1136(The)X
+1281(current)X
+1529(line)X
+1669(is)X
+1742(set)X
+1851(as)X
+1938(described)X
+2266(for)X
+2380(the)X
+2498(command\(s\).)X
+776 3552(Column:)N
+1136(The)X
+1281(current)X
+1529(column)X
+1789(is)X
+1862(set)X
+1971(as)X
+2058(described)X
+2386(for)X
+2500(the)X
+2618(command\(s\).)X
+776 3642(Options:)N
+1136(None.)X
+3 f
+576 3822([count])N
+841(A)X
+1 f
+776 3912(Enter)N
+981(input)X
+1176(mode,)X
+1405(appending)X
+1770(the)X
+1899(text)X
+2050(after)X
+2229(the)X
+2358(end)X
+2505(of)X
+2603(the)X
+2732(line.)X
+2923(If)X
+7 f
+3008(count)X
+1 f
+3279(is)X
+3363(speci\256ed,)X
+3699(the)X
+3828(text)X
+3979(is)X
+776 4002(repeatedly)N
+1131(input)X
+7 f
+1315(count)X
+1603(-)X
+1699(1)X
+1 f
+1767(more)X
+1952(times)X
+2145(after)X
+2313(input)X
+2497(mode)X
+2695(is)X
+2768(exited.)X
+776 4182(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 4272(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 4362(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 4452(gin)N
+1 f
+1262(options.)X
+3 f
+576 4632([count])N
+841(B)X
+1 f
+776 4722(Move)N
+995(backward)X
+7 f
+1340(count)X
+1 f
+1612(bigwords.)X
+1982(Move)X
+2201(the)X
+2331(cursor)X
+2564(backward)X
+2909(to)X
+3003(the)X
+3133(beginning)X
+3485(of)X
+3584(a)X
+3652(bigword)X
+3952(by)X
+776 4812(repeating)N
+1096(the)X
+1215(following)X
+1547(algorithm:)X
+1901(if)X
+1971(the)X
+2090(current)X
+2339(position)X
+2617(is)X
+2691(at)X
+2770(the)X
+2889(beginning)X
+3230(of)X
+3318(a)X
+3374(bigword)X
+3661(or)X
+3748(the)X
+3866(char-)X
+776 4902(acter)N
+955(at)X
+1036(the)X
+1157(current)X
+1408(position)X
+1688(cannot)X
+1925(be)X
+2024(part)X
+2172(of)X
+2262(a)X
+2321(bigword,)X
+2631(move)X
+2832(to)X
+2917(the)X
+3038(\256rst)X
+3185(character)X
+3504(of)X
+3594(the)X
+3715(preceding)X
+776 4992(bigword.)N
+1105(Otherwise,)X
+1477(move)X
+1677(to)X
+1761(the)X
+1881(\256rst)X
+2027(character)X
+2345(of)X
+2434(the)X
+2554(bigword)X
+2843(at)X
+2923(the)X
+3043(current)X
+3293(position.)X
+3612(If)X
+3688(no)X
+3790(preced-)X
+776 5082(ing)N
+908(bigword)X
+1205(exists)X
+1418(on)X
+1529(the)X
+1658(current)X
+1917(line,)X
+2088(move)X
+2297(to)X
+2390(the)X
+2519(\256rst)X
+2674(character)X
+3001(of)X
+3099(the)X
+3228(last)X
+3370(bigword)X
+3668(on)X
+3779(the)X
+3908(\256rst)X
+776 5172(preceding)N
+1113(line)X
+1253(that)X
+1393(contains)X
+1680(a)X
+1736(bigword.)X
+776 5352(The)N
+3 f
+921(B)X
+1 f
+994(command)X
+1330(may)X
+1488(be)X
+1584(used)X
+1751(as)X
+1838(the)X
+1956(motion)X
+2202(component)X
+2578(of)X
+2665(other)X
+3 f
+2850(vi)X
+1 f
+2932(commands,)X
+3319(in)X
+3401(which)X
+3617(case)X
+3776(any)X
+3912(text)X
+776 5442(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 5622(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(word)X
+2259(selected.)X
+776 5712(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(character)X
+1918(of)X
+2005(the)X
+2123(word)X
+2308(selected.)X
+
+21 p
+%%Page: 21 20
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-21)X
+1 f
+776 762(Options:)N
+1136(None.)X
+3 f
+576 942([buffer])N
+864([count])X
+1129(C)X
+1 f
+776 1032(Change)N
+1058(text)X
+1215(from)X
+1408(the)X
+1543(current)X
+1808(position)X
+2102(to)X
+2201(the)X
+2336(end-of-line.)X
+2770(If)X
+7 f
+2862(count)X
+1 f
+3140(is)X
+3231(speci\256ed,)X
+3574(the)X
+3710(input)X
+3912(text)X
+776 1122(replaces)N
+1060(from)X
+1236(the)X
+1354(current)X
+1602(position)X
+1879(to)X
+1961(the)X
+2079(end-of-line,)X
+2476(plus)X
+7 f
+2629(count)X
+2917(-)X
+3013(1)X
+1 f
+3081(subsequent)X
+3457(lines.)X
+776 1302(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 1392(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 1482(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 1572(gin)N
+1 f
+1262(options.)X
+3 f
+576 1752([buffer])N
+864(D)X
+1 f
+776 1842(Delete)N
+1006(text)X
+1146(from)X
+1322(the)X
+1440(current)X
+1688(position)X
+1965(to)X
+2047(the)X
+2165(end-of-line.)X
+776 2022(It)N
+845(is)X
+918(not)X
+1040(an)X
+1136(error)X
+1313(to)X
+1395(execute)X
+1661(the)X
+3 f
+1779(D)X
+1 f
+1857(command)X
+2193(on)X
+2293(an)X
+2389(empty)X
+2609(line.)X
+776 2202(Line:)N
+1136(Unchanged.)X
+776 2292(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(character)X
+1774(before)X
+2000(the)X
+2118(current)X
+2367(character,)X
+2704(or,)X
+2812(column)X
+3073(1)X
+3134(if)X
+3204(the)X
+3323(cursor)X
+3545(was)X
+3691(on)X
+3792(column)X
+1136 2382(1.)N
+776 2472(Options:)N
+1136(None.)X
+3 f
+576 2652([count])N
+841(E)X
+1 f
+776 2742(Move)N
+983(forward)X
+7 f
+1258(count)X
+1 f
+1518(end-of-bigwords.)X
+2113(Move)X
+2320(the)X
+2438(cursor)X
+2659(forward)X
+2935(to)X
+3018(the)X
+3137(end)X
+3274(of)X
+3362(a)X
+3419(bigword)X
+3707(by)X
+3808(repeat-)X
+776 2832(ing)N
+906(the)X
+1032(following)X
+1371(algorithm:)X
+1732(if)X
+1809(the)X
+1935(current)X
+2191(position)X
+2476(is)X
+2557(the)X
+2683(end)X
+2827(of)X
+2922(a)X
+2986(bigword)X
+3281(or)X
+3376(the)X
+3502(character)X
+3826(at)X
+3912(that)X
+776 2922(position)N
+1061(cannot)X
+1303(be)X
+1407(part)X
+1560(of)X
+1655(a)X
+1719(bigword,)X
+2034(move)X
+2240(to)X
+2331(the)X
+2458(last)X
+2598(character)X
+2923(of)X
+3019(the)X
+3146(following)X
+3486(bigword.)X
+3822(Other-)X
+776 3012(wise,)N
+973(move)X
+1181(to)X
+1273(the)X
+1401(last)X
+1542(character)X
+1868(of)X
+1965(the)X
+2093(bigword)X
+2390(at)X
+2477(the)X
+2604(current)X
+2861(position.)X
+3187(If)X
+3270(no)X
+3379(succeeding)X
+3765(bigword)X
+776 3102(exists)N
+984(on)X
+1090(the)X
+1214(current)X
+1468(line,)X
+1634(move)X
+1838(to)X
+1927(the)X
+2052(last)X
+2190(character)X
+2513(of)X
+2607(the)X
+2732(\256rst)X
+2883(bigword)X
+3177(on)X
+3284(the)X
+3409(next)X
+3574(following)X
+3912(line)X
+776 3192(that)N
+916(contains)X
+1203(a)X
+1259(bigword.)X
+776 3372(The)N
+3 f
+921(E)X
+1 f
+994(command)X
+1330(may)X
+1488(be)X
+1584(used)X
+1751(as)X
+1838(the)X
+1956(motion)X
+2202(component)X
+2578(of)X
+2665(other)X
+3 f
+2850(vi)X
+1 f
+2932(commands,)X
+3319(in)X
+3401(which)X
+3617(case)X
+3776(any)X
+3912(text)X
+776 3462(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 3642(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(word)X
+2259(selected.)X
+776 3732(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(of)X
+1992(the)X
+2110(word)X
+2295(selected.)X
+776 3822(Options:)N
+1136(None.)X
+3 f
+576 4002([count])N
+841(F)X
+910 0.3125(<character>)AX
+1 f
+776 4092(Search)N
+7 f
+1015(count)X
+1 f
+1275(times)X
+1468(backward)X
+1801(through)X
+2070(the)X
+2188(current)X
+2436(line)X
+2576(for)X
+7 f
+2690(<character>)X
+1 f
+(.)S
+776 4272(The)N
+3 f
+921(F)X
+1 f
+990(command)X
+1326(may)X
+1484(be)X
+1580(used)X
+1747(as)X
+1834(the)X
+1952(motion)X
+2198(component)X
+2574(of)X
+2661(other)X
+3 f
+2846(vi)X
+1 f
+2928(commands,)X
+3315(in)X
+3398(which)X
+3615(case)X
+3775(any)X
+3912(text)X
+776 4362(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 4542(Line:)N
+1136(Unchanged.)X
+776 4632(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458 0.3068(searched-for)AX
+1881(character.)X
+776 4722(Options:)N
+1136(None.)X
+3 f
+576 4902([count])N
+841(G)X
+1 f
+776 4992(Move)N
+983(to)X
+1065(line)X
+7 f
+1205(count)X
+1 f
+(,)S
+1485(or)X
+1572(the)X
+1690(last)X
+1821(line)X
+1961(of)X
+2048(the)X
+2166(\256le)X
+2288(if)X
+7 f
+2357(count)X
+1 f
+2617(not)X
+2739(speci\256ed.)X
+776 5172(The)N
+3 f
+924(G)X
+1 f
+1009(command)X
+1348(is)X
+1424(an)X
+1523(absolute)X
+1813(movement.)X
+2214(The)X
+3 f
+2362(G)X
+1 f
+2447(command)X
+2786(may)X
+2947(be)X
+3046(used)X
+3216(as)X
+3306(the)X
+3427(motion)X
+3676(component)X
+776 5262(of)N
+863(other)X
+3 f
+1048(vi)X
+1 f
+1130(commands,)X
+1517(in)X
+1599(which)X
+1815(case)X
+1974(any)X
+2110(text)X
+2250(copied)X
+2484(into)X
+2628(a)X
+2684(buffer)X
+2901(is)X
+2974(line)X
+3114(oriented.)X
+776 5442(Line:)N
+1136(Set)X
+1258(to)X
+7 f
+1340(count)X
+1 f
+(,)S
+1620(if)X
+1689(speci\256ed,)X
+2014(otherwise,)X
+2366(the)X
+2484(last)X
+2615(line.)X
+776 5532(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 5622(Options:)N
+1136(None.)X
+
+22 p
+%%Page: 22 21
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-22)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+576 762([count])N
+841(H)X
+1 f
+776 852(Move)N
+983(to)X
+1065(the)X
+1183(screen)X
+1409(line)X
+7 f
+1549(count)X
+1837(-)X
+1933(1)X
+1 f
+2001(lines)X
+2172(below)X
+2388(the)X
+2506(top)X
+2628(of)X
+2715(the)X
+2833(screen.)X
+776 1032(The)N
+3 f
+924(H)X
+1 f
+1009(command)X
+1348(is)X
+1424(an)X
+1523(absolute)X
+1813(movement.)X
+2214(The)X
+3 f
+2362(H)X
+1 f
+2447(command)X
+2786(may)X
+2947(be)X
+3046(used)X
+3216(as)X
+3306(the)X
+3427(motion)X
+3676(component)X
+776 1122(of)N
+863(other)X
+3 f
+1048(vi)X
+1 f
+1130(commands,)X
+1517(in)X
+1599(which)X
+1815(case)X
+1974(any)X
+2110(text)X
+2250(copied)X
+2484(into)X
+2628(a)X
+2684(buffer)X
+2901(is)X
+2974(line)X
+3114(oriented.)X
+776 1302(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+7 f
+1598(count)X
+1886(-)X
+1982(1)X
+1 f
+2050(lines)X
+2221(below)X
+2437(the)X
+2555(top)X
+2677(of)X
+2764(the)X
+2882(screen.)X
+776 1392(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2 f
+2441(screen)X
+1 f
+2671(line.)X
+776 1482(Options:)N
+1136(None.)X
+3 f
+576 1662([count])N
+841(I)X
+1 f
+776 1752(Enter)N
+971(input)X
+1156(mode,)X
+1375(inserting)X
+1676(the)X
+1795(text)X
+1936(at)X
+2015(the)X
+2134(beginning)X
+2475(of)X
+2564(the)X
+2684(line.)X
+2866(If)X
+7 f
+2942(count)X
+1 f
+3204(is)X
+3279(speci\256ed,)X
+3606(the)X
+3726(text)X
+3868(input)X
+776 1842(is)N
+849(repeatedly)X
+1204(input)X
+7 f
+1388(count)X
+1676(-)X
+1772(1)X
+1 f
+1840(more)X
+2025(times.)X
+776 2022(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 2112(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 2202(Options:)N
+1136(None.)X
+3 f
+576 2382([count])N
+841(J)X
+1 f
+776 2472(Join)N
+929(lines.)X
+1140(If)X
+7 f
+1214(count)X
+1 f
+1474(is)X
+1547(speci\256ed,)X
+7 f
+1872(count)X
+1 f
+2132(lines)X
+2303(are)X
+2422(joined;)X
+2664(a)X
+2720(minimum)X
+3050(of)X
+3137(two)X
+3277(lines)X
+3448(are)X
+3568(always)X
+3812(joined,)X
+776 2562(regardless)N
+1122(of)X
+1209(the)X
+1327(value)X
+1521(of)X
+7 f
+1608(count)X
+1 f
+(.)S
+776 2742(If)N
+859(the)X
+986(current)X
+1244(line)X
+1394(ends)X
+1571(with)X
+1743(a)X
+1809(whitespace)X
+2196(character,)X
+2542(all)X
+2652(whitespace)X
+3039(is)X
+3122(stripped)X
+3410(from)X
+3596(the)X
+3724(next)X
+3892(line.)X
+776 2832(Otherwise,)N
+1148(if)X
+1219(the)X
+1338(next)X
+1497(line)X
+1638(starts)X
+1828(with)X
+1991(a)X
+2048(open)X
+2225(parenthesis)X
+2607(\(``)X
+7 f
+2688(\()X
+1 f
+(''\))S
+2838(do)X
+2939(nothing.)X
+3244(Otherwise,)X
+3615(if)X
+3685(the)X
+3804(current)X
+776 2922(line)N
+917(ends)X
+1086(with)X
+1250(a)X
+1308(question)X
+1601(mark)X
+1788(\(``)X
+7 f
+1869(?)X
+1 f
+(''\),)S
+2040(period)X
+2267(\(``)X
+7 f
+2348(.)X
+1 f
+(''\))S
+2519(or)X
+2608(exclamation)X
+3022(point)X
+3208(\(``)X
+7 f
+3289(!)X
+1 f
+(''\),)S
+3460(insert)X
+3660(two)X
+3802(spaces.)X
+776 3012(Otherwise,)N
+1146(insert)X
+1344(a)X
+1400(single)X
+1611(space.)X
+776 3192(It)N
+845(is)X
+918(not)X
+1040(an)X
+1136(error)X
+1313(to)X
+1395(join)X
+1539(lines)X
+1710(past)X
+1859(the)X
+1977(end)X
+2113(of)X
+2200(the)X
+2318(\256le,)X
+2460(i.e.)X
+2578(lines)X
+2749(that)X
+2889(do)X
+2989(not)X
+3111(exist.)X
+776 3372(Line:)N
+1136(Unchanged.)X
+776 3462(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(character)X
+1774(after)X
+1942(the)X
+2060(last)X
+2191(character)X
+2507(of)X
+2594(the)X
+2712(next-to-last)X
+3097(joined)X
+3317(line.)X
+776 3552(Options:)N
+1136(None.)X
+3 f
+576 3732([count])N
+841(L)X
+1 f
+776 3822(Move)N
+983(to)X
+1065(the)X
+1183(screen)X
+1409(line)X
+7 f
+1549(count)X
+1837(-)X
+1933(1)X
+1 f
+2001(lines)X
+2172(above)X
+2384(the)X
+2502(bottom)X
+2748(of)X
+2835(the)X
+2953(screen.)X
+776 4002(The)N
+3 f
+925(L)X
+1 f
+1002(command)X
+1342(is)X
+1419(an)X
+1519(absolute)X
+1810(movement.)X
+2212(The)X
+3 f
+2361(L)X
+1 f
+2438(command)X
+2778(may)X
+2940(be)X
+3040(used)X
+3211(as)X
+3302(the)X
+3425(motion)X
+3676(component)X
+776 4092(of)N
+863(other)X
+3 f
+1048(vi)X
+1 f
+1130(commands,)X
+1517(in)X
+1599(which)X
+1815(case)X
+1974(any)X
+2110(text)X
+2250(copied)X
+2484(into)X
+2628(a)X
+2684(buffer)X
+2901(is)X
+2974(line)X
+3114(oriented.)X
+776 4272(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+7 f
+1598(count)X
+1886(-)X
+1982(1)X
+1 f
+2050(lines)X
+2221(above)X
+2433(the)X
+2551(bottom)X
+2797(of)X
+2884(the)X
+3002(screen.)X
+776 4362(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2 f
+2441(screen)X
+1 f
+2671(line.)X
+776 4452(Options:)N
+1136(None.)X
+3 f
+596 4632(M)N
+1 f
+776 4722(Move)N
+983(to)X
+1065(the)X
+1183(screen)X
+1409(line)X
+1549(in)X
+1631(the)X
+1749(middle)X
+1991(of)X
+2078(the)X
+2196(screen.)X
+776 4902(The)N
+3 f
+922(M)X
+1 f
+1019(command)X
+1356(is)X
+1430(an)X
+1527(absolute)X
+1815(movement.)X
+2214(The)X
+3 f
+2360(M)X
+1 f
+2457(command)X
+2794(may)X
+2953(be)X
+3050(used)X
+3219(as)X
+3308(the)X
+3428(motion)X
+3676(component)X
+776 4992(of)N
+863(other)X
+3 f
+1048(vi)X
+1 f
+1130(commands,)X
+1517(in)X
+1599(which)X
+1815(case)X
+1974(any)X
+2110(text)X
+2250(copied)X
+2484(into)X
+2628(a)X
+2684(buffer)X
+2901(is)X
+2974(line)X
+3114(oriented.)X
+776 5172(Historically,)N
+1194(any)X
+7 f
+1330(count)X
+1 f
+1590(speci\256ed)X
+1895(to)X
+1977(the)X
+3 f
+2095(M)X
+1 f
+2191(command)X
+2527(was)X
+2672(ignored.)X
+776 5352(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(in)X
+1680(the)X
+1798(middle)X
+2040(of)X
+2127(the)X
+2245(screen.)X
+776 5442(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2 f
+2441(screen)X
+1 f
+2671(line.)X
+776 5532(Options:)N
+1136(None.)X
+3 f
+576 5712([count])N
+841(O)X
+1 f
+776 5802(Enter)N
+970(input)X
+1154(mode,)X
+1372(appending)X
+1726(text)X
+1866(in)X
+1948(a)X
+2004(new)X
+2158(line)X
+2298(above)X
+2510(the)X
+2628(current)X
+2876(line.)X
+3057(If)X
+7 f
+3132(count)X
+1 f
+3393(is)X
+3467(speci\256ed,)X
+3793(the)X
+3912(text)X
+
+23 p
+%%Page: 23 22
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-23)X
+1 f
+776 762(input)N
+960(is)X
+1033(repeatedly)X
+1388(input)X
+7 f
+1572(count)X
+1860(-)X
+1956(1)X
+1 f
+2024(more)X
+2209(times.)X
+776 942(Historically,)N
+1194(any)X
+7 f
+1330(count)X
+1 f
+1590(speci\256ed)X
+1895(to)X
+1977(the)X
+3 f
+2095(O)X
+1 f
+2177(command)X
+2513(was)X
+2658(ignored.)X
+776 1122(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 1212(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 1302(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 1392(gin)N
+1 f
+1262(options.)X
+3 f
+576 1572([buffer])N
+864(P)X
+1 f
+776 1662(Insert)N
+980(text)X
+1121(from)X
+1298(a)X
+1355(buffer.)X
+1613(Text)X
+1782(from)X
+1960(the)X
+2080(buffer)X
+2299(\(the)X
+2446(unnamed)X
+2762(buffer)X
+2981(by)X
+3083(default\))X
+3355(is)X
+3430(inserted)X
+3706(before)X
+3934(the)X
+776 1752(current)N
+1024(column)X
+1284(or,)X
+1391(if)X
+1460(the)X
+1578(buffer)X
+1795(is)X
+1868(line)X
+2008(oriented,)X
+2311(before)X
+2537(the)X
+2655(current)X
+2903(line.)X
+776 1932(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(lowest)X
+1687(numbered)X
+2028(line)X
+2168(insert,)X
+2386(if)X
+2455(the)X
+2573(buffer)X
+2790(is)X
+2863(line)X
+3003(oriented,)X
+3306(otherwise)X
+3638(unchanged.)X
+776 2022(Column:)N
+1136(Set)X
+1261(to)X
+1346(the)X
+1467(\256rst)X
+1614(nonblank)X
+1935(character)X
+2254(of)X
+2344(the)X
+2465(appended)X
+2796(text,)X
+2959(if)X
+3032(the)X
+3154(buffer)X
+3375(is)X
+3452(line)X
+3596(oriented,)X
+3903(oth-)X
+1136 2112(erwise,)N
+1386(the)X
+1504(last)X
+1635(character)X
+1951(of)X
+2038(the)X
+2156(appended)X
+2484(text.)X
+776 2202(Options:)N
+1136(None.)X
+3 f
+576 2382(Q)N
+1 f
+776 2472(Exit)N
+3 f
+929(vi)X
+1 f
+1011(\(or)X
+1125(visual\))X
+1363(mode)X
+1561(and)X
+1697(switch)X
+1926(to)X
+3 f
+2008(ex)X
+1 f
+2104(mode.)X
+776 2652(Line:)N
+1136(Unchanged.)X
+776 2742(Column:)N
+1136(No)X
+1254(longer)X
+1479(relevant.)X
+776 2832(Options:)N
+1136(None.)X
+3 f
+576 3012([count])N
+841(R)X
+1 f
+776 3102(Enter)N
+971(input)X
+1156(mode,)X
+1375(replacing)X
+1695(the)X
+1814(characters)X
+2162(in)X
+2245(the)X
+2364(current)X
+2613(line.)X
+2794(If)X
+7 f
+2869(count)X
+1 f
+3130(is)X
+3204(speci\256ed,)X
+3531(the)X
+3651(text)X
+3793(input)X
+3979(is)X
+776 3192(repeatedly)N
+1131(input)X
+7 f
+1315(count)X
+1603(-)X
+1699(1)X
+1 f
+1767(more)X
+1952(times.)X
+776 3372(If)N
+855(the)X
+978(end)X
+1119(of)X
+1211(the)X
+1334(current)X
+1587(line)X
+1732(is)X
+1810(reached,)X
+2106(no)X
+2211(more)X
+2401(characters)X
+2753(are)X
+2877(replaced)X
+3176(and)X
+3318(any)X
+3460(further)X
+3705(characters)X
+776 3462(input)N
+960(are)X
+1079(appended)X
+1407(to)X
+1489(the)X
+1607(line.)X
+776 3642(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 3732(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 3822(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 3912(gin)N
+1 f
+1262(options.)X
+3 f
+576 4092([buffer])N
+864([count])X
+1129(S)X
+1 f
+776 4182(Substitute)N
+7 f
+1115(count)X
+1 f
+1375(lines.)X
+776 4362(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 4452(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 4542(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 4632(gin)N
+1 f
+1262(options.)X
+3 f
+576 4812([count])N
+841(T)X
+914 0.3125(<character>)AX
+1 f
+776 4902(Search)N
+1014(backward,)X
+7 f
+1366(count)X
+1 f
+1625(times,)X
+1837(through)X
+2105(the)X
+2222(current)X
+2469(line)X
+2608(for)X
+2721(the)X
+2838(character)X
+2 f
+3153(after)X
+1 f
+3323(the)X
+3440(speci\256ed)X
+7 f
+3744(<char-)X
+776 4992(acter>)N
+1 f
+(.)S
+776 5172(The)N
+3 f
+921(T)X
+1 f
+994(command)X
+1330(may)X
+1488(be)X
+1584(used)X
+1751(as)X
+1838(the)X
+1956(motion)X
+2202(component)X
+2578(of)X
+2665(other)X
+3 f
+2850(vi)X
+1 f
+2932(commands,)X
+3319(in)X
+3401(which)X
+3617(case)X
+3776(any)X
+3912(text)X
+776 5262(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 5442(Line:)N
+1136(Unchanged.)X
+776 5532(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(character)X
+2 f
+1774(after)X
+1 f
+1945(the)X
+2063 0.3068(searched-for)AX
+2486(character.)X
+776 5622(Options:)N
+1136(None.)X
+
+24 p
+%%Page: 24 23
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-24)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+576 762(U)N
+1 f
+776 852(Restore)N
+1041(the)X
+1159(current)X
+1407(line)X
+1547(to)X
+1629(its)X
+1724(state)X
+1891(before)X
+2117(the)X
+2235(cursor)X
+2456(last)X
+2587(moved)X
+2825(to)X
+2907(it.)X
+776 1032(Line:)N
+1136(Unchanged.)X
+776 1122(Column:)N
+1136(The)X
+1281(\256rst)X
+1425(character)X
+1741(in)X
+1823(the)X
+1941(line.)X
+776 1212(Options:)N
+1136(None.)X
+3 f
+576 1392([count])N
+841(W)X
+1 f
+776 1482(Move)N
+985(forward)X
+7 f
+1262(count)X
+1 f
+1524(bigwords.)X
+1884(Move)X
+2094(the)X
+2215(cursor)X
+2439(forward)X
+2717(to)X
+2802(the)X
+2923(beginning)X
+3266(of)X
+3356(a)X
+3415(bigword)X
+3705(by)X
+3808(repeat-)X
+776 1572(ing)N
+903(the)X
+1026(following)X
+1362(algorithm:)X
+1720(if)X
+1794(the)X
+1917(current)X
+2170(position)X
+2452(is)X
+2530(within)X
+2759(a)X
+2820(bigword)X
+3112(or)X
+3204(the)X
+3326(character)X
+3646(at)X
+3728(that)X
+3872(posi-)X
+776 1662(tion)N
+926(cannot)X
+1166(be)X
+1268(part)X
+1419(of)X
+1512(a)X
+1574(bigword,)X
+1887(move)X
+2091(to)X
+2179(the)X
+2303(\256rst)X
+2453(character)X
+2775(of)X
+2868(the)X
+2992(next)X
+3156(bigword.)X
+3489(If)X
+3569(no)X
+3676(subsequent)X
+776 1752(bigword)N
+1066(exists)X
+1271(on)X
+1374(the)X
+1495(current)X
+1746(line,)X
+1909(move)X
+2110(to)X
+2195(the)X
+2316(\256rst)X
+2463(character)X
+2782(of)X
+2872(the)X
+2993(\256rst)X
+3139(bigword)X
+3428(on)X
+3530(the)X
+3650(\256rst)X
+3796(follow-)X
+776 1842(ing)N
+898(line)X
+1038(that)X
+1178(contains)X
+1465(a)X
+1521(bigword.)X
+776 2022(The)N
+3 f
+927(W)X
+1 f
+1033(command)X
+1375(may)X
+1539(be)X
+1641(used)X
+1814(as)X
+1908(the)X
+2033(motion)X
+2286(component)X
+2669(of)X
+2763(other)X
+3 f
+2955(vi)X
+1 f
+3044(commands,)X
+3438(in)X
+3527(which)X
+3750(case)X
+3916(any)X
+776 2112(text)N
+916(copied)X
+1150(into)X
+1294(a)X
+1350(buffer)X
+1567(is)X
+1640(character)X
+1956(oriented.)X
+776 2292(Line:)N
+1136(The)X
+1281(line)X
+1421(containing)X
+1779(the)X
+1897(word)X
+2082(selected.)X
+776 2382(Column:)N
+1136(The)X
+1281(\256rst)X
+1425(character)X
+1741(of)X
+1828(the)X
+1946(word)X
+2131(selected.)X
+776 2472(Options:)N
+1136(None.)X
+3 f
+576 2652([buffer])N
+864([count])X
+1129(X)X
+1 f
+776 2742(Delete)N
+7 f
+1008(count)X
+1 f
+1270(characters)X
+1619(before)X
+1847(the)X
+1967(cursor.)X
+2230(If)X
+2306(the)X
+2426(number)X
+2693(of)X
+2782(characters)X
+3132(to)X
+3217(be)X
+3316(deleted)X
+3571(is)X
+3647(greater)X
+3894(than)X
+776 2832(or)N
+874(equal)X
+1079(to)X
+1172(the)X
+1301(number)X
+1577(of)X
+1675(characters)X
+2033(to)X
+2126(the)X
+2255(beginning)X
+2606(of)X
+2704(the)X
+2833(line,)X
+3004(all)X
+3115(of)X
+3213(the)X
+3341(characters)X
+3698(before)X
+3934(the)X
+776 2922(current)N
+1024(cursor)X
+1245(position,)X
+1542(to)X
+1624(the)X
+1742(beginning)X
+2082(of)X
+2169(the)X
+2287(line,)X
+2447(are)X
+2566(deleted.)X
+776 3102(Line:)N
+1136(Unchanged.)X
+776 3192(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(current)X
+1706(character)X
+2022(minus)X
+7 f
+2237(count)X
+1 f
+(,)S
+2518(or)X
+2606(the)X
+2725(\256rst)X
+2870(character)X
+3187(if)X
+3257(count)X
+3456(is)X
+3530(greater)X
+3775(than)X
+3934(the)X
+1136 3282(number)N
+1401(of)X
+1488(characters)X
+1835(in)X
+1917(the)X
+2035(line)X
+2175(before)X
+2401(the)X
+2519(cursor.)X
+776 3372(Options:)N
+1136(None.)X
+3 f
+576 3552([buffer])N
+864([count])X
+1129(Y)X
+1 f
+776 3642(Copy)N
+969(\(or)X
+1083(``yank''\))X
+7 f
+1394(count)X
+1 f
+1654(lines)X
+1825(into)X
+1969(the)X
+2087(speci\256ed)X
+2392(buffer.)X
+776 3822(Line:)N
+1136(Unchanged.)X
+776 3912(Column:)N
+1136(Unchanged.)X
+776 4002(Options:)N
+1136(None.)X
+3 f
+576 4182(ZZ)N
+1 f
+776 4272(Write)N
+979(the)X
+1097(\256le)X
+1219(and)X
+1356(exit)X
+3 f
+1497(vi)X
+1 f
+1559(.)X
+1620(The)X
+1766(\256le)X
+1889(is)X
+1963(only)X
+2126(written)X
+2374(if)X
+2444(it)X
+2509(has)X
+2637(been)X
+2810(modi\256ed)X
+3115(since)X
+3301(the)X
+3420(last)X
+3552(complete)X
+3867(write)X
+776 4362(of)N
+863(the)X
+981(\256le)X
+1103(to)X
+1185(any)X
+1321(\256le.)X
+776 4542(The)N
+3 f
+922(ZZ)X
+1 f
+1050(command)X
+1388(will)X
+1534(exit)X
+1676(the)X
+1796(editor)X
+2005(after)X
+2175(writing)X
+2428(the)X
+2548(\256le,)X
+2692(if)X
+2763(there)X
+2946(are)X
+3067(no)X
+3169(further)X
+3410(\256les)X
+3565(to)X
+3649(edit.)X
+3831(Enter-)X
+776 4632(ing)N
+901(two)X
+1044(``quit'')X
+1299(commands)X
+1669(\(i.e.)X
+3 f
+1837(wq)X
+1 f
+1939(,)X
+3 f
+1981(quit)X
+1 f
+2118(,)X
+3 f
+2160(xit)X
+1 f
+2271(or)X
+3 f
+2360(ZZ)X
+1 f
+2466(\))X
+2515(in)X
+2599(a)X
+2657(row)X
+2804(will)X
+2950(override)X
+3240(this)X
+3377(check)X
+3587(and)X
+3725(the)X
+3845(editor)X
+776 4722(will)N
+920(exit,)X
+1080(ignoring)X
+1371(any)X
+1507(\256les)X
+1660(that)X
+1800(have)X
+1972(not)X
+2094(yet)X
+2212(been)X
+2384(edited.)X
+776 4902(Line:)N
+1136(Unchanged.)X
+776 4992(Column:)N
+1136(Unchanged.)X
+776 5082(Options:)N
+1136(None.)X
+3 f
+576 5262([count])N
+841([[)X
+1 f
+776 5352(Back)N
+961(up)X
+7 f
+1061(count)X
+1 f
+1321(section)X
+1568(boundaries.)X
+776 5532(The)N
+3 f
+925([[)X
+1 f
+1003(command)X
+1343(is)X
+1420(an)X
+1520(absolute)X
+1811(movement.)X
+2213(The)X
+3 f
+2362([[)X
+1 f
+2440(command)X
+2780(may)X
+2942(be)X
+3042(used)X
+3213(as)X
+3304(the)X
+3426(motion)X
+3676(component)X
+776 5622(of)N
+871(other)X
+3 f
+1064(vi)X
+1 f
+1153(commands,)X
+1547(in)X
+1636(which)X
+1859(case)X
+2025(any)X
+2168(text)X
+2315(copied)X
+2556(into)X
+2707(a)X
+2770(buffer)X
+2994(is)X
+3074(character)X
+3397(oriented,)X
+3707(unless)X
+3934(the)X
+776 5712(starting)N
+1036(position)X
+1313(is)X
+1386(column)X
+1646(0,)X
+1726(in)X
+1808(which)X
+2024(case)X
+2183(it)X
+2247(is)X
+2320(line)X
+2460(oriented.)X
+
+25 p
+%%Page: 25 24
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-25)X
+1 f
+776 762(This)N
+938(is)X
+1011(an)X
+1107(error)X
+1284(if)X
+1353(the)X
+1471(movement)X
+1829(is)X
+1902(past)X
+2051(the)X
+2169(beginning)X
+2509(of)X
+2596(the)X
+2714(\256le.)X
+776 942(Line:)N
+1136(Set)X
+1261(to)X
+1346(the)X
+1467(previous)X
+1766(line)X
+1909(that)X
+2052(is)X
+7 f
+2128(count)X
+1 f
+2391(section)X
+2641(boundaries)X
+3016(back,)X
+3212(or)X
+3303(the)X
+3425(\256rst)X
+3573(line)X
+3717(of)X
+3808(the)X
+3930(\256le)X
+1136 1032(if)N
+1205(no)X
+1305(more)X
+1490(section)X
+1737(boundaries)X
+2109(exist)X
+2280(preceding)X
+2617(the)X
+2735(current)X
+2983(line.)X
+776 1122(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 1212(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(sections)X
+1 f
+1943(option.)X
+3 f
+576 1392([count])N
+841(]])X
+1 f
+776 1482(Move)N
+983(forward)X
+7 f
+1258(count)X
+1 f
+1518(section)X
+1765(boundaries.)X
+776 1662(The)N
+3 f
+925(]])X
+1 f
+1003(command)X
+1343(is)X
+1420(an)X
+1520(absolute)X
+1811(movement.)X
+2213(The)X
+3 f
+2362(]])X
+1 f
+2440(command)X
+2780(may)X
+2942(be)X
+3042(used)X
+3213(as)X
+3304(the)X
+3426(motion)X
+3676(component)X
+776 1752(of)N
+871(other)X
+3 f
+1064(vi)X
+1 f
+1153(commands,)X
+1547(in)X
+1636(which)X
+1859(case)X
+2025(any)X
+2168(text)X
+2315(copied)X
+2556(into)X
+2707(a)X
+2770(buffer)X
+2994(is)X
+3074(character)X
+3397(oriented,)X
+3707(unless)X
+3934(the)X
+776 1842(starting)N
+1036(position)X
+1313(is)X
+1386(column)X
+1646(0,)X
+1726(in)X
+1808(which)X
+2024(case)X
+2183(it)X
+2247(is)X
+2320(line)X
+2460(oriented.)X
+776 2022(This)N
+938(is)X
+1011(an)X
+1107(error)X
+1284(if)X
+1353(the)X
+1471(movement)X
+1829(is)X
+1902(past)X
+2051(the)X
+2169(end)X
+2305(of)X
+2392(the)X
+2510(\256le.)X
+776 2202(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(that)X
+1738(is)X
+7 f
+1811(count)X
+1 f
+2072(section)X
+2320(boundaries)X
+2693(forward,)X
+2989(or)X
+3077(to)X
+3160(the)X
+3279(last)X
+3411(line)X
+3552(of)X
+3640(the)X
+3759(\256le)X
+3882(if)X
+3952(no)X
+1136 2292(more)N
+1321(section)X
+1568(boundaries)X
+1940(exist)X
+2111(following)X
+2442(the)X
+2560(current)X
+2808(line.)X
+776 2382(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 2472(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(sections)X
+1 f
+1943(option.)X
+3 f
+576 2652(\303)N
+1 f
+776 2742(Move)N
+983(to)X
+1065(\256rst)X
+1209(nonblank)X
+1527(character)X
+1843(on)X
+1943(the)X
+2061(current)X
+2309(line.)X
+776 2922(The)N
+3 f
+922(\303)X
+1 f
+970(command)X
+1307(may)X
+1466(be)X
+1563(used)X
+1731(as)X
+1819(the)X
+1938(motion)X
+2185(component)X
+2562(of)X
+2651(other)X
+3 f
+2838(vi)X
+1 f
+2922(commands,)X
+3311(in)X
+3395(which)X
+3613(case)X
+3774(any)X
+3912(text)X
+776 3012(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 3192(Line:)N
+1136(Unchanged.)X
+776 3282(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(of)X
+2323(the)X
+2441(current)X
+2689(line.)X
+776 3372(Options:)N
+1136(None.)X
+3 f
+576 3552([count])N
+841(_)X
+1 f
+776 3642(Move)N
+985(down)X
+7 f
+1185(count)X
+1475(-)X
+1573(1)X
+1 f
+1643(lines,)X
+1836(to)X
+1920(the)X
+2040(\256rst)X
+2186(nonblank)X
+2506(character.)X
+2864(The)X
+3 f
+3012(_)X
+1 f
+3075(command)X
+3414(may)X
+3575(be)X
+3674(used)X
+3844(as)X
+3934(the)X
+776 3732(motion)N
+1022(component)X
+1398(of)X
+1485(other)X
+3 f
+1670(vi)X
+1 f
+1752(commands,)X
+2139(in)X
+2221(which)X
+2437(case)X
+2596(any)X
+2732(text)X
+2872(copied)X
+3106(into)X
+3250(a)X
+3306(buffer)X
+3523(is)X
+3596(line)X
+3736(oriented.)X
+776 3912(It)N
+845(is)X
+918(not)X
+1040(an)X
+1136(error)X
+1313(to)X
+1395(execute)X
+1661(the)X
+3 f
+1779(_)X
+1 f
+1839(command)X
+2175(when)X
+2369(the)X
+2487(cursor)X
+2708(is)X
+2781(on)X
+2881(the)X
+2999(\256rst)X
+3143(character)X
+3459(in)X
+3541(the)X
+3659(line.)X
+776 4092(Line:)N
+1136(The)X
+1281(current)X
+1529(line)X
+1669(plus)X
+7 f
+1822(count)X
+2110(-)X
+2206(1)X
+1 f
+(.)S
+776 4182(Column:)N
+1136(The)X
+1281(\256rst)X
+1425(nonblank)X
+1743(character)X
+2059(in)X
+2141(the)X
+2259(line.)X
+776 4272(Options:)N
+1136(None.)X
+3 f
+576 4452([count])N
+841(a)X
+1 f
+776 4542(Enter)N
+971(input)X
+1156(mode,)X
+1375(appending)X
+1730(the)X
+1850(text)X
+1992(after)X
+2162(the)X
+2282(cursor.)X
+2545(If)X
+7 f
+2621(count)X
+1 f
+2883(is)X
+2958(speci\256ed,)X
+3285(the)X
+3405(text)X
+3547(input)X
+3733(is)X
+3808(repeat-)X
+776 4632(edly)N
+934(input)X
+7 f
+1118(count)X
+1406(-)X
+1502(1)X
+1 f
+1570(more)X
+1755(times.)X
+776 4812(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 4902(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 4992(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 5082(gin)N
+1 f
+1262(options.)X
+3 f
+576 5262([count])N
+841(b)X
+1 f
+776 5352(Move)N
+986(backward)X
+7 f
+1322(count)X
+1 f
+1585(words.)X
+1844(Move)X
+2054(the)X
+2175(cursor)X
+2400(backward)X
+2737(to)X
+2823(the)X
+2945(beginning)X
+3289(of)X
+3380(a)X
+3440(word)X
+3629(by)X
+3733(repeating)X
+776 5442(the)N
+895(following)X
+1227(algorithm:)X
+1581(if)X
+1651(the)X
+1770(current)X
+2018(position)X
+2295(is)X
+2368(at)X
+2446(the)X
+2564(beginning)X
+2904(of)X
+2991(a)X
+3047(word,)X
+3252(move)X
+3450(to)X
+3532(the)X
+3650(\256rst)X
+3794(charac-)X
+776 5532(ter)N
+883(of)X
+972(the)X
+1092(preceding)X
+1431(word.)X
+1658(Otherwise,)X
+2030(the)X
+2150(current)X
+2400(position)X
+2679(moves)X
+2910(to)X
+2994(the)X
+3114(\256rst)X
+3260(character)X
+3578(of)X
+3667(the)X
+3787(word)X
+3974(at)X
+776 5622(the)N
+895(current)X
+1144(position.)X
+1462(If)X
+1537(no)X
+1638(preceding)X
+1976(word)X
+2161(exists)X
+2363(on)X
+2463(the)X
+2581(current)X
+2829(line,)X
+2989(move)X
+3187(to)X
+3269(the)X
+3387(\256rst)X
+3531(character)X
+3847(of)X
+3934(the)X
+776 5712(last)N
+907(word)X
+1092(on)X
+1192(the)X
+1310(\256rst)X
+1454(preceding)X
+1791(line)X
+1931(that)X
+2071(contains)X
+2358(a)X
+2414(word.)X
+
+26 p
+%%Page: 26 25
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-26)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+1 f
+776 762(The)N
+3 f
+921(b)X
+1 f
+985(command)X
+1321(may)X
+1479(be)X
+1575(used)X
+1742(as)X
+1829(the)X
+1947(motion)X
+2193(component)X
+2570(of)X
+2658(other)X
+3 f
+2844(vi)X
+1 f
+2927(commands,)X
+3315(in)X
+3398(which)X
+3615(case)X
+3775(any)X
+3912(text)X
+776 852(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 1032(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(word)X
+2259(selected.)X
+776 1122(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(character)X
+1918(of)X
+2005(the)X
+2123(word)X
+2308(selected.)X
+776 1212(Options:)N
+1136(None.)X
+3 f
+576 1392([buffer])N
+864([count])X
+1129(c)X
+1185(motion)X
+1 f
+776 1482(Change)N
+1041(a)X
+1097(region)X
+1322(of)X
+1409(text.)X
+1589(If)X
+1663(only)X
+1825(part)X
+1970(of)X
+2057(a)X
+2113(single)X
+2324(line)X
+2464(is)X
+2537(affected,)X
+2838(then)X
+2997(the)X
+3116(last)X
+3248(character)X
+3565(being)X
+3764(changed)X
+776 1572(is)N
+849(marked)X
+1110(with)X
+1272(a)X
+1328(``)X
+7 f
+1382($)X
+1 f
+(''.)S
+1544(Otherwise,)X
+1914(the)X
+2032(region)X
+2257(of)X
+2344(text)X
+2484(is)X
+2557(deleted,)X
+2829(and)X
+2965(input)X
+3149(mode)X
+3347(is)X
+3420(entered.)X
+776 1752(If)N
+7 f
+850(count)X
+1 f
+1110(is)X
+1183(speci\256ed,)X
+1508(it)X
+1572(is)X
+1645(applied)X
+1901(to)X
+1983(the)X
+7 f
+2101(motion)X
+1 f
+(.)S
+776 1932(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 2022(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 2112(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 2202(gin)N
+1 f
+1262(options.)X
+3 f
+576 2382([buffer])N
+864([count])X
+1129(d)X
+1193(motion)X
+1 f
+776 2472(Delete)N
+1006(a)X
+1062(region)X
+1287(of)X
+1374(text.)X
+1554(If)X
+7 f
+1628(count)X
+1 f
+1888(is)X
+1961(speci\256ed,)X
+2286(it)X
+2350(is)X
+2423(applied)X
+2679(to)X
+2761(the)X
+7 f
+2879(motion)X
+1 f
+(.)S
+776 2652(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(where)X
+1815(the)X
+1933(region)X
+2158(starts.)X
+776 2742(Column:)N
+1136(Set)X
+1261(to)X
+1346(the)X
+1467(\256rst)X
+1615(character)X
+1935(in)X
+2021(the)X
+2143(line)X
+2287(after)X
+2459(the)X
+2581(last)X
+2716(character)X
+3036(in)X
+3122(the)X
+3244(region.)X
+3513(If)X
+3591(no)X
+3695(such)X
+3866(char-)X
+1136 2832(acter)N
+1313(exists,)X
+1535(set)X
+1644(to)X
+1726(the)X
+1844(last)X
+1975(character)X
+2291(before)X
+2517(the)X
+2635(region.)X
+776 2922(Options:)N
+1136(None.)X
+3 f
+576 3102([count])N
+841(e)X
+1 f
+776 3192(Move)N
+984(forward)X
+7 f
+1260(count)X
+1 f
+1521(end-of-words.)X
+2015(Move)X
+2223(the)X
+2342(cursor)X
+2564(forward)X
+2840(to)X
+2923(the)X
+3042(end)X
+3179(of)X
+3267(a)X
+3324(word)X
+3511(by)X
+3613(repeating)X
+3934(the)X
+776 3282(following)N
+1108(algorithm:)X
+1462(if)X
+1532(the)X
+1651(current)X
+1900(position)X
+2178(is)X
+2252(the)X
+2371(end)X
+2508(of)X
+2596(a)X
+2653(word,)X
+2859(move)X
+3058(to)X
+3141(the)X
+3260(last)X
+3392(character)X
+3709(of)X
+3797(the)X
+3916(fol-)X
+776 3372(lowing)N
+1034(word.)X
+1275(Otherwise,)X
+1661(move)X
+1876(to)X
+1975(the)X
+2110(last)X
+2258(character)X
+2591(of)X
+2695(the)X
+2830(word)X
+3032(at)X
+3127(the)X
+3262(current)X
+3527(position.)X
+3861(If)X
+3952(no)X
+776 3462(succeeding)N
+1161(word)X
+1354(exists)X
+1564(on)X
+1672(the)X
+1798(current)X
+2053(line,)X
+2220(move)X
+2425(to)X
+2514(the)X
+2639(last)X
+2777(character)X
+3100(of)X
+3194(the)X
+3319(\256rst)X
+3470(word)X
+3662(on)X
+3769(the)X
+3894(next)X
+776 3552(following)N
+1107(line)X
+1247(that)X
+1387(contains)X
+1674(a)X
+1730(word.)X
+776 3732(The)N
+3 f
+921(e)X
+1 f
+978(command)X
+1315(may)X
+1474(be)X
+1571(used)X
+1739(as)X
+1827(the)X
+1946(motion)X
+2193(component)X
+2570(of)X
+2658(other)X
+3 f
+2844(vi)X
+1 f
+2927(commands,)X
+3315(in)X
+3398(which)X
+3615(case)X
+3775(any)X
+3912(text)X
+776 3822(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 4002(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(word)X
+2259(selected.)X
+776 4092(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(of)X
+1992(the)X
+2110(word)X
+2295(selected.)X
+776 4182(Options:)N
+1136(None.)X
+3 f
+576 4362([count])N
+841(f)X
+888 0.3125(<character>)AX
+1 f
+776 4452(Search)N
+1015(forward,)X
+7 f
+1310(count)X
+1 f
+1570(times,)X
+1783(through)X
+2052(the)X
+2170(rest)X
+2306(of)X
+2393(the)X
+2511(current)X
+2759(line)X
+2899(for)X
+7 f
+3013(<character>)X
+1 f
+(.)S
+776 4632(The)N
+3 f
+922(f)X
+1 f
+970(command)X
+1307(may)X
+1466(be)X
+1563(used)X
+1731(as)X
+1819(the)X
+1938(motion)X
+2185(component)X
+2562(of)X
+2651(other)X
+3 f
+2838(vi)X
+1 f
+2922(commands,)X
+3311(in)X
+3395(which)X
+3613(case)X
+3774(any)X
+3912(text)X
+776 4722(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 4902(Line:)N
+1136(Unchanged.)X
+776 4992(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458 0.3068(searched-for)AX
+1881(character.)X
+776 5082(Options:)N
+1136(None.)X
+3 f
+576 5262([count])N
+841(i)X
+1 f
+776 5352(Enter)N
+971(input)X
+1156(mode,)X
+1375(inserting)X
+1676(the)X
+1795(text)X
+1936(before)X
+2163(the)X
+2282(cursor.)X
+2545(If)X
+7 f
+2621(count)X
+1 f
+2883(is)X
+2958(speci\256ed,)X
+3285(the)X
+3405(text)X
+3547(input)X
+3733(is)X
+3808(repeat-)X
+776 5442(edly)N
+934(input)X
+7 f
+1118(count)X
+1406(-)X
+1502(1)X
+1 f
+1570(more)X
+1755(times.)X
+776 5622(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 5712(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+
+27 p
+%%Page: 27 26
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-27)X
+1 f
+776 762(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 852(gin)N
+1 f
+1262(options.)X
+3 f
+576 1032(m)N
+663 0.3125(<character>)AX
+1 f
+776 1122(Save)N
+956(the)X
+1078(current)X
+1330(context)X
+1590(\(line)X
+1761(and)X
+1902(column\))X
+2194(as)X
+7 f
+2286(<character>)X
+1 f
+(.)S
+2879(The)X
+3029(exact)X
+3224(position)X
+3506(is)X
+3584(referred)X
+3865(to)X
+3952(by)X
+776 1212(``)N
+7 f
+830(`<character>)X
+1 f
+(''.)S
+1520(The)X
+1665(line)X
+1805(is)X
+1878(referred)X
+2154(to)X
+2236(by)X
+2336(``)X
+7 f
+2390('<character>)X
+1 f
+(''.)S
+776 1392(Historically,)N
+7 f
+1205(<character>)X
+1 f
+1764(was)X
+1920(restricted)X
+2250(to)X
+2343(lower-case)X
+2723(letters)X
+2950(only,)X
+3 f
+3143(nvi)X
+1 f
+3280(permits)X
+3551(the)X
+3680(use)X
+3818(of)X
+3916(any)X
+776 1482(character.)N
+776 1662(Line:)N
+1136(Unchanged.)X
+776 1752(Column:)N
+1136(Unchanged.)X
+776 1842(Options:)N
+1136(None.)X
+3 f
+576 2022([count])N
+841(o)X
+1 f
+776 2112(Enter)N
+970(input)X
+1154(mode,)X
+1372(appending)X
+1727(text)X
+1868(in)X
+1951(a)X
+2008(new)X
+2163(line)X
+2304(under)X
+2508(the)X
+2627(current)X
+2876(line.)X
+3057(If)X
+7 f
+3132(count)X
+1 f
+3393(is)X
+3467(speci\256ed,)X
+3793(the)X
+3912(text)X
+776 2202(input)N
+960(is)X
+1033(repeatedly)X
+1388(input)X
+7 f
+1572(count)X
+1860(-)X
+1956(1)X
+1 f
+2024(more)X
+2209(times.)X
+776 2382(Historically,)N
+1194(any)X
+7 f
+1330(count)X
+1 f
+1590(speci\256ed)X
+1895(to)X
+1977(the)X
+3 f
+2095(o)X
+1 f
+2155(command)X
+2491(was)X
+2636(ignored.)X
+776 2562(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 2652(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 2742(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 2832(gin)N
+1 f
+1262(options.)X
+3 f
+576 3012([buffer])N
+864(p)X
+1 f
+776 3102(Append)N
+1055(text)X
+1200(from)X
+1381(a)X
+1442(buffer.)X
+1704(Text)X
+1876(from)X
+2057(the)X
+2180(buffer)X
+2402(\(the)X
+2552(unnamed)X
+2871(buffer)X
+3093(by)X
+3198(default\))X
+3473(is)X
+3551(appended)X
+3884(after)X
+776 3192(the)N
+894(current)X
+1142(column)X
+1402(or,)X
+1509(if)X
+1578(the)X
+1696(buffer)X
+1913(is)X
+1986(line)X
+2126(oriented,)X
+2429(after)X
+2597(the)X
+2715(current)X
+2963(line.)X
+776 3372(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(line)X
+1742(appended,)X
+2090(if)X
+2159(the)X
+2277(buffer)X
+2494(is)X
+2567(line)X
+2707(oriented,)X
+3010(otherwise)X
+3342(unchanged.)X
+776 3462(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2237(of)X
+2325(the)X
+2444(appended)X
+2773(text)X
+2914(if)X
+2984(the)X
+3103(buffer)X
+3321(is)X
+3395(line)X
+3536(oriented,)X
+3840(other-)X
+1136 3552(wise,)N
+1323(the)X
+1441(last)X
+1572(character)X
+1888(of)X
+1975(the)X
+2093(appended)X
+2421(text.)X
+776 3642(Options:)N
+1136(None.)X
+3 f
+576 3822([count])N
+841(r)X
+897 0.3125(<character>)AX
+1 f
+776 3912(Replace)N
+1073(characters.)X
+1478(The)X
+1641(next)X
+7 f
+1817(count)X
+1 f
+2095(characters)X
+2460(in)X
+2560(the)X
+2696(line)X
+2854(are)X
+2991(replaced)X
+3303(with)X
+7 f
+3484(<character>)X
+1 f
+(.)S
+776 4002(Replacing)N
+1121(characters)X
+1468(with)X
+7 f
+1630(<newline>)X
+1 f
+2082(characters)X
+2429(results)X
+2658(in)X
+2740(creating)X
+3019(new,)X
+3193(empty)X
+3413(lines)X
+3584(into)X
+3728(the)X
+3846(\256le.)X
+776 4182(If)N
+7 f
+850(<character>)X
+1 f
+1398(is)X
+7 f
+1471(<escape>)X
+1 f
+(,)S
+1895(the)X
+2013(command)X
+2349(is)X
+2422(cancelled.)X
+776 4362(Line:)N
+1136(Unchanged)X
+1527(unless)X
+1752(the)X
+1875(replacement)X
+2293(character)X
+2614(is)X
+2692(a)X
+7 f
+2753(<newline>)X
+1 f
+(,)S
+3231(in)X
+3319(which)X
+3541(case)X
+3706(it)X
+3776(is)X
+3855(set)X
+3970(to)X
+1136 4452(the)N
+1254(current)X
+1502(line)X
+1642(plus)X
+7 f
+1795(count)X
+2083(-)X
+2179(1)X
+1 f
+(.)S
+776 4542(Column:)N
+1136(Set)X
+1264(to)X
+1352(the)X
+1476(last)X
+1613(character)X
+1935(replaced,)X
+2254(unless)X
+2480(the)X
+2605(replacement)X
+3025(character)X
+3348(is)X
+3428(a)X
+7 f
+3491(<newline>)X
+1 f
+(,)S
+3970(in)X
+1136 4632(which)N
+1352(case)X
+1511(the)X
+1629(cursor)X
+1850(is)X
+1923(in)X
+2005(column)X
+2265(1)X
+2325(of)X
+2412(the)X
+2530(last)X
+2661(line)X
+2801(inserted.)X
+776 4722(Options:)N
+1136(None.)X
+3 f
+576 4902([buffer])N
+864([count])X
+1129(s)X
+1 f
+776 4992(Substitute)N
+7 f
+1115(count)X
+1 f
+1375(characters)X
+1722(in)X
+1804(the)X
+1922(current)X
+2170(line)X
+2310(starting)X
+2570(with)X
+2732(the)X
+2850(current)X
+3098(character.)X
+776 5172(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(line)X
+1729(upon)X
+1909(which)X
+2125(characters)X
+2472(were)X
+2649(entered.)X
+776 5262(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(last)X
+1589(character)X
+1905(entered.)X
+776 5352(Options:)N
+1136(Affected)X
+1440(by)X
+1542(the)X
+3 f
+1662(altwerase)X
+1 f
+1988(,)X
+3 f
+2030(autoindent)X
+1 f
+2398(,)X
+3 f
+2440(beautify)X
+1 f
+(,)S
+3 f
+2762(showmatch)X
+1 f
+3149(,)X
+3 f
+3191(ttywerase)X
+1 f
+3545(and)X
+3 f
+3684(wrapmar-)X
+1136 5442(gin)N
+1 f
+1262(options.)X
+3 f
+576 5622([count])N
+841(t)X
+888 0.3125(<character>)AX
+1 f
+776 5712(Search)N
+1014(forward,)X
+7 f
+1308(count)X
+1 f
+1567(times,)X
+1779(through)X
+2047(the)X
+2164(current)X
+2411(line)X
+2551(for)X
+2665(the)X
+2783(character)X
+3099(immediately)X
+2 f
+3519(before)X
+7 f
+3744(<char-)X
+776 5802(acter>)N
+1 f
+(.)S
+
+28 p
+%%Page: 28 27
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-28)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+1 f
+776 762(The)N
+3 f
+922(t)X
+1 f
+970(command)X
+1307(may)X
+1466(be)X
+1563(used)X
+1731(as)X
+1819(the)X
+1938(motion)X
+2185(component)X
+2562(of)X
+2651(other)X
+3 f
+2838(vi)X
+1 f
+2922(commands,)X
+3311(in)X
+3395(which)X
+3613(case)X
+3774(any)X
+3912(text)X
+776 852(copied)N
+1010(into)X
+1154(a)X
+1210(buffer)X
+1427(is)X
+1500(character)X
+1816(oriented.)X
+776 1032(Line:)N
+1136(Unchanged.)X
+776 1122(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(character)X
+2 f
+1774(before)X
+1 f
+1999(the)X
+2117 0.3068(searched-for)AX
+2540(character.)X
+776 1212(Options:)N
+1136(None.)X
+3 f
+576 1392(u)N
+1 f
+776 1482(Undo)N
+985(the)X
+1114(last)X
+1256(change)X
+1515(made)X
+1720(to)X
+1813(the)X
+1942(\256le.)X
+2115(If)X
+2200(repeated,)X
+2524(the)X
+3 f
+2653(u)X
+1 f
+2728(command)X
+3075(alternates)X
+3415(between)X
+3715(these)X
+3912(two)X
+776 1572(states,)N
+997(and)X
+1136(is)X
+1212(its)X
+1310(own)X
+1471(inverse.)X
+1766(When)X
+1981(used)X
+2151(after)X
+2322(an)X
+2421(insert)X
+2622(that)X
+2765(inserted)X
+3042(text)X
+3185(on)X
+3287(more)X
+3474(than)X
+3634(one)X
+3772(line,)X
+3934(the)X
+776 1662(lines)N
+947(are)X
+1066(saved)X
+1269(in)X
+1351(the)X
+1469(numeric)X
+1752(buffers.)X
+776 1842(The)N
+3 f
+928(.)X
+1 f
+995(command,)X
+1358(when)X
+1560(used)X
+1735(immediately)X
+2163(after)X
+2339(the)X
+3 f
+2465(u)X
+1 f
+2537(command,)X
+2901(causes)X
+3139(the)X
+3265(change)X
+3521(log)X
+3651(to)X
+3741(be)X
+3845(rolled)X
+776 1932(forward)N
+1051(or)X
+1138(backward,)X
+1491(depending)X
+1845(on)X
+1945(the)X
+2063(action)X
+2279(of)X
+2366(the)X
+3 f
+2484(u)X
+1 f
+2548(command.)X
+776 2112(Line:)N
+1136(Set)X
+1276(to)X
+1376(the)X
+1512(position)X
+1807(of)X
+1912(the)X
+2048(\256rst)X
+2211(line)X
+2370(changed,)X
+2697(if)X
+2785(the)X
+2922(reversal)X
+3216(affects)X
+3470(only)X
+3651(one)X
+3806(line)X
+3965(or)X
+1136 2202(represents)N
+1482(an)X
+1578(addition)X
+1860(or)X
+1947(change;)X
+2217(otherwise,)X
+2569(the)X
+2687(line)X
+2827(preceding)X
+3164(the)X
+3282(deleted)X
+3534(text.)X
+776 2292(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(cursor)X
+1679(position)X
+1956(before)X
+2182(the)X
+2300(change)X
+2548(was)X
+2693(made.)X
+776 2382(Options:)N
+1136(None.)X
+3 f
+576 2562([count])N
+841(w)X
+1 f
+776 2652(Move)N
+986(forward)X
+7 f
+1264(count)X
+1 f
+1527(words.)X
+1786(Move)X
+1996(the)X
+2117(cursor)X
+2341(forward)X
+2619(to)X
+2704(the)X
+2825(beginning)X
+3168(of)X
+3258(a)X
+3318(word)X
+3507(by)X
+3611(repeating)X
+3934(the)X
+776 2742(following)N
+1111(algorithm:)X
+1468(if)X
+1541(the)X
+1663(current)X
+1915(position)X
+2196(is)X
+2273(at)X
+2355(the)X
+2477(beginning)X
+2821(of)X
+2912(a)X
+2972(word,)X
+3181(move)X
+3383(to)X
+3468(the)X
+3589(\256rst)X
+3736(character)X
+776 2832(of)N
+866(the)X
+987(next)X
+1148(word.)X
+1376(If)X
+1453(no)X
+1556(subsequent)X
+1935(word)X
+2123(exists)X
+2328(on)X
+2431(the)X
+2552(current)X
+2803(line,)X
+2966(move)X
+3167(to)X
+3253(the)X
+3375(\256rst)X
+3523(character)X
+3843(of)X
+3934(the)X
+776 2922(\256rst)N
+920(word)X
+1105(on)X
+1205(the)X
+1323(\256rst)X
+1467(following)X
+1798(line)X
+1938(that)X
+2078(contains)X
+2365(a)X
+2421(word.)X
+776 3102(The)N
+3 f
+928(w)X
+1 f
+1014(command)X
+1358(may)X
+1524(be)X
+1628(used)X
+1803(as)X
+1898(the)X
+2024(motion)X
+2278(component)X
+2662(of)X
+2757(other)X
+3 f
+2950(vi)X
+1 f
+3040(commands,)X
+3435(in)X
+3525(which)X
+3749(case)X
+3916(any)X
+776 3192(text)N
+916(copied)X
+1150(into)X
+1294(a)X
+1350(buffer)X
+1567(is)X
+1640(character)X
+1956(oriented.)X
+776 3372(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(word)X
+2259(selected.)X
+776 3462(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(character)X
+1918(of)X
+2005(the)X
+2123(word)X
+2308(selected.)X
+776 3552(Options:)N
+1136(None.)X
+3 f
+576 3732([buffer])N
+864([count])X
+1129(x)X
+1 f
+776 3822(Delete)N
+7 f
+1007(count)X
+1 f
+1268(characters.)X
+1656(The)X
+1802(deletion)X
+2081(is)X
+2155(at)X
+2235(the)X
+2355(current)X
+2605(character)X
+2923(position.)X
+3242(If)X
+3318(the)X
+3438(number)X
+3705(of)X
+3794(charac-)X
+776 3912(ters)N
+915(to)X
+1000(be)X
+1099(deleted)X
+1354(is)X
+1430(greater)X
+1676(than)X
+1836(or)X
+1925(equal)X
+2121(to)X
+2205(the)X
+2325(number)X
+2592(of)X
+2681(characters)X
+3030(to)X
+3114(the)X
+3234(end)X
+3372(of)X
+3461(the)X
+3581(line,)X
+3743(all)X
+3845(of)X
+3934(the)X
+776 4002(characters)N
+1123(from)X
+1299(the)X
+1417(current)X
+1665(cursor)X
+1886(position)X
+2163(to)X
+2245(the)X
+2363(end)X
+2499(of)X
+2586(the)X
+2704(line)X
+2844(are)X
+2963(deleted.)X
+776 4182(Line:)N
+1136(Unchanged.)X
+776 4272(Column:)N
+1136(Unchanged)X
+1525(unless)X
+1748(the)X
+1869(last)X
+2003(character)X
+2322(in)X
+2407(the)X
+2528(line)X
+2671(is)X
+2747(deleted)X
+3002(and)X
+3141(the)X
+3263(cursor)X
+3488(is)X
+3565(not)X
+3691(already)X
+3952(on)X
+1136 4362(the)N
+1254(\256rst)X
+1398(character)X
+1714(in)X
+1796(the)X
+1914(line,)X
+2074(in)X
+2156(which)X
+2372(case)X
+2531(it)X
+2595(is)X
+2668(set)X
+2777(to)X
+2859(the)X
+2977(previous)X
+3273(character.)X
+776 4452(Options:)N
+1136(None.)X
+3 f
+576 4632([buffer])N
+864([count])X
+1129(y)X
+1189(motion)X
+1 f
+776 4722(Copy)N
+981(\(or)X
+1107(``yank''\))X
+1430(a)X
+1498(text)X
+1650(region)X
+1887(speci\256ed)X
+2204(by)X
+2316(the)X
+7 f
+2446(count)X
+1 f
+2718(and)X
+2866(motion)X
+3124(into)X
+3280(a)X
+3349(buffer.)X
+3619(If)X
+7 f
+3706(count)X
+1 f
+3979(is)X
+776 4812(speci\256ed,)N
+1101(it)X
+1165(is)X
+1238(applied)X
+1494(to)X
+1576(the)X
+7 f
+1694(motion)X
+1 f
+(.)S
+776 4992(Line:)N
+1136(Unchanged,)X
+1544(unless)X
+1766(the)X
+1886(region)X
+2113(covers)X
+2345(more)X
+2532(than)X
+2692(a)X
+2751(single)X
+2965(line,)X
+3128(in)X
+3213(which)X
+3432(case)X
+3594(it)X
+3661(is)X
+3737(set)X
+3849(to)X
+3934(the)X
+1136 5082(line)N
+1276(where)X
+1493(the)X
+1611(region)X
+1836(starts.)X
+776 5172(Column:)N
+1136(Unchanged,)X
+1544(unless)X
+1766(the)X
+1886(region)X
+2113(covers)X
+2345(more)X
+2532(than)X
+2692(a)X
+2751(single)X
+2965(line,)X
+3128(in)X
+3213(which)X
+3432(case)X
+3594(it)X
+3661(is)X
+3737(set)X
+3849(to)X
+3934(the)X
+1136 5262(character)N
+1452(were)X
+1629(the)X
+1747(region)X
+1972(starts.)X
+776 5352(Options:)N
+1136(None.)X
+3 f
+576 5532([count1])N
+881(z)X
+937([count2])X
+1242(type)X
+1 f
+776 5622(Redraw)N
+1049(the)X
+1170(screen)X
+1399(with)X
+1564(a)X
+1623(window)X
+7 f
+1904(count2)X
+1 f
+2215(lines)X
+2389(long,)X
+2574(with)X
+2740(line)X
+7 f
+2884(count1)X
+1 f
+3196(placed)X
+3430(as)X
+3521(speci\256ed)X
+3830(by)X
+3934(the)X
+7 f
+776 5712(type)N
+1 f
+1005(character.)X
+1378(If)X
+7 f
+1469(count1)X
+1 f
+1794(is)X
+1884(not)X
+2023(speci\256ed,)X
+2365(it)X
+2445(defaults)X
+2735(to)X
+2833(the)X
+2967(current)X
+3231(line.)X
+3427(If)X
+7 f
+3517(count2)X
+1 f
+3841(is)X
+3930(not)X
+776 5802(speci\256ed,)N
+1101(it)X
+1165(defaults)X
+1439(to)X
+1521(the)X
+1639(current)X
+1887(window)X
+2165(size.)X
+
+29 p
+%%Page: 29 28
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-29)X
+1 f
+776 762(The)N
+921(following)X
+7 f
+1252(type)X
+1 f
+1464(characters)X
+1811(may)X
+1969(be)X
+2065(used:)X
+776 942(+)N
+1136(If)X
+7 f
+1225(count1)X
+1 f
+1548(is)X
+1636(speci\256ed,)X
+1977(place)X
+2183(the)X
+2317(line)X
+7 f
+2473(count1)X
+1 f
+2797(at)X
+2891(the)X
+3025(top)X
+3163(of)X
+3266(the)X
+3400(screen.)X
+3682(Otherwise,)X
+1136 1032(display)N
+1387(the)X
+1505(screen)X
+1731(after)X
+1899(the)X
+2017(current)X
+2265(screen,)X
+2511(similarly)X
+2815(to)X
+2897(the)X
+3 f
+3015(<control-F>)X
+1 f
+3448(command.)X
+776 1122 0.2266(<carriage-return>)AN
+1136 1212(Place)N
+1330(the)X
+1448(line)X
+7 f
+1588(count1)X
+1 f
+1896(at)X
+1974(the)X
+2092(top)X
+2214(of)X
+2301(the)X
+2419(screen.)X
+776 1302(.)N
+1136(Place)X
+1330(the)X
+1448(line)X
+7 f
+1588(count1)X
+1 f
+1896(in)X
+1978(the)X
+2096(center)X
+2313(of)X
+2400(the)X
+2518(screen.)X
+9 f
+776 1392(-)N
+1 f
+1136(Place)X
+1330(the)X
+1448(line)X
+7 f
+1588(count1)X
+1 f
+1896(at)X
+1974(the)X
+2092(bottom)X
+2338(of)X
+2425(the)X
+2543(screen.)X
+776 1482(\303)N
+1136(If)X
+7 f
+1214(count1)X
+1 f
+1526(is)X
+1603(speci\256ed,)X
+1932(place)X
+2126(the)X
+2248(line)X
+2392(that)X
+2536(is)X
+2613(at)X
+2695(the)X
+2817(top)X
+2943(of)X
+3034(the)X
+3156(screen)X
+3386(when)X
+7 f
+3584(count1)X
+1 f
+3896(is)X
+3974(at)X
+1136 1572(the)N
+1264(bottom)X
+1520(of)X
+1617(the)X
+1745(screen,)X
+2001(at)X
+2089(the)X
+2217(bottom)X
+2472(of)X
+2568(the)X
+2695(screen,)X
+2950(i.e.)X
+3077(display)X
+3337(the)X
+3464(screen)X
+3699(before)X
+3934(the)X
+1136 1662(screen)N
+1362(before)X
+7 f
+1588(count1)X
+1 f
+(.)S
+1937(Otherwise,)X
+2308(display)X
+2560(the)X
+2679(screen)X
+2906(before)X
+3133(the)X
+3252(current)X
+3501(screen,)X
+3748(similarly)X
+1136 1752(to)N
+1218(the)X
+3 f
+1336(<control-B>)X
+1 f
+1773(command.)X
+776 1932(Line:)N
+1136(Set)X
+1263(to)X
+7 f
+1350(count1)X
+1 f
+1663(unless)X
+7 f
+1888(count1)X
+1 f
+2201(is)X
+2279(not)X
+2406(speci\256ed)X
+2716(and)X
+2857(the)X
+7 f
+2980(type)X
+1 f
+3197(character)X
+3518(was)X
+3668(either)X
+3876(``)X
+7 f
+3930(\303)X
+1 f
+('')S
+1136 2022(or)N
+1224(``)X
+7 f
+1278(+)X
+1 f
+('',)S
+1421(in)X
+1504(which)X
+1721(case)X
+1881(it)X
+1946(is)X
+2020(set)X
+2130(to)X
+2213(the)X
+2332(line)X
+2473(before)X
+2700(the)X
+2819(\256rst)X
+2964(line)X
+3105(on)X
+3206(the)X
+3325(previous)X
+3621(screen)X
+3847(or)X
+3934(the)X
+1136 2112(line)N
+1276(after)X
+1444(the)X
+1562(last)X
+1693(line)X
+1833(on)X
+1933(the)X
+2051(previous)X
+2347(screen,)X
+2593(respectively.)X
+776 2202(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 2292(Options:)N
+1136(None.)X
+3 f
+576 2472([count])N
+841({)X
+1 f
+776 2562(Move)N
+983(backward)X
+7 f
+1316(count)X
+1 f
+1576(paragraphs.)X
+776 2742(The)N
+3 f
+922({)X
+1 f
+975(command)X
+1312(is)X
+1386(an)X
+1483(absolute)X
+1771(movement.)X
+2170(The)X
+3 f
+2316({)X
+1 f
+2369(command)X
+2706(may)X
+2865(be)X
+2962(used)X
+3130(as)X
+3219(the)X
+3339(motion)X
+3587(component)X
+3965(of)X
+776 2832(other)N
+3 f
+963(vi)X
+1 f
+1047(commands,)X
+1436(in)X
+1520(which)X
+1738(case)X
+1899(any)X
+2036(text)X
+2177(copied)X
+2412(into)X
+2557(a)X
+2614(buffer)X
+2832(is)X
+2906(character)X
+3223(oriented,)X
+3527(unless)X
+3748(the)X
+3867(start-)X
+776 2922(ing)N
+898(character)X
+1214(is)X
+1287(the)X
+1405(\256rst)X
+1549(character)X
+1865(on)X
+1965(its)X
+2060(line,)X
+2220(in)X
+2302(which)X
+2518(case)X
+2677(it)X
+2741(is)X
+2814(line)X
+2954(oriented.)X
+776 3102(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(beginning)X
+2414(of)X
+2501(the)X
+2619(previous)X
+2915(paragraph.)X
+776 3192(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 3282(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(paragraph)X
+1 f
+2040(option.)X
+3 f
+576 3462([count])N
+841(|)X
+1 f
+776 3552(Move)N
+983(to)X
+1065(a)X
+1121(speci\256c)X
+2 f
+1386(column)X
+1 f
+1642(position)X
+1919(on)X
+2019(the)X
+2137(current)X
+2385(line.)X
+776 3732(The)N
+3 f
+922(|)X
+1 f
+962(command)X
+1300(may)X
+1460(be)X
+1558(used)X
+1727(as)X
+1816(the)X
+1936(motion)X
+2184(component)X
+2562(of)X
+2651(other)X
+3 f
+2838(vi)X
+1 f
+2922(commands,)X
+3311(in)X
+3395(which)X
+3613(case)X
+3774(any)X
+3912(text)X
+776 3822(copied)N
+1012(into)X
+1158(a)X
+1216(buffer)X
+1435(is)X
+1510(character)X
+1828(oriented.)X
+2153(It)X
+2224(is)X
+2299(an)X
+2397(error)X
+2576(to)X
+2660(use)X
+2789(the)X
+3 f
+2908(|)X
+1 f
+2947(command)X
+3284(as)X
+3372(a)X
+3429(motion)X
+3676(component)X
+776 3912(and)N
+912(for)X
+1026(the)X
+1144(cursor)X
+1365(not)X
+1487(to)X
+1569(move.)X
+776 4092(Line:)N
+1136(Unchanged.)X
+776 4182(Column:)N
+1136(Set)X
+1265(to)X
+1355(the)X
+1481(character)X
+1805(occupying)X
+2167(the)X
+2293(column)X
+2561(position)X
+2846(identi\256ed)X
+3176(by)X
+7 f
+3284(count)X
+1 f
+(,)S
+3572(if)X
+3649(the)X
+3775(position)X
+1136 4272(exists)N
+1339(in)X
+1422(the)X
+1541(line.)X
+1722(If)X
+1797(the)X
+1916(column)X
+2176(length)X
+2396(of)X
+2483(the)X
+2601(current)X
+2849(line)X
+2989(is)X
+3062(less)X
+3202(than)X
+7 f
+3360(count)X
+1 f
+(,)S
+3640(the)X
+3758(cursor)X
+3979(is)X
+1136 4362(moved)N
+1374(to)X
+1456(the)X
+1574(last)X
+1705(character)X
+2021(in)X
+2103(the)X
+2221(line.)X
+776 4452(Options:)N
+1136(None.)X
+3 f
+576 4632([count])N
+841(})X
+1 f
+776 4722(Move)N
+983(forward)X
+7 f
+1258(count)X
+1 f
+1518(paragraphs.)X
+776 4902(The)N
+3 f
+922(})X
+1 f
+975(command)X
+1312(is)X
+1386(an)X
+1483(absolute)X
+1771(movement.)X
+2170(The)X
+3 f
+2316(})X
+1 f
+2369(command)X
+2706(may)X
+2865(be)X
+2962(used)X
+3130(as)X
+3219(the)X
+3339(motion)X
+3587(component)X
+3965(of)X
+776 4992(other)N
+3 f
+963(vi)X
+1 f
+1047(commands,)X
+1436(in)X
+1520(which)X
+1738(case)X
+1899(any)X
+2036(text)X
+2177(copied)X
+2412(into)X
+2557(a)X
+2614(buffer)X
+2832(is)X
+2906(character)X
+3223(oriented,)X
+3527(unless)X
+3748(the)X
+3867(start-)X
+776 5082(ing)N
+898(character)X
+1214(is)X
+1287(at)X
+1365(or)X
+1452(before)X
+1678(any)X
+1814(nonblank)X
+2132(characters)X
+2479(in)X
+2561(its)X
+2656(line,)X
+2816(in)X
+2898(which)X
+3114(case)X
+3273(it)X
+3337(is)X
+3410(line)X
+3550(oriented.)X
+776 5262(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(containing)X
+1956(the)X
+2074(beginning)X
+2414(of)X
+2501(the)X
+2619(next)X
+2777(paragraph.)X
+776 5352(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(\256rst)X
+1602(nonblank)X
+1920(character)X
+2236(in)X
+2318(the)X
+2436(line.)X
+776 5442(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(paragraph)X
+1 f
+2040(option.)X
+3 f
+576 5622([count])N
+841(\304)X
+1 f
+776 5712(Reverse)N
+1062(the)X
+1187(case)X
+1353(of)X
+1447(the)X
+1572(next)X
+7 f
+1738(count)X
+1 f
+2006 0.3021(character\(s\).)AX
+2455(This)X
+2625(is)X
+2706(the)X
+2832(historic)X
+3100(semantic)X
+3413(for)X
+3535(the)X
+3 f
+3661(\304)X
+1 f
+3716(command)X
+776 5802(and)N
+912(it)X
+976(is)X
+1049(only)X
+1211(in)X
+1293(effect)X
+1497(if)X
+1566(the)X
+3 f
+1684(tildeop)X
+1 f
+1939(option)X
+2163(is)X
+2236(not)X
+2358(set.)X
+
+30 p
+%%Page: 30 29
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-30)N
+2826(Nvi/Nex)X
+3122 0.3906(Reference)AX
+3487(\(Vi)X
+3614(Commands\))X
+1 f
+776 762(Lowercase)N
+1148(alphabetic)X
+1501(characters)X
+1851(are)X
+1974(changed)X
+2266(to)X
+2352(uppercase,)X
+2718(and)X
+2858(uppercase)X
+3204(characters)X
+3555(are)X
+3678(changed)X
+3970(to)X
+776 852(lowercase.)N
+1158(No)X
+1276(other)X
+1461(characters)X
+1808(are)X
+1927(affected.)X
+776 1032(Historically,)N
+1203(the)X
+3 f
+1330(\304)X
+1 f
+1386(command)X
+1731(did)X
+1863(not)X
+1995(take)X
+2159(an)X
+2265(associated)X
+2625(count,)X
+2853(nor)X
+2990(did)X
+3122(it)X
+3196(move)X
+3404(past)X
+3563(the)X
+3691(end)X
+3837(of)X
+3934(the)X
+776 1122(current)N
+1025(line.)X
+1206(As)X
+1316(it)X
+1381(had)X
+1518(no)X
+1619(associated)X
+1970(motion)X
+2217(it)X
+2282(was)X
+2428(dif\256cult)X
+2701(to)X
+2783(change)X
+3031(the)X
+3149(case)X
+3308(of)X
+3395(large)X
+3576(blocks)X
+3805(of)X
+3892(text.)X
+776 1212(In)N
+3 f
+868(nvi)X
+1 f
+974(,)X
+1019(if)X
+1093(the)X
+1216(cursor)X
+1442(is)X
+1520(on)X
+1625(the)X
+1748(last)X
+1884(character)X
+2205(of)X
+2297(a)X
+2359(line,)X
+2525(and)X
+2667(there)X
+2854(are)X
+2979(more)X
+3170(lines)X
+3347(in)X
+3435(the)X
+3559(\256le,)X
+3707(the)X
+3831(cursor)X
+776 1302(moves)N
+1005(to)X
+1087(the)X
+1205(next)X
+1363(line.)X
+776 1482(It)N
+849(is)X
+926(not)X
+1052(an)X
+1152(error)X
+1333(to)X
+1419(specify)X
+1675(a)X
+1735(count)X
+1938(larger)X
+2151(than)X
+2314(the)X
+2437(number)X
+2707(of)X
+2799(characters)X
+3151(between)X
+3444(the)X
+3567(cursor)X
+3793(and)X
+3934(the)X
+776 1572(end)N
+912(of)X
+999(the)X
+1117(\256le.)X
+776 1752(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(of)X
+1685(the)X
+1803(character)X
+2119(after)X
+7 f
+2287(count)X
+1 f
+2547(characters,)X
+2914(or,)X
+3021(end)X
+3157(of)X
+3244(\256le.)X
+776 1842(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(character)X
+1774(after)X
+7 f
+1942(count)X
+1 f
+2202(characters,)X
+2569(or,)X
+2676(end-of-\256le.)X
+776 1932(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(tildeop)X
+1 f
+1911(option.)X
+3 f
+576 2112([count])N
+841(\304)X
+888(motion)X
+1 f
+776 2202(Reverse)N
+1063(the)X
+1189(case)X
+1356(of)X
+1451(the)X
+1577(characters)X
+1932(in)X
+2022(a)X
+2086(text)X
+2234(region)X
+2467(speci\256ed)X
+2780(by)X
+2888(the)X
+7 f
+3014(count)X
+1 f
+3282(and)X
+7 f
+3426(motion)X
+1 f
+(.)S
+3782(Only)X
+3970(in)X
+776 2292(effect)N
+980(if)X
+1049(the)X
+3 f
+1167(tildeop)X
+1 f
+1422(option)X
+1646(is)X
+1719(set.)X
+776 2472(Lowercase)N
+1147(characters)X
+1496(are)X
+1617(changed)X
+1908(to)X
+1993(uppercase,)X
+2358(and)X
+2497(uppercase)X
+2842(characters)X
+3192(are)X
+3314(changed)X
+3605(to)X
+3690(lowercase.)X
+776 2562(No)N
+894(other)X
+1079(characters)X
+1426(are)X
+1545(affected.)X
+776 2742(Line:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(line)X
+1598(of)X
+1685(the)X
+1803(character)X
+2119(after)X
+2287(the)X
+2405(last)X
+2536(character)X
+2852(in)X
+2934(the)X
+3052(region.)X
+776 2832(Column:)N
+1136(Set)X
+1258(to)X
+1340(the)X
+1458(character)X
+1774(after)X
+1942(the)X
+2060(last)X
+2191(character)X
+2507(in)X
+2589(the)X
+2707(region.)X
+776 2922(Options:)N
+1136(Affected)X
+1438(by)X
+1538(the)X
+3 f
+1656(tildeop)X
+1 f
+1911(option.)X
+3 f
+576 3102(<interrupt>)N
+1 f
+776 3192(Interrupt)N
+1087(the)X
+1215(current)X
+1473(operation.)X
+1846(Many)X
+2063(of)X
+2160(the)X
+2289(potentially)X
+2662(long-running)X
+3 f
+3111(vi)X
+1 f
+3204(commands)X
+3582(may)X
+3751(be)X
+3858(inter-)X
+776 3282(rupted)N
+1014(using)X
+1220(the)X
+1351(terminal)X
+1650(interrupt)X
+1958(character.)X
+2326(These)X
+2550(operations)X
+2916(include)X
+3184(searches,)X
+3509(\256le)X
+3643(reading)X
+3916(and)X
+776 3372(writing,)N
+1059(\256lter)X
+1242(operations)X
+1608(and)X
+1756(map)X
+1927(character)X
+2256(expansion.)X
+2654(Interrupts)X
+2999(are)X
+3131(also)X
+3293(enabled)X
+3576(when)X
+3783(running)X
+776 3462(commands)N
+1143(outside)X
+1394(of)X
+3 f
+1481(vi)X
+1 f
+1543(.)X
+776 3642(If)N
+853(the)X
+7 f
+974(<interrupt>)X
+1 f
+1525(character)X
+1844(is)X
+1920(used)X
+2090(to)X
+2175(interrupt)X
+2474(while)X
+2675(entering)X
+2961(an)X
+3 f
+3060(ex)X
+1 f
+3159(command,)X
+3518(the)X
+3639(command)X
+3979(is)X
+776 3732(aborted,)N
+1057(the)X
+1175(cursor)X
+1396(returns)X
+1639(to)X
+1721(its)X
+1816(previous)X
+2112(position,)X
+2409(and)X
+3 f
+2545(vi)X
+1 f
+2627(remains)X
+2901(in)X
+2983(command)X
+3319(mode.)X
+776 3912(Generally,)N
+1145(if)X
+1226(the)X
+7 f
+1356(<interrupt>)X
+1 f
+1916(character)X
+2244(is)X
+2329(used)X
+2508(to)X
+2603(interrupt)X
+2912(any)X
+3061(operation,)X
+3417(any)X
+3566(changes)X
+3858(made)X
+776 4002(before)N
+1002(the)X
+1120(interrupt)X
+1416(are)X
+1535(left)X
+1662(in)X
+1744(place.)X
+776 4182(Line:)N
+1136(Dependent)X
+1504(on)X
+1604(the)X
+1722(operation)X
+2045(being)X
+2243(interrupted.)X
+776 4272(Column:)N
+1136(Dependent)X
+1504(on)X
+1604(the)X
+1722(operation)X
+2045(being)X
+2243(interrupted.)X
+776 4362(Options:)N
+1136(None.)X
+3 f
+776 4548(11.)N
+916(Vi)X
+1016(Text)X
+1192(Input)X
+1402(Commands)X
+1 f
+976 4671(The)N
+1121(following)X
+1452(section)X
+1699(describes)X
+2018(the)X
+2136(commands)X
+2503(available)X
+2813(in)X
+2895(the)X
+3013(text)X
+3153(input)X
+3337(mode)X
+3535(of)X
+3622(the)X
+3 f
+3740(vi)X
+1 f
+3822(editor.)X
+976 4794(Historically,)N
+3 f
+1394(vi)X
+1 f
+1476(implementations)X
+2030(only)X
+2193(permitted)X
+2521(the)X
+2640(characters)X
+2988(inserted)X
+3263(on)X
+3364(the)X
+3483(current)X
+3732(line)X
+3873(to)X
+3956(be)X
+776 4884(erased.)N
+1060(In)X
+1165(addition,)X
+1485(only)X
+1665(the)X
+7 f
+1801(<control-D>)X
+1 f
+2367(erase)X
+2571(character)X
+2905(and)X
+3059(the)X
+3195(``)X
+7 f
+3249(0<control-D>)X
+1 f
+('')S
+3916(and)X
+776 4974(``)N
+7 f
+830(\303<control-D>)X
+1 f
+('')S
+1488(erase)X
+1683(strings)X
+1925(could)X
+2132(erase)X
+2327(autoindent)X
+2694(characters.)X
+3090(This)X
+3261(implementation)X
+3792(permits)X
+776 5064(erasure)N
+1038(to)X
+1129(continue)X
+1434(past)X
+1592(the)X
+1719(beginning)X
+2068(of)X
+2164(the)X
+2291(current)X
+2548(line,)X
+2717(and)X
+2862(back)X
+3043(to)X
+3134(where)X
+3360(text)X
+3509(input)X
+3701(mode)X
+3907(was)X
+776 5154(entered.)N
+1080(In)X
+1174(addition,)X
+1483(autoindent)X
+1848(characters)X
+2202(may)X
+2367(be)X
+2471(erased)X
+2705(using)X
+2906(the)X
+3032(standard)X
+3332(erase)X
+3526(characters.)X
+3921(For)X
+776 5244(the)N
+908(line)X
+1061(and)X
+1210(word)X
+1408(erase)X
+1607(characters,)X
+1987(reaching)X
+2297(the)X
+2428(autoindent)X
+2799(characters)X
+3159(forms)X
+3379(a)X
+3448(``soft'')X
+3709(boundary,)X
+776 5334(denoting)N
+1081(the)X
+1204(end)X
+1345(of)X
+1437(the)X
+1561(current)X
+1815(word)X
+2006(or)X
+2099(line)X
+2245(erase.)X
+2477(Repeating)X
+2828(the)X
+2952(word)X
+3143(or)X
+3236(line)X
+3382(erase)X
+3574(key)X
+3716(will)X
+3866(erase)X
+776 5424(the)N
+894(autoindent)X
+1252(characters.)X
+976 5547(Historically,)N
+3 f
+1396(vi)X
+1 f
+1480(always)X
+1725(used)X
+7 f
+1894(<control-H>)X
+1 f
+2444(and)X
+7 f
+2582(<control-W>)X
+1 f
+3132(as)X
+3221(character)X
+3539(and)X
+3678(word)X
+3866(erase)X
+776 5637(characters,)N
+1148(respectively,)X
+1581(regardless)X
+1932(of)X
+2024(the)X
+2146(current)X
+2398(terminal)X
+2689(settings.)X
+2997(This)X
+3163(implementation)X
+3689(accepts,)X
+3970(in)X
+776 5727(addition)N
+1058(to)X
+1140(these)X
+1325(two)X
+1465(characters,)X
+1832(the)X
+1950(current)X
+2198(terminal)X
+2485(characters)X
+2832(for)X
+2946(those)X
+3135(operations.)X
+
+31 p
+%%Page: 31 30
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Vi)X
+1364(Commands\))X
+3658(USD:13-31)X
+776 762(<nul>)N
+1 f
+976 852(If)N
+1050(the)X
+1168(\256rst)X
+1312(character)X
+1628(of)X
+1715(the)X
+1833(input)X
+2017(is)X
+2090(a)X
+7 f
+2146(<nul>)X
+1 f
+(,)S
+2426(the)X
+2544(previous)X
+2840(input)X
+3024(is)X
+3097(replayed,)X
+3414(as)X
+3501(if)X
+3570(just)X
+3705(entered.)X
+3 f
+776 1032(<control-D>)N
+1 f
+976 1122(If)N
+1058(the)X
+1184(previous)X
+1488(character)X
+1813(on)X
+1922(the)X
+2049(line)X
+2198(was)X
+2352(an)X
+2457(autoindent)X
+2824(character,)X
+3169(erase)X
+3364(it.)X
+3477(Otherwise,)X
+3856(if)X
+3934(the)X
+976 1212(user)N
+1135(is)X
+1213(entering)X
+1501(the)X
+1624(\256rst)X
+1773(character)X
+2094(in)X
+2181(the)X
+2304(line,)X
+7 f
+2469(<control-D>)X
+1 f
+3022(is)X
+3100(ignored.)X
+3410(Otherwise,)X
+3785(a)X
+3845(literal)X
+7 f
+976 1302(<control-D>)N
+1 f
+1524(character)X
+1840(is)X
+1913(entered.)X
+3 f
+776 1482(\303<control-D>)N
+1 f
+976 1572(If)N
+1058(the)X
+1184(previous)X
+1488(character)X
+1812(on)X
+1920(the)X
+2047(line)X
+2196(was)X
+2350(an)X
+2455(autoindent)X
+2822(character,)X
+3167(erase)X
+3362(all)X
+3471(of)X
+3567(the)X
+3694(autoindent)X
+976 1662(characters)N
+1323(on)X
+1423(the)X
+1541(line.)X
+1721(In)X
+1808(addition,)X
+2110(the)X
+2228(autoindent)X
+2586(level)X
+2762(is)X
+2835(reset)X
+3007(to)X
+3089(0.)X
+3 f
+776 1842(0<control-D>)N
+1 f
+976 1932(If)N
+1058(the)X
+1184(previous)X
+1488(character)X
+1812(on)X
+1920(the)X
+2047(line)X
+2196(was)X
+2350(an)X
+2455(autoindent)X
+2822(character,)X
+3167(erase)X
+3362(all)X
+3471(of)X
+3567(the)X
+3694(autoindent)X
+976 2022(characters)N
+1323(on)X
+1423(the)X
+1541(line.)X
+3 f
+776 2202(<control-T>)N
+1 f
+976 2292(Insert)N
+1191(suf\256cient)X
+7 f
+1521(<tab>)X
+1 f
+1793(and)X
+7 f
+1941(<space>)X
+1 f
+2309(characters)X
+2669(to)X
+2764(move)X
+2975(the)X
+3106(cursor)X
+3340(forward)X
+3628(to)X
+3723(a)X
+3792(column)X
+976 2382(immediately)N
+1396(after)X
+1564(the)X
+1682(next)X
+1840(column)X
+2100(which)X
+2316(is)X
+2389(an)X
+2485(even)X
+2657(multiple)X
+2943(of)X
+3030(the)X
+3 f
+3148(shiftwidth)X
+1 f
+3514(option.)X
+976 2562(Historically,)N
+3 f
+1397(vi)X
+1 f
+1482(did)X
+1607(not)X
+1732(permit)X
+1965(the)X
+7 f
+2087(<control-T>)X
+1 f
+2639(command)X
+2979(to)X
+3065(be)X
+3165(used)X
+3336(unless)X
+3560(the)X
+3682(cursor)X
+3907(was)X
+976 2652(at)N
+1056(the)X
+1176(\256rst)X
+1322(column)X
+1584(of)X
+1673(a)X
+1731(new)X
+1887(line)X
+2029(or)X
+2117(it)X
+2182(was)X
+2328(preceded)X
+2640(only)X
+2803(by)X
+2904(autoindent)X
+3263(characters.)X
+3 f
+3651(Nvi)X
+1 f
+3792(permits)X
+976 2742(it)N
+1040(to)X
+1122(be)X
+1218(used)X
+1385(at)X
+1463(any)X
+1599(time)X
+1761(during)X
+1990(insert)X
+2188(mode.)X
+3 f
+776 2922(<erase>)N
+776 3012(<control-H>)N
+1 f
+976 3102(Erase)N
+1175(the)X
+1293(last)X
+1424(character.)X
+3 f
+776 3282(<literal)N
+1047(next>)X
+1 f
+976 3372(Quote)N
+1197(the)X
+1320(next)X
+1483(character.)X
+1844(The)X
+1994(next)X
+2157(character)X
+2479(will)X
+2629(not)X
+2757(be)X
+2859(mapped)X
+3139(\(see)X
+3295(the)X
+3 f
+3419(map)X
+1 f
+3596(command)X
+3938(for)X
+976 3462(more)N
+1162(information\))X
+1588(or)X
+1676(interpreted)X
+2045(specially.)X
+2391(A)X
+2470(carat)X
+2648(\(``)X
+7 f
+2729(\303)X
+1 f
+(''\))S
+2878(character)X
+3194(will)X
+3338(be)X
+3434(displayed)X
+3761(immedi-)X
+976 3552(ately)N
+1152(as)X
+1239(a)X
+1295(placeholder,)X
+1710(but)X
+1832(will)X
+1976(be)X
+2072(replaced)X
+2365(by)X
+2465(the)X
+2583(next)X
+2741(character.)X
+3 f
+776 3732(<escape>)N
+1 f
+976 3822(Resolve)N
+1254(all)X
+1354(text)X
+1494(input)X
+1678(into)X
+1822(the)X
+1940(\256le,)X
+2082(and)X
+2218(return)X
+2430(to)X
+2512(command)X
+2848(mode.)X
+3 f
+776 4002(<line)N
+966(erase>)X
+1 f
+976 4092(Erase)N
+1175(the)X
+1293(current)X
+1541(line.)X
+3 f
+776 4272(<control-W>)N
+776 4362(<word)N
+1020(erase>)X
+1 f
+976 4452(Erase)N
+1188(the)X
+1319(last)X
+1463(word.)X
+1701(The)X
+1859(de\256nition)X
+2198(of)X
+2298(word)X
+2496(is)X
+2582(dependent)X
+2945(on)X
+3059(the)X
+3 f
+3191(altwerase)X
+1 f
+3551(and)X
+3 f
+3701(ttywerase)X
+1 f
+976 4542(options.)N
+3 f
+776 4722 0.2102(<control-X>[0-9A-Fa-f]*)AN
+1 f
+976 4812(Insert)N
+1179(a)X
+1235(character)X
+1551(with)X
+1713(the)X
+1831(speci\256ed)X
+2136(hexadecimal)X
+2562(value)X
+2756(into)X
+2900(the)X
+3018(text.)X
+3 f
+776 4992(<interrupt>)N
+1 f
+976 5082(Interrupt)N
+1288(text)X
+1439(input)X
+1634(mode,)X
+1863(returning)X
+2188(to)X
+2281(command)X
+2628(mode.)X
+2877(If)X
+2962(the)X
+7 f
+3091(<interrupt>)X
+1 f
+3651(character)X
+3979(is)X
+976 5172(used)N
+1151(to)X
+1241(interrupt)X
+1545(inserting)X
+1852(text)X
+1999(into)X
+2150(the)X
+2275(\256le,)X
+2424(it)X
+2495(is)X
+2575(as)X
+2669(if)X
+2745(the)X
+7 f
+2870(<escape>)X
+1 f
+3281(character)X
+3604(was)X
+3756(used;)X
+3952(all)X
+976 5262(text)N
+1116(input)X
+1300(up)X
+1400(to)X
+1482(the)X
+1600(interruption)X
+1998(is)X
+2071(resolved)X
+2363(into)X
+2507(the)X
+2625(\256le.)X
+3 f
+776 5448(12.)N
+916(Ex)X
+1029(Addressing)X
+1 f
+976 5571(Addressing)N
+1363(in)X
+3 f
+1447(ex)X
+1 f
+1545(\(and)X
+1710(when)X
+3 f
+1906(ex)X
+1 f
+2004(commands)X
+2373(are)X
+2494(executed)X
+2802(from)X
+3 f
+2980(vi)X
+1 f
+3042(\))X
+3092(relates)X
+3325(to)X
+3410(the)X
+3531(current)X
+3782(line.)X
+3965(In)X
+776 5661(general,)N
+1054(the)X
+1172(current)X
+1420(line)X
+1560(is)X
+1633(the)X
+1751(last)X
+1882(line)X
+2022(affected)X
+2302(by)X
+2402(a)X
+2458(command.)X
+2834(The)X
+2979(exact)X
+3169(effect)X
+3373(on)X
+3473(the)X
+3591(current)X
+3839(line)X
+3979(is)X
+776 5751(discussed)N
+1103(under)X
+1306(the)X
+1424(description)X
+1800(of)X
+1888(each)X
+2057(command.)X
+2434(When)X
+2647(the)X
+2766(\256le)X
+2889(contains)X
+3177(no)X
+3278(lines,)X
+3470(the)X
+3589(current)X
+3838(line)X
+3979(is)X
+
+32 p
+%%Page: 32 31
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-32)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+1 f
+776 762(zero.)N
+976 885(Addresses)N
+1326(are)X
+1445(constructed)X
+1835(by)X
+1935(one)X
+2071(or)X
+2158(more)X
+2343(of)X
+2430(the)X
+2548(following)X
+2879(methods:)X
+816 1008(\(1\))N
+1030(The)X
+1175(address)X
+1436(``)X
+7 f
+1490(.)X
+1 f
+('')S
+1632(refers)X
+1836(to)X
+1918(the)X
+2036(current)X
+2284(line.)X
+816 1131(\(2\))N
+1030(The)X
+1175(address)X
+1436(``)X
+7 f
+1490($)X
+1 f
+('')S
+1612(refers)X
+1816(to)X
+1898(the)X
+2016(last)X
+2147(line)X
+2287(of)X
+2374(the)X
+2492(\256le.)X
+816 1254(\(3\))N
+1030(The)X
+1175(address)X
+1436(``)X
+7 f
+1490(N)X
+1 f
+('',)S
+1632(where)X
+7 f
+1849(N)X
+1 f
+1917(is)X
+1990(a)X
+2046(positive)X
+2319(number,)X
+2604(refers)X
+2808(to)X
+2890(the)X
+3008(N-th)X
+3175(line)X
+3315(of)X
+3402(the)X
+3520(\256le.)X
+816 1377(\(4\))N
+1030(The)X
+1178(address)X
+1442(``)X
+7 f
+1496('<character>)X
+1 f
+('')S
+2149(or)X
+2239(``)X
+7 f
+2293(`<character>)X
+1 f
+('')S
+2946(refers)X
+3153(to)X
+3238(the)X
+3359(line)X
+3503(marked)X
+3768(with)X
+3934(the)X
+1030 1467(name)N
+7 f
+1234(<character>)X
+1 f
+(.)S
+1832(\(See)X
+2005(the)X
+3 f
+2133(k)X
+1 f
+2207(or)X
+3 f
+2304(m)X
+1 f
+2400(commands)X
+2776(for)X
+2899(more)X
+3093(information)X
+3500(on)X
+3609(how)X
+3776(to)X
+3867(mark)X
+1030 1557(lines.\))N
+816 1680(\(5\))N
+1030(A)X
+1113(regular)X
+1366(expression)X
+1734(\(RE\))X
+1915(enclosed)X
+2221(by)X
+2326(slashes)X
+2578(\(``)X
+7 f
+2659(/)X
+1 f
+(''\))S
+2813(is)X
+2891(an)X
+2992(address,)X
+3278(and)X
+3419(it)X
+3488(refers)X
+3697(to)X
+3784(the)X
+3908(\256rst)X
+1030 1770(line)N
+1171(found)X
+1379(by)X
+1480(searching)X
+1809(forward)X
+2085(from)X
+2262(the)X
+2381(line)X
+2 f
+2522(after)X
+1 f
+2694(the)X
+2813(current)X
+3062(line)X
+3203(toward)X
+3447(the)X
+3566(end)X
+3703(of)X
+3791(the)X
+3910(\256le,)X
+1030 1860(and)N
+1170(stopping)X
+1469(at)X
+1551(the)X
+1673(\256rst)X
+1821(line)X
+1965(containing)X
+2327(a)X
+2387(string)X
+2593(matching)X
+2915(the)X
+3037(RE.)X
+3203(\(The)X
+3379(trailing)X
+3634(slash)X
+3819(can)X
+3956(be)X
+1030 1950(omitted)N
+1294(at)X
+1372(the)X
+1490(end)X
+1626(of)X
+1713(the)X
+1831(command)X
+2167(line.\))X
+1030 2130(If)N
+1104(no)X
+1204(RE)X
+1326(is)X
+1399(speci\256ed,)X
+1724(i.e.)X
+1842(the)X
+1960(pattern)X
+2203(is)X
+2276(``)X
+7 f
+2330(//)X
+1 f
+('',)S
+2520(the)X
+2638(last)X
+2769(RE)X
+2891(used)X
+3058(in)X
+3140(any)X
+3276(command)X
+3612(is)X
+3685(used)X
+3852(in)X
+3934(the)X
+1030 2220(search.)N
+1030 2400(If)N
+1111(the)X
+3 f
+1236(extended)X
+1 f
+1570(option)X
+1801(is)X
+1881(set,)X
+2017(the)X
+2142(RE)X
+2271(is)X
+2351(handled)X
+2632(as)X
+2726(an)X
+2829(extended)X
+3146(RE,)X
+3295(not)X
+3425(a)X
+3489(basic)X
+3682(RE.)X
+3852(If)X
+3934(the)X
+3 f
+1030 2490(wrapscan)N
+1 f
+1381(option)X
+1607(is)X
+1681(set,)X
+1811(the)X
+1930(search)X
+2157(wraps)X
+2370(around)X
+2614(to)X
+2697(the)X
+2816(beginning)X
+3157(of)X
+3245(the)X
+3364(\256le)X
+3487(and)X
+3624(continues)X
+3952(up)X
+1030 2580(to)N
+1112(and)X
+1248(including)X
+1570(the)X
+1688(current)X
+1936(line,)X
+2096(so)X
+2187(that)X
+2327(the)X
+2445(entire)X
+2648(\256le)X
+2770(is)X
+2843(searched.)X
+1030 2760(The)N
+1175(form)X
+1351(``)X
+7 f
+1405(\\/)X
+1 f
+('')S
+1575(is)X
+1648(accepted)X
+1950(for)X
+2064(historic)X
+2324(reasons,)X
+2605(and)X
+2741(is)X
+2814(identical)X
+3110(to)X
+3192(``)X
+7 f
+3246(//)X
+1 f
+(''.)S
+816 2883(\(6\))N
+1030(An)X
+1153(RE)X
+1280(enclosed)X
+1586(in)X
+1673(question)X
+1969(marks)X
+2190(\(``)X
+7 f
+2271(?)X
+1 f
+(''\))S
+2446(addresses)X
+2780(the)X
+2904(\256rst)X
+3054(line)X
+3200(found)X
+3413(by)X
+3519(searching)X
+3853(back-)X
+1030 2973(ward)N
+1212(from)X
+1389(the)X
+1508(line)X
+2 f
+1648(preceding)X
+1 f
+1989(the)X
+2107(current)X
+2355(line,)X
+2515(toward)X
+2758(the)X
+2876(beginning)X
+3216(of)X
+3303(the)X
+3421(\256le)X
+3543(and)X
+3679(stopping)X
+3974(at)X
+1030 3063(the)N
+1149(\256rst)X
+1294(line)X
+1435(containing)X
+1794(a)X
+1851(string)X
+2054(matching)X
+2373(the)X
+2492(RE.)X
+2655(\(The)X
+2828(trailing)X
+3080(question)X
+3372(mark)X
+3558(can)X
+3691(be)X
+3788(omitted)X
+1030 3153(at)N
+1108(the)X
+1226(end)X
+1362(of)X
+1449(a)X
+1505(command)X
+1841(line.\))X
+1030 3333(If)N
+1104(no)X
+1204(RE)X
+1326(is)X
+1399(speci\256ed,)X
+1724(i.e.)X
+1842(the)X
+1960(pattern)X
+2203(is)X
+2276(``)X
+7 f
+2330(??)X
+1 f
+('',)S
+2520(the)X
+2638(last)X
+2769(RE)X
+2891(used)X
+3058(in)X
+3140(any)X
+3276(command)X
+3612(is)X
+3685(used)X
+3852(in)X
+3934(the)X
+1030 3423(search.)N
+1030 3603(If)N
+1111(the)X
+3 f
+1236(extended)X
+1 f
+1570(option)X
+1801(is)X
+1881(set,)X
+2017(the)X
+2142(RE)X
+2271(is)X
+2351(handled)X
+2632(as)X
+2726(an)X
+2829(extended)X
+3146(RE,)X
+3295(not)X
+3425(a)X
+3489(basic)X
+3682(RE.)X
+3852(If)X
+3934(the)X
+3 f
+1030 3693(wrapscan)N
+1 f
+1382(option)X
+1609(is)X
+1685(set,)X
+1817(the)X
+1938(search)X
+2187(wraps)X
+2402(around)X
+2648(from)X
+2827(the)X
+2948(beginning)X
+3290(of)X
+3379(the)X
+3499(\256le)X
+3623(to)X
+3707(the)X
+3827(end)X
+3965(of)X
+1030 3783(the)N
+1148(\256le)X
+1270(and)X
+1406(continues)X
+1733(up)X
+1833(to)X
+1915(and)X
+2051(including)X
+2373(the)X
+2491(current)X
+2739(line,)X
+2899(so)X
+2990(that)X
+3130(the)X
+3248(entire)X
+3451(\256le)X
+3573(is)X
+3646(searched.)X
+1030 3963(The)N
+1175(form)X
+1351(``)X
+7 f
+1405(\\?)X
+1 f
+('')S
+1595(is)X
+1668(accepted)X
+1970(for)X
+2084(historic)X
+2344(reasons,)X
+2625(and)X
+2761(is)X
+2834(identical)X
+3130(to)X
+3212(``)X
+7 f
+3266(??)X
+1 f
+(''.)S
+816 4086(\(7\))N
+1030(An)X
+1148(address)X
+1409(followed)X
+1714(by)X
+1814(a)X
+1870(plus)X
+2023(sign)X
+2176(\(``)X
+7 f
+2257(+)X
+1 f
+(''\))S
+2406(or)X
+2494(a)X
+2551(minus)X
+2767(sign)X
+2921(\(``)X
+7 f
+3002(-)X
+1 f
+(''\))S
+3152(followed)X
+3458(by)X
+3559(a)X
+3616(number)X
+3882(is)X
+3956(an)X
+1030 4176(offset)N
+1237(address)X
+1502(and)X
+1642(refers)X
+1850(to)X
+1936(the)X
+2058(address)X
+2323(plus)X
+2480(\(or)X
+2598(minus\))X
+2844(the)X
+2966(indicated)X
+3284(number)X
+3553(of)X
+3643(lines.)X
+3857(If)X
+3934(the)X
+1030 4266(address)N
+1291(is)X
+1364(omitted,)X
+1648(the)X
+1766(addition)X
+2048(or)X
+2135(subtraction)X
+2511(is)X
+2584(done)X
+2760(with)X
+2922(respect)X
+3170(to)X
+3252(the)X
+3370(current)X
+3618(line.)X
+816 4389(\(8\))N
+1030(An)X
+1158(address)X
+1429(of)X
+1526(``)X
+7 f
+1580(+)X
+1 f
+('')S
+1712(or)X
+1809(``)X
+7 f
+9 f
+1863(-)X
+1 f
+1907('')X
+1991(followed)X
+2306(by)X
+2416(a)X
+2482(number)X
+2757(is)X
+2840(an)X
+2946(offset)X
+3159(from)X
+3345(the)X
+3473(current)X
+3731(line.)X
+3921(For)X
+1030 4479(example,)N
+1342(``)X
+7 f
+9 f
+1396(-)X
+7 f
+1440(5)X
+1 f
+('')S
+1562(is)X
+1635(the)X
+1753(same)X
+1938(as)X
+2025(``)X
+7 f
+2079(.)X
+9 f
+(-)S
+7 f
+2171(5)X
+1 f
+(''.)S
+816 4602(\(9\))N
+1030(An)X
+1151(address)X
+1415(ending)X
+1656(with)X
+1821(``)X
+7 f
+1875(+)X
+1 f
+('')S
+2000(or)X
+2090(``)X
+7 f
+2144(-)X
+1 f
+('')S
+2270(has)X
+2401(1)X
+2465(added)X
+2681(to)X
+2767(or)X
+2858(subtracted)X
+3212(from)X
+3392(the)X
+3514(address,)X
+3799(respec-)X
+1030 4692(tively.)N
+1276(As)X
+1389(a)X
+1449(consequence)X
+1884(of)X
+1975(this)X
+2114(rule)X
+2263(and)X
+2403(of)X
+2494(the)X
+2615(previous)X
+2914(rule,)X
+3082(the)X
+3203(address)X
+3467(``)X
+7 f
+9 f
+3521(-)X
+1 f
+3565('')X
+3642(refers)X
+3849(to)X
+3934(the)X
+1030 4782(line)N
+1173(preceding)X
+1513(the)X
+1634(current)X
+1886(line.)X
+2070(Moreover,)X
+2431(trailing)X
+2686(``)X
+7 f
+2740(+)X
+1 f
+('')S
+2866(and)X
+3006(``)X
+7 f
+9 f
+3060(-)X
+1 f
+3104('')X
+3182(characters)X
+3533(have)X
+3709(a)X
+3769(cumula-)X
+1030 4872(tive)N
+1170(effect.)X
+1414(For)X
+1545(example,)X
+1857(``)X
+7 f
+1911(++)X
+9 f
+(-)S
+7 f
+2051(++)X
+1 f
+('')S
+2221(refers)X
+2425(to)X
+2507(the)X
+2625(current)X
+2873(line)X
+3013(plus)X
+3166(3.)X
+816 4995(\(10\))N
+1030(A)X
+1108(percent)X
+1365(sign)X
+1518(\(``)X
+7 f
+1599(%)X
+1 f
+(''\))S
+1748(is)X
+1821(equivalent)X
+2175(to)X
+2257(the)X
+2375(address)X
+2636(range)X
+2835(``)X
+7 f
+2889(1,$)X
+1 f
+(''.)S
+3 f
+976 5118(Ex)N
+1 f
+1099(commands)X
+1476(require)X
+1734(zero,)X
+1923(one,)X
+2089(or)X
+2186(two)X
+2336(addresses.)X
+2714(It)X
+2793(is)X
+2876(an)X
+2982(error)X
+3169(to)X
+3261(specify)X
+3524(an)X
+3631(address)X
+3903(to)X
+3996(a)X
+776 5208(command)N
+1112(which)X
+1328(requires)X
+1607(zero)X
+1766(addresses.)X
+976 5331(If)N
+1053(the)X
+1174(user)X
+1331(provides)X
+1630(more)X
+1818(than)X
+1979(the)X
+2100(expected)X
+2409(number)X
+2677(of)X
+2768(addresses)X
+3100(to)X
+3186(any)X
+3 f
+3326(ex)X
+1 f
+3426(command,)X
+3786(the)X
+3908(\256rst)X
+776 5421(addresses)N
+1108(speci\256ed)X
+1417(are)X
+1540(discarded.)X
+1912(For)X
+2047(example,)X
+2362(``)X
+7 f
+2416(1,2,3,5)X
+1 f
+(''print)S
+2980(prints)X
+3185(lines)X
+3359(3)X
+3422(through)X
+3694(5,)X
+3777(because)X
+776 5511(the)N
+3 f
+894(print)X
+1 f
+1087(command)X
+1423(only)X
+1585(takes)X
+1770(two)X
+1910(addresses.)X
+976 5634(The)N
+1131(addresses)X
+1469(in)X
+1561(a)X
+1627(range)X
+1836(are)X
+1965(separated)X
+2299(from)X
+2485(each)X
+2663(other)X
+2858(by)X
+2968(a)X
+3034(comma)X
+3300(\(``)X
+7 f
+3381(,)X
+1 f
+(''\))S
+3540(or)X
+3637(a)X
+3703(semicolon)X
+776 5724(\(``)N
+7 f
+857(;)X
+1 f
+(''\).)S
+1058(In)X
+1157(the)X
+1287(latter)X
+1484(case,)X
+1675(the)X
+1805(current)X
+2065(line)X
+2217(\(``)X
+7 f
+2298(.)X
+1 f
+(''\))S
+2479(is)X
+2564(set)X
+2685(to)X
+2779(the)X
+2909(\256rst)X
+3065(address,)X
+3358(and)X
+3506(only)X
+3680(then)X
+3850(is)X
+3934(the)X
+
+33 p
+%%Page: 33 32
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3658(USD:13-33)X
+1 f
+776 762(second)N
+1026(address)X
+1295(calculated.)X
+1689(This)X
+1859(feature)X
+2111(can)X
+2251(be)X
+2355(used)X
+2530(to)X
+2620(determine)X
+2969(the)X
+3095(starting)X
+3363(line)X
+3511(for)X
+3633(forward)X
+3916(and)X
+776 852(backward)N
+1116(searches)X
+1416(\(see)X
+1572(rules)X
+1754(\(5\))X
+1874(and)X
+2016(\(6\))X
+2136(above\).)X
+2421(The)X
+2572(second)X
+2821(address)X
+3088(of)X
+3181(any)X
+3323(two-address)X
+3737(sequence)X
+776 942(corresponds)N
+1193(to)X
+1284(a)X
+1349(line)X
+1498(that)X
+1647(follows,)X
+1936(in)X
+2027(the)X
+2154(\256le,)X
+2305(the)X
+2432(line)X
+2581(corresponding)X
+3069(to)X
+3160(the)X
+3288(\256rst)X
+3442(address.)X
+3753(The)X
+3908(\256rst)X
+776 1032(address)N
+1044(must)X
+1226(be)X
+1329(less)X
+1475(than)X
+1639(or)X
+1732(equal)X
+1932(to)X
+2020(the)X
+2144(second)X
+2393(address.)X
+2700(The)X
+2851(\256rst)X
+3001(address)X
+3268(must)X
+3449(be)X
+3551(greater)X
+3801(than)X
+3965(or)X
+776 1122(equal)N
+973(to)X
+1058(the)X
+1179(\256rst)X
+1326(line)X
+1469(of)X
+1559(the)X
+1680(\256le,)X
+1825(and)X
+1964(the)X
+2085(last)X
+2219(address)X
+2483(must)X
+2661(be)X
+2761(less)X
+2905(than)X
+3067(or)X
+3158(equal)X
+3356(to)X
+3442(the)X
+3564(last)X
+3699(line)X
+3843(of)X
+3934(the)X
+776 1212(\256le.)N
+3 f
+776 1398(13.)N
+916(Ex)X
+1029(Description)X
+1 f
+976 1521(The)N
+1121(following)X
+1452(words)X
+1668(have)X
+1840(special)X
+2083(meanings)X
+2410(for)X
+3 f
+2524(ex)X
+1 f
+2620(commands.)X
+3 f
+776 1701(<eof>)N
+1 f
+976 1791(The)N
+1130(end-of-\256le)X
+1498(character)X
+1823(is)X
+1905(used)X
+2081(to)X
+2172(scroll)X
+2379(the)X
+2506(screen)X
+2741(in)X
+2832(the)X
+3 f
+2959(ex)X
+1 f
+3064(editor.)X
+3320(This)X
+3491(character)X
+3816(is)X
+3898(nor-)X
+976 1881(mally)N
+7 f
+1178(<control-D>)X
+1 f
+(,)S
+1746(however,)X
+2063(whatever)X
+2378(character)X
+2694(is)X
+2767(set)X
+2876(for)X
+2990(the)X
+3108(current)X
+3356(terminal)X
+3643(is)X
+3716(used.)X
+3 f
+776 2061(line)N
+1 f
+976 2151(A)N
+1054(single-line)X
+1412(address,)X
+1693(given)X
+1891(in)X
+1973(any)X
+2109(of)X
+2196(the)X
+2314(forms)X
+2521(described)X
+2849(in)X
+2931(the)X
+3049(section)X
+3296(entitled)X
+3557(``)X
+3 f
+3611(Ex)X
+3725(Address-)X
+976 2241(ing)N
+1 f
+1082(''.)X
+1196(The)X
+1341(default)X
+1584(for)X
+7 f
+1698(line)X
+1 f
+1910(is)X
+1983(the)X
+2101(current)X
+2349(line.)X
+3 f
+776 2421(range)N
+1 f
+976 2511(A)N
+1058(line,)X
+1222(or)X
+1313(a)X
+1373(pair)X
+1522(of)X
+1613(line)X
+1757(addresses,)X
+2109(separated)X
+2437(by)X
+2541(a)X
+2601(comma)X
+2861(or)X
+2952(semicolon.)X
+3345(\(See)X
+3512(the)X
+3634(section)X
+3885(enti-)X
+976 2601(tled)N
+1123(``)X
+3 f
+1177(Ex)X
+1297(Addressing)X
+1 f
+1683('')X
+1764(for)X
+1884(more)X
+2075(information.\))X
+2546(The)X
+2697(default)X
+2946(for)X
+3066(range)X
+3271(is)X
+3350(the)X
+3474(current)X
+3728(line)X
+2 f
+3874(only)X
+1 f
+4012(,)X
+976 2691(i.e.)N
+1114(``)X
+7 f
+1168(.,.)X
+1 f
+(''.)S
+1426(A)X
+1504(percent)X
+1761(sign)X
+1914(\(``)X
+7 f
+1995(%)X
+1 f
+(''\))S
+2144(stands)X
+2364(for)X
+2479(the)X
+2598(range)X
+2798(``)X
+7 f
+2852(1,$)X
+1 f
+(''.)S
+3111(The)X
+3257(starting)X
+3518(address)X
+3780(must)X
+3956(be)X
+976 2781(less)N
+1116(than,)X
+1294(or)X
+1381(equal)X
+1575(to,)X
+1677(the)X
+1795(ending)X
+2033(address.)X
+3 f
+776 2961(count)N
+1 f
+976 3051(A)N
+1058(positive)X
+1335(integer,)X
+1602(specifying)X
+1961(the)X
+2084(number)X
+2354(of)X
+2446(lines)X
+2622(to)X
+2709(be)X
+2810(affected)X
+3095(by)X
+3200(the)X
+3323(command;)X
+3686(the)X
+3809(default)X
+976 3141(is)N
+1055(1.)X
+1161(Generally,)X
+1524(a)X
+1586(count)X
+1790(past)X
+1945(the)X
+2068(end-of-\256le)X
+2432(may)X
+2595(be)X
+2696(speci\256ed,)X
+3026(e.g.)X
+3167(the)X
+3290(command)X
+3631(``)X
+7 f
+3685(p)X
+3786(3000)X
+1 f
+('')S
+976 3231(in)N
+1064(a)X
+1127(10)X
+1234(line)X
+1381(\256le)X
+1510(is)X
+1590(acceptable,)X
+1977(and)X
+2120(will)X
+2271(print)X
+2449(from)X
+2632(the)X
+2757(current)X
+3012(line)X
+3159(through)X
+3435(the)X
+3560(last)X
+3698(line)X
+3845(in)X
+3934(the)X
+976 3321(\256le.)N
+3 f
+776 3501(\257ags)N
+1 f
+976 3591(One)N
+1132(or)X
+1221(more)X
+1408(of)X
+1497(the)X
+1617(characters)X
+1966(``#'',)X
+2156(``p'',)X
+2346(and)X
+2484(``l''.)X
+2677(When)X
+2892(a)X
+2951(command)X
+3290(that)X
+3433(accepts)X
+3693(these)X
+3881(\257ags)X
+976 3681(completes,)N
+1343(the)X
+1463(addressed)X
+1802(line\(s\))X
+2029(are)X
+2150(written)X
+2399(out)X
+2523(as)X
+2612(if)X
+2683(by)X
+2785(the)X
+2905(corresponding)X
+3 f
+3386(#)X
+1 f
+(,)S
+3 f
+3468(l)X
+1 f
+3512(or)X
+3 f
+3600(p)X
+1 f
+3665(commands.)X
+976 3771(In)N
+1064(addition,)X
+1367(any)X
+1504(number)X
+1770(of)X
+1858(``)X
+7 f
+1912(+)X
+1 f
+('')S
+2035(or)X
+2123(``)X
+7 f
+9 f
+2177(-)X
+1 f
+2221('')X
+2296(characters)X
+2644(can)X
+2777(be)X
+2874(speci\256ed)X
+3180(before,)X
+3427(after,)X
+3616(or)X
+3704(during)X
+3934(the)X
+976 3861(\257ags,)N
+1175(in)X
+1265(which)X
+1489(case)X
+1656(the)X
+1782(line)X
+1930(written)X
+2185(is)X
+2266(not)X
+2396(necessarily)X
+2780(the)X
+2905(one)X
+3048(affected)X
+3335(by)X
+3442(the)X
+3567(command,)X
+3930(but)X
+976 3951(rather)N
+1184(the)X
+1302(line)X
+1442(addressed)X
+1779(by)X
+1879(the)X
+1997(offset)X
+2200(address)X
+2461(speci\256ed.)X
+2806(The)X
+2951(default)X
+3194(for)X
+7 f
+3308(flags)X
+1 f
+3568(is)X
+3641(none.)X
+3 f
+776 4131(\256le)N
+1 f
+976 4221(A)N
+1055(pattern)X
+1299(used)X
+1467(to)X
+1550(derive)X
+1772(a)X
+1829(pathname;)X
+2184(the)X
+2303(default)X
+2547(is)X
+2621(the)X
+2740(current)X
+2989(\256le.)X
+3152(File)X
+3297(names)X
+3524(are)X
+3645(subjected)X
+3970(to)X
+976 4311(normal)N
+2 f
+1223(sh)X
+1 f
+1294(\(1\))X
+1408(word)X
+1593(expansions.)X
+976 4434(Anywhere)N
+1336(a)X
+1397(\256le)X
+1524(name)X
+1723(is)X
+1801(speci\256ed,)X
+2131(it)X
+2200(is)X
+2279(also)X
+2434(possible)X
+2722(to)X
+2810(use)X
+2943(the)X
+3067(special)X
+3316(string)X
+3524(``)X
+7 f
+3578(/tmp)X
+1 f
+(''.)S
+3890(This)X
+776 4524(will)N
+936(be)X
+1048(replaced)X
+1357(with)X
+1535(a)X
+1607(temporary)X
+1973(\256le)X
+2111(name)X
+2321(which)X
+2553(can)X
+2701(be)X
+2813(used)X
+2996(for)X
+3126(temporary)X
+3491(work,)X
+3711(e.g.)X
+3882(``)X
+7 f
+3936(:e)X
+776 4614(/tmp)N
+1 f
+('')S
+1042(creates)X
+1286(and)X
+1422(edits)X
+1593(a)X
+1649(new)X
+1803(\256le.)X
+976 4737(If)N
+1052(both)X
+1216(a)X
+1274(count)X
+1474(and)X
+1613(a)X
+1672(range)X
+1874(are)X
+1996(speci\256ed)X
+2304(for)X
+2421(commands)X
+2791(that)X
+2934(use)X
+3064(either,)X
+3290(the)X
+3411(starting)X
+3674(line)X
+3817(for)X
+3934(the)X
+776 4827(command)N
+1120(is)X
+1200(the)X
+2 f
+1325(last)X
+1 f
+1467(line)X
+1614(addressed)X
+1958(by)X
+2065(the)X
+2190(range,)X
+2416(and)X
+7 f
+2559(count)X
+1 f
+(-)S
+2853(subsequent)X
+3236(lines)X
+3414(are)X
+3540(affected)X
+3827(by)X
+3934(the)X
+776 4917(command,)N
+1132(e.g.)X
+1268(the)X
+1386(command)X
+1722(``)X
+7 f
+1776(2,3p4)X
+1 f
+('')S
+2090(prints)X
+2292(out)X
+2414(lines)X
+2585(3,)X
+2665(4,)X
+2745(5)X
+2805(and)X
+2941(6.)X
+976 5040(When)N
+1188(only)X
+1350(a)X
+1406(line)X
+1546(or)X
+1633(range)X
+1833(is)X
+1907(speci\256ed,)X
+2233(with)X
+2396(no)X
+2497(command,)X
+2854(the)X
+2973(implied)X
+3238(command)X
+3575(is)X
+3649(either)X
+3853(a)X
+3 f
+3910(list)X
+1 f
+4012(,)X
+3 f
+776 5130(number)N
+1 f
+1073(or)X
+3 f
+1166(print)X
+1 f
+1365(command.)X
+1747(The)X
+1898(command)X
+2240(used)X
+2413(is)X
+2492(the)X
+2616(most)X
+2797(recent)X
+3020(of)X
+3112(the)X
+3235(three)X
+3421(commands)X
+3793(to)X
+3880(have)X
+776 5220(been)N
+949(used)X
+1117(\(including)X
+1467(any)X
+1604(use)X
+1732(as)X
+1820(a)X
+1877(\257ag\).)X
+2085(If)X
+2160(none)X
+2337(of)X
+2425(these)X
+2611(commands)X
+2979(have)X
+3152(been)X
+3325(used)X
+3493(before,)X
+3740(the)X
+3 f
+3859(print)X
+1 f
+776 5310(command)N
+1117(is)X
+1195(the)X
+1318(implied)X
+1587(command.)X
+1968(When)X
+2185(no)X
+2290(range)X
+2494(or)X
+2585(count)X
+2787(is)X
+2864(speci\256ed)X
+3173(and)X
+3313(the)X
+3435(command)X
+3775(line)X
+3919(is)X
+3996(a)X
+776 5400(blank)N
+974(line,)X
+1134(the)X
+1252(current)X
+1500(line)X
+1640(is)X
+1713(incremented)X
+2130(by)X
+2230(1)X
+2290(and)X
+2426(then)X
+2584(the)X
+2702(current)X
+2950(line)X
+3090(is)X
+3163(displayed.)X
+976 5523(Zero)N
+1149(or)X
+1237(more)X
+1423(whitespace)X
+1801(characters)X
+2149(may)X
+2308(precede)X
+2580(or)X
+2668(follow)X
+2898(the)X
+3017(addresses,)X
+3366(count,)X
+3585(\257ags,)X
+3778(or)X
+3867(com-)X
+776 5613(mand)N
+980(name.)X
+1220(Any)X
+1384(object)X
+1606(following)X
+1943(a)X
+2004(command)X
+2345(name)X
+2544(\(such)X
+2743(as)X
+2835(buffer,)X
+3077(\256le,)X
+3224(etc.\),)X
+3410(that)X
+3555(begins)X
+3789(with)X
+3956(an)X
+776 5703(alphabetic)N
+1130(character,)X
+1471(should)X
+1709(be)X
+1810(separated)X
+2139(from)X
+2320(the)X
+2443(command)X
+2784(name)X
+2983(by)X
+3088(at)X
+3171(least)X
+3343(one)X
+3484(whitespace)X
+3866(char-)X
+776 5793(acter.)N
+
+34 p
+%%Page: 34 33
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-34)N
+2813(Nvi/Nex)X
+3109 0.3906(Reference)AX
+3474(\(Ex)X
+3614(Commands\))X
+1 f
+976 762(Any)N
+1148(character,)X
+1498(including)X
+7 f
+1834(<carriage-return>)X
+1 f
+(,)S
+2704(``)X
+7 f
+2758(%)X
+1 f
+('')S
+2894(and)X
+3045(``)X
+7 f
+3099(#)X
+1 f
+('')S
+3236(retain)X
+3454(their)X
+3636(literal)X
+3858(value)X
+776 852(when)N
+970(preceded)X
+1281(by)X
+1381(a)X
+1437(backslash.)X
+3 f
+776 1038(14.)N
+916(Ex)X
+1029(Commands)X
+1 f
+976 1161(The)N
+1122(following)X
+1454(section)X
+1702(describes)X
+2022(the)X
+2141(commands)X
+2509(available)X
+2820(in)X
+2903(the)X
+3 f
+3023(ex)X
+1 f
+3121(editor.)X
+3370(In)X
+3459(each)X
+3629(entry)X
+3816(below,)X
+776 1251(the)N
+894(tag)X
+1012(line)X
+1152(is)X
+1225(a)X
+1281(usage)X
+1484(synopsis)X
+1779(for)X
+1893(the)X
+2011(command.)X
+976 1374(Each)N
+1161(command)X
+1501(can)X
+1637(be)X
+1737(entered)X
+1998(as)X
+2089(the)X
+2211(abbreviation)X
+2636(\(those)X
+2856(characters)X
+3207(in)X
+3293(the)X
+3416(synopsis)X
+3716(command)X
+776 1464(word)N
+966(preceding)X
+1307(the)X
+1429(``['')X
+1588 0.3375(character\),)AX
+1955(the)X
+2077(full)X
+2212(command)X
+2552(\(all)X
+2683(characters)X
+3034(shown)X
+3267(for)X
+3385(the)X
+3507(command)X
+3847(word,)X
+776 1554(omitting)N
+1067(the)X
+1187(``['')X
+1344(and)X
+1482(``]'')X
+1639 0.2955(characters\),)AX
+2035(or)X
+2124(any)X
+2262(leading)X
+2520(subset)X
+2742(of)X
+2831(the)X
+2951(full)X
+3084(command)X
+3422(down)X
+3622(to)X
+3706(the)X
+3826(abbre-)X
+776 1644(viation.)N
+1064(For)X
+1201(example,)X
+1519(the)X
+1643(args)X
+1803(command)X
+2145(\(shown)X
+2407(as)X
+2500(``)X
+7 f
+2554(ar[gs])X
+1 f
+('')S
+2922(in)X
+3010(the)X
+3134(synopsis\))X
+3462(can)X
+3600(be)X
+3702(entered)X
+3965(as)X
+776 1734(``)N
+7 f
+830(ar)X
+1 f
+('',)S
+1020(``)X
+7 f
+1074(arg)X
+1 f
+('')S
+1292(or)X
+1379(``)X
+7 f
+1433(args)X
+1 f
+(''.)S
+976 1857(Each)N
+3 f
+1163(ex)X
+1 f
+1265(command)X
+1607(described)X
+1941(below)X
+2163(notes)X
+2359(the)X
+2484(new)X
+2645(current)X
+2900(line)X
+3047(after)X
+3222(it)X
+3293(is)X
+3373(executed,)X
+3706(as)X
+3800(well)X
+3965(as)X
+776 1947(any)N
+912(options)X
+1167(that)X
+1307(affect)X
+1511(the)X
+1629(command.)X
+976 2127(A)N
+1063(comment.)X
+1430(Command)X
+1792(lines)X
+1972(beginning)X
+2321(with)X
+2492(the)X
+2619(double-quote)X
+3072(character)X
+3398(\(``)X
+7 f
+3479(")X
+1 f
+(''\))S
+3638(are)X
+3767(ignored.)X
+976 2217(This)N
+1138(permits)X
+1398(comments)X
+1747(in)X
+1829(editor)X
+2036(scripts)X
+2265(and)X
+2401(startup)X
+2639(\256les.)X
+3 f
+776 2397(<end-of-\256le>)N
+1 f
+976 2487(Scroll)N
+1189(the)X
+1309(screen.)X
+1577(Write)X
+1782(the)X
+1902(next)X
+2062(N)X
+2142(lines,)X
+2336(where)X
+2556(N)X
+2637(is)X
+2713(the)X
+2834(value)X
+3031(of)X
+3121(the)X
+3 f
+3242(scroll)X
+1 f
+3452(option.)X
+3719(The)X
+3867(com-)X
+976 2577(mand)N
+1191(is)X
+1281(the)X
+1416(end-of-\256le)X
+1792(terminal)X
+2096(character,)X
+2449(which)X
+2682(may)X
+2857(be)X
+2970(different)X
+3284(on)X
+3401(different)X
+3714(terminals.)X
+976 2667(Traditionally,)N
+1434(it)X
+1498(is)X
+1571(the)X
+7 f
+1689(<control-D>)X
+1 f
+2237(key.)X
+976 2847(Historically,)N
+1397(the)X
+3 f
+1518(eof)X
+1 f
+1644(command)X
+1984(ignored)X
+2253(any)X
+2393(preceding)X
+2734(count,)X
+2956(and)X
+3096(the)X
+7 f
+3218(<end-of-file>)X
+1 f
+3866(char-)X
+976 2937(acter)N
+1155(was)X
+1302(ignored)X
+1569(unless)X
+1791(it)X
+1857(was)X
+2004(entered)X
+2263(as)X
+2352(the)X
+2472(\256rst)X
+2618(character)X
+2936(of)X
+3025(the)X
+3145(command.)X
+3522(This)X
+3685(implemen-)X
+976 3027(tation)N
+1178(treats)X
+1372(it)X
+1436(as)X
+1523(a)X
+1579(command)X
+2 f
+1915(only)X
+1 f
+2073(if)X
+2142(entered)X
+2399(as)X
+2486(the)X
+2604(\256rst)X
+2748(character)X
+3064(of)X
+3151(the)X
+3269(command)X
+3605(line,)X
+3766(and)X
+3903(oth-)X
+976 3117(erwise)N
+1206(treats)X
+1400(it)X
+1464(as)X
+1551(any)X
+1687(other)X
+1872(character.)X
+976 3297(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(last)X
+1789(line)X
+1929(written.)X
+976 3387(Options:)N
+1336(None.)X
+3 f
+776 3567(!)N
+823(argument\(s\))X
+776 3657([range]!)N
+1073(argument\(s\))X
+1 f
+976 3747(Execute)N
+1263(a)X
+1327(shell)X
+1506(command,)X
+1870(or)X
+1966(\256lter)X
+2146(lines)X
+2326(through)X
+2604(a)X
+2669(shell)X
+2849(command.)X
+3234(In)X
+3330(the)X
+3457(\256rst)X
+3610(synopsis,)X
+3934(the)X
+976 3837(remainder)N
+1333(of)X
+1430(the)X
+1558(line)X
+1708(after)X
+1886(the)X
+2014(``)X
+7 f
+2068(!)X
+1 f
+('')S
+2220(character)X
+2546(is)X
+2629(passed)X
+2873(to)X
+2965(the)X
+3093(program)X
+3395(named)X
+3639(by)X
+3749(the)X
+3 f
+3877(shell)X
+1 f
+976 3927(option,)N
+1220(as)X
+1307(a)X
+1363(single)X
+1574(argument.)X
+976 4107(Within)N
+1227(the)X
+1354(rest)X
+1499(of)X
+1595(the)X
+1722(line,)X
+1891(``)X
+7 f
+1945(%)X
+1 f
+('')S
+2076(and)X
+2221(``)X
+7 f
+2275(#)X
+1 f
+('')S
+2407(are)X
+2536(expanded)X
+2874(into)X
+3028(the)X
+3156(current)X
+3414(and)X
+3560(alternate)X
+3867(path-)X
+976 4197(names,)N
+1223(respectively.)X
+1673(The)X
+1820(character)X
+2138(``)X
+7 f
+2192(!)X
+1 f
+('')S
+2336(is)X
+2411(expanded)X
+2741(with)X
+2904(the)X
+3023(command)X
+3360(text)X
+3501(of)X
+3589(the)X
+3708(previous)X
+3 f
+4005(!)X
+1 f
+976 4287(command.)N
+1354 0.3125(\(Therefore,)AX
+1741(the)X
+1861(command)X
+3 f
+2199(!!)X
+1 f
+2295(repeats)X
+2545(the)X
+2665(previous)X
+3 f
+2963(!)X
+1 f
+3032(command.\))X
+3437(The)X
+3585(special)X
+3831(mean-)X
+976 4377(ings)N
+1130(of)X
+1218(``)X
+7 f
+1272(%)X
+1 f
+('',)S
+1415(``)X
+7 f
+1469(#)X
+1 f
+('',)S
+1612(and)X
+1749(``)X
+7 f
+1803(!)X
+1 f
+('')S
+1946(can)X
+2079(be)X
+2176(overridden)X
+2545(by)X
+2646(escaping)X
+2948(them)X
+3129(with)X
+3292(a)X
+3349(backslash.)X
+3722(If)X
+3797(no)X
+3 f
+3898(!)X
+1 f
+3965(or)X
+3 f
+976 4467(:!)N
+1 f
+1075(command)X
+1416(has)X
+1548(yet)X
+1671(been)X
+1848(executed,)X
+2179(it)X
+2248(is)X
+2326(an)X
+2427(error)X
+2609(to)X
+2696(use)X
+2828(an)X
+2929(unescaped)X
+3290(``)X
+7 f
+3344(!)X
+1 f
+('')S
+3492(character.)X
+3854(The)X
+3 f
+4005(!)X
+1 f
+976 4557(command)N
+1325(does)X
+2 f
+1505(not)X
+1 f
+1640(do)X
+1752(shell)X
+1935(expansion)X
+2292(on)X
+2404(the)X
+2534(strings)X
+2779(provided)X
+3096(as)X
+3195(arguments.)X
+3601(If)X
+3687(any)X
+3835(of)X
+3934(the)X
+976 4647(above)N
+1197(expansions)X
+1582(change)X
+1839(the)X
+1966(command)X
+2311(the)X
+2438(user)X
+2602(entered,)X
+2889(the)X
+3017(command)X
+3363(is)X
+3446(redisplayed)X
+3846(at)X
+3934(the)X
+976 4737(bottom)N
+1222(of)X
+1309(the)X
+1427(screen.)X
+3 f
+976 4917(Ex)N
+1 f
+1092(then)X
+1253(executes)X
+1553(the)X
+1674(program)X
+1969(named)X
+2206(by)X
+2309(the)X
+3 f
+2430(shell)X
+1 f
+2608(option,)X
+2855(with)X
+3020(a)X
+3 f
+9 f
+3079(-)X
+3081(-)X
+3 f
+3125(c)X
+1 f
+3184(\257ag)X
+3327(followed)X
+3636(by)X
+3740(the)X
+3862(argu-)X
+976 5007(ments)N
+1187(\(which)X
+1430(are)X
+1549(bundled)X
+1827(into)X
+1971(a)X
+2027(single)X
+2238(argument\).)X
+976 5187(The)N
+3 f
+1121(!)X
+1 f
+1188(command)X
+1524(is)X
+1597(permitted)X
+1924(in)X
+2006(an)X
+2102(empty)X
+2322(\256le.)X
+976 5367(If)N
+1050(the)X
+1168(\256le)X
+1290(has)X
+1417(been)X
+1589(modi\256ed)X
+1893(since)X
+2078(it)X
+2142(was)X
+2287(last)X
+2418(completely)X
+2794(written,)X
+3061(the)X
+3179(command)X
+3515(will)X
+3659(warn)X
+3840(you.)X
+976 5547(A)N
+1054(single)X
+1265(``)X
+7 f
+1319(!)X
+1 f
+('')S
+1461(character)X
+1777(is)X
+1850(displayed)X
+2177(when)X
+2371(the)X
+2489(command)X
+2825(completes.)X
+976 5727(In)N
+1064(the)X
+1183(second)X
+1427(form)X
+1604(of)X
+1692(the)X
+3 f
+1811(!)X
+1 f
+1879(command,)X
+2236(the)X
+2355(remainder)X
+2702(of)X
+2790(the)X
+2909(line)X
+3051(after)X
+3221(the)X
+3341(``)X
+7 f
+3395(!)X
+1 f
+('')S
+3539(is)X
+3614(passed)X
+3850(to)X
+3934(the)X
+
+35 p
+%%Page: 35 34
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Ex)X
+1377(Commands\))X
+3658(USD:13-35)X
+1 f
+976 762(program)N
+1273(named)X
+1512(by)X
+1617(the)X
+3 f
+1740(shell)X
+1 f
+1920(option,)X
+2169(as)X
+2261(described)X
+2594(above.)X
+2851(The)X
+3001(speci\256ed)X
+3311(lines)X
+3487(are)X
+3610(passed)X
+3848(to)X
+3934(the)X
+976 852(program)N
+1273(as)X
+1365(standard)X
+1662(input,)X
+1871(and)X
+2012(the)X
+2135(standard)X
+2432(and)X
+2573(standard)X
+2871(error)X
+3054(output)X
+3284(of)X
+3377(the)X
+3501(program)X
+3799(replace)X
+976 942(the)N
+1094(original)X
+1363(lines.)X
+976 1122(Line:)N
+1336(Unchanged)X
+1722(if)X
+1791(no)X
+1891(range)X
+2090(was)X
+2235(speci\256ed,)X
+2560(otherwise)X
+2892(set)X
+3001(to)X
+3083(the)X
+3201(\256rst)X
+3345(line)X
+3485(of)X
+3572(the)X
+3690(range.)X
+976 1212(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(autowrite)X
+1 f
+2206(and)X
+3 f
+2342(writeany)X
+1 f
+2665(options.)X
+3 f
+776 1392([range])N
+1046(nu[mber])X
+1391([count])X
+1656([\257ags])X
+776 1482([range])N
+1046(#)X
+1106([count])X
+1371([\257ags])X
+1 f
+976 1572(Display)N
+1245(the)X
+1363(selected)X
+1642(lines,)X
+1833(each)X
+2001(preceded)X
+2312(with)X
+2474(its)X
+2569(line)X
+2709(number.)X
+976 1752(The)N
+1121(line)X
+1261(number)X
+1526(format)X
+1760(is)X
+1833(``%6d'',)X
+2128(followed)X
+2433(by)X
+2533(two)X
+2673(spaces.)X
+976 1932(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(last)X
+1789(line)X
+1929(displayed.)X
+976 2022(Options:)N
+1336(None.)X
+3 f
+776 2202(@)N
+870(buffer)X
+776 2292(*)N
+836(buffer)X
+1 f
+976 2382(Execute)N
+1255(a)X
+1311(buffer.)X
+1568(Each)X
+1749(line)X
+1890(in)X
+1973(the)X
+2092(named)X
+2327(buffer)X
+2545(is)X
+2619(executed)X
+2926(as)X
+3014(an)X
+3 f
+3111(ex)X
+1 f
+3208(command.)X
+3585(If)X
+3660(no)X
+3761(buffer)X
+3979(is)X
+976 2472(speci\256ed,)N
+1301(or)X
+1388(if)X
+1457(the)X
+1575(speci\256ed)X
+1880(buffer)X
+2097(is)X
+2170(``)X
+7 f
+2224(@)X
+1 f
+('')S
+2346(or)X
+2433(``)X
+7 f
+2487(*)X
+1 f
+('',)S
+2629(the)X
+2747(last)X
+2878(buffer)X
+3095(executed)X
+3401(is)X
+3474(used.)X
+3 f
+776 2652([range])N
+1046(<[<)X
+1185(...])X
+1292([count])X
+1557([\257ags])X
+1 f
+976 2742(Shift)N
+1154(lines)X
+1328(left)X
+1458(or)X
+1548(right.)X
+1762(The)X
+1910(speci\256ed)X
+2218(lines)X
+2392(are)X
+2514(shifted)X
+2755(to)X
+2840(the)X
+2961(left)X
+3091(\(for)X
+3235(the)X
+3 f
+3356(<)X
+1 f
+3425(command\))X
+3791(or)X
+3881(right)X
+976 2832(\(for)N
+1130(the)X
+3 f
+1261(>)X
+1 f
+1340(command\),)X
+1736(by)X
+1849(the)X
+1980(number)X
+2257(of)X
+2356(columns)X
+2659(speci\256ed)X
+2976(by)X
+3088(the)X
+3 f
+3218(shiftwidth)X
+1 f
+3596(option.)X
+3872(Only)X
+976 2922(leading)N
+1237(whitespace)X
+1619(characters)X
+1971(are)X
+2095(deleted)X
+2352(when)X
+2552(shifting)X
+2822(left;)X
+2977(once)X
+3155(the)X
+3279(\256rst)X
+3429(column)X
+3695(of)X
+3788(the)X
+3912(line)X
+976 3012(contains)N
+1283(a)X
+1359(nonblank)X
+1697(character,)X
+2053(the)X
+3 f
+2191(shift)X
+1 f
+2382(command)X
+2738(will)X
+2901(succeed,)X
+3215(but)X
+3356(the)X
+3493(line)X
+3652(will)X
+3815(not)X
+3956(be)X
+976 3102(modi\256ed.)N
+976 3282(If)N
+1050(the)X
+1168(command)X
+1504(character)X
+3 f
+1820(<)X
+1 f
+1886(or)X
+3 f
+1973(>)X
+1 f
+2039(is)X
+2112(repeated)X
+2405(more)X
+2590(than)X
+2748(once,)X
+2941(the)X
+3060(command)X
+3397(is)X
+3471(repeated)X
+3765(once)X
+3938(for)X
+976 3372(each)N
+1144(additional)X
+1484(command)X
+1820(character.)X
+976 3552(Line:)N
+1336(If)X
+1416(the)X
+1540(current)X
+1794(line)X
+1940(is)X
+2019(set)X
+2134(to)X
+2222(one)X
+2364(of)X
+2457(the)X
+2581(lines)X
+2758(that)X
+2904(are)X
+3029(affected)X
+3315(by)X
+3421(the)X
+3545(command,)X
+3908(it)X
+3979(is)X
+1336 3642(unchanged.)N
+1751(Otherwise,)X
+2128(it)X
+2199(is)X
+2279(set)X
+2395(to)X
+2484(the)X
+2609(\256rst)X
+2760(nonblank)X
+3085(character)X
+3408(of)X
+3502(the)X
+3627(lowest)X
+3863(num-)X
+1336 3732(bered)N
+1535(line)X
+1675(shifted.)X
+976 3822(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(shiftwidth)X
+1 f
+2222(option.)X
+3 f
+776 4002([line])N
+974(=)X
+1040([\257ags])X
+1 f
+976 4092(Display)N
+1250(the)X
+1373(line)X
+1518(number.)X
+1828(Display)X
+2102(the)X
+2225(line)X
+2370(number)X
+2640(of)X
+7 f
+2732(line)X
+1 f
+2949(\(which)X
+3197(defaults)X
+3476(to)X
+3563(the)X
+3687(last)X
+3824(line)X
+3970(in)X
+976 4182(the)N
+1094(\256le\).)X
+976 4362(Line:)N
+1336(Unchanged.)X
+976 4452(Options:)N
+1336(None.)X
+3 f
+776 4632([range])N
+1046(>[>)X
+1185(...])X
+1292([count])X
+1557([\257ags])X
+1 f
+976 4722(Shift)N
+1155(right.)X
+1370(The)X
+1519(speci\256ed)X
+1828(lines)X
+2003(are)X
+2127(shifted)X
+2370(to)X
+2457(the)X
+2580(right)X
+2756(by)X
+2861(the)X
+2984(number)X
+3254(of)X
+3346(columns)X
+3642(speci\256ed)X
+3952(by)X
+976 4812(the)N
+3 f
+1094(shiftwidth)X
+1 f
+1460(option,)X
+1704(by)X
+1804(inserting)X
+2104(tab)X
+2222(and)X
+2358(space)X
+2557(characters.)X
+2944(Empty)X
+3177(lines)X
+3348(are)X
+3467(not)X
+3589(changed.)X
+976 4992(If)N
+1053(the)X
+1174(command)X
+1513(character)X
+1832(``)X
+7 f
+1886(>)X
+1 f
+('')S
+2011(is)X
+2087(repeated)X
+2383(more)X
+2571(than)X
+2732(once,)X
+2927(the)X
+3048(command)X
+3388(is)X
+3465(repeated)X
+3762(once)X
+3938(for)X
+976 5082(each)N
+1144(additional)X
+1484(command)X
+1820(character.)X
+976 5262(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(last)X
+1789(line)X
+1929(modi\256ed)X
+2233(by)X
+2333(the)X
+2451(command.)X
+976 5352(Options:)N
+1336(None.)X
+3 f
+776 5532(ab[brev])N
+1090(lhs)X
+1207(rhs)X
+1 f
+976 5622(Add)N
+1135(an)X
+1232(abbreviation)X
+1654(to)X
+1737(the)X
+1856(current)X
+2105(abbreviation)X
+2527(list.)X
+2686(In)X
+3 f
+2775(vi)X
+1 f
+2837(,)X
+2879(if)X
+7 f
+2950(lhs)X
+1 f
+3116(is)X
+3191(entered)X
+3450(such)X
+3619(that)X
+3761(it)X
+3827(is)X
+3902(pre-)X
+976 5712(ceded)N
+1194(and)X
+1340(followed)X
+1655(by)X
+1765(characters)X
+2122(that)X
+2272(cannot)X
+2516(be)X
+2622(part)X
+2777(of)X
+2874(a)X
+2940(word,)X
+3155(it)X
+3229(is)X
+3312(replaced)X
+3614(by)X
+3723(the)X
+3850(string)X
+7 f
+976 5802(rhs)N
+1 f
+(.)S
+
+36 p
+%%Page: 36 35
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-36)N
+2813(Nvi/Nex)X
+3109 0.3906(Reference)AX
+3474(\(Ex)X
+3614(Commands\))X
+1 f
+976 762(Line:)N
+1336(Unchanged.)X
+976 852(Options:)N
+1336(None.)X
+3 f
+776 1032([line])N
+974(a[ppend][!])X
+1 f
+976 1122(The)N
+1123(input)X
+1309(text)X
+1451(is)X
+1526(appended)X
+1856(to)X
+1940(the)X
+2060(speci\256ed)X
+2367(line.)X
+2549(If)X
+2626(line)X
+2769(0)X
+2832(is)X
+2908(speci\256ed,)X
+3236(the)X
+3357(text)X
+3500(is)X
+3576(inserted)X
+3853(at)X
+3934(the)X
+976 1212(beginning)N
+1317(of)X
+1405(the)X
+1524(\256le.)X
+1687(Set)X
+1810(to)X
+1893(the)X
+2012(last)X
+2144(line)X
+2285(input.)X
+2510(If)X
+2585(no)X
+2686(lines)X
+2858(are)X
+2978(input,)X
+3183(then)X
+3342(set)X
+3451(to)X
+7 f
+3533(line)X
+1 f
+(,)S
+3765(or)X
+3852(to)X
+3934(the)X
+976 1302(\256rst)N
+1125(line)X
+1270(of)X
+1362(the)X
+1485(\256le)X
+1612(if)X
+1686(a)X
+7 f
+1747(line)X
+1 f
+1965(of)X
+2058(0)X
+2124(was)X
+2275(speci\256ed.)X
+2626(Following)X
+2980(the)X
+3104(command)X
+3446(name)X
+3646(with)X
+3814(a)X
+3876(``)X
+7 f
+3930(!)X
+1 f
+('')S
+976 1392(character)N
+1292(causes)X
+1522(the)X
+3 f
+1640(autoindent)X
+1 f
+2028(option)X
+2252(to)X
+2334(be)X
+2430(toggled)X
+2690(for)X
+2804(the)X
+2922(duration)X
+3209(of)X
+3296(the)X
+3414(command.)X
+976 1572(Line:)N
+1336(Unchanged.)X
+976 1662(Options:)N
+1336(Affected)X
+1661(by)X
+1784(the)X
+3 f
+1925(altwerase)X
+1 f
+2251(,)X
+3 f
+2314(autoindent)X
+1 f
+2682(,)X
+3 f
+2746(beautify)X
+1 f
+(,)S
+3 f
+3090(showmatch)X
+1 f
+3477(,)X
+3 f
+3541(ttywerase)X
+1 f
+3916(and)X
+3 f
+1336 1752(wrapmargin)N
+1 f
+1783(options.)X
+3 f
+776 1932(ar[gs])N
+1 f
+976 2022(Display)N
+1248(the)X
+1369(argument)X
+1695(list.)X
+1855(The)X
+2003(current)X
+2254(argument)X
+2580(is)X
+2657(displayed)X
+2988(inside)X
+3203(of)X
+3294(``)X
+7 f
+3348([)X
+1 f
+('')S
+3474(and)X
+3614(``)X
+7 f
+3668(])X
+1 f
+('')S
+3794(charac-)X
+976 2112(ters.)N
+1154(The)X
+1300(argument)X
+1624(list)X
+1742(is)X
+1816(the)X
+1935(list)X
+2053(of)X
+2141(operands)X
+2452(speci\256ed)X
+2758(on)X
+2859(startup,)X
+3118(which)X
+3335(can)X
+3468(be)X
+3565(replaced)X
+3859(using)X
+976 2202(the)N
+3 f
+1094(next)X
+1 f
+1261(command.)X
+976 2382(Line:)N
+1336(Unchanged.)X
+976 2472(Options:)N
+1336(None.)X
+3 f
+776 2652(bg)N
+976 2742(Vi)N
+1 f
+1076(mode)X
+1274(only.)X
+1476(Background)X
+1888(the)X
+2006(current)X
+2254(screen.)X
+976 2922(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(current)X
+1906(line)X
+2046(when)X
+2240(the)X
+2358(screen)X
+2584(was)X
+2729(last)X
+2860(edited.)X
+976 3012(Options:)N
+1336(None.)X
+3 f
+776 3192([range])N
+1046(c[hange][!])X
+1441([count])X
+1 f
+976 3282(Replace)N
+1256(the)X
+1375(lines)X
+1548(with)X
+1712(input)X
+1898(text.)X
+2080(Following)X
+2430(the)X
+2550(command)X
+2888(name)X
+3084(with)X
+3248(a)X
+3306(``)X
+7 f
+3360(!)X
+1 f
+('')S
+3504(character)X
+3822(causes)X
+976 3372(the)N
+3 f
+1094(autoindent)X
+1 f
+1482(option)X
+1706(to)X
+1788(be)X
+1884(toggled)X
+2144(for)X
+2258(the)X
+2376(duration)X
+2663(of)X
+2750(the)X
+2868(command.)X
+976 3552(Line:)N
+1336(Set)X
+1463(to)X
+1550(the)X
+1673(last)X
+1809(line)X
+1954(input,)X
+2163(or,)X
+2275(if)X
+2349(no)X
+2454(lines)X
+2630(were)X
+2812(input,)X
+3021(set)X
+3135(to)X
+3223(the)X
+3347(line)X
+3493(before)X
+3725(the)X
+3849(target)X
+1336 3642(line,)N
+1496(or)X
+1583(to)X
+1665(the)X
+1783(\256rst)X
+1927(line)X
+2067(of)X
+2154(the)X
+2272(\256le)X
+2394(if)X
+2463(there)X
+2644(are)X
+2763(no)X
+2863(lines)X
+3034(preceding)X
+3371(the)X
+3489(target)X
+3692(line.)X
+976 3732(Options:)N
+1336(Affected)X
+1661(by)X
+1784(the)X
+3 f
+1925(altwerase)X
+1 f
+2251(,)X
+3 f
+2314(autoindent)X
+1 f
+2682(,)X
+3 f
+2746(beautify)X
+1 f
+(,)S
+3 f
+3090(showmatch)X
+1 f
+3477(,)X
+3 f
+3541(ttywerase)X
+1 f
+3916(and)X
+3 f
+1336 3822(wrapmargin)N
+1 f
+1783(options.)X
+3 f
+776 4002(chd[ir][!])N
+1113([directory])X
+776 4092(cd[!])N
+957([directory])X
+1 f
+976 4182(Change)N
+1244(the)X
+1365(current)X
+1616(working)X
+1906(directory.)X
+2259(The)X
+7 f
+2407(directory)X
+1 f
+2862(argument)X
+3188(is)X
+3265(subjected)X
+3592(to)X
+2 f
+3678(sh)X
+1 f
+3749(\(1\))X
+3867(word)X
+976 4272(expansions.)N
+1395(When)X
+1610(invoked)X
+1891(with)X
+2056(no)X
+2159(directory)X
+2472(argument)X
+2798(and)X
+2937(the)X
+7 f
+3057(HOME)X
+1 f
+3271(environment)X
+3698(variable)X
+3979(is)X
+976 4362(set,)N
+1105(the)X
+1223(directory)X
+1533(named)X
+1767(by)X
+1867(the)X
+7 f
+1985(HOME)X
+1 f
+2197(environment)X
+2622(variable)X
+2901(becomes)X
+3202(the)X
+3320(new)X
+3474(current)X
+3722(directory.)X
+976 4452(Otherwise,)N
+1353(the)X
+1478(new)X
+1639(current)X
+1894(directory)X
+2211(becomes)X
+2519(the)X
+2644(directory)X
+2961(returned)X
+3256(by)X
+3363(the)X
+2 f
+3488(getpwent)X
+1 f
+3777(\(3\))X
+3898(rou-)X
+976 4542(tine.)N
+976 4722(The)N
+3 f
+1125(chdir)X
+1 f
+1331(command)X
+1671(will)X
+1819(fail)X
+1950(if)X
+2023(the)X
+2145(\256le)X
+2271(has)X
+2402(been)X
+2578(modi\256ed)X
+2886(since)X
+3075(the)X
+3197(last)X
+3333(complete)X
+3652(write)X
+3842(of)X
+3934(the)X
+976 4812(\256le.)N
+1138(You)X
+1296(can)X
+1428(override)X
+1716(this)X
+1851(check)X
+2059(by)X
+2159(appending)X
+2513(a)X
+2569(``)X
+7 f
+2623(!)X
+1 f
+('')S
+2765(character)X
+3081(to)X
+3163(the)X
+3281(command.)X
+976 4992(Line:)N
+1336(Unchanged.)X
+976 5082(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(cdpath)X
+1 f
+2111(option.)X
+3 f
+776 5262([range])N
+1046(co[py])X
+1280(line)X
+1424([\257ags])X
+776 5352([range])N
+1046(t)X
+1093(line)X
+1237([\257ags])X
+1 f
+976 5442(Copy)N
+1169(the)X
+1288(speci\256ed)X
+1594(lines)X
+1766(\(range\))X
+2020(after)X
+2189(the)X
+2308(destination)X
+2680(line.)X
+2861(Line)X
+3029(0)X
+3090(may)X
+3249(be)X
+3346(speci\256ed)X
+3652(to)X
+3735(insert)X
+3934(the)X
+976 5532(lines)N
+1147(at)X
+1225(the)X
+1343(beginning)X
+1683(of)X
+1770(the)X
+1888(\256le.)X
+976 5712(Line:)N
+1336(Unchanged.)X
+
+37 p
+%%Page: 37 36
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Ex)X
+1377(Commands\))X
+3658(USD:13-37)X
+1 f
+976 762(Options:)N
+1336(None.)X
+3 f
+776 942([range])N
+1046(d[elete])X
+1321([buffer])X
+1609([count])X
+1874([\257ags])X
+1 f
+976 1032(Delete)N
+1208(the)X
+1329(lines)X
+1503(from)X
+1682(the)X
+1803(\256le.)X
+1968(The)X
+2116(deleted)X
+2371(text)X
+2514(is)X
+2590(saved)X
+2796(in)X
+2881(the)X
+3002(speci\256ed)X
+3310(buffer,)X
+3550(or,)X
+3660(if)X
+3732(no)X
+3835(buffer)X
+976 1122(is)N
+1051(speci\256ed,)X
+1378(in)X
+1462(the)X
+1582(unnamed)X
+1898(buffer.)X
+2157(If)X
+2233(the)X
+2353(command)X
+2691(name)X
+2887(is)X
+2962(followed)X
+3269(by)X
+3371(a)X
+3429(letter)X
+3616(that)X
+3757(could)X
+3956(be)X
+976 1212(interpreted)N
+1346(as)X
+1435(either)X
+1640(a)X
+1698(buffer)X
+1917(name)X
+2113(or)X
+2202(a)X
+2261(\257ag)X
+2404(value)X
+2601(\(because)X
+2906(neither)X
+3152(a)X
+7 f
+3211(count)X
+1 f
+3474(or)X
+7 f
+3564(flags)X
+1 f
+3827(values)X
+976 1302(were)N
+1160(given\),)X
+3 f
+1412(ex)X
+1 f
+1515(treats)X
+1716(the)X
+1841(letter)X
+2033(as)X
+2127(a)X
+7 f
+2190(flags)X
+1 f
+2457(value)X
+2658(if)X
+2734(the)X
+2859(letter)X
+3051(immediately)X
+3477(follows)X
+3743(the)X
+3867(com-)X
+976 1392(mand)N
+1174(name,)X
+1388(without)X
+1652(any)X
+1788(whitespace)X
+2165(separation.)X
+2555(If)X
+2629(the)X
+2747(letter)X
+2932(is)X
+3005(preceded)X
+3316(by)X
+3416(whitespace)X
+3794(charac-)X
+976 1482(ters,)N
+1132(it)X
+1196(treats)X
+1390(it)X
+1454(as)X
+1541(a)X
+1597(buffer)X
+1814(name.)X
+976 1662(Line:)N
+1336(Set)X
+1459(to)X
+1542(the)X
+1661(line)X
+1802(following)X
+2134(the)X
+2253(deleted)X
+2506(lines,)X
+2698(or)X
+2786(to)X
+2869(the)X
+2988(last)X
+3120(line)X
+3261(if)X
+3331(the)X
+3450(deleted)X
+3703(lines)X
+3875(were)X
+1336 1752(at)N
+1414(the)X
+1532(end.)X
+976 1842(Options:)N
+1336(None.)X
+3 f
+776 2022(di[splay])N
+1093(b[uffers])X
+1412(|)X
+1450(s[creens])X
+1774(|)X
+1812(t[ags])X
+1 f
+976 2112(Display)N
+1256(buffers,)X
+1535(screens)X
+1803(or)X
+1901(tags.)X
+2101(The)X
+3 f
+2257(display)X
+1 f
+2531(command)X
+2878(takes)X
+3074(one)X
+3221(of)X
+3319(three)X
+3511(additional)X
+3862(argu-)X
+976 2202(ments,)N
+1207(which)X
+1423(are)X
+1542(as)X
+1629(follows:)X
+976 2382(b[uffers])N
+1336(Display)X
+1605(all)X
+1705(buffers)X
+1953(\(including)X
+2302(named,)X
+2556(unnamed,)X
+2890(and)X
+3026(numeric\))X
+3336(that)X
+3476(contain)X
+3732(text.)X
+976 2472(s[creens])N
+1336(Display)X
+1605(the)X
+1723(\256le)X
+1845(names)X
+2070(of)X
+2157(all)X
+2257(background)X
+2656(screens.)X
+976 2562(t[ags])N
+1336(Display)X
+1605(the)X
+1723(tags)X
+1872(stack.)X
+976 2742(Line:)N
+1336(Unchanged.)X
+976 2832(Options:)N
+1336(None.)X
+3 f
+776 3012(e[dit][!])N
+1060([+cmd])X
+1327([\256le])X
+776 3102(ex[!])N
+953([+cmd])X
+1220([\256le])X
+1 f
+976 3192(Edit)N
+1133(a)X
+1193(different)X
+1494(\256le.)X
+1661(If)X
+1740(the)X
+1863(current)X
+2116(buffer)X
+2338(has)X
+2470(been)X
+2647(modi\256ed)X
+2956(since)X
+3146(the)X
+3269(last)X
+3405(complete)X
+3724(write,)X
+3934(the)X
+976 3282(command)N
+1324(will)X
+1480(fail.)X
+1659(You)X
+1829(can)X
+1972(override)X
+2271(this)X
+2417(by)X
+2528(appending)X
+2893(a)X
+2960(``)X
+7 f
+3014(!)X
+1 f
+('')S
+3167(character)X
+3494(to)X
+3587(the)X
+3716(command)X
+976 3372(name.)N
+976 3552(If)N
+1053(the)X
+1174(``)X
+7 f
+1228(+cmd)X
+1 f
+('')S
+1497(option)X
+1724(is)X
+1800(speci\256ed,)X
+2128(that)X
+3 f
+2271(ex)X
+1 f
+2370(command)X
+2709(will)X
+2856(be)X
+2955(executed)X
+3264(in)X
+3349(the)X
+3470(new)X
+3628(\256le.)X
+3794(Any)X
+3 f
+3956(ex)X
+1 f
+976 3642(command)N
+1326(may)X
+1498(be)X
+1607(used,)X
+1807(although)X
+2120(the)X
+2251(most)X
+2439(common)X
+2752(use)X
+2892(of)X
+2992(this)X
+3140(feature)X
+3397(is)X
+3483(to)X
+3578(specify)X
+3843(a)X
+3912(line)X
+976 3732(number)N
+1241(or)X
+1328(search)X
+1554(pattern)X
+1797(to)X
+1879(set)X
+1988(the)X
+2106(initial)X
+2312(location)X
+2590(in)X
+2672(the)X
+2790(new)X
+2944(\256le.)X
+976 3912(Line:)N
+1336(If)X
+1415(you)X
+1560(have)X
+1737(previously)X
+2100(edited)X
+2321(the)X
+2444(\256le,)X
+2591(the)X
+2714(current)X
+2967(line)X
+3112(will)X
+3261(be)X
+3362(set)X
+3476(to)X
+3563(your)X
+3735(last)X
+3872(posi-)X
+1336 4002(tion)N
+1482(in)X
+1566(the)X
+1686(\256le.)X
+1850(If)X
+1926(that)X
+2068(position)X
+2347(does)X
+2516(not)X
+2640(exist,)X
+2833(or)X
+2921(you)X
+3062(have)X
+3235(not)X
+3358(previously)X
+3717(edited)X
+3934(the)X
+1336 4092(\256le,)N
+1481(the)X
+1602(current)X
+1853(line)X
+1996(will)X
+2143(be)X
+2242(set)X
+2354(to)X
+2439(the)X
+2560(\256rst)X
+2707(line)X
+2850(of)X
+2940(the)X
+3061(\256le)X
+3186(if)X
+3258(you)X
+3401(are)X
+3523(in)X
+3 f
+3608(vi)X
+1 f
+3694(mode,)X
+3916(and)X
+1336 4182(the)N
+1454(last)X
+1585(line)X
+1725(of)X
+1812(the)X
+1930(\256le)X
+2052(if)X
+2121(you)X
+2261(are)X
+2380(in)X
+3 f
+2462(ex)X
+1 f
+2538(.)X
+976 4272(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(autowrite)X
+1 f
+2206(and)X
+3 f
+2342(writeany)X
+1 f
+2665(options.)X
+3 f
+776 4452(exu[sage])N
+1117([command])X
+1 f
+976 4542(Display)N
+1249(usage)X
+1456(for)X
+1574(an)X
+3 f
+1674(ex)X
+1 f
+1774(command.)X
+2154(If)X
+7 f
+2233(command)X
+1 f
+2594(is)X
+2672(speci\256ed,)X
+3002(a)X
+3063(usage)X
+3271(statement)X
+3603(for)X
+3722(that)X
+3867(com-)X
+976 4632(mand)N
+1174(is)X
+1247(displayed.)X
+1614(Otherwise,)X
+1984(usage)X
+2187(statements)X
+2545(for)X
+2659(all)X
+3 f
+2759(ex)X
+1 f
+2855(commands)X
+3222(are)X
+3341(displayed.)X
+976 4812(Line:)N
+1336(Unchanged.)X
+976 4902(Options:)N
+1336(None.)X
+3 f
+776 5082(f[ile])N
+957([\256le])X
+1 f
+976 5172(Display)N
+1249(and)X
+1389(optionally)X
+1737(change)X
+1989(the)X
+2111(\256le)X
+2237(name.)X
+2475(If)X
+2553(a)X
+2613(\256le)X
+2739(name)X
+2937(is)X
+3014(speci\256ed,)X
+3344(the)X
+3467(current)X
+3720(pathname)X
+976 5262(is)N
+1054(changed)X
+1347(to)X
+1434(the)X
+1557(speci\256ed)X
+1867(name.)X
+2106(The)X
+2256(current)X
+2509(pathname,)X
+2865(the)X
+2987(number)X
+3256(of)X
+3347(lines,)X
+3542(and)X
+3682(the)X
+3804(current)X
+976 5352(position)N
+1253(in)X
+1335(the)X
+1453(\256le)X
+1575(are)X
+1694(displayed.)X
+976 5532(Line:)N
+1336(Unchanged.)X
+976 5622(Options:)N
+1336(None.)X
+
+38 p
+%%Page: 38 37
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-38)N
+2813(Nvi/Nex)X
+3109 0.3906(Reference)AX
+3474(\(Ex)X
+3614(Commands\))X
+776 762(fg)N
+863([name])X
+976 852(Vi)N
+1 f
+1085(mode)X
+1292(only.)X
+1503(Foreground)X
+1906(the)X
+2033(speci\256ed)X
+2347(screen.)X
+2622(Swap)X
+2829(the)X
+2956(current)X
+3213(screen)X
+3448(with)X
+3619(the)X
+3747(speci\256ed)X
+976 942(backgrounded)N
+1451(screen.)X
+1717(If)X
+1791(no)X
+1891(screen)X
+2117(is)X
+2190(speci\256ed,)X
+2515(the)X
+2633(\256rst)X
+2777(background)X
+3176(screen)X
+3402(is)X
+3475(foregrounded.)X
+976 1122(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(current)X
+1906(line)X
+2046(when)X
+2240(the)X
+2358(screen)X
+2584(was)X
+2729(last)X
+2860(edited.)X
+976 1212(Options:)N
+1336(None.)X
+3 f
+776 1392([range])N
+1046(g[lobal])X
+1328(/pattern/)X
+1646([commands])X
+776 1482([range])N
+1046(v)X
+1106(/pattern/)X
+1424([commands])X
+1 f
+976 1572(Apply)N
+1206(commands)X
+1583(to)X
+1675(lines)X
+1856(matching)X
+2184(\(or)X
+2308(not)X
+2440(matching\))X
+2795(a)X
+2861(pattern.)X
+3154(The)X
+3309(lines)X
+3490(within)X
+3725(the)X
+3854(given)X
+976 1662(range)N
+1191(that)X
+1347(match)X
+1579(\(``)X
+7 f
+1660(g[lobal])X
+1 f
+(''\),)S
+2181(or)X
+2284(do)X
+2400(not)X
+2538(match)X
+2770(\(``)X
+7 f
+2851(v)X
+1 f
+(''\))S
+3015(the)X
+3148(given)X
+3361(pattern)X
+3619(are)X
+3753(selected.)X
+976 1752(Then,)N
+1197(the)X
+1331(speci\256ed)X
+3 f
+1652(ex)X
+1 f
+1764(command\(s\))X
+2201(are)X
+2336(executed)X
+2658(with)X
+2836(the)X
+2970(current)X
+3235(line)X
+3392(\(``)X
+7 f
+3473(.)X
+1 f
+(''\))S
+3659(set)X
+3785(to)X
+3884(each)X
+976 1842(selected)N
+1257(line.)X
+1439(If)X
+1515(no)X
+1617(range)X
+1818(is)X
+1893(speci\256ed,)X
+2220(the)X
+2340(entire)X
+2545(\256le)X
+2669(is)X
+2744(searched)X
+3048(for)X
+3164(matching,)X
+3503(or)X
+3591(not)X
+3714(matching,)X
+976 1932(lines.)N
+976 2112(Multiple)N
+1279(commands)X
+1654(can)X
+1794(be)X
+1899(speci\256ed,)X
+2233(one)X
+2378(per)X
+2510(line,)X
+2679(by)X
+2788(escaping)X
+3098(each)X
+7 f
+3275(<newline>)X
+1 f
+3736(character)X
+976 2202(with)N
+1152(a)X
+1222(backslash,)X
+1588(or)X
+1689(by)X
+1803(separating)X
+2167(commands)X
+2548(with)X
+2724(a)X
+2794(``)X
+7 f
+2848(|)X
+1 f
+('')S
+2984(character.)X
+3353(If)X
+3440(no)X
+3553(commands)X
+3933(are)X
+976 2292(speci\256ed,)N
+1301(the)X
+1419(command)X
+1755(defaults)X
+2029(to)X
+2111(the)X
+3 f
+2229(print)X
+1 f
+2422(command.)X
+976 2472(For)N
+1111(the)X
+3 f
+1233(append)X
+1 f
+1485(,)X
+3 f
+1529(change)X
+1 f
+1793(and)X
+3 f
+1933(insert)X
+1 f
+2153(commands,)X
+2544(the)X
+2666(input)X
+2854(text)X
+2998(must)X
+3177(be)X
+3277(part)X
+3427(of)X
+3519(the)X
+3642(global)X
+3867(com-)X
+976 2562(mand)N
+1174(line.)X
+1354(In)X
+1441(this)X
+1576(case,)X
+1755(the)X
+1873(terminating)X
+2262(period)X
+2487(can)X
+2619(be)X
+2715(omitted)X
+2979(if)X
+3048(it)X
+3112(ends)X
+3279(the)X
+3397(commands.)X
+976 2742(The)N
+3 f
+1123(visual)X
+1 f
+1344(command)X
+1682(may)X
+1842(also)X
+1993(be)X
+2091(speci\256ed)X
+2398(as)X
+2487(one)X
+2625(of)X
+2714(the)X
+3 f
+2834(ex)X
+1 f
+2933(commands.)X
+3343(In)X
+3433(this)X
+3571(mode,)X
+3792(input)X
+3979(is)X
+976 2832(taken)N
+1173(from)X
+1352(the)X
+1473(terminal.)X
+1803(Entering)X
+2102(a)X
+3 f
+2161(Q)X
+1 f
+2246(command)X
+2585(in)X
+3 f
+2670(vi)X
+1 f
+2755(mode)X
+2956(causes)X
+3189(the)X
+3310(next)X
+3471(line)X
+3614(matching)X
+3934(the)X
+976 2922(pattern)N
+1219(to)X
+1301(be)X
+1397(selected)X
+1676(and)X
+3 f
+1812(vi)X
+1 f
+1894(to)X
+1976(be)X
+2072(reentered,)X
+2412(until)X
+2578(the)X
+2696(list)X
+2813(is)X
+2886(exhausted.)X
+976 3102(The)N
+3 f
+1121(global)X
+1 f
+1329(,)X
+3 f
+1369(v)X
+1 f
+1429(and)X
+3 f
+1565(undo)X
+1 f
+1757(commands)X
+2124(cannot)X
+2358(be)X
+2454(used)X
+2621(as)X
+2708(part)X
+2853(of)X
+2940(these)X
+3125(commands.)X
+976 3282(The)N
+1131(editor)X
+1348(options)X
+3 f
+1613(autoprint)X
+1 f
+1937(,)X
+3 f
+1987(autoindent)X
+1 f
+2355(,)X
+2405(and)X
+3 f
+2551(report)X
+1 f
+2800(are)X
+2929(turned)X
+3164(off)X
+3288(for)X
+3412(the)X
+3540(duration)X
+3837(of)X
+3934(the)X
+3 f
+976 3372(global)N
+1 f
+1204(and)X
+3 f
+1340(v)X
+1 f
+1400(commands.)X
+976 3552(Line:)N
+1336(The)X
+1481(last)X
+1612(line)X
+1752(modi\256ed.)X
+976 3642(Options:)N
+1336(None.)X
+3 f
+776 3822(he[lp])N
+1 f
+3912(Display)Y
+1245(a)X
+1301(help)X
+1459(message.)X
+976 4092(Line:)N
+1336(Unchanged.)X
+976 4182(Options:)N
+1336(None.)X
+3 f
+776 4362([line])N
+974(i[nsert][!])X
+1 f
+976 4452(The)N
+1123(input)X
+1309(text)X
+1451(is)X
+1526(inserted)X
+1803(before)X
+2032(the)X
+2153(speci\256ed)X
+2461(line.)X
+2644(Following)X
+2995(the)X
+3116(command)X
+3455(name)X
+3652(with)X
+3817(a)X
+3876(``)X
+7 f
+3930(!)X
+1 f
+('')S
+976 4542(character)N
+1292(causes)X
+1522(the)X
+3 f
+1640(autoindent)X
+1 f
+2028(option)X
+2252(setting)X
+2485(to)X
+2567(be)X
+2663(toggled)X
+2923(for)X
+3037(the)X
+3155(duration)X
+3442(of)X
+3529(this)X
+3664(command.)X
+976 4722(Line:)N
+1336(Set)X
+1460(to)X
+1544(the)X
+1664(last)X
+1797(line)X
+1939(input;)X
+2147(if)X
+2218(no)X
+2320(lines)X
+2493(were)X
+2672(input,)X
+2878(set)X
+2989(to)X
+3073(the)X
+3193(line)X
+3336(before)X
+3565(the)X
+3686(target)X
+3892(line,)X
+1336 4812(or)N
+1423(to)X
+1505(the)X
+1623(\256rst)X
+1767(line)X
+1907(of)X
+1994(the)X
+2112(\256le)X
+2234(if)X
+2303(there)X
+2484(are)X
+2603(no)X
+2703(lines)X
+2874(preceding)X
+3211(the)X
+3329(target)X
+3532(line.)X
+976 4902(Options:)N
+1336(Affected)X
+1661(by)X
+1784(the)X
+3 f
+1925(altwerase)X
+1 f
+2251(,)X
+3 f
+2314(autoindent)X
+1 f
+2682(,)X
+3 f
+2746(beautify)X
+1 f
+(,)S
+3 f
+3090(showmatch)X
+1 f
+3477(,)X
+3 f
+3541(ttywerase)X
+1 f
+3916(and)X
+3 f
+1336 4992(wrapmargin)N
+1 f
+1783(options.)X
+3 f
+776 5172([range])N
+1046(j[oin][!])X
+1334([count])X
+1599([\257ags])X
+1 f
+976 5262(Join)N
+1129(lines)X
+1300(of)X
+1387(text)X
+1527(together.)X
+976 5442(A)N
+7 f
+1056(count)X
+1 f
+1318(speci\256ed)X
+1625(to)X
+1709(the)X
+1829(command)X
+2167(speci\256es)X
+2465(that)X
+2607(the)X
+2727(last)X
+2860(line)X
+3002(of)X
+3091(the)X
+7 f
+3212(range)X
+1 f
+3475(plus)X
+7 f
+3631(count)X
+1 f
+3894(sub-)X
+976 5532(sequent)N
+1258(lines)X
+1445(will)X
+1605(be)X
+1717(joined.)X
+1993(\(Note,)X
+2232(this)X
+2383(differs)X
+2629(by)X
+2745(one)X
+2897(from)X
+3089(the)X
+3223(general)X
+3496(rule)X
+3657(where)X
+3890(only)X
+7 f
+976 5622(count)N
+1 f
+(-)S
+1263(subsequent)X
+1639(lines)X
+1810(are)X
+1929(affected.\))X
+976 5802(If)N
+1057(the)X
+1182(current)X
+1438(line)X
+1586(ends)X
+1761(with)X
+1931(a)X
+1995(whitespace)X
+2380(character,)X
+2724(all)X
+2832(whitespace)X
+3217(is)X
+3298(stripped)X
+3584(from)X
+3768(the)X
+3894(next)X
+
+39 p
+%%Page: 39 38
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Ex)X
+1377(Commands\))X
+3658(USD:13-39)X
+1 f
+976 762(line.)N
+1160(Otherwise,)X
+1534(if)X
+1607(the)X
+1729(next)X
+1891(line)X
+2035(starts)X
+2228(with)X
+2394(a)X
+2454(open)X
+2634(parenthesis)X
+3019(\(``)X
+7 f
+3100(\()X
+1 f
+(''\),)S
+3272(do)X
+3375(nothing.)X
+3682(Otherwise,)X
+976 852(if)N
+1061(the)X
+1195(current)X
+1459(line)X
+1615(ends)X
+1798(with)X
+1976(a)X
+2049(question)X
+2357(mark)X
+2559(\(``)X
+7 f
+2640(?)X
+1 f
+(''\),)S
+2826(period)X
+3068(\(``)X
+7 f
+3149(.)X
+1 f
+(''\))S
+3335(or)X
+3439(exclamation)X
+3868(point)X
+976 942(\(``)N
+7 f
+1057(!)X
+1 f
+(''\),)S
+1226(insert)X
+1424(two)X
+1564(spaces.)X
+1834(Otherwise,)X
+2204(insert)X
+2402(a)X
+2458(single)X
+2669(space.)X
+976 1122(Appending)N
+1355(a)X
+1414(``)X
+7 f
+1468(!)X
+1 f
+('')S
+1613(character)X
+1932(to)X
+2017(the)X
+2138(command)X
+2477(name)X
+2674(causes)X
+2907(a)X
+2966(simpler)X
+3230(join)X
+3378(with)X
+3544(no)X
+3648(white-space)X
+976 1212(processing.)N
+976 1392(Line:)N
+1336(Unchanged.)X
+976 1482(Options:)N
+1336(None.)X
+3 f
+776 1662([range])N
+1046(l[ist])X
+1222([count])X
+1487([\257ags])X
+1 f
+976 1752(Display)N
+1258(the)X
+1389(lines)X
+1573(unambiguously.)X
+2139(Tabs)X
+2328(are)X
+2460(displayed)X
+2801(as)X
+2902(``)X
+7 f
+2956(\303I)X
+1 f
+('',)S
+3160(and)X
+3310(the)X
+3442(end)X
+3592(of)X
+3693(the)X
+3825(line)X
+3979(is)X
+976 1842(marked)N
+1237(with)X
+1399(a)X
+1455(``)X
+7 f
+1509($)X
+1 f
+('')S
+1631(character.)X
+976 2022(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(last)X
+1789(line)X
+1929(displayed.)X
+976 2112(Options:)N
+1336(None.)X
+3 f
+776 2292(map[!])N
+1028([lhs)X
+1172(rhs])X
+1 f
+976 2382(De\256ne)N
+1210(or)X
+1297(display)X
+1548(maps)X
+1737(\(for)X
+3 f
+1878(vi)X
+1 f
+1960(only\).)X
+976 2562(If)N
+1050(``)X
+7 f
+1104(lhs)X
+1 f
+('')S
+1322(and)X
+1458(``)X
+7 f
+1512(rhs)X
+1 f
+('')S
+1730(are)X
+1849(not)X
+1971(speci\256ed,)X
+2296(the)X
+2414(current)X
+2662(set)X
+2771(of)X
+2859(command)X
+3196(mode)X
+3395(maps)X
+3585(are)X
+3705(displayed.)X
+976 2652(If)N
+1050(a)X
+1106(``)X
+7 f
+1160(!)X
+1 f
+('')S
+1302(character)X
+1618(is)X
+1691(appended)X
+2019(to)X
+2101(to)X
+2183(the)X
+2301(command,)X
+2657(the)X
+2775(text)X
+2915(input)X
+3099(mode)X
+3297(maps)X
+3486(are)X
+3605(displayed.)X
+976 2832(Otherwise,)N
+1365(when)X
+1578(the)X
+1715(``)X
+7 f
+1769(lhs)X
+1 f
+('')S
+2006(character)X
+2342(sequence)X
+2677(is)X
+2770(entered)X
+3047(in)X
+3 f
+3149(vi)X
+1 f
+3211(,)X
+3271(the)X
+3409(action)X
+3645(is)X
+3738(as)X
+3845(if)X
+3934(the)X
+976 2922(corresponding)N
+1466(``)X
+7 f
+1520(rhs)X
+1 f
+('')S
+1749(had)X
+1896(been)X
+2079(entered.)X
+2387(If)X
+2472(a)X
+2539(``)X
+7 f
+2593(!)X
+1 f
+('')S
+2746(character)X
+3073(is)X
+3157(appended)X
+3496(to)X
+3588(the)X
+3716(command)X
+976 3012(name,)N
+1196(the)X
+1320(mapping)X
+1626(is)X
+1705(effective)X
+2013(during)X
+2249(text)X
+2396(input)X
+2587(mode,)X
+2812(otherwise,)X
+3171(it)X
+3242(is)X
+3322(effective)X
+3631(during)X
+3867(com-)X
+976 3102(mand)N
+1175(mode.)X
+1414(This)X
+1577(allows)X
+1807(``)X
+7 f
+1861(lhs)X
+1 f
+('')S
+2080(to)X
+2163(have)X
+2336(two)X
+2476(different)X
+2773(macro)X
+2994(de\256nitions)X
+3351(at)X
+3429(the)X
+3547(same)X
+3732(time:)X
+3916(one)X
+976 3192(for)N
+1090(command)X
+1426(mode)X
+1624(and)X
+1760(one)X
+1896(for)X
+2010(input)X
+2194(mode.)X
+976 3372(Whitespace)N
+1373(characters)X
+1722(require)X
+1972(escaping)X
+2275(with)X
+2439(a)X
+7 f
+2497(<literal)X
+1 f
+(next>)S
+3086(character)X
+3405(to)X
+3490(be)X
+3589(entered)X
+3849(in)X
+3934(the)X
+7 f
+976 3462(lhs)N
+1 f
+1140(string)X
+1342(in)X
+1424(visual)X
+1635(mode.)X
+976 3642(Normally,)N
+1330(keys)X
+1504(in)X
+1593(the)X
+7 f
+1718(rhs)X
+1 f
+1889(string)X
+2098(are)X
+2224(remapped)X
+2569(\(see)X
+2727(the)X
+3 f
+2853(remap)X
+1 f
+3104(option\),)X
+3383(and)X
+3527(it)X
+3599(is)X
+3680(possible)X
+3970(to)X
+976 3732(create)N
+1207(in\256nite)X
+1471(loops.)X
+1722(However,)X
+2075(keys)X
+2260(which)X
+2494(map)X
+2670(to)X
+2770(themselves)X
+3164(are)X
+3300(not)X
+3439(further)X
+3695(remapped,)X
+976 3822(regardless)N
+1327(of)X
+1419(the)X
+1542(setting)X
+1780(of)X
+1872(the)X
+3 f
+1995(remap)X
+1 f
+2243(option.)X
+2512(For)X
+2648(example,)X
+2966(the)X
+3090(command)X
+3432(``)X
+7 f
+3486(:map)X
+3732(n)X
+3834(nz.)X
+1 f
+('')S
+976 3912(maps)N
+1165(the)X
+1283(``)X
+7 f
+1337(n)X
+1 f
+('')S
+1459(key)X
+1595(to)X
+1677(the)X
+3 f
+1795(n)X
+1 f
+1859(and)X
+3 f
+1995(z)X
+1 f
+2051(commands.)X
+976 4092(To)N
+1085(exit)X
+1225(an)X
+1321(in\256nitely)X
+1629(looping)X
+1893(map,)X
+2071(use)X
+2198(the)X
+2316(terminal)X
+7 f
+2603(<interrupt>)X
+1 f
+3151(character.)X
+976 4272(Line:)N
+1336(Unchanged.)X
+976 4362(Options:)N
+1336(None.)X
+3 f
+776 4542([line])N
+974(ma[rk])X
+1235 0.3125(<character>)AX
+776 4632([line])N
+974(k)X
+1038 0.3125(<character>)AX
+1 f
+976 4722(Mark)N
+1189(the)X
+1326(line)X
+1485(with)X
+1666(the)X
+1803(mark)X
+7 f
+2007(<character>)X
+1 f
+(.)S
+2614(The)X
+2778(expressions)X
+3192(``)X
+7 f
+3246('<character>)X
+1 f
+('')S
+3916(and)X
+976 4812(``)N
+7 f
+1030(`<character>)X
+1 f
+('')S
+1680(can)X
+1812(then)X
+1970(be)X
+2066(used)X
+2233(as)X
+2320(an)X
+2416(address)X
+2677(in)X
+2759(any)X
+2895(command)X
+3231(that)X
+3371(uses)X
+3529(one.)X
+976 4992(Line:)N
+1336(Unchanged.)X
+976 5082(Options:)N
+1336(None.)X
+3 f
+776 5262([range])N
+1046(m[ove])X
+1303(line)X
+1 f
+976 5352(Move)N
+1188(the)X
+1312(speci\256ed)X
+1623(lines)X
+1800(after)X
+1974(the)X
+2098(target)X
+2307(line.)X
+2493(A)X
+2577(target)X
+2786(line)X
+2932(of)X
+3025(0)X
+3091(places)X
+3318(the)X
+3442(lines)X
+3619(at)X
+3703(the)X
+3827(begin-)X
+976 5442(ning)N
+1138(of)X
+1225(the)X
+1343(\256le.)X
+976 5622(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(\256rst)X
+1802(of)X
+1889(the)X
+2007(moved)X
+2245(lines.)X
+976 5712(Options:)N
+1336(None.)X
+
+40 p
+%%Page: 40 39
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-40)N
+2813(Nvi/Nex)X
+3109 0.3906(Reference)AX
+3474(\(Ex)X
+3614(Commands\))X
+776 762 0.3250(mk[exrc][!])AN
+1190(\256le)X
+1 f
+976 852(Write)N
+1180(the)X
+1299(abbreviations,)X
+1772(editor)X
+1980(options)X
+2237(and)X
+2375(maps)X
+2566(to)X
+2650(the)X
+2770(speci\256ed)X
+3077(\256le.)X
+3241(Information)X
+3646(is)X
+3721(written)X
+3970(in)X
+976 942(a)N
+1034(form)X
+1212(which)X
+1430(can)X
+1564(later)X
+1729(be)X
+1827(read)X
+1988(back)X
+2162(in)X
+2246(using)X
+2441(the)X
+3 f
+2561(ex)X
+2659(source)X
+1 f
+2904(command.)X
+3282(If)X
+7 f
+3358(file)X
+1 f
+3572(already)X
+3830(exists,)X
+976 1032(the)N
+3 f
+1097(mkexrc)X
+1 f
+1379(command)X
+1718(will)X
+1865(fail.)X
+2035(This)X
+2200(check)X
+2411(can)X
+2546(be)X
+2645(overridden)X
+3016(by)X
+3119(appending)X
+3476(a)X
+3536(``)X
+7 f
+3590(!)X
+1 f
+('')S
+3736(character)X
+976 1122(to)N
+1058(the)X
+1176(command.)X
+976 1302(Line:)N
+1336(Unchanged.)X
+976 1392(Options:)N
+1336(None.)X
+3 f
+776 1572(n[ext][!])N
+1078([\256le)X
+1227(...])X
+1 f
+976 1662(Edit)N
+1142(the)X
+1273(next)X
+1444(\256le)X
+1579(from)X
+1768(the)X
+1899(argument)X
+2235(list.)X
+2405(The)X
+3 f
+2563(next)X
+1 f
+2743(command)X
+3092(will)X
+3249(fail)X
+3389(if)X
+3471(the)X
+3603(\256le)X
+3739(has)X
+3880(been)X
+976 1752(modi\256ed)N
+1287(since)X
+1478(the)X
+1602(last)X
+1739(complete)X
+2059(write.)X
+2290(This)X
+2458(check)X
+2672(can)X
+2810(be)X
+2912(overridden)X
+3286(by)X
+3392(appending)X
+3752(the)X
+3876(``)X
+7 f
+3930(!)X
+1 f
+('')S
+976 1842(character)N
+1294(to)X
+1378(the)X
+1498(command)X
+1836(name.)X
+2072(The)X
+2219(argument)X
+2544(list)X
+2663(can)X
+2797(optionally)X
+3143(be)X
+3241(replaced)X
+3536(by)X
+3639(specifying)X
+3996(a)X
+976 1932(new)N
+1131(one)X
+1268(as)X
+1355(arguments)X
+1709(to)X
+1791(this)X
+1926(command.)X
+2302(In)X
+2389(this)X
+2524(case,)X
+2703(editing)X
+2945(starts)X
+3134(with)X
+3296(the)X
+3414(\256rst)X
+3558(\256le)X
+3680(on)X
+3780(the)X
+3898(new)X
+976 2022(list.)N
+976 2202(Line:)N
+1336(Set)X
+1458(as)X
+1545(described)X
+1873(for)X
+1987(the)X
+3 f
+2105(edit)X
+1 f
+2254(command.)X
+976 2292(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+1856(options)X
+3 f
+2111(autowrite)X
+1 f
+2461(and)X
+3 f
+2597(writeany)X
+1 f
+2900(.)X
+3 f
+776 2472([line])N
+974(o[pen])X
+1212(/pattern/)X
+1530([\257ags])X
+1 f
+976 2562(Enter)N
+1172(open)X
+1350(mode.)X
+1590(Open)X
+1786(mode)X
+1987(is)X
+2063(the)X
+2184(same)X
+2372(as)X
+2462(being)X
+2663(in)X
+3 f
+2748(vi)X
+1 f
+2810(,)X
+2853(but)X
+2978(with)X
+3143(a)X
+3202(one-line)X
+3488(window.)X
+3809(All)X
+3934(the)X
+976 2652(standard)N
+3 f
+1278(vi)X
+1 f
+1370(commands)X
+1747(are)X
+1876(available.)X
+2236(If)X
+2320(a)X
+2386(match)X
+2612(is)X
+2694(found)X
+2910(for)X
+3033(the)X
+3160(optional)X
+3451(RE)X
+3582(argument,)X
+3934(the)X
+976 2742(cursor)N
+1197(is)X
+1270(set)X
+1379(to)X
+1461(the)X
+1579(start)X
+1737(of)X
+1824(the)X
+1942(matching)X
+2260(pattern.)X
+2 f
+976 2922(This)N
+1133(command)X
+1465(is)X
+1538(not)X
+1660(yet)X
+1774(implemented.)X
+1 f
+976 3102(Line:)N
+1336(Unchanged,)X
+1750(unless)X
+1978(the)X
+2104(optional)X
+2394(RE)X
+2524(is)X
+2605(speci\256ed,)X
+2938(in)X
+3028(which)X
+3253(case)X
+3421(it)X
+3494(is)X
+3576(set)X
+3694(to)X
+3785(the)X
+3912(line)X
+1336 3192(where)N
+1553(the)X
+1671(matching)X
+1989(pattern)X
+2232(is)X
+2305(found.)X
+976 3282(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(open)X
+1 f
+2040(option.)X
+3 f
+776 3462(pre[serve])N
+1 f
+976 3552(Save)N
+1161(the)X
+1288(\256le)X
+1419(in)X
+1510(a)X
+1575(form)X
+1760(that)X
+1909(can)X
+2050(later)X
+2222(be)X
+2327(recovered)X
+2674(using)X
+2877(the)X
+3 f
+3005(ex)X
+9 f
+3111(-)X
+3113(-)X
+3 f
+3157(r)X
+1 f
+3223(option.)X
+3497(When)X
+3719(the)X
+3847(\256le)X
+3979(is)X
+976 3642(preserved,)N
+1329(an)X
+1425(email)X
+1623(message)X
+1915(is)X
+1988(sent)X
+2137(to)X
+2219(the)X
+2337(user.)X
+976 3822(Line:)N
+1336(Unchanged.)X
+976 3912(Options:)N
+1336(None.)X
+3 f
+776 4092(prev[ious][!])N
+1 f
+976 4182(Edit)N
+1136(the)X
+1261(previous)X
+1564(\256le)X
+1693(from)X
+1876(the)X
+2001(argument)X
+2331(list.)X
+2495(The)X
+3 f
+2647(previous)X
+1 f
+2967(command)X
+3310(will)X
+3461(fail)X
+3595(if)X
+3671(the)X
+3796(\256le)X
+3925(has)X
+976 4272(been)N
+1155(modi\256ed)X
+1466(since)X
+1658(the)X
+1783(last)X
+1921(complete)X
+2241(write.)X
+2472(This)X
+2640(check)X
+2854(can)X
+2992(be)X
+3094(overridden)X
+3468(by)X
+3574(appending)X
+3934(the)X
+976 4362(``)N
+7 f
+1030(!)X
+1 f
+('')S
+1172(character)X
+1488(to)X
+1570(the)X
+1688(command)X
+2024(name.)X
+976 4542(Line:)N
+1336(Set)X
+1458(as)X
+1545(described)X
+1873(for)X
+1987(the)X
+3 f
+2105(edit)X
+1 f
+2254(command.)X
+976 4632(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+1856(options)X
+3 f
+2111(autowrite)X
+1 f
+2461(and)X
+3 f
+2597(writeany)X
+1 f
+2900(.)X
+2960(None.)X
+3 f
+776 4812([range])N
+1046(p[rint])X
+1293([count])X
+1558([\257ags])X
+1 f
+976 4902(Display)N
+1245(the)X
+1363(speci\256ed)X
+1668(lines.)X
+976 5082(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(last)X
+1789(line)X
+1929(displayed.)X
+976 5172(Options:)N
+1336(None.)X
+3 f
+776 5352([line])N
+974(pu[t])X
+1163([buffer])X
+1 f
+976 5442(Append)N
+1250(buffer)X
+1467(contents)X
+1755(to)X
+1838(the)X
+1957(current)X
+2206(line.)X
+2387(If)X
+2462(a)X
+2519(buffer)X
+2737(is)X
+2811(speci\256ed,)X
+3137(its)X
+3233(contents)X
+3521(are)X
+3641(appended)X
+3970(to)X
+976 5532(the)N
+1094(line,)X
+1254(otherwise,)X
+1606(the)X
+1724(contents)X
+2011(of)X
+2098(the)X
+2216(unnamed)X
+2530(buffer)X
+2747(are)X
+2866(used.)X
+976 5712(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(line)X
+1798(after)X
+1966(the)X
+2084(current)X
+2332(line.)X
+
+41 p
+%%Page: 41 40
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Ex)X
+1377(Commands\))X
+3658(USD:13-41)X
+1 f
+976 762(Options:)N
+1336(None.)X
+3 f
+776 942(q[uit][!])N
+1 f
+976 1032(End)N
+1133(the)X
+1259(editing)X
+1509(session.)X
+1808(If)X
+1890(the)X
+2016(\256le)X
+2146(has)X
+2281(been)X
+2461(modi\256ed)X
+2773(since)X
+2966(the)X
+3092(last)X
+3231(complete)X
+3554(write,)X
+3768(the)X
+3 f
+3895(quit)X
+1 f
+976 1122(command)N
+1314(will)X
+1460(fail.)X
+1629(This)X
+1793(check)X
+2003(may)X
+2163(be)X
+2261(overridden)X
+2631(by)X
+2733(appending)X
+3089(a)X
+3147(``)X
+7 f
+3201(!)X
+1 f
+('')S
+3345(character)X
+3663(to)X
+3747(the)X
+3867(com-)X
+976 1212(mand.)N
+976 1392(If)N
+1053(there)X
+1237(are)X
+1359(more)X
+1547(\256les)X
+1703(to)X
+1788(edit,)X
+1951(the)X
+3 f
+2072(quit)X
+1 f
+2232(command)X
+2571(will)X
+2718(fail.)X
+2888(Appending)X
+3268(a)X
+3328(``)X
+7 f
+3382(!)X
+1 f
+('')S
+3528(character)X
+3848(to)X
+3934(the)X
+976 1482(command)N
+1315(name)X
+1511(or)X
+1600(entering)X
+1885(two)X
+3 f
+2027(quit)X
+1 f
+2186(commands)X
+2555(\(i.e.)X
+3 f
+2722(wq)X
+1 f
+2824(,)X
+3 f
+2866(quit)X
+1 f
+3003(,)X
+3 f
+3045(xit)X
+1 f
+3156(or)X
+3 f
+3245(ZZ)X
+1 f
+3351(\))X
+3400(in)X
+3484(a)X
+3542(row\))X
+3716(will)X
+3862(over-)X
+976 1572(ride)N
+1121(this)X
+1256(check)X
+1464(and)X
+1600(the)X
+1718(editor)X
+1925(will)X
+2069(exit.)X
+976 1752(Line:)N
+1336(Unchanged.)X
+976 1842(Options:)N
+1336(None.)X
+3 f
+776 2022([line])N
+974(r[ead][!])X
+1285([\256le])X
+1 f
+976 2112(Read)N
+1171(a)X
+1237(\256le.)X
+1409(A)X
+1497(copy)X
+1683(of)X
+1780(the)X
+1908(speci\256ed)X
+2223(\256le)X
+2355(is)X
+2438(appended)X
+2776(to)X
+2868(the)X
+2996(line.)X
+3186(If)X
+7 f
+3270(line)X
+1 f
+3492(is)X
+3575(0,)X
+3665(the)X
+3793(copy)X
+3979(is)X
+976 2202(inserted)N
+1252(at)X
+1332(the)X
+1452(beginning)X
+1794(of)X
+1883(the)X
+2003(\256le.)X
+2167(If)X
+2243(no)X
+2345(\256le)X
+2469(is)X
+2544(speci\256ed,)X
+2871(the)X
+2991(current)X
+3241(\256le)X
+3365(is)X
+3440(read;)X
+3623(if)X
+3694(there)X
+3877(is)X
+3952(no)X
+976 2292(current)N
+1233(\256le,)X
+1384(then)X
+7 f
+1552(file)X
+1 f
+1774(becomes)X
+2085(the)X
+2213(current)X
+2471(\256le.)X
+2643(If)X
+2727(there)X
+2918(is)X
+3001(no)X
+3111(current)X
+3369(\256le)X
+3501(and)X
+3647(no)X
+7 f
+3757(file)X
+1 f
+3979(is)X
+976 2382(speci\256ed,)N
+1301(then)X
+1459(the)X
+3 f
+1577(read)X
+1 f
+1753(command)X
+2089(will)X
+2233(fail.)X
+976 2562(If)N
+7 f
+1054(file)X
+1 f
+1270(is)X
+1347(preceded)X
+1662(by)X
+1766(a)X
+1826(``)X
+7 f
+1880(!)X
+1 f
+('')S
+2026(character,)X
+7 f
+2366(file)X
+1 f
+2582(is)X
+2659(treated)X
+2902(as)X
+2993(if)X
+3067(it)X
+3136(were)X
+3318(a)X
+3379(shell)X
+3555(command,)X
+3916(and)X
+976 2652(passed)N
+1213(to)X
+1298(the)X
+1419(program)X
+1713(named)X
+1949(by)X
+2051(the)X
+7 f
+2171(SHELL)X
+1 f
+2433(environment)X
+2860(variable.)X
+3181(The)X
+3328(standard)X
+3622(and)X
+3760(standard)X
+976 2742(error)N
+1155(outputs)X
+1412(of)X
+1501(that)X
+1643(command)X
+1981(are)X
+2102(read)X
+2263(into)X
+2409(the)X
+2529(\256le)X
+2654(after)X
+2825(the)X
+2946(speci\256ed)X
+3254(line.)X
+3437(The)X
+3585(special)X
+3831(mean-)X
+976 2832(ing)N
+1098(of)X
+1185(the)X
+1303(``)X
+7 f
+1357(!)X
+1 f
+('')S
+1499(character)X
+1815(can)X
+1947(be)X
+2043(overridden)X
+2411(by)X
+2511(escaping)X
+2812(it)X
+2876(with)X
+3038(a)X
+3094(backslash)X
+3426(\(``)X
+7 f
+3507(\\)X
+1 f
+(''\))S
+3656(character.)X
+976 3012(Line:)N
+1336(When)X
+1550(executed)X
+1858(from)X
+3 f
+2036(ex)X
+1 f
+2112(,)X
+2154(the)X
+2274(current)X
+2524(line)X
+2666(is)X
+2741(set)X
+2852(to)X
+2936(the)X
+3056(last)X
+3189(line)X
+3331(read.)X
+3532(When)X
+3746(executed)X
+1336 3102(from)N
+3 f
+1512(vi)X
+1 f
+1574(,)X
+1614(the)X
+1732(current)X
+1980(line)X
+2120(is)X
+2193(set)X
+2302(to)X
+2384(the)X
+2502(\256rst)X
+2646(line)X
+2786(read.)X
+976 3192(Options:)N
+1336(None.)X
+3 f
+776 3372 0.4063(rec[over])AN
+1110(\256le)X
+1 f
+976 3462(Recover)N
+7 f
+1273(file)X
+1 f
+1494(if)X
+1572(it)X
+1645(was)X
+1799(previously)X
+2166(saved.)X
+2418(If)X
+2501(no)X
+2610(saved)X
+2822(\256le)X
+2953(by)X
+3062(that)X
+3211(name)X
+3414(exists,)X
+3645(the)X
+3 f
+3772(recover)X
+1 f
+976 3552(command)N
+1312(behaves)X
+1591(similarly)X
+1895(to)X
+1977(the)X
+3 f
+2095(edit)X
+1 f
+2244(command.)X
+976 3732(Line:)N
+1336(Set)X
+1458(as)X
+1545(described)X
+1873(for)X
+1987(the)X
+3 f
+2105(edit)X
+1 f
+2254(command.)X
+976 3822(Options:)N
+1336(None.)X
+3 f
+776 4002(res[ize])N
+1047([+|-]size)X
+976 4092(Vi)N
+1 f
+1081(mode)X
+1284(only.)X
+1492(Grow)X
+1701(or)X
+1794(shrink)X
+2020(the)X
+2144(current)X
+2398(screen.)X
+2670(If)X
+7 f
+2750(size)X
+1 f
+2968(is)X
+3047(a)X
+3109(positive,)X
+3408(signed)X
+3643(number,)X
+3934(the)X
+976 4182(current)N
+1227(screen)X
+1456(is)X
+1532(grown)X
+1760(by)X
+1863(that)X
+2006(many)X
+2207(lines.)X
+2421(If)X
+7 f
+2498(size)X
+1 f
+2713(is)X
+2789(a)X
+2848(negative,)X
+3163(signed)X
+3395(number,)X
+3683(the)X
+3804(current)X
+976 4272(screen)N
+1212(is)X
+1295(shrunk)X
+1543(by)X
+1653(that)X
+1803(many)X
+2011(lines.)X
+2232(If)X
+7 f
+2316(size)X
+1 f
+2538(is)X
+2621(not)X
+2753(signed,)X
+3012(the)X
+3141(current)X
+3400(screen)X
+3637(is)X
+3721(set)X
+3841(to)X
+3934(the)X
+976 4362(speci\256ed)N
+7 f
+1281(size)X
+1 f
+(.)S
+1533(Applicable)X
+1905(only)X
+2067(to)X
+2149(split)X
+2306(screens.)X
+976 4542(Line:)N
+1336(Unchanged.)X
+976 4632(Options:)N
+1336(None.)X
+3 f
+776 4812(rew[ind][!])N
+1 f
+976 4902(Rewind)N
+1251(the)X
+1375(argument)X
+1704(list.)X
+1867(If)X
+1947(the)X
+2071(current)X
+2325(\256le)X
+2453(has)X
+2586(been)X
+2764(modi\256ed)X
+3074(since)X
+3265(the)X
+3389(last)X
+3526(complete)X
+3847(write,)X
+976 4992(the)N
+3 f
+1097(rewind)X
+1 f
+1360(command)X
+1699(will)X
+1846(fail.)X
+2016(This)X
+2180(check)X
+2390(may)X
+2550(be)X
+2648(overridden)X
+3018(by)X
+3120(appending)X
+3476(the)X
+3596(``)X
+7 f
+3650(!)X
+1 f
+('')S
+3794(charac-)X
+976 5082(ter)N
+1081(to)X
+1163(the)X
+1281(command.)X
+976 5262(Otherwise,)N
+1346(the)X
+1464(current)X
+1712(\256le)X
+1834(is)X
+1907(set)X
+2016(to)X
+2098(the)X
+2216(\256rst)X
+2360(\256le)X
+2482(in)X
+2564(the)X
+2682(argument)X
+3005(list.)X
+976 5442(Line:)N
+1336(Set)X
+1458(as)X
+1545(described)X
+1873(for)X
+1987(the)X
+3 f
+2105(edit)X
+1 f
+2254(command.)X
+976 5532(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(autowrite)X
+1 f
+2206(and)X
+3 f
+2342(writeany)X
+1 f
+2665(options.)X
+3 f
+776 5712(se[t])N
+944([option[=[value]])X
+1544(...])X
+1651([nooption)X
+1999(...])X
+2106([option?)X
+2410(...])X
+2517([all])X
+1 f
+976 5802(Display)N
+1252(or)X
+1346(set)X
+1462(editor)X
+1676(options.)X
+1979(When)X
+2199(no)X
+2307(arguments)X
+2669(are)X
+2796(speci\256ed,)X
+3129(the)X
+3255(editor)X
+3470(option)X
+3 f
+3702(term)X
+1 f
+3868(,)X
+3916(and)X
+
+42 p
+%%Page: 42 41
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-42)N
+2813(Nvi/Nex)X
+3109 0.3906(Reference)AX
+3474(\(Ex)X
+3614(Commands\))X
+1 f
+976 762(any)N
+1115(editor)X
+1325(options)X
+1583(whose)X
+1811(values)X
+2039(have)X
+2214(been)X
+2389(changed)X
+2679(from)X
+2857(the)X
+2977(default)X
+3222(settings)X
+3488(are)X
+3609(displayed.)X
+3978(If)X
+976 852(the)N
+1094(argument)X
+7 f
+1417(all)X
+1 f
+1581(is)X
+1654(speci\256ed,)X
+1979(the)X
+2097(values)X
+2322(of)X
+2409(all)X
+2509(of)X
+2596(editor)X
+2803(options)X
+3058(are)X
+3177(displayed.)X
+976 1032(Specifying)N
+1353(an)X
+1459(option)X
+1693(name)X
+1897(followed)X
+2212(by)X
+2322(the)X
+2450(character)X
+2776(``)X
+7 f
+2830(?)X
+1 f
+('')S
+2982(causes)X
+3222(the)X
+3350(current)X
+3609(value)X
+3814(of)X
+3912(that)X
+976 1122(option)N
+1203(to)X
+1288(be)X
+1387(displayed.)X
+1757(The)X
+1905(``)X
+7 f
+1959(?)X
+1 f
+('')S
+2104(can)X
+2239(be)X
+2338(separated)X
+2665(from)X
+2843(the)X
+2963(option)X
+3189(name)X
+3385(by)X
+3487(whitespace)X
+3866(char-)X
+976 1212(acters.)N
+1225(The)X
+1371(``)X
+7 f
+1425(?)X
+1 f
+('')S
+1568(is)X
+1642(necessary)X
+1976(only)X
+2139(for)X
+2254(Boolean)X
+2543(valued)X
+2779(options.)X
+3076(Boolean)X
+3365(options)X
+3622(can)X
+3756(be)X
+3854(given)X
+976 1302(values)N
+1209(by)X
+1317(the)X
+1443(form)X
+1627(``)X
+7 f
+1681(set)X
+1881(option)X
+1 f
+('')S
+2251(to)X
+2341(turn)X
+2498(them)X
+2686(on,)X
+2814(or)X
+2909(``)X
+7 f
+2963(set)X
+3162(nooption)X
+1 f
+('')S
+3627(to)X
+3716(turn)X
+3872(them)X
+976 1392(off.)N
+1131(String)X
+1347(and)X
+1484(numeric)X
+1768(options)X
+2024(can)X
+2158(be)X
+2256(assigned)X
+2554(by)X
+2656(the)X
+2776(form)X
+2954(``)X
+7 f
+3008(set)X
+3202(option=value)X
+1 f
+(''.)S
+3894(Any)X
+976 1482(whitespace)N
+1359(characters)X
+1712(in)X
+1800(strings)X
+2039(can)X
+2176(be)X
+2277(included)X
+2578(literally)X
+2852(by)X
+2957(preceding)X
+3299(each)X
+3472(with)X
+3639(a)X
+3700(backslash.)X
+976 1572(More)N
+1180(than)X
+1349(one)X
+1496(option)X
+1731(can)X
+1874(be)X
+1981(set)X
+2101(or)X
+2199(listed)X
+2403(by)X
+2514(a)X
+2581(single)X
+2803(set)X
+2923(command,)X
+3290(by)X
+3401(specifying)X
+3766(multiple)X
+976 1662(arguments,)N
+1350(each)X
+1518(separated)X
+1842(from)X
+2018(the)X
+2136(next)X
+2294(by)X
+2394(whitespace)X
+2771(characters.)X
+976 1842(Line:)N
+1336(Unchanged.)X
+976 1932(Options:)N
+1336(None.)X
+3 f
+776 2112(sh[ell])N
+1 f
+976 2202(Run)N
+1131(a)X
+1189(shell)X
+1362(program.)X
+1696(The)X
+1843(program)X
+2137(named)X
+2373(by)X
+2475(the)X
+3 f
+2596(shell)X
+1 f
+2774(option)X
+3001(is)X
+3077(run)X
+3207(with)X
+3372(a)X
+3 f
+9 f
+3431(-)X
+3433(-)X
+3 f
+3477(i)X
+1 f
+3522(\(for)X
+3666(interactive\))X
+976 2292(\257ag.)N
+1156(Editing)X
+1411(is)X
+1484(resumed)X
+1776(when)X
+1970(that)X
+2110(program)X
+2402(exits.)X
+976 2472(Line:)N
+1336(Unchanged.)X
+976 2562(Options:)N
+1336(None.)X
+3 f
+776 2742(so[urce])N
+1073(\256le)X
+1 f
+976 2832(Read)N
+1161(and)X
+1297(execute)X
+3 f
+1563(ex)X
+1 f
+1659(commands)X
+2026(from)X
+2202(a)X
+2258(\256le.)X
+3 f
+2420(Source)X
+1 f
+2676(commands)X
+3043(may)X
+3201(be)X
+3297(nested.)X
+976 3012(Line:)N
+1336(Unchanged.)X
+976 3102(Options:)N
+1336(None.)X
+3 f
+776 3282(sp[lit])N
+996([\256le)X
+1145(...])X
+976 3372(Vi)N
+1 f
+1078(mode)X
+1278(only.)X
+1482(Split)X
+1655(the)X
+1776(screen.)X
+2045(The)X
+2193(current)X
+2444(screen)X
+2673(is)X
+2749(split)X
+2909(into)X
+3056(two)X
+3199(screens,)X
+3479(of)X
+3569(approximately)X
+976 3462(equal)N
+1173(size.)X
+1361(If)X
+1438(the)X
+1559(cursor)X
+1783(is)X
+1859(in)X
+1944(the)X
+2065(lower)X
+2271(half)X
+2419(of)X
+2509(the)X
+2630(screen,)X
+2879(the)X
+3000(screen)X
+3229(will)X
+3376(split)X
+3536(up,)X
+3658(i.e.)X
+3778(the)X
+3898(new)X
+976 3552(screen)N
+1213(will)X
+1368(be)X
+1475(above)X
+1699(the)X
+1829(old)X
+1963(one.)X
+2151(If)X
+2237(the)X
+2367(cursor)X
+2600(is)X
+2685(in)X
+2779(the)X
+2909(upper)X
+3124(half)X
+3281(of)X
+3380(the)X
+3510(screen,)X
+3768(the)X
+3898(new)X
+976 3642(screen)N
+1202(will)X
+1346(be)X
+1442(below)X
+1658(the)X
+1776(old)X
+1898(one.)X
+976 3822(If)N
+7 f
+1052(file)X
+1 f
+1267(is)X
+1343(speci\256ed,)X
+1671(the)X
+1792(new)X
+1949(screen)X
+2178(is)X
+2254(editing)X
+2499(that)X
+2642(\256le,)X
+2787(otherwise,)X
+3142(both)X
+3307(screens)X
+3567(are)X
+3689(editing)X
+3934(the)X
+976 3912(same)N
+1165(\256le,)X
+1310(and)X
+1449(changes)X
+1731(in)X
+1816(each)X
+1987(will)X
+2134(be)X
+2233(be)X
+2332(re\257ected)X
+2632(in)X
+2717(the)X
+2838(other.)X
+3066(The)X
+3214(argument)X
+3540(list)X
+3660(for)X
+3777(the)X
+3898(new)X
+976 4002(screen)N
+1204(consists)X
+1479(of)X
+1568(the)X
+1688(list)X
+1807(of)X
+1896(\256les)X
+2051(speci\256ed)X
+2358(as)X
+2447(arguments)X
+2803(to)X
+2888(this)X
+3026(command,)X
+3385(or,)X
+3495(the)X
+3616(current)X
+3867(path-)X
+976 4092(name)N
+1170(if)X
+1239(no)X
+1339(\256les)X
+1492(are)X
+1611(speci\256ed.)X
+976 4272(Line:)N
+1336(If)X
+7 f
+1410(file)X
+1 f
+1622(is)X
+1695(speci\256ed,)X
+2020(set)X
+2129(as)X
+2216(for)X
+2330(the)X
+3 f
+2448(edit)X
+1 f
+2597(command,)X
+2953(otherwise)X
+3285(unchanged.)X
+976 4362(Options:)N
+1336(None.)X
+3 f
+776 4542([range])N
+1046(s[ubstitute])X
+1453([/pattern/replace/])X
+2097([options])X
+2419([count])X
+2684([\257ags])X
+776 4632([range])N
+1046(&)X
+1133([options])X
+1455([count])X
+1720([\257ags])X
+776 4722([range])N
+1046(\304)X
+1093([options])X
+1415([count])X
+1680([\257ags])X
+1 f
+976 4812(Make)N
+1185(substitutions.)X
+1654(Replace)X
+1939(the)X
+2063(\256rst)X
+2214(instance)X
+2504(of)X
+7 f
+2598(pattern)X
+1 f
+2961(with)X
+3130(the)X
+3255(string)X
+7 f
+3464(replace)X
+1 f
+3827(on)X
+3934(the)X
+976 4902(speci\256ed)N
+1343(line\(s\).)X
+1670(If)X
+1806(the)X
+1986(``)X
+7 f
+2040(/pattern/repl/)X
+1 f
+('')S
+2847(argument)X
+3231(is)X
+3365(not)X
+3548(speci\256ed,)X
+3934(the)X
+976 4992(``)N
+7 f
+1030(/pattern/repl/)X
+1 f
+('')S
+1776(from)X
+1952(the)X
+2070(previous)X
+3 f
+2366(substitute)X
+1 f
+2719(command)X
+3055(is)X
+3128(used.)X
+976 5172(If)N
+7 f
+1054(options)X
+1 f
+1414(includes)X
+1705(the)X
+1827(letter)X
+2017(``)X
+7 f
+2071(c)X
+1 f
+('')S
+2198(\(con\256rm\),)X
+2546(you)X
+2691(will)X
+2840(be)X
+2941(prompted)X
+3273(for)X
+3392(con\256rmation)X
+3826(before)X
+976 5262(each)N
+1152(replacement)X
+1573(is)X
+1654(done.)X
+1878(An)X
+2004(af\256rmative)X
+2384(response)X
+2693(\(in)X
+2810(English,)X
+3101(a)X
+3164(``)X
+7 f
+3218(y)X
+1 f
+('')S
+3347 0.3750(character\))AX
+3697(causes)X
+3934(the)X
+976 5352(replacement)N
+1393(to)X
+1479(be)X
+1579(made.)X
+1817(A)X
+1899(quit)X
+2047(response)X
+2352(\(in)X
+2465(English,)X
+2753(a)X
+2813(``)X
+7 f
+2867(q)X
+1 f
+('')S
+2993 0.3750(character\))AX
+3341(causes)X
+3576(the)X
+3 f
+3699(substitute)X
+1 f
+976 5442(command)N
+1320(to)X
+1410(be)X
+1514(terminated.)X
+1925(Any)X
+2091(other)X
+2284(response)X
+2592(causes)X
+2829(the)X
+2954(replacement)X
+3374(not)X
+3503(to)X
+3592(be)X
+3695(made,)X
+3916(and)X
+976 5532(the)N
+3 f
+1094(substitute)X
+1 f
+1447(command)X
+1783(continues.)X
+2150(If)X
+7 f
+2224(options)X
+1 f
+2580(includes)X
+2867(the)X
+2985(letter)X
+3170(``)X
+7 f
+3224(g)X
+1 f
+('')S
+3346(\(global\),)X
+3641(all)X
+3742(nonover-)X
+976 5622(lapping)N
+1236(instances)X
+1550(of)X
+7 f
+1637(pattern)X
+1 f
+1993(in)X
+2075(the)X
+2193(line)X
+2333(are)X
+2452(replaced.)X
+976 5802(The)N
+3 f
+1122(&)X
+1 f
+1210(version)X
+1467(of)X
+1555(the)X
+1674(command)X
+2011(is)X
+2085(the)X
+2204(same)X
+2390(as)X
+2479(not)X
+2603(specifying)X
+2959(a)X
+3017(pattern)X
+3262(or)X
+3351(replacement)X
+3766(string)X
+3970(to)X
+
+43 p
+%%Page: 43 42
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Ex)X
+1377(Commands\))X
+3658(USD:13-43)X
+1 f
+976 762(the)N
+3 f
+1098(substitute)X
+1 f
+1455(command,)X
+1815(and)X
+1955(the)X
+2077(``)X
+7 f
+2131(&)X
+1 f
+('')S
+2257(is)X
+2333(replaced)X
+2629(by)X
+2732(the)X
+2853(pattern)X
+3099(and)X
+3238(replacement)X
+3654(information)X
+976 852(from)N
+1152(the)X
+1270(previous)X
+1566(substitute)X
+1892(command.)X
+976 1032(The)N
+3 f
+1121(\304)X
+1 f
+1168(version)X
+1424(of)X
+1511(the)X
+1629(command)X
+1966(is)X
+2040(the)X
+2159(same)X
+2345(as)X
+3 f
+2433(&)X
+1 f
+2521(and)X
+3 f
+2658(s)X
+1 f
+2689(,)X
+2730(except)X
+2961(that)X
+3102(the)X
+3221(search)X
+3448(pattern)X
+3692(used)X
+3860(is)X
+3934(the)X
+976 1122(last)N
+1107(RE)X
+1229(used)X
+1396(in)X
+2 f
+1478(any)X
+1 f
+1614(command,)X
+1970(not)X
+2092(necessarily)X
+2469(the)X
+2587(one)X
+2723(used)X
+2890(in)X
+2972(the)X
+3090(last)X
+3 f
+3221(substitute)X
+1 f
+3574(command.)X
+976 1302(For)N
+1107(example,)X
+1419(in)X
+1501(the)X
+1619(sequence)X
+7 f
+1296 1425(s/red/blue/)N
+1296 1515(/green)N
+1296 1605(\304)N
+1 f
+976 1728(the)N
+1094(``)X
+7 f
+1148(\304)X
+1 f
+('')S
+1270(is)X
+1343(equivalent)X
+1697(to)X
+1779(``)X
+7 f
+1833(s/green/blue/)X
+1 f
+(''.)S
+976 1908(The)N
+3 f
+1126(substitute)X
+1 f
+1484(command)X
+1825(may)X
+1988(be)X
+2089(interrupted,)X
+2486(using)X
+2685(the)X
+2809(terminal)X
+3102(interrupt)X
+3404(character.)X
+3766(All)X
+3894(sub-)X
+976 1998(stitutions)N
+1288(completed)X
+1642(before)X
+1868(the)X
+1986(interrupt)X
+2282(are)X
+2401(retained.)X
+976 2178(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(last)X
+1789(line)X
+1929(upon)X
+2109(which)X
+2325(a)X
+2381(substitution)X
+2773(was)X
+2918(made.)X
+976 2268(Options:)N
+1336(None.)X
+3 f
+776 2448(su[spend][!])N
+776 2538(st[op][!])N
+776 2628(<control-Z>)N
+1 f
+976 2718(Suspend)N
+1285(the)X
+1422(edit)X
+1581(session.)X
+1891(Appending)X
+2286(a)X
+2361(``)X
+7 f
+2415(!)X
+1 f
+('')S
+2576(character)X
+2911(to)X
+3012(these)X
+3216(commands)X
+3602(turns)X
+3801(off)X
+3934(the)X
+3 f
+976 2808(autowrite)N
+1 f
+1326(option)X
+1550(for)X
+1664(the)X
+1782(command.)X
+976 2988(Line:)N
+1336(Unchanged.)X
+976 3078(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(autowrite)X
+1 f
+2206(option.)X
+3 f
+776 3258(ta[g][!])N
+1038(tagstring)X
+1 f
+976 3348(Edit)N
+1133(the)X
+1255(\256le)X
+1381(containing)X
+1743(the)X
+1865(speci\256ed)X
+2174(tag.)X
+2337(Search)X
+2581(for)X
+2700(the)X
+2823(tagstring,)X
+3148(which)X
+3369(can)X
+3506(be)X
+3607(in)X
+3694(a)X
+3755(different)X
+976 3438(\256le.)N
+1149(If)X
+1234(the)X
+1363(tag)X
+1492(is)X
+1576(in)X
+1669(a)X
+1736(different)X
+2044(\256le,)X
+2197(then)X
+2366(the)X
+2495(new)X
+2660(\256le)X
+2792(is)X
+2875(edited.)X
+3141(If)X
+3225(the)X
+3353(current)X
+3611(\256le)X
+3743(has)X
+3880(been)X
+976 3528(modi\256ed)N
+1283(since)X
+1471(the)X
+1592(last)X
+1726(complete)X
+2043(write,)X
+2251(the)X
+3 f
+2372(tag)X
+1 f
+2502(command)X
+2841(will)X
+2988(fail.)X
+3159(This)X
+3325(check)X
+3537(can)X
+3673(be)X
+3773(overrid-)X
+976 3618(den)N
+1112(by)X
+1212(appending)X
+1566(the)X
+1684(``)X
+7 f
+1738(!)X
+1 f
+('')S
+1880(character)X
+2196(to)X
+2278(the)X
+2396(command)X
+2732(name.)X
+976 3798(The)N
+3 f
+1128(tag)X
+1 f
+1262(command)X
+1605(searches)X
+1905(for)X
+7 f
+2026(tagstring)X
+1 f
+2485(in)X
+2574(the)X
+2699(tags)X
+2855(\256le\(s\))X
+3070(speci\256ed)X
+3383(by)X
+3491(the)X
+3617(option.)X
+3889(\(See)X
+2 f
+976 3888(ctags)N
+1 f
+1145(\(1\))X
+1259(for)X
+1373(more)X
+1558(information)X
+1956(on)X
+2056(tags)X
+2205(\256les.\))X
+976 4068(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(line)X
+1798(indicated)X
+2112(by)X
+2212(the)X
+2330(tag.)X
+976 4158(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(autowrite)X
+1 f
+2186(,)X
+3 f
+2226(taglength)X
+1 f
+(,)S
+3 f
+2586(tags)X
+1 f
+2744(and)X
+3 f
+2880(writeany)X
+1 f
+3203(options.)X
+3 f
+776 4338(tagp[op][!])N
+1166([\256le)X
+1315(|)X
+1353(number])X
+1 f
+976 4428(Pop)N
+1122(to)X
+1206(the)X
+1326(speci\256ed)X
+1633(tag)X
+1753(in)X
+1837(the)X
+1957(tags)X
+2108(stack.)X
+2335(If)X
+2411(neither)X
+7 f
+2656(file)X
+1 f
+2871(or)X
+7 f
+2961(number)X
+1 f
+3272(is)X
+3348(speci\256ed,)X
+3676(the)X
+3 f
+3797(tagpop)X
+1 f
+976 4518(command)N
+1313(pops)X
+1485(to)X
+1568(the)X
+1686(most)X
+1861(recent)X
+2078(entry)X
+2263(on)X
+2363(the)X
+2481(tags)X
+2630(stack.)X
+2855(If)X
+7 f
+2929(file)X
+1 f
+3141(or)X
+7 f
+3228(number)X
+1 f
+3536(is)X
+3609(speci\256ed,)X
+3934(the)X
+3 f
+976 4608(tagpop)N
+1 f
+1242(command)X
+1589(pops)X
+1771(to)X
+1864(the)X
+1993(most)X
+2179(recent)X
+2407(entry)X
+2603(in)X
+2696(the)X
+2825(tags)X
+2985(stack)X
+3181(for)X
+3306(that)X
+3458(\256le,)X
+3612(or)X
+3711(numbered)X
+976 4698(entry)N
+1165(in)X
+1251(the)X
+1373(tags)X
+1526(stack,)X
+1735(respectively.)X
+2186(\(See)X
+2352(the)X
+3 f
+2473(display)X
+1 f
+2739(command)X
+3078(for)X
+3195(information)X
+3596(on)X
+3699(displaying)X
+976 4788(the)N
+1094(tags)X
+1243(stack.\))X
+976 4968(If)N
+1051(the)X
+1170(\256le)X
+1293(has)X
+1421(been)X
+1594(modi\256ed)X
+1899(since)X
+2085(the)X
+2204(last)X
+2337(complete)X
+2653(write,)X
+2860(the)X
+3 f
+2980(tagpop)X
+1 f
+3237(command)X
+3575(will)X
+3721(fail.)X
+3890(This)X
+976 5058(check)N
+1184(may)X
+1342(be)X
+1438(overridden)X
+1806(by)X
+1906(appending)X
+2260(a)X
+2316(``)X
+7 f
+2370(!)X
+1 f
+('')S
+2512(character)X
+2828(to)X
+2910(the)X
+3028(command)X
+3364(name.)X
+976 5238(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(line)X
+1798(indicated)X
+2112(by)X
+2212(the)X
+2330(tag.)X
+976 5328(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(autowrite)X
+1 f
+2186(,)X
+2226(and)X
+3 f
+2362(writeany)X
+1 f
+2685(options.)X
+3 f
+776 5508(tagt[op][!])N
+1 f
+976 5598(Pop)N
+1120(to)X
+1202(the)X
+1320(least)X
+1487(recent)X
+1704(tag)X
+1822(on)X
+1922(the)X
+2040(tags)X
+2189(stack,)X
+2394(clearing)X
+2673(the)X
+2791(tags)X
+2940(stack.)X
+976 5778(If)N
+1051(the)X
+1170(\256le)X
+1293(has)X
+1421(been)X
+1594(modi\256ed)X
+1899(since)X
+2085(the)X
+2204(last)X
+2337(complete)X
+2653(write,)X
+2860(the)X
+3 f
+2980(tagpop)X
+1 f
+3237(command)X
+3575(will)X
+3721(fail.)X
+3890(This)X
+
+44 p
+%%Page: 44 43
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-44)N
+2813(Nvi/Nex)X
+3109 0.3906(Reference)AX
+3474(\(Ex)X
+3614(Commands\))X
+1 f
+976 762(check)N
+1184(may)X
+1342(be)X
+1438(overridden)X
+1806(by)X
+1906(appending)X
+2260(a)X
+2316(``)X
+7 f
+2370(!)X
+1 f
+('')S
+2512(character)X
+2828(to)X
+2910(the)X
+3028(command)X
+3364(name.)X
+976 942(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(line)X
+1798(indicated)X
+2112(by)X
+2212(the)X
+2330(tag.)X
+976 1032(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(autowrite)X
+1 f
+2186(,)X
+2226(and)X
+3 f
+2362(writeany)X
+1 f
+2685(options.)X
+3 f
+776 1212(una[bbrev])N
+1178(lhs)X
+1 f
+976 1302(Delete)N
+1206(an)X
+1302(abbreviation.)X
+1763(Delete)X
+7 f
+1993(lhs)X
+1 f
+2157(from)X
+2333(the)X
+2451(current)X
+2699(list)X
+2816(of)X
+2903(abbreviations.)X
+976 1482(Line:)N
+1336(Unchanged.)X
+976 1572(Options:)N
+1336(None.)X
+3 f
+776 1752(u[ndo])N
+1 f
+976 1842(Undo)N
+1177(the)X
+1298(last)X
+1432(change)X
+1683(made)X
+1880(to)X
+1965(the)X
+2086(\256le.)X
+2251(Changes)X
+2550(made)X
+2747(by)X
+3 f
+2850(global)X
+1 f
+3058(,)X
+3 f
+3101(v)X
+1 f
+(,)S
+3 f
+3184(visual)X
+1 f
+3406(and)X
+3545(map)X
+3706(sequences)X
+976 1932(are)N
+1103(considered)X
+1479(a)X
+1543(single)X
+1762(command.)X
+2146(If)X
+2228(repeated,)X
+2549(the)X
+3 f
+2675(u)X
+1 f
+2747(command)X
+3090(alternates)X
+3425(between)X
+3720(these)X
+3912(two)X
+976 2022(states,)N
+1194(and)X
+1330(is)X
+1403(its)X
+1498(own)X
+1656(inverse.)X
+976 2202(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(last)X
+1789(line)X
+1929(modi\256ed)X
+2233(by)X
+2333(the)X
+2451(command.)X
+976 2292(Options:)N
+1336(None.)X
+3 f
+776 2472(unm[ap][!])N
+1170(lhs)X
+1 f
+976 2562(Unmap)N
+1235(a)X
+1294(mapped)X
+1571(string.)X
+1816(Delete)X
+2049(the)X
+2170(command)X
+2509(mode)X
+2710(map)X
+2872(de\256nition)X
+3202(for)X
+7 f
+3320(lhs)X
+1 f
+(.)S
+3528(If)X
+3606(a)X
+3666(``)X
+7 f
+3720(!)X
+1 f
+('')S
+3866(char-)X
+976 2652(acter)N
+1153(is)X
+1226(appended)X
+1554(to)X
+1636(the)X
+1754(command)X
+2090(name,)X
+2304(delete)X
+2516(the)X
+2634(text)X
+2774(input)X
+2958(mode)X
+3156(map)X
+3314(de\256nition)X
+3640(instead.)X
+976 2832(Line:)N
+1336(Unchanged.)X
+976 2922(Options:)N
+1336(None.)X
+3 f
+776 3102(ve[rsion])N
+1 f
+976 3192(Display)N
+1245(the)X
+1363(version)X
+1619(of)X
+1706(the)X
+3 f
+1824(ex/vi)X
+1 f
+2004(editor.)X
+3 f
+776 3372([line])N
+974(vi[sual])X
+1247([type])X
+1468([count])X
+1733([\257ags])X
+976 3462(Ex)N
+1 f
+1092(mode)X
+1293(only.)X
+1498(Enter)X
+3 f
+1695(vi)X
+1 f
+1757(.)X
+1820(The)X
+7 f
+1968(type)X
+1 f
+2183(is)X
+2259(optional,)X
+2564(and)X
+2703(can)X
+2838(be)X
+2937(``)X
+7 f
+9 f
+2991(-)X
+1 f
+3035('',)X
+3132(``)X
+7 f
+3186(+)X
+1 f
+('')S
+3311(or)X
+3401(``)X
+7 f
+3455(\303)X
+1 f
+('',)S
+3600(as)X
+3690(in)X
+3775(the)X
+3 f
+3896(ex)X
+3996(z)X
+1 f
+976 3552(command,)N
+1337(to)X
+1424(specify)X
+1681(the)X
+1804(the)X
+1926(position)X
+2207(of)X
+2298(the)X
+2420(speci\256ed)X
+2729(line)X
+2873(in)X
+2959(the)X
+3081(screen)X
+3311(window.)X
+3633(\(The)X
+3809(default)X
+976 3642(is)N
+1054(to)X
+1141(place)X
+1336(the)X
+1459(line)X
+1605(at)X
+1689(the)X
+1813(top)X
+1941(of)X
+2034(the)X
+2158(screen)X
+2390(window.\))X
+2741(A)X
+7 f
+2825(count)X
+1 f
+3091(speci\256es)X
+3393(the)X
+3517(number)X
+3788(of)X
+3881(lines)X
+976 3732(that)N
+1116(will)X
+1260(initially)X
+1528(be)X
+1624(displayed.)X
+1991(\(The)X
+2163(default)X
+2406(is)X
+2479(the)X
+2597(value)X
+2791(of)X
+2878(the)X
+3 f
+2996(window)X
+1 f
+3282(editor)X
+3489(option.\))X
+976 3912(Line:)N
+1336(Unchanged)X
+1722(unless)X
+7 f
+1942(line)X
+1 f
+2154(is)X
+2227(speci\256ed,)X
+2552(in)X
+2634(which)X
+2850(case)X
+3009(it)X
+3073(is)X
+3146(set)X
+3255(to)X
+3337(that)X
+3477(line.)X
+976 4002(Options:)N
+1336(None.)X
+3 f
+776 4182(vi[sual][!])N
+1130([+cmd])X
+1397([\256le])X
+976 4272(Vi)N
+1 f
+1076(mode)X
+1274(only.)X
+1476(Edit)X
+1629(a)X
+1685(new)X
+1839(\256le.)X
+2001(Identical)X
+2302(to)X
+2384(the)X
+2502(``)X
+7 f
+2556(edit[!])X
+2940([+cmd])X
+3276([file])X
+1 f
+('')S
+3638(command.)X
+3 f
+776 4452(viu[sage])N
+1103([command])X
+1 f
+976 4542(Display)N
+1253(usage)X
+1464(for)X
+1586(a)X
+3 f
+1650(vi)X
+1 f
+1740(command.)X
+2124(If)X
+7 f
+2206(command)X
+1 f
+2570(is)X
+2651(speci\256ed,)X
+2984(a)X
+3048(usage)X
+3259(statement)X
+3595(for)X
+3718(that)X
+3867(com-)X
+976 4632(mand)N
+1174(is)X
+1247(displayed.)X
+1614(Otherwise,)X
+1984(usage)X
+2187(statements)X
+2545(for)X
+2659(all)X
+3 f
+2759(vi)X
+1 f
+2841(commands)X
+3208(are)X
+3327(displayed.)X
+976 4812(Line:)N
+1336(Unchanged.)X
+976 4902(Options:)N
+1336(None.)X
+3 f
+776 5082([range])N
+1046 0.3611(w[rite][!])AX
+1380([>>])X
+1546([\256le])X
+776 5172([range])N
+1046(w[rite])X
+1299([!])X
+1400([\256le])X
+776 5262([range])N
+1046(wn[!])X
+1249([>>])X
+1415([\256le])X
+776 5352([range])N
+1046(wq[!])X
+1249([>>])X
+1415([\256le])X
+1 f
+976 5442(Write)N
+1183(the)X
+1305(\256le.)X
+1472(The)X
+1622(speci\256ed)X
+1932(lines)X
+2108(\(the)X
+2258(entire)X
+2466(\256le,)X
+2613(if)X
+2687(no)X
+2792(range)X
+2996(is)X
+3074(given\))X
+3304(is)X
+3382(written)X
+3634(to)X
+7 f
+3721(file)X
+1 f
+(.)S
+3978(If)X
+7 f
+976 5532(file)N
+1 f
+1195(is)X
+1275(not)X
+1403(speci\256ed,)X
+1734(the)X
+1858(current)X
+2112(pathname)X
+2450(is)X
+2529(used.)X
+2742(If)X
+7 f
+2822(file)X
+1 f
+3040(is)X
+3119(speci\256ed,)X
+3450(and)X
+3592(it)X
+3662(exists,)X
+3890(or)X
+3983(if)X
+976 5622(the)N
+1101(current)X
+1356(pathname)X
+1695(was)X
+1847(set)X
+1963(using)X
+2163(the)X
+3 f
+2288(\256le)X
+1 f
+2417(command,)X
+2780(and)X
+2923(the)X
+3049(\256le)X
+3179(already)X
+3444(exists,)X
+3674(these)X
+3867(com-)X
+976 5712(mands)N
+1212(will)X
+1363(fail.)X
+1537(Appending)X
+1919(a)X
+1981(``)X
+7 f
+2035(!)X
+1 f
+('')S
+2183(character)X
+2505(to)X
+2593(the)X
+2717(command)X
+3059(name)X
+3259(will)X
+3409(override)X
+3703(this)X
+3844(check)X
+976 5802(and)N
+1112(the)X
+1230(write)X
+1415(will)X
+1559(be)X
+1655(attempted,)X
+2011(regardless.)X
+
+45 p
+%%Page: 45 44
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+1237(\(Ex)X
+1377(Commands\))X
+3658(USD:13-45)X
+1 f
+976 762(Specifying)N
+1348(the)X
+1471(optional)X
+1758(``)X
+7 f
+1812(>>)X
+1 f
+('')S
+1987(string)X
+2194(will)X
+2344(cause)X
+2549(the)X
+2673(write)X
+2864(to)X
+2952(be)X
+3054(appended)X
+3388(to)X
+3476(the)X
+3600(\256le,)X
+3748(in)X
+3836(which)X
+976 852(case)N
+1135(no)X
+1235(tests)X
+1397(are)X
+1516(made)X
+1710(for)X
+1824(the)X
+1942(\256le)X
+2064(already)X
+2321(existing.)X
+976 1032(If)N
+1060(the)X
+1188(\256le)X
+1320(is)X
+1403(preceded)X
+1724(by)X
+1834(a)X
+1900(``)X
+7 f
+1954(!)X
+1 f
+('')S
+2106(character,)X
+2452(the)X
+2580(program)X
+2882(named)X
+3126(in)X
+3218(the)X
+3347(SHELL)X
+3627(environment)X
+976 1122(variable)N
+1258(is)X
+1334(invoked)X
+1615(with)X
+1780(\256le)X
+1905(as)X
+1995(its)X
+2093(second)X
+2339(argument,)X
+2685(and)X
+2824(the)X
+2945(speci\256ed)X
+3253(lines)X
+3427(are)X
+3549(passed)X
+3786(as)X
+3876(stan-)X
+976 1212(dard)N
+1143(input)X
+1331(to)X
+1417(that)X
+1561(command.)X
+1941(The)X
+2090(``)X
+7 f
+2144(!)X
+1 f
+('')S
+2291(in)X
+2378(this)X
+2518(usage)X
+2726(must)X
+2906(be)X
+3007(separated)X
+3336(from)X
+3517(command)X
+3858(name)X
+976 1302(by)N
+1080(at)X
+1162(least)X
+1333(one)X
+1473(whitespace)X
+1854(character.)X
+2214(The)X
+2363(special)X
+2610(meaning)X
+2910(of)X
+3001(the)X
+3122(``)X
+7 f
+3176(!)X
+1 f
+('')S
+3321(may)X
+3482(be)X
+3581(overridden)X
+3952(by)X
+976 1392(escaping)N
+1277(it)X
+1341(with)X
+1503(a)X
+1559(backslash)X
+1891(\(``)X
+7 f
+1972(\\)X
+1 f
+(''\))S
+2121(character.)X
+976 1572(The)N
+3 f
+1124(wq)X
+1 f
+1249(version)X
+1509(of)X
+1600(the)X
+1722(write)X
+1911(command)X
+2251(will)X
+2399(exit)X
+2543(the)X
+2665(editor)X
+2876(after)X
+3048(writing)X
+3303(the)X
+3425(\256le,)X
+3571(if)X
+3644(there)X
+3829(are)X
+3952(no)X
+976 1662(further)N
+1232(\256les)X
+1402(to)X
+1501(edit.)X
+1698(Appending)X
+2091(a)X
+2164(``)X
+7 f
+2218(!)X
+1 f
+('')S
+2377(character)X
+2710(to)X
+2809(the)X
+2944(command)X
+3297(name)X
+3508(or)X
+3612(entering)X
+3912(two)X
+976 1752(``quit'')N
+1232(commands)X
+1603(\(i.e.)X
+3 f
+1772(wq)X
+1 f
+1874(,)X
+3 f
+1918(quit)X
+1 f
+2055(,)X
+3 f
+2099(xit)X
+1 f
+2212(or)X
+3 f
+2303(ZZ)X
+1 f
+2409(\))X
+2461(in)X
+2548(a)X
+2609(row\))X
+2786(will)X
+2935(override)X
+3228(this)X
+3368(check)X
+3581(and)X
+3722(the)X
+3845(editor)X
+976 1842(will)N
+1120(exit,)X
+1280(ignoring)X
+1571(any)X
+1707(\256les)X
+1860(that)X
+2000(have)X
+2172(not)X
+2294(yet)X
+2412(been)X
+2584(edited.)X
+976 2022(The)N
+3 f
+1127(wn)X
+1 f
+1255(version)X
+1517(of)X
+1610(the)X
+1734(write)X
+1925(command)X
+2267(will)X
+2417(move)X
+2621(to)X
+2709(the)X
+2833(next)X
+2997(\256le)X
+3125(after)X
+3300(writing)X
+3558(the)X
+3683(\256le,)X
+3832(unless)X
+976 2112(the)N
+1094(write)X
+1279(fails.)X
+976 2292(Line:)N
+1336(Unchanged.)X
+976 2382(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(readonly)X
+1 f
+2178(and)X
+3 f
+2314(writeany)X
+1 f
+2637(options.)X
+3 f
+776 2562([range])N
+1046(x[it][!])X
+1290([\256le])X
+1 f
+976 2652(Write)N
+1185(the)X
+1309(\256le)X
+1437(if)X
+1512(it)X
+1582(has)X
+1715(been)X
+1894(modi\256ed.)X
+2245(The)X
+2397(speci\256ed)X
+2709(lines)X
+2887(are)X
+3013(written)X
+3267(to)X
+7 f
+3356(file)X
+1 f
+(,)S
+3595(if)X
+3671(the)X
+3796(\256le)X
+3925(has)X
+976 2742(been)N
+1149(modi\256ed)X
+1454(since)X
+1640(the)X
+1759(last)X
+1891(complete)X
+2206(write)X
+2392(to)X
+2475(any)X
+2612(\256le.)X
+2775(If)X
+2850(no)X
+7 f
+2951(range)X
+1 f
+3211(is)X
+3284(speci\256ed,)X
+3609(the)X
+3727(entire)X
+3930(\256le)X
+976 2832(is)N
+1049(written.)X
+976 3012(The)N
+3 f
+1126(xit)X
+1 f
+1240(command)X
+1581(will)X
+1730(exit)X
+1875(the)X
+1998(editor)X
+2210(after)X
+2383(writing)X
+2639(the)X
+2762(\256le,)X
+2909(if)X
+2983(there)X
+3169(are)X
+3294(no)X
+3400(further)X
+3645(\256les)X
+3804(to)X
+3892(edit.)X
+976 3102(Appending)N
+1362(a)X
+1428(``)X
+7 f
+1482(!)X
+1 f
+('')S
+1634(character)X
+1960(to)X
+2052(the)X
+2180(command)X
+2526(name)X
+2730(or)X
+2827(entering)X
+3120(two)X
+3270(``quit'')X
+3531(commands)X
+3907(\(i.e.)X
+3 f
+976 3192(wq)N
+1 f
+1078(,)X
+3 f
+1125(quit)X
+1 f
+1262(,)X
+3 f
+1309(xit)X
+1 f
+1425(or)X
+3 f
+1519(ZZ)X
+1 f
+1625(\))X
+1679(in)X
+1768(a)X
+1831(row\))X
+2010(will)X
+2161(override)X
+2456(this)X
+2598(check)X
+2813(and)X
+2956(the)X
+3082(editor)X
+3297(will)X
+3449(exit,)X
+3617(ignoring)X
+3916(any)X
+976 3282(\256les)N
+1129(that)X
+1269(have)X
+1441(not)X
+1563(yet)X
+1681(been)X
+1853(edited.)X
+976 3462(Line:)N
+1336(Unchanged.)X
+976 3552(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+3 f
+1856(readonly)X
+1 f
+2178(and)X
+3 f
+2314(writeany)X
+1 f
+2637(options.)X
+3 f
+776 3732([range])N
+1046(ya[nk])X
+1288([buffer])X
+1576([count])X
+1 f
+976 3822(Copy)N
+1169(the)X
+1287(speci\256ed)X
+1592(lines)X
+1763(to)X
+1845(a)X
+1901(buffer.)X
+2158(If)X
+2232(no)X
+2332(buffer)X
+2549(is)X
+2622(speci\256ed,)X
+2947(the)X
+3065(unnamed)X
+3379(buffer)X
+3596(is)X
+3669(used.)X
+976 4002(Line:)N
+1336(Unchanged.)X
+976 4092(Options:)N
+1336(None.)X
+3 f
+776 4272([line])N
+974(z)X
+1030([type])X
+1251([count])X
+1516([\257ags])X
+1 f
+976 4362(Adjust)N
+1210(the)X
+1329(window.)X
+1648(If)X
+1723(no)X
+7 f
+1824(type)X
+1 f
+2037(is)X
+2111(speci\256ed,)X
+2437(then)X
+7 f
+2596(count)X
+1 f
+2858(lines)X
+3031(following)X
+3364(the)X
+3484(speci\256ed)X
+3791(line)X
+3933(are)X
+976 4452(displayed.)N
+1362(The)X
+1526(default)X
+7 f
+1788(count)X
+1 f
+2067(is)X
+2159(the)X
+2296(value)X
+2509(of)X
+2614(the)X
+3 f
+2750(window)X
+1 f
+3054(option.)X
+3336(The)X
+7 f
+3499(type)X
+1 f
+3729(argument)X
+976 4542(changes)N
+1266(the)X
+1395(position)X
+1683(at)X
+1772(which)X
+7 f
+1999(line)X
+1 f
+2222(is)X
+2306(displayed)X
+2644(on)X
+2755(the)X
+2884(screen)X
+3121(by)X
+3232(changing)X
+3558(the)X
+3688(number)X
+3965(of)X
+976 4632(lines)N
+1147(displayed)X
+1474(before)X
+1700(and)X
+1836(after)X
+7 f
+2004(line)X
+1 f
+(.)S
+2256(The)X
+2401(following)X
+7 f
+2732(type)X
+1 f
+2944(characters)X
+3291(may)X
+3449(be)X
+3545(used:)X
+9 f
+976 4812(-)N
+1 f
+1336(Place)X
+1530(the)X
+1648(line)X
+1788(at)X
+1866(the)X
+1984(bottom)X
+2230(of)X
+2317(the)X
+2435(screen.)X
+976 4902(+)N
+1336(Place)X
+1530(the)X
+1648(line)X
+1788(at)X
+1866(the)X
+1984(top)X
+2106(of)X
+2193(the)X
+2311(screen.)X
+976 4992(.)N
+1336(Place)X
+1530(the)X
+1648(line)X
+1788(in)X
+1870(the)X
+1988(middle)X
+2230(of)X
+2317(the)X
+2435(screen.)X
+976 5082(\303)N
+1336(Write)X
+1540(out)X
+1663(count)X
+1862(lines)X
+2034(starting)X
+7 f
+2295(count)X
+2584(*)X
+2681(2)X
+1 f
+2750(lines)X
+2922(before)X
+7 f
+3149(line)X
+1 f
+(;)S
+3384(the)X
+3503(net)X
+3622(effect)X
+3828(of)X
+3917(this)X
+1336 5172(is)N
+1409(that)X
+1549(a)X
+1605(``)X
+7 f
+1659(z\303)X
+1 f
+('')S
+1829(command)X
+2165(following)X
+2496(a)X
+3 f
+2552(z)X
+1 f
+2608(command)X
+2944(writes)X
+3160(the)X
+3278(previous)X
+3574(page.)X
+976 5262(=)N
+1336(Center)X
+7 f
+1580(line)X
+1 f
+1802(on)X
+1912(the)X
+2040(screen)X
+2276(with)X
+2448(a)X
+2514(line)X
+2664(of)X
+2761(hyphens)X
+3058(displayed)X
+3395(immediately)X
+3826(before)X
+1336 5352(and)N
+1485(after)X
+1666(it.)X
+1783(The)X
+1941(number)X
+2219(of)X
+2319(preceding)X
+2669(and)X
+2817(following)X
+3160(lines)X
+3343(of)X
+3442(text)X
+3594(displayed)X
+3933(are)X
+1336 5442(reduced)N
+1611(to)X
+1693(account)X
+1963(for)X
+2077(those)X
+2266(lines.)X
+976 5622(Line:)N
+1336(Set)X
+1458(to)X
+1540(the)X
+1658(last)X
+1789(line)X
+1929(displayed,)X
+2276(with)X
+2438(the)X
+2556(exception)X
+2888(of)X
+2975(the)X
+7 f
+3093(type)X
+1 f
+(,)S
+3326(where)X
+3544(the)X
+3663(current)X
+3912(line)X
+1336 5712(is)N
+1409(set)X
+1518(to)X
+1600(the)X
+1718(line)X
+1858(speci\256ed)X
+2163(by)X
+2263(the)X
+2381(command.)X
+
+46 p
+%%Page: 46 45
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-46)N
+2813(Nvi/Nex)X
+3109 0.3906(Reference)AX
+3474(\(Ex)X
+3614(Commands\))X
+1 f
+976 762(Options:)N
+1336(Affected)X
+1638(by)X
+1738(the)X
+1856(option.)X
+3 f
+776 948(15.)N
+916(Set)X
+1043(Options)X
+1 f
+976 1071(There)N
+1186(are)X
+1307(a)X
+1365(large)X
+1548(number)X
+1815(of)X
+1904(options)X
+2161(that)X
+2303(may)X
+2463(be)X
+2561(set)X
+2672(\(or)X
+2788(unset\))X
+3006(to)X
+3091(change)X
+3342(the)X
+3463(editor's)X
+3731(behavior.)X
+776 1161(This)N
+938(section)X
+1185(describes)X
+1504(the)X
+1622(options,)X
+1897(their)X
+2064(abbreviations)X
+2516(and)X
+2652(their)X
+2819(default)X
+3062(values.)X
+976 1284(In)N
+1064(each)X
+1233(entry)X
+1419(below,)X
+1656(the)X
+1775(\256rst)X
+1920(part)X
+2066(of)X
+2154(the)X
+2273(tag)X
+2392(line)X
+2533(is)X
+2607(the)X
+2726(full)X
+2858(name)X
+3053(of)X
+3141(the)X
+3261(option,)X
+3507(followed)X
+3814(by)X
+3916(any)X
+776 1374(equivalent)N
+1135(abbreviations.)X
+1632(\(Regardless)X
+2036(of)X
+2128(the)X
+2251(abbreviations,)X
+2728(it)X
+2797(is)X
+2875(only)X
+3042(necessary)X
+3380(to)X
+3467(use)X
+3599(the)X
+3722(minimum)X
+776 1464(number)N
+1047(of)X
+1140(characters)X
+1493(necessary)X
+1832(to)X
+1920(distinguish)X
+2296(an)X
+2398(abbreviation)X
+2825(from)X
+3007(all)X
+3113(other)X
+3304(commands)X
+3677(for)X
+3797(it)X
+3867(to)X
+3956(be)X
+776 1554(accepted,)N
+1099(in)X
+3 f
+1182(nex)X
+1 f
+(/)S
+3 f
+1324(nvi)X
+1 f
+1430(.)X
+1491(Historically,)X
+1910(only)X
+2073(the)X
+2192(full)X
+2324(name)X
+2519(and)X
+2656(the)X
+2774(of\256cial)X
+3021(abbreviations)X
+3473(were)X
+3650(accepted)X
+3952(by)X
+3 f
+776 1644(ex)N
+1 f
+852(/)X
+3 f
+874(vi)X
+1 f
+936(.)X
+1002(Using)X
+1220(full)X
+1358(names)X
+1590(in)X
+1679(your)X
+1853(startup)X
+2098(\256les)X
+2258(and)X
+2401(environmental)X
+2891(variables)X
+3208(will)X
+3359(probably)X
+3671(make)X
+3872(them)X
+776 1734(more)N
+968(portable.\))X
+1325(The)X
+1477(part)X
+1629(in)X
+1718(square)X
+1955(brackets)X
+2250(is)X
+2330(the)X
+2454(default)X
+2703(value)X
+2903(of)X
+2996(the)X
+3120(option.)X
+3390(Most)X
+3580(of)X
+3673(the)X
+3797(options)X
+776 1824(are)N
+895(boolean,)X
+1189(i.e.)X
+1307(they)X
+1465(are)X
+1584(either)X
+1787(on)X
+1887(or)X
+1974(off,)X
+2108(and)X
+2244(do)X
+2344(not)X
+2466(have)X
+2638(an)X
+2734(associated)X
+3084(value.)X
+976 1947(Options)N
+1249(apply)X
+1447(to)X
+1529(both)X
+3 f
+1691(ex)X
+1 f
+1787(and)X
+3 f
+1923(vi)X
+1 f
+2005(modes,)X
+2254(unless)X
+2474(otherwise)X
+2806(speci\256ed.)X
+976 2070(For)N
+1107(information)X
+1505(on)X
+1605(modifying)X
+1958(the)X
+2076(options)X
+2331(or)X
+2419(to)X
+2502(display)X
+2754(the)X
+2873(options)X
+3129(and)X
+3266(their)X
+3434(current)X
+3683(values,)X
+3929(see)X
+776 2160(the)N
+894(``set'')X
+1111(command)X
+1447(in)X
+1529(the)X
+1647(section)X
+1894(entitled)X
+2154(``)X
+3 f
+2208(Ex)X
+2321(Commands)X
+1 f
+2712(''.)X
+3 f
+776 2340(altwerase)N
+1122([off])X
+976 2430(Vi)N
+1 f
+1084(only.)X
+1295(Change)X
+1569(how)X
+3 f
+1736(vi)X
+1 f
+1827(does)X
+2003(word)X
+2197(erase)X
+2392(during)X
+2630(text)X
+2779(input.)X
+3012(When)X
+3233(this)X
+3377(option)X
+3610(is)X
+3692(set,)X
+3830(text)X
+3979(is)X
+976 2520(broken)N
+1230(up)X
+1340(into)X
+1494(three)X
+1685(classes:)X
+1960(alphabetic,)X
+2340(numeric)X
+2633(and)X
+2779(underscore)X
+3162(characters,)X
+3539(other)X
+3734(nonblank)X
+976 2610(characters,)N
+1343(and)X
+1479(blank)X
+1677(characters.)X
+2064(Changing)X
+2395(from)X
+2571(one)X
+2707(class)X
+2884(to)X
+2967(another)X
+3229(marks)X
+3446(the)X
+3565(end)X
+3702(of)X
+3790(a)X
+3847(word.)X
+976 2700(In)N
+1070(addition,)X
+1379(the)X
+1504(class)X
+1687(of)X
+1781(the)X
+1906(\256rst)X
+2057(character)X
+2380(erased)X
+2612(is)X
+2691(ignored)X
+2962(\(which)X
+3211(is)X
+3290(exactly)X
+3548(what)X
+3730(you)X
+3876(want)X
+976 2790(when)N
+1170(erasing)X
+1422(pathname)X
+1754(components\).)X
+3 f
+776 2970(autoindent,)N
+1184(ai)X
+1266([off])X
+1 f
+976 3060(If)N
+1052(this)X
+1189(option)X
+1415(is)X
+1490(set,)X
+1621(whenever)X
+1956(you)X
+2098(create)X
+2313(a)X
+2371(new)X
+2527(line)X
+2669(\(using)X
+2891(the)X
+3 f
+3012(vi)X
+3097(A)X
+1 f
+3155(,)X
+3 f
+3198(a)X
+1 f
+(,)S
+3 f
+3281(C)X
+1 f
+3339(,)X
+3 f
+3382(c)X
+1 f
+3418(,)X
+3 f
+3461(I)X
+1 f
+3492(,)X
+3 f
+3535(i)X
+1 f
+3557(,)X
+3 f
+3600(O)X
+1 f
+3662(,)X
+3 f
+3705(o)X
+1 f
+(,)S
+3 f
+3788(R)X
+1 f
+3846(,)X
+3 f
+3889(r)X
+1 f
+3925(,)X
+3 f
+3968(S)X
+1 f
+4012(,)X
+976 3150(and)N
+3 f
+1117(s)X
+1 f
+1173(commands,)X
+1565(or)X
+1657(the)X
+3 f
+1780(ex)X
+1881(append)X
+1 f
+2133(,)X
+3 f
+2178(change)X
+1 f
+(,)S
+2463(and)X
+3 f
+2604(insert)X
+1 f
+2825(commands\))X
+3224(the)X
+3346(new)X
+3504(line)X
+3648(is)X
+3725(automati-)X
+976 3240(cally)N
+1156(indented)X
+1456(to)X
+1542(align)X
+1726(the)X
+1848(cursor)X
+2073(with)X
+2239(the)X
+2361(\256rst)X
+2509(nonblank)X
+2831(character)X
+3151(of)X
+3242(the)X
+3365(line)X
+3510(from)X
+3691(which)X
+3912(you)X
+976 3330(created)N
+1231(it.)X
+1337(Lines)X
+1537(are)X
+1658(indented)X
+1956(using)X
+2150(tab)X
+2269(characters)X
+2617(to)X
+2700(the)X
+2819(extent)X
+3036(possible)X
+3319(\(based)X
+3550(on)X
+3651(the)X
+3770(value)X
+3965(of)X
+976 3420(the)N
+3 f
+1094(tabstop)X
+1 f
+1367(option\))X
+1618(and)X
+1754(then)X
+1912(using)X
+2105(space)X
+2304(characters)X
+2651(as)X
+2738(necessary.)X
+3111(For)X
+3243(commands)X
+3611(inserting)X
+3912(text)X
+976 3510(into)N
+1124(the)X
+1246(middle)X
+1492(of)X
+1583(a)X
+1643(line,)X
+1807(any)X
+1947(blank)X
+2149(characters)X
+2500(to)X
+2586(the)X
+2708(right)X
+2883(of)X
+2974(the)X
+3096(cursor)X
+3321(are)X
+3444(discarded,)X
+3795(and)X
+3934(the)X
+976 3600(\256rst)N
+1120(nonblank)X
+1438(character)X
+1754(to)X
+1836(the)X
+1954(right)X
+2125(of)X
+2212(the)X
+2330(cursor)X
+2551(is)X
+2624(aligned)X
+2880(as)X
+2967(described)X
+3295(above.)X
+976 3780(The)N
+1128(indent)X
+1355(characters)X
+1709(are)X
+1835(themselves)X
+2218(somewhat)X
+2570(special.)X
+2860(If)X
+2941(you)X
+3088(do)X
+3195(not)X
+3324(enter)X
+3512(more)X
+3705(characters)X
+976 3870(on)N
+1085(the)X
+1212(new)X
+1375(line)X
+1524(before)X
+1759(moving)X
+2032(to)X
+2123(another)X
+2393(line,)X
+2562(or)X
+2658(entering)X
+7 f
+2950(<escape>)X
+1 f
+(,)S
+3382(the)X
+3508(indent)X
+3736(character)X
+976 3960(will)N
+1121(be)X
+1218(deleted)X
+1471(and)X
+1608(the)X
+1727(line)X
+1868(will)X
+2013(be)X
+2111(empty.)X
+2373(For)X
+2506(example,)X
+2820(if)X
+2891(you)X
+3033(enter)X
+7 f
+3216(<carriage-return>)X
+1 f
+976 4050(twice)N
+1181(in)X
+1274(succession,)X
+1668(the)X
+1797(line)X
+1947(created)X
+2210(by)X
+2320(the)X
+2448(\256rst)X
+7 f
+2602(<carriage-return>)X
+1 f
+3448(will)X
+3602(not)X
+3734(have)X
+3916(any)X
+976 4140(characters)N
+1323(in)X
+1405(it,)X
+1489(regardless)X
+1835(of)X
+1922(the)X
+2040(indentation)X
+2420(of)X
+2507(the)X
+2625(previous)X
+2921(or)X
+3008(subsequent)X
+3384(line.)X
+976 4320(Indent)N
+1210(characters)X
+1566(also)X
+1725(require)X
+1983(that)X
+2133(you)X
+2283(enter)X
+2474(additional)X
+2824(erase)X
+3020(characters)X
+3377(to)X
+3469(delete)X
+3691(them.)X
+3921(For)X
+976 4410(example,)N
+1290(if)X
+1361(you)X
+1503(have)X
+1677(an)X
+1775(indented)X
+2072(line,)X
+2233(containing)X
+2592(only)X
+2755(blanks,)X
+3005(the)X
+3124(\256rst)X
+7 f
+3269(<word-erase>)X
+1 f
+3866(char-)X
+976 4500(acter)N
+1156(you)X
+1299(enter)X
+1483(will)X
+1630(erase)X
+1819(up)X
+1922(to)X
+2007(end)X
+2146(of)X
+2236(the)X
+2357(indent)X
+2580(characters,)X
+2950(and)X
+3089(the)X
+3210(second)X
+3456(will)X
+3604(erase)X
+3794(back)X
+3970(to)X
+976 4590(the)N
+1094(beginning)X
+1434(of)X
+1521(the)X
+1639(line.)X
+1819(\(Historically,)X
+2264(only)X
+2426(the)X
+3 f
+2544(<control-D>)X
+1 f
+2986(key)X
+3122(would)X
+3342(erase)X
+3528(the)X
+3646(indent)X
+3866(char-)X
+976 4680(acters.)N
+1231(Both)X
+1413(the)X
+3 f
+1538(<control-D>)X
+1 f
+1988(key)X
+2132(and)X
+2276(the)X
+2402(usual)X
+2599(erase)X
+2793(keys)X
+2968(work)X
+3161(in)X
+3 f
+3251(nvi)X
+1 f
+3357(.\))X
+3452(In)X
+3547(addition,)X
+3857(if)X
+3934(the)X
+976 4770(cursor)N
+1211(is)X
+1298(positioned)X
+1665(at)X
+1756(the)X
+1887(end)X
+2036(of)X
+2136(the)X
+2267(indent)X
+2500(characters,)X
+2880(the)X
+3011(keys)X
+3191(``)X
+7 f
+3245(0<control-D>)X
+1 f
+('')S
+3908(will)X
+976 4860(erase)N
+1163(all)X
+1264(of)X
+1352(the)X
+1472(indent)X
+1694(characters)X
+2043(for)X
+2159(the)X
+2279(current)X
+2529(line,)X
+2691(resetting)X
+2989(the)X
+3109(indentation)X
+3491(level)X
+3669(to)X
+3753(0.)X
+3855(Simi-)X
+976 4950(larly,)N
+1168(the)X
+1291(keys)X
+1462(``)X
+7 f
+1516(\303<control-D>)X
+1 f
+('')S
+2170(will)X
+2318(erase)X
+2508(all)X
+2612(of)X
+2703(the)X
+2825(indent)X
+3049(characters)X
+3400(for)X
+3518(the)X
+3640(current)X
+3892(line,)X
+976 5040(leaving)N
+1232(the)X
+1350(indentation)X
+1730(level)X
+1906(for)X
+2020(future)X
+2232(created)X
+2485(lines)X
+2656(unaffected.)X
+976 5220(Finally,)N
+1243(if)X
+1313(the)X
+3 f
+1432(autoindent)X
+1 f
+1821(option)X
+2047(is)X
+2122(set,)X
+2253(the)X
+3 f
+2373(S)X
+1 f
+2439(and)X
+3 f
+2577(cc)X
+1 f
+2671(commands)X
+3040(change)X
+3290(from)X
+3468(the)X
+3588(\256rst)X
+3734(nonblank)X
+976 5310(of)N
+1063(the)X
+1181(line)X
+1321(to)X
+1403(the)X
+1521(end)X
+1657(of)X
+1744(the)X
+1862(line,)X
+2022(instead)X
+2269(of)X
+2356(from)X
+2532(the)X
+2650(beginning)X
+2990(of)X
+3077(the)X
+3195(line)X
+3335(to)X
+3417(the)X
+3535(end)X
+3671(of)X
+3758(the)X
+3876(line.)X
+3 f
+776 5490(autoprint,)N
+1140(ap)X
+1244([off])X
+976 5580(Ex)N
+1 f
+1099(only.)X
+1311(Cause)X
+1537(the)X
+1665(current)X
+1923(line)X
+2073(to)X
+2165(be)X
+2271(automatically)X
+2738(displayed)X
+3076(after)X
+3255(the)X
+3 f
+3384(ex)X
+1 f
+3491(commands)X
+3 f
+3869(<)X
+1 f
+3915(,)X
+3 f
+3966(>)X
+1 f
+4012(,)X
+3 f
+976 5670(copy)N
+1 f
+(,)S
+3 f
+1176(delete)X
+1 f
+1377(,)X
+3 f
+1417(join)X
+1 f
+1550(,)X
+3 f
+1590(move)X
+1 f
+1773(,)X
+3 f
+1813(put)X
+1 f
+1928(,)X
+3 f
+1968(t)X
+1 f
+1995(,)X
+3 f
+2035(Undo)X
+1 f
+2221(,)X
+2261(and)X
+3 f
+2397(undo)X
+1 f
+2569(.)X
+2629(This)X
+2791(automatic)X
+3127(display)X
+3378(is)X
+3451(suppressed)X
+3823(during)X
+3 f
+976 5760(global)N
+1 f
+1226(and)X
+3 f
+1384(vglobal)X
+1 f
+1675(commands,)X
+2085(and)X
+2244(for)X
+2381(any)X
+2540(command)X
+2899(where)X
+3139(optional)X
+3444(\257ags)X
+3638(are)X
+3780(used)X
+3970(to)X
+
+47 p
+%%Page: 47 46
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3658(USD:13-47)X
+1 f
+976 762(explicitly)N
+1298(display)X
+1549(the)X
+1667(line.)X
+3 f
+776 942(autowrite,)N
+1146(aw)X
+1264([off])X
+1 f
+976 1032(If)N
+1053(this)X
+1191(option)X
+1418(is)X
+1494(set,)X
+1626(the)X
+3 f
+1747(vi)X
+1832(!)X
+1 f
+1859(,)X
+3 f
+1902(\303\303)X
+1 f
+1956(,)X
+3 f
+1999(\303])X
+1 f
+2076(and)X
+3 f
+2215(<control-Z>)X
+1 f
+2655(commands,)X
+3046(and)X
+3186(the)X
+3 f
+3308(ex)X
+3408(edit)X
+1 f
+3537(,)X
+3 f
+3581(next)X
+1 f
+3728(,)X
+3 f
+3772(rewind)X
+1 f
+(,)S
+3 f
+976 1122(stop)N
+1 f
+1118(,)X
+3 f
+1161(suspend)X
+1 f
+1435(,)X
+3 f
+1478(tag)X
+1 f
+1585(,)X
+3 f
+1628(tagpop)X
+1 f
+1863(,)X
+1906(and)X
+3 f
+2045(tagtop)X
+1 f
+2286(commands)X
+2656(automatically)X
+3115(write)X
+3302(the)X
+3422(current)X
+3672(\256le)X
+3796(back)X
+3970(to)X
+976 1212(the)N
+1103(current)X
+1360(\256le)X
+1491(name)X
+1694(if)X
+1772(it)X
+1845(has)X
+1981(been)X
+2163(modi\256ed)X
+2477(since)X
+2672(it)X
+2746(was)X
+2901(last)X
+3042(written.)X
+3339(If)X
+3423(the)X
+3551(write)X
+3746(fails,)X
+3934(the)X
+976 1302(command)N
+1312(fails)X
+1470(and)X
+1606(goes)X
+1773(no)X
+1873(further.)X
+976 1482(Appending)N
+1363(the)X
+1492(optional)X
+1785(force)X
+1982(\257ag)X
+2133(character)X
+2460(``)X
+7 f
+2514(!)X
+1 f
+('')S
+2668(to)X
+2762(the)X
+3 f
+2892(ex)X
+1 f
+3000(commands)X
+3 f
+3379(next)X
+1 f
+3526(,)X
+3 f
+3578(rewind)X
+1 f
+(,)S
+3 f
+3870(stop)X
+1 f
+4012(,)X
+3 f
+976 1572(suspend)N
+1 f
+1250(,)X
+3 f
+1290(tag)X
+1 f
+1397(,)X
+3 f
+1437(tagpop)X
+1 f
+1672(,)X
+1712(and)X
+3 f
+1848(tagtop)X
+1 f
+2086(stops)X
+2270(the)X
+2388(automatic)X
+2724(write)X
+2909(from)X
+3085(being)X
+3283(attempted.)X
+976 1752(\(Historically,)N
+1421(the)X
+3 f
+1539(next)X
+1 f
+1706(command)X
+2042(ignored)X
+2307(the)X
+2425(optional)X
+2707(force)X
+2894(\257ag.\))X
+3102(Note,)X
+3299(the)X
+3 f
+3418(ex)X
+1 f
+3515(commands)X
+3 f
+3883(edit)X
+1 f
+4012(,)X
+3 f
+976 1842(quit)N
+1 f
+1113(,)X
+3 f
+1153(shell)X
+1 f
+1308(,)X
+1348(and)X
+3 f
+1484(xit)X
+1 f
+1593(are)X
+2 f
+1712(not)X
+1 f
+1834(affected)X
+2114(by)X
+2214(the)X
+3 f
+2332(autowrite)X
+1 f
+2682(option.)X
+3 f
+776 2022(beautify,)N
+1096(bf)X
+1187([off])X
+1 f
+976 2112(If)N
+1061(this)X
+1207(option)X
+1442(is)X
+1527(set,)X
+1668(all)X
+1780(control)X
+2039(characters)X
+2398(that)X
+2550(are)X
+2681(not)X
+2815(currently)X
+3137(being)X
+3347(specially)X
+3664(interpreted,)X
+976 2202(other)N
+1166(than)X
+7 f
+1329(<tab>)X
+1 f
+(,)S
+7 f
+1613(<newline>)X
+1 f
+(,)S
+2089(and)X
+7 f
+2229(<form-feed>)X
+1 f
+(,)S
+2801(are)X
+2924(discarded)X
+3256(from)X
+3436(commands)X
+3807(read)X
+3970(in)X
+976 2292(by)N
+3 f
+1078(ex)X
+1 f
+1176(from)X
+1354(command)X
+1692(\256les,)X
+1867(and)X
+2005(from)X
+2183(input)X
+2369(text)X
+2511(entered)X
+2770(to)X
+3 f
+2854(vi)X
+1 f
+2938(\(either)X
+3170(into)X
+3316(the)X
+3436(\256le)X
+3560(or)X
+3649(to)X
+3733(the)X
+3854(colon)X
+976 2382(command)N
+1312(line\).)X
+1519(Text)X
+1686(\256les)X
+1839(read)X
+1998(by)X
+3 f
+2098(ex)X
+1 f
+2174(/)X
+3 f
+2196(vi)X
+1 f
+2278(are)X
+2 f
+2397(not)X
+1 f
+2519(affected)X
+2799(by)X
+2899(the)X
+3 f
+3017(beautify)X
+1 f
+3317(option.)X
+3 f
+776 2562(cdpath)N
+1031([environment)X
+1514(variable)X
+1814(CDPATH,)X
+2192(or)X
+2288(current)X
+2567(directory])X
+1 f
+976 2652(This)N
+1152(option)X
+1390(is)X
+1477(used)X
+1658(to)X
+1754(specify)X
+2020(a)X
+2090(colon)X
+2302(separated)X
+2640(list)X
+2771(of)X
+2872(directories)X
+3245(which)X
+3476(are)X
+3610(used)X
+3792(as)X
+3894(path)X
+976 2742(pre\256xes)N
+1252(for)X
+1368(any)X
+1506(relative)X
+1769(path)X
+1929(names)X
+2156(used)X
+2325(as)X
+2414(arguments)X
+2770(for)X
+2886(the)X
+3 f
+3006(cd)X
+1 f
+3108(command.)X
+3486(The)X
+3633(value)X
+3829(of)X
+3917(this)X
+976 2832(option)N
+1202(defaults)X
+1478(to)X
+1562(the)X
+1682(value)X
+1878(of)X
+1967(the)X
+2088(environmental)X
+2574(variable)X
+7 f
+2856(CDPATH)X
+1 f
+3167(if)X
+3239(it)X
+3306(is)X
+3382(set,)X
+3514(otherwise)X
+3849(to)X
+3934(the)X
+976 2922(current)N
+1232(directory.)X
+1590(For)X
+1729(compatibility)X
+2183(with)X
+2353(the)X
+2478(POSIX)X
+2736(1003.2)X
+2983(shell,)X
+3181(the)X
+3 f
+3306(cd)X
+1 f
+3413(command)X
+3756(does)X
+2 f
+3930(not)X
+1 f
+976 3012(check)N
+1200(the)X
+1334(current)X
+1598(directory)X
+1924(as)X
+2027(a)X
+2099(path)X
+2273(pre\256x)X
+2496(for)X
+2627(relative)X
+2905(path)X
+3080(names)X
+3322(unless)X
+3559(it)X
+3640(is)X
+3730(explicitly)X
+976 3102(speci\256ed.)N
+1334(It)X
+1416(may)X
+1586(be)X
+1694(so)X
+1797(speci\256ed)X
+2114(by)X
+2226(entering)X
+2521(an)X
+2629(empty)X
+2861(string)X
+3075(or)X
+3174(a)X
+3242(``)X
+7 f
+3296(.)X
+1 f
+('')S
+3450(character)X
+3778(into)X
+3934(the)X
+7 f
+976 3192(CDPATH)N
+1 f
+1284(variable)X
+1563(or)X
+1650(the)X
+1768(option)X
+1992(value.)X
+3 f
+776 3372(columns,)N
+1100(co)X
+1196([80])X
+1 f
+976 3462(The)N
+1132(number)X
+1408(of)X
+1506(columns)X
+1808(in)X
+1901(the)X
+2030(screen.)X
+2307(Setting)X
+2565(this)X
+2712(option)X
+2948(causes)X
+3 f
+3190(ex)X
+1 f
+3266(/)X
+3 f
+3288(vi)X
+1 f
+3382(to)X
+3476(set)X
+3597(\(or)X
+3723(reset\))X
+3934(the)X
+976 3552(environmental)N
+1464(variable)X
+7 f
+1748(COLUMNS)X
+1 f
+(.)S
+2149(See)X
+2290(the)X
+2413(section)X
+2665(entitled)X
+2930(``)X
+3 f
+2984(Sizing)X
+3217(the)X
+3349(Screen)X
+1 f
+3581('')X
+3660(more)X
+3849(infor-)X
+976 3642(mation.)N
+3 f
+776 3822(comment)N
+1113([off])X
+976 3912(Vi)N
+1 f
+1079(only.)X
+1284(If)X
+1361(the)X
+1482(\256rst)X
+1629(non-empty)X
+1999(line)X
+2142(of)X
+2232(the)X
+2354(\256le)X
+2480(begins)X
+2713(with)X
+2879(the)X
+3001(string)X
+3207(``)X
+7 f
+3261(/*)X
+1 f
+('',)S
+3455(this)X
+3594(option)X
+3822(causes)X
+3 f
+976 4002(vi)N
+1 f
+1072(to)X
+1167(skip)X
+1333(to)X
+1428(the)X
+1559(end)X
+1708(of)X
+1808(that)X
+1961(C-language)X
+2364(comment)X
+2695(\(probably)X
+3040(a)X
+3109(terribly)X
+3378(boring)X
+3620(legal)X
+3809(notice\))X
+976 4092(before)N
+1202(displaying)X
+1555(the)X
+1673(\256le.)X
+3 f
+776 4272(directory,)N
+1133(dir)X
+1255([environment)X
+1738(variable)X
+2038(TMPDIR,)X
+2403(or)X
+2499(/tmp])X
+1 f
+976 4362(The)N
+1123(directory)X
+1435(where)X
+1655(temporary)X
+2008(\256les)X
+2164(are)X
+2286(created.)X
+2582(The)X
+2730(environmental)X
+3216(variable)X
+7 f
+3498(TMPDIR)X
+1 f
+3809(is)X
+3885(used)X
+976 4452(as)N
+1063(the)X
+1181(default)X
+1424(value)X
+1618(if)X
+1687(it)X
+1751(exists,)X
+1973(otherwise)X
+7 f
+2305(/tmp)X
+1 f
+2517(is)X
+2590(used.)X
+3 f
+776 4632(edcompatible,)N
+1274(ed)X
+1374([off])X
+1 f
+976 4722(Remember)N
+1349(the)X
+1468(values)X
+1694(of)X
+1782(the)X
+1901(``c'')X
+2066(and)X
+2203(``g'')X
+2372(suf\256ces)X
+2638(to)X
+2721(the)X
+3 f
+2840(substitute)X
+1 f
+3194(commands,)X
+3583(instead)X
+3832(of)X
+3921(ini-)X
+976 4812(tializing)N
+1262(them)X
+1446(as)X
+1537(unset)X
+1730(for)X
+1848(each)X
+2020(new)X
+2178(command.)X
+2558(Specifying)X
+2929(pattern)X
+3176(and)X
+3316(replacement)X
+3733(strings)X
+3970(to)X
+976 4902(the)N
+3 f
+1094(substitute)X
+1 f
+1447(command)X
+1783(unsets)X
+2003(the)X
+2121(``c'')X
+2285(and)X
+2421(``g'')X
+2589(suf\256ces)X
+2854(as)X
+2941(well.)X
+3 f
+776 5082(errorbells,)N
+1155(eb)X
+1255([off])X
+976 5172(Ex)N
+1 f
+1089(only.)X
+3 f
+1292(Ex)X
+1 f
+1406(error)X
+1584(messages)X
+1908(are)X
+2028(normally)X
+2338(presented)X
+2667(in)X
+2750(inverse)X
+3003(video.)X
+3242(If)X
+3317(that)X
+3458(is)X
+3532(not)X
+3655(possible)X
+3938(for)X
+976 5262(the)N
+1096(terminal,)X
+1405(setting)X
+1640(this)X
+1777(option)X
+2003(causes)X
+2235(error)X
+2414(messages)X
+2739(to)X
+2823(be)X
+2921(announced)X
+3291(by)X
+3393(ringing)X
+3646(the)X
+3765(terminal)X
+976 5352(bell.)N
+3 f
+776 5532(exrc,)N
+964(ex)X
+1060([off])X
+1 f
+976 5622(If)N
+1061(this)X
+1207(option)X
+1442(is)X
+1526(turned)X
+1762(off)X
+1887(in)X
+1980(the)X
+2109(system)X
+2362(or)X
+2460($HOME)X
+2767(startup)X
+3016(\256les,)X
+3200(the)X
+3330(local)X
+3518(startup)X
+3768(\256les)X
+3933(are)X
+976 5712(never)N
+1177(read)X
+1338(\(unless)X
+1587(they)X
+1747(are)X
+1868(the)X
+1988(same)X
+2175(as)X
+2264(the)X
+2384(system)X
+2628(or)X
+2717($HOME)X
+3015(startup)X
+3255(\256les\).)X
+3477(Turning)X
+3757(it)X
+3823(on)X
+3925(has)X
+976 5802(no)N
+1091(effect,)X
+1330(i.e.)X
+1463(the)X
+1596(normal)X
+1858(checks)X
+2112(for)X
+2241(local)X
+2432(startup)X
+2685(\256les)X
+2854(are)X
+2989(performed,)X
+3380(regardless.)X
+3782(See)X
+3934(the)X
+
+48 p
+%%Page: 48 47
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-48)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+1 f
+976 762(section)N
+1223(entitled)X
+1483(``)X
+3 f
+1537(Startup)X
+1819(Information)X
+1 f
+2237('')X
+2311(for)X
+2425(more)X
+2610(information.)X
+3 f
+776 942(extended)N
+1103([off])X
+1 f
+976 1032(This)N
+1147(option)X
+1380(causes)X
+1619(all)X
+1728(regular)X
+1986(expressions)X
+2390(to)X
+2482(be)X
+2588(treated)X
+2837(as)X
+2934(POSIX)X
+3195(1003.2)X
+3445(Extended)X
+3778(Regular)X
+976 1122(Expressions)N
+1383(\(which)X
+1626(are)X
+1745(similar)X
+1987(to)X
+2069(historic)X
+2 f
+2329(egrep)X
+1 f
+2512(\(1\))X
+2626(style)X
+2797(expressions\).)X
+3 f
+776 1302(\257ash)N
+955([on])X
+1 f
+976 1392(This)N
+1139(option)X
+1364(causes)X
+1595(the)X
+1714(screen)X
+1941(to)X
+2025(\257ash)X
+2198(instead)X
+2447(of)X
+2536(beeping)X
+2812(the)X
+2932(keyboard,)X
+3273(on)X
+3375(error,)X
+3574(if)X
+3645(the)X
+3765(terminal)X
+976 1482(has)N
+1103(the)X
+1221(capability.)X
+3 f
+776 1662(hardtabs,)N
+1122(ht)X
+1213([8])X
+1 f
+976 1752(This)N
+1141(option)X
+1369(de\256nes)X
+1620(the)X
+1742(spacing)X
+2011(between)X
+2303(hardware)X
+2627(tab)X
+2749(settings,)X
+3037(i.e.)X
+3179(the)X
+3301(tab)X
+3423(expansion)X
+3772(done)X
+3952(by)X
+976 1842(the)N
+1099(operating)X
+1427(system)X
+1674(and/or)X
+1904(the)X
+2027(terminal)X
+2319(itself.)X
+2544(As)X
+3 f
+2658(nex)X
+1 f
+(/)S
+3 f
+2800(nvi)X
+1 f
+2931(never)X
+3135(writes)X
+7 f
+3355(<tab>)X
+1 f
+3619(characters)X
+3970(to)X
+976 1932(the)N
+1094(terminal,)X
+1401(unlike)X
+1621(historic)X
+1881(versions)X
+2168(of)X
+3 f
+2255(ex)X
+1 f
+2331(/)X
+3 f
+2353(vi)X
+1 f
+2415(,)X
+2455(this)X
+2590(option)X
+2814(does)X
+2981(not)X
+3103(currently)X
+3413(have)X
+3585(any)X
+3721(affect.)X
+3 f
+776 2112(ignorecase,)N
+1177(ic)X
+1255([off])X
+1 f
+976 2202(This)N
+1141(option)X
+1368(causes)X
+1602(regular)X
+1854(expressions,)X
+2272(both)X
+2438(in)X
+3 f
+2524(ex)X
+1 f
+2624(commands)X
+2995(and)X
+3135(in)X
+3221(searches,)X
+3538(to)X
+3624(be)X
+3724(evaluated)X
+976 2292(in)N
+1058(a)X
+1114(case-insensitive)X
+1642(manner.)X
+3 f
+776 2472(keytime)N
+1068([6])X
+1 f
+976 2562(The)N
+1121(10th's)X
+1341(of)X
+1428(a)X
+1484(second)X
+3 f
+1727(ex)X
+1 f
+1803(/)X
+3 f
+1825(vi)X
+1 f
+1907(waits)X
+2096(for)X
+2210(a)X
+2266(subsequent)X
+2642(key)X
+2778(to)X
+2860(complete)X
+3174(a)X
+3230(key)X
+3366(mapping.)X
+3 f
+776 2742(leftright)N
+1077([off])X
+976 2832(Vi)N
+1 f
+1083(only.)X
+1293(This)X
+1463(option)X
+1695(causes)X
+1933(the)X
+2059(screen)X
+2293(to)X
+2383(be)X
+2487(scrolled)X
+2769(left-right)X
+3082(to)X
+3172(view)X
+3356(lines)X
+3535(longer)X
+3768(than)X
+3934(the)X
+976 2922(screen,)N
+1232(instead)X
+1489(of)X
+1586(the)X
+1714(traditional)X
+3 f
+2073(vi)X
+1 f
+2165(screen)X
+2401(interface)X
+2713(which)X
+2939(folds)X
+3129(long)X
+3301(lines)X
+3482(at)X
+3570(the)X
+3698(right-hand)X
+976 3012(margin)N
+1223(of)X
+1310(the)X
+1428(terminal.)X
+3 f
+776 3192(lines,)N
+971(li)X
+1035([24])X
+976 3282(Vi)N
+1 f
+1076(only.)X
+1278(The)X
+1423(number)X
+1688(of)X
+1775(lines)X
+1946(in)X
+2028(the)X
+2146(screen.)X
+2412(Setting)X
+2658(this)X
+2793(option)X
+3017(causes)X
+3 f
+3247(ex)X
+1 f
+3323(/)X
+3 f
+3345(vi)X
+1 f
+3427(to)X
+3509(set)X
+3619(\(or)X
+3734(reset\))X
+3934(the)X
+976 3372(environmental)N
+1462(variable)X
+7 f
+1744(LINES)X
+1 f
+(.)S
+2047(See)X
+2186(the)X
+2307(section)X
+2557(entitled)X
+2820(``)X
+3 f
+2874(Sizing)X
+3105(the)X
+3235(Screen)X
+1 f
+3467('')X
+3544(for)X
+3661(more)X
+3849(infor-)X
+976 3462(mation.)N
+3 f
+776 3642(lisp)N
+915([off])X
+976 3732(Vi)N
+1 f
+1078(only.)X
+1282(This)X
+1447(option)X
+1674(changes)X
+1956(the)X
+2077(behavior)X
+2381(of)X
+2471(the)X
+3 f
+2592(vi)X
+2677(\()X
+1 f
+2704(,)X
+3 f
+2747(\))X
+1 f
+2774(,)X
+3 f
+2817({)X
+1 f
+2849(,)X
+3 f
+2892(})X
+1 f
+2924(,)X
+3 f
+2967([[)X
+1 f
+3044(and)X
+3 f
+3183(]])X
+1 f
+3260(commands)X
+3630(to)X
+3715(match)X
+3934(the)X
+976 3822(Lisp)N
+1138(language.)X
+1488(Also,)X
+1679(the)X
+3 f
+1797(autoindent)X
+1 f
+2185(option's)X
+2467(behavior)X
+2768(is)X
+2841(changed)X
+3129(to)X
+3211(be)X
+3307(appropriate)X
+3693(for)X
+3807(Lisp.)X
+2 f
+976 4002(This)N
+1133(option)X
+1357(is)X
+1430(not)X
+1552(yet)X
+1666(implemented.)X
+3 f
+776 4182(list)N
+898([off])X
+1 f
+976 4272(This)N
+1151(option)X
+1388(causes)X
+1631(lines)X
+1815(to)X
+1910(be)X
+2019(displayed)X
+2359(in)X
+2454(an)X
+2563(unambiguous)X
+3028(fashion.)X
+3338(Speci\256cally,)X
+3770(tabs)X
+3933(are)X
+976 4362(displayed)N
+1305(as)X
+1394(control)X
+1643(characters,)X
+2012(i.e.)X
+2152(``)X
+7 f
+2206(\303I)X
+1 f
+('',)S
+2398(and)X
+2536(the)X
+2656(ends)X
+2825(of)X
+2914(lines)X
+3087(are)X
+3207(marked)X
+3469(with)X
+3632(a)X
+3689(``)X
+7 f
+3743($)X
+1 f
+('')S
+3866(char-)X
+976 4452(acter.)N
+3 f
+776 4632(magic)N
+1001([on])X
+1 f
+976 4722(This)N
+1141(option)X
+1368(is)X
+1444(on)X
+1547(by)X
+1650(default.)X
+1936(Turning)X
+2217(the)X
+3 f
+2338(magic)X
+1 f
+2566(option)X
+2793(off)X
+2910(causes)X
+3143(all)X
+3247(regular)X
+3499(expression)X
+3866(char-)X
+976 4812(acters)N
+1189(except)X
+1423(for)X
+1541(``)X
+7 f
+1595(\303)X
+1 f
+('')S
+1721(and)X
+1861(``)X
+7 f
+1915($)X
+1 f
+('',)S
+2061(to)X
+2147(be)X
+2247(treated)X
+2490(as)X
+2581(ordinary)X
+2877(characters.)X
+3268(To)X
+3381(re-enable)X
+3705(characters)X
+976 4902(individually,)N
+1402(when)X
+1597(the)X
+3 f
+1716(magic)X
+1 f
+1942(option)X
+2167(is)X
+2241(off,)X
+2376(precede)X
+2648(them)X
+2829(with)X
+2992(a)X
+3049(backslash)X
+3382(``)X
+7 f
+3436(\\)X
+1 f
+('')S
+3559(character.)X
+3916(See)X
+976 4992(the)N
+1094(section)X
+1341(entitled)X
+1601(``)X
+3 f
+1655(Regular)X
+1951(Expressions)X
+2379(and)X
+2527(Replacement)X
+2993(Strings)X
+1 f
+3237('')X
+3311(for)X
+3425(more)X
+3610(information.)X
+3 f
+776 5172(matchtime)N
+1162([7])X
+976 5262(Vi)N
+1 f
+1078(only.)X
+1282(The)X
+1429(10th's)X
+1651(of)X
+1740(a)X
+1798(second)X
+3 f
+2043(ex)X
+1 f
+2119(/)X
+3 f
+2141(vi)X
+1 f
+2226(pauses)X
+2463(on)X
+2566(the)X
+2687(matching)X
+3008(character)X
+3327(when)X
+3524(the)X
+3 f
+3645(showmatch)X
+1 f
+976 5352(option)N
+1200(is)X
+1273(set.)X
+3 f
+776 5532(mesg)N
+970([on])X
+1 f
+976 5622(This)N
+1140(option)X
+1366(allows)X
+1597(other)X
+1784(users)X
+1972(to)X
+2057(contact)X
+2312(you)X
+2455(using)X
+2651(the)X
+2 f
+2772(talk)X
+1 f
+(\(1\))S
+3009(and)X
+2 f
+3148(write)X
+1 f
+3312(\(1\))X
+3429(utilities,)X
+3711(while)X
+3912(you)X
+976 5712(are)N
+1101(editing.)X
+3 f
+1389(Ex)X
+1 f
+1482(/)X
+3 f
+1504(vi)X
+1 f
+1592(does)X
+1764(not)X
+1891(turn)X
+2045(message)X
+2342(on,)X
+2467(i.e.)X
+2590(if)X
+2664(messages)X
+2992(were)X
+3174(turned)X
+3404(off)X
+3523(when)X
+3722(the)X
+3845(editor)X
+976 5802(was)N
+1124(invoked,)X
+1425(they)X
+1586(will)X
+1733(stay)X
+1885(turned)X
+2113(off.)X
+2270(This)X
+2435(option)X
+2662(only)X
+2827(permits)X
+3090(you)X
+3233(to)X
+3318(disallow)X
+3612(messages)X
+3938(for)X
+
+49 p
+%%Page: 49 48
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3658(USD:13-49)X
+1 f
+976 762(the)N
+1094(edit)X
+1234(session.)X
+1525(See)X
+1661(the)X
+2 f
+1779(mesg)X
+1 f
+1944(\(1\))X
+2058(utility)X
+2268(for)X
+2382(more)X
+2567(information.)X
+3 f
+776 942(modelines,)N
+1158(modeline)X
+1489([off])X
+1 f
+976 1032(If)N
+1052(the)X
+3 f
+1172(modelines)X
+1 f
+1536(option)X
+1762(is)X
+1837(set,)X
+3 f
+1968(ex)X
+1 f
+2044(/)X
+3 f
+2066(vi)X
+1 f
+2150(has)X
+2279(historically)X
+2661(scanned)X
+2942(the)X
+3062(\256rst)X
+3208(and)X
+3346(last)X
+3479(\256ve)X
+3621(lines)X
+3794(of)X
+3884(each)X
+976 1122(\256le)N
+1101(as)X
+1191(it)X
+1258(is)X
+1334(read)X
+1496(for)X
+1613(editing,)X
+1877(looking)X
+2143(for)X
+2259(any)X
+3 f
+2397(ex)X
+1 f
+2495(commands)X
+2864(that)X
+3006(have)X
+3180(been)X
+3354(placed)X
+3586(in)X
+3670(those)X
+3861(lines.)X
+976 1212(After)N
+1167(the)X
+1286(startup)X
+1525(information)X
+1924(has)X
+2052(been)X
+2225(processed,)X
+2583(and)X
+2720(before)X
+2947(the)X
+3066(user)X
+3221(starts)X
+3411(editing)X
+3654(the)X
+3773(\256le,)X
+3916(any)X
+976 1302(commands)N
+1343(embedded)X
+1693(in)X
+1775(the)X
+1893(\256le)X
+2015(are)X
+2134(executed.)X
+976 1482(Commands)N
+1362(were)X
+1541(recognized)X
+1916(by)X
+2018(the)X
+2138(letters)X
+2356(``e'')X
+2522(or)X
+2611(``v'')X
+2781(followed)X
+3088(by)X
+3191(``x'')X
+3362(or)X
+3452(``i'',)X
+3625(at)X
+3706(the)X
+3827(begin-)X
+976 1572(ning)N
+1144(of)X
+1237(a)X
+1299(line)X
+1445(or)X
+1538(following)X
+1875(a)X
+1937(tab)X
+2061(or)X
+2154(space)X
+2359(character,)X
+2701(and)X
+2843(followed)X
+3153(by)X
+3258(a)X
+3319(``:'',)X
+3494(an)X
+3 f
+3595(ex)X
+1 f
+3696(command,)X
+976 1662(and)N
+1112(another)X
+1373(``:''.)X
+976 1842(This)N
+1144(option)X
+1374(is)X
+1453(a)X
+1516(security)X
+1797(problem)X
+2091(of)X
+2185(immense)X
+2501(proportions,)X
+2917(and)X
+3060(should)X
+3300(not)X
+3429(be)X
+3532(used)X
+3706(under)X
+3916(any)X
+976 1932(circumstances.)N
+2 f
+976 2112(This)N
+1133(option)X
+1357(will)X
+1496(never)X
+1695(be)X
+1791(implemented.)X
+3 f
+776 2292(number,)N
+1087(nu)X
+1195([off])X
+1 f
+976 2382(Precede)N
+1251(each)X
+1419(line)X
+1559(displayed)X
+1886(with)X
+2048(its)X
+2143(current)X
+2391(line)X
+2531(number.)X
+3 f
+776 2562(octal)N
+961([off])X
+1 f
+976 2652(Display)N
+1245(unknown)X
+1563(characters)X
+1910(as)X
+1997(octal)X
+2173(numbers,)X
+2489(instead)X
+2736(of)X
+2823(the)X
+2941(default)X
+3184(hexadecimal.)X
+3 f
+776 2832(open)N
+960([on])X
+976 2922(Ex)N
+1 f
+1089(only.)X
+1291(If)X
+1365(this)X
+1500(option)X
+1724(is)X
+1797(not)X
+1919(set,)X
+2048(the)X
+3 f
+2166(open)X
+1 f
+2350(and)X
+3 f
+2486(visual)X
+1 f
+2705(commands)X
+3072(are)X
+3191(disallowed.)X
+3 f
+776 3102(optimize,)N
+1110(opt)X
+1241([on])X
+976 3192(Vi)N
+1 f
+1081(only.)X
+1288(Throughput)X
+1691(of)X
+1783(text)X
+1929(is)X
+2008(expedited)X
+2346(by)X
+2452(setting)X
+2691(the)X
+2815(terminal)X
+3108(not)X
+3236(to)X
+3324(do)X
+3430(automatic)X
+3772(carriage)X
+976 3282(returns)N
+1222(when)X
+1419(printing)X
+1695(more)X
+1883(than)X
+2044(one)X
+2183(\(logical\))X
+2478(line)X
+2621(of)X
+2710(output,)X
+2956(greatly)X
+3201(speeding)X
+3508(output)X
+3734(on)X
+3836(termi-)X
+976 3372(nals)N
+1125(without)X
+1389(addressable)X
+1784(cursors)X
+2036(when)X
+2230(text)X
+2370(with)X
+2532(leading)X
+2788(white)X
+2986(space)X
+3185(is)X
+3258(printed.)X
+2 f
+976 3552(This)N
+1133(option)X
+1357(is)X
+1430(not)X
+1552(yet)X
+1666(implemented.)X
+3 f
+776 3732(paragraphs,)N
+1211(para)X
+1391([IPLPPPQPP)X
+1878 -0.3625(LIpplpipbp])AX
+976 3822(Vi)N
+1 f
+1079(only.)X
+1284(De\256ne)X
+1521(additional)X
+1864(paragraph)X
+2209(boundaries)X
+2584(for)X
+2701(the)X
+3 f
+2822({)X
+1 f
+2877(and)X
+3 f
+3016(})X
+1 f
+3071(commands.)X
+3481(The)X
+3629(value)X
+3826(of)X
+3917(this)X
+976 3912(option)N
+1200(must)X
+1375(be)X
+1471(a)X
+1527(character)X
+1843(string)X
+2045(consisting)X
+2389(of)X
+2476(zero)X
+2635(or)X
+2722(more)X
+2907(character)X
+3223(pairs.)X
+976 4092(In)N
+1070(the)X
+1195(text)X
+1342(to)X
+1431(be)X
+1534(edited,)X
+1777(the)X
+1902(character)X
+2226(string)X
+7 f
+2436(<newline>.<char-pair>)X
+1 f
+(,)S
+3492(\(where)X
+7 f
+3744(<char-)X
+976 4182(pair>)N
+1 f
+1241(is)X
+1319(one)X
+1460(of)X
+1552(the)X
+1675(character)X
+1996(pairs)X
+2177(in)X
+2264(the)X
+2386(option's)X
+2672(value\))X
+2897(de\256nes)X
+3148(a)X
+3208(paragraph)X
+3554(boundary.)X
+3921(For)X
+976 4272(example,)N
+1291(if)X
+1363(the)X
+1484(option)X
+1711(were)X
+1891(set)X
+2003(to)X
+7 f
+2088(LaA<space>##)X
+1 f
+(,)S
+2708(then)X
+2870(all)X
+2974(of)X
+3065(the)X
+3187(following)X
+3522(additional)X
+3866(para-)X
+976 4362(graph)N
+1179(boundaries)X
+1551(would)X
+1771(be)X
+1867(recognized:)X
+1296 4575(<newline>.La)N
+1296 4665(<newline>.A<space>)N
+1296 4755(<newline>.##)N
+3 f
+776 4968(prompt)N
+1054([on])X
+976 5058(Ex)N
+1 f
+1090(only.)X
+1293(This)X
+1456(option)X
+1681(causes)X
+3 f
+1912(ex)X
+1 f
+2009(to)X
+2092(prompt)X
+2344(for)X
+2459(command)X
+2796(input)X
+2981(with)X
+3144(a)X
+3201(``)X
+7 f
+3255(:)X
+1 f
+('')S
+3378(character;)X
+3717(when)X
+3913(it)X
+3979(is)X
+976 5148(not)N
+1098(set,)X
+1227(no)X
+1327(prompt)X
+1578(is)X
+1651(displayed.)X
+3 f
+776 5328(readonly,)N
+1118(ro)X
+1214([off])X
+1 f
+976 5418(This)N
+1138(option)X
+1362(causes)X
+1592(a)X
+1648(force)X
+1834(\257ag)X
+1974(to)X
+2056(be)X
+2152(required)X
+2440(to)X
+2522(attempt)X
+2782(to)X
+2864(write)X
+3049(the)X
+3167(\256le)X
+3289(back)X
+3461(to)X
+3543(the)X
+3661(original)X
+3930(\256le)X
+976 5508(name.)N
+1215(Setting)X
+1466(this)X
+1605(option)X
+1833(is)X
+1910(equivalent)X
+2268(to)X
+2354(using)X
+2551(the)X
+3 f
+9 f
+2673(-)X
+2675(-)X
+3 f
+2719(R)X
+1 f
+2801(command)X
+3141(line)X
+3285(option,)X
+3533(or)X
+3624(editing)X
+3870(a)X
+3930(\256le)X
+976 5598(which)N
+1192(lacks)X
+1377(write)X
+1562(permission.)X
+
+50 p
+%%Page: 50 49
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-50)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+776 762(recdir)N
+1006([/var/tmp/vi.recover])X
+1 f
+976 852(The)N
+1121(directory)X
+1431(where)X
+1648(recovery)X
+1950(\256les)X
+2103(are)X
+2222(stored.)X
+976 1032(If)N
+1051(you)X
+1192(change)X
+1441(the)X
+1561(value)X
+1757(of)X
+3 f
+1846(recdir)X
+1 f
+2056(,)X
+2098(be)X
+2196(careful)X
+2442(to)X
+2526(choose)X
+2771(a)X
+2829(directory)X
+3141(whose)X
+3368(contents)X
+3657(are)X
+3778(not)X
+3902(reg-)X
+976 1122(ularly)N
+1197(deleted.)X
+1503(Bad)X
+1666(choices)X
+1941(include)X
+2211(directories)X
+2584(in)X
+2680(memory)X
+2981(based)X
+3198(\256lesystems,)X
+3607(or)X
+7 f
+3707(/tmp)X
+1 f
+(,)S
+3952(on)X
+976 1212(most)N
+1151(systems,)X
+1444(as)X
+1531(their)X
+1698(contents)X
+1985(are)X
+2104(removed)X
+2405(when)X
+2599(the)X
+2717(machine)X
+3009(is)X
+3082(rebooted.)X
+976 1392(Public)N
+1219(directories)X
+1597(like)X
+7 f
+1757(/usr/tmp)X
+1 f
+2181(and)X
+7 f
+2337(/var/tmp)X
+1 f
+2761(are)X
+2900(usually)X
+3171(safe,)X
+3361(although)X
+3681(some)X
+3890(sites)X
+976 1482(periodically)N
+1387(prune)X
+1598(old)X
+1728(\256les)X
+1889(from)X
+2073(them.)X
+2301(There)X
+2517(is)X
+2598(no)X
+2706(requirement)X
+3122(that)X
+3270(you)X
+3418(use)X
+3553(a)X
+3617(public)X
+3844(direc-)X
+976 1572(tory,)N
+1145(e.g.)X
+1281(a)X
+1337(sub-directory)X
+1785(of)X
+1872(your)X
+2039(home)X
+2237(directory)X
+2547(will)X
+2691(work)X
+2876(\256ne.)X
+976 1752(Finally,)N
+1248(if)X
+1323(you)X
+1469(change)X
+1723(the)X
+1847(value)X
+2047(of)X
+3 f
+2140(recdir)X
+1 f
+2350(,)X
+2396(you)X
+2542(must)X
+2723(modify)X
+2980(the)X
+3104(recovery)X
+3412(script)X
+3617(to)X
+3706(operate)X
+3970(in)X
+976 1842(your)N
+1143(chosen)X
+1386(recovery)X
+1688(area.)X
+976 2022(See)N
+1112(the)X
+1230(section)X
+1477(entitled)X
+1737(``)X
+3 f
+1791(Recovery)X
+1 f
+2113('')X
+2187(for)X
+2301(further)X
+2540(information.)X
+3 f
+776 2202(redraw,)N
+1066(re)X
+1158([off])X
+976 2292(Vi)N
+1 f
+1087(only.)X
+1301(The)X
+1458(editor)X
+1677(simulates)X
+2011(\(using)X
+2243(great)X
+2436(amounts)X
+2739(of)X
+2838(output\),)X
+3121(an)X
+3229(intelligent)X
+3585(terminal)X
+3884(on)X
+3996(a)X
+976 2382(dumb)N
+1200(terminal)X
+1509(\(e.g.)X
+1694(during)X
+1945(insertions)X
+2297(in)X
+3 f
+2400(vi)X
+1 f
+2503(the)X
+2642(characters)X
+3010(to)X
+3113(the)X
+3252(right)X
+3444(of)X
+3552(the)X
+3691(cursor)X
+3933(are)X
+976 2472(refreshed)N
+1296(as)X
+1383(each)X
+1551(input)X
+1735(character)X
+2051(is)X
+2124(typed\).)X
+2 f
+976 2652(This)N
+1133(option)X
+1357(is)X
+1430(not)X
+1552(yet)X
+1666(implemented.)X
+3 f
+776 2832(remap)N
+1019([on])X
+1 f
+976 2922(If)N
+1055(this)X
+1195(option)X
+1424(is)X
+1502(set,)X
+1636(it)X
+1705(is)X
+1783(possible)X
+2070(to)X
+2157(de\256ne)X
+2378(macros)X
+2635(in)X
+2722(terms)X
+2926(of)X
+3019(other)X
+3210(macros.)X
+3508(Otherwise,)X
+3884(each)X
+976 3012(key)N
+1121(is)X
+1203(only)X
+1374(remapped)X
+1720(up)X
+1829(to)X
+1920(one)X
+2064(time.)X
+2274(For)X
+2413(example,)X
+2733(if)X
+2810(``)X
+7 f
+2864(A)X
+1 f
+('')S
+2994(is)X
+3075(mapped)X
+3357(to)X
+3447(``)X
+7 f
+3501(B)X
+1 f
+('',)S
+3651(and)X
+3795(``)X
+7 f
+3849(B)X
+1 f
+('')S
+3979(is)X
+976 3102(mapped)N
+1251(to)X
+1334(``)X
+7 f
+1388(C)X
+1 f
+('',)S
+1531(The)X
+1677(keystroke)X
+2010(``)X
+7 f
+2064(A)X
+1 f
+('')S
+2187(will)X
+2332(be)X
+2429(mapped)X
+2704(to)X
+2787(``)X
+7 f
+2841(C)X
+1 f
+('')S
+2964(if)X
+3035(the)X
+3 f
+3155(remap)X
+1 f
+3400(option)X
+3626(is)X
+3701(set,)X
+3832(and)X
+3970(to)X
+976 3192(``)N
+7 f
+1030(B)X
+1 f
+('')S
+1152(if)X
+1221(it)X
+1285(is)X
+1358(not)X
+1480(set.)X
+3 f
+776 3372(report)N
+1015([5])X
+1 f
+976 3462(Set)N
+1103(the)X
+1226(threshold)X
+1549(of)X
+1642(the)X
+1766(number)X
+2037(of)X
+2130(lines)X
+2307(that)X
+2453(need)X
+2631(to)X
+2719(be)X
+2821(changed)X
+3115(or)X
+3208(yanked)X
+3466(before)X
+3698(a)X
+3760(message)X
+976 3552(will)N
+1127(be)X
+1230(displayed)X
+1564(to)X
+1653(the)X
+1778(user.)X
+1979(For)X
+2117(everything)X
+2487(but)X
+2616(the)X
+2741(yank)X
+2924(command,)X
+3287(the)X
+3412(value)X
+3613(is)X
+3693(the)X
+3818(largest)X
+976 3642(value)N
+1172(about)X
+1372(which)X
+1590(the)X
+1711(editor)X
+1921(is)X
+1997(silent,)X
+2213(i.e.)X
+2334(by)X
+2437(default,)X
+2703(6)X
+2766(lines)X
+2940(must)X
+3118(be)X
+3217(deleted)X
+3472(before)X
+3701(the)X
+3822(user)X
+3979(is)X
+976 3732(noti\256ed.)N
+1283(However,)X
+1621(if)X
+1693(the)X
+1814(number)X
+2082(of)X
+2172(lines)X
+2346(yanked)X
+2601(is)X
+2677(greater)X
+2924(than)X
+2 f
+3085(or)X
+3179(equal)X
+3380(to)X
+1 f
+3465(the)X
+3586(set)X
+3697(value,)X
+3913(it)X
+3979(is)X
+976 3822(reported)N
+1264(to)X
+1346(the)X
+1464(user.)X
+3 f
+776 4002(ruler)N
+970([off])X
+976 4092(Vi)N
+1 f
+1076(only.)X
+1278(Display)X
+1547(a)X
+1603(row/column)X
+2010(ruler)X
+2182(on)X
+2282(the)X
+2400(colon)X
+2598(command)X
+2934(line.)X
+3 f
+776 4272(scroll,)N
+1003(scr)X
+1126([window)X
+1439(/)X
+1481(2])X
+1 f
+976 4362(Set)N
+1098(the)X
+1216(number)X
+1481(of)X
+1568(lines)X
+1739(scrolled)X
+2013(by)X
+2113(the)X
+3 f
+2231(vi)X
+2313(<control-D>)X
+1 f
+2755(and)X
+3 f
+2891(<control-U>)X
+1 f
+3333(commands.)X
+976 4542(Historically,)N
+1395(the)X
+3 f
+1514(ex)X
+1611(z)X
+1 f
+1668(command,)X
+2025(when)X
+2221(speci\256ed)X
+2528(without)X
+2794(a)X
+2852(count,)X
+3072(used)X
+3241(two)X
+3383(times)X
+3578(the)X
+3698(size)X
+3845(of)X
+3934(the)X
+976 4632(scroll)N
+1174(value;)X
+1390(the)X
+1508(POSIX)X
+1759(1003.2)X
+1999(standard)X
+2291(speci\256ed)X
+2596(the)X
+2714(window)X
+2992(size,)X
+3157(which)X
+3373(is)X
+3446(a)X
+3502(better)X
+3705(choice.)X
+3 f
+776 4812(sections,)N
+1083(sect)X
+1233([NHSHH)X
+1568(HUnhsh])X
+976 4902(Vi)N
+1 f
+1076(only.)X
+1278(De\256ne)X
+1512(additional)X
+1852(section)X
+2099(boundaries)X
+2471(for)X
+2585(the)X
+3 f
+2703([[)X
+1 f
+2777(and)X
+3 f
+2913(]])X
+1 f
+2987(commands.)X
+3394(The)X
+3 f
+3540(sections)X
+1 f
+3828(option)X
+976 4992(should)N
+1213(be)X
+1313(set)X
+1426(to)X
+1512(a)X
+1572(character)X
+1892(string)X
+2098(consisting)X
+2446(of)X
+2537(zero)X
+2700(or)X
+2791(more)X
+2979(character)X
+3298(pairs.)X
+3517(In)X
+3607(the)X
+3728(text)X
+3871(to)X
+3956(be)X
+976 5082(edited,)N
+1219(the)X
+1344(character)X
+1667(string)X
+7 f
+1876(<newline>.<char-pair>)X
+1 f
+(,)S
+2932(\(where)X
+7 f
+3184(<char-pair>)X
+1 f
+3740(is)X
+3821(one)X
+3965(of)X
+976 5172(the)N
+1100(character)X
+1422(pairs)X
+1604(in)X
+1692(the)X
+1816(option's)X
+2104(value\),)X
+2351(de\256nes)X
+2604(a)X
+2666(section)X
+2918(boundary)X
+3246(in)X
+3333(the)X
+3456(same)X
+3646(manner)X
+3912(that)X
+3 f
+976 5262(paragraph)N
+1 f
+1360(option)X
+1584(boundaries)X
+1956(are)X
+2075(de\256ned.)X
+3 f
+776 5442(shell,)N
+971(sh)X
+1066([environment)X
+1549(variable)X
+1849(SHELL,)X
+2154(or)X
+2250(/bin/sh])X
+1 f
+976 5532(Select)N
+1195(the)X
+1316(shell)X
+1490(used)X
+1660(by)X
+1763(the)X
+1884(editor.)X
+2134(The)X
+2282(speci\256ed)X
+2590(path)X
+2751(is)X
+2827(the)X
+2948(pathname)X
+3283(of)X
+3373(the)X
+3495(shell)X
+3670(invoked)X
+3952(by)X
+976 5622(the)N
+3 f
+1103(vi)X
+1194(!)X
+1 f
+1270(shell)X
+1450(escape)X
+1694(command)X
+2038(and)X
+2182(by)X
+2290(the)X
+3 f
+2416(ex)X
+2520(shell)X
+1 f
+2703(command.)X
+3087(This)X
+3257(program)X
+3557(is)X
+3638(also)X
+3795(used)X
+3970(to)X
+976 5712(resolve)N
+1228(any)X
+1364(shell)X
+1535 0.2679(meta-characters)AX
+2065(in)X
+3 f
+2147(ex)X
+1 f
+2243(commands.)X
+
+51 p
+%%Page: 51 50
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3658(USD:13-51)X
+776 762(shiftwidth,)N
+1162(sw)X
+1271([8])X
+1 f
+976 852(Set)N
+1098(the)X
+1216(autoindent)X
+1575(and)X
+1712(shift)X
+1875(command)X
+2212(indentation)X
+2593(width.)X
+2836(This)X
+2999(width)X
+3202(is)X
+3276(used)X
+3444(by)X
+3545(the)X
+3 f
+3664(autoindent)X
+1 f
+976 942(option)N
+1200(and)X
+1336(by)X
+1436(the)X
+3 f
+1554(<)X
+1 f
+1600(,)X
+3 f
+1640(>)X
+1 f
+1686(,)X
+1726(and)X
+3 f
+1862(shift)X
+1 f
+2033(commands.)X
+3 f
+776 1122(showdirty)N
+1138([off])X
+976 1212(Vi)N
+1 f
+1076(only.)X
+1278(Display)X
+1547(an)X
+1643(asterisk)X
+1908(on)X
+2008(the)X
+2126(colon)X
+2324(command)X
+2660(line)X
+2800(if)X
+2869(the)X
+2987(\256le)X
+3109(has)X
+3236(been)X
+3408(modi\256ed.)X
+3 f
+776 1392(showmatch,)N
+1203(sm)X
+1321([off])X
+976 1482(Vi)N
+1 f
+1078(only.)X
+1282(This)X
+1446(option)X
+1673(causes)X
+3 f
+1906(vi)X
+1 f
+1968(,)X
+2011(when)X
+2208(a)X
+2267(``)X
+7 f
+2321(})X
+1 f
+('')S
+2446(or)X
+2536(``)X
+7 f
+2590(\))X
+1 f
+('')S
+2715(is)X
+2791(entered,)X
+3071(to)X
+3156(brie\257y)X
+3388(move)X
+3589(the)X
+3710(cursor)X
+3934(the)X
+976 1572(matching)N
+1294(``)X
+7 f
+1348({)X
+1 f
+('')S
+1470(or)X
+1557(``)X
+7 f
+1611(\()X
+1 f
+(''.)S
+1773(See)X
+1909(the)X
+3 f
+2027(matchtime)X
+1 f
+2413(option)X
+2637(for)X
+2751(more)X
+2936(information.)X
+3 f
+776 1752(showmode)N
+1156([off])X
+976 1842(Vi)N
+1 f
+1083(only.)X
+1292(This)X
+1461(option)X
+1693(causes)X
+3 f
+1931(vi)X
+1 f
+2021(to)X
+2111(display)X
+2370(a)X
+2434(string)X
+2644(identifying)X
+3023(the)X
+3149(current)X
+3405(editor)X
+3620(mode)X
+3826(on)X
+3934(the)X
+976 1932(colon)N
+1174(command)X
+1510(line.)X
+3 f
+776 2112(sidescroll)N
+1116([16])X
+976 2202(Vi)N
+1 f
+1078(only.)X
+1282(Sets)X
+1437(the)X
+1557(number)X
+1825(of)X
+1915(columns)X
+2209(that)X
+2352(are)X
+2474(shifted)X
+2715(to)X
+2800(the)X
+2921(left)X
+3051(or)X
+3141(right,)X
+3335(when)X
+3 f
+3532(vi)X
+1 f
+3617(is)X
+3693(doing)X
+3898(left-)X
+976 2292(right)N
+1151(scrolling)X
+1455(and)X
+1595(the)X
+1717(left)X
+1848(or)X
+1939(right)X
+2114(margin)X
+2365(is)X
+2442(crossed.)X
+2747(See)X
+2887(the)X
+3 f
+3009(leftright)X
+1 f
+3314(option)X
+3542(for)X
+3660(more)X
+3849(infor-)X
+976 2382(mation.)N
+3 f
+776 2562(slowopen,)N
+1131(slow)X
+1302([off])X
+1 f
+976 2652(This)N
+1141(option)X
+1368(affects)X
+1606(the)X
+1727(display)X
+1981(algorithm)X
+2315(used)X
+2485(by)X
+3 f
+2588(vi)X
+1 f
+2650(,)X
+2693(holding)X
+2960(off)X
+3077(display)X
+3331(updating)X
+3635(during)X
+3868(input)X
+976 2742(of)N
+1063(new)X
+1217(text)X
+1357(to)X
+1439(improve)X
+1726(throughput)X
+2097(when)X
+2291(the)X
+2409(terminal)X
+2696(in)X
+2778(use)X
+2905(is)X
+2978(slow)X
+3149(and)X
+3285(unintelligent.)X
+2 f
+976 2922(This)N
+1133(option)X
+1357(is)X
+1430(not)X
+1552(yet)X
+1666(implemented.)X
+3 f
+776 3102(sourceany)N
+1143([off])X
+1 f
+976 3192(If)N
+1054(this)X
+1193(option)X
+1421(is)X
+1498(turned)X
+1727(on,)X
+3 f
+1851(vi)X
+1 f
+1937(historically)X
+2321(read)X
+2485(startup)X
+2728(\256les)X
+2886(that)X
+3031(were)X
+3213(owned)X
+3452(by)X
+3557(someone)X
+3867(other)X
+976 3282(than)N
+1142(the)X
+1268(editor)X
+1483(user.)X
+1685(See)X
+1829(the)X
+1955(section)X
+2210(entitled)X
+2478(``)X
+3 f
+2532(Startup)X
+2822(Information)X
+1 f
+3240('')X
+3321(for)X
+3442(more)X
+3634(information.)X
+976 3372(This)N
+1144(option)X
+1374(is)X
+1453(a)X
+1516(security)X
+1797(problem)X
+2091(of)X
+2185(immense)X
+2501(proportions,)X
+2917(and)X
+3060(should)X
+3300(not)X
+3429(be)X
+3532(used)X
+3706(under)X
+3916(any)X
+976 3462(circumstances.)N
+2 f
+976 3642(This)N
+1133(option)X
+1357(will)X
+1496(never)X
+1695(be)X
+1791(implemented.)X
+3 f
+776 3822(tabstop,)N
+1069(ts)X
+1147([8])X
+1 f
+976 3912(This)N
+1138(option)X
+1362(sets)X
+1502(tab)X
+1620(widths)X
+1853(for)X
+1967(the)X
+2085(editor)X
+2292(display.)X
+3 f
+776 4092(taglength,)N
+1136(tl)X
+1205([0])X
+1 f
+976 4182(This)N
+1148(option)X
+1383(sets)X
+1534(the)X
+1663(maximum)X
+2018(number)X
+2294(of)X
+2392(characters)X
+2750(that)X
+2901(are)X
+3031(considered)X
+3410(signi\256cant)X
+3774(in)X
+3867(a)X
+3934(tag)X
+976 4272(name.)N
+1210(Setting)X
+1456(the)X
+1574(value)X
+1768(to)X
+1850(0)X
+1910(makes)X
+2135(all)X
+2235(of)X
+2322(the)X
+2440(characters)X
+2787(in)X
+2869(the)X
+2987(tag)X
+3105(name)X
+3299(signi\256cant.)X
+3 f
+776 4452(tags,)N
+954(tag)X
+1081([tags)X
+1266(/var/db/libc.tags)X
+1838(/sys/kern/tags])X
+1 f
+976 4542(Sets)N
+1129(the)X
+1247(list)X
+1364(of)X
+1451(tags)X
+1600(\256les,)X
+1773(in)X
+1855(search)X
+2081(order,)X
+2291(which)X
+2507(are)X
+2626(used)X
+2793(when)X
+2987(the)X
+3105(editor)X
+3312(searches)X
+3605(for)X
+3719(a)X
+3775(tag.)X
+3 f
+776 4722(term,)N
+982(ttytype,)X
+1263(tty)X
+1377([environment)X
+1860(variable)X
+2160(TERM])X
+1 f
+976 4812(Set)N
+1101(the)X
+1223(terminal)X
+1514(type.)X
+1716(Setting)X
+1966(this)X
+2105(option)X
+2333(causes)X
+3 f
+2567(ex)X
+1 f
+2643(/)X
+3 f
+2665(vi)X
+1 f
+2751(to)X
+2837(set)X
+2950(\(or)X
+3068(reset\))X
+3271(the)X
+3393(environmental)X
+3880(vari-)X
+976 4902(able)N
+7 f
+1130(TERM)X
+1 f
+(.)S
+3 f
+776 5082(terse)N
+962([off])X
+1 f
+976 5172(This)N
+1142(option)X
+1370(has)X
+1501(historically)X
+1885(made)X
+2083(editor)X
+2294(messages)X
+2621(less)X
+2765(verbose.)X
+3079(It)X
+3152(has)X
+3283(no)X
+3387(effect)X
+3596(in)X
+3683(this)X
+3823(imple-)X
+976 5262(mentation.)N
+1356(See)X
+1492(the)X
+3 f
+1610(verbose)X
+1 f
+1893(option)X
+2117(for)X
+2231(more)X
+2416(information.)X
+3 f
+776 5442(tildeop)N
+1 f
+976 5532(Modify)N
+1236(the)X
+3 f
+1354(\304)X
+1 f
+1401(command)X
+1737(to)X
+1819(take)X
+1973(an)X
+2069(associated)X
+2419(motion.)X
+3 f
+776 5712(timeout,)N
+1079(to)X
+1166([on])X
+1 f
+976 5802(If)N
+1057(this)X
+1199(option)X
+1431(is)X
+1512(set,)X
+3 f
+1649(ex)X
+1 f
+1725(/)X
+3 f
+1747(vi)X
+1 f
+1837(waits)X
+2034(for)X
+2156(a)X
+2220(speci\256c)X
+2493(period)X
+2726(for)X
+2848(a)X
+2912(subsequent)X
+3296(key)X
+3440(to)X
+3530(complete)X
+3852(a)X
+3916(key)X
+
+52 p
+%%Page: 52 51
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-52)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+1 f
+976 762(mapping)N
+1282(\(see)X
+1438(the)X
+3 f
+1561(keytime)X
+1 f
+1858(option\).)X
+2154(If)X
+2233(the)X
+2356(option)X
+2585(is)X
+2663(not)X
+2790(set,)X
+2924(the)X
+3047(editor)X
+3259(waits)X
+3453(until)X
+3624(enough)X
+3885(keys)X
+976 852(are)N
+1095(entered)X
+1352(to)X
+1434(resolve)X
+1686(the)X
+1804(ambiguity,)X
+2168(regardless)X
+2514(of)X
+2601(how)X
+2759(long)X
+2921(it)X
+2985(takes.)X
+3 f
+776 1032(ttywerase)N
+1127([off])X
+976 1122(Vi)N
+1 f
+1082(only.)X
+1290(This)X
+1458(option)X
+1688(changes)X
+1973(how)X
+3 f
+2137(vi)X
+1 f
+2225(does)X
+2398(word)X
+2589(erase)X
+2781(during)X
+3016(text)X
+3162(input.)X
+3392(If)X
+3472(this)X
+3613(option)X
+3843(is)X
+3923(set,)X
+976 1212(text)N
+1123(is)X
+1203(broken)X
+1452(up)X
+1558(into)X
+1708(two)X
+1854(classes,)X
+2123(blank)X
+2327(characters)X
+2680(and)X
+2822(nonblank)X
+3146(characters.)X
+3539(Changing)X
+3876(from)X
+976 1302(one)N
+1112(class)X
+1288(to)X
+1370(another)X
+1631(marks)X
+1847(the)X
+1965(end)X
+2101(of)X
+2188(a)X
+2244(word.)X
+3 f
+776 1482(verbose)N
+1059([off])X
+976 1572(Vi)N
+1 f
+1078(only.)X
+3 f
+1282(Vi)X
+1 f
+1384(historically)X
+1766(bells)X
+1939(the)X
+2059(terminal)X
+2348(for)X
+2464(many)X
+2665(obvious)X
+2941(mistakes,)X
+3264(e.g.)X
+3403(trying)X
+3617(to)X
+3702(move)X
+3903(past)X
+976 1662(the)N
+1108(left-hand)X
+1432(margin,)X
+1713(or)X
+1814(past)X
+1977(the)X
+2109(end)X
+2259(of)X
+2360(the)X
+2492(\256le.)X
+2668(If)X
+2756(this)X
+2905(option)X
+3143(is)X
+3230(set,)X
+3373(an)X
+3483(error)X
+3674(message)X
+3979(is)X
+976 1752(displayed)N
+1303(for)X
+1417(all)X
+1517(errors.)X
+3 f
+776 1932(w300)N
+974([no)X
+1105(default])X
+976 2022(Vi)N
+1 f
+1080(only.)X
+1286(Set)X
+1412(the)X
+1534(window)X
+1816(size)X
+1965(if)X
+2038(the)X
+2160(baud)X
+2340(rate)X
+2485(is)X
+2562(less)X
+2706(than)X
+2868(1200)X
+3052(baud.)X
+3273(See)X
+3414(the)X
+3 f
+3537(window)X
+1 f
+3828(option)X
+976 2112(for)N
+1090(more)X
+1275(information.)X
+3 f
+776 2292(w1200)N
+1014([no)X
+1145(default])X
+976 2382(Vi)N
+1 f
+1081(only.)X
+1288(Set)X
+1415(the)X
+1538(window)X
+1821(size)X
+1971(if)X
+2045(the)X
+2168(baud)X
+2349(rate)X
+2495(is)X
+2574(equal)X
+2774(to)X
+2862(1200)X
+3048(baud.)X
+3270(See)X
+3412(the)X
+3 f
+3536(window)X
+1 f
+3828(option)X
+976 2472(for)N
+1090(more)X
+1275(information.)X
+3 f
+776 2652(w9600)N
+1014([no)X
+1145(default])X
+976 2742(Vi)N
+1 f
+1087(only.)X
+1300(Set)X
+1433(the)X
+1562(window)X
+1851(size)X
+2007(if)X
+2087(the)X
+2216(baud)X
+2404(rate)X
+2557(is)X
+2642(greater)X
+2898(than)X
+3068(1200)X
+3260(baud.)X
+3488(See)X
+3636(the)X
+3 f
+3766(window)X
+1 f
+976 2832(option)N
+1200(for)X
+1314(more)X
+1499(information.)X
+3 f
+776 3012(warn)N
+974([on])X
+976 3102(Ex)N
+1 f
+1094(only.)X
+1302(This)X
+1470(option)X
+1700(causes)X
+1936(a)X
+1998(warning)X
+2287(message)X
+2585(to)X
+2673(the)X
+2797(terminal)X
+3090(if)X
+3165(the)X
+3289(\256le)X
+3417(has)X
+3550(been)X
+3728(modi\256ed,)X
+976 3192(since)N
+1161(it)X
+1225(was)X
+1370(last)X
+1501(written,)X
+1768(before)X
+1994(a)X
+3 f
+2050(!)X
+1 f
+2117(command.)X
+3 f
+776 3372(window,)N
+1082(w,)X
+1180(wi)X
+1280([environment)X
+1763(variable)X
+2063(LINES])X
+1 f
+976 3462(This)N
+1148(option)X
+1382(determines)X
+1764(the)X
+1892(default)X
+2145(number)X
+2420(of)X
+2517(lines)X
+2698(in)X
+2791(a)X
+2858(screenful,)X
+3204(as)X
+3302(written)X
+3560(by)X
+3671(the)X
+3 f
+3800(z)X
+1 f
+3867(com-)X
+976 3552(mand.)N
+1221(It)X
+1297(also)X
+1453(determines)X
+1832(the)X
+1957(number)X
+2229(of)X
+2323(lines)X
+2501(scrolled)X
+2782(by)X
+2889(the)X
+3 f
+3014(vi)X
+1 f
+3103(commands)X
+3 f
+3477(<control-F>)X
+1 f
+3916(and)X
+3 f
+976 3642(<control-B>)N
+1 f
+1393(.)X
+1457(The)X
+1606(value)X
+1804(of)X
+1895(window)X
+2177(can)X
+2313(be)X
+2413(unrelated)X
+2736(to)X
+2822(the)X
+2944(real)X
+3089(screen)X
+3319(size,)X
+3489(although)X
+3794(it)X
+3863(starts)X
+976 3732(out)N
+1110(as)X
+1209(the)X
+1338(number)X
+1614(of)X
+1712(lines)X
+1894(on)X
+2005(the)X
+2134(screen)X
+2371(\(see)X
+2532(the)X
+2661(section)X
+2919(entitled)X
+3190(``)X
+3 f
+3244(Sizing)X
+3483(the)X
+3621(Screen)X
+1 f
+3853('')X
+3938(for)X
+976 3822(more)N
+1165(information\).)X
+1634(Setting)X
+1884(the)X
+2006(value)X
+2204(of)X
+2295(the)X
+3 f
+2417(window)X
+1 f
+2707(option)X
+2935(is)X
+3012(the)X
+3135(same)X
+3325(as)X
+3417(using)X
+3615(the)X
+3 f
+9 f
+3738(-)X
+3740(-)X
+3 f
+3784(w)X
+1 f
+3867(com-)X
+976 3912(mand)N
+1174(line)X
+1314(option.)X
+976 4092(If)N
+1055(the)X
+1178(value)X
+1377(of)X
+1469(the)X
+3 f
+1592(window)X
+1 f
+1883(option)X
+2112(\(as)X
+2231(set)X
+2345(by)X
+2450(the)X
+3 f
+2574(window)X
+1 f
+2840(,)X
+3 f
+2886(w300)X
+1 f
+3064(,)X
+3 f
+3110(w1200)X
+1 f
+3354(or)X
+3 f
+3447(w9600)X
+1 f
+3691(options\))X
+3979(is)X
+976 4182(smaller)N
+1233(than)X
+1391(the)X
+1509(actual)X
+1721(size)X
+1866(of)X
+1953(the)X
+2071(screen,)X
+2317(large)X
+2498(screen)X
+2724(movements)X
+3113(will)X
+3257(result)X
+3455(in)X
+3537(displaying)X
+3890(only)X
+976 4272(that)N
+1116(smaller)X
+1373(number)X
+1639(of)X
+1727(lines)X
+1899(on)X
+2000(the)X
+2119(screen.)X
+2386(\(Further)X
+2670(movements)X
+3060(in)X
+3143(that)X
+3284(same)X
+3470(area)X
+3626(will)X
+3771(result)X
+3970(in)X
+976 4362(the)N
+1097(screen)X
+1325(being)X
+1525(\256lled.\))X
+1778(This)X
+1942(can)X
+2076(provide)X
+2343(a)X
+2401(performance)X
+2830(improvement)X
+3279(when)X
+3475(viewing)X
+3755(different)X
+976 4452(places)N
+1197(in)X
+1279(one)X
+1415(or)X
+1502(more)X
+1687(\256les)X
+1840(over)X
+2003(a)X
+2059(slow)X
+2230(link.)X
+3 f
+776 4632(wrapmargin,)N
+1243(wm)X
+1388([0])X
+976 4722(Vi)N
+1 f
+1077(only.)X
+1280(If)X
+1356(the)X
+1476(value)X
+1672(of)X
+1761(the)X
+3 f
+1881(wrapmargin)X
+1 f
+2330(option)X
+2556(is)X
+2631(non-zero,)X
+3 f
+2959(vi)X
+1 f
+3043(will)X
+3189(split)X
+3348(lines)X
+3521(so)X
+3614(that)X
+3756(they)X
+3916(end)X
+976 4812(at)N
+1057(least)X
+1227(that)X
+1370(number)X
+1638(of)X
+1728(characters)X
+2078(before)X
+2307(the)X
+2428(right-hand)X
+2785(margin)X
+3035(of)X
+3125(the)X
+3245(screen.)X
+3513(\(Note,)X
+3738(the)X
+3858(value)X
+976 4902(of)N
+3 f
+1063(wrapmargin)X
+1 f
+1510(is)X
+2 f
+1583(not)X
+1 f
+1705(a)X
+1761(text)X
+1901(length.)X
+2161(In)X
+2248(a)X
+2304(screen)X
+2530(that)X
+2670(is)X
+2743(80)X
+2843(columns)X
+3134(wide,)X
+3330(the)X
+3449(command)X
+3786(``)X
+7 f
+3840(:set)X
+976 4992(wrapmargin=8)N
+1 f
+('')S
+1626(attempts)X
+1917(to)X
+1999(keep)X
+2171(the)X
+2289(lines)X
+2460(less)X
+2600(than)X
+2758(or)X
+2845(equal)X
+3039(to)X
+3121(72)X
+3221(columns)X
+3512(wide.\))X
+976 5172(Lines)N
+1181(are)X
+1307(split)X
+1471(at)X
+1556(the)X
+1681(previous)X
+1984(whitespace)X
+2368(character)X
+2691(closest)X
+2936(to)X
+3025(the)X
+3150(number.)X
+3462(Any)X
+3627(trailing)X
+3885(whi-)X
+976 5262(tespace)N
+1239(characters)X
+1592(before)X
+1824(that)X
+1970(character)X
+2292(are)X
+2417(deleted.)X
+2715(If)X
+2795(the)X
+2919(line)X
+3065(is)X
+3143(split)X
+3305(because)X
+3585(of)X
+3677(an)X
+3778(inserted)X
+7 f
+976 5352(<space>)N
+1 f
+1346(or)X
+7 f
+1447(<tab>)X
+1 f
+1721(character,)X
+2072(and)X
+2223(you)X
+2378(then)X
+2551(enter)X
+2747(another)X
+7 f
+3023(<space>)X
+1 f
+3394(character,)X
+3745(it)X
+3824(is)X
+3912(dis-)X
+976 5442(carded.)N
+976 5622(If)N
+1052(wrapmargin)X
+1462(is)X
+1537(set)X
+1648(to)X
+1732(0,)X
+1815(or)X
+1905(if)X
+1977(there)X
+2161(is)X
+2237(no)X
+2340(blank)X
+2541(character)X
+2860(upon)X
+3043(which)X
+3262(to)X
+3347(split)X
+3507(the)X
+3628(line,)X
+3791(the)X
+3912(line)X
+976 5712(is)N
+1049(not)X
+1171(broken.)X
+
+53 p
+%%Page: 53 52
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3658(USD:13-53)X
+776 762(wrapscan,)N
+1145(ws)X
+1254([on])X
+1 f
+976 852(This)N
+1138(option)X
+1362(causes)X
+1592(searches)X
+1885(to)X
+1967(wrap)X
+2148(around)X
+2391(the)X
+2509(end)X
+2645(or)X
+2732(the)X
+2850(beginning)X
+3191(of)X
+3279(the)X
+3398(\256le,)X
+3541(and)X
+3678(back)X
+3851(to)X
+3934(the)X
+976 942(starting)N
+1236(point.)X
+1460(Otherwise,)X
+1830(the)X
+1948(end)X
+2084(or)X
+2171(beginning)X
+2511(of)X
+2598(the)X
+2716(\256le)X
+2838(terminates)X
+3192(the)X
+3310(search.)X
+3 f
+776 1122(writeany,)N
+1119(wa)X
+1237([off])X
+1 f
+976 1212(If)N
+1056(this)X
+1197(option)X
+1427(is)X
+1506(set,)X
+1641(\256le-overwriting)X
+2170(checks)X
+2416(that)X
+2563(would)X
+2790(usually)X
+3048(be)X
+3151(made)X
+3352(before)X
+3585(the)X
+3 f
+3710(write)X
+1 f
+3916(and)X
+3 f
+976 1302(xit)N
+1 f
+1094(commands,)X
+1490(or)X
+1586(before)X
+1821(an)X
+1926(automatic)X
+2271(write)X
+2465(\(see)X
+2624(the)X
+3 f
+2751(autowrite)X
+1 f
+3110(option\),)X
+3390(are)X
+3518(not)X
+3648(made.)X
+3890(This)X
+976 1392(allows)N
+1205(a)X
+1261(write)X
+1446(to)X
+1528(any)X
+1664(\256le,)X
+1806(provided)X
+2111(the)X
+2229(\256le)X
+2351(permissions)X
+2753(allow)X
+2951(it.)X
+3 f
+776 1578(16.)N
+916(Additional)X
+1299(Features)X
+1618(in)X
+1704(Nex/Nvi)X
+1 f
+976 1701(There)N
+1190(are)X
+1315(a)X
+1377(few)X
+1524(features)X
+1805(in)X
+3 f
+1894(nex)X
+1 f
+(/)S
+3 f
+2036(nvi)X
+1 f
+2169(that)X
+2316(are)X
+2442(not)X
+2571(found)X
+2785(in)X
+2874(historic)X
+3141(versions)X
+3435(of)X
+3 f
+3529(ex)X
+1 f
+3605(/)X
+3 f
+3627(vi)X
+1 f
+3689(.)X
+3756(Some)X
+3965(of)X
+776 1791(the)N
+894(more)X
+1079(interesting)X
+1437(of)X
+1524(those)X
+1713(features)X
+1988(are)X
+2107(as)X
+2194(follows:)X
+3 f
+776 1971(8-bit)N
+956(clean)X
+1154(data,)X
+1345(large)X
+1539(lines,)X
+1734(\256les)X
+976 2061(Nex)N
+1 f
+1110(/)X
+3 f
+1132(nvi)X
+1 f
+1260(will)X
+1407(edit)X
+1550(any)X
+1689(format)X
+1926(\256le.)X
+2091(Line)X
+2261(lengths)X
+2515(are)X
+2637(limited)X
+2886(by)X
+2989(available)X
+3302(memory,)X
+3612(and)X
+3751(\256le)X
+3876(sizes)X
+976 2151(are)N
+1099(limited)X
+1349(by)X
+1453(available)X
+1767(disk)X
+1924(space.)X
+2167(The)X
+3 f
+2316(vi)X
+1 f
+2402(text)X
+2546(input)X
+2734(mode)X
+2935(command)X
+3 f
+3274(<control-X>)X
+1 f
+3719(can)X
+3854(insert)X
+976 2241(any)N
+1112(possible)X
+1394(character)X
+1710(value)X
+1904(into)X
+2048(the)X
+2166(text.)X
+3 f
+776 2421(Split)N
+955(screens)X
+1 f
+976 2511(The)N
+3 f
+1127(split)X
+1 f
+1299(command)X
+1641(divides)X
+1898(the)X
+2022(screen)X
+2254(into)X
+2404(multiple)X
+2696(editing)X
+2944(regions.)X
+3246(The)X
+3 f
+3397(<control-W>)X
+1 f
+3867(com-)X
+976 2601(mand)N
+1183(rotates)X
+1426(between)X
+1723(the)X
+1850(foreground)X
+2236(screens.)X
+2541(The)X
+3 f
+2694(resize)X
+1 f
+2919(command)X
+3263(can)X
+3403(be)X
+3507(used)X
+3682(to)X
+3772(grow)X
+3965(or)X
+976 2691(shrink)N
+1196(a)X
+1252(particular)X
+1580(screen.)X
+3 f
+776 2871(Background)N
+1217(and)X
+1365(foreground)X
+1772(screens)X
+1 f
+976 2961(The)N
+3 f
+1134(bg)X
+1 f
+1251(command)X
+1600(backgrounds)X
+2044(the)X
+2176(current)X
+2438(screen,)X
+2698(and)X
+2848(the)X
+3 f
+2980(fg)X
+1 f
+3081(command)X
+3431(foregrounds)X
+3853(back-)X
+976 3051(grounded)N
+1299(screens.)X
+1596(The)X
+3 f
+1741(display)X
+1 f
+2004(command)X
+2340(can)X
+2472(be)X
+2568(used)X
+2735(to)X
+2817(list)X
+2934(the)X
+3052(background)X
+3451(screens.)X
+3 f
+776 3231(Tag)N
+929(stacks)X
+1 f
+976 3321(Tags)N
+1159(are)X
+1285(now)X
+1450(maintained)X
+1834(in)X
+1924(a)X
+1988(stack.)X
+2221(The)X
+3 f
+2374(<control-T>)X
+1 f
+2819(command)X
+3163(returns)X
+3414(to)X
+3504(the)X
+3630(previous)X
+3934(tag)X
+976 3411(location.)N
+1299(The)X
+3 f
+1449(tagpop)X
+1 f
+1709(command)X
+2050(returns)X
+2298(to)X
+2385(the)X
+2508(most)X
+2688(recent)X
+2910(tag)X
+3033(location)X
+3316(by)X
+3421(default,)X
+3689(or,)X
+3801(option-)X
+976 3501(ally)N
+1119(to)X
+1204(a)X
+1263(speci\256c)X
+1531(tag)X
+1652(number)X
+1920(in)X
+2005(the)X
+2126(tag)X
+2248(stack,)X
+2457(or)X
+2548(the)X
+2670(most)X
+2849(recent)X
+3070(tag)X
+3192(from)X
+3372(a)X
+3432(speci\256ed)X
+3741(\256le.)X
+3907(The)X
+3 f
+976 3591(display)N
+1 f
+1241(command)X
+1579(can)X
+1713(be)X
+1810(used)X
+1978(to)X
+2061(list)X
+2179(the)X
+2298(tags)X
+2448(stack.)X
+2674(The)X
+3 f
+2820(tagtop)X
+1 f
+3059(command)X
+3396(returns)X
+3640(to)X
+3723(the)X
+3842(top)X
+3965(of)X
+976 3681(the)N
+1094(tag)X
+1212(stack.)X
+3 f
+776 3861(New)N
+948(displays)X
+1 f
+976 3951(The)N
+3 f
+1128(display)X
+1 f
+1398(command)X
+1741(can)X
+1880(be)X
+1984(used)X
+2159(to)X
+2249(display)X
+2508(the)X
+2634(current)X
+2890(buffers,)X
+3166(the)X
+3292(backgrounded)X
+3775(screens,)X
+976 4041(and)N
+1112(the)X
+1230(tags)X
+1379(stack.)X
+3 f
+776 4221(In\256nite)N
+1044(undo)X
+1 f
+976 4311(Changes)N
+1282(made)X
+1486(during)X
+1725(an)X
+1832(edit)X
+1983(session)X
+2245(may)X
+2414(be)X
+2521(rolled)X
+2739(backward)X
+3083(and)X
+3230(forward.)X
+3556(A)X
+3 f
+3645(.)X
+1 f
+3716(command)X
+976 4401(immediately)N
+1403(after)X
+1578(a)X
+3 f
+1640(u)X
+1 f
+1710(command)X
+2052(continues)X
+2385(either)X
+2594(forward)X
+2875(or)X
+2968(backward)X
+3307(depending)X
+3667(on)X
+3773(whether)X
+976 4491(the)N
+3 f
+1094(u)X
+1 f
+1158(command)X
+1494(was)X
+1639(an)X
+1735(undo)X
+1915(or)X
+2002(a)X
+2058(redo.)X
+3 f
+776 4671(Usage)N
+1001(information)X
+1 f
+976 4761(The)N
+3 f
+1126(exusage)X
+1 f
+1418(and)X
+3 f
+1559(viusage)X
+1 f
+1837(commands)X
+2209(provide)X
+2479(usage)X
+2688(information)X
+3092(for)X
+3212(all)X
+3318(of)X
+3411(the)X
+3 f
+3535(ex)X
+1 f
+3637(and)X
+3 f
+3779(vi)X
+1 f
+3867(com-)X
+976 4851(mands)N
+1205(by)X
+1305(default,)X
+1568(or,)X
+1675(optionally,)X
+2039(for)X
+2153(a)X
+2209(speci\256c)X
+2474(command)X
+2810(or)X
+2897(key.)X
+3 f
+776 5031(Extended)N
+1120(Regular)X
+1416(Expressions)X
+1 f
+976 5121(The)N
+3 f
+1133(extended)X
+1 f
+1472(option)X
+1708(causes)X
+1950(Regular)X
+2237(Expressions)X
+2657(to)X
+2752(be)X
+2861(interpreted)X
+3242(as)X
+3342(as)X
+3442(Extended)X
+3778(Regular)X
+976 5211(Expressions,)N
+1403(\(i.e.)X
+2 f
+1548(egrep)X
+1 f
+1731(\(1\))X
+1845(style)X
+2016(Regular)X
+2290(Expressions\).)X
+3 f
+776 5391(Word)N
+996(search)X
+1 f
+976 5481(The)N
+3 f
+1121(<control-A>)X
+1 f
+1563(command)X
+1899(searches)X
+2192(for)X
+2306(the)X
+2424(word)X
+2609 0.4028(referenced)AX
+2970(by)X
+3070(the)X
+3188(cursor.)X
+3 f
+776 5661(Number)N
+1081(increment)X
+1 f
+976 5751(The)N
+3 f
+1121(#)X
+1 f
+1181(command)X
+1517(increments)X
+1889(or)X
+1976(decrements)X
+2362(the)X
+2480(number)X
+2745 0.4028(referenced)AX
+3106(by)X
+3206(the)X
+3324(cursor.)X
+
+54 p
+%%Page: 54 53
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-54)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+776 762(Previous)N
+1094(\256le)X
+1 f
+976 852(The)N
+3 f
+1121(previous)X
+1 f
+1434(command)X
+1770(edits)X
+1941(the)X
+2059(previous)X
+2355(\256le)X
+2477(from)X
+2653(the)X
+2771(argument)X
+3094(list.)X
+3 f
+776 1032(Left-right)N
+1135(scrolling)X
+1 f
+976 1122(The)N
+3 f
+1130(leftright)X
+1 f
+1440(option)X
+1673(causes)X
+3 f
+1912(nvi)X
+1 f
+2047(to)X
+2138(do)X
+2248(left-right)X
+2563(screen)X
+2799(scrolling,)X
+3129(instead)X
+3386(of)X
+3483(the)X
+3611(traditional)X
+3 f
+3970(vi)X
+1 f
+976 1212(line)N
+1116(wrapping.)X
+
+55 p
+%%Page: 55 54
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(Nvi/Nex)N
+872 0.3906(Reference)AX
+3658(USD:13-55)X
+776 762(17.)N
+916(Index)X
+1 f
+776 885(.)N
+1549(18)X
+776 975(!)N
+1429(15,)X
+1549(34)X
+776 1065("")N
+1549(34)X
+776 1155(#)N
+1429(16,)X
+1549(35)X
+776 1245($)N
+1549(16)X
+776 1335(%)N
+1549(16)X
+776 1425(&)N
+1429(17,)X
+1549(42)X
+776 1515(\()N
+1549(17)X
+776 1605(\))N
+1549(17)X
+776 1695(*)N
+1549(35)X
+776 1785(+)N
+1549(13)X
+776 1875(,)N
+1549(18)X
+776 1965(/RE/)N
+1549(18)X
+776 2055(0)N
+1549(19)X
+776 2145(0<control-D>)N
+1549(31)X
+776 2235(:)N
+1549(19)X
+776 2325(;)N
+1549(19)X
+776 2415(<)N
+1429(20,)X
+1549(35)X
+776 2505(<control-A>)N
+1549(11)X
+776 2595(<control-B>)N
+1549(11)X
+776 2685(<control-D>)N
+1429(12,)X
+1549(31)X
+776 2775(<control-E>)N
+1549(12)X
+776 2865(<control-F>)N
+1549(12)X
+776 2955(<control-G>)N
+1549(12)X
+776 3045(<control-H>)N
+1429(12,)X
+1549(31)X
+776 3135(<control-J>)N
+1549(13)X
+776 3225(<control-L>)N
+1549(13)X
+776 3315(<control-M>)N
+1549(13)X
+776 3405(<control-N>)N
+1549(13)X
+776 3495(<control-P>)N
+1549(13)X
+776 3585(<control-R>)N
+1549(13)X
+776 3675(<control-T>)N
+1429(14,)X
+1549(31)X
+776 3765(<control-U>)N
+1549(14)X
+776 3855(<control-W>)N
+1429(14,)X
+1549(31)X
+776 3945(<control-X>)N
+1549(31)X
+776 4035(<control-Y>)N
+1549(14)X
+776 4125(<control-Z>)N
+1429(14,)X
+1549(43)X
+776 4215(<control-]>)N
+1549(15)X
+776 4305(<control-\303>)N
+1549(15)X
+776 4395(<end-of-\256le>)N
+1549(34)X
+776 4485(<eof>)N
+1549(33)X
+776 4575(<erase>)N
+1549(31)X
+776 4665(<escape>)N
+1429(14,)X
+1549(31)X
+776 4755(<interrupt>)N
+1349(7,)X
+1429(30,)X
+1549(31)X
+776 4845(<line)N
+961(erase>)X
+1549(31)X
+776 4935(<literal)N
+1028(next>)X
+1469(7,)X
+1549(31)X
+776 5025(<nul>)N
+1549(30)X
+776 5115(<space>)N
+1549(15)X
+776 5205(<word)N
+1006(erase>)X
+1549(31)X
+776 5295(=)N
+1549(35)X
+776 5385(>)N
+1429(20,)X
+1549(35)X
+776 5475(?RE?)N
+1549(18)X
+776 5565(@)N
+1429(20,)X
+1549(35)X
+776 5655(A)N
+1549(20)X
+776 5745(B)N
+1549(20)X
+2077 885(C)N
+2850(21)X
+2077 975(D)N
+2850(21)X
+2077 1065(E)N
+2850(21)X
+2077 1155(F)N
+2850(21)X
+2077 1245(G)N
+2850(21)X
+2077 1335(H)N
+2850(21)X
+2077 1425(I)N
+2850(22)X
+2077 1515(J)N
+2850(22)X
+2077 1605(L)N
+2850(22)X
+2077 1695(M)N
+2850(22)X
+2077 1785(N)N
+2850(18)X
+2077 1875(O)N
+2850(22)X
+2077 1965(P)N
+2850(23)X
+2077 2055(Q)N
+2850(23)X
+2077 2145(R)N
+2850(23)X
+2077 2235(S)N
+2850(23)X
+2077 2325(T)N
+2850(23)X
+2077 2415(U)N
+2850(23)X
+2077 2505(W)N
+2850(24)X
+2077 2595(X)N
+2850(24)X
+2077 2685(Y)N
+2850(24)X
+2077 2775(ZZ)N
+2850(24)X
+2077 2865([[)N
+2850(24)X
+9 f
+2077 2955(-)N
+1 f
+2850(18)X
+2077 3045(]])N
+2850(25)X
+2077 3135(\303)N
+2850(25)X
+2077 3225(\303<control-D>)N
+2850(31)X
+2077 3315(_)N
+2850(25)X
+2077 3405 0.2841(`<character>)AN
+2850(17)X
+2077 3495(a)N
+2850(25)X
+2077 3585(abbrev)N
+2850(35)X
+2077 3675(alternate)N
+2374(pathname)X
+2890(8)X
+2077 3765(altwerase)N
+2850(46)X
+2077 3855(append)N
+2850(36)X
+2077 3945(args)N
+2850(36)X
+2077 4035(autoindent)N
+2850(46)X
+2077 4125(autoprint)N
+2850(46)X
+2077 4215(autowrite)N
+2850(47)X
+2077 4305(b)N
+2850(25)X
+2077 4395(beautify)N
+2850(47)X
+2077 4485(bg)N
+2850(36)X
+2077 4575(bigword)N
+2850(10)X
+2077 4665(buffer)N
+2890(8)X
+2077 4755(c)N
+2850(26)X
+2077 4845(cd)N
+2850(36)X
+2077 4935(cdpath)N
+2850(47)X
+2077 5025(change)N
+2850(36)X
+2077 5115(chdir)N
+2850(36)X
+2077 5205(columns)N
+2850(47)X
+2077 5295(comment)N
+2850(47)X
+2077 5385(copy)N
+2850(36)X
+2077 5475(count)N
+2730(10,)X
+2850(33)X
+2077 5565(current)N
+2325(pathname)X
+2890(8)X
+2077 5655(d)N
+2850(26)X
+2077 5745(delete)N
+2850(37)X
+3378 885(directory)N
+4151(47)X
+3378 975(display)N
+4151(37)X
+3378 1065(e)N
+4151(26)X
+3378 1155(edcompatible)N
+4151(47)X
+3378 1245(edit)N
+4151(37)X
+3378 1335(errorbells)N
+4151(47)X
+3378 1425(exrc)N
+4151(47)X
+3378 1515(extended)N
+4151(48)X
+3378 1605(exusage)N
+4151(37)X
+3378 1695(f)N
+4151(26)X
+3378 1785(fg)N
+4151(37)X
+3378 1875(\256le)N
+4031(33,)X
+4151(37)X
+3378 1965(\257ags)N
+4151(33)X
+3378 2055(\257ash)N
+4151(48)X
+3378 2145(global)N
+4151(38)X
+3378 2235(hardtabs)N
+4151(48)X
+3378 2325(help)N
+4151(38)X
+3378 2415(i)N
+4151(26)X
+3378 2505(ignorecase)N
+4151(48)X
+3378 2595(insert)N
+4151(38)X
+3378 2685(j)N
+4151(13)X
+3378 2775(join)N
+4151(38)X
+3378 2865(k)N
+4031(13,)X
+4151(39)X
+3378 2955(keytime)N
+4151(48)X
+3378 3045(l)N
+4151(15)X
+3378 3135(leftright)N
+4151(48)X
+3378 3225(line)N
+4151(33)X
+3378 3315(lines)N
+4151(48)X
+3378 3405(lisp)N
+4151(48)X
+3378 3495(list)N
+4031(39,)X
+4151(48)X
+3378 3585(m)N
+4151(27)X
+3378 3675(magic)N
+4151(48)X
+3378 3765(map)N
+4151(39)X
+3378 3855(mark)N
+4151(39)X
+3378 3945(matchtime)N
+4151(48)X
+3378 4035(mesg)N
+4151(48)X
+3378 4125(mkexrc)N
+4151(39)X
+3378 4215(modelines)N
+4151(49)X
+3378 4305(motion)N
+4151(10)X
+3378 4395(move)N
+4151(39)X
+3378 4485(n)N
+4151(18)X
+3378 4575(next)N
+4151(40)X
+3378 4665(number)N
+4031(35,)X
+4151(49)X
+3378 4755(o)N
+4151(27)X
+3378 4845(octal)N
+4151(49)X
+3378 4935(open)N
+4031(40,)X
+4151(49)X
+3378 5025(optimize)N
+4151(49)X
+3378 5115(p)N
+4151(27)X
+3378 5205(paragraph)N
+4151(11)X
+3378 5295(paragraphs)N
+4151(49)X
+3378 5385(preserve)N
+4151(40)X
+3378 5475(previous)N
+4151(40)X
+3378 5565(previous)N
+3674(context)X
+4191(9)X
+3378 5655(print)N
+4151(40)X
+3378 5745(prompt)N
+4151(49)X
+
+56 p
+%%Page: 56 55
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-56)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+1 f
+776 762(put)N
+1549(40)X
+776 852(quit)N
+1549(41)X
+776 942(r)N
+1549(27)X
+776 1032(range)N
+1549(33)X
+776 1122(read)N
+1549(41)X
+776 1212(readonly)N
+1549(49)X
+776 1302(recdir)N
+1549(49)X
+776 1392(recover)N
+1549(41)X
+776 1482(redraw)N
+1549(50)X
+776 1572(remap)N
+1549(50)X
+776 1662(report)N
+1549(50)X
+776 1752(resize)N
+1549(41)X
+776 1842(rewind)N
+1549(41)X
+776 1932(ruler)N
+1549(50)X
+776 2022(s)N
+1549(27)X
+776 2112(scroll)N
+1549(50)X
+776 2202(section)N
+1549(11)X
+776 2292(sections)N
+1549(50)X
+776 2382(sentence)N
+1549(11)X
+776 2472(set)N
+1549(41)X
+776 2562(shell)N
+1429(42,)X
+1549(50)X
+776 2652(shiftwidth)N
+1549(50)X
+776 2742(showdirty)N
+1549(51)X
+776 2832(showmatch)N
+1549(51)X
+776 2922(showmode)N
+1549(51)X
+776 3012(sidescroll)N
+1549(51)X
+776 3102(slowopen)N
+1549(51)X
+776 3192(source)N
+1549(42)X
+776 3282(sourceany)N
+1549(51)X
+776 3372(split)N
+1549(42)X
+776 3462(stop)N
+1549(43)X
+776 3552(substitute)N
+1549(42)X
+776 3642(suspend)N
+1549(43)X
+776 3732(t)N
+1429(27,)X
+1549(36)X
+776 3822(tabstop)N
+1549(51)X
+776 3912(tag)N
+1549(43)X
+776 4002(taglength)N
+1549(51)X
+776 4092(tagpop)N
+1549(43)X
+776 4182(tags)N
+1549(51)X
+776 4272(tagtop)N
+1549(43)X
+776 4362(term)N
+1549(51)X
+776 4452(terse)N
+1549(51)X
+776 4542(tildeop)N
+1549(51)X
+776 4632(timeout)N
+1549(51)X
+776 4722(ttywerase)N
+1549(52)X
+776 4812(u)N
+1549(28)X
+776 4902(unabbrev)N
+1549(44)X
+776 4992(undo)N
+1549(44)X
+776 5082(unmap)N
+1549(44)X
+776 5172(unnamed)N
+1090(buffer)X
+1589(8)X
+776 5262(v)N
+1549(38)X
+776 5352(verbose)N
+1549(52)X
+776 5442(version)N
+1549(44)X
+776 5532(visual)N
+1549(44)X
+776 5622(viusage)N
+1549(44)X
+776 5712(w)N
+1549(28)X
+776 5802(w1200)N
+1549(52)X
+2077 762(w300)N
+2850(52)X
+2077 852(w9600)N
+2850(52)X
+2077 942(warn)N
+2850(52)X
+2077 1032(window)N
+2850(52)X
+2077 1122(wn)N
+2850(44)X
+2077 1212(word)N
+2850(10)X
+2077 1302(wq)N
+2850(44)X
+2077 1392(wrapmargin)N
+2850(52)X
+2077 1482(wrapscan)N
+2850(52)X
+2077 1572(write)N
+2850(44)X
+2077 1662(writeany)N
+2850(53)X
+2077 1752(x)N
+2850(28)X
+2077 1842(xit)N
+2850(45)X
+2077 1932(y)N
+2850(28)X
+2077 2022(yank)N
+2850(45)X
+2077 2112(z)N
+2730(28,)X
+2850(45)X
+2077 2202({)N
+2850(29)X
+2077 2292(|)N
+2850(29)X
+2077 2382(})N
+2850(29)X
+2077 2472(\304)N
+2610(29,)X
+2730(30,)X
+2850(42)X
+
+2 p
+%%Page: 2 56
+10 s 10 xH 0 xS 1 f 1 i
+3 f
+576 474(USD:13-2)N
+3391(Nvi/Nex)X
+3687 0.3906(Reference)AX
+12 s
+2039 762(Table)N
+2298(of)X
+2402(Contents)X
+1 f
+10 s
+776 961(Description)N
+1184(................................................................................................................................)X
+3992(3)X
+776 1070(Startup)N
+1027(Information)X
+1444(...................................................................................................................)X
+3992(3)X
+776 1179(Recovery)N
+1104(....................................................................................................................................)X
+3992(3)X
+776 1288(Sizing)N
+1000(the)X
+1118(Screen)X
+1364(.......................................................................................................................)X
+3992(5)X
+776 1397(Character)N
+1109(Display)X
+1384(......................................................................................................................)X
+3992(5)X
+776 1506(Multiple)N
+1071(Screens)X
+1344(........................................................................................................................)X
+3992(6)X
+776 1615(Regular)N
+1050(Expressions)X
+1457(and)X
+1593(Replacement)X
+2032(Strings)X
+2284(.........................................................................)X
+3992(6)X
+776 1724(General)N
+1051(Editor)X
+1271(Description)X
+1684(.......................................................................................................)X
+3992(7)X
+776 1833(Vi)N
+876(Description)X
+1284(...........................................................................................................................)X
+3992(8)X
+776 1942(Vi)N
+876(Commands)X
+1264(............................................................................................................................)X
+3952(11)X
+776 2051(Vi)N
+876(Text)X
+1043(Input)X
+1232(Commands)X
+1624(..........................................................................................................)X
+3952(30)X
+776 2160(Ex)N
+885(Addressing)X
+1284(...........................................................................................................................)X
+3952(31)X
+776 2269(Ex)N
+885(Description)X
+1284(...........................................................................................................................)X
+3952(33)X
+776 2378(Ex)N
+885(Commands)X
+1284(...........................................................................................................................)X
+3952(34)X
+776 2487(Set)N
+898(Options)X
+1184(................................................................................................................................)X
+3952(46)X
+776 2596(Additional)N
+1138(Features)X
+1430(in)X
+1512(Nex/Nvi)X
+1824(................................................................................................)X
+3952(53)X
+776 2705(Index)N
+984(..........................................................................................................................................)X
+3952(55)X
+
+56 p
+%%Trailer
+xt
+
+xs
diff --git a/usr.bin/vi/USD.doc/vi.ref/set.opt.roff b/usr.bin/vi/USD.doc/vi.ref/set.opt.roff
new file mode 100644
index 000000000000..d59599d14268
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/set.opt.roff
@@ -0,0 +1,949 @@
+.\" 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.26 (Berkeley) 8/11/94
+.\"
+.SH 1 "Set Options"
+.pp
+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.
+(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
+.EV nex nvi .
+Historically, only the full name and the official abbreviations
+were accepted by
+.EV ex vi .
+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 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
+.CO ex
+and
+.CO vi
+modes, unless otherwise specified.
+.pp
+For information on modifying the options or to display the options and
+their current values, see the
+.QQ set
+command in the section entitled
+.QB "Ex Commands" .
+.KY altwerase
+.IP "altwerase [off]"
+.CO Vi
+only.
+Change how
+.CO 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 nonblank
+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).
+.KY autoindent
+.IP "autoindent, ai [off]"
+If this option is set, whenever you create a new line (using the
+.CO vi
+.CO A ,
+.CO a ,
+.CO C ,
+.CO c ,
+.CO I ,
+.CO i ,
+.CO O ,
+.CO o ,
+.CO R ,
+.CO r ,
+.CO S ,
+and
+.CO s
+commands, or the
+.CO ex
+.CO append ,
+.CO change ,
+and
+.CO insert
+commands) the new line is automatically indented to align the cursor with
+the first nonblank 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
+.OP 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 nonblank character
+to the right of the cursor is aligned as described above.
+.sp
+The indent characters are themselves somewhat special.
+If you do not enter more characters on the new line before moving to
+another line, or entering
+.LI <escape> ,
+the indent character will be deleted and the line will be empty.
+For example, if you enter
+.LI <carriage-return>
+twice in succession,
+the line created by the first
+.LI <carriage-return>
+will not have any characters in it,
+regardless of the indentation of the previous or subsequent line.
+.sp
+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
+.LI <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
+.CO <control-D>
+key would erase the indent characters.
+Both the
+.CO <control-D>
+key and the usual erase keys work in
+.CO nvi .)
+In addition, if the cursor is positioned at the end of the indent
+characters, the keys
+.QT 0<control-D>
+will erase all of the indent characters for the current line,
+resetting the indentation level to 0.
+Similarly, the keys
+.QT ^<control-D>
+will erase all of the indent characters for the current line,
+leaving the indentation level for future created lines unaffected.
+.sp
+Finally, if the
+.OP autoindent
+option is set, the
+.CO S
+and
+.CO cc
+commands change from the first nonblank of the line to the end of the
+line, instead of from the beginning of the line to the end of the line.
+.KY autoprint
+.IP "autoprint, ap [off]"
+.CO Ex
+only.
+Cause the current line to be automatically displayed after the
+.CO ex
+commands
+.CO < ,
+.CO > ,
+.CO copy ,
+.CO delete ,
+.CO join ,
+.CO move ,
+.CO put ,
+.CO t ,
+.CO Undo ,
+and
+.CO undo .
+This automatic display is suppressed during
+.CO global
+and
+.CO vglobal
+commands, and for any command where optional flags are used to explicitly
+display the line.
+.KY autowrite
+.IP "autowrite, aw [off]"
+If this option is set, the
+.CO vi
+.CO ! ,
+.CO ^^ ,
+.CO ^]
+and
+.CO <control-Z>
+commands, and the
+.CO ex
+.CO edit ,
+.CO next ,
+.CO rewind ,
+.CO stop ,
+.CO suspend ,
+.CO tag ,
+.CO tagpop ,
+and
+.CO 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.
+.sp
+Appending the optional force flag character
+.QT !
+to the
+.CO ex
+commands
+.CO next ,
+.CO rewind ,
+.CO stop ,
+.CO suspend ,
+.CO tag ,
+.CO tagpop ,
+and
+.CO tagtop
+stops the automatic write from being attempted.
+.sp
+(Historically, the
+.CO next
+command ignored the optional force flag.)
+Note, the
+.CO ex
+commands
+.CO edit ,
+.CO quit ,
+.CO shell ,
+and
+.CO xit
+are
+.i not
+affected by the
+.OP autowrite
+option.
+.KY beautify
+.IP "beautify, bf [off]"
+If this option is set, all control characters that are not currently being
+specially interpreted, other than
+.LI <tab> ,
+.LI <newline> ,
+and
+.LI <form-feed> ,
+are
+discarded from commands read in by
+.CO ex
+from command files, and from input text entered to
+.CO vi
+(either into the file or to the colon command line).
+Text files read by
+.EV ex vi
+are
+.i not
+affected by the
+.OP beautify
+option.
+.KY cdpath
+.IP "cdpath [environment variable CDPATH, or current directory]"
+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
+.CO cd
+command.
+The value of this option defaults to the value of the environmental
+variable
+.LI CDPATH
+if it is set, otherwise to the current directory.
+For compatibility with the POSIX 1003.2 shell, the
+.CO cd
+command does
+.i 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
+.QT \&.
+character into the
+.LI CDPATH
+variable or the option value.
+.KY columns
+.IP "columns, co [80]"
+The number of columns in the screen.
+Setting this option causes
+.EV ex vi
+to set (or reset) the environmental variable
+.LI COLUMNS .
+See the section entitled
+.QB "Sizing the Screen"
+more information.
+.KY comment
+.IP "comment [off]"
+.CO Vi
+only.
+If the first non-empty line of the file begins with the string
+.QT /\&* ,
+this option causes
+.CO vi
+to skip to the end of that C-language comment (probably a terribly boring
+legal notice) before displaying the file.
+.KY directory
+.IP "directory, dir [environment variable TMPDIR, or /tmp]"
+The directory where temporary files are created.
+The environmental variable
+.LI TMPDIR
+is used as the default value if it exists, otherwise
+.LI /tmp
+is used.
+.KY edcompatible
+.IP "edcompatible, ed [off]"
+Remember the values of the
+.QQ c
+and
+.QQ g
+suffices to the
+.CO substitute
+commands, instead of initializing them as unset for each new
+command.
+Specifying pattern and replacement strings to the
+.CO substitute
+command unsets the
+.QQ c
+and
+.QQ g
+suffices as well.
+.KY errorbells
+.IP "errorbells, eb [off]"
+.CO Ex
+only.
+.CO Ex
+error messages are normally presented in inverse video.
+If that is not possible for the terminal, setting this option causes
+error messages to be announced by ringing the terminal bell.
+.KY exrc
+.IP "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, regardless.
+See the section entitled
+.QB "Startup Information"
+for more information.
+.KY extended
+.IP "extended [off]"
+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).
+.KY flash
+.IP "flash [on]"
+This option causes the screen to flash instead of beeping the keyboard,
+on error, if the terminal has the capability.
+.KY hardtabs
+.IP "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
+.EV nex nvi
+never writes
+.LI <tab>
+characters to the terminal, unlike historic versions of
+.EV ex vi ,
+this option does not currently have any affect.
+.KY ignorecase
+.IP "ignorecase, ic [off]"
+This option causes regular expressions, both in
+.CO ex
+commands and in searches,
+to be evaluated in a case-insensitive manner.
+.KY keytime
+.IP "keytime [6]"
+The 10th's of a second
+.EV ex vi
+waits for a subsequent key to complete a key mapping.
+.KY leftright
+.IP "leftright [off]"
+.CO Vi
+only.
+This option causes the screen to be scrolled left-right to view
+lines longer than the screen, instead of the traditional
+.CO vi
+screen interface which folds long lines at the right-hand margin
+of the terminal.
+.KY lines
+.IP "lines, li [24]"
+.CO Vi
+only.
+The number of lines in the screen.
+Setting this option causes
+.EV ex vi
+to set (or reset) the environmental variable
+.LI LINES .
+See the section entitled
+.QB "Sizing the Screen"
+for more information.
+.KY lisp
+.IP "lisp [off]"
+.CO Vi
+only.
+This option changes the behavior of the
+.CO vi
+.CO ( ,
+.CO ) ,
+.CO { ,
+.CO } ,
+.CO [[
+and
+.CO ]]
+commands to match the Lisp language.
+Also, the
+.OP autoindent
+option's behavior is changed to be appropriate for Lisp.
+.sp
+.i "This option is not yet implemented."
+.KY list
+.IP "list [off]"
+This option causes lines to be displayed in an unambiguous fashion.
+Specifically, tabs are displayed as control characters, i.e.
+.QT ^I ,
+and the ends of lines are marked with a
+.QT $
+character.
+.KY magic
+.IP "magic [on]"
+This option is on by default.
+Turning the
+.OP magic
+option off causes all regular expression characters except for
+.QT ^
+and
+.QT $ ,
+to be treated as ordinary characters.
+To re-enable characters individually, when the
+.OP magic
+option is off,
+precede them with a backslash
+.QT \e
+character.
+See the section entitled
+.QB "Regular Expressions and Replacement Strings"
+for more information.
+.KY matchtime
+.IP "matchtime [7]"
+.CO Vi
+only.
+The 10th's of a second
+.EV ex vi
+pauses on the matching character when the
+.OP showmatch
+option is set.
+.KY mesg
+.IP "mesg [on]"
+This option allows other users to contact you using the
+.XR talk 1
+and
+.XR write 1
+utilities, while you are editing.
+.EV 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.
+.KY modelines
+.IP "modelines, modeline [off]"
+If the
+.OP modelines
+option is set,
+.EV ex vi
+has historically scanned the first and last five lines of each file as
+it is read for editing, looking for any
+.CO 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.
+.sp
+Commands were recognized by the letters
+.QQ e
+or
+.QQ v
+followed by
+.QQ x
+or
+.QQ i ,
+at the beginning of a line or following a tab or space character,
+and followed by a
+.QQ : ,
+an
+.CO ex
+command, and another
+.QQ : .
+.sp
+This option is a security problem of immense proportions,
+and should not be used under any circumstances.
+.sp
+.i "This option will never be implemented."
+.KY number
+.IP "number, nu [off]"
+Precede each line displayed with its current line number.
+.KY octal
+.IP "octal [off]"
+Display unknown characters as octal numbers, instead of the default
+hexadecimal.
+.KY open
+.IP "open [on]"
+.CO Ex
+only.
+If this option is not set, the
+.CO open
+and
+.CO visual
+commands are disallowed.
+.KY optimize
+.IP "optimize, opt [on]"
+.CO Vi
+only.
+Throughput of text is expedited by setting the terminal not to 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.
+.sp
+.i "This option is not yet implemented."
+.KY paragraphs
+.IP "paragraphs, para [IPLPPPQPP LIpplpipbp]"
+.CO Vi
+only.
+Define additional paragraph boundaries for the
+.CO {
+and
+.CO }
+commands.
+The value of this option must be a character string consisting
+of zero or more character pairs.
+.sp
+In the text to be edited, the character string
+.LI "<newline>.<char-pair>" ,
+(where
+.LI <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
+.LI "LaA<space>##" ,
+then all of the following additional paragraph boundaries would be
+recognized:
+.sp
+.(l
+<newline>.La
+<newline>.A<space>
+<newline>.##
+.)l
+.KY prompt
+.IP "prompt [on]"
+.CO Ex
+only.
+This option causes
+.CO ex
+to prompt for command input with a
+.QT :
+character; when it is not set, no prompt is displayed.
+.KY readonly
+.IP "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
+.b \-R
+command line option, or editing a file which lacks write permission.
+.KY recdir
+.IP "recdir [/var/tmp/vi.recover]"
+The directory where recovery files are stored.
+.sp
+If you change the value of
+.CO recdir ,
+be careful to choose a directory whose contents are not regularly
+deleted.
+Bad choices include directories in memory based filesystems,
+or
+.LI /tmp ,
+on most systems,
+as their contents are removed when the machine is rebooted.
+.sp
+Public directories like
+.LI /usr/tmp
+and
+.LI /var/tmp
+are usually safe, although some sites periodically prune old files
+from them.
+There is no requirement that you use a public directory,
+e.g. a sub-directory of your home directory will work fine.
+.sp
+Finally, if you change the value of
+.CO recdir ,
+you must modify the recovery script to operate in your chosen recovery
+area.
+.sp
+See the section entitled
+.QB "Recovery"
+for further information.
+.KY redraw
+.IP "redraw, re [off]"
+.CO Vi
+only.
+The editor simulates (using great amounts of output), an intelligent
+terminal on a dumb terminal (e.g. during insertions in
+.CO vi
+the characters to the right of the cursor are refreshed as each input
+character is typed).
+.sp
+.i "This option is not yet implemented."
+.KY remap
+.IP "remap [on]"
+If this option is set,
+it is possible to define macros in terms of other macros.
+Otherwise, each key is only remapped up to one time.
+For example, if
+.QT A
+is mapped to
+.QT B ,
+and
+.QT B
+is mapped to
+.QT C ,
+The keystroke
+.QT A
+will be mapped to
+.QT C
+if the
+.OP remap
+option is set, and to
+.QT B
+if it is not set.
+.KY report
+.IP "report [5]"
+Set the threshold of the number of lines that need to be changed or
+yanked before a message will be displayed to the user.
+For everything but the yank command, the value is the largest value
+about which the editor is silent, i.e. by default, 6 lines must be
+deleted before the user is notified.
+However, if the number of lines yanked is greater than
+.i "or equal to"
+the set value, it is reported to the user.
+.KY ruler
+.IP "ruler [off]"
+.CO Vi
+only.
+Display a row/column ruler on the colon command line.
+.KY scroll
+.IP "scroll, scr [window / 2]"
+Set the number of lines scrolled by the
+.CO vi
+.CO <control-D>
+and
+.CO <control-U>
+commands.
+.sp
+Historically, the
+.CO ex
+.CO 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.
+.KY sections
+.IP "sections, sect [NHSHH HUnhsh]"
+.CO Vi
+only.
+Define additional section boundaries for the
+.CO [[
+and
+.CO ]]
+commands.
+The
+.OP 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
+.LI "<newline>.<char-pair>" ,
+(where
+.LI <char-pair>
+is one of the character pairs in the option's value),
+defines a section boundary in the same manner that
+.OP paragraph
+option boundaries are defined.
+.KY shell
+.IP "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
+.CO vi
+.CO !
+shell escape command and by the
+.CO ex
+.CO shell
+command.
+This program is also used to resolve any shell meta-characters in
+.CO ex
+commands.
+.KY shiftwidth
+.IP "shiftwidth, sw [8]"
+Set the autoindent and shift command indentation width.
+This width is used by the
+.OP autoindent
+option and by the
+.CO < ,
+.CO > ,
+and
+.CO shift
+commands.
+.KY showdirty
+.IP "showdirty [off]"
+.CO Vi
+only.
+Display an asterisk on the colon command line if the file has been modified.
+.KY showmatch
+.IP "showmatch, sm [off]"
+.CO Vi
+only.
+This option causes
+.CO vi ,
+when a
+.QT }
+or
+.QT )
+is entered, to briefly move the cursor the matching
+.QT {
+or
+.QT ( .
+See the
+.OP matchtime
+option for more information.
+.KY showmode
+.IP "showmode [off]"
+.CO Vi
+only.
+This option causes
+.CO vi
+to display a string identifying the current editor mode on the
+colon command line.
+.KY sidescroll
+.IP "sidescroll [16]"
+.CO Vi
+only.
+Sets the number of columns that are shifted to the left or right,
+when
+.CO vi
+is doing left-right scrolling and the left or right margin is
+crossed.
+See the
+.OP leftright
+option for more information.
+.KY slowopen
+.IP "slowopen, slow [off]"
+This option affects the display algorithm used by
+.CO vi ,
+holding off display updating during input of new text to improve
+throughput when the terminal in use is slow and unintelligent.
+.sp
+.i "This option is not yet implemented."
+.KY sourceany
+.IP "sourceany [off]"
+If this option is turned on,
+.CO vi
+historically read startup files that were owned by someone other than
+the editor user.
+See the section entitled
+.QB "Startup Information"
+for more information.
+This option is a security problem of immense proportions,
+and should not be used under any circumstances.
+.sp
+.i "This option will never be implemented."
+.KY tabstop
+.IP "tabstop, ts [8]"
+This option sets tab widths for the editor display.
+.KY taglength
+.IP "taglength, tl [0]"
+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.
+.KY tags
+.IP "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.
+.KY term
+.IP "term, ttytype, tty [environment variable TERM]"
+Set the terminal type.
+Setting this option causes
+.EV ex vi
+to set (or reset) the environmental variable
+.LI TERM .
+.KY terse
+.IP "terse [off]"
+This option has historically made editor messages less verbose.
+It has no effect in this implementation.
+See the
+.OP verbose
+option for more information.
+.KY tildeop
+.IP "tildeop"
+Modify the
+.CO ~
+command to take an associated motion.
+.KY timeout
+.IP "timeout, to [on]"
+If this option is set,
+.EV ex vi
+waits for a specific period for a subsequent key to complete a key
+mapping (see the
+.OP 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.
+.KY ttywerase
+.IP "ttywerase [off]"
+.CO Vi
+only.
+This option changes how
+.CO vi
+does word erase during text input.
+If this option is set, text is broken up into two classes,
+blank characters and nonblank characters.
+Changing from one class to another marks the end of a word.
+.KY verbose
+.IP "verbose [off]"
+.CO Vi
+only.
+.CO 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.
+.KY w300
+.IP "w300 [no default]"
+.CO Vi
+only.
+Set the window size if the baud rate is less than 1200 baud.
+See the
+.OP window
+option for more information.
+.KY w1200
+.IP "w1200 [no default]"
+.CO Vi
+only.
+Set the window size if the baud rate is equal to 1200 baud.
+See the
+.OP window
+option for more information.
+.KY w9600
+.IP "w9600 [no default]"
+.CO Vi
+only.
+Set the window size if the baud rate is greater than 1200 baud.
+See the
+.OP window
+option for more information.
+.KY warn
+.IP "warn [on]"
+.CO Ex
+only.
+This option causes a warning message to the terminal if the file has
+been modified, since it was last written, before a
+.CO !
+command.
+.KY window
+.IP "window, w, wi [environment variable LINES]"
+This option determines the default number of lines in a screenful,
+as written by the
+.CO z
+command.
+It also determines the number of lines scrolled by the
+.CO vi
+commands
+.CO <control-F>
+and
+.CO <control-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 section entitled
+.QB "Sizing the Screen"
+for more information).
+Setting the value of the
+.OP window
+option is the same as using the
+.b \-w
+command line option.
+.sp
+If the value of the
+.OP window
+option (as set by the
+.OP window ,
+.OP w300 ,
+.OP w1200
+or
+.OP 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.
+.KY wrapmargin
+.IP "wrapmargin, wm [0]"
+.CO Vi
+only.
+If the value of the
+.OP wrapmargin
+option is non-zero,
+.CO vi
+will split lines so that they end at least that number of characters
+before the right-hand margin of the screen.
+(Note, the value of
+.OP wrapmargin
+is
+.i not
+a text length.
+In a screen that is 80 columns wide, the command
+.QT ":set wrapmargin=8"
+attempts to keep the lines less than or equal to 72 columns wide.)
+.sp
+Lines are split at the previous whitespace character closest to the
+number.
+Any trailing whitespace characters before that character are deleted.
+If the line is split because of an inserted
+.LI <space>
+or
+.LI <tab>
+character, and you then enter another
+.LI <space>
+character, it is discarded.
+.sp
+If wrapmargin is set to 0,
+or if there is no blank character upon which to split the line,
+the line is not broken.
+.KY wrapscan
+.IP "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.
+.KY writeany
+.IP "writeany, wa [off]"
+If this option is set, file-overwriting checks that would usually be
+made before the
+.CO write
+and
+.CO xit
+commands, or before an automatic write (see the
+.OP autowrite
+option), are not made.
+This allows a write to any file, provided the file permissions allow it.
diff --git a/usr.bin/vi/USD.doc/vi.ref/spell.ok b/usr.bin/vi/USD.doc/vi.ref/spell.ok
new file mode 100644
index 000000000000..60084e31bcf4
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/spell.ok
@@ -0,0 +1,270 @@
+Amir
+Autoprint
+BRE's
+Bostic
+Bourne
+DOUBLEQUOTE
+Dq
+Ds
+ERE's
+EXINIT
+Englar
+Ev
+FF
+Fa
+Fl
+HUnhsh
+IPLPPPQPP
+Kirkendall
+Korn
+LIpplpipbp
+LaA
+Li
+Lowercase
+MINUSSIGN
+Makefiles
+NEX
+NEXINIT
+NHSHH
+NVI
+Nex
+Nvi
+OS
+POSIX
+PostScript
+RE's
+README
+RECDIR
+Reference''USD:13
+SIGHUP
+SIGWINCH
+SQUOTE
+Se
+Std
+Std1003.2
+Sy
+TANDARDS
+TIOCGWINSZ
+TMPDIR
+Todo
+USD.doc
+USD:13
+UUNET
+Vx
+Whitespace
+XOFF
+XON
+XOptions
+XXCOLUMNS
+XXXX
+XXXXXX
+XXb
+ZZ
+ab
+abbrev
+ags
+ai
+al
+altwerase
+arg
+args
+autoindent
+autoprint
+autowrite
+aw
+bbrev
+bf
+bigword
+bigwords
+bostic
+brev
+bugs.current
+c2w
+carat
+cdy
+changelog
+chd
+cmd
+count1
+count2
+creens
+cs.berkeley.edu
+db
+dbopen
+def
+di
+dir
+dit
+docs
+eFlRsv
+eFlRv
+ead
+eb
+edcompatible
+elete
+elvis
+email
+enum
+eof
+errorbells
+esc
+ex.cmd.roff
+exrc
+ext
+exu
+exusage
+fi
+filesystem
+filesystems
+ftp.cs.berkeley.edu
+ftp.uu.net
+gdb
+gdb.script
+gs
+gzip'd
+halfbyte
+hange
+hangup
+hardtabs
+ht
+ic
+ifdef
+ignorecase
+ile
+ind
+ious
+ir
+ist
+ize
+keystroke
+keystrokes
+keytime
+leftright
+lhs
+li
+lib
+libc.tags
+lobal
+lowercase
+lp
+matchtime
+mber
+meta
+mk
+mkexrc
+modeful
+modeline
+modelines
+ndo
+nex
+nexrc
+nk
+nomagic
+nooption
+nsert
+nul
+nvi
+nvi.tar.Z
+nvi.tar.z
+nz
+oin
+op
+ove
+para
+pathname
+pathnames
+ppend
+pu
+py
+rc.local
+readonly
+rec
+recdir
+recfile
+recover.XXXX
+recover.XXXXXX
+recover.c
+recover.script
+remapmax
+res
+rew
+rhs
+ript
+rk
+ro
+roff
+rsion
+sc
+scr
+screeen
+se
+set.opt.roff
+shiftwidth
+showmatch
+showmode
+sidescroll
+slowopen
+sm
+sourceany
+sp
+spell.ok
+st
+sual
+svi
+sw
+ta
+tabstop
+taglength
+tagp
+tagpop
+tagstring
+tagt
+tagtop
+terminfo
+th
+tildeop
+tl
+tmp
+ts
+ttytype
+ttywerase
+uR
+ubstitute
+ucb
+uffers
+uit
+una
+unabbrev
+unm
+uppercase
+urce
+uunet
+var
+ve
+vglobal
+vi.0.ps
+vi.0.txt
+vi.1
+vi.XXXX
+vi.XXXXXX
+vi.cmd.roff
+vi.exrc
+vi.recover
+vibackup
+virecovery
+viu
+viusage
+wa
+whitespace
+wi
+wm
+wn
+wq
+wrapmargin
+wrapscan
+writeany
+ws
+xaw
+xit
+ya
+yy
diff --git a/usr.bin/vi/USD.doc/vi.ref/vi.cmd.roff b/usr.bin/vi/USD.doc/vi.ref/vi.cmd.roff
new file mode 100644
index 000000000000..57c0d372af69
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/vi.cmd.roff
@@ -0,0 +1,2984 @@
+.\" 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.cmd.roff 8.28 (Berkeley) 7/17/94
+.\"
+.SH 1 "Vi Description"
+.pp
+.CO Vi
+takes up the entire screen to display the edited file,
+except for the bottom line of the screen.
+The bottom line of the screen is used to enter
+.CO ex
+commands, and for
+.CO vi
+error and informational messages.
+If no other information is being displayed,
+the default display can show the current cursor row and cursor column,
+an indication of whether the file has been modified,
+and the current mode of the editor.
+See the
+.OP ruler ,
+.OP showdirty
+and
+.OP showmode
+options for more information.
+.pp
+Empty lines do not have any special representation on the screen,
+but lines on the screen that would logically come after the end of
+the file are displayed as a single tilde
+.PQ ~
+character.
+To differentiate between empty lines and lines consisting of only
+whitespace characters, use the
+.OP list
+option.
+Historically, implementations of
+.CO vi
+have also displayed some lines as single asterisk
+.PQ @
+characters.
+These were lines that were not correctly displayed, i.e. lines on the
+screen that did not correspond to lines in the file, or lines that did
+not fit on the current screen.
+.CO Nvi
+never displays lines in this fashion.
+.pp
+.CO Vi
+is a modeful editor, i.e. it has two modes,
+.QQ command
+mode and
+.QQ "text input"
+mode.
+When
+.CO vi
+first starts, it is in command mode.
+There are several commands that change
+.CO vi
+into text input mode.
+The
+.LI <escape>
+character is used to resolve the text input into the file,
+and exit back into command mode.
+In
+.CO vi
+command mode, the cursor is always positioned on the last column of
+characters which take up more than one column on the screen.
+In
+.CO vi
+text insert mode, the cursor is positioned on the first column of
+characters which take up more than one column on the screen.
+.pp
+Generally, if the cursor line and cursor column are not on the screen,
+then the screen is scrolled (if the target cursor is close) or repainted
+(if the target cursor is far away) so that the cursor is on the screen.
+If the screen is scrolled, it is moved a minimal amount, and the cursor
+line will usually appear at the top or bottom of the screen.
+In the screen is repainted, the cursor line will appear in the center of
+the screen, unless the cursor is sufficiently close to the beginning or
+end of the file that this is not possible.
+If the
+.OP leftright
+option is set, the screen may be scrolled or repainted in a horizontal
+direction as well as in a vertical one.
+.pp
+A major difference between the historical
+.CO vi
+presentation and
+.CO nvi
+is in the scrolling and screen oriented position commands,
+.CO <control-B> ,
+.CO <control-D> ,
+.CO <control-E> ,
+.CO <control-F> ,
+.CO <control-U> ,
+.CO <control-Y> ,
+.CO H ,
+.CO L
+and
+.CO M .
+In historical implementations of
+.CO vi ,
+these commands acted on physical (as opposed to logical, or screen)
+lines.
+For lines that were sufficiently long in relation to the size of the
+screen, this meant that single line scroll commands might repaint the
+entire screen, scrolling or screen positioning command might not change
+the screen or move the cursor at all, and some lines simply could not
+be displayed, even though
+.CO vi
+would edit the file that contained them.
+In
+.CO nvi ,
+these commands act on logical, i.e. screen lines.
+You are unlikely to notice any difference unless you are editing files
+with lines significantly longer than a screen width.
+.pp
+.CO Vi
+keeps track of the currently
+.QQ "most attractive"
+cursor position.
+Each command description (for commands that can change the current
+cursor position),
+specifies if the cursor is set to a specific location in the line,
+or if it is moved to the
+.QQ "most attractive cursor position" .
+The latter means that the cursor is moved to the cursor position
+that is vertically as close as possible to the current cursor
+position.
+If the current line is shorter than the cursor position
+.CO vi
+would select, the cursor is positioned on the last character in the line.
+(If the line is empty, the cursor is positioned on the first column
+of the line.)
+If a command moves the cursor to the most attractive position,
+it does not alter the current cursor position, and a subsequent
+movement will again attempt to move the cursor to that position.
+Therefore, although a movement to a line shorter than the currently
+most attractive position will cause the cursor to move to the end of
+that line, a subsequent movement to a longer line will cause the
+cursor to move back to the most attractive position.
+.pp
+In addition, the
+.CO $
+command makes the end of each line the most attractive cursor position
+rather than a specific column.
+.pp
+Each
+.CO vi
+command described below notes where the cursor ends up after it is
+executed.
+This position is described in terms of characters on the line, i.e.
+.QQ "the previous character" ,
+or,
+.QQ "the last character in the line" .
+This is to avoid needing to continually refer to on what part of the
+character the cursor rests.
+.pp
+The following words have special meaning for
+.CO vi
+commands.
+.KY "previous context"
+.IP "previous context"
+The position of the cursor before the command which caused the
+last absolute movement was executed.
+Each
+.CO vi
+command described in the next section that is considered an
+absolute movement is so noted.
+In addition, specifying
+.i any
+address to an
+.CO ex
+command is considered an absolute movement.
+.KY "motion"
+.IP "motion"
+A second
+.CO vi
+command can be used as an optional trailing argument to the
+.CO vi
+.CO \&! ,
+.CO \&< ,
+.CO \&> ,
+.CO \&c ,
+.CO \&d ,
+.CO \&y ,
+and (depending on the
+.OP tildeop
+option)
+.CO \&~
+commands.
+This command indicates the end of the region of text that's affected by
+the command.
+The motion command may be either the command character repeated (in
+which case it means the current line) or a cursor movement command.
+In the latter case, the region affected by the command is from the
+starting or stopping cursor position which comes first in the file,
+to immediately before the starting or stopping cursor position which
+comes later in the file.
+Commands that operate on lines instead of using beginning and ending
+cursor positions operate on all of the lines that are wholly or
+partially in the region.
+In addition, some other commands become line oriented depending on
+where in the text they are used.
+The command descriptions below note these special cases.
+.sp
+The following commands may all be used as motion components for
+.CO vi
+commands:
+.sp
+.ne 12v
+.ft C
+.TS
+r r r r.
+<control-A> <control-H> <control-J> <control-M>
+<control-N> <control-P> <space> $
+% '<character> ( )
++ , - /
+0 ; ? B
+E F G H
+L M N T
+W [[ ]] ^
+\&_ `<character> b e
+f h j k
+l n t w
+{ | }
+.TE
+.ft R
+.sp
+The optional count prefix available for some of the
+.CO vi
+commands that take motion commands, or the count prefix available
+for the
+.CO vi
+commands that are used as motion components,
+may be included and is
+.i always
+considered part of the motion argument.
+For example, the commands
+.QT c2w
+and
+.QT 2cw
+are equivalent, and the region affected by the
+.CO c
+command is two words of text.
+In addition, if the optional count prefix is specified for both the
+.CO vi
+command and its motion component, the effect is multiplicative and
+is considered part of the motion argument.
+For example, the commands
+.QT 4cw
+and
+.QT 2c2w
+are equivalent, and the region affected by the
+.CO c
+command is four words of text.
+.KY "count"
+.IP "count"
+A positive number used as an optional argument to most commands,
+either to give a size or a position (for display or movement commands),
+or as a repeat count (for commands that modify text).
+The count argument is always optional and defaults to 1 unless otherwise
+noted in the command description.
+.sp
+When a
+.CO vi
+command synopsis shows both a
+.LI [buffer]
+and
+.LI [count] ,
+they may be presented in any order.
+.KY "bigword"
+.IP "bigword"
+A set of non-whitespace characters preceded and followed by whitespace
+characters or the beginning or end of the file or line.
+.sp
+Groups of empty lines (or lines containing only whitespace characters)
+are treated as a single bigword.
+.KY word
+.IP word
+Generally, in languages where it is applicable,
+.CO vi
+recognizes two kinds of words.
+First, a sequence of letters, digits and underscores, delimited at both
+ends by: characters other than letters, digits, or underscores; the
+beginning or end of a line; the beginning or end of the file.
+Second, a sequence of characters other than letters, digits, underscores,
+or whitespace characters, delimited at both ends by: a letter, digit,
+underscore, or whitespace character;
+the beginning or end of a line; the beginning or end of the file.
+.sp
+Groups of empty lines (or lines containing only whitespace characters)
+are treated as a single word.
+.KY "paragraph"
+.IP "paragraph"
+An area of text that begins with either the beginning of a file,
+an empty line, or a section boundary, and continues until either
+an empty line, section boundary, or the end of the file.
+.sp
+Groups of empty lines (or lines containing only whitespace characters)
+are treated as a single paragraph.
+.sp
+Additional paragraph boundaries can be defined using the
+.OP paragraph
+option.
+.KY "section"
+.IP "section"
+An area of text that starts with the beginning of the file or a line
+whose first character is an open brace
+.PQ {
+and continues until the next section or the end of the file.
+.sp
+Additional section boundaries can be defined using the
+.OP sections
+option.
+.KY "sentence"
+.IP "sentence"
+An area of text that begins with either the beginning of the file or the
+first nonblank character following the previous sentence, paragraph, or
+section boundary and continues until the end of the file or a or a period
+.PQ \&.
+exclamation point
+.PQ !
+or question mark
+.PQ ?
+character,
+followed by either an end-of-line or two whitespace characters.
+Any number of closing parentheses
+.PQ ) ,
+brackets
+.PQ ]
+or double-quote
+.PQ """"
+characters can appear between the period, exclamation point,
+or question mark and the whitespace characters or end-of-line.
+.sp
+Groups of empty lines (or lines containing only whitespace characters)
+are treated as a single sentence.
+.SH 1 "Vi Commands"
+.pp
+The following section describes the commands available in the command
+mode of the
+.CO vi
+editor.
+In each entry below, the tag line is a usage synopsis for the command
+character.
+In addition, the final line and column the cursor rests upon,
+and any options which affect the command are noted.
+.KY <control-A>
+.IP "[count] <control-A>"
+Search forward
+.LI count
+times for the current word.
+The current word begins at the first non-whitespace character on or
+after the current cursor position,
+and extends up to the next non-word character or the end of the line.
+The search is literal, i.e. no characters in the word have any special
+meaning in terms of Regular Expressions.
+It is an error if no matching pattern is found between the starting position
+and the end of the file.
+.sp
+The
+.CO <control-A>
+command is an absolute movement.
+The
+.CO <control-A>
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Set to the line where the word is found.
+.SP Column:
+Set to the first character of the word.
+.SP Options:
+Affected by the
+.OP extended ,
+.OP ignorecase
+and
+.OP wrapscan
+options.
+.SE
+.KY <control-B>
+.IP "[count] <control-B>"
+Page backward
+.LI count
+screens.
+Two lines of overlap are maintained by displaying the window
+starting at line
+.LI "(top_line - count * window_size) + 2" ,
+where
+.LI window_size
+is the value of the
+.OP window
+option.
+(In the case of split screens, this size is corrected to the
+current screen size.)
+This is an error if the movement is past the beginning of the file.
+.sp
+The
+.CO <control-B>
+command is an absolute movement.
+.SS
+.SP Line:
+Set to the last line of text displayed on the screen.
+.SP Column:
+Set to the first nonblank character of the line.
+.SP Options:
+None.
+.SE
+.KY <control-D>
+.IP "[count] <control-D>"
+Scroll forward
+.LI count
+lines.
+If
+.LI count
+is not specified, scroll forward the number of lines specified by the last
+.CO <control-D>
+or
+.CO <control-U>
+command.
+If this is the first
+.CO <control-D>
+or
+.CO <control-U>
+command,
+scroll forward half the number of lines in the screen.
+(In the case of split screens, the default scrolling distance is
+corrected to half the current screen size.)
+This is an error if the movement is past the end of the file.
+.sp
+The
+.CO <control-D>
+command is an absolute movement.
+.SS
+.SP Line:
+Set to the current line plus the number of lines scrolled.
+.SP Column:
+Set to the first nonblank character of the line.
+.SP Options:
+None.
+.SE
+.KY <control-E>
+.IP "[count] <control-E>"
+Scroll forward
+.LI count
+lines, leaving the cursor on the current line and column, if possible.
+This is an error if the movement is past the end of the file.
+.SS
+.SP Line:
+Unchanged unless the current line scrolls off the screen,
+in which case it is set to the first line on the screen.
+.SP Column:
+Unchanged unless the current line scrolls off the screen,
+in which case it is set to the most attractive cursor position.
+.SP Options:
+None.
+.SE
+.KY <control-F>
+.IP "[count] <control-F>"
+Page forward
+.LI count
+screens.
+Two lines of overlap are maintained by displaying the window
+starting at line
+.LI "top_line + count * window_size - 2" ,
+where
+.LI window_size
+is the value of the
+.OP window
+option.
+(In the case of split screens, this size is corrected to the
+current screen size.)
+This is an error if the movement is past the end of the file.
+.sp
+The
+.CO <control-F>
+command is an absolute movement.
+.SS
+.SP Line:
+Set to the first line on the screen.
+.SP Column:
+Set to the first nonblank character of the current line.
+.SP Options:
+None.
+.SE
+.KY <control-G>
+.IP "<control-G>"
+Display the file information.
+The information includes the current pathname, the current line,
+the number of total lines in the file, the current line as a percentage
+of the total lines in the file, if the file has been modified,
+was able to be locked, if the file's name has been changed,
+and if the edit session is read-only.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY <control-H>
+.IP "<control-H>"
+.Ip "[count] h"
+Move the cursor back
+.LI count
+characters in the current line.
+This is an error if the cursor is on the first character in the line.
+.sp
+The
+.CO <control-H>
+and
+.CO h
+commands may be used as the motion component of other
+.CO vi
+commands,
+in which case any text copied into a buffer is character oriented.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the
+.LI "current - count"
+character, or, the first character in the line if
+.LI count
+is greater than or equal to the number of characters in the line
+before the cursor.
+.SP Options:
+None.
+.SE
+.KY <control-J>
+.IP "[count] <control-J>"
+.KY <control-N>
+.Ip "[count] <control-N>"
+.KY j
+.Ip "[count] j"
+Move the cursor down
+.LI count
+lines without changing the current column.
+This is an error if the movement is past the end of the file.
+.sp
+The
+.CO <control-J> ,
+.CO <control-N>
+and
+.CO j
+commands may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.SS
+.SP Line:
+Set to the current line plus
+.LI count .
+.SP Column:
+The most attractive cursor position.
+.SP Options:
+None.
+.SE
+.KY <control-L>
+.IP "<control-L>"
+.KY <control-R>
+.Ip "<control-R>"
+Repaint the screen.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY <control-M>
+.IP "[count] <control-M>"
+.KY +
+.Ip "[count] +"
+Move the cursor down
+.LI count
+lines to the first nonblank character of that line.
+This is an error if the movement is past the end of the file.
+.sp
+The
+.CO <control-M>
+and
+.CO +
+commands may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.SS
+.SP Line:
+Set to the current line plus
+.LI count .
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+None.
+.SE
+.KY <control-P>
+.IP "[count] <control-P>"
+.KY k
+.Ip "[count] k"
+Move the cursor up
+.LI count
+lines, without changing the current column.
+This is an error if the movement is past the beginning of the file.
+.sp
+The
+.CO <control-P>
+and
+.CO k
+commands may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.SS
+.SP Line:
+Set to the current line minus count.
+.SP Column:
+The most attractive cursor position.
+.SP Options:
+None.
+.SE
+.KY <control-T>
+.IP "<control-T>"
+Return to the most recent tag context.
+The
+.CO <control-T>
+command is an absolute movement.
+.SS
+.SP Line:
+Set to the context of the previous tag command.
+.SP Column:
+Set to the context of the previous tag command.
+.SP Options:
+None.
+.SE
+.KY <control-U>
+.IP "<control-U>"
+Scroll backward
+.LI count
+lines.
+If
+.LI count
+is not specified, scroll backward the number of lines specified by the
+last
+.CO <control-D>
+or
+.CO <control-U>
+command.
+If this is the first
+.CO <control-D>
+or
+.CO <control-U>
+command,
+scroll backward half the number of lines in the screen.
+(In the case of split screens, the default scrolling distance is
+corrected to half the current screen size.)
+This is an error if the movement is past the beginning of the file.
+.sp
+The
+.CO <control-U>
+command is an absolute movement.
+.SS
+.SP Line:
+Set to the current line minus the amount scrolled.
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+None.
+.SE
+.KY <control-W>
+.IP "<control-W>"
+Switch to the next lower screen in the window, or, to the first
+screen if there are no lower screens in the window.
+.SS
+.SP Line:
+Set to the previous cursor position in the window.
+.SP Column:
+Set to the previous cursor position in the window.
+.SP Options:
+None.
+.SE
+.KY <control-Y>
+.IP "<control-Y>"
+Scroll backward
+.LI count
+lines, leaving the current line and column as is, if possible.
+This is an error if the movement is past the beginning of the file.
+.SS
+.SP Line:
+Unchanged unless the current line scrolls off the screen,
+in which case it is set to the last line of text displayed
+on the screen.
+.SP Column:
+Unchanged unless the current line scrolls off the screen,
+in which case it is the most attractive cursor position.
+.SP Options:
+None.
+.SE
+.KY <control-Z>
+.IP "<control-Z>"
+Suspend the current editor session.
+If the file has been modified since it was last completely written,
+and the
+.OP autowrite
+option is set, the file is written before the editor session is
+suspended.
+If this write fails, the editor session is not suspended.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Unchanged.
+.SP Options:
+Affected by the
+.OP autowrite
+option.
+.SE
+.KY <escape>
+.IP "<escape>"
+Execute
+.CO ex
+commands or cancel partial commands.
+If an
+.CO ex
+command is being entered (e.g.
+.CO / ,
+.CO ? ,
+.CO :
+or
+.CO ! ),
+the command is executed.
+If a partial command has been entered, e.g.
+.QL "[0-9]*" ,
+or
+.QL "[0-9]*[!<>cdy]" ,
+the command is cancelled.
+Otherwise, it is an error.
+.SS
+.SP Line:
+When an
+.CO ex
+command is being executed, the current line is set as described for
+that command.
+Otherwise, unchanged.
+.SP Column:
+When an
+.CO ex
+command is being executed, the current column is set as described for
+that command.
+Otherwise, unchanged.
+.SP Options:
+None.
+.SE
+.KY <control-]>
+.IP "<control-]>"
+Push a tag reference onto the tag stack.
+The tags files (see the
+.OP tags
+option for more information) are searched for a tag matching the
+current word.
+The current word begins at the first non-whitespace character on or
+after the current cursor position,
+and extends up to the next non-word character or the end of the line.
+If a matching tag is found, the current file is discarded and the
+file containing the tag reference is edited.
+.sp
+If the current file has been modified since it was last completely
+written, the command will fail.
+The
+.CO <control-]>
+command is an absolute movement.
+.SS
+.SP Line:
+Set to the line containing the matching tag string.
+.SP Column:
+Set to the start of the matching tag string.
+.SP Options:
+Affected by the
+.OP tags
+and
+.OP taglength
+options.
+.SE
+.KY <control-^>
+.IP "<control-^>"
+Switch to the most recently edited file.
+.sp
+If the file has been modified since it was last completely written,
+and the
+.OP autowrite
+option is set, the file is written out.
+If this write fails, the command will fail.
+Otherwise, if the current file has been modified since it was last
+completely written, the command will fail.
+.SS
+.SP Line:
+Set to the line the cursor was on when the file was last edited.
+.SP Column:
+Set to the column the cursor was on when the file was last edited.
+.SP Options:
+Affected by the
+.OP autowrite
+option.
+.SE
+.KY <space>
+.IP "[count] <space>"
+.KY l
+.Ip "[count] l"
+Move the cursor forward
+.LI count
+characters without changing the current line.
+This is an error if the cursor is on the last character in the line.
+.sp
+The
+.CO <space>
+and
+.CO \&l
+commands may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+In addition, these commands may be used as the motion components
+of other commands when the cursor is on the last character in the
+line, without error.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the current character plus the next
+.LI count
+characters, or to the last character on the line if
+.LI count
+is greater than the number of characters in the line after the
+current character.
+.SP Options:
+None.
+.SE
+.KY !
+.IP "[count] ! motion shell-argument(s)"
+Replace text with results from a shell command.
+Pass the lines specified by the
+.LI count
+and
+.LI motion
+arguments as standard input to the program named by the
+.OP shell
+option, and replace those lines with the output (both
+standard error and standard output) of that command.
+.sp
+After the motion is entered,
+.CO vi
+prompts for arguments to the shell command.
+.sp
+Within those arguments,
+.QT %
+and
+.QT #
+characters are expanded to the current and alternate pathnames,
+respectively.
+The
+.QT !
+character is expanded with the command text of the previous
+.CO !
+or
+.CO :!
+commands.
+(Therefore, the command
+.CO !!
+repeats the previous
+.CO !
+command.)
+The special meanings of
+.QT % ,
+.QT #
+and
+.QT !
+can be overridden by escaping them with a backslash.
+If no
+.CO !
+or
+.CO :!
+command has yet been executed, it is an error to use an unescaped
+.QT !
+character.
+The
+.CO !
+command does
+.i not
+do shell expansion on the strings provided as arguments.
+If any of the above expansions change the arguments the user entered,
+the command is redisplayed at the bottom of the screen.
+.sp
+.CO Vi
+then executes the program named by the
+.OP shell
+option, with a
+.b \-c
+flag followed by the arguments (which are bundled into a single argument).
+.sp
+The
+.CO !
+command is permitted in an empty file.
+.sp
+If the file has been modified since it was last completely written,
+the
+.CO !
+command will warn you.
+.SS
+.SP Line:
+The first line of the replaced text.
+.SP Column:
+The first column of the replaced text.
+.SP Options:
+Affected by the
+.OP shell
+option.
+.SE
+.KY #
+.IP "[count] # +|-|#"
+Increment or decrement the current number.
+The current number begins at the first non-number character on or
+before the current cursor position, or the beginning of the line,
+and extends up to the first non-number character on or after the
+current cursor position or the end of the line.
+If the trailing character is a
+.LI \&+ ,
+the number is incremented by
+.LI count .
+If the trailing character is a
+.LI \&- ,
+the number is decremented by
+.LI count .
+If the trailing character is a
+.LI \&# ,
+the previous increment or decrement is repeated.
+.sp
+The format of the number (decimal, hexadecimal, and octal,
+and leading 0's) is retained unless the new value cannot be
+represented in the previous format.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the first character in the cursor word.
+.SP Options:
+None.
+.SE
+.KY $
+.IP "[count] $"
+Move the cursor to the end of a line.
+If
+.LI count
+is specified, the cursor moves down
+.LI "count - 1"
+lines.
+.sp
+It is not an error to use the
+.CO $
+command when the cursor is on the last character in the line or
+when the line is empty.
+.sp
+The
+.CO $
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the cursor is at, or before the first
+nonblank character in the line, in which case it is line oriented.
+It is not an error to use the
+.CO $
+command as a motion component when the cursor is on the last character
+in the line, although it is an error when the line is empty.
+.SS
+.SP Line:
+Set to the current line plus
+.LI count
+minus 1.
+.SP Column:
+Set to the last character in the line.
+.SP Options:
+None.
+.SE
+.KY %
+.IP %
+Move to the matching character.
+The cursor moves to the parenthesis or curly brace which
+.i matches
+the parenthesis or curly brace found at the current cursor position
+or which is the closest one to the right of the cursor on the line.
+It is an error to execute the
+.CO %
+command on a line without a parenthesis or curly brace.
+Historically, any
+.LI count
+specified to the
+.CO %
+command was ignored.
+.sp
+The
+.CO %
+command is an absolute movement.
+The
+.CO %
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the starting point of the region is at
+or before the first nonblank character on its line, and the ending
+point is at or after the last nonblank character on its line, in
+which case it is line oriented.
+.SS
+.SP Line:
+Set to the line containing the matching character.
+.SP Column:
+Set to the matching character.
+.SP Options:
+None.
+.SE
+.KY &
+.IP "&"
+Repeat the previous substitution command on the current line.
+.sp
+Historically, any
+.LI count
+specified to the
+.CO &
+command was ignored.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Unchanged if the cursor was on the last character in the line,
+otherwise, set to the first nonblank character in the line.
+.SP Options:
+Affected by the
+.OP edcompatible ,
+.OP extended ,
+.OP ignorecase
+and
+.OP magic
+options.
+.SE
+.KY SQUOTE<character>
+.IP \'<character>
+.KY `<character>
+.Ip `<character>
+Return to a context marked by the character
+.LI <character> .
+If
+.LI <character>
+is the
+.QT '
+or
+.QT `
+character, return to the previous context.
+If
+.LI <character>
+is any other character,
+return to the context marked by that character (see the
+.CO m
+command for more information).
+If the command is the
+.CO \'
+command, only the line value is restored,
+and the cursor is placed on the first nonblank character of that line.
+If the command is the
+.CO `
+command, both the line and column values are restored.
+.sp
+It is an error if the context no longer exists because of
+line deletion.
+(Contexts follow lines that are moved, or which are deleted
+and then restored.)
+.sp
+The
+.CO \'
+and
+.CO `
+commands are both absolute movements.
+They may be used as a motion component for other
+.CO vi
+commands.
+For the
+.CO \'
+command, any text copied into a buffer is line oriented.
+For the
+.CO `
+command, any text copied into a buffer is character oriented, unless
+it both starts and stops at the first character in the line, in which
+case it is line oriented.
+In addition, when using the
+.CO `
+command as a motion component,
+commands which move backward and started at the first character in the
+line, or move forward and ended at the first character in the line,
+are corrected to the last character of the starting and ending lines,
+respectively.
+.SS
+.SP Line:
+Set to the line from the context.
+.SP Column:
+Set to the first nonblank character in the line, for the
+.CO \'
+command, and set to the context's column for the
+.CO `
+command.
+.SP Options:
+None.
+.SE
+.KY (
+.IP "[count] ("
+Back up
+.LI count
+sentences.
+.sp
+The
+.CO (
+command is an absolute movement.
+The
+.CO (
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the starting and stopping points of the
+region are the first character in the line, in which case it is
+line oriented.
+In the latter case, the stopping point of the region is adjusted
+to be the end of the line immediately before it, and not the original
+cursor position.
+.SS
+.SP Line:
+Set to the line containing the beginning of the sentence.
+.SP Column:
+Set to the first nonblank character of the sentence.
+.SP Options:
+None.
+.SE
+.KY )
+.IP "[count] )"
+Move forward
+.LI count
+sentences.
+.sp
+The
+.CO )
+command is an absolute movement.
+The
+.CO )
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the starting point of the region is the
+first character in the line, in which case it is line oriented.
+In the latter case, if the stopping point of the region is also
+the first character in the line, it is adjusted to be the end of the
+line immediately before it.
+.SS
+.SP Line:
+Set to the line containing the beginning of the sentence.
+.SP Column:
+Set to the first nonblank character of the sentence.
+.SP Options:
+None.
+.SE
+.KY ,
+.IP "[count] ,"
+Reverse find character
+.LI count
+times.
+Reverse the last
+.CO F ,
+.CO f ,
+.CO T
+or
+.CO t
+command, searching the other way in the line,
+.LI count
+times.
+.sp
+The
+.CO ,
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the searched-for character.
+.SP Options:
+None.
+.SE
+.KY MINUSSIGN
+.IP "[count] \-"
+Move to first nonblank of the previous line,
+.LI count
+times.
+.sp
+This is an error if the movement is past the beginning of the file.
+.sp
+The
+.CO -
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.SS
+.SP Line:
+Set to the current line minus
+.LI count .
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+None.
+.SE
+.KY \&.
+.IP "[count] \&."
+Repeat the last
+.CO vi
+command that modified text.
+The repeated command may be a command and motion component combination.
+If
+.LI count
+is specified, it replaces
+.i both
+the count specified for the repeated command, and, if applicable, for
+the repeated motion component.
+If
+.LI count
+is not specified, the counts originally specified to the command being
+repeated are used again.
+.sp
+As a special case, if the
+.CO \.
+command is executed immediately after the
+.CO u
+command, the change log is rolled forward or backward, depending on
+the action of the
+.CO u
+command.
+.SS
+.SP Line:
+Set as described for the repeated command.
+.SP Column:
+Set as described for the repeated command.
+.SP Options:
+None.
+.SE
+.KY /RE/
+.IP "/RE<carriage-return>"
+.Ip "/RE/ [offset]<carriage-return>"
+.KY ?RE?
+.Ip "?RE<carriage-return>"
+.Ip "?RE? [offset]<carriage-return>"
+.KY N
+.Ip "N"
+.KY n
+.Ip "n"
+Search forward or backward for a regular expression.
+The commands beginning with a slash
+.PQ /
+character are forward searches, the commands beginning with a
+question mark
+.PQ ?
+are backward searches.
+.CO Vi
+prompts with the leading character on the last line of the screen
+for a string.
+It then searches forward or backward in the file for the next
+occurrence of the string, which is interpreted as a Basic Regular
+Expression.
+.sp
+The
+.CO /
+and
+.CO ?
+commands are absolute movements.
+They may be used as the motion components of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the search started and ended on
+the first column of a line, in which case it is line oriented.
+In addition, forward searches ending at the first character of a line,
+and backward searches beginning at the first character in the line,
+are corrected to begin or end at the last character of the previous line.
+(Note, forward and backward searches can occur for both
+.CO /
+and
+.CO ?
+commands, if the
+.OP wrapscan
+option is set.)
+.sp
+If an offset from the matched line is specified (i.e. a trailing
+.QT /
+or
+.QT ?
+character is followed by a signed offset), the buffer will always
+be line oriented (e.g.
+.QT /string/+0
+will always guarantee a line orientation).
+.sp
+The
+.CO n
+command repeats the previous search.
+.sp
+The
+.CO N
+command repeats the previous search, but in the reverse direction.
+.sp
+Missing RE's (e.g.
+.QT //<carriage-return> ,
+.QT /<carriage-return> ,
+.QT ??<carriage-return> ,
+or
+.QT ?<carriage-return>
+search for the last search RE, in the indicated direction.
+.sp
+Searches may be interrupted using the
+.LI <interrupt>
+character.
+.SS
+.SP Line:
+Set to the line in which the match occurred.
+.SP Column:
+Set to the first character of the matched string.
+.SP Options:
+Affected by the
+.OP edcompatible ,
+.OP extended ,
+.OP ignorecase ,
+.OP magic ,
+and
+.OP wrapscan
+options.
+.SE
+.KY 0
+.IP "0"
+Move to the first character in the current line.
+It is not an error to use the
+.CO 0
+command when the cursor is on the first character in the line,
+.sp
+The
+.CO 0
+command may be used as the motion component of other
+.CO vi
+commands, in which case it is an error if the cursor is on the
+first character in the line.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the first character in the line.
+.SP Options:
+None.
+.SE
+.KY :
+.IP ":"
+Execute an ex command.
+.CO Vi
+prompts for an
+.CO ex
+command on the last line of the screen, using a colon
+.PQ :
+character.
+The command is terminated by a
+.LI <carriage-return> ,
+.LI <newline>
+or
+.LI <escape>
+character; all of these characters may be escaped by using a
+.LI "<literal next>"
+character.
+The command is then executed.
+.sp
+If the
+.CO ex
+command writes to the screen,
+.CO vi
+will prompt the user for a
+.LI <carriage-return>
+before continuing
+when the
+.CO ex
+command finishes.
+Large amounts of output from the
+.CO ex
+command will be paged for the user, and the user prompted for a
+.LI <carriage-return>
+or
+.LI <space>
+key to continue.
+In some cases, a quit (normally a
+.QQ q
+character) or
+.LI <interrupt>
+may be entered to interrupt the
+.CO ex
+command.
+.sp
+When the
+.CO ex
+command finishes, and the user is prompted to resume visual mode,
+it is also possible to enter another
+.QT :
+character followed by another
+.CO ex
+command.
+.SS
+.SP Line:
+The current line is set as described for the
+.CO ex
+command.
+.SP Column:
+The current column is set as described for the
+.CO ex
+command.
+.SP Options:
+None.
+.SE
+.KY ;
+.IP "[count] ;"
+Repeat the last character find
+.LI count
+times.
+The last character find is one of the
+.CO F ,
+.CO f ,
+.CO T
+or
+.CO t
+commands.
+.sp
+The
+.CO ;
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the searched-for character.
+.SP Options:
+None.
+.SE
+.KY <
+.IP "[count] < motion"
+.KY >
+.Ip "[count] > motion"
+Shift lines left or right.
+Shift the number of lines in the region specified by the motion component,
+times
+.LI count ,
+left (for the
+.CO <
+command) or right (for the
+.CO >
+command) by the number of columns specified by the
+.OP shiftwidth
+option.
+Only whitespace characters are deleted when shifting left;
+once the first character in the line contains a nonblank character,
+the
+.CO shift
+will succeed, but the line will not be modified.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+Affected by the
+.OP shiftwidth
+option.
+.SE
+.KY @
+.IP "@ buffer"
+Execute a named buffer.
+Execute the named buffer as
+.CO vi
+commands.
+The buffer may include
+.CO ex
+commands, too, but they must be expressed as a
+.CO :
+command.
+If the buffer is line oriented,
+.LI <newline>
+characters are logically appended to each line of the buffer.
+If the buffer is character oriented,
+.LI <newline>
+characters are logically appended to all but the last line in the buffer.
+.sp
+If the buffer name is
+.QT @ ,
+or
+.QT * ,
+then the last buffer executed shall be used.
+It is an error to specify
+.QT @@
+or
+.QT **
+if there were no buffer previous executions.
+The text of a macro may contain an
+.CO @
+command,
+and it is possible to create infinite loops in this manner.
+(The
+.LI <interrupt>
+character may be used to interrupt the loop.)
+.SS
+.SP Line:
+The current line is set as described for the command(s).
+.SP Column:
+The current column is set as described for the command(s).
+.SP Options:
+None.
+.SE
+.KY A
+.IP "[count] A"
+Enter input mode, appending the text after the end of the line.
+If
+.LI count
+is specified, the text is repeatedly input
+.LI "count - 1"
+more times after input mode is exited.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY B
+.IP "[count] B"
+Move backward
+.LI count
+bigwords.
+Move the cursor backward to the beginning of a bigword by repeating the
+following algorithm: if the current position is at the beginning of a
+bigword or the character at the current position cannot be part of a bigword,
+move to the first character of the preceding bigword.
+Otherwise, move to the first character of the bigword at the current position.
+If no preceding bigword exists on the current line, move to the first
+character of the last bigword on the first preceding line that contains a
+bigword.
+.sp
+The
+.CO B
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Set to the line containing the word selected.
+.SP Column:
+Set to the first character of the word selected.
+.SP Options:
+None.
+.SE
+.KY C
+.IP "[buffer] [count] C"
+Change text from the current position to the end-of-line.
+If
+.LI count
+is specified, the input text replaces from the current position to
+the end-of-line, plus
+.LI "count - 1"
+subsequent lines.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY D
+.IP "[buffer] D"
+Delete text from the current position to the end-of-line.
+.sp
+It is not an error to execute the
+.CO D
+command on an empty line.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the character before the current character, or, column 1 if
+the cursor was on column 1.
+.SP Options:
+None.
+.SE
+.KY E
+.IP "[count] E"
+Move forward
+.LI count
+end-of-bigwords.
+Move the cursor forward to the end of a bigword by repeating the
+following algorithm: if the current position is the end of a
+bigword or the character at that position cannot be part of a bigword,
+move to the last character of the following bigword.
+Otherwise, move to the last character of the bigword at the current
+position.
+If no succeeding bigword exists on the current line,
+move to the last character of the first bigword on the next following
+line that contains a bigword.
+.sp
+The
+.CO E
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Set to the line containing the word selected.
+.SP Column:
+Set to the last character of the word selected.
+.SP Options:
+None.
+.SE
+.KY F
+.IP "[count] F <character>"
+Search
+.LI count
+times backward through the current line for
+.LI <character> .
+.sp
+The
+.CO F
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the searched-for character.
+.SP Options:
+None.
+.SE
+.KY G
+.IP "[count] G"
+Move to line
+.LI count ,
+or the last line of the file if
+.LI count
+not specified.
+.sp
+The
+.CO G
+command is an absolute movement.
+The
+.CO \&G
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.SS
+.SP Line:
+Set to
+.LI count ,
+if specified, otherwise, the last line.
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+None.
+.SE
+.KY H
+.IP "[count] H"
+Move to the screen line
+.LI "count - 1"
+lines below the top of the screen.
+.sp
+The
+.CO H
+command is an absolute movement.
+The
+.CO H
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.SS
+.SP Line:
+Set to the line
+.LI "count - 1"
+lines below the top of the screen.
+.SP Column:
+Set to the first nonblank character of the
+.i screen
+line.
+.SP Options:
+None.
+.SE
+.KY I
+.IP "[count] I"
+Enter input mode, inserting the text at the beginning of the line.
+If
+.LI count
+is specified, the text input is repeatedly input
+.LI "count - 1"
+more times.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+None.
+.SE
+.KY J
+.IP "[count] J"
+Join lines.
+If
+.LI count
+is specified,
+.LI count
+lines are joined; a minimum of two lines are always joined,
+regardless of the value of
+.LI count .
+.sp
+If the current line ends with a whitespace character, all whitespace
+is stripped from the next line.
+Otherwise, if the next line starts with a open parenthesis
+.PQ (
+do nothing.
+Otherwise, if the current line ends with a question mark
+.PQ ? ,
+period
+.PQ \&.
+or exclamation point
+.PQ ! ,
+insert two spaces.
+Otherwise, insert a single space.
+.sp
+It is not an error to join lines past the end of the file,
+i.e. lines that do not exist.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the character after the last character of the next-to-last
+joined line.
+.SP Options:
+None.
+.SE
+.KY L
+.IP "[count] L"
+Move to the screen line
+.LI "count - 1"
+lines above the bottom of the screen.
+.sp
+The
+.CO L
+command is an absolute movement.
+The
+.CO L
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.SS
+.SP Line:
+Set to the line
+.LI "count - 1"
+lines above the bottom of the screen.
+.SP Column:
+Set to the first nonblank character of the
+.i screen
+line.
+.SP Options:
+None.
+.SE
+.KY M
+.IP " M"
+Move to the screen line in the middle of the screen.
+.sp
+The
+.CO M
+command is an absolute movement.
+The
+.CO M
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.sp
+Historically, any
+.LI count
+specified to the
+.CO M
+command was ignored.
+.SS
+.SP Line:
+Set to the line in the middle of the screen.
+.SP Column:
+Set to the first nonblank character of the
+.i screen
+line.
+.SP Options:
+None.
+.SE
+.KY O
+.IP "[count] O"
+Enter input mode, appending text in a new line above the current line.
+If
+.LI count
+is specified, the text input is repeatedly input
+.LI "count - 1"
+more times.
+.sp
+Historically, any
+.LI count
+specified to the
+.CO O
+command was ignored.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY P
+.IP "[buffer] P"
+Insert text from a buffer.
+Text from the buffer (the unnamed buffer by default) is inserted
+before the current column or, if the buffer is line oriented,
+before the current line.
+.SS
+.SP Line:
+Set to the lowest numbered line insert,
+if the buffer is line oriented, otherwise unchanged.
+.SP Column:
+Set to the first nonblank character of the appended text,
+if the buffer is line oriented, otherwise, the last character
+of the appended text.
+.SP Options:
+None.
+.SE
+.KY Q
+.IP "Q"
+Exit
+.CO vi
+(or visual) mode and switch to
+.CO ex
+mode.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+No longer relevant.
+.SP Options:
+None.
+.SE
+.KY R
+.IP "[count] R"
+Enter input mode, replacing the characters in the current line.
+If
+.LI count
+is specified, the text input is repeatedly input
+.LI "count - 1"
+more times.
+.sp
+If the end of the current line is reached, no more characters are
+replaced and any further characters input are appended to the line.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY S
+.IP "[buffer] [count] S"
+Substitute
+.LI count
+lines.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY T
+.IP "[count] T <character>"
+Search backward,
+.LI count
+times,
+through the current line for the character
+.i after
+the specified
+.LI <character> .
+.sp
+The
+.CO T
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the character
+.i after
+the searched-for character.
+.SP Options:
+None.
+.SE
+.KY U
+.IP "U"
+Restore the current line to its state before the cursor last
+moved to it.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+The first character in the line.
+.SP Options:
+None.
+.SE
+.KY W
+.IP "[count] W"
+Move forward
+.LI count
+bigwords.
+Move the cursor forward to the beginning of a bigword by repeating the
+following algorithm: if the current position is within a bigword or the
+character at that position cannot be part of a bigword, move to the first
+character of the next bigword.
+If no subsequent bigword exists on the current line,
+move to the first character of the first bigword on the first following
+line that contains a bigword.
+.sp
+The
+.CO W
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+The line containing the word selected.
+.SP Column:
+The first character of the word selected.
+.SP Options:
+None.
+.SE
+.KY X
+.IP "[buffer] [count] X"
+Delete
+.LI count
+characters before the cursor.
+If the number of characters to be deleted is greater than or equal to
+the number of characters to the beginning of the line, all of the
+characters before the current cursor position, to the beginning of the
+line, are deleted.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the current character minus
+.LI count ,
+or the first character if count is greater than the number of
+characters in the line before the cursor.
+.SP Options:
+None.
+.SE
+.KY Y
+.IP "[buffer] [count] Y"
+Copy (or
+.QQ yank )
+.LI count
+lines into the specified buffer.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY ZZ
+.IP "ZZ"
+Write the file and exit
+.CO vi .
+The file is only written if it has been modified since the last
+complete write of the file to any file.
+.sp
+The
+.CO ZZ
+command will exit the editor after writing the file,
+if there are no further files to edit.
+Entering two
+.QQ quit
+commands (i.e.
+.CO wq ,
+.CO quit ,
+.CO xit
+or
+.CO ZZ )
+in a row will override this check and the editor will exit,
+ignoring any files that have not yet been edited.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY [[
+.IP "[count] [["
+Back up
+.LI count
+section boundaries.
+.sp
+The
+.CO [[
+command is an absolute movement.
+The
+.CO [[
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the starting position is column 0,
+in which case it is line oriented.
+.sp
+This is an error if the movement is past the beginning of the file.
+.SS
+.SP Line:
+Set to the previous line that is
+.LI count
+section boundaries back,
+or the first line of the file if no more section boundaries exist
+preceding the current line.
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+Affected by the
+.OP sections
+option.
+.SE
+.KY ]]
+.IP "[count] ]]"
+Move forward
+.LI count
+section boundaries.
+.sp
+The
+.CO ]]
+command is an absolute movement.
+The
+.CO ]]
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the starting position is column 0,
+in which case it is line oriented.
+.sp
+This is an error if the movement is past the end of the file.
+.SS
+.SP Line:
+Set to the line that is
+.LI count
+section boundaries forward,
+or to the last line of the file if no more section
+boundaries exist following the current line.
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+Affected by the
+.OP sections
+option.
+.SE
+.KY ^
+.IP "\&^"
+Move to first nonblank character on the current line.
+.sp
+The
+.CO ^
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the first nonblank character of the current line.
+.SP Options:
+None.
+.SE
+.KY _
+.IP "[count] _"
+Move down
+.LI "count - 1"
+lines, to the first nonblank character.
+The
+.CO _
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+line oriented.
+.sp
+It is not an error to execute the
+.CO _
+command when the cursor is on the first character in the line.
+.SS
+.SP Line:
+The current line plus
+.LI "count - 1" .
+.SP Column:
+The first nonblank character in the line.
+.SP Options:
+None.
+.SE
+.KY a
+.IP "[count] a"
+Enter input mode, appending the text after the cursor.
+If
+.LI count
+is specified, the text input is repeatedly input
+.LI "count - 1"
+more times.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY b
+.IP "[count] b"
+Move backward
+.LI count
+words.
+Move the cursor backward to the beginning of a word by repeating the
+following algorithm: if the current position is at the beginning of a word,
+move to the first character of the preceding word.
+Otherwise, the current position moves to the first character of the word
+at the current position.
+If no preceding word exists on the current line, move to the first
+character of the last word on the first preceding line that contains
+a word.
+.sp
+The
+.CO b
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Set to the line containing the word selected.
+.SP Column:
+Set to the first character of the word selected.
+.SP Options:
+None.
+.SE
+.KY c
+.IP "[buffer] [count] c motion"
+Change a region of text.
+If only part of a single line is affected, then the last character
+being changed is marked with a
+.QT $ .
+Otherwise, the region of text is deleted, and input mode is entered.
+.sp
+If
+.LI count
+is specified, it is applied to the
+.LI motion .
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY d
+.IP "[buffer] [count] d motion"
+Delete a region of text.
+If
+.LI count
+is specified, it is applied to the
+.LI motion .
+.SS
+.SP Line:
+Set to the line where the region starts.
+.SP Column:
+Set to the first character in the line after the last character in the
+region.
+If no such character exists, set to the last character before the region.
+.SP Options:
+None.
+.SE
+.KY e
+.IP "[count] e"
+Move forward
+.LI count
+end-of-words.
+Move the cursor forward to the end of a word by repeating the following
+algorithm: if the current position is the end of a word,
+move to the last character of the following word.
+Otherwise, move to the last character of the word at the current position.
+If no succeeding word exists on the current line, move to the last character
+of the first word on the next following line that contains a word.
+.sp
+The
+.CO e
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Set to the line containing the word selected.
+.SP Column:
+Set to the last character of the word selected.
+.SP Options:
+None.
+.SE
+.KY f
+.IP "[count] f <character>"
+Search forward,
+.LI count
+times, through the rest of the current line for
+.LI <character> .
+.sp
+The
+.CO f
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the searched-for character.
+.SP Options:
+None.
+.SE
+.KY i
+.IP "[count] i"
+Enter input mode, inserting the text before the cursor.
+If
+.LI count
+is specified, the text input is repeatedly input
+.LI "count - 1"
+more times.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY m
+.IP "m <character>"
+Save the current context (line and column) as
+.LI <character> .
+The exact position is referred to by
+.QT `<character> .
+The line is referred to by
+.QT '<character> .
+.sp
+Historically,
+.LI <character>
+was restricted to lower-case letters only,
+.CO nvi
+permits the use of any character.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Unchanged.
+.SP Options:
+None.
+.SE
+.KY o
+.IP "[count] o"
+Enter input mode, appending text in a new line under the current line.
+If
+.LI count
+is specified, the text input is repeatedly input
+.LI "count - 1"
+more times.
+.sp
+Historically, any
+.LI count
+specified to the
+.CO o
+command was ignored.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY p
+.IP "[buffer] p"
+Append text from a buffer.
+Text from the buffer (the unnamed buffer by default) is appended
+after the current column or, if the buffer is line oriented,
+after the current line.
+.SS
+.SP Line:
+Set to the first line appended, if the buffer is line oriented,
+otherwise unchanged.
+.SP Column:
+Set to the first nonblank character of the appended text if the buffer
+is line oriented, otherwise, the last character of the appended text.
+.SP Options:
+None.
+.SE
+.KY r
+.IP "[count] r <character>"
+Replace characters.
+The next
+.LI count
+characters in the line are replaced with
+.LI <character> .
+Replacing characters with
+.LI <newline>
+characters results in creating new, empty lines into the file.
+.sp
+If
+.LI <character>
+is
+.LI <escape> ,
+the command is cancelled.
+.SS
+.SP Line:
+Unchanged unless the replacement character is a
+.LI <newline> ,
+in which case it is set to the current line plus
+.LI "count - 1" .
+.SP Column:
+Set to the last character replaced,
+unless the replacement character is a
+.LI <newline> ,
+in which case the cursor is in column 1 of the last line inserted.
+.SP Options:
+None.
+.SE
+.KY s
+.IP "[buffer] [count] s"
+Substitute
+.LI count
+characters in the current line starting with the current character.
+.SS
+.SP Line:
+Set to the last line upon which characters were entered.
+.SP Column:
+Set to the last character entered.
+.SP Options:
+Affected by the
+.OP altwerase ,
+.OP autoindent ,
+.OP beautify ,
+.OP showmatch ,
+.OP ttywerase
+and
+.OP wrapmargin
+options.
+.SE
+.KY t
+.IP "[count] t <character>"
+Search forward,
+.LI count
+times, through the current line for the character immediately
+.i before
+.LI <character> .
+.sp
+The
+.CO t
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the character
+.i before
+the searched-for character.
+.SP Options:
+None.
+.SE
+.KY u
+.IP "u"
+Undo the last change made to the file.
+If repeated, the
+.CO u
+command alternates between these two states, and is its own inverse.
+When used after an insert that inserted text on more than one line,
+the lines are saved in the numeric buffers.
+.sp
+The
+.CO \&.
+command, when used immediately after the
+.CO u
+command, causes the change log to be rolled forward or backward,
+depending on the action of the
+.CO u
+command.
+.SS
+.SP Line:
+Set to the position of the first line changed, if the reversal affects
+only one line or represents an addition or change; otherwise, the line
+preceding the deleted text.
+.SP Column:
+Set to the cursor position before the change was made.
+.SP Options:
+None.
+.SE
+.KY w
+.IP "[count] w"
+Move forward
+.LI count
+words.
+Move the cursor forward to the beginning of a word by repeating the
+following algorithm: if the current position is at the
+beginning of a word, move to the first character of the next word.
+If no subsequent word exists on the current line, move to the first
+character of the first word on the first following line that contains
+a word.
+.sp
+The
+.CO w
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+.SS
+.SP Line:
+Set to the line containing the word selected.
+.SP Column:
+Set to the first character of the word selected.
+.SP Options:
+None.
+.SE
+.KY x
+.IP "[buffer] [count] x"
+Delete
+.LI count
+characters.
+The deletion is at the current character position.
+If the number of characters to be deleted is greater than or equal to
+the number of characters to the end of the line, all of the characters
+from the current cursor position to the end of the line are deleted.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Unchanged unless the last character in the line is deleted and the cursor
+is not already on the first character in the line, in which case it is
+set to the previous character.
+.SP Options:
+None.
+.SE
+.KY y
+.IP "[buffer] [count] y motion"
+Copy (or
+.QQ yank )
+a text region specified by the
+.LI count
+and motion into a buffer.
+If
+.LI count
+is specified, it is applied to the
+.LI motion .
+.SS
+.SP Line:
+Unchanged, unless the region covers more than a single line,
+in which case it is set to the line where the region starts.
+.SP Column:
+Unchanged, unless the region covers more than a single line,
+in which case it is set to the character were the region starts.
+.SP Options:
+None.
+.SE
+.KY z
+.IP "[count1] z [count2] type"
+Redraw the screen with a window
+.LI count2
+lines long, with line
+.LI count1
+placed as specified by the
+.LI type
+character.
+If
+.LI count1
+is not specified, it defaults to the current line.
+If
+.LI count2
+is not specified, it defaults to the current window size.
+.sp
+The following
+.LI type
+characters may be used:
+.SS
+.SP +
+If
+.LI count1
+is specified, place the line
+.LI count1
+at the top of the screen.
+Otherwise, display the screen after the current screen, similarly to the
+.CO <control-F>
+command.
+.SP <carriage-return>
+Place the line
+.LI count1
+at the top of the screen.
+.SP \&.
+Place the line
+.LI count1
+in the center of the screen.
+.SP \-
+Place the line
+.LI count1
+at the bottom of the screen.
+.SP ^
+If
+.LI count1
+is specified, place the line that is at the top of the screen
+when
+.LI count1
+is at the bottom of the screen, at the bottom of the screen,
+i.e. display the screen before the screen before
+.LI count1 .
+Otherwise, display the screen before the current screen, similarly to the
+.CO <control-B>
+command.
+.SE
+.SS
+.SP Line:
+Set to
+.LI count1
+unless
+.LI count1
+is not specified and the
+.LI type
+character was either
+.QT ^
+or
+.QT + ,
+in which case it is set to the line before the first line on the
+previous screen or the line after the last line on the previous
+screen, respectively.
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+None.
+.SE
+.KY {
+.IP "[count] {"
+Move backward
+.LI count
+paragraphs.
+.sp
+The
+.CO {
+command is an absolute movement.
+The
+.CO {
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the starting character is the first
+character on its line, in which case it is line oriented.
+.SS
+.SP Line:
+Set to the line containing the beginning of the previous paragraph.
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+Affected by the
+.OP paragraph
+option.
+.SE
+.KY |
+.IP "[count] |"
+Move to a specific
+.i column
+position on the current line.
+.sp
+The
+.CO |
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented.
+It is an error to use the
+.CO |
+command as a motion component and for the cursor not to move.
+.SS
+.SP Line:
+Unchanged.
+.SP Column:
+Set to the character occupying the column position identified by
+.LI count ,
+if the position exists in the line.
+If the column length of the current line is less than
+.LI count ,
+the cursor is moved to the last character in the line.
+.SP Options:
+None.
+.SE
+.KY }
+.IP "[count] }"
+Move forward
+.LI count
+paragraphs.
+.sp
+The
+.CO }
+command is an absolute movement.
+The
+.CO }
+command may be used as the motion component of other
+.CO vi
+commands, in which case any text copied into a buffer is
+character oriented, unless the starting character is at or
+before any nonblank characters in its line,
+in which case it is line oriented.
+.SS
+.SP Line:
+Set to the line containing the beginning of the next paragraph.
+.SP Column:
+Set to the first nonblank character in the line.
+.SP Options:
+Affected by the
+.OP paragraph
+option.
+.SE
+.KY ~
+.IP "[count] ~"
+Reverse the case of the next
+.LI count
+character(s).
+This is the historic semantic for the
+.CO ~
+command and it is only in effect if the
+.OP tildeop
+option is not set.
+.sp
+Lowercase alphabetic characters are changed to uppercase,
+and uppercase characters are changed to lowercase.
+No other characters are affected.
+.sp
+Historically, the
+.CO ~
+command did not take an associated count, nor did it move past the
+end of the current line.
+As it had no associated motion it was difficult to change the case
+of large blocks of text.
+In
+.CO nvi ,
+if the cursor is on the last character of a line, and there are
+more lines in the file, the cursor moves to the next line.
+.sp
+It is not an error to specify a count larger than the number of
+characters between the cursor and the end of the file.
+.SS
+.SP Line:
+Set to the line of the character after
+.LI count
+characters, or, end of file.
+.SP Column:
+Set to the character after
+.LI count
+characters, or, end-of-file.
+.SP Options:
+Affected by the
+.OP tildeop
+option.
+.SE
+.KY ~
+.IP "[count] ~ motion"
+Reverse the case of the characters in a text region specified by the
+.LI count
+and
+.LI motion .
+Only in effect if the
+.OP tildeop
+option is set.
+.sp
+Lowercase characters are changed to uppercase,
+and uppercase characters are changed to lowercase.
+No other characters are affected.
+.SS
+.SP Line:
+Set to the line of the character after the last character in the region.
+.SP Column:
+Set to the character after the last character in the region.
+.SP Options:
+Affected by the
+.OP tildeop
+option.
+.SE
+.KY <interrupt>
+.IP "<interrupt>"
+Interrupt the current operation.
+Many of the potentially long-running
+.CO vi
+commands may be interrupted using the terminal interrupt character.
+These operations include searches, file reading and writing, filter
+operations and map character expansion.
+Interrupts are also enabled when running commands outside of
+.CO vi .
+.sp
+If the
+.LI <interrupt>
+character is used to interrupt while entering an
+.CO ex
+command, the command is aborted, the cursor returns to its previous
+position, and
+.CO vi
+remains in command mode.
+.sp
+Generally, if the
+.LI <interrupt>
+character is used to interrupt any
+operation, any changes made before the interrupt are left in place.
+.SS
+.SP Line:
+Dependent on the operation being interrupted.
+.SP Column:
+Dependent on the operation being interrupted.
+.SP Options:
+None.
+.SH 1 "Vi Text Input Commands"
+.pp
+The following section describes the commands available in the text
+input mode of the
+.CO vi
+editor.
+.pp
+Historically,
+.CO vi
+implementations only permitted the characters inserted on the current
+line to be erased.
+In addition, only the
+.LI <control-D>
+erase character and the
+.QT 0<control-D>
+and
+.QT ^<control-D>
+erase strings could erase autoindent characters.
+This implementation permits erasure to continue past the beginning
+of the current line, and back to where text input mode was entered.
+In addition, autoindent characters may be erased using the standard
+erase characters.
+For the line and word erase characters, reaching the autoindent
+characters forms a
+.QQ soft
+boundary, denoting the end of the current word or line erase.
+Repeating the word or line erase key will erase the autoindent characters.
+.pp
+Historically,
+.CO vi
+always used
+.LI <control-H>
+and
+.LI <control-W>
+as character and word erase characters, respectively, regardless of
+the current terminal settings.
+This implementation accepts, in addition to these two characters,
+the current terminal characters for those operations.
+.KY <nul>
+.IP "<nul>"
+If the first character of the input is a
+.LI <nul> ,
+the previous input is replayed, as if just entered.
+.KY <control-D>
+.IP "<control-D>"
+If the previous character on the line was an autoindent character,
+erase it.
+Otherwise, if the user is entering the first character in the line,
+.LI <control-D>
+is ignored.
+Otherwise, a literal
+.LI <control-D>
+character is entered.
+.KY ^<control-D>
+.IP "^<control-D>"
+If the previous character on the line was an autoindent character,
+erase all of the autoindent characters on the line.
+In addition, the autoindent level is reset to 0.
+.KY 0<control-D>
+.IP "0<control-D>"
+If the previous character on the line was an autoindent character,
+erase all of the autoindent characters on the line.
+.KY <control-T>
+.IP "<control-T>"
+Insert sufficient
+.LI <tab>
+and
+.LI <space>
+characters to move the cursor forward to a column immediately
+after the next column which is an even multiple of the
+.OP shiftwidth
+option.
+.sp
+Historically,
+.CO vi
+did not permit the
+.LI <control-T>
+command to be used unless the cursor was at the first column of a new
+line or it was preceded only by autoindent characters.
+.CO Nvi
+permits it to be used at any time during insert mode.
+.KY <erase>
+.IP <erase>
+.KY <control-H>
+.Ip <control-H>
+Erase the last character.
+.KY "<literal next>"
+.IP "<literal next>"
+Quote the next character.
+The next character will not be mapped (see the
+.CO map
+command for more information)
+or interpreted specially.
+A carat
+.PQ ^
+character will be displayed immediately as a placeholder,
+but will be replaced by the next character.
+.KY <escape>
+.IP <escape>
+Resolve all text input into the file, and return to command mode.
+.KY "<line erase>"
+.IP "<line erase>"
+Erase the current line.
+.KY "<control-W>"
+.IP "<control-W>"
+.KY "<word erase>"
+.Ip "<word erase>"
+Erase the last word.
+The definition of word is dependent on the
+.OP altwerase
+and
+.OP ttywerase
+options.
+.KY "<control-X>"
+.IP "<control-X>[0-9A-Fa-f]*"
+Insert a character with the specified hexadecimal value into the text.
+.KY <interrupt>
+.IP "<interrupt>"
+Interrupt text input mode, returning to command mode.
+If the
+.LI <interrupt>
+character is used to interrupt inserting text into the file,
+it is as if the
+.LI <escape>
+character was used; all text input up to the interruption is
+resolved into the file.
diff --git a/usr.bin/vi/USD.doc/vi.ref/vi.ref b/usr.bin/vi/USD.doc/vi.ref/vi.ref
new file mode 100644
index 000000000000..5058cc780dd5
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/vi.ref
@@ -0,0 +1,1270 @@
+.\" 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.52 (Berkeley) 8/13/94
+.\"
+.\"
+.so ref.so
+.tp
+.(l C
+.ps 12
+.ft B
+Ex/Vi Reference Manual
+.ft
+.ps
+.sp
+.i "Keith Bostic"
+.sp
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, California 94720
+.sp 1
+\*(td
+.sp 3
+.i Abstract
+.sp
+.)l
+.(q
+.pp
+This document is the reference guide for the 4.4BSD
+implementations of
+.EV nex nvi ,
+which are reimplementations of the historic Berkeley
+.EV ex vi
+editors.
+.)q
+.sp 3
+.(l C
+.i Acknowledgements
+.)l
+.sp
+.(q
+.pp
+Bruce Englar encouraged the early development of the historic
+.EV ex vi
+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
+.EV ex vi
+work on a large number of terminals and Unix systems.
+.pp
+.CO Nvi
+is originally derived from software contributed to the University of
+California, Berkeley by Steve Kirkendall, the author of the
+.CO vi
+clone
+.CO elvis .
+.pp
+IEEE Standard Portable Operating System Interface for Computer
+Environments (POSIX) 1003.2 style Regular Expression support was
+done by Henry Spencer.
+.pp
+The curses library was originally done by Ken Arnold.
+Scrolling and reworking for
+.CO nvi
+was done by Elan Amir.
+.pp
+The Institute of Electrical and Electronics Engineers has
+given us permission to reprint portions of their documentation.
+Portions of this document are reprinted and reproduced from
+IEEE Std 1003.2-1992, IEEE Standard Portable Operating
+System Interface for Computer Environments (POSIX),
+copyright 1992 by the Institute of Electrical and Electronics
+Engineers, Inc.
+.pp
+The financial support of UUNET Communications Services is gratefully
+acknowledged.
+.)q
+.sy echo -n >index
+.oh 'Nvi/Nex Reference''USD:13-%'
+.eh 'USD:13-%''Nvi/Nex Reference'
+.bp 3
+.SH 1 Description
+.pp
+.CO Vi
+is a screen oriented text editor.
+.CO Ex
+is a line-oriented text editor.
+.CO Ex
+and
+.CO vi
+are different interfaces to the same program,
+and it is possible to switch back and forth during an edit session.
+.CO View
+is the equivalent of using the
+.b \-R
+(read-only) option of
+.CO vi .
+.pp
+This reference manual is the one provided with the
+.EV nex nvi
+versions of the
+.EV ex vi
+text editors.
+.EV Nex nvi
+are intended as bug-for-bug compatible replacements for the original
+Fourth Berkeley Software Distribution (4BSD)
+.EV ex vi
+programs.
+This reference manual is accompanied by a traditional-style manual page.
+That manual page describes the functionality found in
+.EV ex vi
+in far less detail than the description here.
+In addition, it describes the system interface to
+.EV ex vi ,
+e.g. command line options, session recovery, signals,
+environmental variables, and similar things.
+.pp
+This reference is intended for users already familiar with
+.EV ex vi .
+Anyone else should almost certainly read a good tutorial on the
+editor first.
+If you are in an unfamiliar environment,
+and you absolutely have to get work done immediately,
+see the section entitled
+.QB "Fast Startup"
+in the manual page.
+It is probably enough to get you started.
+.pp
+There are a few features in
+.EV nex nvi
+that are not found in historic versions of
+.EV ex vi .
+Some of the more interesting of those features are briefly described
+in the section entitled
+.QB "Additional Features"
+near the end of this document.
+For the rest of this document,
+.EV nex nvi
+is used only when it is necessary to distinguish it from the historic
+implementations of
+.EV ex vi .
+.pp
+Future versions of this software will be periodically made available
+by anonymous ftp, and can be retrieved from
+.LI ftp.cs.berkeley.edu ,
+in the directory
+.LI ucb/4bsd .
+.SH 1 "Startup Information"
+.pp
+.EV 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
+.CO ex
+commands, not
+.CO vi
+commands.
+In addition, they are interpreted
+.i before
+the file to be edited is read, and therefore many
+.CO 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
+Because the
+.CO ex
+command set supported by
+.EV nex nvi
+is a superset of the command set supported by most historical
+implementations of
+.CO ex ,
+.EV nex nvi
+can use the startup files created for the historical implementations,
+but the converse may not be true.
+.pp
+If the
+.b \-s
+(the historic \- option)
+is specified, or if standard input is redirected from a file,
+all environmental variables and startup files are ignored.
+.pp
+Otherwise, startup files and environmental variables are handled
+in the following order:
+.np
+The file
+.LI /etc/vi.exrc
+is read,
+as long as it is owned by root or the effective user ID of the user.
+.np
+The environmental variable
+.LI NEXINIT
+(or the variable
+.LI EXINIT ,
+if
+.LI NEXINIT
+is not set) is interpreted.
+.np
+If neither
+.LI NEXINIT
+or
+.LI EXINIT
+was set, and the
+.LI HOME
+environmental variable is set, the file
+.LI $HOME/.nexrc
+(or the file
+.LI $HOME/.exrc ,
+if
+.LI $HOME/.nexrc
+does not exist) is read,
+as long as the effective user ID of the user is root or is the same as
+the owner of the file.
+.np
+If the
+.OP exrc
+option was turned on by one of the previous startup information
+sources, the file
+.LI \&.nexrc
+(or the file
+.LI \&.exrc ,
+if
+.LI \&.nexrc
+does not exist) is read, as long as the effective user ID of the user
+is the same as the owner of the file.
+.pp
+No startup file is read if it is writable by anyone other than its owner.
+.pp
+It is not an error for any of the startup environmental variables or files
+not to exist.
+.pp
+Once all environmental variables are interpreted,
+and all startup files are read,
+the first file to be edited is read in (or a temporary file is created).
+Then, any commands specified using the
+.b \-c
+option are executed, in the context of that file.
+.SH 1 Recovery
+.pp
+There is no recovery program for
+.EV nex nvi ,
+nor does
+.EV nex nvi
+run setuid.
+Recovery files are created readable and writable by the owner only.
+Users may recover any file which they can read,
+and the superuser may recover any edit session.
+.pp
+Edit sessions are backed by files in the directory named by the
+.OP recdir
+option (the directory
+.LI /var/tmp/vi.recover
+by default), and are named
+.QC vi.XXXXXX ,
+where
+.QC XXXXXX
+is a number related to the process ID.
+When a file is first modified,
+a second recovery file containing an email message for the user is created,
+and is named
+.QC recover.XXXXXX ,
+where, again,
+.QC XXXXXX
+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 runs the
+.CO ex
+.CO preserve
+command.
+.pp
+The
+.OP recdir
+option may be set in either the user's or system's startup information,
+changing the recovery directory.
+(Note, however, that if a memory based file system is used as the backup
+directory, each system reboot will delete all of the recovery files!
+The same caution applies to directories such as
+.LI /tmp
+which are cleared of their contents by a system reboot, or
+.LI /usr/tmp
+which is periodically cleared of old files on many systems.)
+.pp
+The recovery directory should be owned by root, or at least by a pseudo-user.
+In addition, if directory
+.QQ sticky-bit
+semantics are available, the directory should have the sticky-bit
+set so that files may only be removed by their owners.
+The recovery directory must be read, write, and executable by any user,
+i.e. mode 1777.
+.pp
+If the recovery directory does not exist,
+.EV ex vi
+will attempt to create it.
+This can result in the recovery directory being owned by a normal user,
+which means that that user will be able to remove other user's recovery
+and backup files.
+This is annoying, but is not a security issue as the user cannot
+otherwise access or modify the files.
+.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
+.XR sendmail 8 .
+When the system is rebooted, all of the files in
+.LI /var/tmp/vi.recover
+named
+.QC recover.XXXXXX
+should be sent to their owners, by email, using the
+.b \-t
+option of
+.CO sendmail
+(or a similar mechanism in other mailers).
+If
+.EV ex vi
+receives a hangup (SIGHUP) signal, or the user executes the
+.CO ex
+.CO preserve
+command,
+.EV ex vi
+will automatically email the recovery information to the user.
+.pp
+If your system does not have the
+.CO sendmail
+utility (or a mailer program which supports its interface)
+the source file
+.LI nvi/common/recover.c
+will have to be modified to use your local mail delivery programs.
+Note, if
+.EV nex nvi
+is changed to use another mailer,
+it is important to remember that the owner of the file given to
+the mailer is the
+.EV nex nvi
+user, so nothing in the file should be trusted as it may have been
+modified in an effort to compromise the system.
+.pp
+Finally, the owner execute bit is set on backup files when they are
+created, and unset when they are first modified, e.g. backup files
+that have no associated email recovery file will have this bit set.
+(There is also a small window where empty files can be created and
+not yet have this bit set.
+This is due to the method in which the files are created.)
+Such files should be deleted when the system reboots.
+.pp
+A simple way to do this cleanup is to insert the following Bourne
+shell script into your
+.LI /etc/rc.local
+(or other startup) file.
+The script should work with the historic Bourne shell,
+a POSIX 1003.2 shell or the Korn shell.
+(A copy of this script is included as
+.LI nvi/install/recover.script
+in the
+.EV nex nvi
+distribution.)
+.sp
+.(b
+.ft C
+.so ../../install/recover.script
+.ft R
+.)b
+.sp
+.pp
+If you are not using the default value for the
+.OP recdir
+option, be sure to substitute the value you're using for the
+.LI RECDIR
+value in the recovery script.
+.pp
+If the path of your system's
+.CO sendmail
+program (or whatever mailer you're using) is not
+.LI /usr/lib/sendmail ,
+be sure to substitute the correct pathname for the
+.LI SENDMAIL
+value in the recovery script.
+Consult the manual page for details on recovering preserved or
+aborted editing sessions.
+.SH 1 "Sizing the Screen"
+.pp
+The size of the screen can be set in a number of ways.
+.EV Ex vi
+takes the following steps until values are obtained for both the
+number of rows and number of columns in the screen.
+.np
+If the environmental variable
+.LI LINES
+exists,
+it is used to specify the number of rows in the screen.
+.np
+If the environmental variable
+.LI COLUMNS
+exists,
+it is used to specify the number of columns in the screen.
+.np
+The TIOCGWINSZ
+.XR ioctl 2
+is attempted on the standard error file descriptor.
+.np
+The termcap entry (or terminfo entry on System V machines)
+is checked for the
+.QQ li
+entry (rows) and the
+.QQ co
+entry (columns).
+.np
+The number of rows is set to 24, and the number of columns is set to 80.
+.pp
+If a window change size signal (SIGWINCH) is received,
+the new window size is retrieved using the TIOCGWINSZ
+.XR ioctl 2
+call, and all other information is ignored.
+.SH 1 "Character Display"
+.pp
+In both
+.CO ex
+and
+.CO vi
+printable characters as defined by
+.XR isprint 3
+are displayed using the local character set.
+.pp
+Non-printable characters, for which
+.XR iscntrl 3
+returns true, and which are less than octal \e076,
+are displayed as the string
+.QT ^<character> ,
+where
+.LI <character>
+is the character that is the original character's value offset from the
+.QT @
+character.
+For example, the octal character \e001 is displayed as
+.QT ^A .
+If
+.XR iscntrl 3
+returns true for the octal character \e177,
+it is displayed as the string
+.QT ^? .
+All other characters are displayed as either hexadecimal values,
+in the form
+.QT "0x<high-halfbyte> ... 0x<low-halfbyte>" ,
+or as octal values, in the form
+.QT "\e<high-one-or-two-bits> ... \e<low-three-bits>" .
+The display of unknown characters is based on the value of the
+.OP octal
+option.
+.pp
+In
+.CO vi
+command mode, the cursor is always positioned on the last column of
+characters which take up more than one column on the screen.
+In
+.CO vi
+text input mode, the cursor is positioned on the first column of
+characters which take up more than one column on the screen.
+.SH 1 "Multiple Screens"
+.pp
+.CO Nvi
+supports multiple screens by dividing the window into regions.
+It also supports stacks of screens by permitting the user to change
+the set of screens that are currently displayed.
+.pp
+The command
+.CO split
+divides the current screen into two regions of approximately equal
+size.
+If a list of files are specified as arguments to the
+.CO split
+command, the list of files to be edited is initialized as if the
+.CO next
+command had been used.
+If no files are specified, the new screen will begin by editing the same
+file as the previous screen.
+.pp
+When more than one screen is editing a file, changes in any screen are
+reflected in all other screens editing the same file.
+Exiting any screen without saving any changes (or explicitly discarding
+them) is permitted until the last screen editing the file is exited.
+.pp
+The
+.CO resize
+command permits resizing of individual screens.
+Screens may be grown, shrunk or set to an absolute number of rows.
+.pp
+The
+.CO ^W
+command is used to switch between screens.
+Each
+.CO ^W
+moves to the next lower screen in the window, or to the first screen
+in the window if there are no lower screens.
+.pp
+The
+.CO bg
+command
+.QQ backgrounds
+the current screen.
+The screen disappears from the window,
+and the rows it occupied are taken over by a neighboring screen.
+It is an error to attempt to background the only screen in the window.
+.pp
+The
+.CO "display screens"
+command displays the names of the files associated with the current
+backgrounded screens in the window.
+.pp
+The
+.CO "fg [file]"
+command
+.QQ foregrounds
+the first screen in the list of backgrounded screens that is
+associated with its argument.
+If no file argument is specified, the first screen on the list is
+foregrounded.
+Foregrounding consists of backgrounding the current screen,
+and replacing its space in the window with the foregrounded screen.
+.pp
+If the last screen in the window is exited, and there are backgrounded
+screens, the first screen on the list of backgrounded screens takes over
+the window.
+.SH 1 "Regular Expressions and Replacement Strings"
+.pp
+Regular expressions are used in line addresses,
+as the first part of the
+.CO ex
+.CO substitute ,
+.CO global ,
+and
+.CO vglobal
+commands, and in search patterns.
+.pp
+The regular expressions supported by
+.EV ex vi
+are, by default, the Basic Regular Expressions (BRE's) described in the
+IEEE POSIX Standard 1003.2.
+The
+.OP 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 the Regular Expressions found in
+.XR ed 1
+and
+.XR grep 1 ,
+and ERE's are the Regular Expressions found in
+.XR egrep 1 .
+.pp
+The following is not intended to provide a description of Regular
+Expressions.
+The information here only describes strings and characters which
+have special meanings in the
+.EV ex vi
+version of RE's,
+or options which change the meanings of characters that normally
+have special meanings in RE's.
+.np
+An empty RE (e.g.
+.QT //
+or
+.QT ??
+is equivalent to the last RE used.
+.np
+The construct
+.QT \e<
+matches the beginning of a word.
+.np
+The construct
+.QT \e>
+matches the end of a word.
+.np
+The character
+.QT ~
+matches the replacement part of the last
+.CO substitute
+command.
+.pp
+When the
+.OP magic
+option is
+.i not
+set, the only characters with special meanings are a
+.QT ^
+character at the beginning of an RE, a
+.QT $
+character at the end of an RE, and the escaping character
+.QT \e .
+The characters
+.QT \&. ,
+.QT * ,
+.QT [
+and
+.QT ~
+are treated as ordinary characters unless preceded by a
+.QT \e ;
+when preceded by a
+.QT \e
+they regain their special meaning.
+.pp
+Replacement strings are the second part of a
+.CO substitute
+command.
+.pp
+The character
+.QT &
+(or
+.QT \e&
+if the
+.OP magic
+option is
+.i not
+set) in the replacement string stands for the text matched by the RE
+that is being replaced.
+The character
+.QT ~
+(or
+.QT \e~
+if the
+.OP magic
+option is
+.i not
+set) stands for the replacement part of the previous
+.CO substitute
+command.
+It is only valid after a
+.CO substitute
+command has been performed.
+.pp
+The string
+.QT \e# ,
+where
+.QT #
+is an integer value from 1 to 9, stands for the text matched by
+the portion of the RE enclosed in the
+.QT # 'th
+set of escaped parentheses, e.g.
+.QT \e(
+and
+.QT \e) .
+For example,
+.QT "s/abc\e(.*\e)def/\e1/"
+deletes the strings
+.QT abc
+and
+.QT def
+from the matched pattern.
+.pp
+The strings
+.QT \el ,
+.QT \eu ,
+.QT \eL
+and
+.QT \eU
+can be used to modify the case of elements in the replacement string.
+The string
+.QT \el
+causes the next character to be converted to lowercase;
+the string
+.QT \eu
+behaves similarly, but converts to uppercase
+(e.g.
+.LI s/abc/\eU&/
+replaces the string
+.LI abc
+with
+.LI ABC ).
+The strings
+.QT \eL
+causes characters up to the end of the string or the next occurrence
+of the strings
+.QT \ee
+or
+.QT \eE
+to be converted to lowercase;
+the string
+.QT \eU
+behaves similarly, but converts to uppercase.
+.pp
+If the entire replacement pattern is
+.QT % ,
+then the last replacement pattern is used again.
+.pp
+In
+.CO vi ,
+inserting a
+.LI <control-M>
+into the replacement string will cause
+the matched line to be split into two lines at that point.
+(The
+.LI <control-M>
+will be discarded.)
+.SH 1 "General Editor Description"
+.pp
+When
+.CO ex
+or
+.CO vi
+are executed,
+the text of a file is read (or a temporary file is created),
+and then all editing changes happen within the context of the
+copy of the file.
+.i "No changes affect the actual file until the file is written out" ,
+either using a write command or another command which is affected by the
+.OP autowrite
+option.
+.pp
+All files are locked (using the
+.XR flock 2
+or
+.XR fcntl 2
+interfaces) during the edit session,
+to avoid inadvertently making modifications to multiple copies of the file.
+If a lock cannot be obtained for a file because it is locked by another
+process, the edit session is read-only (as if the
+.OP readonly
+option or the
+.b \-R
+flag had been specified).
+If a lock cannot be obtained for other reasons, the edit session will
+continue, but the file status information
+(see the
+.CO <control-G>
+command) will reflect this fact.
+.pp
+Both
+.CO ex
+and
+.CO vi
+are modeful editors, i.e. they have two modes,
+.QQ command
+mode and
+.QQ "text input"
+mode.
+The former is intended to permit you to enter commands which modifies
+already existing text.
+The latter is intended to permit you to enter new text.
+When
+.CO ex
+first starts running, it is in command mode, and usually displays a prompt
+(see the
+.OP prompt
+option for more information).
+The prompt is a single colon
+.PQ :
+character.
+There are three commands that switch
+.CO ex
+into text input mode:
+.CO append ,
+.CO change
+and
+.CO insert .
+Once in input mode, entering a line containing only a single period
+.PQ \&.
+terminates text input mode and returns to command mode,
+where the prompt is redisplayed.
+.pp
+When
+.CO vi
+first starts running, it is in command mode as well.
+There are eleven commands that switch
+.CO vi
+into text input mode:
+.CO A ,
+.CO a ,
+.CO C ,
+.CO c ,
+.CO I ,
+.CO i ,
+.CO O ,
+.CO o ,
+.CO R ,
+.CO S
+and
+.CO s .
+Once in input mode, entering an
+.LI <escape>
+character terminates text input mode and returns to command mode.
+.pp
+The following words have special meanings in both the
+.CO ex
+and
+.CO vi
+command descriptions:
+.KY <interrupt>
+.IP <interrupt>
+The interrupt character is used to interrupt the current operation.
+Normally
+.LI <control-C> ,
+whatever character is set for the current terminal is used.
+.KY "<literal next>"
+.IP "<literal next>"
+The literal next character is used to escape the subsequent character
+from any special meaning.
+This character is always
+.LI <control-V> .
+If the terminal is not set up to do XON/XOFF flow control,
+then
+.LI <control-Q>
+is used to mean literal next as well.
+.KY "current pathname"
+.IP "current pathname"
+The pathname of the file currently being edited by vi.
+When the percent character
+.PQ %
+appears in a file name entered as part of an
+.CO ex
+command argument, it is replaced by the current pathname.
+(The
+.QT %
+character can be escaped by preceding it with a backslash.)
+.KY "alternate pathname"
+.IP "alternate pathname"
+The name of the last file name mentioned in an
+.CO ex
+command, or,
+the previous current pathname if the last file mentioned
+becomes the current file.
+When the hash mark character
+.PQ #
+appears in a file name entered as part of an
+.CO ex
+command argument, it is replaced by the alternate pathname.
+(The
+.QT #
+character can be escaped by preceding it with a backslash.)
+.KY buffer
+.IP buffer
+One of a number of named areas for saving copies of text.
+Commands that change or delete text can save the changed or deleted
+text into a specific buffer, for later use, if the command allows
+it (i.e. the
+.CO ex
+.CO change
+command cannot save the changed text in a named buffer).
+Buffers are named with a single character, preceded by a double quote,
+e.g.
+.LI """<character>" .
+Historic implementations of
+.EV ex vi
+limited
+.LI <character>
+to the alphanumeric characters;
+.EV nex nvi
+permits the use of any character.
+.sp
+Buffers named by uppercase characters are the same as buffers
+named by lowercase characters, e.g. the buffer named by the
+English character
+.QT A
+is the same as the buffer named by the character
+.QT a ,
+with the exception that, if the buffer contents are being changed (as
+with a text deletion or
+.CO vi
+.CO change
+command), the text is
+.i appended
+to the buffer, instead of replacing the current contents.
+.sp
+The buffers named by the numeric characters (in English,
+.QT 1
+through
+.QT 9 ),
+are special, in that if at least one line is changed or deleted in
+the file,
+(or a command changes or deletes a region that crosses a line boundary)
+a copy of the text is placed into the numeric buffer
+.QT 1 ,
+regardless of the user specifying another buffer in which to save it.
+Before this copy is done, the previous contents of buffer
+.QT 1
+are moved into buffer
+.QT 2 ,
+.QT 2
+into buffer
+.QT 3 ,
+and so on.
+The contents of buffer
+.QT 9
+are discarded.
+In
+.CO vi ,
+text may be explicitly stored into the numeric buffers.
+In this case, the buffer rotation described above occurs before the
+replacement of the buffer's contents.
+(Text cannot be explicitly stored into the numeric buffers in
+.CO ex
+because of ambiguities that this would cause in the
+.CO ex
+command syntax.)
+.sp
+When a
+.CO vi
+command synopsis shows both a
+.LI [buffer]
+and a
+.LI [count] ,
+they may be presented in any order.
+.sp
+Finally, all buffers are either
+.QQ line
+or
+.QQ character
+oriented.
+All
+.CO ex
+commands which store text into buffers are line oriented.
+Some
+.CO vi
+commands which store text into buffers are line oriented,
+and some are character oriented; the description for each applicable
+.CO vi
+command notes whether text copied into buffers using the command
+is line or character oriented.
+In addition, the
+.CO vi
+command
+.CO "display buffers"
+displays the current orientation for each buffer.
+Generally, the only importance attached to this orientation is that
+if the buffer is subsequently inserted into the text, line oriented
+buffers create new lines for each of the lines they contain, and
+character oriented buffers create new lines for any lines
+.i other
+than the first and last lines they contain.
+The first and last lines are inserted into the text at the current
+cursor position, becoming part of the current line.
+If there is more than one line in the buffer, however, the current
+line itself will be split.
+.KY "unnamed buffer"
+.IP "unnamed buffer"
+The unnamed buffer is a text storage area which is used by commands
+that take a buffer as an argument, when no buffer is specified by
+the user.
+There is no way to explicitly reference this buffer.
+.oh 'Nvi/Nex Reference (Vi Commands)''USD:13-%'
+.eh 'USD:13-%''Nvi/Nex Reference (Vi Commands)'
+.so vi.cmd.roff
+.oh 'Nvi/Nex Reference''USD:13-%'
+.eh 'USD:13-%''Nvi/Nex Reference'
+.SH 1 "Ex Addressing"
+.pp
+Addressing in
+.CO ex
+(and when
+.CO ex
+commands are executed from
+.CO vi )
+relates to the current line.
+In general, the current line is the last line affected by a command.
+The exact effect on the current line is discussed under the description
+of each command.
+When the file contains no lines, the current line is zero.
+.pp
+Addresses are constructed by one or more of the following methods:
+.np
+The address
+.QT \&.
+refers to the current line.
+.np
+The address
+.QT $
+refers to the last line of the file.
+.np
+The address
+.QT N ,
+where
+.LI N
+is a positive number, refers to the N-th line of the file.
+.np
+The address
+.QT '<character>
+or
+.QT `<character>
+refers to the line marked with the name
+.LI <character> .
+(See the
+.CO k
+or
+.CO m
+commands for more information on how to mark lines.)
+.np
+A regular expression (RE) enclosed by slashes
+.PQ /
+is an address,
+and it refers to the first line found by searching forward from the line
+.i after
+the current line toward the end of the file, and stopping at the
+first line containing a string matching the RE.
+(The trailing slash can be omitted at the end of the command line.)
+.sp
+If no RE is specified, i.e. the pattern is
+.QT // ,
+the last RE used in any command is used in the search.
+.sp
+If the
+.OP extended
+option is set, the RE is handled as an extended RE, not a basic RE.
+If the
+.OP wrapscan
+option is set, the search wraps around to the beginning of the file
+and continues up to and including the current line, so that the entire
+file is searched.
+.sp
+The form
+.QT \e/
+is accepted for historic reasons,
+and is identical to
+.QT // .
+.np
+An RE enclosed in question marks
+.PQ ?
+addresses the first line found by searching backward from the line
+.i preceding
+the current line, toward the beginning of the file and stopping at the
+first line containing a string matching the RE.
+(The trailing question mark can be omitted at the end of a command line.)
+.sp
+If no RE is specified, i.e. the pattern is
+.QT ?? ,
+the last RE used in any command is used in the search.
+.sp
+If the
+.OP extended
+option is set, the RE is handled as an extended RE, not a basic RE.
+If the
+.OP wrapscan
+option is set, the search wraps around from the beginning of the file to
+the end of the file and continues up to and including the current line,
+so that the entire file is searched.
+.sp
+The form
+.QT \e?
+is accepted for historic reasons, and is identical to
+.QT ?? .
+.np
+An address followed by a plus sign
+.PQ +
+or a minus sign
+.PQ -
+followed by a number is an offset address and refers to the address
+plus (or minus) the indicated number of lines.
+If the address is omitted, the addition or subtraction is done with
+respect to the current line.
+.np
+An address of
+.QT +
+or
+.QT \-
+followed by a number is an offset from the current line.
+For example,
+.QT \-5
+is the same as
+.QT \&.\-5 .
+.np
+An address ending with
+.QT +
+or
+.QT -
+has 1 added to or subtracted from the address, respectively.
+As a consequence of this rule and of the previous rule, the address
+.QT \-
+refers to the line preceding the current line.
+Moreover, trailing
+.QT +
+and
+.QT \-
+characters have a cumulative effect.
+For example,
+.QT ++\-++
+refers to the current line plus 3.
+.np
+A percent sign
+.PQ %
+is equivalent to the address range
+.QT 1,$ .
+.pp
+.CO Ex
+commands require zero, one, or two addresses.
+It is an error to specify an address to a command which requires zero
+addresses.
+.pp
+If the user provides more than the expected number of addresses to any
+.CO ex
+command, the first addresses specified are discarded.
+For example,
+.QT 1,2,3,5 print
+prints lines 3 through 5, because the
+.CO print
+command only takes two addresses.
+.pp
+The addresses in a range are separated from each other by a comma
+.PQ ,
+or a semicolon
+.PQ ; .
+In the latter case, the current line
+.PQ \&.
+is set to the first address, and only then is the second address calculated.
+This feature can be used to determine the starting line for forward and
+backward searches (see rules (5) and (6) above).
+The second address of any two-address sequence corresponds to a line that
+follows, in the file, the line corresponding to the first address.
+The first address must be less than or equal to the second address.
+The first address must be greater than or equal to the first line of the
+file, and the last address must be less than or equal to the last line
+of the file.
+.oh 'Nvi/Nex Reference (Ex Commands)''USD:13-%'
+.eh 'USD:13-%''Nvi/Nex Reference (Ex Commands)'
+.so ex.cmd.roff
+.oh 'Nvi/Nex Reference''USD:13-%'
+.eh 'USD:13-%''Nvi/Nex Reference'
+.so set.opt.roff
+.SH 1 "Additional Features in Nex/Nvi"
+.pp
+There are a few features in
+.EV nex nvi
+that are not found in historic versions of
+.EV ex vi .
+Some of the more interesting of those features are as follows:
+.IP "8-bit clean data, large lines, files"
+.EV Nex nvi
+will edit any format file.
+Line lengths are limited by available memory,
+and file sizes are limited by available disk space.
+The
+.CO vi
+text input mode command
+.CO <control-X>
+can insert any possible character value into the text.
+.IP "Split screens"
+The
+.CO split
+command divides the screen into multiple editing regions.
+The
+.CO <control-W>
+command rotates between the foreground screens.
+The
+.CO resize
+command can be used to grow or shrink a particular screen.
+.IP "Background and foreground screens"
+The
+.CO bg
+command backgrounds the current screen, and the
+.CO fg
+command foregrounds backgrounded screens.
+The
+.CO display
+command can be used to list the background screens.
+.\".IP "Shell screens"
+.\"The
+.\".CO ":sc[ript] [file ...]"
+.\"command runs a shell in the screen.
+.\"Editing is unchanged, with the exception that a \fC<carriage-return>\fP
+.\"enters the current line (stripped of any prompt) as input to the
+.\"shell.
+.IP "Tag stacks"
+Tags are now maintained in a stack.
+The
+.CO <control-T>
+command returns to the previous tag location.
+The
+.CO tagpop
+command 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 a specified file.
+The
+.CO display
+command can be used to list the tags stack.
+The
+.CO tagtop
+command returns to the top of the tag stack.
+.IP "New displays"
+The
+.CO display
+command can be used to display the current buffers, the backgrounded
+screens, and the tags stack.
+.IP "Infinite undo"
+Changes made during an edit session may be rolled backward and forward.
+A
+.CO \&.
+command immediately after a
+.CO u
+command continues either forward or backward depending on whether the
+.CO u
+command was an undo or a redo.
+.IP "Usage information"
+The
+.CO exusage
+and
+.CO viusage
+commands provide usage information for all of the
+.CO ex
+and
+.CO vi
+commands by default, or, optionally, for a specific command or key.
+.IP "Extended Regular Expressions"
+The
+.CO extended
+option causes Regular Expressions to be interpreted as as Extended
+Regular Expressions, (i.e. \fIegrep\fP(1) style Regular Expressions).
+.IP "Word search"
+The
+.CO <control-A>
+command searches for the word referenced by the cursor.
+.IP "Number increment"
+The
+.CO \&#
+command increments or decrements the number referenced by the cursor.
+.IP "Previous file"
+The
+.CO previous
+command edits the previous file from the argument list.
+.IP "Left-right scrolling"
+The
+.CO leftright
+option causes
+.CO nvi
+to do left-right screen scrolling, instead of the traditional
+.CO vi
+line wrapping.
+.bp
+.SH 1 Index
+.lp
+.2c +0.5i 3
+.ta \n($luR
+.nf
+.so index.so
+.fi
+.bp 2
+.1c
+.ce 1
+\fB\s+2Table of Contents\s0\fP
+.sp
+.xp
diff --git a/usr.bin/vi/USD.doc/vi.ref/vi.ref.txt b/usr.bin/vi/USD.doc/vi.ref/vi.ref.txt
new file mode 100644
index 000000000000..88a98c772989
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vi.ref/vi.ref.txt
@@ -0,0 +1,5544 @@
+
+
+
+
+
+
+
+
+ EExx//VVii RReeffeerreennccee MMaannuuaall
+
+ _K_e_i_t_h _B_o_s_t_i_c
+
+ Computer Science Division
+ Department of Electrical Engineering and Computer Science
+ University of California, Berkeley
+ Berkeley, California 94720
+
+ August 15, 1994
+
+
+
+ _A_b_s_t_r_a_c_t
+
+
+
+
+ This document is the reference guide for the 4.4BSD
+implementations of nneexx/nnvvii, which are reimplementations
+of the historic Berkeley eexx/vvii editors.
+
+
+
+
+
+ _A_c_k_n_o_w_l_e_d_g_e_m_e_n_t_s
+
+
+
+
+ Bruce Englar encouraged the early development of
+the historic eexx/vvii 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 frame-
+work that users see in the present editor. Mark Horton
+added macros and other features and made eexx/vvii work on a
+large number of terminals and Unix systems.
+
+ NNvvii is originally derived from software contributed
+to the University of California, Berkeley by Steve Kirk-
+endall, the author of the vvii clone eellvviiss.
+
+ IEEE Standard Portable Operating System Interface
+for Computer Environments (POSIX) 1003.2 style Regular
+Expression support was done by Henry Spencer.
+
+ The curses library was originally done by Ken
+Arnold. Scrolling and reworking for nnvvii was done by
+Elan Amir.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The Institute of Electrical and Electronics Engi-
+neers has given us permission to reprint portions of
+their documentation. Portions of this document are
+reprinted and reproduced from IEEE Std 1003.2-1992, IEEE
+Standard Portable Operating System Interface for Comput-
+er Environments (POSIX), copyright 1992 by the Institute
+of Electrical and Electronics Engineers, Inc.
+
+ The financial support of UUNET Communications Ser-
+vices is gratefully acknowledged.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--33
+
+
+11.. 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 possible to switch back and
+forth during an edit session. VViieeww is the equivalent 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/vvii
+programs. This reference manual is accompanied by a tradi-
+tional-style manual page. That manual page describes the
+functionality 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, session
+recovery, signals, 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 are in an unfamiliar
+environment, and you absolutely have to get work done imme-
+diately, see the section entitled "FFaasstt SSttaarrttuupp" in the man-
+ual page. It is probably enough to get you started.
+
+ There are a few features in nneexx/nnvvii that are not found
+in historic versions of eexx/vvii. Some of the more interesting
+of those features are briefly described in the section enti-
+tled "AAddddiittiioonnaall FFeeaattuurreess" near the end of this document.
+For the rest of this document, nneexx/nnvvii is used only when it
+is necessary to distinguish it from the historic implementa-
+tions of eexx/vvii.
+
+ Future versions of this software will be periodically
+made available by anonymous ftp, and can be retrieved from
+ffttpp..ccss..bbeerrkkeelleeyy..eedduu, in the directory uuccbb//44bbssdd.
+
+22.. SSttaarrttuupp IInnffoorrmmaattiioonn
+
+ EExx/vvii interprets one of two possible environmental
+variables and reads up to three of five possible files dur-
+ing startup. The variables and files are expected to con-
+tain eexx commands, not vvii commands. In addition, they are
+interpreted _b_e_f_o_r_e the file to be edited is read, and there-
+fore many eexx commands may not be used. Generally, any com-
+mand 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.
+
+ Because the eexx command set supported by nneexx/nnvvii is a
+superset of the command set supported by most historical
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--44 NNvvii//NNeexx RReeffeerreennccee
+
+
+implementations of eexx, nneexx/nnvvii can use the startup files
+created for the historical implementations, but the converse
+may not be true.
+
+ If the --ss (the historic - option) is specified, or if
+standard input is redirected from a file, all environmental
+variables and startup files are ignored.
+
+ Otherwise, startup files and environmental variables
+are handled in the following order:
+
+ (1) The file //eettcc//vvii..eexxrrcc is read, as long as it is owned
+ by root or the effective user ID of the user.
+
+ (2) The environmental variable NNEEXXIINNIITT (or the variable
+ EEXXIINNIITT, if NNEEXXIINNIITT is not set) is interpreted.
+
+ (3) If neither NNEEXXIINNIITT or EEXXIINNIITT was set, and the HHOOMMEE
+ environmental variable is set, the file $$HHOOMMEE//..nneexxrrcc
+ (or the file $$HHOOMMEE//..eexxrrcc, if $$HHOOMMEE//..nneexxrrcc does not
+ exist) is read, as long as the effective user ID of
+ the user is root or is the same as the owner of the
+ file.
+
+ (4) If the eexxrrcc option was turned on by one of the previ-
+ ous startup information sources, the file ..nneexxrrcc (or
+ the file ..eexxrrcc, if ..nneexxrrcc does not exist) is read, as
+ long as the effective user ID of the user is the same
+ as the owner of the file.
+
+ No startup file is read if it is writable by anyone
+other than its owner.
+
+ It is not an error for any of the startup environmental
+variables or files not to exist.
+
+ Once all environmental variables are interpreted, and
+all startup files are read, the first file to be edited is
+read in (or a temporary file is created). Then, any com-
+mands specified using the --cc option are executed, in the
+context of that file.
+
+33.. RReeccoovveerryy
+
+ There is no recovery program for nneexx/nnvvii, nor does
+nneexx/nnvvii run setuid. Recovery files are created readable and
+writable by the owner only. Users may recover any file
+which they can read, and the superuser may recover any edit
+session.
+
+ Edit sessions are backed by files in the directory
+named by the rreeccddiirr option (the directory
+//vvaarr//ttmmpp//vvii..rreeccoovveerr by default), and are named "vvii..XXXXXXXXXXXX",
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--55
+
+
+where "XXXXXXXXXXXX" is a number related to the process ID. When
+a file is first modified, a second recovery file containing
+an email message for the user is created, and is named
+"rreeccoovveerr..XXXXXXXXXXXX", where, again, "XXXXXXXXXXXX" is associated with
+the process ID. Both files are removed at the end of a nor-
+mal edit session, but will remain if the edit session is
+abnormally terminated or the user runs the eexx pprreesseerrvvee com-
+mand.
+
+ The rreeccddiirr option may be set in either the user's or
+system's startup information, changing the recovery direc-
+tory. (Note, however, that if a memory based file system is
+used as the backup directory, each system reboot will delete
+all of the recovery files! The same caution applies to
+directories such as //ttmmpp which are cleared of their contents
+by a system reboot, or //uussrr//ttmmpp which is periodically
+cleared of old files on many systems.)
+
+ The recovery directory should be owned by root, or at
+least by a pseudo-user. In addition, if directory "sticky-
+bit" semantics are available, the directory should have the
+sticky-bit set so that files may only be removed by their
+owners. The recovery directory must be read, write, and
+executable by any user, i.e. mode 1777.
+
+ If the recovery directory does not exist, eexx/vvii will
+attempt to create it. This can result in the recovery
+directory being owned by a normal user, which means that
+that user will be able to remove other user's recovery and
+backup files. This is annoying, but is not a security issue
+as the user cannot otherwise access or modify the files.
+
+ 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
+_s_e_n_d_m_a_i_l(8). When the system is rebooted, all of the files
+in //vvaarr//ttmmpp//vvii..rreeccoovveerr named "rreeccoovveerr..XXXXXXXXXXXX" should be sent
+to their owners, by email, using the --tt option of sseennddmmaaiill
+(or a similar mechanism in other mailers). If eexx/vvii
+receives a hangup (SIGHUP) signal, or the user executes the
+eexx pprreesseerrvvee command, eexx/vvii will automatically email the
+recovery information to the user.
+
+ If your system does not have the sseennddmmaaiill utility (or a
+mailer program which supports its interface) the source file
+nnvvii//ccoommmmoonn//rreeccoovveerr..cc will have to be modified to use your
+local mail delivery programs. Note, if nneexx/nnvvii is changed
+to use another mailer, it is important to remember that the
+owner of the file given to the mailer is the nneexx/nnvvii user,
+so nothing in the file should be trusted as it may have been
+modified in an effort to compromise the system.
+
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--66 NNvvii//NNeexx RReeffeerreennccee
+
+
+ Finally, the owner execute bit is set on backup files
+when they are created, and unset when they are first modi-
+fied, e.g. backup files that have no associated email recov-
+ery file will have this bit set. (There is also a small
+window where empty files can be created and not yet have
+this bit set. This is due to the method in which the files
+are created.) Such files should be deleted when the system
+reboots.
+
+ A simple way to do this cleanup is to insert the fol-
+lowing Bourne shell script into your //eettcc//rrcc..llooccaall (or other
+startup) file. The script should work with the historic
+Bourne shell, a POSIX 1003.2 shell or the Korn shell. (A
+copy of this script is included as
+nnvvii//iinnssttaallll//rreeccoovveerr..ssccrriipptt in the nneexx/nnvvii distribution.)
+
+
+ ## @@((##))rreeccoovveerr..ssccrriipptt 88..44 ((BBeerrkkeelleeyy)) 88//1133//9944
+ ##
+ ## RReeccoovveerr nnvvii eeddiittoorr ffiilleess::
+ RREECCDDIIRR==//vvaarr//ttmmpp//vvii..rreeccoovveerr
+ SSEENNDDMMAAIILL==//uussrr//lliibb//sseennddmmaaiill
+ eecchhoo ''RReeccoovveerriinngg nnvvii eeddiittoorr sseessssiioonnss..''
+
+ ## UUnnmmooddiiffiieedd nnvvii eeddiittoorr bbaacckkuupp ffiilleess aarree eeiitthheerr zzeerroo lleennggtthh oorr
+ ## hhaavvee tthhee eexxeeccuuttee bbiitt sseett.. DDeelleettee bbootthh ccaasseess..
+ vviibbaacckkuupp==``eecchhoo $$RREECCDDIIRR//vvii..**``
+ iiff [[ ""$$vviibbaacckkuupp"" !!== ""$$RREECCDDIIRR//vvii..**"" ]];; tthheenn
+ ffoorr ii iinn $$vviibbaacckkuupp;; ddoo
+ iiff tteesstt --xx $$ii --oo !! --ss $$ii;; tthheenn
+ rrmm $$ii
+ ffii
+ ddoonnee
+ ffii
+
+ ## IItt iiss ppoossssiibbllee ttoo ggeett iinnccoommpplleettee rreeccoovveerryy ffiilleess,, iiff tthhee eeddiittoorr
+ ## ccrraasshheess aatt tthhee rriigghhtt ttiimmee.. DDeelleettee aannyy rreeccoovveerryy ffiilleess wwiitthhoouutt
+ ## ccoorrrreessppoonnddiinngg bbaacckkuupp ffiilleess,, ootthheerrwwiissee sseenndd mmaaiill ttoo tthhee uusseerr..
+ vviirreeccoovveerryy==``eecchhoo $$RREECCDDIIRR//rreeccoovveerr..**``
+ iiff [[ ""$$vviirreeccoovveerryy"" !!== ""$$RREECCDDIIRR//rreeccoovveerr..**"" ]];; tthheenn
+ ffoorr ii iinn $$vviirreeccoovveerryy;; ddoo
+ rreeccffiillee==``aawwkk ''//^^XX--vvii--rreeccoovveerr--ppaatthh:://{{pprriinntt $$22}}'' << $$ii``
+ iiff tteesstt !! --nn $$rreeccffiillee --aa --ss $$rreeccffiillee;; tthheenn
+ $$SSEENNDDMMAAIILL --tt << $$ii
+ eellssee
+ rrmm $$ii
+ ffii
+ ddoonnee
+ ffii
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--77
+
+
+ If you are not using the default value for the rreeccddiirr
+option, be sure to substitute the value you're using for the
+RREECCDDIIRR value in the recovery script.
+
+ If the path of your system's sseennddmmaaiill program (or what-
+ever mailer you're using) is not //uussrr//lliibb//sseennddmmaaiill, be sure
+to substitute the correct pathname for the SSEENNDDMMAAIILL value in
+the recovery script. Consult the manual page for details on
+recovering preserved or aborted editing sessions.
+
+44.. 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 LLIINNEESS exists, it is
+ used to specify the number of rows in the screen.
+
+ (2) If the environmental variable CCOOLLUUMMNNSS exists, it is
+ used to specify the number of columns in the screen.
+
+ (3) The TIOCGWINSZ _i_o_c_t_l(2) is attempted on the standard
+ error file descriptor.
+
+ (4) The termcap entry (or terminfo entry on System V
+ machines) 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 new window size is retrieved using the TIOCGWINSZ
+_i_o_c_t_l(2) call, and all other information is ignored.
+
+55.. CChhaarraacctteerr DDiissppllaayy
+
+ In both eexx and vvii printable characters as defined by
+_i_s_p_r_i_n_t(3) are displayed using the local character set.
+
+ Non-printable characters, for which _i_s_c_n_t_r_l(3) returns
+true, and which are less than octal \076, are displayed as
+the string "^^<<cchhaarraacctteerr>>", where <<cchhaarraacctteerr>> is the charac-
+ter that is the original character's value offset from the
+"@@" character. For example, the octal character \001 is
+displayed as "^^AA". If _i_s_c_n_t_r_l(3) returns true for the octal
+character \177, it is displayed as the string "^^??". All
+other characters are displayed as either hexadecimal values,
+in the form "00xx<<hhiigghh--hhaallffbbyyttee>> ...... 00xx<<llooww--hhaallffbbyyttee>>", or as
+octal values, in the form "\\<<hhiigghh--oonnee--oorr--ttwwoo--bbiittss>> ......
+\\<<llooww--tthhrreeee--bbiittss>>". The display of unknown characters is
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--88 NNvvii//NNeexx RReeffeerreennccee
+
+
+based on the value of the ooccttaall option.
+
+ In vvii command mode, the cursor is always positioned on
+the last column of characters which take up more than one
+column on the screen. In vvii text input mode, the cursor is
+positioned on the first column of characters which take up
+more than one column on the screen.
+
+66.. MMuullttiippllee SSccrreeeennss
+
+ NNvvii supports multiple screens by dividing the window
+into regions. It also supports stacks of screens by permit-
+ting the user to change the set of screens that are cur-
+rently displayed.
+
+ The command sspplliitt divides the current screen into two
+regions of approximately equal size. If a list of files are
+specified as arguments to the sspplliitt command, the list of
+files to be edited is initialized as if the nneexxtt command had
+been used. If no files are specified, the new screen will
+begin by editing the same file as the previous screen.
+
+ When more than one screen is editing a file, changes in
+any screen are reflected in all other screens editing the
+same file. Exiting any screen without saving any changes
+(or explicitly discarding them) is permitted until the last
+screen editing the file is exited.
+
+ The rreessiizzee command permits resizing of individual
+screens. Screens may be grown, shrunk or set to an absolute
+number of rows.
+
+ The ^^WW command is used to switch between screens. Each
+^^WW moves to the next lower screen in the window, or to the
+first screen in the window if there are no lower screens.
+
+ The bbgg command "backgrounds" the current screen. The
+screen disappears from the window, and the rows it occupied
+are taken over by a neighboring screen. It is an error to
+attempt to background the only screen in the window.
+
+ The ddiissppllaayy ssccrreeeennss command displays the names of the
+files associated with the current backgrounded screens in
+the window.
+
+ The ffgg [[ffiillee]] command "foregrounds" the first screen in
+the list of backgrounded screens that is associated with its
+argument. If no file argument is specified, the first
+screen on the list is foregrounded. Foregrounding consists
+of backgrounding the current screen, and replacing its space
+in the window with the foregrounded screen.
+
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--99
+
+
+ If the last screen in the window is exited, and there
+are backgrounded screens, the first screen on the list of
+backgrounded screens takes over the window.
+
+77.. RReegguullaarr EExxpprreessssiioonnss aanndd RReeppllaacceemmeenntt SSttrriinnggss
+
+ Regular expressions are used in line addresses, as the
+first part of the eexx ssuubbssttiittuuttee, gglloobbaall, and vvgglloobbaall com-
+mands, and in search patterns.
+
+ The regular expressions supported by eexx/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 _r_e___f_o_r_m_a_t(7) for more information.) Generally speak-
+ing, BRE's are the Regular Expressions found in _e_d(1) and
+_g_r_e_p(1), and ERE's are the Regular Expressions found in
+_e_g_r_e_p(1).
+
+ The following is not intended to provide a description
+of Regular Expressions. The information here only describes
+strings and characters which have special meanings in the
+eexx/vvii version of RE's, or options which change the meanings
+of characters that normally have special meanings in RE's.
+
+ (1) An empty RE (e.g. "////" or "????" 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 meanings are a "^^" character at the beginning
+of an RE, a "$$" character 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 mean-
+ing.
+
+ Replacement strings are the second part of a ssuubbssttiittuuttee
+command.
+
+ The character "&&" (or "\\&&" if the mmaaggiicc option is _n_o_t
+set) in the replacement string stands for the text matched
+by the RE that is being replaced. The character "~~" (or
+"\\~~" if the mmaaggiicc option is _n_o_t set) stands for the replace-
+ment part of the previous ssuubbssttiittuuttee command. It is only
+valid after a ssuubbssttiittuuttee command has been performed.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--1100 NNvvii//NNeexx RReeffeerreennccee
+
+
+ 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, "ss//aabbcc\\((..**\\))ddeeff//\\11//" deletes
+the strings "aabbcc" and "ddeeff" from the matched pattern.
+
+ The strings "\\ll", "\\uu", "\\LL" and "\\UU" can be used to
+modify the case of elements in the replacement string. The
+string "\\ll" causes the next character to be converted to
+lowercase; the string "\\uu" behaves similarly, but converts
+to uppercase (e.g. ss//aabbcc//\\UU&&// replaces the string aabbcc with
+AABBCC). The strings "\\LL" causes characters up to the end of
+the string or the next occurrence of the strings "\\ee" or
+"\\EE" to be converted to lowercase; the string "\\UU" behaves
+similarly, but converts to uppercase.
+
+ If the entire replacement pattern is "%%", then the last
+replacement pattern is used again.
+
+ In vvii, inserting a <<ccoonnttrrooll--MM>> into the replacement
+string will cause the matched line to be split into two
+lines at that point. (The <<ccoonnttrrooll--MM>> will be discarded.)
+
+88.. GGeenneerraall EEddiittoorr DDeessccrriippttiioonn
+
+ When eexx or vvii are executed, the text of a file is read
+(or a temporary file is created), and then all editing
+changes happen within the context of the copy of the file.
+_N_o _c_h_a_n_g_e_s _a_f_f_e_c_t _t_h_e _a_c_t_u_a_l _f_i_l_e _u_n_t_i_l _t_h_e _f_i_l_e _i_s _w_r_i_t_t_e_n
+_o_u_t, either using a write command or another command which
+is affected by the aauuttoowwrriittee option.
+
+ All files are locked (using the _f_l_o_c_k(2) or _f_c_n_t_l(2)
+interfaces) during the edit session, to avoid inadvertently
+making modifications to multiple copies of the file. If a
+lock cannot be obtained for a file because it is locked by
+another process, the edit session is read-only (as if the
+rreeaaddoonnllyy option or the --RR flag had been specified). If a
+lock cannot be obtained for other reasons, the edit session
+will continue, but the file status information (see the
+<<ccoonnttrrooll--GG>> command) will reflect this fact.
+
+ Both eexx and vvii are modeful editors, i.e. they have two
+modes, "command" mode and "text input" mode. The former is
+intended to permit you to enter commands which modifies
+already existing text. The latter is intended to permit you
+to enter new text. When eexx first starts running, it is in
+command mode, and usually displays a prompt (see the pprroommpptt
+option for more information). The prompt is a single colon
+("::") character. There are three commands that switch eexx
+into text input mode: aappppeenndd, cchhaannggee and iinnsseerrtt. Once in
+input mode, entering a line containing only a single period
+("..") terminates text input mode and returns to command
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--1111
+
+
+mode, where the prompt is redisplayed.
+
+ When vvii first starts running, it is in command mode as
+well. There are eleven commands that switch vvii into text
+input mode: AA, aa, CC, cc, II, ii, OO, oo, RR, SS and ss. Once in
+input mode, entering an <<eessccaappee>> character terminates text
+input mode and returns to command mode.
+
+ The following words have special meanings in both the
+eexx and vvii command descriptions:
+
+<<iinntteerrrruupptt>>
+ The interrupt character is used to interrupt the cur-
+ rent operation. Normally <<ccoonnttrrooll--CC>>, whatever charac-
+ ter is set for the current terminal is used.
+
+<<lliitteerraall nneexxtt>>
+ The literal next character is used to escape the subse-
+ quent character from any special meaning. This charac-
+ ter is always <<ccoonnttrrooll--VV>>. If the terminal is not set
+ up to do XON/XOFF flow control, then <<ccoonnttrrooll--QQ>> is
+ used to mean literal next as well.
+
+ccuurrrreenntt ppaatthhnnaammee
+ The pathname of the file currently being edited by vi.
+ When the percent character ("%%") appears in a file name
+ entered as part of an eexx command argument, it is
+ replaced by the current pathname. (The "%%" character
+ can be escaped by preceding it with a backslash.)
+
+aalltteerrnnaattee ppaatthhnnaammee
+ The name of the last file name mentioned in an eexx com-
+ mand, or, the previous current pathname if the last
+ file mentioned becomes the current file. When the hash
+ mark character ("##") appears in a file name entered as
+ part of an eexx command argument, it is replaced by the
+ alternate pathname. (The "##" character can be escaped
+ by preceding it with a backslash.)
+
+bbuuffffeerr
+ One of a number of named areas for saving copies of
+ text. Commands that change or delete text can save the
+ changed or deleted text into a specific buffer, for
+ later use, if the command allows it (i.e. the eexx cchhaannggee
+ command cannot save the changed text in a named
+ buffer). Buffers are named with a single character,
+ preceded by a double quote, e.g. ""<<cchhaarraacctteerr>>. His-
+ toric implementations of eexx/vvii limited <<cchhaarraacctteerr>> to
+ the alphanumeric characters; nneexx/nnvvii permits the use of
+ any character.
+
+ Buffers named by uppercase characters are the same as
+ buffers named by lowercase characters, e.g. the buffer
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--1122 NNvvii//NNeexx RReeffeerreennccee
+
+
+ named by the English character "AA" is the same as the
+ buffer named by the character "aa", with the exception
+ that, if the buffer contents are being changed (as with
+ a text deletion or vvii cchhaannggee command), the text is
+ _a_p_p_e_n_d_e_d to the buffer, instead of replacing the cur-
+ rent contents.
+
+ The buffers named by the numeric characters (in
+ English, "11" through "99"), are special, in that if at
+ least one line is changed or deleted in the file, (or a
+ command changes or deletes a region that crosses a line
+ boundary) a copy of the text is placed into the numeric
+ buffer "11", regardless of the user specifying another
+ buffer in which to save it. Before this copy is done,
+ the previous contents of buffer "11" are moved into
+ buffer "22", "22" into buffer "33", and so on. The con-
+ tents of buffer "99" are discarded. In vvii, text may be
+ explicitly stored into the numeric buffers. In this
+ case, the buffer rotation described above occurs before
+ the replacement of the buffer's contents. (Text cannot
+ be explicitly stored into the numeric buffers in eexx
+ because of ambiguities that this would cause in the eexx
+ command syntax.)
+
+ When a vvii command synopsis shows both a [[bbuuffffeerr]] and a
+ [[ccoouunntt]], they may be presented in any order.
+
+ Finally, all buffers are either "line" or "character"
+ oriented. All eexx commands which store text into
+ buffers are line oriented. Some vvii commands which
+ store text into buffers are line oriented, and some are
+ character oriented; the description for each applicable
+ vvii command notes whether text copied into buffers using
+ the command is line or character oriented. In addi-
+ tion, the vvii command ddiissppllaayy bbuuffffeerrss displays the cur-
+ rent orientation for each buffer. Generally, the only
+ importance attached to this orientation is that if the
+ buffer is subsequently inserted into the text, line
+ oriented buffers create new lines for each of the lines
+ they contain, and character oriented buffers create new
+ lines for any lines _o_t_h_e_r than the first and last lines
+ they contain. The first and last lines are inserted
+ into the text at the current cursor position, becoming
+ part of the current line. If there is more than one
+ line in the buffer, however, the current line itself
+ will be split.
+
+uunnnnaammeedd bbuuffffeerr
+ The unnamed buffer is a text storage area which is used
+ by commands that take a buffer as an argument, when no
+ buffer is specified by the user. There is no way to
+ explicitly reference this buffer.
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--1133
+
+
+99.. VVii DDeessccrriippttiioonn
+
+ VVii takes up the entire screen to display the edited
+file, except for the bottom line of the screen. The bottom
+line of the screen is used to enter eexx commands, and for vvii
+error and informational messages. If no other information
+is being displayed, the default display can show the current
+cursor row and cursor column, an indication of whether the
+file has been modified, and the current mode of the editor.
+See the rruulleerr, sshhoowwddiirrttyy and sshhoowwmmooddee options for more
+information.
+
+ Empty lines do not have any special representation on
+the screen, but lines on the screen that would logically
+come after the end of the file are displayed as a single
+tilde ("~~") character. To differentiate between empty lines
+and lines consisting of only whitespace characters, use the
+lliisstt option. Historically, implementations of vvii have also
+displayed some lines as single asterisk ("@@") characters.
+These were lines that were not correctly displayed, i.e.
+lines on the screen that did not correspond to lines in the
+file, or lines that did not fit on the current screen. NNvvii
+never displays lines in this fashion.
+
+ VVii is a modeful editor, i.e. it has two modes, "com-
+mand" mode and "text input" mode. When vvii first starts, it
+is in command mode. There are several commands that change
+vvii into text input mode. The <<eessccaappee>> character is used to
+resolve the text input into the file, and exit back into
+command mode. In vvii command mode, the cursor is always
+positioned on the last column of characters which take up
+more than one column on the screen. In vvii text insert mode,
+the cursor is positioned on the first column of characters
+which take up more than one column on the screen.
+
+ Generally, if the cursor line and cursor column are not
+on the screen, then the screen is scrolled (if the target
+cursor is close) or repainted (if the target cursor is far
+away) so that the cursor is on the screen. If the screen is
+scrolled, it is moved a minimal amount, and the cursor line
+will usually appear at the top or bottom of the screen. In
+the screen is repainted, the cursor line will appear in the
+center of the screen, unless the cursor is sufficiently
+close to the beginning or end of the file that this is not
+possible. If the lleeffttrriigghhtt option is set, the screen may be
+scrolled or repainted in a horizontal direction as well as
+in a vertical one.
+
+ A major difference between the historical vvii presenta-
+tion and nnvvii is in the scrolling and screen oriented posi-
+tion commands, <<ccoonnttrrooll--BB>>, <<ccoonnttrrooll--DD>>, <<ccoonnttrrooll--EE>>, <<ccoonn--
+ttrrooll--FF>>, <<ccoonnttrrooll--UU>>, <<ccoonnttrrooll--YY>>, HH, LL and MM. In histori-
+cal implementations of vvii, these commands acted on physical
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--1144 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+(as opposed to logical, or screen) lines. For lines that
+were sufficiently long in relation to the size of the
+screen, this meant that single line scroll commands might
+repaint the entire screen, scrolling or screen positioning
+command might not change the screen or move the cursor at
+all, and some lines simply could not be displayed, even
+though vvii would edit the file that contained them. In nnvvii,
+these commands act on logical, i.e. screen lines. You are
+unlikely to notice any difference unless you are editing
+files with lines significantly longer than a screen width.
+
+ VVii keeps track of the currently "most attractive" cur-
+sor position. Each command description (for commands that
+can change the current cursor position), specifies if the
+cursor is set to a specific location in the line, or if it
+is moved to the "most attractive cursor position". The lat-
+ter means that the cursor is moved to the cursor position
+that is vertically as close as possible to the current cur-
+sor position. If the current line is shorter than the cur-
+sor position vvii would select, the cursor is positioned on
+the last character in the line. (If the line is empty, the
+cursor is positioned on the first column of the line.) If a
+command moves the cursor to the most attractive position, it
+does not alter the current cursor position, and a subsequent
+movement will again attempt to move the cursor to that posi-
+tion. Therefore, although a movement to a line shorter than
+the currently most attractive position will cause the cursor
+to move to the end of that line, a subsequent movement to a
+longer line will cause the cursor to move back to the most
+attractive position.
+
+ In addition, the $$ command makes the end of each line
+the most attractive cursor position rather than a specific
+column.
+
+ Each vvii command described below notes where the cursor
+ends up after it is executed. This position is described in
+terms of characters on the line, i.e. "the previous charac-
+ter", or, "the last character in the line". This is to
+avoid needing to continually refer to on what part of the
+character the cursor rests.
+
+ The following words have special meaning for vvii com-
+mands.
+
+pprreevviioouuss ccoonntteexxtt
+ The position of the cursor before the command which
+ caused the last absolute movement was executed. Each
+ vvii command described in the next section that is con-
+ sidered an absolute movement is so noted. In addition,
+ specifying _a_n_y address to an eexx command is considered
+ an absolute movement.
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--1155
+
+
+mmoottiioonn
+ A second vvii command can be used as an optional trailing
+ argument to the vvii !!, <<, >>, cc, dd, yy, and (depending on
+ the ttiillddeeoopp option) ~~ commands. This command indicates
+ the end of the region of text that's affected by the
+ command. The motion command may be either the command
+ character repeated (in which case it means the current
+ line) or a cursor movement command. In the latter
+ case, the region affected by the command is from the
+ starting or stopping cursor position which comes first
+ in the file, to immediately before the starting or
+ stopping cursor position which comes later in the file.
+ Commands that operate on lines instead of using begin-
+ ning and ending cursor positions operate on all of the
+ lines that are wholly or partially in the region. In
+ addition, some other commands become line oriented
+ depending on where in the text they are used. The com-
+ mand descriptions below note these special cases.
+
+ The following commands may all be used as motion compo-
+ nents for vvii commands:
+
+
+ <<ccoonnttrrooll--AA>> <<ccoonnttrrooll--HH>> <<ccoonnttrrooll--JJ>> <<ccoonnttrrooll--MM>>
+ <<ccoonnttrrooll--NN>> <<ccoonnttrrooll--PP>> <<ssppaaccee>> $$
+ %% ''<<cchhaarraacctteerr>> (( ))
+ ++ ,, -- //
+ 00 ;; ?? BB
+ EE FF GG HH
+ LL MM NN TT
+ WW [[[[ ]]]] ^^
+ __ ``<<cchhaarraacctteerr>> bb ee
+ ff hh jj kk
+ ll nn tt ww
+ {{ || }}
+
+
+ The optional count prefix available for some of the vvii
+ commands that take motion commands, or the count prefix
+ available for the vvii commands that are used as motion
+ components, may be included and is _a_l_w_a_y_s considered
+ part of the motion argument. For example, the commands
+ "cc22ww" and "22ccww" are equivalent, and the region affected
+ by the cc command is two words of text. In addition, if
+ the optional count prefix is specified for both the vvii
+ command and its motion component, the effect is multi-
+ plicative and is considered part of the motion argu-
+ ment. For example, the commands "44ccww" and "22cc22ww" are
+ equivalent, and the region affected by the cc command is
+ four words of text.
+
+
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--1166 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ccoouunntt
+ A positive number used as an optional argument to most
+ commands, either to give a size or a position (for dis-
+ play or movement commands), or as a repeat count (for
+ commands that modify text). The count argument is
+ always optional and defaults to 1 unless otherwise
+ noted in the command description.
+
+ When a vvii command synopsis shows both a [[bbuuffffeerr]] and
+ [[ccoouunntt]], they may be presented in any order.
+
+bbiiggwwoorrdd
+ A set of non-whitespace characters preceded and fol-
+ lowed by whitespace characters or the beginning or end
+ of the file or line.
+
+ Groups of empty lines (or lines containing only whites-
+ pace characters) are treated as a single bigword.
+
+wwoorrdd
+ Generally, in languages where it is applicable, vvii rec-
+ ognizes two kinds of words. First, a sequence of let-
+ ters, digits and underscores, delimited at both ends
+ by: characters other than letters, digits, or under-
+ scores; the beginning or end of a line; the beginning
+ or end of the file. Second, a sequence of characters
+ other than letters, digits, underscores, or whitespace
+ characters, delimited at both ends by: a letter, digit,
+ underscore, or whitespace character; the beginning or
+ end of a line; the beginning or end of the file.
+
+ Groups of empty lines (or lines containing only whites-
+ pace characters) are treated as a single word.
+
+ppaarraaggrraapphh
+ An area of text that begins with either the beginning
+ of a file, an empty line, or a section boundary, and
+ continues until either an empty line, section boundary,
+ or the end of the file.
+
+ Groups of empty lines (or lines containing only whites-
+ pace characters) are treated as a single paragraph.
+
+ Additional paragraph boundaries can be defined using
+ the ppaarraaggrraapphh option.
+
+sseeccttiioonn
+ An area of text that starts with the beginning of the
+ file or a line whose first character is an open brace
+ ("{{") and continues until the next section or the end
+ of the file.
+
+ Additional section boundaries can be defined using the
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--1177
+
+
+ sseeccttiioonnss option.
+
+sseenntteennccee
+ An area of text that begins with either the beginning
+ of the file or the first nonblank character following
+ the previous sentence, paragraph, or section boundary
+ and continues until the end of the file or a or a
+ period ("..") exclamation point ("!!") or question mark
+ ("??") character, followed by either an end-of-line or
+ two whitespace characters. Any number of closing
+ parentheses ("))"), brackets ("]]") or double-quote ("""")
+ characters can appear between the period, exclamation
+ point, or question mark and the whitespace characters
+ or end-of-line.
+
+ Groups of empty lines (or lines containing only whites-
+ pace characters) are treated as a single sentence.
+
+1100.. VVii CCoommmmaannddss
+
+ The following section describes the commands available
+in the command mode of the vvii editor. In each entry below,
+the tag line is a usage synopsis for the command character.
+In addition, the final line and column the cursor rests
+upon, and any options which affect the command are noted.
+
+[[ccoouunntt]] <<ccoonnttrrooll--AA>>
+ Search forward ccoouunntt times for the current word. The
+ current word begins at the first non-whitespace charac-
+ ter on or after the current cursor position, and
+ extends up to the next non-word character or the end of
+ the line. The search is literal, i.e. no characters in
+ the word have any special meaning in terms of Regular
+ Expressions. It is an error if no matching pattern is
+ found between the starting position and the end of the
+ file.
+
+ The <<ccoonnttrrooll--AA>> command is an absolute movement. The
+ <<ccoonnttrrooll--AA>> command may be used as the motion component
+ of other vvii commands, in which case any text copied
+ into a buffer is character oriented.
+
+ Line: Set to the line where the word is found.
+ Column: Set to the first character of the word.
+ Options: Affected by the eexxtteennddeedd, iiggnnoorreeccaassee and wwrraapp--
+ ssccaann options.
+
+[[ccoouunntt]] <<ccoonnttrrooll--BB>>
+ Page backward ccoouunntt screens. Two lines of overlap are
+ maintained by displaying the window starting at line
+ ((ttoopp__lliinnee -- ccoouunntt ** wwiinnddooww__ssiizzee)) ++ 22, where wwiinnddooww__ssiizzee
+ is the value of the wwiinnddooww option. (In the case of
+ split screens, this size is corrected to the current
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--1188 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ screen size.) This is an error if the movement is past
+ the beginning of the file.
+
+ The <<ccoonnttrrooll--BB>> command is an absolute movement.
+
+ Line: Set to the last line of text displayed on the
+ screen.
+ Column: Set to the first nonblank character of the
+ line.
+ Options: None.
+
+[[ccoouunntt]] <<ccoonnttrrooll--DD>>
+ Scroll forward ccoouunntt lines. If ccoouunntt is not specified,
+ scroll forward the number of lines specified by the
+ last <<ccoonnttrrooll--DD>> or <<ccoonnttrrooll--UU>> command. If this is
+ the first <<ccoonnttrrooll--DD>> or <<ccoonnttrrooll--UU>> command, scroll
+ forward half the number of lines in the screen. (In
+ the case of split screens, the default scrolling dis-
+ tance is corrected to half the current screen size.)
+ This is an error if the movement is past the end of the
+ file.
+
+ The <<ccoonnttrrooll--DD>> command is an absolute movement.
+
+ Line: Set to the current line plus the number of
+ lines scrolled.
+ Column: Set to the first nonblank character of the
+ line.
+ Options: None.
+
+[[ccoouunntt]] <<ccoonnttrrooll--EE>>
+ Scroll forward ccoouunntt lines, leaving the cursor on the
+ current line and column, if possible. This is an error
+ if the movement is past the end of the file.
+
+ Line: Unchanged unless the current line scrolls off
+ the screen, in which case it is set to the
+ first line on the screen.
+ Column: Unchanged unless the current line scrolls off
+ the screen, in which case it is set to the
+ most attractive cursor position.
+ Options: None.
+
+[[ccoouunntt]] <<ccoonnttrrooll--FF>>
+ Page forward ccoouunntt screens. Two lines of overlap are
+ maintained by displaying the window starting at line
+ ttoopp__lliinnee ++ ccoouunntt ** wwiinnddooww__ssiizzee -- 22, where wwiinnddooww__ssiizzee
+ is the value of the wwiinnddooww option. (In the case of
+ split screens, this size is corrected to the current
+ screen size.) This is an error if the movement is past
+ the end of the file.
+
+ The <<ccoonnttrrooll--FF>> command is an absolute movement.
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--1199
+
+
+ Line: Set to the first line on the screen.
+ Column: Set to the first nonblank character of the
+ current line.
+ Options: None.
+
+<<ccoonnttrrooll--GG>>
+ Display the file information. The information includes
+ the current pathname, the current line, the number of
+ total lines in the file, the current line as a percent-
+ age of the total lines in the file, if the file has
+ been modified, was able to be locked, if the file's
+ name has been changed, and if the edit session is read-
+ only.
+
+ Line: Unchanged.
+ Column: Unchanged.
+ Options: None.
+
+<<ccoonnttrrooll--HH>>
+[[ccoouunntt]] hh
+ Move the cursor back ccoouunntt characters in the current
+ line. This is an error if the cursor is on the first
+ character in the line.
+
+ The <<ccoonnttrrooll--HH>> and hh commands may be used as the
+ motion component of other vvii commands, in which case
+ any text copied into a buffer is character oriented.
+
+ Line: Unchanged.
+ Column: Set to the ccuurrrreenntt -- ccoouunntt character, or, the
+ first character in the line if ccoouunntt is
+ greater than or equal to the number of charac-
+ ters in the line before the cursor.
+ Options: None.
+
+[[ccoouunntt]] <<ccoonnttrrooll--JJ>>
+[[ccoouunntt]] <<ccoonnttrrooll--NN>>
+[[ccoouunntt]] jj
+ Move the cursor down ccoouunntt lines without changing the
+ current column. This is an error if the movement is
+ past the end of the file.
+
+ The <<ccoonnttrrooll--JJ>>, <<ccoonnttrrooll--NN>> and jj commands may be used
+ as the motion component of other vvii commands, in which
+ case any text copied into a buffer is line oriented.
+
+ Line: Set to the current line plus ccoouunntt.
+ Column: The most attractive cursor position.
+ Options: None.
+
+<<ccoonnttrrooll--LL>>
+<<ccoonnttrrooll--RR>>
+ Repaint the screen.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--2200 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Line: Unchanged.
+ Column: Unchanged.
+ Options: None.
+
+[[ccoouunntt]] <<ccoonnttrrooll--MM>>
+[[ccoouunntt]] ++
+ Move the cursor down ccoouunntt lines to the first nonblank
+ character of that line. This is an error if the move-
+ ment is past the end of the file.
+
+ The <<ccoonnttrrooll--MM>> and ++ commands may be used as the
+ motion component of other vvii commands, in which case
+ any text copied into a buffer is line oriented.
+
+ Line: Set to the current line plus ccoouunntt.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: None.
+
+[[ccoouunntt]] <<ccoonnttrrooll--PP>>
+[[ccoouunntt]] kk
+ Move the cursor up ccoouunntt lines, without changing the
+ current column. This is an error if the movement is
+ past the beginning of the file.
+
+ The <<ccoonnttrrooll--PP>> and kk commands may be used as the
+ motion component of other vvii commands, in which case
+ any text copied into a buffer is line oriented.
+
+ Line: Set to the current line minus count.
+ Column: The most attractive cursor position.
+ Options: None.
+
+<<ccoonnttrrooll--TT>>
+ Return to the most recent tag context. The <<ccoonnttrrooll--TT>>
+ command is an absolute movement.
+
+ Line: Set to the context of the previous tag com-
+ mand.
+ Column: Set to the context of the previous tag com-
+ mand.
+ Options: None.
+
+<<ccoonnttrrooll--UU>>
+ Scroll backward ccoouunntt lines. If ccoouunntt is not speci-
+ fied, scroll backward the number of lines specified by
+ the last <<ccoonnttrrooll--DD>> or <<ccoonnttrrooll--UU>> command. If this
+ is the first <<ccoonnttrrooll--DD>> or <<ccoonnttrrooll--UU>> command, scroll
+ backward half the number of lines in the screen. (In
+ the case of split screens, the default scrolling dis-
+ tance is corrected to half the current screen size.)
+ This is an error if the movement is past the beginning
+ of the file.
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2211
+
+
+ The <<ccoonnttrrooll--UU>> command is an absolute movement.
+
+ Line: Set to the current line minus the amount
+ scrolled.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: None.
+
+<<ccoonnttrrooll--WW>>
+ Switch to the next lower screen in the window, or, to
+ the first screen if there are no lower screens in the
+ window.
+
+ Line: Set to the previous cursor position in the
+ window.
+ Column: Set to the previous cursor position in the
+ window.
+ Options: None.
+
+<<ccoonnttrrooll--YY>>
+ Scroll backward ccoouunntt lines, leaving the current line
+ and column as is, if possible. This is an error if the
+ movement is past the beginning of the file.
+
+ Line: Unchanged unless the current line scrolls off
+ the screen, in which case it is set to the
+ last line of text displayed on the screen.
+ Column: Unchanged unless the current line scrolls off
+ the screen, in which case it is the most
+ attractive cursor position.
+ Options: None.
+
+<<ccoonnttrrooll--ZZ>>
+ Suspend the current editor session. If the file has
+ been modified since it was last completely written, and
+ the aauuttoowwrriittee option is set, the file is written before
+ the editor session is suspended. If this write fails,
+ the editor session is not suspended.
+
+ Line: Unchanged.
+ Column: Unchanged.
+ Options: Affected by the aauuttoowwrriittee option.
+
+<<eessccaappee>>
+ Execute eexx commands or cancel partial commands. If an
+ eexx command is being entered (e.g. //, ??, :: or !!), the
+ command is executed. If a partial command has been
+ entered, e.g. or the command is cancelled. Otherwise,
+ it is an error.
+
+ Line: When an eexx command is being executed, the cur-
+ rent line is set as described for that com-
+ mand. Otherwise, unchanged.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--2222 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Column: When an eexx command is being executed, the cur-
+ rent column is set as described for that com-
+ mand. Otherwise, unchanged.
+ Options: None.
+
+<<ccoonnttrrooll--]]>>
+ Push a tag reference onto the tag stack. The tags
+ files (see the ttaaggss option for more information) are
+ searched for a tag matching the current word. The cur-
+ rent word begins at the first non-whitespace character
+ on or after the current cursor position, and extends up
+ to the next non-word character or the end of the line.
+ If a matching tag is found, the current file is dis-
+ carded and the file containing the tag reference is
+ edited.
+
+ If the current file has been modified since it was last
+ completely written, the command will fail. The <<ccoonn--
+ ttrrooll--]]>> command is an absolute movement.
+
+ Line: Set to the line containing the matching tag
+ string.
+ Column: Set to the start of the matching tag string.
+ Options: Affected by the ttaaggss and ttaagglleennggtthh options.
+
+<<ccoonnttrrooll--^^>>
+ Switch to the most recently edited file.
+
+ If the file has been modified since it was last com-
+ pletely written, and the aauuttoowwrriittee option is set, the
+ file is written out. If this write fails, the command
+ will fail. Otherwise, if the current file has been
+ modified since it was last completely written, the com-
+ mand will fail.
+
+ Line: Set to the line the cursor was on when the
+ file was last edited.
+ Column: Set to the column the cursor was on when the
+ file was last edited.
+ Options: Affected by the aauuttoowwrriittee option.
+
+[[ccoouunntt]] <<ssppaaccee>>
+[[ccoouunntt]] ll
+ Move the cursor forward ccoouunntt characters without chang-
+ ing the current line. This is an error if the cursor
+ is on the last character in the line.
+
+ The <<ssppaaccee>> and ll commands may be used as the motion
+ component of other vvii commands, in which case any text
+ copied into a buffer is character oriented. In addi-
+ tion, these commands may be used as the motion compo-
+ nents of other commands when the cursor is on the last
+ character in the line, without error.
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2233
+
+
+ Line: Unchanged.
+ Column: Set to the current character plus the next
+ ccoouunntt characters, or to the last character on
+ the line if ccoouunntt is greater than the number
+ of characters in the line after the current
+ character.
+ Options: None.
+
+[[ccoouunntt]] !! mmoottiioonn sshheellll--aarrgguummeenntt((ss))
+ Replace text with results from a shell command. Pass
+ the lines specified by the ccoouunntt and mmoottiioonn arguments
+ as standard input to the program named by the sshheellll
+ option, and replace those lines with the output (both
+ standard error and standard output) of that command.
+
+ After the motion is entered, vvii prompts for arguments
+ to the shell command.
+
+ Within those arguments, "%%" and "##" characters are
+ expanded to the current and alternate pathnames,
+ respectively. The "!!" character is expanded with the
+ command text of the previous !! or ::!! commands.
+ (Therefore, the command !!!! repeats the previous !!
+ command.) The special meanings of "%%", "##" and "!!"
+ can be overridden by escaping them with a backslash.
+ If no !! or ::!! command has yet been executed, it is an
+ error to use an unescaped "!!" character. The !! com-
+ mand does _n_o_t do shell expansion on the strings pro-
+ vided as arguments. If any of the above expansions
+ change the arguments the user entered, the command is
+ redisplayed at the bottom of the screen.
+
+ VVii then executes the program named by the sshheellll option,
+ with a --cc flag followed by the arguments (which are
+ bundled into a single argument).
+
+ The !! command is permitted in an empty file.
+
+ If the file has been modified since it was last com-
+ pletely written, the !! command will warn you.
+
+ Line: The first line of the replaced text.
+ Column: The first column of the replaced text.
+ Options: Affected by the sshheellll option.
+
+[[ccoouunntt]] ## ++||--||##
+ Increment or decrement the current number. The current
+ number begins at the first non-number character on or
+ before the current cursor position, or the beginning of
+ the line, and extends up to the first non-number char-
+ acter on or after the current cursor position or the
+ end of the line. If the trailing character is a ++, the
+ number is incremented by ccoouunntt. If the trailing
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--2244 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ character is a --, the number is decremented by ccoouunntt.
+ If the trailing character is a ##, the previous incre-
+ ment or decrement is repeated.
+
+ The format of the number (decimal, hexadecimal, and
+ octal, and leading 0's) is retained unless the new
+ value cannot be represented in the previous format.
+
+ Line: Unchanged.
+ Column: Set to the first character in the cursor word.
+ Options: None.
+
+[[ccoouunntt]] $$
+ Move the cursor to the end of a line. If ccoouunntt is
+ specified, the cursor moves down ccoouunntt -- 11 lines.
+
+ It is not an error to use the $$ command when the cursor
+ is on the last character in the line or when the line
+ is empty.
+
+ The $$ command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented, unless the cursor is at,
+ or before the first nonblank character in the line, in
+ which case it is line oriented. It is not an error to
+ use the $$ command as a motion component when the cursor
+ is on the last character in the line, although it is an
+ error when the line is empty.
+
+ Line: Set to the current line plus ccoouunntt minus 1.
+ Column: Set to the last character in the line.
+ Options: None.
+
+%%
+ Move to the matching character. The cursor moves to
+ the parenthesis or curly brace which _m_a_t_c_h_e_s the paren-
+ thesis or curly brace found at the current cursor posi-
+ tion or which is the closest one to the right of the
+ cursor on the line. It is an error to execute the %%
+ command on a line without a parenthesis or curly brace.
+ Historically, any ccoouunntt specified to the %% command was
+ ignored.
+
+ The %% command is an absolute movement. The %% command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ character oriented, unless the starting point of the
+ region is at or before the first nonblank character on
+ its line, and the ending point is at or after the last
+ nonblank character on its line, in which case it is
+ line oriented.
+
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2255
+
+
+ Line: Set to the line containing the matching char-
+ acter.
+ Column: Set to the matching character.
+ Options: None.
+
+&&
+ Repeat the previous substitution command on the current
+ line.
+
+ Historically, any ccoouunntt specified to the && command was
+ ignored.
+
+ Line: Unchanged.
+ Column: Unchanged if the cursor was on the last char-
+ acter in the line, otherwise, set to the first
+ nonblank character in the line.
+ Options: Affected by the eeddccoommppaattiibbllee, eexxtteennddeedd,
+ iiggnnoorreeccaassee and mmaaggiicc options.
+
+''<<cchhaarraacctteerr>>
+``<<cchhaarraacctteerr>>
+ Return to a context marked by the character <<cchhaarraacc--
+ tteerr>>. If <<cchhaarraacctteerr>> is the "''" or "``" character,
+ return to the previous context. If <<cchhaarraacctteerr>> is any
+ other character, return to the context marked by that
+ character (see the mm command for more information). If
+ the command is the '' command, only the line value is
+ restored, and the cursor is placed on the first non-
+ blank character of that line. If the command is the ``
+ command, both the line and column values are restored.
+
+ It is an error if the context no longer exists because
+ of line deletion. (Contexts follow lines that are
+ moved, or which are deleted and then restored.)
+
+ The '' and `` commands are both absolute movements. They
+ may be used as a motion component for other vvii com-
+ mands. For the '' command, any text copied into a
+ buffer is line oriented. For the `` command, any text
+ copied into a buffer is character oriented, unless it
+ both starts and stops at the first character in the
+ line, in which case it is line oriented. In addition,
+ when using the `` command as a motion component, com-
+ mands which move backward and started at the first
+ character in the line, or move forward and ended at the
+ first character in the line, are corrected to the last
+ character of the starting and ending lines, respec-
+ tively.
+
+ Line: Set to the line from the context.
+ Column: Set to the first nonblank character in the
+ line, for the '' command, and set to the con-
+ text's column for the `` command.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--2266 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Options: None.
+
+[[ccoouunntt]] ((
+ Back up ccoouunntt sentences.
+
+ The (( command is an absolute movement. The (( command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ character oriented, unless the starting and stopping
+ points of the region are the first character in the
+ line, in which case it is line oriented. In the latter
+ case, the stopping point of the region is adjusted to
+ be the end of the line immediately before it, and not
+ the original cursor position.
+
+ Line: Set to the line containing the beginning of
+ the sentence.
+ Column: Set to the first nonblank character of the
+ sentence.
+ Options: None.
+
+[[ccoouunntt]] ))
+ Move forward ccoouunntt sentences.
+
+ The )) command is an absolute movement. The )) command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ character oriented, unless the starting point of the
+ region is the first character in the line, in which
+ case it is line oriented. In the latter case, if the
+ stopping point of the region is also the first charac-
+ ter in the line, it is adjusted to be the end of the
+ line immediately before it.
+
+ Line: Set to the line containing the beginning of
+ the sentence.
+ Column: Set to the first nonblank character of the
+ sentence.
+ Options: None.
+
+[[ccoouunntt]] ,,
+ Reverse find character ccoouunntt times. Reverse the last
+ FF, ff, TT or tt command, searching the other way in the
+ line, ccoouunntt times.
+
+ The ,, command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Unchanged.
+ Column: Set to the searched-for character.
+ Options: None.
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2277
+
+
+[[ccoouunntt]] --
+ Move to first nonblank of the previous line, ccoouunntt
+ times.
+
+ This is an error if the movement is past the beginning
+ of the file.
+
+ The -- command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is line oriented.
+
+ Line: Set to the current line minus ccoouunntt.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: None.
+
+[[ccoouunntt]] ..
+ Repeat the last vvii command that modified text. The
+ repeated command may be a command and motion component
+ combination. If ccoouunntt is specified, it replaces _b_o_t_h
+ the count specified for the repeated command, and, if
+ applicable, for the repeated motion component. If
+ ccoouunntt is not specified, the counts originally specified
+ to the command being repeated are used again.
+
+ As a special case, if the .. command is executed imme-
+ diately after the uu command, the change log is rolled
+ forward or backward, depending on the action of the uu
+ command.
+
+ Line: Set as described for the repeated command.
+ Column: Set as described for the repeated command.
+ Options: None.
+
+//RREE<<ccaarrrriiaaggee--rreettuurrnn>>
+//RREE// [[ooffffsseett]]<<ccaarrrriiaaggee--rreettuurrnn>>
+??RREE<<ccaarrrriiaaggee--rreettuurrnn>>
+??RREE?? [[ooffffsseett]]<<ccaarrrriiaaggee--rreettuurrnn>>
+NN
+nn
+ Search forward or backward for a regular expression.
+ The commands beginning with a slash ("//") character are
+ forward searches, the commands beginning with a ques-
+ tion mark ("??") are backward searches. VVii prompts
+ with the leading character on the last line of the
+ screen for a string. It then searches forward or back-
+ ward in the file for the next occurrence of the string,
+ which is interpreted as a Basic Regular Expression.
+
+ The // and ?? commands are absolute movements. They may
+ be used as the motion components of other vvii commands,
+ in which case any text copied into a buffer is charac-
+ ter oriented, unless the search started and ended on
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--2288 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ the first column of a line, in which case it is line
+ oriented. In addition, forward searches ending at the
+ first character of a line, and backward searches begin-
+ ning at the first character in the line, are corrected
+ to begin or end at the last character of the previous
+ line. (Note, forward and backward searches can occur
+ for both // and ?? commands, if the wwrraappssccaann option is
+ set.)
+
+ If an offset from the matched line is specified (i.e. a
+ trailing "//" or "??" character is followed by a signed
+ offset), the buffer will always be line oriented (e.g.
+ "//ssttrriinngg//++00" will always guarantee a line orientation).
+
+ The nn command repeats the previous search.
+
+ The NN command repeats the previous search, but in the
+ reverse direction.
+
+ Missing RE's (e.g. "////<<ccaarrrriiaaggee--rreettuurrnn>>", "//<<ccaarrrriiaaggee--
+ rreettuurrnn>>", "????<<ccaarrrriiaaggee--rreettuurrnn>>", or "??<<ccaarrrriiaaggee--
+ rreettuurrnn>>" search for the last search RE, in the indi-
+ cated direction.
+
+ Searches may be interrupted using the <<iinntteerrrruupptt>> char-
+ acter.
+
+ Line: Set to the line in which the match occurred.
+ Column: Set to the first character of the matched
+ string.
+ Options: Affected by the eeddccoommppaattiibbllee, eexxtteennddeedd,
+ iiggnnoorreeccaassee, mmaaggiicc, and wwrraappssccaann options.
+
+00
+ Move to the first character in the current line. It is
+ not an error to use the 00 command when the cursor is on
+ the first character in the line,
+
+ The 00 command may be used as the motion component of
+ other vvii commands, in which case it is an error if the
+ cursor is on the first character in the line.
+
+ Line: Unchanged.
+ Column: Set to the first character in the line.
+ Options: None.
+
+::
+ Execute an ex command. VVii prompts for an eexx command on
+ the last line of the screen, using a colon ("::") char-
+ acter. The command is terminated by a <<ccaarrrriiaaggee--
+ rreettuurrnn>>, <<nneewwlliinnee>> or <<eessccaappee>> character; all of these
+ characters may be escaped by using a <<lliitteerraall nneexxtt>>
+ character. The command is then executed.
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2299
+
+
+ If the eexx command writes to the screen, vvii will prompt
+ the user for a <<ccaarrrriiaaggee--rreettuurrnn>> before continuing when
+ the eexx command finishes. Large amounts of output from
+ the eexx command will be paged for the user, and the user
+ prompted for a <<ccaarrrriiaaggee--rreettuurrnn>> or <<ssppaaccee>> key to con-
+ tinue. In some cases, a quit (normally a "q" charac-
+ ter) or <<iinntteerrrruupptt>> may be entered to interrupt the eexx
+ command.
+
+ When the eexx command finishes, and the user is prompted
+ to resume visual mode, it is also possible to enter
+ another "::" character followed by another eexx command.
+
+ Line: The current line is set as described for the
+ eexx command.
+ Column: The current column is set as described for the
+ eexx command.
+ Options: None.
+
+[[ccoouunntt]] ;;
+ Repeat the last character find ccoouunntt times. The last
+ character find is one of the FF, ff, TT or tt commands.
+
+ The ;; command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Unchanged.
+ Column: Set to the searched-for character.
+ Options: None.
+
+[[ccoouunntt]] << mmoottiioonn
+[[ccoouunntt]] >> mmoottiioonn
+ Shift lines left or right. Shift the number of lines
+ in the region specified by the motion component, times
+ ccoouunntt, left (for the << command) or right (for the >>
+ command) by the number of columns specified by the
+ sshhiiffttwwiiddtthh option. Only whitespace characters are
+ deleted when shifting left; once the first character in
+ the line contains a nonblank character, the sshhiifftt will
+ succeed, but the line will not be modified.
+
+ Line: Unchanged.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: Affected by the sshhiiffttwwiiddtthh option.
+
+@@ bbuuffffeerr
+ Execute a named buffer. Execute the named buffer as vvii
+ commands. The buffer may include eexx commands, too, but
+ they must be expressed as a :: command. If the buffer
+ is line oriented, <<nneewwlliinnee>> characters are logically
+ appended to each line of the buffer. If the buffer is
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--3300 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ character oriented, <<nneewwlliinnee>> characters are logically
+ appended to all but the last line in the buffer.
+
+ If the buffer name is "@@", or "**", then the last buffer
+ executed shall be used. It is an error to specify "@@@@"
+ or "****" if there were no buffer previous executions.
+ The text of a macro may contain an @@ command, and it is
+ possible to create infinite loops in this manner. (The
+ <<iinntteerrrruupptt>> character may be used to interrupt the
+ loop.)
+
+ Line: The current line is set as described for the
+ command(s).
+ Column: The current column is set as described for the
+ command(s).
+ Options: None.
+
+[[ccoouunntt]] AA
+ Enter input mode, appending the text after the end of
+ the line. If ccoouunntt is specified, the text is repeat-
+ edly input ccoouunntt -- 11 more times after input mode is
+ exited.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+[[ccoouunntt]] BB
+ Move backward ccoouunntt bigwords. Move the cursor backward
+ to the beginning of a bigword by repeating the follow-
+ ing algorithm: if the current position is at the begin-
+ ning of a bigword or the character at the current posi-
+ tion cannot be part of a bigword, move to the first
+ character of the preceding bigword. Otherwise, move to
+ the first character of the bigword at the current posi-
+ tion. If no preceding bigword exists on the current
+ line, move to the first character of the last bigword
+ on the first preceding line that contains a bigword.
+
+ The BB command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Set to the line containing the word selected.
+ Column: Set to the first character of the word
+ selected.
+ Options: None.
+
+[[bbuuffffeerr]] [[ccoouunntt]] CC
+ Change text from the current position to the end-of-
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3311
+
+
+ line. If ccoouunntt is specified, the input text replaces
+ from the current position to the end-of-line, plus
+ ccoouunntt -- 11 subsequent lines.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+[[bbuuffffeerr]] DD
+ Delete text from the current position to the end-of-
+ line.
+
+ It is not an error to execute the DD command on an empty
+ line.
+
+ Line: Unchanged.
+ Column: Set to the character before the current char-
+ acter, or, column 1 if the cursor was on col-
+ umn 1.
+ Options: None.
+
+[[ccoouunntt]] EE
+ Move forward ccoouunntt end-of-bigwords. Move the cursor
+ forward to the end of a bigword by repeating the fol-
+ lowing algorithm: if the current position is the end of
+ a bigword or the character at that position cannot be
+ part of a bigword, move to the last character of the
+ following bigword. Otherwise, move to the last charac-
+ ter of the bigword at the current position. If no suc-
+ ceeding bigword exists on the current line, move to the
+ last character of the first bigword on the next follow-
+ ing line that contains a bigword.
+
+ The EE command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Set to the line containing the word selected.
+ Column: Set to the last character of the word
+ selected.
+ Options: None.
+
+[[ccoouunntt]] FF <<cchhaarraacctteerr>>
+ Search ccoouunntt times backward through the current line
+ for <<cchhaarraacctteerr>>.
+
+ The FF command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--3322 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Line: Unchanged.
+ Column: Set to the searched-for character.
+ Options: None.
+
+[[ccoouunntt]] GG
+ Move to line ccoouunntt, or the last line of the file if
+ ccoouunntt not specified.
+
+ The GG command is an absolute movement. The GG command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ line oriented.
+
+ Line: Set to ccoouunntt, if specified, otherwise, the
+ last line.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: None.
+
+[[ccoouunntt]] HH
+ Move to the screen line ccoouunntt -- 11 lines below the top
+ of the screen.
+
+ The HH command is an absolute movement. The HH command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ line oriented.
+
+ Line: Set to the line ccoouunntt -- 11 lines below the top
+ of the screen.
+ Column: Set to the first nonblank character of the
+ _s_c_r_e_e_n line.
+ Options: None.
+
+[[ccoouunntt]] II
+ Enter input mode, inserting the text at the beginning
+ of the line. If ccoouunntt is specified, the text input is
+ repeatedly input ccoouunntt -- 11 more times.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: None.
+
+[[ccoouunntt]] JJ
+ Join lines. If ccoouunntt is specified, ccoouunntt lines are
+ joined; a minimum of two lines are always joined,
+ regardless of the value of ccoouunntt.
+
+ If the current line ends with a whitespace character,
+ all whitespace is stripped from the next line. Other-
+ wise, if the next line starts with a open parenthesis
+ ("((") do nothing. Otherwise, if the current line ends
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3333
+
+
+ with a question mark ("??"), period ("..") or exclama-
+ tion point ("!!"), insert two spaces. Otherwise, insert
+ a single space.
+
+ It is not an error to join lines past the end of the
+ file, i.e. lines that do not exist.
+
+ Line: Unchanged.
+ Column: Set to the character after the last character
+ of the next-to-last joined line.
+ Options: None.
+
+[[ccoouunntt]] LL
+ Move to the screen line ccoouunntt -- 11 lines above the bot-
+ tom of the screen.
+
+ The LL command is an absolute movement. The LL command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ line oriented.
+
+ Line: Set to the line ccoouunntt -- 11 lines above the bot-
+ tom of the screen.
+ Column: Set to the first nonblank character of the
+ _s_c_r_e_e_n line.
+ Options: None.
+
+ MM
+ Move to the screen line in the middle of the screen.
+
+ The MM command is an absolute movement. The MM command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ line oriented.
+
+ Historically, any ccoouunntt specified to the MM command was
+ ignored.
+
+ Line: Set to the line in the middle of the screen.
+ Column: Set to the first nonblank character of the
+ _s_c_r_e_e_n line.
+ Options: None.
+
+[[ccoouunntt]] OO
+ Enter input mode, appending text in a new line above
+ the current line. If ccoouunntt is specified, the text
+ input is repeatedly input ccoouunntt -- 11 more times.
+
+ Historically, any ccoouunntt specified to the OO command was
+ ignored.
+
+ Line: Set to the last line upon which characters
+ were entered.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--3344 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+[[bbuuffffeerr]] PP
+ Insert text from a buffer. Text from the buffer (the
+ unnamed buffer by default) is inserted before the cur-
+ rent column or, if the buffer is line oriented, before
+ the current line.
+
+ Line: Set to the lowest numbered line insert, if the
+ buffer is line oriented, otherwise unchanged.
+ Column: Set to the first nonblank character of the
+ appended text, if the buffer is line oriented,
+ otherwise, the last character of the appended
+ text.
+ Options: None.
+
+QQ
+ Exit vvii (or visual) mode and switch to eexx mode.
+
+ Line: Unchanged.
+ Column: No longer relevant.
+ Options: None.
+
+[[ccoouunntt]] RR
+ Enter input mode, replacing the characters in the cur-
+ rent line. If ccoouunntt is specified, the text input is
+ repeatedly input ccoouunntt -- 11 more times.
+
+ If the end of the current line is reached, no more
+ characters are replaced and any further characters
+ input are appended to the line.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+[[bbuuffffeerr]] [[ccoouunntt]] SS
+ Substitute ccoouunntt lines.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3355
+
+
+[[ccoouunntt]] TT <<cchhaarraacctteerr>>
+ Search backward, ccoouunntt times, through the current line
+ for the character _a_f_t_e_r the specified <<cchhaarraacctteerr>>.
+
+ The TT command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Unchanged.
+ Column: Set to the character _a_f_t_e_r the searched-for
+ character.
+ Options: None.
+
+UU
+ Restore the current line to its state before the cursor
+ last moved to it.
+
+ Line: Unchanged.
+ Column: The first character in the line.
+ Options: None.
+
+[[ccoouunntt]] WW
+ Move forward ccoouunntt bigwords. Move the cursor forward
+ to the beginning of a bigword by repeating the follow-
+ ing algorithm: if the current position is within a big-
+ word or the character at that position cannot be part
+ of a bigword, move to the first character of the next
+ bigword. If no subsequent bigword exists on the cur-
+ rent line, move to the first character of the first
+ bigword on the first following line that contains a
+ bigword.
+
+ The WW command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: The line containing the word selected.
+ Column: The first character of the word selected.
+ Options: None.
+
+[[bbuuffffeerr]] [[ccoouunntt]] XX
+ Delete ccoouunntt characters before the cursor. If the num-
+ ber of characters to be deleted is greater than or
+ equal to the number of characters to the beginning of
+ the line, all of the characters before the current cur-
+ sor position, to the beginning of the line, are
+ deleted.
+
+ Line: Unchanged.
+ Column: Set to the current character minus ccoouunntt, or
+ the first character if count is greater than
+ the number of characters in the line before
+ the cursor.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--3366 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Options: None.
+
+[[bbuuffffeerr]] [[ccoouunntt]] YY
+ Copy (or "yank") ccoouunntt lines into the specified buffer.
+
+ Line: Unchanged.
+ Column: Unchanged.
+ Options: None.
+
+ZZZZ
+ Write the file and exit vvii. The file is only written
+ if it has been modified since the last complete write
+ of the file to any file.
+
+ The ZZZZ command will exit the editor after writing the
+ file, if there are no further files to edit. Entering
+ two "quit" commands (i.e. wwqq, qquuiitt, xxiitt or ZZZZ) in a
+ row will override this check and the editor will exit,
+ ignoring any files that have not yet been edited.
+
+ Line: Unchanged.
+ Column: Unchanged.
+ Options: None.
+
+[[ccoouunntt]] [[[[
+ Back up ccoouunntt section boundaries.
+
+ The [[[[ command is an absolute movement. The [[[[ command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ character oriented, unless the starting position is
+ column 0, in which case it is line oriented.
+
+ This is an error if the movement is past the beginning
+ of the file.
+
+ Line: Set to the previous line that is ccoouunntt section
+ boundaries back, or the first line of the file
+ if no more section boundaries exist preceding
+ the current line.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: Affected by the sseeccttiioonnss option.
+
+[[ccoouunntt]] ]]]]
+ Move forward ccoouunntt section boundaries.
+
+ The ]]]] command is an absolute movement. The ]]]] command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ character oriented, unless the starting position is
+ column 0, in which case it is line oriented.
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3377
+
+
+ This is an error if the movement is past the end of the
+ file.
+
+ Line: Set to the line that is ccoouunntt section bound-
+ aries forward, or to the last line of the file
+ if no more section boundaries exist following
+ the current line.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: Affected by the sseeccttiioonnss option.
+
+^^
+ Move to first nonblank character on the current line.
+
+ The ^^ command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Unchanged.
+ Column: Set to the first nonblank character of the
+ current line.
+ Options: None.
+
+[[ccoouunntt]] __
+ Move down ccoouunntt -- 11 lines, to the first nonblank char-
+ acter. The __ command may be used as the motion compo-
+ nent of other vvii commands, in which case any text
+ copied into a buffer is line oriented.
+
+ It is not an error to execute the __ command when the
+ cursor is on the first character in the line.
+
+ Line: The current line plus ccoouunntt -- 11.
+ Column: The first nonblank character in the line.
+ Options: None.
+
+[[ccoouunntt]] aa
+ Enter input mode, appending the text after the cursor.
+ If ccoouunntt is specified, the text input is repeatedly
+ input ccoouunntt -- 11 more times.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+[[ccoouunntt]] bb
+ Move backward ccoouunntt words. Move the cursor backward to
+ the beginning of a word by repeating the following
+ algorithm: if the current position is at the beginning
+ of a word, move to the first character of the preceding
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--3388 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ word. Otherwise, the current position moves to the
+ first character of the word at the current position.
+ If no preceding word exists on the current line, move
+ to the first character of the last word on the first
+ preceding line that contains a word.
+
+ The bb command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Set to the line containing the word selected.
+ Column: Set to the first character of the word
+ selected.
+ Options: None.
+
+[[bbuuffffeerr]] [[ccoouunntt]] cc mmoottiioonn
+ Change a region of text. If only part of a single line
+ is affected, then the last character being changed is
+ marked with a "$$". Otherwise, the region of text is
+ deleted, and input mode is entered.
+
+ If ccoouunntt is specified, it is applied to the mmoottiioonn.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+[[bbuuffffeerr]] [[ccoouunntt]] dd mmoottiioonn
+ Delete a region of text. If ccoouunntt is specified, it is
+ applied to the mmoottiioonn.
+
+ Line: Set to the line where the region starts.
+ Column: Set to the first character in the line after
+ the last character in the region. If no such
+ character exists, set to the last character
+ before the region.
+ Options: None.
+
+[[ccoouunntt]] ee
+ Move forward ccoouunntt end-of-words. Move the cursor for-
+ ward to the end of a word by repeating the following
+ algorithm: if the current position is the end of a
+ word, move to the last character of the following word.
+ Otherwise, move to the last character of the word at
+ the current position. If no succeeding word exists on
+ the current line, move to the last character of the
+ first word on the next following line that contains a
+ word.
+
+ The ee command may be used as the motion component of
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3399
+
+
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Set to the line containing the word selected.
+ Column: Set to the last character of the word
+ selected.
+ Options: None.
+
+[[ccoouunntt]] ff <<cchhaarraacctteerr>>
+ Search forward, ccoouunntt times, through the rest of the
+ current line for <<cchhaarraacctteerr>>.
+
+ The ff command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Unchanged.
+ Column: Set to the searched-for character.
+ Options: None.
+
+[[ccoouunntt]] ii
+ Enter input mode, inserting the text before the cursor.
+ If ccoouunntt is specified, the text input is repeatedly
+ input ccoouunntt -- 11 more times.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+mm <<cchhaarraacctteerr>>
+ Save the current context (line and column) as <<cchhaarraacc--
+ tteerr>>. The exact position is referred to by "``<<cchhaarraacc--
+ tteerr>>". The line is referred to by "''<<cchhaarraacctteerr>>".
+
+ Historically, <<cchhaarraacctteerr>> was restricted to lower-case
+ letters only, nnvvii permits the use of any character.
+
+ Line: Unchanged.
+ Column: Unchanged.
+ Options: None.
+
+[[ccoouunntt]] oo
+ Enter input mode, appending text in a new line under
+ the current line. If ccoouunntt is specified, the text
+ input is repeatedly input ccoouunntt -- 11 more times.
+
+ Historically, any ccoouunntt specified to the oo command was
+ ignored.
+
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--4400 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+[[bbuuffffeerr]] pp
+ Append text from a buffer. Text from the buffer (the
+ unnamed buffer by default) is appended after the cur-
+ rent column or, if the buffer is line oriented, after
+ the current line.
+
+ Line: Set to the first line appended, if the buffer
+ is line oriented, otherwise unchanged.
+ Column: Set to the first nonblank character of the
+ appended text if the buffer is line oriented,
+ otherwise, the last character of the appended
+ text.
+ Options: None.
+
+[[ccoouunntt]] rr <<cchhaarraacctteerr>>
+ Replace characters. The next ccoouunntt characters in the
+ line are replaced with <<cchhaarraacctteerr>>. Replacing charac-
+ ters with <<nneewwlliinnee>> characters results in creating new,
+ empty lines into the file.
+
+ If <<cchhaarraacctteerr>> is <<eessccaappee>>, the command is cancelled.
+
+ Line: Unchanged unless the replacement character is
+ a <<nneewwlliinnee>>, in which case it is set to the
+ current line plus ccoouunntt -- 11.
+ Column: Set to the last character replaced, unless the
+ replacement character is a <<nneewwlliinnee>>, in which
+ case the cursor is in column 1 of the last
+ line inserted.
+ Options: None.
+
+[[bbuuffffeerr]] [[ccoouunntt]] ss
+ Substitute ccoouunntt characters in the current line start-
+ ing with the current character.
+
+ Line: Set to the last line upon which characters
+ were entered.
+ Column: Set to the last character entered.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu--
+ ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn
+ options.
+
+[[ccoouunntt]] tt <<cchhaarraacctteerr>>
+ Search forward, ccoouunntt times, through the current line
+ for the character immediately _b_e_f_o_r_e <<cchhaarraacctteerr>>.
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--4411
+
+
+ The tt command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Unchanged.
+ Column: Set to the character _b_e_f_o_r_e the searched-for
+ character.
+ Options: None.
+
+uu
+ Undo the last change made to the file. If repeated,
+ the uu command alternates between these two states, and
+ is its own inverse. When used after an insert that
+ inserted text on more than one line, the lines are
+ saved in the numeric buffers.
+
+ The .. command, when used immediately after the uu com-
+ mand, causes the change log to be rolled forward or
+ backward, depending on the action of the uu command.
+
+ Line: Set to the position of the first line changed,
+ if the reversal affects only one line or rep-
+ resents an addition or change; otherwise, the
+ line preceding the deleted text.
+ Column: Set to the cursor position before the change
+ was made.
+ Options: None.
+
+[[ccoouunntt]] ww
+ Move forward ccoouunntt words. Move the cursor forward to
+ the beginning of a word by repeating the following
+ algorithm: if the current position is at the beginning
+ of a word, move to the first character of the next
+ word. If no subsequent word exists on the current
+ line, move to the first character of the first word on
+ the first following line that contains a word.
+
+ The ww command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented.
+
+ Line: Set to the line containing the word selected.
+ Column: Set to the first character of the word
+ selected.
+ Options: None.
+
+[[bbuuffffeerr]] [[ccoouunntt]] xx
+ Delete ccoouunntt characters. The deletion is at the cur-
+ rent character position. If the number of characters
+ to be deleted is greater than or equal to the number of
+ characters to the end of the line, all of the charac-
+ ters from the current cursor position to the end of the
+ line are deleted.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--4422 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Line: Unchanged.
+ Column: Unchanged unless the last character in the
+ line is deleted and the cursor is not already
+ on the first character in the line, in which
+ case it is set to the previous character.
+ Options: None.
+
+[[bbuuffffeerr]] [[ccoouunntt]] yy mmoottiioonn
+ Copy (or "yank") a text region specified by the ccoouunntt
+ and motion into a buffer. If ccoouunntt is specified, it is
+ applied to the mmoottiioonn.
+
+ Line: Unchanged, unless the region covers more than
+ a single line, in which case it is set to the
+ line where the region starts.
+ Column: Unchanged, unless the region covers more than
+ a single line, in which case it is set to the
+ character were the region starts.
+ Options: None.
+
+[[ccoouunntt11]] zz [[ccoouunntt22]] ttyyppee
+ Redraw the screen with a window ccoouunntt22 lines long, with
+ line ccoouunntt11 placed as specified by the ttyyppee character.
+ If ccoouunntt11 is not specified, it defaults to the current
+ line. If ccoouunntt22 is not specified, it defaults to the
+ current window size.
+
+ The following ttyyppee characters may be used:
+
+ + If ccoouunntt11 is specified, place the line ccoouunntt11
+ at the top of the screen. Otherwise, display
+ the screen after the current screen, similarly
+ to the <<ccoonnttrrooll--FF>> command.
+ <carriage-return>
+ Place the line ccoouunntt11 at the top of the
+ screen.
+ . Place the line ccoouunntt11 in the center of the
+ screen.
+ - Place the line ccoouunntt11 at the bottom of the
+ screen.
+ ^ If ccoouunntt11 is specified, place the line that is
+ at the top of the screen when ccoouunntt11 is at the
+ bottom of the screen, at the bottom of the
+ screen, i.e. display the screen before the
+ screen before ccoouunntt11. Otherwise, display the
+ screen before the current screen, similarly to
+ the <<ccoonnttrrooll--BB>> command.
+
+ Line: Set to ccoouunntt11 unless ccoouunntt11 is not specified
+ and the ttyyppee character was either "^^" or "++",
+ in which case it is set to the line before the
+ first line on the previous screen or the line
+ after the last line on the previous screen,
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--4433
+
+
+ respectively.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: None.
+
+[[ccoouunntt]] {{
+ Move backward ccoouunntt paragraphs.
+
+ The {{ command is an absolute movement. The {{ command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ character oriented, unless the starting character is
+ the first character on its line, in which case it is
+ line oriented.
+
+ Line: Set to the line containing the beginning of
+ the previous paragraph.
+ Column: Set to the first nonblank character in the
+ line.
+ Options: Affected by the ppaarraaggrraapphh option.
+
+[[ccoouunntt]] ||
+ Move to a specific _c_o_l_u_m_n position on the current line.
+
+ The || command may be used as the motion component of
+ other vvii commands, in which case any text copied into a
+ buffer is character oriented. It is an error to use
+ the || command as a motion component and for the cursor
+ not to move.
+
+ Line: Unchanged.
+ Column: Set to the character occupying the column
+ position identified by ccoouunntt, if the position
+ exists in the line. If the column length of
+ the current line is less than ccoouunntt, the cur-
+ sor is moved to the last character in the
+ line.
+ Options: None.
+
+[[ccoouunntt]] }}
+ Move forward ccoouunntt paragraphs.
+
+ The }} command is an absolute movement. The }} command
+ may be used as the motion component of other vvii com-
+ mands, in which case any text copied into a buffer is
+ character oriented, unless the starting character is at
+ or before any nonblank characters in its line, in which
+ case it is line oriented.
+
+ Line: Set to the line containing the beginning of
+ the next paragraph.
+ Column: Set to the first nonblank character in the
+ line.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--4444 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ Options: Affected by the ppaarraaggrraapphh option.
+
+[[ccoouunntt]] ~~
+ Reverse the case of the next ccoouunntt character(s). This
+ is the historic semantic for the ~~ command and it is
+ only in effect if the ttiillddeeoopp option is not set.
+
+ Lowercase alphabetic characters are changed to upper-
+ case, and uppercase characters are changed to lower-
+ case. No other characters are affected.
+
+ Historically, the ~~ command did not take an associated
+ count, nor did it move past the end of the current
+ line. As it had no associated motion it was difficult
+ to change the case of large blocks of text. In nnvvii, if
+ the cursor is on the last character of a line, and
+ there are more lines in the file, the cursor moves to
+ the next line.
+
+ It is not an error to specify a count larger than the
+ number of characters between the cursor and the end of
+ the file.
+
+ Line: Set to the line of the character after ccoouunntt
+ characters, or, end of file.
+ Column: Set to the character after ccoouunntt characters,
+ or, end-of-file.
+ Options: Affected by the ttiillddeeoopp option.
+
+[[ccoouunntt]] ~~ mmoottiioonn
+ Reverse the case of the characters in a text region
+ specified by the ccoouunntt and mmoottiioonn. Only in effect if
+ the ttiillddeeoopp option is set.
+
+ Lowercase characters are changed to uppercase, and
+ uppercase characters are changed to lowercase. No
+ other characters are affected.
+
+ Line: Set to the line of the character after the
+ last character in the region.
+ Column: Set to the character after the last character
+ in the region.
+ Options: Affected by the ttiillddeeoopp option.
+
+<<iinntteerrrruupptt>>
+ Interrupt the current operation. Many of the poten-
+ tially long-running vvii commands may be interrupted
+ using the terminal interrupt character. These opera-
+ tions include searches, file reading and writing, fil-
+ ter operations and map character expansion. Interrupts
+ are also enabled when running commands outside of vvii.
+
+ If the <<iinntteerrrruupptt>> character is used to interrupt while
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--4455
+
+
+ entering an eexx command, the command is aborted, the
+ cursor returns to its previous position, and vvii remains
+ in command mode.
+
+ Generally, if the <<iinntteerrrruupptt>> character is used to
+ interrupt any operation, any changes made before the
+ interrupt are left in place.
+
+ Line: Dependent on the operation being interrupted.
+ Column: Dependent on the operation being interrupted.
+ Options: None.
+
+ 1111.. VVii TTeexxtt IInnppuutt CCoommmmaannddss
+
+ The following section describes the commands
+ available in the text input mode of the vvii editor.
+
+ Historically, vvii implementations only permitted
+ the characters inserted on the current line to be
+ erased. In addition, only the <<ccoonnttrrooll--DD>> erase char-
+ acter and the "00<<ccoonnttrrooll--DD>>" and "^^<<ccoonnttrrooll--DD>>" erase
+ strings could erase autoindent characters. This imple-
+ mentation permits erasure to continue past the begin-
+ ning of the current line, and back to where text input
+ mode was entered. In addition, autoindent characters
+ may be erased using the standard erase characters. For
+ the line and word erase characters, reaching the
+ autoindent characters forms a "soft" boundary, denoting
+ the end of the current word or line erase. Repeating
+ the word or line erase key will erase the autoindent
+ characters.
+
+ Historically, vvii always used <<ccoonnttrrooll--HH>> and <<ccoonn--
+ ttrrooll--WW>> as character and word erase characters, respec-
+ tively, regardless of the current terminal settings.
+ This implementation accepts, in addition to these two
+ characters, the current terminal characters for those
+ operations.
+
+ <<nnuull>>
+ If the first character of the input is a <<nnuull>>,
+ the previous input is replayed, as if just
+ entered.
+
+ <<ccoonnttrrooll--DD>>
+ If the previous character on the line was an
+ autoindent character, erase it. Otherwise, if the
+ user is entering the first character in the line,
+ <<ccoonnttrrooll--DD>> is ignored. Otherwise, a literal
+ <<ccoonnttrrooll--DD>> character is entered.
+
+ ^^<<ccoonnttrrooll--DD>>
+ If the previous character on the line was an
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--4466 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss))
+
+
+ autoindent character, erase all of the autoindent
+ characters on the line. In addition, the autoin-
+ dent level is reset to 0.
+
+ 00<<ccoonnttrrooll--DD>>
+ If the previous character on the line was an
+ autoindent character, erase all of the autoindent
+ characters on the line.
+
+ <<ccoonnttrrooll--TT>>
+ Insert sufficient <<ttaabb>> and <<ssppaaccee>> characters to
+ move the cursor forward to a column immediately
+ after the next column which is an even multiple of
+ the sshhiiffttwwiiddtthh option.
+
+ Historically, vvii did not permit the <<ccoonnttrrooll--TT>>
+ command to be used unless the cursor was at the
+ first column of a new line or it was preceded only
+ by autoindent characters. NNvvii permits it to be
+ used at any time during insert mode.
+
+ <<eerraassee>>
+ <<ccoonnttrrooll--HH>>
+ Erase the last character.
+
+ <<lliitteerraall nneexxtt>>
+ Quote the next character. The next character will
+ not be mapped (see the mmaapp command for more infor-
+ mation) or interpreted specially. A carat ("^^")
+ character will be displayed immediately as a
+ placeholder, but will be replaced by the next
+ character.
+
+ <<eessccaappee>>
+ Resolve all text input into the file, and return
+ to command mode.
+
+ <<lliinnee eerraassee>>
+ Erase the current line.
+
+ <<ccoonnttrrooll--WW>>
+ <<wwoorrdd eerraassee>>
+ Erase the last word. The definition of word is
+ dependent on the aallttwweerraassee and ttttyywweerraassee options.
+
+ <<ccoonnttrrooll--XX>>[[00--99AA--FFaa--ff]]**
+ Insert a character with the specified hexadecimal
+ value into the text.
+
+ <<iinntteerrrruupptt>>
+ Interrupt text input mode, returning to command
+ mode. If the <<iinntteerrrruupptt>> character is used to
+ interrupt inserting text into the file, it is as
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--4477
+
+
+ if the <<eessccaappee>> character was used; all text input
+ up to the interruption is resolved into the file.
+
+ 1122.. EExx AAddddrreessssiinngg
+
+ Addressing in eexx (and when eexx commands are exe-
+ cuted from vvii) relates to the current line. In gen-
+ eral, the current line is the last line affected by a
+ command. The exact effect on the current line is dis-
+ cussed under the description of each command. When the
+ file contains no lines, the current line is zero.
+
+ Addresses are constructed by one or more of the
+ following methods:
+
+ (1) The address ".." refers to the current line.
+
+ (2) The address "$$" refers to the last line of the
+ file.
+
+ (3) The address "NN", where NN is a positive number,
+ refers to the N-th line of the file.
+
+ (4) The address "''<<cchhaarraacctteerr>>" or "``<<cchhaarraacctteerr>>"
+ refers to the line marked with the name <<cchhaarraacc--
+ tteerr>>. (See the kk or mm commands for more infor-
+ mation on how to mark lines.)
+
+ (5) A regular expression (RE) enclosed by slashes
+ ("//") is an address, and it refers to the first
+ line found by searching forward from the line
+ _a_f_t_e_r the current line toward the end of the
+ file, and stopping at the first line containing
+ a string matching the RE. (The trailing slash
+ can be omitted at the end of the command line.)
+
+ If no RE is specified, i.e. the pattern is "////",
+ the last RE used in any command is used in the
+ search.
+
+ If the eexxtteennddeedd option is set, the RE is handled
+ as an extended RE, not a basic RE. If the wwrraapp--
+ ssccaann option is set, the search wraps around to
+ the beginning of the file and continues up to
+ and including the current line, so that the
+ entire file is searched.
+
+ The form "\\//" is accepted for historic reasons,
+ and is identical to "////".
+
+ (6) An RE enclosed in question marks ("??")
+ addresses the first line found by searching
+ backward from the line _p_r_e_c_e_d_i_n_g the current
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--4488 NNvvii//NNeexx RReeffeerreennccee
+
+
+ line, toward the beginning of the file and stop-
+ ping at the first line containing a string
+ matching the RE. (The trailing question mark
+ can be omitted at the end of a command line.)
+
+ If no RE is specified, i.e. the pattern is "????",
+ the last RE used in any command is used in the
+ search.
+
+ If the eexxtteennddeedd option is set, the RE is handled
+ as an extended RE, not a basic RE. If the wwrraapp--
+ ssccaann option is set, the search wraps around
+ from the beginning of the file to the end of the
+ file and continues up to and including the cur-
+ rent line, so that the entire file is searched.
+
+ The form "\\??" is accepted for historic reasons,
+ and is identical to "????".
+
+ (7) An address followed by a plus sign ("++") or a
+ minus sign ("--") followed by a number is an off-
+ set address and refers to the address plus (or
+ minus) the indicated number of lines. If the
+ address is omitted, the addition or subtraction
+ is done with respect to the current line.
+
+ (8) An address of "++" or "--" followed by a number is
+ an offset from the current line. For example,
+ "--55" is the same as "..--55".
+
+ (9) An address ending with "++" or "--" has 1 added to
+ or subtracted from the address, respectively.
+ As a consequence of this rule and of the previ-
+ ous rule, the address "--" refers to the line
+ preceding the current line. Moreover, trailing
+ "++" and "--" characters have a cumulative effect.
+ For example, "++++--++++" refers to the current line
+ plus 3.
+
+ (10) A percent sign ("%%") is equivalent to the
+ address range "11,,$$".
+
+ EExx commands require zero, one, or two addresses.
+ It is an error to specify an address to a command which
+ requires zero addresses.
+
+ If the user provides more than the expected number
+ of addresses to any eexx command, the first addresses
+ specified are discarded. For example, "11,,22,,33,,55"print
+ prints lines 3 through 5, because the pprriinntt command
+ only takes two addresses.
+
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--4499
+
+
+ The addresses in a range are separated from each
+ other by a comma (",,") or a semicolon (";;"). In the
+ latter case, the current line ("..") is set to the
+ first address, and only then is the second address cal-
+ culated. This feature can be used to determine the
+ starting line for forward and backward searches (see
+ rules (5) and (6) above). The second address of any
+ two-address sequence corresponds to a line that fol-
+ lows, in the file, the line corresponding to the first
+ address. The first address must be less than or equal
+ to the second address. The first address must be
+ greater than or equal to the first line of the file,
+ and the last address must be less than or equal to the
+ last line of the file.
+
+ 1133.. EExx DDeessccrriippttiioonn
+
+ The following words have special meanings for eexx
+ commands.
+
+ <<eeooff>>
+ The end-of-file character is used to scroll the
+ screen in the eexx editor. This character is nor-
+ mally <<ccoonnttrrooll--DD>>, however, whatever character is
+ set for the current terminal is used.
+
+ lliinnee
+ A single-line address, given in any of the forms
+ described in the section entitled "EExx AAddddrreessssiinngg".
+ The default for lliinnee is the current line.
+
+ rraannggee
+ A line, or a pair of line addresses, separated by
+ a comma or semicolon. (See the section entitled
+ "EExx AAddddrreessssiinngg" for more information.) The
+ default for range is the current line _o_n_l_y, i.e.
+ "..,,..". A percent sign ("%%") stands for the range
+ "11,,$$". The starting address must be less than, or
+ equal to, the ending address.
+
+ ccoouunntt
+ A positive integer, specifying the number of lines
+ to be affected by the command; the default is 1.
+ Generally, a count past the end-of-file may be
+ specified, e.g. the command "pp 33000000" in a 10 line
+ file is acceptable, and will print from the cur-
+ rent line through the last line in the file.
+
+ ffllaaggss
+ One or more of the characters "#", "p", and "l".
+ When a command that accepts these flags completes,
+ the addressed line(s) are written out as if by the
+ corresponding ##, ll or pp commands. In addition,
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--5500 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ any number of "++" or "--" characters can be speci-
+ fied before, after, or during the flags, in which
+ case the line written is not necessarily the one
+ affected by the command, but rather the line
+ addressed by the offset address specified. The
+ default for ffllaaggss is none.
+
+ ffiillee
+ A pattern used to derive a pathname; the default
+ is the current file. File names are subjected to
+ normal _s_h(1) word expansions.
+
+ Anywhere a file name is specified, it is also pos-
+ sible to use the special string "//ttmmpp". This will be
+ replaced with a temporary file name which can be used
+ for temporary work, e.g. "::ee //ttmmpp" creates and edits a
+ new file.
+
+ If both a count and a range are specified for com-
+ mands that use either, the starting line for the com-
+ mand is the _l_a_s_t line addressed by the range, and
+ ccoouunntt- subsequent lines are affected by the command,
+ e.g. the command "22,,33pp44" prints out lines 3, 4, 5 and
+ 6.
+
+ When only a line or range is specified, with no
+ command, the implied command is either a lliisstt, nnuummbbeerr
+ or pprriinntt command. The command used is the most recent
+ of the three commands to have been used (including any
+ use as a flag). If none of these commands have been
+ used before, the pprriinntt command is the implied command.
+ When no range or count is specified and the command
+ line is a blank line, the current line is incremented
+ by 1 and then the current line is displayed.
+
+ Zero or more whitespace characters may precede or
+ follow the addresses, count, flags, or command name.
+ Any object following a command name (such as buffer,
+ file, etc.), that begins with an alphabetic character,
+ should be separated from the command name by at least
+ one whitespace character.
+
+ Any character, including <<ccaarrrriiaaggee--rreettuurrnn>>, "%%"
+ and "##" retain their literal value when preceded by a
+ backslash.
+
+ 1144.. EExx CCoommmmaannddss
+
+ The following section describes the commands
+ available in the eexx editor. In each entry below, the
+ tag line is a usage synopsis for the command.
+
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5511
+
+
+ Each command can be entered as the abbreviation
+ (those characters in the synopsis command word preced-
+ ing the "[" character), the full command (all charac-
+ ters shown for the command word, omitting the "[" and
+ "]" characters), or any leading subset of the full com-
+ mand down to the abbreviation. For example, the args
+ command (shown as "aarr[[ggss]]" in the synopsis) can be
+ entered as "aarr", "aarrgg" or "aarrggss".
+
+ Each eexx command described below notes the new cur-
+ rent line after it is executed, as well as any options
+ that affect the command.
+
+ ""
+ A comment. Command lines beginning with the dou-
+ ble-quote character ("""") are ignored. This per-
+ mits comments in editor scripts and startup files.
+
+ <<eenndd--ooff--ffiillee>>
+ Scroll the screen. Write the next N lines, where
+ N is the value of the ssccrroollll option. The command
+ is the end-of-file terminal character, which may
+ be different on different terminals. Tradition-
+ ally, it is the <<ccoonnttrrooll--DD>> key.
+
+ Historically, the eeooff command ignored any preced-
+ ing count, and the <<eenndd--ooff--ffiillee>> character was
+ ignored unless it was entered as the first charac-
+ ter of the command. This implementation treats it
+ as a command _o_n_l_y if entered as the first charac-
+ ter of the command line, and otherwise treats it
+ as any other character.
+
+ Line: Set to the last line written.
+ Options: None.
+
+ !! aarrgguummeenntt((ss))
+ [[rraannggee]]!! aarrgguummeenntt((ss))
+ Execute a shell command, or filter lines through a
+ shell command. In the first synopsis, the remain-
+ der of the line after the "!!" character is passed
+ to the program named by the sshheellll option, as a
+ single argument.
+
+ Within the rest of the line, "%%" and "##" are
+ expanded into the current and alternate pathnames,
+ respectively. The character "!!" is expanded with
+ the command text of the previous !! command.
+ (Therefore, the command !!!! repeats the previous !!
+ command.) The special meanings of "%%", "##", and
+ "!!" can be overridden by escaping them with a
+ backslash. If no !! or ::!! command has yet been
+ executed, it is an error to use an unescaped "!!"
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--5522 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ character. The !! command does _n_o_t do shell
+ expansion on the strings provided as arguments.
+ If any of the above expansions change the command
+ the user entered, the command is redisplayed at
+ the bottom of the screen.
+
+ EExx then executes the program named by the sshheellll
+ option, with a --cc flag followed by the arguments
+ (which are bundled into a single argument).
+
+ The !! command is permitted in an empty file.
+
+ If the file has been modified since it was last
+ completely written, the command will warn you.
+
+ A single "!!" character is displayed when the com-
+ mand completes.
+
+ In the second form of the !! command, the remain-
+ der of the line after the "!!" is passed to the
+ program named by the sshheellll option, as described
+ above. The specified lines are passed to the pro-
+ gram as standard input, and the standard and stan-
+ dard error output of the program replace the orig-
+ inal lines.
+
+ Line: Unchanged if no range was specified, oth-
+ erwise set to the first line of the
+ range.
+ Options: Affected by the aauuttoowwrriittee and wwrriitteeaannyy
+ options.
+
+ [[rraannggee]] nnuu[[mmbbeerr]] [[ccoouunntt]] [[ffllaaggss]]
+ [[rraannggee]] ## [[ccoouunntt]] [[ffllaaggss]]
+ Display the selected lines, each preceded with its
+ line number.
+
+ The line number format is "%6d", followed by two
+ spaces.
+
+ Line: Set to the last line displayed.
+ Options: None.
+
+ @@ bbuuffffeerr
+ ** bbuuffffeerr
+ Execute a buffer. Each line in the named buffer
+ is executed as an eexx command. If no buffer is
+ specified, or if the specified buffer is "@@" or
+ "**", the last buffer executed is used.
+
+ [[rraannggee]] <<[[<< ......]] [[ccoouunntt]] [[ffllaaggss]]
+ Shift lines left or right. The specified lines
+ are shifted to the left (for the << command) or
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5533
+
+
+ right (for the >> command), by the number of
+ columns specified by the sshhiiffttwwiiddtthh option. Only
+ leading whitespace characters are deleted when
+ shifting left; once the first column of the line
+ contains a nonblank character, the sshhiifftt command
+ will succeed, but the line will not be modified.
+
+ If the command character << or >> is repeated more
+ than once, the command is repeated once for each
+ additional command character.
+
+ Line: If the current line is set to one of the
+ lines that are affected by the command,
+ it is unchanged. Otherwise, it is set to
+ the first nonblank character of the low-
+ est numbered line shifted.
+ Options: Affected by the sshhiiffttwwiiddtthh option.
+
+ [[lliinnee]] == [[ffllaaggss]]
+ Display the line number. Display the line number
+ of lliinnee (which defaults to the last line in the
+ file).
+
+ Line: Unchanged.
+ Options: None.
+
+ [[rraannggee]] >>[[>> ......]] [[ccoouunntt]] [[ffllaaggss]]
+ Shift right. The specified lines are shifted to
+ the right by the number of columns specified by
+ the sshhiiffttwwiiddtthh option, by inserting tab and space
+ characters. Empty lines are not changed.
+
+ If the command character ">>" is repeated more than
+ once, the command is repeated once for each addi-
+ tional command character.
+
+ Line: Set to the last line modified by the com-
+ mand.
+ Options: None.
+
+ aabb[[bbrreevv]] llhhss rrhhss
+ Add an abbreviation to the current abbreviation
+ list. In vvii, if llhhss is entered such that it is
+ preceded and followed by characters that cannot be
+ part of a word, it is replaced by the string rrhhss.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[lliinnee]] aa[[ppppeenndd]][[!!]]
+ The input text is appended to the specified line.
+ If line 0 is specified, the text is inserted at
+ the beginning of the file. Set to the last line
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--5544 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ input. If no lines are input, then set to lliinnee,
+ or to the first line of the file if a lliinnee of 0
+ was specified. Following the command name with a
+ "!!" character causes the aauuttooiinnddeenntt option to be
+ toggled for the duration of the command.
+
+ Line: Unchanged.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt,
+ bbeeaauuttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraapp--
+ mmaarrggiinn options.
+
+ aarr[[ggss]]
+ Display the argument list. The current argument
+ is displayed inside of "[[" and "]]" characters.
+ The argument list is the list of operands speci-
+ fied on startup, which can be replaced using the
+ nneexxtt command.
+
+ Line: Unchanged.
+ Options: None.
+
+ bbgg
+ VVii mode only. Background the current screen.
+
+ Line: Set to the current line when the screen
+ was last edited.
+ Options: None.
+
+ [[rraannggee]] cc[[hhaannggee]][[!!]] [[ccoouunntt]]
+ Replace the lines with input text. Following the
+ command name with a "!!" character causes the
+ aauuttooiinnddeenntt option to be toggled for the duration
+ of the command.
+
+ Line: Set to the last line input, or, if no
+ lines were input, set to the line before
+ the target line, or to the first line of
+ the file if there are no lines preceding
+ the target line.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt,
+ bbeeaauuttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraapp--
+ mmaarrggiinn options.
+
+ cchhdd[[iirr]][[!!]] [[ddiirreeccttoorryy]]
+ ccdd[[!!]] [[ddiirreeccttoorryy]]
+ Change the current working directory. The ddiirreecc--
+ ttoorryy argument is subjected to _s_h(1) word expan-
+ sions. When invoked with no directory argument
+ and the HHOOMMEE environment variable is set, the
+ directory named by the HHOOMMEE environment variable
+ becomes the new current directory. Otherwise, the
+ new current directory becomes the directory
+ returned by the _g_e_t_p_w_e_n_t(3) routine.
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5555
+
+
+ The cchhddiirr command will fail if the file has been
+ modified since the last complete write of the
+ file. You can override this check by appending a
+ "!!" character to the command.
+
+ Line: Unchanged.
+ Options: Affected by the ccddppaatthh option.
+
+ [[rraannggee]] ccoo[[ppyy]] lliinnee [[ffllaaggss]]
+ [[rraannggee]] tt lliinnee [[ffllaaggss]]
+ Copy the specified lines (range) after the desti-
+ nation line. Line 0 may be specified to insert
+ the lines at the beginning of the file.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[rraannggee]] dd[[eelleettee]] [[bbuuffffeerr]] [[ccoouunntt]] [[ffllaaggss]]
+ Delete the lines from the file. The deleted text
+ is saved in the specified buffer, or, if no buffer
+ is specified, in the unnamed buffer. If the com-
+ mand name is followed by a letter that could be
+ interpreted as either a buffer name or a flag
+ value (because neither a ccoouunntt or ffllaaggss values
+ were given), eexx treats the letter as a ffllaaggss value
+ if the letter immediately follows the command
+ name, without any whitespace separation. If the
+ letter is preceded by whitespace characters, it
+ treats it as a buffer name.
+
+ Line: Set to the line following the deleted
+ lines, or to the last line if the deleted
+ lines were at the end.
+ Options: None.
+
+ ddii[[ssppllaayy]] bb[[uuffffeerrss]] || ss[[ccrreeeennss]] || tt[[aaggss]]
+ Display buffers, screens or tags. The ddiissppllaayy
+ command takes one of three additional arguments,
+ which are as follows:
+
+ b[uffers]
+ Display all buffers (including named,
+ unnamed, and numeric) that contain text.
+ s[creens]
+ Display the file names of all background
+ screens.
+ t[ags] Display the tags stack.
+
+ Line: Unchanged.
+ Options: None.
+
+ ee[[ddiitt]][[!!]] [[++ccmmdd]] [[ffiillee]]
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--5566 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ eexx[[!!]] [[++ccmmdd]] [[ffiillee]]
+ Edit a different file. If the current buffer has
+ been modified since the last complete write, the
+ command will fail. You can override this by
+ appending a "!!" character to the command name.
+
+ If the "++ccmmdd" option is specified, that eexx command
+ will be executed in the new file. Any eexx command
+ may be used, although the most common use of this
+ feature is to specify a line number or search pat-
+ tern to set the initial location in the new file.
+
+ Line: If you have previously edited the file,
+ the current line will be set to your last
+ position in the file. If that position
+ does not exist, or you have not previ-
+ ously edited the file, the current line
+ will be set to the first line of the file
+ if you are in vvii mode, and the last line
+ of the file if you are in eexx.
+ Options: Affected by the aauuttoowwrriittee and wwrriitteeaannyy
+ options.
+
+ eexxuu[[ssaaggee]] [[ccoommmmaanndd]]
+ Display usage for an eexx command. If ccoommmmaanndd is
+ specified, a usage statement for that command is
+ displayed. Otherwise, usage statements for all eexx
+ commands are displayed.
+
+ Line: Unchanged.
+ Options: None.
+
+ ff[[iillee]] [[ffiillee]]
+ Display and optionally change the file name. If a
+ file name is specified, the current pathname is
+ changed to the specified name. The current path-
+ name, the number of lines, and the current posi-
+ tion in the file are displayed.
+
+ Line: Unchanged.
+ Options: None.
+
+ ffgg [[nnaammee]]
+ VVii mode only. Foreground the specified screen.
+ Swap the current screen with the specified back-
+ grounded screen. If no screen is specified, the
+ first background screen is foregrounded.
+
+ Line: Set to the current line when the screen
+ was last edited.
+ Options: None.
+
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5577
+
+
+ [[rraannggee]] gg[[lloobbaall]] //ppaatttteerrnn// [[ccoommmmaannddss]]
+ [[rraannggee]] vv //ppaatttteerrnn// [[ccoommmmaannddss]]
+ Apply commands to lines matching (or not matching)
+ a pattern. The lines within the given range that
+ match ("gg[[lloobbaall]]"), or do not match ("vv") the
+ given pattern are selected. Then, the specified
+ eexx command(s) are executed with the current line
+ ("..") set to each selected line. If no range is
+ specified, the entire file is searched for match-
+ ing, or not matching, lines.
+
+ Multiple commands can be specified, one per line,
+ by escaping each <<nneewwlliinnee>> character with a back-
+ slash, or by separating commands with a "||" char-
+ acter. If no commands are specified, the command
+ defaults to the pprriinntt command.
+
+ For the aappppeenndd, cchhaannggee and iinnsseerrtt commands, the
+ input text must be part of the global command
+ line. In this case, the terminating period can be
+ omitted if it ends the commands.
+
+ The vviissuuaall command may also be specified as one of
+ the eexx commands. In this mode, input is taken
+ from the terminal. Entering a QQ command in vvii
+ mode causes the next line matching the pattern to
+ be selected and vvii to be reentered, until the list
+ is exhausted.
+
+ The gglloobbaall, vv and uunnddoo commands cannot be used as
+ part of these commands.
+
+ The editor options aauuttoopprriinntt, aauuttooiinnddeenntt, and
+ rreeppoorrtt are turned off for the duration of the
+ gglloobbaall and vv commands.
+
+ Line: The last line modified.
+ Options: None.
+
+ hhee[[llpp]]
+ Display a help message.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[lliinnee]] ii[[nnsseerrtt]][[!!]]
+ The input text is inserted before the specified
+ line. Following the command name with a "!!"
+ character causes the aauuttooiinnddeenntt option setting to
+ be toggled for the duration of this command.
+
+ Line: Set to the last line input; if no lines
+ were input, set to the line before the
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--5588 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ target line, or to the first line of the
+ file if there are no lines preceding the
+ target line.
+ Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt,
+ bbeeaauuttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraapp--
+ mmaarrggiinn options.
+
+ [[rraannggee]] jj[[ooiinn]][[!!]] [[ccoouunntt]] [[ffllaaggss]]
+ Join lines of text together.
+
+ A ccoouunntt specified to the command specifies that
+ the last line of the rraannggee plus ccoouunntt subsequent
+ lines will be joined. (Note, this differs by one
+ from the general rule where only ccoouunntt- subsequent
+ lines are affected.)
+
+ If the current line ends with a whitespace charac-
+ ter, all whitespace is stripped from the next
+ line. Otherwise, if the next line starts with a
+ open parenthesis ("(("), do nothing. Otherwise, if
+ the current line ends with a question mark ("??"),
+ period ("..") or exclamation point ("!!"), insert
+ two spaces. Otherwise, insert a single space.
+
+ Appending a "!!" character to the command name
+ causes a simpler join with no white-space process-
+ ing.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[rraannggee]] ll[[iisstt]] [[ccoouunntt]] [[ffllaaggss]]
+ Display the lines unambiguously. Tabs are dis-
+ played as "^^II", and the end of the line is marked
+ with a "$$" character.
+
+ Line: Set to the last line displayed.
+ Options: None.
+
+ mmaapp[[!!]] [[llhhss rrhhss]]
+ Define or display maps (for vvii only).
+
+ If "llhhss" and "rrhhss" are not specified, the current
+ set of command mode maps are displayed. If a "!!"
+ character is appended to to the command, the text
+ input mode maps are displayed.
+
+ Otherwise, when the "llhhss" character sequence is
+ entered in vvii, the action is as if the correspond-
+ ing "rrhhss" had been entered. If a "!!" character
+ is appended to the command name, the mapping is
+ effective during text input mode, otherwise, it is
+ effective during command mode. This allows "llhhss"
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5599
+
+
+ to have two different macro definitions at the
+ same time: one for command mode and one for input
+ mode.
+
+ Whitespace characters require escaping with a
+ <<lliitteerraallnext> character to be entered in the llhhss
+ string in visual mode.
+
+ Normally, keys in the rrhhss string are remapped (see
+ the rreemmaapp option), and it is possible to create
+ infinite loops. However, keys which map to them-
+ selves are not further remapped, regardless of the
+ setting of the rreemmaapp option. For example, the
+ command "::mmaapp nn nnzz.." maps the "nn" key to the nn
+ and zz commands.
+
+ To exit an infinitely looping map, use the termi-
+ nal <<iinntteerrrruupptt>> character.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[lliinnee]] mmaa[[rrkk]] <<cchhaarraacctteerr>>
+ [[lliinnee]] kk <<cchhaarraacctteerr>>
+ Mark the line with the mark <<cchhaarraacctteerr>>. The
+ expressions "''<<cchhaarraacctteerr>>" and "``<<cchhaarraacctteerr>>" can
+ then be used as an address in any command that
+ uses one.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[rraannggee]] mm[[oovvee]] lliinnee
+ Move the specified lines after the target line. A
+ target line of 0 places the lines at the beginning
+ of the file.
+
+ Line: Set to the first of the moved lines.
+ Options: None.
+
+ mmkk[[eexxrrcc]][[!!]] ffiillee
+ Write the abbreviations, editor options and maps
+ to the specified file. Information is written in
+ a form which can later be read back in using the
+ eexx ssoouurrccee command. If ffiillee already exists, the
+ mmkkeexxrrcc command will fail. This check can be over-
+ ridden by appending a "!!" character to the com-
+ mand.
+
+ Line: Unchanged.
+ Options: None.
+
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--6600 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ nn[[eexxtt]][[!!]] [[ffiillee ......]]
+ Edit the next file from the argument list. The
+ nneexxtt command will fail if the file has been modi-
+ fied since the last complete write. This check
+ can be overridden by appending the "!!" character
+ to the command name. The argument list can
+ optionally be replaced by specifying a new one as
+ arguments to this command. In this case, editing
+ starts with the first file on the new list.
+
+ Line: Set as described for the eeddiitt command.
+ Options: Affected by the options aauuttoowwrriittee and
+ wwrriitteeaannyy.
+
+ [[lliinnee]] oo[[ppeenn]] //ppaatttteerrnn// [[ffllaaggss]]
+ Enter open mode. Open mode is the same as being
+ in vvii, but with a one-line window. All the stan-
+ dard vvii commands are available. If a match is
+ found for the optional RE argument, the cursor is
+ set to the start of the matching pattern.
+
+ _T_h_i_s _c_o_m_m_a_n_d _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_.
+
+ Line: Unchanged, unless the optional RE is
+ specified, in which case it is set to the
+ line where the matching pattern is found.
+ Options: Affected by the ooppeenn option.
+
+ pprree[[sseerrvvee]]
+ Save the file in a form that can later be recov-
+ ered using the eexx --rr option. When the file is
+ preserved, an email message is sent to the user.
+
+ Line: Unchanged.
+ Options: None.
+
+ pprreevv[[iioouuss]][[!!]]
+ Edit the previous file from the argument list.
+ The pprreevviioouuss command will fail if the file has
+ been modified since the last complete write. This
+ check can be overridden by appending the "!!"
+ character to the command name.
+
+ Line: Set as described for the eeddiitt command.
+ Options: Affected by the options aauuttoowwrriittee and
+ wwrriitteeaannyy. None.
+
+ [[rraannggee]] pp[[rriinntt]] [[ccoouunntt]] [[ffllaaggss]]
+ Display the specified lines.
+
+ Line: Set to the last line displayed.
+ Options: None.
+
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--6611
+
+
+ [[lliinnee]] ppuu[[tt]] [[bbuuffffeerr]]
+ Append buffer contents to the current line. If a
+ buffer is specified, its contents are appended to
+ the line, otherwise, the contents of the unnamed
+ buffer are used.
+
+ Line: Set to the line after the current line.
+ Options: None.
+
+ qq[[uuiitt]][[!!]]
+ End the editing session. If the file has been
+ modified since the last complete write, the qquuiitt
+ command will fail. This check may be overridden
+ by appending a "!!" character to the command.
+
+ If there are more files to edit, the qquuiitt command
+ will fail. Appending a "!!" character to the com-
+ mand name or entering two qquuiitt commands (i.e. wwqq,
+ qquuiitt, xxiitt or ZZZZ) in a row) will override this
+ check and the editor will exit.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[lliinnee]] rr[[eeaadd]][[!!]] [[ffiillee]]
+ Read a file. A copy of the specified file is
+ appended to the line. If lliinnee is 0, the copy is
+ inserted at the beginning of the file. If no file
+ is specified, the current file is read; if there
+ is no current file, then ffiillee becomes the current
+ file. If there is no current file and no ffiillee is
+ specified, then the rreeaadd command will fail.
+
+ If ffiillee is preceded by a "!!" character, ffiillee is
+ treated as if it were a shell command, and passed
+ to the program named by the SSHHEELLLL environment
+ variable. The standard and standard error outputs
+ of that command are read into the file after the
+ specified line. The special meaning of the "!!"
+ character can be overridden by escaping it with a
+ backslash ("\\") character.
+
+ Line: When executed from eexx, the current line
+ is set to the last line read. When exe-
+ cuted from vvii, the current line is set to
+ the first line read.
+ Options: None.
+
+ rreecc[[oovveerr]] ffiillee
+ Recover ffiillee if it was previously saved. If no
+ saved file by that name exists, the rreeccoovveerr com-
+ mand behaves similarly to the eeddiitt command.
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--6622 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ Line: Set as described for the eeddiitt command.
+ Options: None.
+
+ rreess[[iizzee]] [[++||--]]ssiizzee
+ VVii mode only. Grow or shrink the current screen.
+ If ssiizzee is a positive, signed number, the current
+ screen is grown by that many lines. If ssiizzee is a
+ negative, signed number, the current screen is
+ shrunk by that many lines. If ssiizzee is not signed,
+ the current screen is set to the specified ssiizzee.
+ Applicable only to split screens.
+
+ Line: Unchanged.
+ Options: None.
+
+ rreeww[[iinndd]][[!!]]
+ Rewind the argument list. If the current file has
+ been modified since the last complete write, the
+ rreewwiinndd command will fail. This check may be over-
+ ridden by appending the "!!" character to the com-
+ mand.
+
+ Otherwise, the current file is set to the first
+ file in the argument list.
+
+ Line: Set as described for the eeddiitt command.
+ Options: Affected by the aauuttoowwrriittee and wwrriitteeaannyy
+ options.
+
+ ssee[[tt]] [[ooppttiioonn[[==[[vvaalluuee]]]] ......]] [[nnooooppttiioonn ......]] [[ooppttiioonn??
+ ......]] [[aallll]]
+ Display or set editor options. When no arguments
+ are specified, the editor option tteerrmm, and any
+ editor options whose values have been changed from
+ the default settings are displayed. If the argu-
+ ment aallll is specified, the values of all of editor
+ options are displayed.
+
+ Specifying an option name followed by the charac-
+ ter "??" causes the current value of that option
+ to be displayed. The "??" can be separated from
+ the option name by whitespace characters. The "??"
+ is necessary only for Boolean valued options.
+ Boolean options can be given values by the form
+ "sseett ooppttiioonn" to turn them on, or "sseett nnooooppttiioonn" to
+ turn them off. String and numeric options can be
+ assigned by the form "sseett ooppttiioonn==vvaalluuee". Any
+ whitespace characters in strings can be included
+ literally by preceding each with a backslash.
+ More than one option can be set or listed by a
+ single set command, by specifying multiple argu-
+ ments, each separated from the next by whitespace
+ characters.
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--6633
+
+
+ Line: Unchanged.
+ Options: None.
+
+ sshh[[eellll]]
+ Run a shell program. The program named by the
+ sshheellll option is run with a --ii (for interactive)
+ flag. Editing is resumed when that program exits.
+
+ Line: Unchanged.
+ Options: None.
+
+ ssoo[[uurrccee]] ffiillee
+ Read and execute eexx commands from a file. SSoouurrccee
+ commands may be nested.
+
+ Line: Unchanged.
+ Options: None.
+
+ sspp[[lliitt]] [[ffiillee ......]]
+ VVii mode only. Split the screen. The current
+ screen is split into two screens, of approximately
+ equal size. If the cursor is in the lower half of
+ the screen, the screen will split up, i.e. the new
+ screen will be above the old one. If the cursor
+ is in the upper half of the screen, the new screen
+ will be below the old one.
+
+ If ffiillee is specified, the new screen is editing
+ that file, otherwise, both screens are editing the
+ same file, and changes in each will be be
+ reflected in the other. The argument list for the
+ new screen consists of the list of files specified
+ as arguments to this command, or, the current
+ pathname if no files are specified.
+
+ Line: If ffiillee is specified, set as for the eeddiitt
+ command, otherwise unchanged.
+ Options: None.
+
+ [[rraannggee]] ss[[uubbssttiittuuttee]] [[//ppaatttteerrnn//rreeppllaaccee//]] [[ooppttiioonnss]]
+ [[ccoouunntt]] [[ffllaaggss]]
+ [[rraannggee]] && [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]]
+ [[rraannggee]] ~~ [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]]
+ Make substitutions. Replace the first instance of
+ ppaatttteerrnn with the string rreeppllaaccee on the specified
+ line(s). If the "//ppaatttteerrnn//rreeppll//" argument is not
+ specified, the "//ppaatttteerrnn//rreeppll//" from the previous
+ ssuubbssttiittuuttee command is used.
+
+ If ooppttiioonnss includes the letter "cc" (confirm), you
+ will be prompted for confirmation before each
+ replacement is done. An affirmative response (in
+ English, a "yy" character) causes the replacement
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--6644 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ to be made. A quit response (in English, a "qq"
+ character) causes the ssuubbssttiittuuttee command to be
+ terminated. Any other response causes the
+ replacement not to be made, and the ssuubbssttiittuuttee
+ command continues. If ooppttiioonnss includes the letter
+ "gg" (global), all nonoverlapping instances of ppaatt--
+ tteerrnn in the line are replaced.
+
+ The && version of the command is the same as not
+ specifying a pattern or replacement string to the
+ ssuubbssttiittuuttee command, and the "&&" is replaced by the
+ pattern and replacement information from the pre-
+ vious substitute command.
+
+ The ~~ version of the command is the same as && and
+ ss, except that the search pattern used is the last
+ RE used in _a_n_y command, not necessarily the one
+ used in the last ssuubbssttiittuuttee command.
+
+ For example, in the sequence
+
+ ss//rreedd//bblluuee//
+ //ggrreeeenn
+ ~~
+
+ the "~~" is equivalent to "ss//ggrreeeenn//bblluuee//".
+
+ The ssuubbssttiittuuttee command may be interrupted, using
+ the terminal interrupt character. All substitu-
+ tions completed before the interrupt are retained.
+
+ Line: Set to the last line upon which a substi-
+ tution was made.
+ Options: None.
+
+ ssuu[[ssppeenndd]][[!!]]
+ sstt[[oopp]][[!!]]
+ <<ccoonnttrrooll--ZZ>>
+ Suspend the edit session. Appending a "!!" char-
+ acter to these commands turns off the aauuttoowwrriittee
+ option for the command.
+
+ Line: Unchanged.
+ Options: Affected by the aauuttoowwrriittee option.
+
+ ttaa[[gg]][[!!]] ttaaggssttrriinngg
+ Edit the file containing the specified tag.
+ Search for the tagstring, which can be in a dif-
+ ferent file. If the tag is in a different file,
+ then the new file is edited. If the current file
+ has been modified since the last complete write,
+ the ttaagg command will fail. This check can be
+ overridden by appending the "!!" character to the
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--6655
+
+
+ command name.
+
+ The ttaagg command searches for ttaaggssttrriinngg in the tags
+ file(s) specified by the option. (See _c_t_a_g_s(1)
+ for more information on tags files.)
+
+ Line: Set to the line indicated by the tag.
+ Options: Affected by the aauuttoowwrriittee, ttaagglleennggtthh,
+ ttaaggss and wwrriitteeaannyy options.
+
+ ttaaggpp[[oopp]][[!!]] [[ffiillee || nnuummbbeerr]]
+ Pop to the specified tag in the tags stack. If
+ neither ffiillee or nnuummbbeerr is specified, the ttaaggppoopp
+ command pops to the most recent entry on the tags
+ stack. If ffiillee or nnuummbbeerr is specified, the ttaaggppoopp
+ command pops to the most recent entry in the tags
+ stack for that file, or numbered entry in the tags
+ stack, respectively. (See the ddiissppllaayy command for
+ information on displaying the tags stack.)
+
+ If the file has been modified since the last com-
+ plete write, the ttaaggppoopp command will fail. This
+ check may be overridden by appending a "!!" char-
+ acter to the command name.
+
+ Line: Set to the line indicated by the tag.
+ Options: Affected by the aauuttoowwrriittee, and wwrriitteeaannyy
+ options.
+
+ ttaaggtt[[oopp]][[!!]]
+ Pop to the least recent tag on the tags stack,
+ clearing the tags stack.
+
+ If the file has been modified since the last com-
+ plete write, the ttaaggppoopp command will fail. This
+ check may be overridden by appending a "!!" char-
+ acter to the command name.
+
+ Line: Set to the line indicated by the tag.
+ Options: Affected by the aauuttoowwrriittee, and wwrriitteeaannyy
+ options.
+
+ uunnaa[[bbbbrreevv]] llhhss
+ Delete an abbreviation. Delete llhhss from the cur-
+ rent list of abbreviations.
+
+ Line: Unchanged.
+ Options: None.
+
+ uu[[nnddoo]]
+ Undo the last change made to the file. Changes
+ made by gglloobbaall, vv, vviissuuaall and map sequences are
+ considered a single command. If repeated, the uu
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--6666 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ command alternates between these two states, and
+ is its own inverse.
+
+ Line: Set to the last line modified by the com-
+ mand.
+ Options: None.
+
+ uunnmm[[aapp]][[!!]] llhhss
+ Unmap a mapped string. Delete the command mode
+ map definition for llhhss. If a "!!" character is
+ appended to the command name, delete the text
+ input mode map definition instead.
+
+ Line: Unchanged.
+ Options: None.
+
+ vvee[[rrssiioonn]]
+ Display the version of the eexx//vvii editor.
+
+ [[lliinnee]] vvii[[ssuuaall]] [[ttyyppee]] [[ccoouunntt]] [[ffllaaggss]]
+ EExx mode only. Enter vvii. The ttyyppee is optional,
+ and can be "--", "++" or "^^", as in the eexx zz com-
+ mand, to specify the the position of the specified
+ line in the screen window. (The default is to
+ place the line at the top of the screen window.)
+ A ccoouunntt specifies the number of lines that will
+ initially be displayed. (The default is the value
+ of the wwiinnddooww editor option.)
+
+ Line: Unchanged unless lliinnee is specified, in
+ which case it is set to that line.
+ Options: None.
+
+ vvii[[ssuuaall]][[!!]] [[++ccmmdd]] [[ffiillee]]
+ VVii mode only. Edit a new file. Identical to the
+ "eeddiitt[[!!]] [[++ccmmdd]] [[ffiillee]]" command.
+
+ vviiuu[[ssaaggee]] [[ccoommmmaanndd]]
+ Display usage for a vvii command. If ccoommmmaanndd is
+ specified, a usage statement for that command is
+ displayed. Otherwise, usage statements for all vvii
+ commands are displayed.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[rraannggee]] ww[[rriittee]][[!!]] [[>>>>]] [[ffiillee]]
+ [[rraannggee]] ww[[rriittee]] [[!!]] [[ffiillee]]
+ [[rraannggee]] wwnn[[!!]] [[>>>>]] [[ffiillee]]
+ [[rraannggee]] wwqq[[!!]] [[>>>>]] [[ffiillee]]
+ Write the file. The specified lines (the entire
+ file, if no range is given) is written to ffiillee.
+ If ffiillee is not specified, the current pathname is
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--6677
+
+
+ used. If ffiillee is specified, and it exists, or if
+ the current pathname was set using the ffiillee com-
+ mand, and the file already exists, these commands
+ will fail. Appending a "!!" character to the com-
+ mand name will override this check and the write
+ will be attempted, regardless.
+
+ Specifying the optional ">>>>" string will cause the
+ write to be appended to the file, in which case no
+ tests are made for the file already existing.
+
+ If the file is preceded by a "!!" character, the
+ program named in the SHELL environment variable is
+ invoked with file as its second argument, and the
+ specified lines are passed as standard input to
+ that command. The "!!" in this usage must be sep-
+ arated from command name by at least one whites-
+ pace character. The special meaning of the "!!"
+ may be overridden by escaping it with a backslash
+ ("\\") character.
+
+ The wwqq version of the write command will exit the
+ editor after writing the file, if there are no
+ further files to edit. Appending a "!!" character
+ to the command name or entering two "quit" com-
+ mands (i.e. wwqq, qquuiitt, xxiitt or ZZZZ) in a row) will
+ override this check and the editor will exit,
+ ignoring any files that have not yet been edited.
+
+ The wwnn version of the write command will move to
+ the next file after writing the file, unless the
+ write fails.
+
+ Line: Unchanged.
+ Options: Affected by the rreeaaddoonnllyy and wwrriitteeaannyy
+ options.
+
+ [[rraannggee]] xx[[iitt]][[!!]] [[ffiillee]]
+ Write the file if it has been modified. The spec-
+ ified lines are written to ffiillee, if the file has
+ been modified since the last complete write to any
+ file. If no rraannggee is specified, the entire file
+ is written.
+
+ The xxiitt command will exit the editor after writing
+ the file, if there are no further files to edit.
+ Appending a "!!" character to the command name or
+ entering two "quit" commands (i.e. wwqq, qquuiitt, xxiitt
+ or ZZZZ) in a row) will override this check and the
+ editor will exit, ignoring any files that have not
+ yet been edited.
+
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--6688 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss))
+
+
+ Line: Unchanged.
+ Options: Affected by the rreeaaddoonnllyy and wwrriitteeaannyy
+ options.
+
+ [[rraannggee]] yyaa[[nnkk]] [[bbuuffffeerr]] [[ccoouunntt]]
+ Copy the specified lines to a buffer. If no
+ buffer is specified, the unnamed buffer is used.
+
+ Line: Unchanged.
+ Options: None.
+
+ [[lliinnee]] zz [[ttyyppee]] [[ccoouunntt]] [[ffllaaggss]]
+ Adjust the window. If no ttyyppee is specified, then
+ ccoouunntt lines following the specified line are dis-
+ played. The default ccoouunntt is the value of the
+ wwiinnddooww option. The ttyyppee argument changes the
+ position at which lliinnee is displayed on the screen
+ by changing the number of lines displayed before
+ and after lliinnee. The following ttyyppee characters may
+ be used:
+
+ - Place the line at the bottom of the
+ screen.
+ + Place the line at the top of the screen.
+ . Place the line in the middle of the
+ screen.
+ ^ Write out count lines starting ccoouunntt ** 22
+ lines before lliinnee; the net effect of this
+ is that a "zz^^" command following a zz com-
+ mand writes the previous page.
+ = Center lliinnee on the screen with a line of
+ hyphens displayed immediately before and
+ after it. The number of preceding and
+ following lines of text displayed are
+ reduced to account for those lines.
+
+ Line: Set to the last line displayed, with the
+ exception of the ttyyppee, where the current
+ line is set to the line specified by the
+ command.
+ Options: Affected by the option.
+
+ 1155.. 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 abbreviations 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 abbrevia-
+ tions, it is only necessary to use the minimum number
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--6699
+
+
+ of characters 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
+ option. 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 oth-
+ erwise specified.
+
+ For information on modifying the options or to
+ display the options and their current values, see the
+ "set" command in the section entitled "EExx CCoommmmaannddss".
+
+ aallttwweerraassee [[ooffff]]
+ VVii only. Change how vvii does word erase during
+ text input. When this option is set, text is bro-
+ ken up into three classes: alphabetic, numeric and
+ underscore characters, other nonblank 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 path-
+ name components).
+
+ aauuttooiinnddeenntt,, aaii [[ooffff]]
+ 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 inserting text into the
+ middle of a line, any blank characters to the
+ right of the cursor are discarded, and the first
+ nonblank character to the right of the cursor is
+ aligned as described above.
+
+ The indent characters are themselves somewhat spe-
+ cial. If you do not enter more characters on the
+ new line before moving to another line, or enter-
+ ing <<eessccaappee>>, the indent character will be deleted
+ and the line will be empty. For example, if you
+ enter <<ccaarrrriiaaggee--rreettuurrnn>> twice in succession, the
+ line created by the first <<ccaarrrriiaaggee--rreettuurrnn>> will
+ not have any characters in it, regardless of the
+ indentation of the previous or subsequent line.
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--7700 NNvvii//NNeexx RReeffeerreennccee
+
+
+ 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 <<wwoorrdd--eerraassee>> character you
+ enter will erase up to end of the indent charac-
+ ters, and the second will erase back to the begin-
+ ning of the line. (Historically, only the <<ccoonn--
+ ttrrooll--DD>> key would erase the indent characters.
+ Both the <<ccoonnttrrooll--DD>> key and the usual erase keys
+ work in nnvvii.) In addition, if the cursor is posi-
+ tioned at the end of the indent characters, the
+ keys "00<<ccoonnttrrooll--DD>>" will erase all of the indent
+ characters for the current line, resetting the
+ indentation level to 0. Similarly, the keys
+ "^^<<ccoonnttrrooll--DD>>" will erase all of the indent char-
+ acters for the current line, leaving the indenta-
+ tion level for future created lines unaffected.
+
+ Finally, if the aauuttooiinnddeenntt option is set, the SS
+ and cccc commands change from the first nonblank of
+ the line to the end of the line, instead of from
+ the beginning of the line to the end of the line.
+
+ aauuttoopprriinntt,, aapp [[ooffff]]
+ EExx only. Cause the current line to be automati-
+ cally displayed 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.
+
+ aauuttoowwrriittee,, aaww [[ooffff]]
+ If this option is set, the vvii !!, ^^^^, ^^]] and <<ccoonn--
+ ttrrooll--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 character "!!"
+ 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.
+
+ bbeeaauuttiiffyy,, bbff [[ooffff]]
+ If this option is set, all control characters that
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7711
+
+
+ are not currently being specially interpreted,
+ other than <<ttaabb>>, <<nneewwlliinnee>>, and <<ffoorrmm--ffeeeedd>>, 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 affected by the bbeeaauu--
+ ttiiffyy option.
+
+ ccddppaatthh [[eennvviirroonnmmeenntt vvaarriiaabbllee CCDDPPAATTHH,, oorr ccuurrrreenntt ddiirreecc--
+ ttoorryy]]
+ This option is used to specify a colon separated
+ list of directories which are used as path pre-
+ fixes for any relative path names used as argu-
+ ments for the ccdd command. The value of this
+ option defaults to the value of the environmental
+ variable CCDDPPAATTHH 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 rela-
+ tive path names unless it is explicitly specified.
+ It may be so specified by entering an empty string
+ or a ".." character into the CCDDPPAATTHH variable or
+ the option value.
+
+ ccoolluummnnss,, ccoo [[8800]]
+ The number of columns in the screen. Setting this
+ option causes eexx/vvii to set (or reset) the environ-
+ mental variable CCOOLLUUMMNNSS. See the section entitled
+ "SSiizziinngg tthhee SSccrreeeenn" more information.
+
+ ccoommmmeenntt [[ooffff]]
+ 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-language comment
+ (probably a terribly boring legal notice) before
+ displaying the file.
+
+ ddiirreeccttoorryy,, ddiirr [[eennvviirroonnmmeenntt vvaarriiaabbllee TTMMPPDDIIRR,, oorr //ttmmpp]]
+ The directory where temporary files are created.
+ The environmental variable TTMMPPDDIIRR is used as the
+ default value if it exists, otherwise //ttmmpp is
+ used.
+
+ eeddccoommppaattiibbllee,, eedd [[ooffff]]
+ Remember the values of the "c" and "g" suffices to
+ the ssuubbssttiittuuttee commands, instead of initializing
+ them as unset for each new command. Specifying
+ pattern and replacement strings to the ssuubbssttiittuuttee
+ command unsets the "c" and "g" suffices as well.
+
+ eerrrroorrbbeellllss,, eebb [[ooffff]]
+ EExx only. EExx error messages are normally presented
+ in inverse video. If that is not possible for the
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--7722 NNvvii//NNeexx RReeffeerreennccee
+
+
+ terminal, setting this option causes error mes-
+ sages to be announced by ringing the terminal
+ bell.
+
+ eexxrrcc,, eexx [[ooffff]]
+ 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 section
+ entitled "SSttaarrttuupp IInnffoorrmmaattiioonn" for more informa-
+ tion.
+
+ eexxtteennddeedd [[ooffff]]
+ This option causes all regular expressions to be
+ treated as POSIX 1003.2 Extended Regular Expres-
+ sions (which are similar to historic _e_g_r_e_p(1)
+ style expressions).
+
+ ffllaasshh [[oonn]]
+ This option causes the screen to flash instead of
+ beeping the keyboard, on error, if the terminal
+ has the capability.
+
+ hhaarrddttaabbss,, hhtt [[88]]
+ 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 <<ttaabb>> characters to the ter-
+ minal, unlike historic versions of eexx/vvii, this
+ option does not currently have any affect.
+
+ iiggnnoorreeccaassee,, iicc [[ooffff]]
+ This option causes regular expressions, both in eexx
+ commands and in searches, to be evaluated in a
+ case-insensitive manner.
+
+ kkeeyyttiimmee [[66]]
+ The 10th's of a second eexx/vvii waits for a subse-
+ quent key to complete a key mapping.
+
+ lleeffttrriigghhtt [[ooffff]]
+ 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.
+
+ lliinneess,, llii [[2244]]
+ VVii only. The number of lines in the screen. Set-
+ ting this option causes eexx/vvii to set (or reset)
+ the environmental variable LLIINNEESS. See the section
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7733
+
+
+ entitled "SSiizziinngg tthhee SSccrreeeenn" for more information.
+
+ lliisspp [[ooffff]]
+ 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_.
+
+ lliisstt [[ooffff]]
+ This option causes lines to be displayed in an
+ unambiguous fashion. Specifically, tabs are dis-
+ played as control characters, i.e. "^^II", and the
+ ends of lines are marked with a "$$" character.
+
+ mmaaggiicc [[oonn]]
+ This option is on by default. Turning the mmaaggiicc
+ option off causes all regular expression charac-
+ ters except for "^^" and "$$", to be treated as
+ ordinary characters. To re-enable characters
+ individually, when the mmaaggiicc option is off, pre-
+ cede them with a backslash "\\" character. See the
+ section entitled "RReegguullaarr EExxpprreessssiioonnss aanndd RReeppllaaccee--
+ mmeenntt SSttrriinnggss" for more information.
+
+ mmaattcchhttiimmee [[77]]
+ VVii only. The 10th's of a second eexx/vvii pauses on
+ the matching character when the sshhoowwmmaattcchh option
+ is set.
+
+ mmeessgg [[oonn]]
+ This option allows other users to contact you
+ using the _t_a_l_k(1) and _w_r_i_t_e(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 _m_e_s_g(1) utility for
+ more information.
+
+ mmooddeelliinneess,, mmooddeelliinnee [[ooffff]]
+ If the mmooddeelliinneess option is set, eexx/vvii has histori-
+ cally 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 exe-
+ cuted.
+
+ Commands were recognized by the letters "e" or "v"
+ followed by "x" or "i", at the beginning of a line
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--7744 NNvvii//NNeexx RReeffeerreennccee
+
+
+ or following a tab or space character, and fol-
+ lowed by a ":", an eexx command, and another ":".
+
+ This option is a security problem of immense pro-
+ portions, and should not be used under any circum-
+ stances.
+
+ _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_.
+
+ nnuummbbeerr,, nnuu [[ooffff]]
+ Precede each line displayed with its current line
+ number.
+
+ ooccttaall [[ooffff]]
+ Display unknown characters as octal numbers,
+ instead of the default hexadecimal.
+
+ ooppeenn [[oonn]]
+ EExx only. If this option is not set, the ooppeenn and
+ vviissuuaall commands are disallowed.
+
+ ooppttiimmiizzee,, oopptt [[oonn]]
+ VVii only. Throughput of text is expedited by set-
+ ting the terminal not to 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_.
+
+ ppaarraaggrraapphhss,, ppaarraa [[IIPPLLPPPPPPQQPPPP LLIIppppllppiippbbpp]]
+ VVii only. Define additional paragraph boundaries
+ for the {{ and }} commands. The value of this
+ option must be a character string consisting of
+ zero or more character pairs.
+
+ In the text to be edited, the character string
+ <<nneewwlliinnee>>..<<cchhaarr--ppaaiirr>>, (where <<cchhaarr--ppaaiirr>> is one
+ of the character pairs in the option's value)
+ defines a paragraph boundary. For example, if the
+ option were set to LLaaAA<<ssppaaccee>>####, then all of the
+ following additional paragraph boundaries would be
+ recognized:
+
+
+ <newline>.La
+ <newline>.A<space>
+ <newline>.##
+
+
+ pprroommpptt [[oonn]]
+ EExx only. This option causes eexx to prompt for
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7755
+
+
+ command input with a "::" character; when it is not
+ set, no prompt is displayed.
+
+ rreeaaddoonnllyy,, rroo [[ooffff]]
+ 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.
+
+ rreeccddiirr [[//vvaarr//ttmmpp//vvii..rreeccoovveerr]]
+ The directory where recovery files are stored.
+
+ If you change the value of rreeccddiirr, be careful to
+ choose a directory whose contents are not regu-
+ larly deleted. Bad choices include directories in
+ memory based filesystems, or //ttmmpp, on most sys-
+ tems, as their contents are removed when the
+ machine is rebooted.
+
+ Public directories like //uussrr//ttmmpp and //vvaarr//ttmmpp are
+ usually safe, although some sites periodically
+ prune old files from them. There is no require-
+ ment that you use a public directory, e.g. a sub-
+ directory of your home directory will work fine.
+
+ Finally, if you change the value of rreeccddiirr, you
+ must modify the recovery script to operate in your
+ chosen recovery area.
+
+ See the section entitled "RReeccoovveerryy" for further
+ information.
+
+ rreeddrraaww,, rree [[ooffff]]
+ VVii only. The editor simulates (using great
+ amounts of output), an intelligent terminal on a
+ dumb terminal (e.g. during insertions in vvii 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_.
+
+ rreemmaapp [[oonn]]
+ If this option is set, it is possible to define
+ macros in terms of other macros. Otherwise, each
+ key is only remapped up to one time. For example,
+ if "AA" is mapped to "BB", and "BB" is mapped to "CC",
+ The keystroke "AA" will be mapped to "CC" if the
+ rreemmaapp option is set, and to "BB" if it is not set.
+
+ rreeppoorrtt [[55]]
+ Set the threshold of the number of lines that need
+ to be changed or yanked before a message will be
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--7766 NNvvii//NNeexx RReeffeerreennccee
+
+
+ displayed to the user. For everything but the
+ yank command, the value is the largest value about
+ which the editor is silent, i.e. by default, 6
+ lines must be deleted before the user is notified.
+ However, if the number of lines yanked is greater
+ than _o_r _e_q_u_a_l _t_o the set value, it is reported to
+ the user.
+
+ rruulleerr [[ooffff]]
+ VVii only. Display a row/column ruler on the colon
+ command line.
+
+ ssccrroollll,, ssccrr [[wwiinnddooww // 22]]
+ Set the number of lines scrolled by the vvii <<ccoonn--
+ ttrrooll--DD>> and <<ccoonnttrrooll--UU>> commands.
+
+ Historically, the eexx zz 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.
+
+ sseeccttiioonnss,, sseecctt [[NNHHSSHHHH HHUUnnhhsshh]]
+ 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 <<nneewwlliinnee>>..<<cchhaarr--
+ ppaaiirr>>, (where <<cchhaarr--ppaaiirr>> is one of the character
+ pairs in the option's value), defines a section
+ boundary in the same manner that ppaarraaggrraapphh option
+ boundaries are defined.
+
+ sshheellll,, sshh [[eennvviirroonnmmeenntt vvaarriiaabbllee SSHHEELLLL,, oorr //bbiinn//sshh]]
+ Select the shell used by the editor. The speci-
+ fied 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.
+
+ sshhiiffttwwiiddtthh,, ssww [[88]]
+ Set the autoindent and shift command indentation
+ width. This width is used by the aauuttooiinnddeenntt
+ option and by the <<, >>, and sshhiifftt commands.
+
+ sshhoowwddiirrttyy [[ooffff]]
+ VVii only. Display an asterisk on the colon command
+ line if the file has been modified.
+
+ sshhoowwmmaattcchh,, ssmm [[ooffff]]
+ VVii only. This option causes vvii, when a "}}" or "))"
+ is entered, to briefly move the cursor the match-
+ ing "{{" or "((". See the mmaattcchhttiimmee option for more
+ information.
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7777
+
+
+ sshhoowwmmooddee [[ooffff]]
+ VVii only. This option causes vvii to display a
+ string identifying the current editor mode on the
+ colon command line.
+
+ ssiiddeessccrroollll [[1166]]
+ 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
+ information.
+
+ sslloowwooppeenn,, ssllooww [[ooffff]]
+ 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_.
+
+ ssoouurrcceeaannyy [[ooffff]]
+ If this option is turned on, vvii historically read
+ startup files that were owned by someone other
+ than the editor user. See the section entitled
+ "SSttaarrttuupp IInnffoorrmmaattiioonn" for more information. This
+ option is a security problem of immense propor-
+ tions, and should not be used under any circum-
+ stances.
+
+ _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_.
+
+ ttaabbssttoopp,, ttss [[88]]
+ This option sets tab widths for the editor dis-
+ play.
+
+ ttaagglleennggtthh,, ttll [[00]]
+ 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.
+
+ ttaaggss,, ttaagg [[ttaaggss //vvaarr//ddbb//lliibbcc..ttaaggss //ssyyss//kkeerrnn//ttaaggss]]
+ Sets the list of tags files, in search order,
+ which are used when the editor searches for a tag.
+
+ tteerrmm,, ttttyyttyyppee,, ttttyy [[eennvviirroonnmmeenntt vvaarriiaabbllee TTEERRMM]]
+ Set the terminal type. Setting this option causes
+ eexx/vvii to set (or reset) the environmental variable
+ TTEERRMM.
+
+ tteerrssee [[ooffff]]
+ This option has historically made editor messages
+ less verbose. It has no effect in this
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--7788 NNvvii//NNeexx RReeffeerreennccee
+
+
+ implementation. See the vveerrbboossee option for more
+ information.
+
+ ttiillddeeoopp
+ Modify the ~~ command to take an associated motion.
+
+ ttiimmeeoouutt,, ttoo [[oonn]]
+ If this option is set, eexx/vvii waits for a specific
+ period for a subsequent key to complete a key map-
+ ping (see the kkeeyyttiimmee 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.
+
+ ttttyywweerraassee [[ooffff]]
+ 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 charac-
+ ters and nonblank characters. Changing from one
+ class to another marks the end of a word.
+
+ vveerrbboossee [[ooffff]]
+ VVii only. VVii 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 dis-
+ played for all errors.
+
+ ww330000 [[nnoo ddeeffaauulltt]]
+ VVii only. Set the window size if the baud rate is
+ less than 1200 baud. See the wwiinnddooww option for
+ more information.
+
+ ww11220000 [[nnoo ddeeffaauulltt]]
+ VVii only. Set the window size if the baud rate is
+ equal to 1200 baud. See the wwiinnddooww option for
+ more information.
+
+ ww99660000 [[nnoo ddeeffaauulltt]]
+ VVii only. Set the window size if the baud rate is
+ greater than 1200 baud. See the wwiinnddooww option for
+ more information.
+
+ wwaarrnn [[oonn]]
+ 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.
+
+ wwiinnddooww,, ww,, wwii [[eennvviirroonnmmeenntt vvaarriiaabbllee LLIINNEESS]]
+ 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 <<ccoonnttrrooll--FF>> and <<ccoonnttrrooll--BB>>. The
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7799
+
+
+ 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 section entitled
+ "SSiizziinngg tthhee SSccrreeeenn" for more information). Set-
+ ting the value of the wwiinnddooww option is the same as
+ using the --ww command line option.
+
+ If the value of the wwiinnddooww option (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 perfor-
+ mance improvement when viewing different places in
+ one or more files over a slow link.
+
+ wwrraappmmaarrggiinn,, wwmm [[00]]
+ VVii only. If the value of the wwrraappmmaarrggiinn option is
+ non-zero, vvii will split lines so that they end at
+ least that number of characters before the right-
+ hand margin of the screen. (Note, the value of
+ wwrraappmmaarrggiinn is _n_o_t a text length. In a screen that
+ is 80 columns wide, the command "::sseett wwrraappmmaarr--
+ ggiinn==88" attempts to keep the lines less than or
+ equal to 72 columns wide.)
+
+ Lines are split at the previous whitespace charac-
+ ter closest to the number. Any trailing whites-
+ pace characters before that character are deleted.
+ If the line is split because of an inserted
+ <<ssppaaccee>> or <<ttaabb>> character, and you then enter
+ another <<ssppaaccee>> character, it is discarded.
+
+ If wrapmargin is set to 0, or if there is no blank
+ character upon which to split the line, the line
+ is not broken.
+
+ wwrraappssccaann,, wwss [[oonn]]
+ 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.
+
+ wwrriitteeaannyy,, wwaa [[ooffff]]
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--8800 NNvvii//NNeexx RReeffeerreennccee
+
+
+ 1166.. AAddddiittiioonnaall FFeeaattuurreess iinn NNeexx//NNvvii
+
+ There are a few features in nneexx/nnvvii that are not
+ found in historic versions of eexx/vvii. Some of the more
+ interesting of those features are as follows:
+
+ 88--bbiitt cclleeaann ddaattaa,, llaarrggee lliinneess,, ffiilleess
+ NNeexx/nnvvii will edit any format file. Line lengths
+ are limited by available memory, and file sizes
+ are limited by available disk space. The vvii text
+ input mode command <<ccoonnttrrooll--XX>> can insert any pos-
+ sible character value into the text.
+
+ SSpplliitt ssccrreeeennss
+ The sspplliitt command divides the screen into multiple
+ editing regions. The <<ccoonnttrrooll--WW>> command rotates
+ between the foreground screens. The rreessiizzee com-
+ mand can be used to grow or shrink a particular
+ screen.
+
+ BBaacckkggrroouunndd aanndd ffoorreeggrroouunndd ssccrreeeennss
+ The bbgg command backgrounds the current screen, and
+ the ffgg command foregrounds backgrounded screens.
+ The ddiissppllaayy command can be used to list the back-
+ ground screens.
+
+ TTaagg ssttaacckkss
+ Tags are now maintained in a stack. The <<ccoonnttrrooll--
+ TT>> command returns to the previous tag location.
+ The ttaaggppoopp command 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 a specified file. The ddiissppllaayy command
+ can be used to list the tags stack. The ttaaggttoopp
+ command returns to the top of the tag stack.
+
+ NNeeww ddiissppllaayyss
+ The ddiissppllaayy command can be used to display the
+ current buffers, the backgrounded screens, and the
+ tags stack.
+
+ IInnffiinniittee uunnddoo
+ Changes made during an edit session may be rolled
+ backward and forward. A .. command immediately
+ after a uu command continues either forward or
+ backward depending on whether the uu command was an
+ undo or a redo.
+
+ UUssaaggee iinnffoorrmmaattiioonn
+ The eexxuussaaggee and vviiuussaaggee commands provide usage
+ information for all of the eexx and vvii commands by
+ default, or, optionally, for a specific command or
+ key.
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--8811
+
+
+ EExxtteennddeedd RReegguullaarr EExxpprreessssiioonnss
+ The eexxtteennddeedd option causes Regular Expressions to
+ be interpreted as as Extended Regular Expressions,
+ (i.e. _e_g_r_e_p(1) style Regular Expressions).
+
+ WWoorrdd sseeaarrcchh
+ The <<ccoonnttrrooll--AA>> command searches for the word ref-
+ erenced by the cursor.
+
+ NNuummbbeerr iinnccrreemmeenntt
+ The ## command increments or decrements the number
+ referenced by the cursor.
+
+ PPrreevviioouuss ffiillee
+ The pprreevviioouuss command edits the previous file from
+ the argument list.
+
+ LLeefftt--rriigghhtt ssccrroolllliinngg
+ The lleeffttrriigghhtt option causes nnvvii to do left-right
+ screen scrolling, instead of the traditional vvii
+ line wrapping.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--8822 NNvvii//NNeexx RReeffeerreennccee
+
+
+ 1177.. IInnddeexx
+
+ ! 15, 34 @ 20, 35 columns 47
+ "" 34 A 20 comment 47
+ # 16, 35 B 20 copy 36
+ $ 16 C 21 count 10, 33
+ % 16 D 21 current pathname 8
+ & 17, 42 E 21 d 26
+ ( 17 F 21 delete 37
+ ) 17 G 21 directory 47
+ * 35 H 21 display 37
+ + 13 I 22 e 26
+ , 18 J 22 edcompatible47
+ /RE/ 18 L 22 edit 37
+ 0 19 M 22 errorbells 47
+ 0<control-D>31 N 18 exrc 47
+ : 19 O 22 extended 48
+ ; 19 P 23 exusage 37
+ < 20, 35 Q 23 f 26
+ <control-A> 11 R 23 fg 37
+ <control-B> 11 S 23 file 33, 37
+ <control-1D2>, 31 T 23 flags 33
+ <control-E> 12 U 23 flash 48
+ <control-F> 12 W 24 global 38
+ <control-G> 12 X 24 hardtabs 48
+ <control-1H2>, 31 Y 24 help 38
+ <control-J> 13 ZZ 24 i 26
+ <control-L> 13 [[ 24 ignorecase 48
+ <control-M> 13 - 18 insert 38
+ <control-N> 13 ]] 25 j 13
+ <control-P> 13 ^ 25 join 38
+ <control-R> 13 ^<control-D>31 k 13, 39
+ <control-1T4>, 31 _ 25 keytime 48
+ <control-U> 14 `<character>17 l 15
+ <control-1W4>, 31 a 25 leftright 48
+ <control-X> 31 abbrev 35 line 33
+ <control-Y> 14 alternate pathname 8 lines 48
+ <control-1Z4>, 43 altwerase 46 lisp 48
+ <control-]> 15 append 36 list 39, 48
+ <control-^> 15 args 36 m 27
+ <end-of-file> 34 autoindent 46 magic 48
+ <eof> 33 autoprint 46 map 39
+ <erase> 31 autowrite 47 mark 39
+ <escape>14, 31 b 25 matchtime 48
+ <inter7r,up3t0>, 31 beautify 47 mesg 48
+ <line erase>31 bg 36 mkexrc 39
+ <literal next> 7, 31 bigword 10 modelines 49
+ <nul> 30 buffer 8 motion 10
+ <space> 15 c 26 move 39
+ <word erase>31 cd 36 n 18
+ = 35 cdpath 47 next 40
+ > 20, 35 change 36 number 35, 49
+ ?RE? 18 chdir 36 o 27
+
+
+
+
+
+
+
+
+
+
+NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--8833
+
+
+ octal 49 tildeop 51
+ open 40, 49 timeout 51
+ optimize 49 ttywerase 52
+ p 27 u 28
+ paragraph 11 unabbrev 44
+ paragraphs 49 undo 44
+ preserve 40 unmap 44
+ previous 40 unnamed buffer 8
+ previous context 9 v 38
+ print 40 verbose 52
+ prompt 49 version 44
+ put 40 visual 44
+ quit 41 viusage 44
+ r 27 w 28
+ range 33 w1200 52
+ read 41 w300 52
+ readonly 49 w9600 52
+ recdir 49 warn 52
+ recover 41 window 52
+ redraw 50 wn 44
+ remap 50 word 10
+ report 50 wq 44
+ resize 41 wrapmargin 52
+ rewind 41 wrapscan 52
+ ruler 50 write 44
+ s 27 writeany 53
+ scroll 50 x 28
+ section 11 xit 45
+ sections 50 y 28
+ sentence 11 yank 45
+ set 41 z 28, 45
+ shell 42, 50 { 29
+ shiftwidth 50 | 29
+ showdirty 51 } 29
+ showmatch 51 ~ 29, 30, 42
+ showmode 51
+ sidescroll 51
+ slowopen 51
+ source 42
+ sourceany 51
+ split 42
+ stop 43
+ substitute 42
+ suspend 43
+ t 27, 36
+ tabstop 51
+ tag 43
+ taglength 51
+ tagpop 43
+ tags 51
+ tagtop 43
+ term 51
+ terse 51
+
+
+
+
+
+
+
+
+
+
+UUSSDD::1133--22 NNvvii//NNeexx RReeffeerreennccee
+
+
+ TTaabbllee ooff CCoonntteennttss
+
+ Description ...................................... 3
+ Startup Information .............................. 3
+ Recovery ......................................... 4
+ Sizing the Screen ................................ 7
+ Character Display ................................ 7
+ Multiple Screens ................................. 8
+ Regular Expressions and Replacement Strings ...... 9
+ General Editor Description ....................... 10
+ Vi Description ................................... 12
+ Vi Commands ...................................... 17
+ Vi Text Input Commands ........................... 45
+ Ex Addressing .................................... 47
+ Ex Description ................................... 49
+ Ex Commands ...................................... 50
+ Set Options ...................................... 68
+ Additional Features in Nex/Nvi ................... 79
+ Index ............................................ 82
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usr.bin/vi/USD.doc/vitut/Makefile b/usr.bin/vi/USD.doc/vitut/Makefile
new file mode 100644
index 000000000000..bfb29bff32e8
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vitut/Makefile
@@ -0,0 +1,17 @@
+# @(#)Makefile 8.1 (Berkeley) 8/14/93
+
+DIR= usd/12.vi
+SRCS= vi.in vi.chars
+MACROS= -msU
+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/USD.doc/vitut/vi.apwh.ms b/usr.bin/vi/USD.doc/vitut/vi.apwh.ms
new file mode 100644
index 000000000000..d0b62611c701
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vitut/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/USD.doc/vitut/vi.chars b/usr.bin/vi/USD.doc/vitut/vi.chars
new file mode 100644
index 000000000000..147c4ff7f2d8
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vitut/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/USD.doc/vitut/vi.in b/usr.bin/vi/USD.doc/vitut/vi.in
new file mode 100644
index 000000000000..3bdfeb95b65e
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vitut/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/USD.doc/vitut/vi.summary b/usr.bin/vi/USD.doc/vitut/vi.summary
new file mode 100644
index 000000000000..a7d99384dc86
--- /dev/null
+++ b/usr.bin/vi/USD.doc/vitut/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/common/Makefile b/usr.bin/vi/common/Makefile
new file mode 100644
index 000000000000..b24e9414a5c6
--- /dev/null
+++ b/usr.bin/vi/common/Makefile
@@ -0,0 +1,98 @@
+# @(#)Makefile 8.47 (Berkeley) 8/14/94
+
+PROG= nvi
+#CFLAGS=-g -DDEBUG
+#CFLAGS+=-pg
+CFLAGS+=-I. -I${.CURDIR}
+#STRIP=
+.PATH: ${.CURDIR}/../common ${.CURDIR}/../ex ${.CURDIR}/../sex \
+ ${.CURDIR}/../vi ${.CURDIR}/../svi ${.CURDIR}/../xaw
+CLEANFILES+=nex
+
+# General sources.
+SRCS= cut.c delete.c exf.c line.c log.c main.c mark.c msg.c options.c \
+ options_f.c put.c screen.c search.c seq.c signal.c recover.c \
+ term.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 ex_bang.c \
+ ex_cd.c ex_delete.c ex_digraph.c ex_display.c ex_edit.c ex_equal.c \
+ ex_exit.c ex_file.c ex_global.c ex_init.c ex_join.c ex_map.c \
+ ex_mark.c ex_mkexrc.c ex_move.c ex_open.c ex_preserve.c ex_print.c \
+ ex_put.c ex_read.c ex_screen.c ex_script.c ex_set.c ex_shell.c \
+ ex_shift.c ex_source.c ex_stop.c ex_subst.c ex_tag.c ex_undo.c \
+ ex_usage.c ex_util.c ex_version.c ex_visual.c ex_write.c ex_yank.c \
+ ex_z.c excmd.c filter.c
+
+# Ex screen source.
+SRCS+= sex_confirm.c sex_get.c sex_refresh.c sex_screen.c sex_term.c \
+ sex_util.c sex_window.c
+
+# Vi source.
+SRCS+= getc.c v_ch.c v_delete.c v_ex.c v_increment.c v_init.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_status.c v_stop.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_curses.c svi_ex.c svi_get.c svi_line.c \
+ svi_refresh.c svi_relative.c svi_screen.c svi_smap.c svi_split.c \
+ svi_term.c svi_util.c
+
+# Athena widget set screen source.
+SRCS+= xaw_screen.c
+
+#LDADD+=-pg
+DPADD+= ${LIBCURSES} ${LIBTERM} ${LIBUTIL}
+LDADD+= -lcurses -ltermlib -lutil
+SPECHDR=compat.h excmd.h options.h
+CLEANFILES+=${SPECHDR}
+LINKS= ${BINDIR}/nvi ${BINDIR}/nex
+
+all: nvi nex vi.0
+nex: nvi
+ rm -f nex
+ ln nvi nex
+
+nvi: compat.h options.h excmd.h
+
+compat.h:
+ :> compat.h
+
+options.h: options.h.stub options.c options.awk
+ rm -f options.h
+ cat ${.CURDIR}/options.h.stub > options.h
+ awk -f ${.CURDIR}/options.awk ${.CURDIR}/options.c >> options.h
+
+excmd.h: excmd.h.stub excmd.c excmd.awk
+ rm -f excmd.h
+ cat ${.CURDIR}/../ex/excmd.h.stub > excmd.h
+ awk -f ${.CURDIR}/../ex/excmd.awk ${.CURDIR}/../ex/excmd.c >> excmd.h
+
+vi.0:
+ rm -f vi.0
+ ln -s ${.CURDIR}/../USD.doc/vi.man/vi.0 vi.0
+
+tags::
+ -(cd ${.CURDIR} && rm -f tags && \
+ ctags ../common/*.[ch] ../common/*.stub ../ex/*.[ch] ../ex/*.stub \
+ ../vi/*.[ch] ../sex/*.[ch] ../svi/*.[ch] ../xaw/*.[ch])
+
+warn:: ${SRCS}
+ -(cd ${.CURDIR} && gcc -Wall -O4 -DDEBUG \
+ -Iobj -I. ${.ALLSRC} -lcurses -ltermlib 2>&1 | \
+ sed -e "/warning: .*sccsid.*defined but not used/d" \
+ -e "/warning: suggest parentheses around/d" \
+ -e "/In function /d" \
+ -e "/At top level:/d" \
+ -e "/warning: .*inline call to/d" \
+ -e "/warning: comparison is always 1 due /d") > \
+ ${.CURDIR}/WARN.OUT
+
+MAN= ${.CURDIR}/../USD.doc/vi.man
+REF= ${.CURDIR}/../USD.doc/vi.ref
+
+.include <bsd.prog.mk>
+
+.depend: ${SPECHDR}
diff --git a/usr.bin/vi/common/args.h b/usr.bin/vi/common/args.h
new file mode 100644
index 000000000000..5e127dec9b34
--- /dev/null
+++ b/usr.bin/vi/common/args.h
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ *
+ * @(#)args.h 8.5 (Berkeley) 7/17/94
+ */
+
+/*
+ * Structure for building "argc/argv" vector of arguments.
+ *
+ * !!!
+ * All arguments are nul terminated as well as having an associated length.
+ * The argument vector is NOT necessarily NULL terminated. The proper way
+ * to check the number of arguments is to use the argc value in the EXCMDARG
+ * structure or to walk the array until an ARGS structure with a length of 0
+ * is found.
+ */
+typedef struct _args {
+ CHAR_T *bp; /* Argument. */
+ size_t blen; /* Buffer length. */
+ size_t len; /* Argument length. */
+
+#define A_ALLOCATED 0x01 /* If allocated space. */
+ u_int8_t flags;
+} ARGS;
diff --git a/usr.bin/vi/common/cut.c b/usr.bin/vi/common/cut.c
new file mode 100644
index 000000000000..df86a95983b0
--- /dev/null
+++ b/usr.bin/vi/common/cut.c
@@ -0,0 +1,366 @@
+/*-
+ * 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[] = "@(#)cut.c 8.32 (Berkeley) 7/28/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+static int cb_rotate __P((SCR *));
+
+/*
+ * cut --
+ * Put a range of lines/columns into a TEXT buffer.
+ *
+ * There are two buffer areas, both found in the global structure. The first
+ * is the linked list of all the buffers the user has named, the second is the
+ * unnamed buffer storage. There is a pointer, too, which is the current
+ * default buffer, i.e. it may point to the unnamed buffer or a named buffer
+ * depending on into what buffer the last text was cut. Logically, in both
+ * delete and yank operations, if the user names a buffer, the text is cut
+ * into it. 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 cut into the buffer named
+ * '1'. The text is always cut into the unnamed buffer.
+ *
+ * In all cases, upper-case buffer names are the same as lower-case names,
+ * with the exception that they cause the buffer to be appended to instead
+ * of replaced. Note, however, that if text is appended to a buffer, the
+ * default buffer only contains the appended text, not the entire contents
+ * of the buffer.
+ *
+ * !!!
+ * 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, and here
+ * we just treat the numeric buffers like any other named buffer.
+ */
+int
+cut(sp, ep, namep, fm, tm, flags)
+ SCR *sp;
+ EXF *ep;
+ CHAR_T *namep;
+ int flags;
+ MARK *fm, *tm;
+{
+ CB *cbp;
+ CHAR_T name;
+ recno_t lno;
+ int append, copy_one, copy_def;
+
+ /*
+ * If the user specified a buffer, put it there. (This may require
+ * a copy into the numeric buffers. We do the copy so that we don't
+ * have to reference count and so we don't have to deal with things
+ * like appends to buffers that are used multiple times.)
+ *
+ * Otherwise, if it's supposed to be put in a numeric buffer (usually
+ * a delete) put it there. The rules for putting things in numeric
+ * buffers were historically a little strange. There were three cases.
+ *
+ * 1: Some motions are always line mode motions, which means
+ * that the cut always goes into the numeric buffers.
+ * 2: Some motions aren't line mode motions, e.g. d10w, but
+ * can cross line boundaries. For these commands, if the
+ * cut crosses a line boundary, it goes into the numeric
+ * buffers. This includes most of the commands.
+ * 3: Some motions aren't line mode motions, e.g. d`<char>,
+ * but always go into the numeric buffers, regardless. This
+ * was the commands: % ` / ? ( ) N n { } -- and nvi adds ^A.
+ *
+ * Otherwise, put it in the unnamed buffer.
+ */
+ append = copy_one = copy_def = 0;
+ if (namep != NULL) {
+ name = *namep;
+ if (LF_ISSET(CUT_NUMREQ) || LF_ISSET(CUT_NUMOPT) &&
+ (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) {
+ copy_one = 1;
+ cb_rotate(sp);
+ }
+ if ((append = isupper(name)) == 1) {
+ if (!copy_one)
+ copy_def = 1;
+ name = tolower(name);
+ }
+namecb: CBNAME(sp, cbp, name);
+ } else if (LF_ISSET(CUT_NUMREQ) || LF_ISSET(CUT_NUMOPT) &&
+ (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) {
+ name = '1';
+ cb_rotate(sp);
+ goto namecb;
+ } else
+ cbp = &sp->gp->dcb_store;
+
+copyloop:
+ /*
+ * If this is a new buffer, create it and add it into the list.
+ * Otherwise, if it's not an append, free its current contents.
+ */
+ if (cbp == NULL) {
+ CALLOC_RET(sp, cbp, CB *, 1, sizeof(CB));
+ cbp->name = name;
+ CIRCLEQ_INIT(&cbp->textq);
+ LIST_INSERT_HEAD(&sp->gp->cutq, cbp, q);
+ } else if (!append) {
+ text_lfree(&cbp->textq);
+ cbp->len = 0;
+ cbp->flags = 0;
+ }
+
+
+#define ENTIRE_LINE 0
+ /* In line mode, it's pretty easy, just cut the lines. */
+ if (LF_ISSET(CUT_LINEMODE)) {
+ cbp->flags |= CB_LMODE;
+ for (lno = fm->lno; lno <= tm->lno; ++lno)
+ if (cut_line(sp, ep, lno, 0, 0, cbp))
+ goto cut_line_err;
+ } else {
+ /*
+ * Get the first line. A length of 0 causes cut_line
+ * to cut from the MARK to the end of the line.
+ */
+ if (cut_line(sp, ep, fm->lno, fm->cno, fm->lno != tm->lno ?
+ ENTIRE_LINE : (tm->cno - fm->cno) + 1, cbp))
+ goto cut_line_err;
+
+ /* Get the intermediate lines. */
+ for (lno = fm->lno; ++lno < tm->lno;)
+ if (cut_line(sp, ep, lno, 0, ENTIRE_LINE, cbp))
+ goto cut_line_err;
+
+ /* Get the last line. */
+ if (tm->lno != fm->lno &&
+ cut_line(sp, ep, lno, 0, tm->cno + 1, cbp)) {
+cut_line_err: text_lfree(&cbp->textq);
+ cbp->len = 0;
+ cbp->flags = 0;
+ return (1);
+ }
+ }
+
+ append = 0; /* Only append to the named buffer. */
+ sp->gp->dcbp = cbp; /* Repoint the default buffer on each pass. */
+
+ if (copy_one) { /* Copy into numeric buffer 1. */
+ name = '1';
+ CBNAME(sp, cbp, name);
+ copy_one = 0;
+ goto copyloop;
+ }
+ if (copy_def) { /* Copy into the default buffer. */
+ cbp = &sp->gp->dcb_store;
+ copy_def = 0;
+ goto copyloop;
+ }
+ return (0);
+}
+
+/*
+ * cb_rotate --
+ * Rotate the numbered buffers up one.
+ */
+static int
+cb_rotate(sp)
+ SCR *sp;
+{
+ CB *cbp, *del_cbp;
+
+ del_cbp = NULL;
+ for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next)
+ switch(cbp->name) {
+ case '1':
+ cbp->name = '2';
+ break;
+ case '2':
+ cbp->name = '3';
+ break;
+ case '3':
+ cbp->name = '4';
+ break;
+ case '4':
+ cbp->name = '5';
+ break;
+ case '5':
+ cbp->name = '6';
+ break;
+ case '6':
+ cbp->name = '7';
+ break;
+ case '7':
+ cbp->name = '8';
+ break;
+ case '8':
+ cbp->name = '9';
+ break;
+ case '9':
+ del_cbp = cbp;
+ break;
+ }
+ if (del_cbp != NULL) {
+ LIST_REMOVE(del_cbp, q);
+ text_lfree(&del_cbp->textq);
+ FREE(del_cbp, sizeof(CB));
+ }
+ return (0);
+}
+
+/*
+ * cut_line --
+ * Cut a portion of a single line.
+ */
+int
+cut_line(sp, ep, lno, fcno, clen, cbp)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ size_t fcno, clen;
+ 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);
+ }
+
+ /* Create a TEXT structure that can hold the entire line. */
+ if ((tp = text_init(sp, NULL, 0, len)) == NULL)
+ return (1);
+
+ /*
+ * 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)
+ clen = len - fcno;
+ 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);
+}
+
+/*
+ * text_init --
+ * Allocate a new TEXT structure.
+ */
+TEXT *
+text_init(sp, p, len, total_len)
+ SCR *sp;
+ const char *p;
+ size_t len, total_len;
+{
+ TEXT *tp;
+
+ 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) != 0) {
+ MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len);
+ if (tp->lb == NULL) {
+ free(tp);
+ return (NULL);
+ }
+ if (p != NULL && len != 0)
+ memmove(tp->lb, p, len);
+ }
+ tp->len = len;
+ return (tp);
+}
+
+/*
+ * text_lfree --
+ * Free a chain of text structures.
+ */
+void
+text_lfree(headp)
+ TEXTH *headp;
+{
+ TEXT *tp;
+
+ while ((tp = headp->cqh_first) != (void *)headp) {
+ CIRCLEQ_REMOVE(headp, tp, q);
+ text_free(tp);
+ }
+}
+
+/*
+ * text_free --
+ * Free a text structure.
+ */
+void
+text_free(tp)
+ TEXT *tp;
+{
+ if (tp->lb != NULL)
+ FREE(tp->lb, tp->lb_len);
+ if (tp->wd != NULL)
+ FREE(tp->wd, tp->wd_len);
+ FREE(tp, sizeof(TEXT));
+}
diff --git a/usr.bin/vi/common/cut.h b/usr.bin/vi/common/cut.h
new file mode 100644
index 000000000000..3113411a5242
--- /dev/null
+++ b/usr.bin/vi/common/cut.h
@@ -0,0 +1,96 @@
+/*-
+ * 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.
+ *
+ * @(#)cut.h 8.19 (Berkeley) 7/28/94
+ */
+
+typedef struct _texth TEXTH; /* TEXT list head structure. */
+CIRCLEQ_HEAD(_texth, _text);
+
+/* Cut buffers. */
+struct _cb {
+ LIST_ENTRY(_cb) q; /* Linked list of cut buffers. */
+ TEXTH textq; /* Linked list of TEXT structures. */
+ CHAR_T name; /* Cut buffer name. */
+ size_t len; /* Total length of cut text. */
+
+#define CB_LMODE 0x01 /* Cut was in line mode. */
+ u_int8_t flags;
+};
+
+/* Lines/blocks of text. */
+struct _text { /* Text: a linked list of lines. */
+ CIRCLEQ_ENTRY(_text) q; /* Linked list of text structures. */
+ char *lb; /* Line buffer. */
+ size_t lb_len; /* Line buffer length. */
+ size_t len; /* Line length. */
+
+ /* These fields are used by the vi text input routine. */
+ recno_t lno; /* 1-N: line number. */
+ size_t ai; /* 0-N: autoindent bytes. */
+ size_t insert; /* 0-N: bytes to insert (push). */
+ size_t offset; /* 0-N: initial, unerasable chars. */
+ size_t owrite; /* 0-N: chars to overwrite. */
+ size_t R_erase; /* 0-N: 'R' erase count. */
+ size_t sv_cno; /* 0-N: Saved line cursor. */
+ size_t sv_len; /* 0-N: Saved line length. */
+
+ /* These fields are used by the ex text input routine. */
+ u_char *wd; /* Width buffer. */
+ size_t wd_len; /* Width buffer length. */
+};
+
+/*
+ * Get named buffer 'name'.
+ * Translate upper-case buffer names to lower-case buffer names.
+ */
+#define CBNAME(sp, cbp, nch) { \
+ CHAR_T __name; \
+ __name = isupper(nch) ? tolower(nch) : (nch); \
+ for (cbp = sp->gp->cutq.lh_first; \
+ cbp != NULL; cbp = cbp->q.le_next) \
+ if (cbp->name == __name) \
+ break; \
+}
+
+#define CUT_LINEMODE 0x01 /* Cut in line mode. */
+#define CUT_NUMOPT 0x02 /* Numeric buffer: optional. */
+#define CUT_NUMREQ 0x04 /* Numeric buffer: required. */
+int cut __P((SCR *, EXF *, CHAR_T *, MARK *, MARK *, int));
+
+int cut_line __P((SCR *, EXF *, recno_t, size_t, size_t, CB *));
+int delete __P((SCR *, EXF *, MARK *, MARK *, int));
+int put __P((SCR *, EXF *, CB *, CHAR_T *, MARK *, MARK *, int));
+
+void text_free __P((TEXT *));
+TEXT *text_init __P((SCR *, const char *, size_t, size_t));
+void text_lfree __P((TEXTH *));
diff --git a/usr.bin/vi/common/delete.c b/usr.bin/vi/common/delete.c
new file mode 100644
index 000000000000..4edd008e6f09
--- /dev/null
+++ b/usr.bin/vi/common/delete.c
@@ -0,0 +1,193 @@
+/*-
+ * 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[] = "@(#)delete.c 8.10 (Berkeley) 4/26/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * delete --
+ * Delete a range of text.
+ */
+int
+delete(sp, ep, fm, tm, lmode)
+ SCR *sp;
+ EXF *ep;
+ MARK *fm, *tm;
+ int lmode;
+{
+ recno_t lno;
+ size_t blen, len, nlen, tlen;
+ char *bp, *p;
+ int eof;
+
+ bp = NULL;
+
+ /* Case 1 -- delete in line mode. */
+ if (lmode) {
+ for (lno = tm->lno; lno >= fm->lno; --lno)
+ if (file_dline(sp, ep, lno))
+ return (1);
+ goto vdone;
+ }
+
+ /*
+ * Case 2 -- delete to EOF. This is a special case because it's
+ * easier to pick it off than try and find it in the other cases.
+ */
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (tm->lno >= lno) {
+ if (tm->lno == lno) {
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ eof = tm->cno >= len ? 1 : 0;
+ } else
+ eof = 1;
+ if (eof) {
+ for (lno = tm->lno; lno > fm->lno; --lno) {
+ if (file_dline(sp, ep, lno))
+ return (1);
+ ++sp->rptlines[L_DELETED];
+ }
+ if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, fm->lno);
+ return (1);
+ }
+ GET_SPACE_RET(sp, bp, blen, fm->cno);
+ memmove(bp, p, fm->cno);
+ if (file_sline(sp, ep, fm->lno, bp, fm->cno))
+ return (1);
+ goto done;
+ }
+ }
+
+ /* Case 3 -- delete within a single line. */
+ if (tm->lno == fm->lno) {
+ if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, fm->lno);
+ return (1);
+ }
+ GET_SPACE_RET(sp, bp, blen, len);
+ 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;
+ }
+
+ /*
+ * Case 4 -- delete over multiple lines.
+ *
+ * Copy the start partial line into place.
+ */
+ if ((tlen = fm->cno) != 0) {
+ if ((p = file_gline(sp, ep, fm->lno, NULL)) == NULL) {
+ GETLINE_ERR(sp, fm->lno);
+ return (1);
+ }
+ GET_SPACE_RET(sp, bp, blen, tlen + 256);
+ memmove(bp, p, tlen);
+ }
+
+ /* Copy the end partial line into place. */
+ if ((p = file_gline(sp, ep, tm->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, tm->lno);
+ goto err;
+ }
+ if (len != 0 && tm->cno != len - 1) {
+ /*
+ * XXX
+ * We can overflow memory here, if the total length is greater
+ * than SIZE_T_MAX. The only portable way I've found to test
+ * is depending on the overflow being less than the value.
+ */
+ nlen = (len - (tm->cno + 1)) + tlen;
+ if (tlen > nlen) {
+ msgq(sp, M_ERR, "Error: line length overflow");
+ goto err;
+ }
+ if (tlen == 0) {
+ GET_SPACE_RET(sp, bp, blen, nlen);
+ } else
+ ADD_SPACE_RET(sp, bp, blen, nlen);
+
+ 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))
+ goto err;
+
+ /* Delete the last and intermediate lines. */
+ for (lno = tm->lno; lno > fm->lno; --lno)
+ if (file_dline(sp, ep, lno))
+ goto err;
+
+ /* Reporting. */
+vdone: sp->rptlines[L_DELETED] += tm->lno - fm->lno + 1;
+
+done: if (bp != NULL)
+ FREE_SPACE(sp, bp, blen);
+
+ return (0);
+
+ /* Free memory. */
+err: if (bp != NULL)
+ FREE_SPACE(sp, bp, blen);
+ return (1);
+}
diff --git a/usr.bin/vi/common/exf.c b/usr.bin/vi/common/exf.c
new file mode 100644
index 000000000000..b18565e2d0a0
--- /dev/null
+++ b/usr.bin/vi/common/exf.c
@@ -0,0 +1,830 @@
+/*-
+ * 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[] = "@(#)exf.c 8.94 (Berkeley) 8/7/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+/*
+ * We include <sys/file.h>, because the flock(2) and open(2) #defines
+ * were found there on historical systems. We also include <fcntl.h>
+ * because the open(2) #defines are found there on newer systems.
+ */
+#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 "compat.h"
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * file_add --
+ * Insert a file name into the FREF list, if it doesn't already
+ * appear in it.
+ *
+ * !!!
+ * The "if it doesn't already appear" changes vi's semantics slightly. If
+ * you do a "vi foo bar", and then execute "next bar baz", the edit of bar
+ * will reflect the line/column of the previous edit session. Historic nvi
+ * did not do this. The change is a logical extension of the change where
+ * vi now remembers the last location in any file that it has ever edited,
+ * not just the previously edited file.
+ */
+FREF *
+file_add(sp, name)
+ SCR *sp;
+ CHAR_T *name;
+{
+ FREF *frp;
+
+ /*
+ * Return it if it already exists. Note that we test against the
+ * user's name, whatever that happens to be, including if it's a
+ * temporary file.
+ */
+ if (name != NULL)
+ for (frp = sp->frefq.cqh_first;
+ frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next)
+ if (!strcmp(frp->name, name))
+ return (frp);
+
+ /* Allocate and initialize the FREF structure. */
+ CALLOC(sp, frp, FREF *, 1, sizeof(FREF));
+ if (frp == NULL)
+ return (NULL);
+
+ /*
+ * If no file name specified, or if the file name is a request
+ * for something temporary, file_init() will allocate the file
+ * name. Temporary files are always ignored.
+ */
+ if (name != NULL && strcmp(name, TEMPORARY_FILE_STRING) &&
+ (frp->name = strdup(name)) == NULL) {
+ FREE(frp, sizeof(FREF));
+ msgq(sp, M_SYSERR, NULL);
+ return (NULL);
+ }
+
+ /* Append into the chain of file names. */
+ CIRCLEQ_INSERT_TAIL(&sp->frefq, frp, q);
+
+ return (frp);
+}
+
+/*
+ * file_init --
+ * Start editing a file, based on the FREF structure. If successsful,
+ * let go of any previous file. Don't release the previous file until
+ * absolutely sure we have the new one.
+ */
+int
+file_init(sp, frp, rcv_name, force)
+ SCR *sp;
+ FREF *frp;
+ char *rcv_name;
+ int force;
+{
+ EXF *ep;
+ RECNOINFO oinfo;
+ struct stat sb;
+ size_t psize;
+ int fd;
+ char *oname, tname[MAXPATHLEN];
+
+ /*
+ * If the file is a recovery file, let the recovery code handle it.
+ * Clear the FR_RECOVER flag first -- the recovery code does set up,
+ * and then calls us! If the recovery call fails, it's probably
+ * because the named file doesn't exist. So, move boldly forward,
+ * presuming that there's an error message the user will get to see.
+ */
+ if (F_ISSET(frp, FR_RECOVER)) {
+ F_CLR(frp, FR_RECOVER);
+ return (rcv_read(sp, frp));
+ }
+
+ /*
+ * Required FRP initialization; the only flag we keep is the
+ * cursor information.
+ */
+ F_CLR(frp, ~FR_CURSORSET);
+
+ /*
+ * Required EXF initialization:
+ * Flush the line caches.
+ * Default recover mail file fd to -1.
+ * Set initial EXF flag bits.
+ */
+ CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF));
+ ep->c_lno = ep->c_nlines = OOBLNO;
+ ep->rcv_fd = ep->fcntl_fd = -1;
+ LIST_INIT(&ep->marks);
+ F_SET(ep, F_FIRSTMODIFY);
+
+ /*
+ * If no name or backing file, create a backing temporary file, saving
+ * the temp file name so we can later unlink it. If the user never
+ * named this file, copy the temporary file name to the real name (we
+ * display that until the user renames it).
+ */
+ if ((oname = frp->name) == NULL || stat(oname, &sb)) {
+ (void)snprintf(tname,
+ sizeof(tname), "%s/vi.XXXXXX", O_STR(sp, O_DIRECTORY));
+ if ((fd = mkstemp(tname)) == -1) {
+ msgq(sp, M_SYSERR, "Temporary file");
+ goto err;
+ }
+ (void)close(fd);
+
+ if (frp->name == NULL)
+ F_SET(frp, FR_TMPFILE);
+ if ((frp->tname = strdup(tname)) == NULL ||
+ frp->name == NULL && (frp->name = strdup(tname)) == NULL) {
+ if (frp->tname != NULL)
+ free(frp->tname);
+ msgq(sp, M_SYSERR, NULL);
+ (void)unlink(tname);
+ goto err;
+ }
+ oname = frp->tname;
+ psize = 4 * 1024;
+ F_SET(frp, FR_NEWFILE);
+ } else {
+ /*
+ * Try to keep it at 10 pages or less per file. This
+ * isn't friendly on a loaded machine, btw.
+ */
+ if (sb.st_size < 40 * 1024)
+ psize = 4 * 1024;
+ else if (sb.st_size < 320 * 1024)
+ psize = 32 * 1024;
+ else
+ psize = 64 * 1024;
+
+ ep->mtime = sb.st_mtime;
+
+ if (!S_ISREG(sb.st_mode))
+ 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. */
+ oinfo.psize = psize;
+ oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0;
+ if (rcv_name == NULL) {
+ if (!rcv_tmp(sp, ep, frp->name))
+ oinfo.bfname = ep->rcv_path;
+ } else {
+ if ((ep->rcv_path = strdup(rcv_name)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ goto err;
+ }
+ oinfo.bfname = ep->rcv_path;
+ F_SET(ep, F_MODIFIED);
+ }
+
+ /* Open a db structure. */
+ if ((ep->db = dbopen(rcv_name == NULL ? oname : NULL,
+ O_NONBLOCK | O_RDONLY, DEFFILEMODE, DB_RECNO, &oinfo)) == NULL) {
+ msgq(sp, M_SYSERR, rcv_name == NULL ? oname : rcv_name);
+ goto err;
+ }
+
+ /*
+ * Do the remaining things that can cause failure of the new file,
+ * mark and logging initialization.
+ */
+ if (mark_init(sp, ep) || log_init(sp, ep))
+ goto err;
+
+ /*
+ * Close the previous file; if that fails, close the new one and
+ * run for the border.
+ *
+ * !!!
+ * There's a nasty special case. If the user edits a temporary file,
+ * and then does an ":e! %", we need to re-initialize the backing
+ * file, but we can't change the name. (It's worse -- we're dealing
+ * with *names* here, we can't even detect that it happened.) Set a
+ * flag so that the file_end routine ignores the backing information
+ * of the old file if it happens to be the same as the new one.
+ *
+ * !!!
+ * Side-effect: after the call to file_end(), sp->frp may be NULL.
+ */
+ F_SET(frp, FR_DONTDELETE);
+ if (sp->ep != NULL && file_end(sp, sp->ep, force)) {
+ (void)file_end(sp, ep, 1);
+ goto err;
+ }
+ F_CLR(frp, FR_DONTDELETE);
+
+ /*
+ * Lock the file; if it's a recovery file, it should already be
+ * locked. Note, we acquire the lock after the previous file
+ * has been ended, so that we don't get an "already locked" error
+ * for ":edit!".
+ *
+ * XXX
+ * While the user can't interrupt us between the open and here,
+ * there's a race between the dbopen() and the lock. Not much
+ * we can do about it.
+ *
+ * XXX
+ * We don't make a big deal of not being able to lock the file. As
+ * locking rarely works over NFS, and often fails if the file was
+ * mmap(2)'d, it's far too common to do anything like print an error
+ * message, let alone make the file readonly. At some future time,
+ * when locking is a little more reliable, this should change to be
+ * an error.
+ */
+ if (rcv_name == NULL)
+ switch (file_lock(oname,
+ &ep->fcntl_fd, ep->db->fd(ep->db), 0)) {
+ case LOCK_FAILED:
+ F_SET(frp, FR_UNLOCKED);
+ break;
+ case LOCK_UNAVAIL:
+ msgq(sp, M_INFO,
+ "%s already locked, session is read-only", oname);
+ F_SET(frp, FR_RDONLY);
+ break;
+ case LOCK_SUCCESS:
+ break;
+ }
+
+ /*
+ * The -R flag, or doing a "set readonly" during a session causes
+ * all files edited during the session (using an edit command, or
+ * even using tags) to be marked read-only. Changing the file name
+ * (see ex/ex_file.c), clears this flag.
+ *
+ * Otherwise, try and figure out if a file is readonly. This is a
+ * dangerous thing to do. The kernel is the only arbiter of whether
+ * or not a file is writeable, and the best that a user program can
+ * do is guess. Obvious loopholes are files that are on a file system
+ * mounted readonly (access catches this one on a few systems), or
+ * alternate protection mechanisms, ACL's for example, that we can't
+ * portably check. Lots of fun, and only here because users whined.
+ *
+ * !!!
+ * Historic vi displayed the readonly message if none of the file
+ * write bits were set, or if an an access(2) call on the path
+ * failed. This seems reasonable. If the file is mode 444, root
+ * users may want to know that the owner of the file did not expect
+ * it to be written.
+ *
+ * Historic vi set the readonly bit if no write bits were set for
+ * a file, even if the access call would have succeeded. This makes
+ * the superuser force the write even when vi expects that it will
+ * succeed. I'm less supportive of this semantic, but it's historic
+ * practice and the conservative approach to vi'ing files as root.
+ *
+ * It would be nice if there was some way to update this when the user
+ * does a "^Z; chmod ...". The problem is that we'd first have to
+ * distinguish between readonly bits set because of file permissions
+ * and those set for other reasons. That's not too hard, but deciding
+ * when to reevaluate the permissions is trickier. An alternative
+ * might be to turn off the readonly bit if the user forces a write
+ * and it succeeds.
+ *
+ * XXX
+ * Access(2) doesn't consider the effective uid/gid values. This
+ * probably isn't a problem for vi when it's running standalone.
+ */
+ if (O_ISSET(sp, O_READONLY) || !F_ISSET(frp, FR_NEWFILE) &&
+ (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) ||
+ access(frp->name, W_OK)))
+ F_SET(frp, FR_RDONLY);
+
+ /*
+ * Set the alternate file name to be the file we've just discarded.
+ *
+ * !!!
+ * If the current file was a temporary file, the call to file_end()
+ * unlinked it and free'd the name. So, there is no previous file,
+ * and there is no alternate file name. This matches historical
+ * practice, although in historical vi it could only happen as the
+ * result of the initial command, i.e. if vi was executed without a
+ * file name.
+ */
+ set_alt_name(sp, sp->frp == NULL ? NULL : sp->frp->name);
+
+ /* Switch... */
+ ++ep->refcnt;
+ sp->ep = ep;
+ sp->frp = frp;
+ return (0);
+
+err: if (frp->name != NULL) {
+ free(frp->name);
+ frp->name = NULL;
+ }
+ if (frp->tname != NULL) {
+ (void)unlink(frp->tname);
+ free(frp->tname);
+ frp->tname = NULL;
+ }
+ if (ep->rcv_path != NULL) {
+ free(ep->rcv_path);
+ ep->rcv_path = NULL;
+ }
+ if (ep->db != NULL)
+ (void)ep->db->close(ep->db);
+ FREE(ep, sizeof(EXF));
+ return (1);
+}
+
+/*
+ * file_end --
+ * Stop editing a file.
+ */
+int
+file_end(sp, ep, force)
+ SCR *sp;
+ EXF *ep;
+ int force;
+{
+ FREF *frp;
+
+ /*
+ * Clean up the FREF structure.
+ *
+ * Save the cursor location.
+ *
+ * XXX
+ * It would be cleaner to do this somewhere else, but by the time
+ * ex or vi knows that we're changing files it's already happened.
+ */
+ frp = sp->frp;
+ frp->lno = sp->lno;
+ frp->cno = sp->cno;
+ F_SET(frp, FR_CURSORSET);
+
+ /*
+ * We may no longer need the temporary backing file, so clean it
+ * up. We don't need the FREF structure either, if the file was
+ * never named, so lose it.
+ *
+ * !!!
+ * Re: FR_DONTDELETE, see the comment above in file_init().
+ */
+ if (!F_ISSET(frp, FR_DONTDELETE) && frp->tname != NULL) {
+ if (unlink(frp->tname))
+ msgq(sp, M_SYSERR, "%s: remove", frp->tname);
+ free(frp->tname);
+ frp->tname = NULL;
+ if (F_ISSET(frp, FR_TMPFILE)) {
+ CIRCLEQ_REMOVE(&sp->frefq, frp, q);
+ free(frp->name);
+ free(frp);
+ }
+ sp->frp = NULL;
+ }
+
+ /*
+ * Clean up the EXF structure.
+ *
+ * sp->ep MAY NOT BE THE SAME AS THE ARGUMENT ep, SO DON'T USE IT!
+ *
+ * If multiply referenced, just decrement the count and return.
+ */
+ if (--ep->refcnt != 0)
+ return (0);
+
+ /* Close the db structure. */
+ if (ep->db->close != NULL && ep->db->close(ep->db) && !force) {
+ msgq(sp, M_ERR, "%s: close: %s", frp->name, strerror(errno));
+ ++ep->refcnt;
+ return (1);
+ }
+
+ /* COMMITTED TO THE CLOSE. THERE'S NO GOING BACK... */
+
+ /* Stop logging. */
+ (void)log_end(sp, ep);
+
+ /* Free up any marks. */
+ (void)mark_end(sp, ep);
+
+ /*
+ * Delete recovery files, close the open descriptor, free recovery
+ * memory. See recover.c for a description of the protocol.
+ *
+ * XXX
+ * Unlink backup file first, we can detect that the recovery file
+ * doesn't reference anything when the user tries to recover it.
+ * There's a race, here, obviously, but it's fairly small.
+ */
+ if (!F_ISSET(ep, F_RCV_NORM)) {
+ if (ep->rcv_path != NULL && unlink(ep->rcv_path))
+ msgq(sp, M_ERR,
+ "%s: remove: %s", ep->rcv_path, strerror(errno));
+ if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath))
+ msgq(sp, M_ERR,
+ "%s: remove: %s", ep->rcv_mpath, strerror(errno));
+ }
+ if (ep->fcntl_fd != -1)
+ (void)close(ep->fcntl_fd);
+ if (ep->rcv_fd != -1)
+ (void)close(ep->rcv_fd);
+ if (ep->rcv_path != NULL)
+ free(ep->rcv_path);
+ if (ep->rcv_mpath != NULL)
+ free(ep->rcv_mpath);
+
+ FREE(ep, sizeof(EXF));
+ return (0);
+}
+
+/*
+ * file_write --
+ * Write the file to disk. Historic vi had fairly convoluted
+ * semantics for whether or not writes would happen. That's
+ * why all the flags.
+ */
+int
+file_write(sp, ep, fm, tm, name, flags)
+ SCR *sp;
+ EXF *ep;
+ MARK *fm, *tm;
+ char *name;
+ int flags;
+{
+ struct stat sb;
+ FILE *fp;
+ FREF *frp;
+ MARK from, to;
+ u_long nlno, nch;
+ int btear, fd, noname, oflags, rval;
+ char *msg;
+
+ frp = sp->frp;
+ if (name == NULL) {
+ noname = 1;
+ name = frp->name;
+ } else
+ noname = 0;
+
+ /* Can't write files marked read-only, unless forced. */
+ if (!LF_ISSET(FS_FORCE) && noname && F_ISSET(frp, FR_RDONLY)) {
+ if (LF_ISSET(FS_POSSIBLE))
+ msgq(sp, M_ERR,
+ "Read-only file, not written; use ! to override");
+ else
+ msgq(sp, M_ERR, "Read-only file, not written");
+ return (1);
+ }
+
+ /* If not forced, not appending, and "writeany" not set ... */
+ if (!LF_ISSET(FS_FORCE | FS_APPEND) && !O_ISSET(sp, O_WRITEANY)) {
+ /* Don't overwrite anything but the original file. */
+ if ((!noname || F_ISSET(frp, FR_NAMECHANGE)) &&
+ !stat(name, &sb)) {
+ if (LF_ISSET(FS_POSSIBLE))
+ msgq(sp, M_ERR,
+ "%s exists, not written; use ! to override", name);
+ else
+ msgq(sp, M_ERR, "%s exists, not written", name);
+ return (1);
+ }
+
+ /*
+ * Don't write part of any existing file. Only test for the
+ * original file, the previous test catches anything else.
+ */
+ if (!LF_ISSET(FS_ALL) && noname && !stat(name, &sb)) {
+ if (LF_ISSET(FS_POSSIBLE))
+ msgq(sp, M_ERR,
+ "Use ! to write a partial file");
+ else
+ msgq(sp, M_ERR, "Partial file, not written");
+ return (1);
+ }
+ }
+
+ /*
+ * Figure out if the file already exists -- if it doesn't, we display
+ * the "new file" message. The stat might not be necessary, but we
+ * just repeat it because it's easier than hacking the previous tests.
+ * The information is only used for the user message and modification
+ * time test, so we can ignore the obvious race condition.
+ *
+ * If the user is overwriting a file other than the original file, and
+ * O_WRITEANY was what got us here (neither force nor append was set),
+ * display the "existing file" messsage. Since the FR_NAMECHANGE flag
+ * is cleared on a successful write, the message only appears once when
+ * the user changes a file name. This is historic practice.
+ *
+ * One final test. If we're not forcing or appending, and we have a
+ * saved modification time, stop the user if it's been written since
+ * we last edited or wrote it, and make them force it.
+ */
+ if (stat(name, &sb))
+ msg = ": new file";
+ else {
+ msg = "";
+ if (!LF_ISSET(FS_FORCE | FS_APPEND)) {
+ if (ep->mtime && sb.st_mtime > ep->mtime) {
+ msgq(sp, M_ERR,
+ "%s: file modified more recently than this copy%s",
+ name, LF_ISSET(FS_POSSIBLE) ?
+ "; use ! to override" : "");
+ return (1);
+ }
+ if (!noname || F_ISSET(frp, FR_NAMECHANGE))
+ msg = ": existing file";
+ }
+ }
+
+ /* Set flags to either append or truncate. */
+ oflags = O_CREAT | O_WRONLY;
+ if (LF_ISSET(FS_APPEND))
+ oflags |= O_APPEND;
+ else
+ oflags |= O_TRUNC;
+
+ /* Open the file. */
+ if ((fd = open(name, oflags, DEFFILEMODE)) < 0) {
+ msgq(sp, M_SYSERR, name);
+ return (1);
+ }
+
+ /* Use stdio for buffering. */
+ if ((fp = fdopen(fd, "w")) == NULL) {
+ (void)close(fd);
+ msgq(sp, M_SYSERR, name);
+ return (1);
+ }
+
+ /* Build fake addresses, if necessary. */
+ if (fm == NULL) {
+ from.lno = 1;
+ from.cno = 0;
+ fm = &from;
+ if (file_lline(sp, ep, &to.lno))
+ return (1);
+ to.cno = 0;
+ tm = &to;
+ }
+
+ /* Turn on the busy message. */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Writing...");
+ rval = ex_writefp(sp, ep, name, fp, fm, tm, &nlno, &nch);
+ if (btear)
+ busy_off(sp);
+
+ /*
+ * Save the new last modification time -- even if the write fails
+ * we re-init the time. That way the user can clean up the disk
+ * and rewrite without having to force it.
+ */
+ ep->mtime = stat(name, &sb) ? 0 : sb.st_mtime;
+
+ /* If the write failed, complain loudly. */
+ if (rval) {
+ if (!LF_ISSET(FS_APPEND))
+ msgq(sp, M_ERR, "%s: WARNING: file truncated!", name);
+ return (1);
+ }
+
+ /*
+ * Once we've actually written the file, it doesn't matter that the
+ * file name was changed -- if it was, we've already whacked it.
+ */
+ F_CLR(frp, FR_NAMECHANGE);
+
+ /*
+ * If wrote the entire file clear the modified bit. If the file was
+ * written back to the original file name and the file is a temporary,
+ * set the "no exit" bit. This permits the user to write the file and
+ * use it in the context of the file system, but still keeps them from
+ * losing their changes by exiting.
+ */
+ if (LF_ISSET(FS_ALL)) {
+ F_CLR(ep, F_MODIFIED);
+ if (F_ISSET(frp, FR_TMPFILE))
+ if (noname)
+ F_SET(frp, FR_TMPEXIT);
+ else
+ F_CLR(frp, FR_TMPEXIT);
+ }
+
+ msgq(sp, M_INFO, "%s%s%s: %lu line%s, %lu characters",
+ INTERRUPTED(sp) ? "Interrupted write: " : "",
+ name, msg, nlno, nlno == 1 ? "" : "s", nch);
+
+ return (0);
+}
+
+/*
+ * file_m1 --
+ * First modification check routine. The :next, :prev, :rewind, :tag,
+ * :tagpush, :tagpop, ^^ modifications check.
+ */
+int
+file_m1(sp, ep, force, flags)
+ SCR *sp;
+ EXF *ep;
+ int force, flags;
+{
+ /*
+ * If the file has been modified, we'll want to write it back or
+ * fail. If autowrite is set, we'll write it back automatically,
+ * unless force is also set. Otherwise, we fail unless forced or
+ * there's another open screen on this file.
+ */
+ if (F_ISSET(ep, F_MODIFIED))
+ if (O_ISSET(sp, O_AUTOWRITE)) {
+ if (!force &&
+ file_write(sp, ep, NULL, NULL, NULL, flags))
+ return (1);
+ } else if (ep->refcnt <= 1 && !force) {
+ msgq(sp, M_ERR,
+ "File modified since last complete write; write or use %s to override",
+ LF_ISSET(FS_POSSIBLE) ? "!" : ":edit!");
+ return (1);
+ }
+
+ return (file_m3(sp, ep, force));
+}
+
+/*
+ * file_m2 --
+ * Second modification check routine. The :edit, :quit, :recover
+ * modifications check.
+ */
+int
+file_m2(sp, ep, force)
+ SCR *sp;
+ EXF *ep;
+ int force;
+{
+ /*
+ * If the file has been modified, we'll want to fail, unless forced
+ * or there's another open screen on this file.
+ */
+ if (F_ISSET(ep, F_MODIFIED) && ep->refcnt <= 1 && !force) {
+ msgq(sp, M_ERR,
+ "File modified since last complete write; write or use ! to override");
+ return (1);
+ }
+
+ return (file_m3(sp, ep, force));
+}
+
+/*
+ * file_m3 --
+ * Third modification check routine.
+ */
+int
+file_m3(sp, ep, force)
+ SCR *sp;
+ EXF *ep;
+ int force;
+{
+ /*
+ * Don't exit while in a temporary files if the file was ever modified.
+ * The problem is that if the user does a ":wq", we write and quit,
+ * unlinking the temporary file. Not what the user had in mind at all.
+ * We permit writing to temporary files, so that user maps using file
+ * system names work with temporary files.
+ */
+ if (F_ISSET(sp->frp, FR_TMPEXIT) && ep->refcnt <= 1 && !force) {
+ msgq(sp, M_ERR,
+ "File is a temporary; exit will discard modifications");
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * file_lock --
+ * Get an exclusive lock on a file.
+ *
+ * XXX
+ * The default locking is flock(2) style, not fcntl(2). The latter is
+ * known to fail badly on some systems, and its only advantage is that
+ * it occasionally works over NFS.
+ *
+ * Furthermore, the semantics of fcntl(2) are wrong. The problems are
+ * two-fold: you can't close any file descriptor associated with the file
+ * without losing all of the locks, and you can't get an exclusive lock
+ * unless you have the file open for writing. Someone ought to be shot,
+ * but it's probably too late, they may already have reproduced. To get
+ * around these problems, nvi opens the files for writing when it can and
+ * acquires a second file descriptor when it can't. The recovery files
+ * are examples of the former, they're always opened for writing. The DB
+ * files can't be opened for writing because the semantics of DB are that
+ * files opened for writing are flushed back to disk when the DB session
+ * is ended. So, in that case we have to acquire an extra file descriptor.
+ */
+enum lockt
+file_lock(name, fdp, fd, iswrite)
+ char *name;
+ int fd, *fdp, iswrite;
+{
+#if !defined(USE_FCNTL) && defined(LOCK_EX)
+ /* Hurrah! We've got flock(2). */
+ /*
+ * !!!
+ * We need to distinguish a lock not being available for the file
+ * from the file system not supporting locking. Flock is documented
+ * as returning EWOULDBLOCK; add EAGAIN for good measure, and assume
+ * they are the former. There's no portable way to do this.
+ */
+ errno = 0;
+ return (flock(fd, LOCK_EX | LOCK_NB) ?
+ errno == EAGAIN || errno == EWOULDBLOCK ?
+ LOCK_UNAVAIL : LOCK_FAILED : LOCK_SUCCESS);
+
+#else /* Gag me. We've got fcntl(2). */
+ struct flock arg;
+ int didopen, sverrno;
+
+ arg.l_type = F_WRLCK;
+ arg.l_whence = 0; /* SEEK_SET */
+ arg.l_start = arg.l_len = 0;
+ arg.l_pid = 0;
+
+ /* If the file descriptor isn't opened for writing, it must fail. */
+ if (!iswrite) {
+ if (name == NULL || fdp == NULL)
+ return (LOCK_FAILED);
+ if ((fd = open(name, O_RDWR, 0)) == -1)
+ return (LOCK_FAILED);
+ *fdp = fd;
+ didopen = 1;
+ }
+
+ errno = 0;
+ if (!fcntl(fd, F_SETLK, &arg))
+ return (LOCK_SUCCESS);
+ if (didopen) {
+ sverrno = errno;
+ (void)close(fd);
+ errno = sverrno;
+ }
+
+ /*
+ * !!!
+ * We need to distinguish a lock not being available for the file
+ * from the file system not supporting locking. Fcntl is documented
+ * as returning EACCESS and EAGAIN; add EWOULDBLOCK for good measure,
+ * and assume they are the former. There's no portable way to do this.
+ */
+ return (errno == EACCES || errno == EAGAIN || errno == EWOULDBLOCK ?
+ LOCK_UNAVAIL : LOCK_FAILED);
+#endif
+}
diff --git a/usr.bin/vi/common/exf.h b/usr.bin/vi/common/exf.h
new file mode 100644
index 000000000000..1b06649384fb
--- /dev/null
+++ b/usr.bin/vi/common/exf.h
@@ -0,0 +1,128 @@
+/*-
+ * 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.
+ *
+ * @(#)exf.h 8.35 (Berkeley) 8/4/94
+ */
+ /* Undo direction. */
+/*
+ * exf --
+ * The file structure.
+ */
+struct _exf {
+ int refcnt; /* Reference count. */
+
+ /* Underlying database state. */
+ DB *db; /* File db structure. */
+ char *c_lp; /* Cached line. */
+ size_t c_len; /* Cached line length. */
+ recno_t c_lno; /* Cached line number. */
+ recno_t c_nlines; /* Cached lines in the file. */
+
+ DB *log; /* Log db structure. */
+ char *l_lp; /* Log buffer. */
+ size_t l_len; /* Log buffer length. */
+ recno_t l_high; /* Log last + 1 record number. */
+ recno_t l_cur; /* Log current record number. */
+ MARK l_cursor; /* Log cursor position. */
+ enum direction lundo; /* Last undo direction. */
+
+ LIST_HEAD(_markh, _lmark) marks;/* Linked list of file MARK's. */
+
+ time_t mtime; /* Last modification time. */
+
+ int fcntl_fd; /* Fcntl locking fd; see exf.c. */
+
+ /*
+ * Recovery in general, and these fields specifically, are described
+ * in recover.c.
+ */
+#define RCV_PERIOD 120 /* Sync every two minutes. */
+ 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. */
+#define F_MULTILOCK 0x004 /* Multiple processes running, lock. */
+#define F_NOLOG 0x008 /* Logging turned off. */
+#define F_RCV_NORM 0x010 /* Don't delete recovery files. */
+#define F_RCV_ON 0x020 /* Recovery is possible. */
+#define F_UNDO 0x040 /* No change since last undo. */
+ u_int8_t flags;
+};
+
+#define GETLINE_ERR(sp, lno) { \
+ msgq(sp, M_ERR, \
+ "Error: %s/%d: unable to retrieve line %u", \
+ tail(__FILE__), __LINE__, lno); \
+}
+
+/* EXF routines. */
+FREF *file_add __P((SCR *, CHAR_T *));
+int file_end __P((SCR *, EXF *, int));
+int file_init __P((SCR *, FREF *, char *, int));
+int file_m1 __P((SCR *, EXF *, int, int));
+int file_m2 __P((SCR *, EXF *, int));
+int file_m3 __P((SCR *, EXF *, int));
+
+enum lockt { LOCK_FAILED, LOCK_SUCCESS, LOCK_UNAVAIL };
+enum lockt
+ file_lock __P((char *, int *, int, int));
+
+#define FS_ALL 0x01 /* Write the entire file. */
+#define FS_APPEND 0x02 /* Append to the file. */
+#define FS_FORCE 0x04 /* Force is set. */
+#define FS_POSSIBLE 0x08 /* Force could be set. */
+int file_write __P((SCR *, EXF *, MARK *, MARK *, char *, int));
+
+/* Recovery routines. */
+int rcv_init __P((SCR *, EXF *));
+int rcv_list __P((SCR *));
+int rcv_on __P((SCR *, EXF *));
+int rcv_read __P((SCR *, FREF *));
+
+#define RCV_EMAIL 0x01 /* Send the user email, IFF file modified. */
+#define RCV_ENDSESSION 0x02 /* End the file session. */
+#define RCV_PRESERVE 0x04 /* Preserve backup file, IFF file modified. */
+#define RCV_SNAPSHOT 0x08 /* Snapshot the recovery, and send email. */
+int rcv_sync __P((SCR *, EXF *, u_int));
+int rcv_tmp __P((SCR *, EXF *, char *));
+
+/* DB interface routines */
+int file_aline __P((SCR *, EXF *, int, recno_t, char *, size_t));
+int file_dline __P((SCR *, EXF *, recno_t));
+char *file_gline __P((SCR *, EXF *, recno_t, size_t *));
+int file_iline __P((SCR *, EXF *, recno_t, char *, size_t));
+int file_lline __P((SCR *, EXF *, recno_t *));
+char *file_rline __P((SCR *, EXF *, recno_t, size_t *));
+int file_sline __P((SCR *, EXF *, recno_t, char *, size_t));
diff --git a/usr.bin/vi/common/gs.h b/usr.bin/vi/common/gs.h
new file mode 100644
index 000000000000..36343f4c404e
--- /dev/null
+++ b/usr.bin/vi/common/gs.h
@@ -0,0 +1,107 @@
+/*-
+ * 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.
+ *
+ * @(#)gs.h 8.39 (Berkeley) 7/23/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. */
+
+ MSGH msgq; /* User message list. */
+
+ char *tmp_bp; /* Temporary buffer. */
+ size_t tmp_blen; /* Size of temporary buffer. */
+
+ sigset_t blockset; /* Signal mask. */
+
+#ifdef DEBUG
+ FILE *tracefp; /* Trace file pointer. */
+#endif
+
+/* INFORMATION SHARED BY ALL SCREENS. */
+ IBUF *tty; /* Key input buffer. */
+
+ CB *dcbp; /* Default cut buffer pointer. */
+ CB dcb_store; /* Default cut buffer storage. */
+ LIST_HEAD(_cuth, _cb) cutq; /* Linked list of cut buffers. */
+
+#define MAX_BIT_SEQ 128 /* Max + 1 fast check character. */
+ LIST_HEAD(_seqh, _seq) seqq; /* Linked list of maps, abbrevs. */
+ bitstr_t bit_decl(seqb, MAX_BIT_SEQ);
+
+#define MAX_FAST_KEY 254 /* Max fast check character.*/
+#define KEY_LEN(sp, ch) \
+ ((ch) <= MAX_FAST_KEY ? \
+ sp->gp->cname[ch].len : __key_len(sp, ch))
+#define KEY_NAME(sp, ch) \
+ ((ch) <= MAX_FAST_KEY ? \
+ sp->gp->cname[ch].name : __key_name(sp, ch))
+ struct {
+ CHAR_T name[MAX_CHARACTER_COLUMNS + 1];
+ u_int8_t len;
+ } cname[MAX_FAST_KEY + 1]; /* Fast lookup table. */
+
+#define KEY_VAL(sp, ch) \
+ ((ch) <= MAX_FAST_KEY ? sp->gp->special_key[ch] : \
+ (ch) > sp->gp->max_special ? 0 : __key_val(sp, ch))
+ CHAR_T max_special; /* Max special character. */
+ u_char /* Fast lookup table. */
+ special_key[MAX_FAST_KEY + 1];
+
+/* Interrupt macros. */
+#define INTERRUPTED(sp) \
+ (F_ISSET((sp), S_INTERRUPTED) || F_ISSET((sp)->gp, G_SIGINT))
+#define CLR_INTERRUPT(sp) { \
+ F_CLR((sp), S_INTERRUPTED | S_INTERRUPTIBLE); \
+ F_CLR((sp)->gp, G_SIGINT); \
+}
+
+#define G_ABBREV 0x0001 /* If have abbreviations. */
+#define G_BELLSCHED 0x0002 /* Bell scheduled. */
+#define G_RECOVER_SET 0x0004 /* Recover system initialized. */
+#define G_SETMODE 0x0008 /* Tty mode changed. */
+#define G_SIGALRM 0x0010 /* SIGALRM arrived. */
+#define G_SIGINT 0x0020 /* SIGINT arrived. */
+#define G_SIGWINCH 0x0040 /* SIGWINCH arrived. */
+#define G_SNAPSHOT 0x0080 /* Always snapshot files. */
+#define G_STDIN_TTY 0x0100 /* Standard input is a tty. */
+#define G_TERMIOS_SET 0x0200 /* Termios structure is valid. */
+#define G_TMP_INUSE 0x0400 /* Temporary buffer in use. */
+ u_int16_t flags;
+};
+
+extern GS *__global_list; /* List of screens. */
diff --git a/usr.bin/vi/common/line.c b/usr.bin/vi/common/line.c
new file mode 100644
index 000000000000..12d22e481dd7
--- /dev/null
+++ b/usr.bin/vi/common/line.c
@@ -0,0 +1,492 @@
+/*-
+ * 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[] = "@(#)line.c 8.30 (Berkeley) 6/30/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static __inline int scr_update
+ __P((SCR *, EXF *, recno_t, enum operation, int));
+
+/*
+ * file_gline --
+ * Look in the text buffers for a line; if it's not there
+ * call file_rline to retrieve it from the database.
+ */
+char *
+file_gline(sp, ep, lno, lenp)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno; /* Line number. */
+ size_t *lenp; /* Length store. */
+{
+ TEXT *tp;
+ recno_t l1, l2;
+
+ /*
+ * The underlying recno stuff handles zero by returning NULL, but
+ * have to have an oob condition for the look-aside into the input
+ * buffer anyway.
+ */
+ if (lno == 0)
+ return (NULL);
+
+ /*
+ * Look-aside into the TEXT buffers and see if the line we want
+ * is there.
+ */
+ if (F_ISSET(sp, S_INPUT)) {
+ l1 = ((TEXT *)sp->tiqp->cqh_first)->lno;
+ l2 = ((TEXT *)sp->tiqp->cqh_last)->lno;
+ if (l1 <= lno && l2 >= lno) {
+ for (tp = sp->tiqp->cqh_first;
+ tp->lno != lno; tp = tp->q.cqe_next);
+ if (lenp)
+ *lenp = tp->len;
+ return (tp->lb);
+ }
+ /*
+ * Adjust the line number for the number of lines used
+ * by the text input buffers.
+ */
+ if (lno > l2)
+ lno -= l2 - l1;
+ }
+ return (file_rline(sp, ep, lno, lenp));
+}
+
+/*
+ * file_rline --
+ * Look in the cache for a line; if it's not there retrieve
+ * it from the file.
+ */
+char *
+file_rline(sp, ep, lno, lenp)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno; /* Line number. */
+ size_t *lenp; /* Length store. */
+{
+ DBT data, key;
+
+ /* Check the cache. */
+ if (lno == ep->c_lno) {
+ if (lenp)
+ *lenp = ep->c_len;
+ return (ep->c_lp);
+ }
+ ep->c_lno = OOBLNO;
+
+ /* Get the line from the underlying database. */
+ key.data = &lno;
+ key.size = sizeof(lno);
+ switch (ep->db->get(ep->db, &key, &data, 0)) {
+ case -1:
+ msgq(sp, M_ERR,
+ "Error: %s/%d: unable to get line %u: %s",
+ tail(__FILE__), __LINE__, lno, strerror(errno));
+ /* FALLTHROUGH */
+ case 1:
+ return (NULL);
+ /* NOTREACHED */
+ }
+ if (lenp)
+ *lenp = data.size;
+
+ /* Fill the cache. */
+ ep->c_lno = lno;
+ ep->c_len = data.size;
+ ep->c_lp = data.data;
+
+ return (data.data);
+}
+
+/*
+ * file_dline --
+ * Delete a line from the file.
+ */
+int
+file_dline(sp, ep, lno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+{
+ DBT key;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "delete line %lu\n", lno);
+#endif
+ /*
+ * XXX
+ * Marks and global commands have to know when lines are
+ * inserted or deleted.
+ */
+ mark_insdel(sp, ep, LINE_DELETE, lno);
+ global_insdel(sp, ep, LINE_DELETE, lno);
+
+ /* Log change. */
+ log_line(sp, ep, lno, LOG_LINE_DELETE);
+
+ /* Update file. */
+ key.data = &lno;
+ key.size = sizeof(lno);
+ SIGBLOCK(sp->gp);
+ if (ep->db->del(ep->db, &key, 0) == 1) {
+ msgq(sp, M_ERR,
+ "Error: %s/%d: unable to delete line %u: %s",
+ tail(__FILE__), __LINE__, lno, strerror(errno));
+ return (1);
+ }
+ SIGUNBLOCK(sp->gp);
+
+ /* Flush the cache, update line count, before screen update. */
+ if (lno <= ep->c_lno)
+ ep->c_lno = OOBLNO;
+ if (ep->c_nlines != OOBLNO)
+ --ep->c_nlines;
+
+ /* File now dirty. */
+ if (F_ISSET(ep, F_FIRSTMODIFY))
+ (void)rcv_init(sp, ep);
+ F_SET(ep, F_MODIFIED);
+
+ /* Update screen. */
+ return (scr_update(sp, ep, lno, LINE_DELETE, 1));
+}
+
+/*
+ * file_aline --
+ * Append a line into the file.
+ */
+int
+file_aline(sp, ep, update, lno, p, len)
+ SCR *sp;
+ EXF *ep;
+ int update;
+ recno_t lno;
+ char *p;
+ size_t len;
+{
+ DBT data, key;
+ recno_t lline;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "append to %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p);
+#endif
+ /*
+ * XXX
+ * Very nasty special case. The historic vi code displays a single
+ * space (or a '$' if the list option is set) for the first line in
+ * an "empty" file. If we "insert" a line, that line gets scrolled
+ * down, not repainted, so it's incorrect when we refresh the the
+ * screen. This is really hard to find and fix in the vi code -- the
+ * text input functions detect it explicitly and don't insert a new
+ * line. The hack here is to repaint the screen if we're appending
+ * to an empty file. The reason that the test is in file_aline, and
+ * not in file_iline or file_sline, is that all of the ex commands
+ * that work in empty files end up here.
+ */
+ if (lno == 0) {
+ if (file_lline(sp, ep, &lline))
+ return (1);
+ if (lline == 0)
+ F_SET(sp, S_REDRAW);
+ }
+
+ /* Update file. */
+ key.data = &lno;
+ key.size = sizeof(lno);
+ data.data = p;
+ data.size = len;
+ SIGBLOCK(sp->gp);
+ if (ep->db->put(ep->db, &key, &data, R_IAFTER) == -1) {
+ msgq(sp, M_ERR,
+ "Error: %s/%d: unable to append to line %u: %s",
+ tail(__FILE__), __LINE__, lno, strerror(errno));
+ return (1);
+ }
+ SIGUNBLOCK(sp->gp);
+
+ /* Flush the cache, update line count, before screen update. */
+ if (lno < ep->c_lno)
+ ep->c_lno = OOBLNO;
+ if (ep->c_nlines != OOBLNO)
+ ++ep->c_nlines;
+
+ /* File now dirty. */
+ if (F_ISSET(ep, F_FIRSTMODIFY))
+ (void)rcv_init(sp, ep);
+ F_SET(ep, F_MODIFIED);
+
+ /* Log change. */
+ log_line(sp, ep, lno + 1, LOG_LINE_APPEND);
+
+ /*
+ * XXX
+ * Marks and global commands have to know when lines are
+ * inserted or deleted.
+ *
+ * XXX
+ * See comment above about empty files. If the file was empty,
+ * then we're adding the first line, which is a replacement, not
+ * an append. So, we shouldn't whack the marks.
+ */
+ if (lno != 0) {
+ mark_insdel(sp, ep, LINE_INSERT, lno + 1);
+ global_insdel(sp, ep, LINE_INSERT, lno + 1);
+ }
+
+ /*
+ * Update screen.
+ *
+ * XXX
+ * Nasty hack. If multiple lines are input by the user, they aren't
+ * committed until an <ESC> is entered. The problem is the screen was
+ * 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));
+}
+
+/*
+ * file_iline --
+ * Insert a line into the file.
+ */
+int
+file_iline(sp, ep, lno, p, len)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ char *p;
+ size_t len;
+{
+ DBT data, key;
+ recno_t lline;
+
+#if defined(DEBUG) && 0
+ TRACE(sp,
+ "insert before %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p);
+#endif
+
+ /* Very nasty special case. See comment in file_aline(). */
+ if (lno == 1) {
+ if (file_lline(sp, ep, &lline))
+ return (1);
+ if (lline == 0)
+ F_SET(sp, S_REDRAW);
+ }
+
+ /* Update file. */
+ key.data = &lno;
+ key.size = sizeof(lno);
+ data.data = p;
+ data.size = len;
+ SIGBLOCK(sp->gp);
+ if (ep->db->put(ep->db, &key, &data, R_IBEFORE) == -1) {
+ msgq(sp, M_ERR,
+ "Error: %s/%d: unable to insert at line %u: %s",
+ tail(__FILE__), __LINE__, lno, strerror(errno));
+ return (1);
+ }
+ SIGUNBLOCK(sp->gp);
+
+ /* Flush the cache, update line count, before screen update. */
+ if (lno >= ep->c_lno)
+ ep->c_lno = OOBLNO;
+ if (ep->c_nlines != OOBLNO)
+ ++ep->c_nlines;
+
+ /* File now dirty. */
+ if (F_ISSET(ep, F_FIRSTMODIFY))
+ (void)rcv_init(sp, ep);
+ F_SET(ep, F_MODIFIED);
+
+ /* Log change. */
+ log_line(sp, ep, lno, LOG_LINE_INSERT);
+
+ /*
+ * XXX
+ * Marks and global commands have to know when lines are
+ * inserted or deleted.
+ */
+ mark_insdel(sp, ep, LINE_INSERT, lno);
+ global_insdel(sp, ep, LINE_INSERT, lno);
+
+ /* Update screen. */
+ return (scr_update(sp, ep, lno, LINE_INSERT, 1));
+}
+
+/*
+ * file_sline --
+ * Store a line in the file.
+ */
+int
+file_sline(sp, ep, lno, p, len)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ char *p;
+ size_t len;
+{
+ DBT data, key;
+
+#if defined(DEBUG) && 0
+ TRACE(sp,
+ "replace line %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p);
+#endif
+ /* Log before change. */
+ log_line(sp, ep, lno, LOG_LINE_RESET_B);
+
+ /* Update file. */
+ key.data = &lno;
+ key.size = sizeof(lno);
+ data.data = p;
+ data.size = len;
+ SIGBLOCK(sp->gp);
+ if (ep->db->put(ep->db, &key, &data, 0) == -1) {
+ msgq(sp, M_ERR,
+ "Error: %s/%d: unable to store line %u: %s",
+ tail(__FILE__), __LINE__, lno, strerror(errno));
+ return (1);
+ }
+ SIGUNBLOCK(sp->gp);
+
+ /* Flush the cache, before logging or screen update. */
+ if (lno == ep->c_lno)
+ ep->c_lno = OOBLNO;
+
+ /* File now dirty. */
+ if (F_ISSET(ep, F_FIRSTMODIFY))
+ (void)rcv_init(sp, ep);
+ F_SET(ep, F_MODIFIED);
+
+ /* Log after change. */
+ log_line(sp, ep, lno, LOG_LINE_RESET_F);
+
+ /* Update screen. */
+ return (scr_update(sp, ep, lno, LINE_RESET, 1));
+}
+
+/*
+ * file_lline --
+ * Return the number of lines in the file.
+ */
+int
+file_lline(sp, ep, lnop)
+ SCR *sp;
+ EXF *ep;
+ recno_t *lnop;
+{
+ DBT data, key;
+ recno_t lno;
+
+ /* Check the cache. */
+ if (ep->c_nlines != OOBLNO) {
+ *lnop = (F_ISSET(sp, S_INPUT) &&
+ ((TEXT *)sp->tiqp->cqh_last)->lno > ep->c_nlines ?
+ ((TEXT *)sp->tiqp->cqh_last)->lno : ep->c_nlines);
+ return (0);
+ }
+
+ key.data = &lno;
+ key.size = sizeof(lno);
+
+ switch (ep->db->seq(ep->db, &key, &data, R_LAST)) {
+ case -1:
+ msgq(sp, M_ERR,
+ "Error: %s/%d: unable to get last line: %s",
+ tail(__FILE__), __LINE__, strerror(errno));
+ *lnop = 0;
+ return (1);
+ case 1:
+ *lnop = 0;
+ return (0);
+ default:
+ 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->tiqp->cqh_last)->lno > lno ?
+ ((TEXT *)sp->tiqp->cqh_last)->lno : lno);
+ return (0);
+}
+
+/*
+ * scr_update --
+ * Update all of the screens that are backed by the file that
+ * just changed.
+ */
+static __inline int
+scr_update(sp, ep, lno, op, current)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ enum operation op;
+ int current;
+{
+ SCR *tsp;
+
+ if (ep->refcnt != 1)
+ for (tsp = sp->gp->dq.cqh_first;
+ tsp != (void *)&sp->gp->dq; tsp = tsp->q.cqe_next)
+ if (sp != tsp && tsp->ep == ep)
+ (void)sp->s_change(tsp, ep, lno, op);
+ return (current && sp->s_change(sp, ep, lno, op));
+}
diff --git a/usr.bin/vi/common/log.c b/usr.bin/vi/common/log.c
new file mode 100644
index 000000000000..09f0c27fe0f4
--- /dev/null
+++ b/usr.bin/vi/common/log.c
@@ -0,0 +1,698 @@
+/*-
+ * 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[] = "@(#)log.c 8.16 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * The log consists of records, each containing a type byte and a variable
+ * length byte string, as follows:
+ *
+ * LOG_CURSOR_INIT MARK
+ * LOG_CURSOR_END MARK
+ * LOG_LINE_APPEND recno_t char *
+ * LOG_LINE_DELETE recno_t char *
+ * LOG_LINE_INSERT recno_t char *
+ * LOG_LINE_RESET_F recno_t char *
+ * LOG_LINE_RESET_B recno_t char *
+ * 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
+ * characters. Since the smallest unit of logging is a line, we're using
+ * up lots of space. This may eventually have to be reduced, probably by
+ * doing logical logging, which is a much cooler database phrase.
+ *
+ * The implementation of the historic vi 'u' command, using roll-forward and
+ * roll-back, is simple. Each set of changes has a LOG_CURSOR_INIT record,
+ * followed by a number of other records, followed by a LOG_CURSOR_END record.
+ * LOG_LINE_RESET records come in pairs. The first is a LOG_LINE_RESET_B
+ * record, and is the line before the change. The second is LOG_LINE_RESET_F,
+ * and is the line after the change. Roll-back is done by backing up to the
+ * first LOG_CURSOR_INIT record before a change. Roll-forward is done in a
+ * similar fashion.
+ *
+ * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
+ * record for a line different from the current one. It should be noted that
+ * this means that a subsequent 'u' command will make a change based on the
+ * new position of the log's cursor. This is okay, and, in fact, historic vi
+ * behaved that way.
+ */
+
+static int log_cursor1 __P((SCR *, EXF *, int));
+#if defined(DEBUG) && 0
+static void log_trace __P((SCR *, char *, recno_t, u_char *));
+#endif
+
+/* Try and restart the log on failure, i.e. if we run out of memory. */
+#define LOG_ERR { \
+ msgq(sp, M_ERR, "Error: %s/%d: put log error: %s", \
+ tail(__FILE__), __LINE__, strerror(errno)); \
+ (void)ep->log->close(ep->log); \
+ if (!log_init(sp, ep)) \
+ msgq(sp, M_ERR, "Log restarted"); \
+ return (1); \
+}
+
+/*
+ * log_init --
+ * Initialize the logging subsystem.
+ */
+int
+log_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ /*
+ * Initialize the buffer. The logging subsystem has its own
+ * buffers because the global ones are almost by definition
+ * going to be in use when the log runs.
+ */
+ ep->l_lp = NULL;
+ ep->l_len = 0;
+ ep->l_cursor.lno = 1; /* XXX Any valid recno. */
+ ep->l_cursor.cno = 0;
+ ep->l_high = ep->l_cur = 1;
+
+ ep->log = dbopen(NULL, O_CREAT | O_NONBLOCK | O_RDWR,
+ S_IRUSR | S_IWUSR, DB_RECNO, NULL);
+ if (ep->log == NULL) {
+ msgq(sp, M_ERR, "log db: %s", strerror(errno));
+ F_SET(ep, F_NOLOG);
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * log_end --
+ * Close the logging subsystem.
+ */
+int
+log_end(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ if (ep->log != NULL) {
+ (void)(ep->log->close)(ep->log);
+ ep->log = NULL;
+ }
+ if (ep->l_lp != NULL) {
+ free(ep->l_lp);
+ ep->l_lp = NULL;
+ }
+ ep->l_len = 0;
+ ep->l_cursor.lno = 1; /* XXX Any valid recno. */
+ ep->l_cursor.cno = 0;
+ ep->l_high = ep->l_cur = 1;
+ return (0);
+}
+
+/*
+ * log_cursor --
+ * Log the current cursor position, starting an event.
+ */
+int
+log_cursor(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ /*
+ * If any changes were made since the last cursor init,
+ * put out the ending cursor record.
+ */
+ if (ep->l_cursor.lno == OOBLNO) {
+ ep->l_cursor.lno = sp->lno;
+ ep->l_cursor.cno = sp->cno;
+ return (log_cursor1(sp, ep, LOG_CURSOR_END));
+ }
+ ep->l_cursor.lno = sp->lno;
+ ep->l_cursor.cno = sp->cno;
+ return (0);
+}
+
+/*
+ * log_cursor1 --
+ * Actually push a cursor record out.
+ */
+static int
+log_cursor1(sp, ep, type)
+ SCR *sp;
+ EXF *ep;
+ int type;
+{
+ DBT data, key;
+
+ BINC_RET(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK));
+ ep->l_lp[0] = type;
+ memmove(ep->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK));
+
+ key.data = &ep->l_cur;
+ key.size = sizeof(recno_t);
+ data.data = ep->l_lp;
+ data.size = sizeof(u_char) + sizeof(MARK);
+ if (ep->log->put(ep->log, &key, &data, 0) == -1)
+ LOG_ERR;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "%lu: %s: %u/%u\n", ep->l_cur,
+ type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
+ sp->lno, sp->cno);
+#endif
+ /* Reset high water mark. */
+ ep->l_high = ++ep->l_cur;
+
+ return (0);
+}
+
+/*
+ * log_line --
+ * Log a line change.
+ */
+int
+log_line(sp, ep, lno, action)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ u_int action;
+{
+ DBT data, key;
+ size_t len;
+ char *lp;
+
+ if (F_ISSET(ep, F_NOLOG))
+ return (0);
+
+ /*
+ * XXX
+ *
+ * Kluge for vi. Clear the EXF undo flag so that the
+ * next 'u' command does a roll-back, regardless.
+ */
+ F_CLR(ep, F_UNDO);
+
+ /* Put out one initial cursor record per set of changes. */
+ if (ep->l_cursor.lno != OOBLNO) {
+ if (log_cursor1(sp, ep, LOG_CURSOR_INIT))
+ 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
+ * line 1, it just means that the user started with an empty file,
+ * so fake an empty length line.
+ */
+ if (action == LOG_LINE_RESET_B) {
+ if ((lp = file_rline(sp, ep, lno, &len)) == NULL) {
+ if (lno != 1) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ len = 0;
+ lp = "";
+ }
+ } else
+ if ((lp = file_gline(sp, ep, lno, &len)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ BINC_RET(sp,
+ ep->l_lp, ep->l_len, len + sizeof(u_char) + sizeof(recno_t));
+ ep->l_lp[0] = action;
+ memmove(ep->l_lp + sizeof(u_char), &lno, sizeof(recno_t));
+ memmove(ep->l_lp + sizeof(u_char) + sizeof(recno_t), lp, len);
+
+ key.data = &ep->l_cur;
+ key.size = sizeof(recno_t);
+ data.data = ep->l_lp;
+ data.size = len + sizeof(u_char) + sizeof(recno_t);
+ if (ep->log->put(ep->log, &key, &data, 0) == -1)
+ LOG_ERR;
+
+#if defined(DEBUG) && 0
+ switch (action) {
+ case LOG_LINE_APPEND:
+ TRACE(sp, "%u: log_line: append: %lu {%u}\n",
+ ep->l_cur, lno, len);
+ break;
+ case LOG_LINE_DELETE:
+ TRACE(sp, "%lu: log_line: delete: %lu {%u}\n",
+ ep->l_cur, lno, len);
+ break;
+ case LOG_LINE_INSERT:
+ TRACE(sp, "%lu: log_line: insert: %lu {%u}\n",
+ ep->l_cur, lno, len);
+ break;
+ case LOG_LINE_RESET_F:
+ TRACE(sp, "%lu: log_line: reset_f: %lu {%u}\n",
+ ep->l_cur, lno, len);
+ break;
+ case LOG_LINE_RESET_B:
+ TRACE(sp, "%lu: log_line: reset_b: %lu {%u}\n",
+ ep->l_cur, lno, len);
+ break;
+ }
+#endif
+ /* Reset high water mark. */
+ ep->l_high = ++ep->l_cur;
+
+ return (0);
+}
+
+/*
+ * log_mark --
+ * Log a mark position. For the log to work, we assume that there
+ * aren't any operations that just put out a log record -- this
+ * would mean that undo operations would only reset marks, and not
+ * cause any other change.
+ */
+int
+log_mark(sp, ep, lmp)
+ SCR *sp;
+ EXF *ep;
+ LMARK *lmp;
+{
+ DBT data, key;
+
+ if (F_ISSET(ep, F_NOLOG))
+ return (0);
+
+ /* Put out one initial cursor record per set of changes. */
+ if (ep->l_cursor.lno != OOBLNO) {
+ if (log_cursor1(sp, ep, LOG_CURSOR_INIT))
+ return (1);
+ ep->l_cursor.lno = OOBLNO;
+ }
+
+ BINC_RET(sp, ep->l_lp,
+ ep->l_len, sizeof(u_char) + sizeof(LMARK));
+ ep->l_lp[0] = LOG_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(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);
+}
+
+/*
+ * Log_backward --
+ * Roll the log backward one operation.
+ */
+int
+log_backward(sp, ep, rp)
+ SCR *sp;
+ EXF *ep;
+ MARK *rp;
+{
+ DBT key, data;
+ LMARK lm;
+ MARK m;
+ recno_t lno;
+ int didop;
+ u_char *p;
+
+ if (F_ISSET(ep, F_NOLOG)) {
+ msgq(sp, M_ERR,
+ "Logging not being performed, undo not possible");
+ return (1);
+ }
+
+ if (ep->l_cur == 1) {
+ msgq(sp, M_BERR, "No changes to undo");
+ return (1);
+ }
+
+ F_SET(ep, F_NOLOG); /* Turn off logging. */
+
+ key.data = &ep->l_cur; /* Initialize db request. */
+ key.size = sizeof(recno_t);
+ for (didop = 0;;) {
+ --ep->l_cur;
+ if (ep->log->get(ep->log, &key, &data, 0))
+ LOG_ERR;
+#if defined(DEBUG) && 0
+ log_trace(sp, "log_backward", ep->l_cur, data.data);
+#endif
+ switch (*(p = (u_char *)data.data)) {
+ case LOG_CURSOR_INIT:
+ if (didop) {
+ memmove(rp, p + sizeof(u_char), sizeof(MARK));
+ F_CLR(ep, F_NOLOG);
+ return (0);
+ }
+ break;
+ case LOG_CURSOR_END:
+ break;
+ case LOG_LINE_APPEND:
+ case LOG_LINE_INSERT:
+ didop = 1;
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ if (file_dline(sp, ep, lno))
+ goto err;
+ ++sp->rptlines[L_DELETED];
+ break;
+ case LOG_LINE_DELETE:
+ didop = 1;
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ if (file_iline(sp, ep, lno, p + sizeof(u_char) +
+ sizeof(recno_t), data.size - sizeof(u_char) -
+ sizeof(recno_t)))
+ goto err;
+ ++sp->rptlines[L_ADDED];
+ break;
+ case LOG_LINE_RESET_F:
+ break;
+ case LOG_LINE_RESET_B:
+ didop = 1;
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ if (file_sline(sp, ep, lno, p + sizeof(u_char) +
+ sizeof(recno_t), data.size - sizeof(u_char) -
+ sizeof(recno_t)))
+ goto err;
+ if (sp->rptlchange != lno) {
+ sp->rptlchange = lno;
+ ++sp->rptlines[L_CHANGED];
+ }
+ break;
+ case LOG_MARK:
+ didop = 1;
+ 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:
+ abort();
+ }
+ }
+
+err: F_CLR(ep, F_NOLOG);
+ return (1);
+}
+
+/*
+ * Log_setline --
+ * Reset the line to its original appearance.
+ *
+ * XXX
+ * There's a bug in this code due to our not logging cursor movements
+ * unless a change was made. If you do a change, move off the line,
+ * then move back on and do a 'U', the line will be restored to the way
+ * it was before the original change.
+ */
+int
+log_setline(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ DBT key, data;
+ LMARK lm;
+ MARK m;
+ recno_t lno;
+ u_char *p;
+
+ if (F_ISSET(ep, F_NOLOG)) {
+ msgq(sp, M_ERR,
+ "Logging not being performed, undo not possible");
+ return (1);
+ }
+
+ if (ep->l_cur == 1)
+ return (1);
+
+ F_SET(ep, F_NOLOG); /* Turn off logging. */
+
+ key.data = &ep->l_cur; /* Initialize db request. */
+ key.size = sizeof(recno_t);
+
+ for (;;) {
+ --ep->l_cur;
+ if (ep->log->get(ep->log, &key, &data, 0))
+ LOG_ERR;
+#if defined(DEBUG) && 0
+ log_trace(sp, "log_setline", ep->l_cur, data.data);
+#endif
+ switch (*(p = (u_char *)data.data)) {
+ case LOG_CURSOR_INIT:
+ memmove(&m, p + sizeof(u_char), sizeof(MARK));
+ if (m.lno != sp->lno || ep->l_cur == 1) {
+ F_CLR(ep, F_NOLOG);
+ return (0);
+ }
+ break;
+ case LOG_CURSOR_END:
+ memmove(&m, p + sizeof(u_char), sizeof(MARK));
+ if (m.lno != sp->lno) {
+ ++ep->l_cur;
+ F_CLR(ep, F_NOLOG);
+ return (0);
+ }
+ break;
+ case LOG_LINE_APPEND:
+ case LOG_LINE_INSERT:
+ case LOG_LINE_DELETE:
+ case LOG_LINE_RESET_F:
+ break;
+ case LOG_LINE_RESET_B:
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ if (lno == sp->lno &&
+ file_sline(sp, ep, lno, p + sizeof(u_char) +
+ sizeof(recno_t), data.size - sizeof(u_char) -
+ sizeof(recno_t)))
+ goto err;
+ if (sp->rptlchange != lno) {
+ sp->rptlchange = lno;
+ ++sp->rptlines[L_CHANGED];
+ }
+ case LOG_MARK:
+ 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:
+ abort();
+ }
+ }
+
+err: F_CLR(ep, F_NOLOG);
+ return (1);
+}
+
+/*
+ * Log_forward --
+ * Roll the log forward one operation.
+ */
+int
+log_forward(sp, ep, rp)
+ SCR *sp;
+ EXF *ep;
+ MARK *rp;
+{
+ DBT key, data;
+ LMARK lm;
+ MARK m;
+ recno_t lno;
+ int didop;
+ u_char *p;
+
+ if (F_ISSET(ep, F_NOLOG)) {
+ msgq(sp, M_ERR,
+ "Logging not being performed, roll-forward not possible");
+ return (1);
+ }
+
+ if (ep->l_cur == ep->l_high) {
+ msgq(sp, M_BERR, "No changes to re-do");
+ return (1);
+ }
+
+ F_SET(ep, F_NOLOG); /* Turn off logging. */
+
+ key.data = &ep->l_cur; /* Initialize db request. */
+ key.size = sizeof(recno_t);
+ for (didop = 0;;) {
+ ++ep->l_cur;
+ if (ep->log->get(ep->log, &key, &data, 0))
+ LOG_ERR;
+#if defined(DEBUG) && 0
+ log_trace(sp, "log_forward", ep->l_cur, data.data);
+#endif
+ switch (*(p = (u_char *)data.data)) {
+ case LOG_CURSOR_END:
+ if (didop) {
+ ++ep->l_cur;
+ memmove(rp, p + sizeof(u_char), sizeof(MARK));
+ F_CLR(ep, F_NOLOG);
+ return (0);
+ }
+ break;
+ case LOG_CURSOR_INIT:
+ break;
+ case LOG_LINE_APPEND:
+ case LOG_LINE_INSERT:
+ didop = 1;
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ if (file_iline(sp, ep, lno, p + sizeof(u_char) +
+ sizeof(recno_t), data.size - sizeof(u_char) -
+ sizeof(recno_t)))
+ goto err;
+ ++sp->rptlines[L_ADDED];
+ break;
+ case LOG_LINE_DELETE:
+ didop = 1;
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ if (file_dline(sp, ep, lno))
+ goto err;
+ ++sp->rptlines[L_DELETED];
+ break;
+ case LOG_LINE_RESET_B:
+ break;
+ case LOG_LINE_RESET_F:
+ didop = 1;
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ if (file_sline(sp, ep, lno, p + sizeof(u_char) +
+ sizeof(recno_t), data.size - sizeof(u_char) -
+ sizeof(recno_t)))
+ goto err;
+ if (sp->rptlchange != lno) {
+ sp->rptlchange = lno;
+ ++sp->rptlines[L_CHANGED];
+ }
+ break;
+ case LOG_MARK:
+ didop = 1;
+ 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:
+ abort();
+ }
+ }
+
+err: F_CLR(ep, F_NOLOG);
+ return (1);
+}
+
+#if defined(DEBUG) && 0
+static void
+log_trace(sp, msg, rno, p)
+ SCR *sp;
+ char *msg;
+ recno_t rno;
+ u_char *p;
+{
+ LMARK lm;
+ MARK m;
+ recno_t lno;
+
+ switch (*p) {
+ case LOG_CURSOR_INIT:
+ memmove(&m, p + sizeof(u_char), sizeof(MARK));
+ TRACE(sp, "%lu: %s: C_INIT: %u/%u\n", rno, msg, m.lno, m.cno);
+ break;
+ case LOG_CURSOR_END:
+ memmove(&m, p + sizeof(u_char), sizeof(MARK));
+ TRACE(sp, "%lu: %s: C_END: %u/%u\n", rno, msg, m.lno, m.cno);
+ break;
+ case LOG_LINE_APPEND:
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ TRACE(sp, "%lu: %s: APPEND: %lu\n", rno, msg, lno);
+ break;
+ case LOG_LINE_INSERT:
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ TRACE(sp, "%lu: %s: INSERT: %lu\n", rno, msg, lno);
+ break;
+ case LOG_LINE_DELETE:
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ TRACE(sp, "%lu: %s: DELETE: %lu\n", rno, msg, lno);
+ break;
+ case LOG_LINE_RESET_F:
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ TRACE(sp, "%lu: %s: RESET_F: %lu\n", rno, msg, lno);
+ break;
+ case LOG_LINE_RESET_B:
+ memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
+ TRACE(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno);
+ break;
+ case LOG_MARK:
+ 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();
+ }
+}
+#endif
diff --git a/usr.bin/vi/common/log.h b/usr.bin/vi/common/log.h
new file mode 100644
index 000000000000..2974df4d14b6
--- /dev/null
+++ b/usr.bin/vi/common/log.h
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ *
+ * @(#)log.h 8.5 (Berkeley) 3/16/94
+ */
+
+#define LOG_NOTYPE 0
+#define LOG_CURSOR_INIT 1
+#define LOG_CURSOR_END 2
+#define LOG_LINE_APPEND 3
+#define LOG_LINE_DELETE 4
+#define LOG_LINE_INSERT 5
+#define LOG_LINE_RESET_F 6
+#define LOG_LINE_RESET_B 7
+#define LOG_MARK 8
+
+int log_backward __P((SCR *, EXF *, MARK *));
+int log_cursor __P((SCR *, EXF *));
+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 *, LMARK *));
+int log_setline __P((SCR *, EXF *));
diff --git a/usr.bin/vi/common/main.c b/usr.bin/vi/common/main.c
new file mode 100644
index 000000000000..5e4593e57034
--- /dev/null
+++ b/usr.bin/vi/common/main.c
@@ -0,0 +1,711 @@
+/*-
+ * 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 copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.103 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/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>
+#include <unistd.h>
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../ex/tag.h"
+
+enum rc { NOEXIST, NOPERM, OK };
+
+static enum rc exrc_isok __P((SCR *, struct stat *, char *, int, int));
+static void gs_end __P((GS *));
+static GS *gs_init __P((void));
+static void obsolete __P((char *[]));
+static void usage __P((int));
+
+GS *__global_list; /* GLOBAL: List of screens. */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ static int reenter; /* STATIC: Re-entrancy check. */
+ struct stat hsb, lsb;
+ GS *gp;
+ FREF *frp;
+ SCR *sp;
+ u_int flags, saved_vi_mode;
+ int ch, eval, flagchk, readonly, silent, snapshot;
+ char *excmdarg, *myname, *p, *tag_f, *trace_f, *wsizearg;
+ char path[MAXPATHLEN];
+
+ /* Stop if indirecting through a NULL pointer. */
+ if (reenter++)
+ abort();
+
+#ifdef GDBATTACH
+ (void)printf("%u waiting...\n", getpid());
+ (void)read(0, &eval, 1);
+#endif
+
+ /* Set screen type and mode based on the program name. */
+ readonly = 0;
+ if ((myname = strrchr(*argv, '/')) == NULL)
+ myname = *argv;
+ else
+ ++myname;
+ if (!strcmp(myname, "ex") || !strcmp(myname, "nex"))
+ LF_INIT(S_EX);
+ else {
+ /* View is readonly. */
+ if (!strcmp(myname, "view"))
+ readonly = 1;
+ LF_INIT(S_VI_CURSES);
+ }
+ saved_vi_mode = S_VI_CURSES;
+
+ /* Convert old-style arguments into new-style ones. */
+ obsolete(argv);
+
+ /* Parse the arguments. */
+ flagchk = '\0';
+ excmdarg = tag_f = trace_f = wsizearg = NULL;
+ silent = 0;
+ snapshot = 1;
+ while ((ch = getopt(argc, argv, "c:eFRrsT:t:vw:X:")) != EOF)
+ switch (ch) {
+ case 'c': /* Run the command. */
+ excmdarg = optarg;
+ break;
+ case 'e': /* Ex mode. */
+ LF_CLR(S_SCREENS);
+ LF_SET(S_EX);
+ break;
+ case 'F': /* No snapshot. */
+ snapshot = 0;
+ break;
+ case 'R': /* Readonly. */
+ readonly = 1;
+ break;
+ case 'r': /* Recover. */
+ if (flagchk == 't')
+ errx(1,
+ "only one of -r and -t may be specified.");
+ flagchk = 'r';
+ break;
+ case 's':
+ silent = 1;
+ break;
+ case 'T': /* Trace. */
+ trace_f = optarg;
+ break;
+ case 't': /* Tag. */
+ if (flagchk == 'r')
+ errx(1,
+ "only one of -r and -t may be specified.");
+ if (flagchk == 't')
+ errx(1,
+ "only one tag file may be specified.");
+ flagchk = 't';
+ tag_f = optarg;
+ break;
+ case 'v': /* Vi mode. */
+ LF_CLR(S_SCREENS);
+ LF_SET(S_VI_CURSES);
+ break;
+ case 'w':
+ wsizearg = optarg;
+ break;
+ case 'X':
+ if (!strcmp(optarg, "aw")) {
+ LF_CLR(S_SCREENS);
+ LF_SET(S_VI_XAW);
+ saved_vi_mode = S_VI_XAW;
+ break;
+ }
+ /* FALLTHROUGH */
+ case '?':
+ default:
+ usage(LF_ISSET(S_EX));
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Silent is only applicable to ex. */
+ if (silent && !LF_ISSET(S_EX))
+ errx(1, "-s only applicable to ex.");
+
+ /* Build and initialize the GS structure. */
+ __global_list = gp = gs_init();
+
+ /*
+ * If not reading from a terminal, it's like -s was specified.
+ * Vi always reads from the terminal, so fail if it's not a
+ * terminal.
+ */
+ if (!F_ISSET(gp, G_STDIN_TTY)) {
+ silent = 1;
+ if (!LF_ISSET(S_EX)) {
+ msgq(NULL, M_ERR,
+ "Vi's standard input must be a terminal");
+ goto err;
+ }
+ }
+
+ /*
+ * Build and initialize the first/current screen. This is a bit
+ * tricky. If an error is returned, we may or may not have a
+ * screen structure. If we have a screen structure, put it on a
+ * display queue so that the error messages get displayed.
+ */
+ if (screen_init(NULL, &sp, flags)) {
+ if (sp != NULL)
+ CIRCLEQ_INSERT_HEAD(&__global_list->dq, sp, q);
+ goto err;
+ }
+ sp->saved_vi_mode = saved_vi_mode;
+ CIRCLEQ_INSERT_HEAD(&__global_list->dq, sp, q);
+
+ if (trace_f != NULL) {
+#ifdef DEBUG
+ if ((gp->tracefp = fopen(trace_f, "w")) == NULL)
+ err(1, "%s", trace_f);
+ (void)fprintf(gp->tracefp, "\n===\ntrace: open %s\n", trace_f);
+#else
+ msgq(sp, M_ERR, "-T support not compiled into this version");
+#endif
+ }
+
+ if (opts_init(sp)) /* Options initialization. */
+ goto err;
+ if (readonly) /* Global read-only bit. */
+ O_SET(sp, O_READONLY);
+ if (silent) { /* Ex batch mode. */
+ O_CLR(sp, O_AUTOPRINT);
+ O_CLR(sp, O_PROMPT);
+ O_CLR(sp, O_VERBOSE);
+ O_CLR(sp, O_WARN);
+ F_SET(sp, S_EXSILENT);
+ }
+ if (wsizearg != NULL) {
+ ARGS *av[2], a, b;
+ errno = 0;
+ if (strtol(wsizearg, &p, 10) < 0 || errno || *p)
+ errx(1, "illegal window size -- %s.", wsizearg);
+ (void)snprintf(path, sizeof(path), "window=%s", wsizearg);
+ a.bp = (CHAR_T *)path;
+ a.len = strlen(path);
+ b.bp = NULL;
+ b.len = 0;
+ av[0] = &a;
+ av[1] = &b;
+ if (opts_set(sp, NULL, av))
+ msgq(sp, M_ERR,
+ "Unable to set command line window size option");
+ }
+
+ /* Keymaps, special keys, must follow option initializations. */
+ if (term_init(sp))
+ goto err;
+
+#ifdef DIGRAPHS
+ if (digraph_init(sp)) /* Digraph initialization. */
+ goto err;
+#endif
+
+ /*
+ * 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.
+ *
+ * !!!
+ * 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 of both the $HOME and local startup files if they exist,
+ * otherwise the historic ones.
+ *
+ * !!!
+ * For a discussion of permissions and when what .exrc files are
+ * read, see the the comment above the exrc_isok() function below.
+ *
+ * !!!
+ * 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 avoid this, as
+ * it's going to make some commands behave oddly, and I can't imagine
+ * anyone depending on it.
+ */
+ if (!silent) {
+ switch (exrc_isok(sp, &hsb, _PATH_SYSEXRC, 1, 0)) {
+ case NOEXIST:
+ case NOPERM:
+ break;
+ case OK:
+ (void)ex_cfile(sp, NULL, _PATH_SYSEXRC, 0);
+ break;
+ }
+
+ if ((p = getenv("NEXINIT")) != NULL ||
+ (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), 0);
+ F_CLR(sp, S_VLITONLY);
+ free(p);
+ }
+ else if ((p = getenv("HOME")) != NULL && *p) {
+ (void)snprintf(path,
+ sizeof(path), "%s/%s", p, _PATH_NEXRC);
+ switch (exrc_isok(sp, &hsb, path, 0, 1)) {
+ case NOEXIST:
+ (void)snprintf(path,
+ sizeof(path), "%s/%s", p, _PATH_EXRC);
+ if (exrc_isok(sp, &hsb, path, 0, 1) == OK)
+ (void)ex_cfile(sp, NULL, path, 0);
+ break;
+ case NOPERM:
+ break;
+ case OK:
+ (void)ex_cfile(sp, NULL, path, 0);
+ break;
+ }
+ }
+
+ if (O_ISSET(sp, O_EXRC))
+ switch (exrc_isok(sp, &lsb, _PATH_NEXRC, 0, 0)) {
+ case NOEXIST:
+ if (exrc_isok(sp,
+ &lsb, _PATH_EXRC, 0, 0) == OK &&
+ (lsb.st_dev != hsb.st_dev ||
+ lsb.st_ino != hsb.st_ino))
+ (void)ex_cfile(sp, NULL, _PATH_EXRC, 0);
+ 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_NEXRC, 0);
+ break;
+ }
+ }
+
+ /* List recovery files if -r specified without file arguments. */
+ if (flagchk == 'r' && argv[0] == NULL)
+ exit(rcv_list(sp));
+
+ /* Set the file snapshot flag. */
+ if (snapshot)
+ F_SET(gp, G_SNAPSHOT);
+
+ /* Use a tag file if specified. */
+ if (tag_f != NULL && ex_tagfirst(sp, tag_f))
+ goto err;
+
+ /*
+ * Append any remaining arguments as file names. Files are
+ * recovery files if -r specified.
+ */
+ if (*argv != NULL) {
+ sp->argv = sp->cargv = argv;
+ F_SET(sp, S_ARGNOFREE);
+ if (flagchk == 'r')
+ F_SET(sp, S_ARGRECOVER);
+ }
+
+ /*
+ * If the tag option hasn't already created a file, create one.
+ * If no files as arguments, use a temporary file.
+ */
+ if (tag_f == NULL) {
+ if ((frp = file_add(sp,
+ sp->argv == NULL ? NULL : (CHAR_T *)(sp->argv[0]))) == NULL)
+ goto err;
+ if (F_ISSET(sp, S_ARGRECOVER))
+ F_SET(frp, FR_RECOVER);
+ if (file_init(sp, frp, NULL, 0))
+ goto err;
+ }
+
+ /*
+ * If there's an initial command, push it on the command stack.
+ * Historically, it was always an ex command, not vi in vi mode
+ * or ex in ex mode. So, make it look like an ex command to vi.
+ *
+ * !!!
+ * Historically, all such commands were executed with the last
+ * line of the file as the current line, and not the first, so
+ * set up vi to be at the end of the file.
+ */
+ if (excmdarg != NULL)
+ if (IN_EX_MODE(sp)) {
+ if (term_push(sp, "\n", 1, 0))
+ goto err;
+ if (term_push(sp, excmdarg, strlen(excmdarg), 0))
+ goto err;
+ } else if (IN_VI_MODE(sp)) {
+ if (term_push(sp, "\n", 1, 0))
+ goto err;
+ if (term_push(sp, excmdarg, strlen(excmdarg), 0))
+ goto err;
+ if (term_push(sp, ":", 1, 0))
+ goto err;
+ if (file_lline(sp, sp->ep, &sp->frp->lno))
+ goto err;
+ F_SET(sp->frp, FR_CURSORSET);
+ }
+
+ /* Set up signals. */
+ if (sig_init(sp))
+ goto err;
+
+ for (;;) {
+ /* Ignore errors -- other screens may succeed. */
+ (void)sp->s_edit(sp, sp->ep);
+
+ /*
+ * Edit the next screen on the display queue, or, move
+ * a screen from the hidden queue to the display queue.
+ */
+ if ((sp = __global_list->dq.cqh_first) ==
+ (void *)&__global_list->dq)
+ if ((sp = __global_list->hq.cqh_first) !=
+ (void *)&__global_list->hq) {
+ CIRCLEQ_REMOVE(&sp->gp->hq, sp, q);
+ CIRCLEQ_INSERT_TAIL(&sp->gp->dq, sp, q);
+ } else
+ break;
+
+ /*
+ * The screen type may have changed -- reinitialize the
+ * functions in case it has.
+ */
+ switch (F_ISSET(sp, S_SCREENS)) {
+ case S_EX:
+ if (sex_screen_init(sp))
+ goto err;
+ break;
+ case S_VI_CURSES:
+ if (svi_screen_init(sp))
+ goto err;
+ break;
+ case S_VI_XAW:
+ if (xaw_screen_init(sp))
+ goto err;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ eval = 0;
+ if (0)
+err: eval = 1;
+
+ /*
+ * NOTE: sp may be GONE when the screen returns, so only
+ * the gp can be trusted.
+ */
+ gs_end(gp);
+
+ exit(eval);
+}
+
+/*
+ * gs_init --
+ * Build and initialize the GS structure.
+ */
+static GS *
+gs_init()
+{
+ GS *gp;
+ int fd;
+
+ CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS));
+ if (gp == NULL)
+ err(1, NULL);
+
+ CIRCLEQ_INIT(&gp->dq);
+ CIRCLEQ_INIT(&gp->hq);
+ LIST_INIT(&gp->msgq);
+
+ /* Structures shared by screens so stored in the GS structure. */
+ CALLOC_NOMSG(NULL, gp->tty, IBUF *, 1, sizeof(IBUF));
+ if (gp->tty == NULL)
+ err(1, NULL);
+
+ CIRCLEQ_INIT(&gp->dcb_store.textq);
+ LIST_INIT(&gp->cutq);
+ LIST_INIT(&gp->seqq);
+
+ /* Set a flag if we're reading from the tty. */
+ if (isatty(STDIN_FILENO))
+ F_SET(gp, G_STDIN_TTY);
+
+ /*
+ * 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_STDIN_TTY)) {
+ if (tcgetattr(STDIN_FILENO, &gp->original_termios) == -1)
+ err(1, "tcgetattr");
+ 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);
+}
+
+
+/*
+ * gs_end --
+ * End the GS structure.
+ */
+static void
+gs_end(gp)
+ GS *gp;
+{
+ MSG *mp;
+ SCR *sp;
+ char *tty;
+
+ /* Default buffer storage. */
+ (void)text_lfree(&gp->dcb_store.textq);
+
+ /* Reset anything that needs resetting. */
+ if (gp->flags & G_SETMODE) /* O_MESG */
+ if ((tty = ttyname(STDERR_FILENO)) == NULL)
+ warn("ttyname");
+ else if (chmod(tty, gp->origmode) < 0)
+ warn("%s", tty);
+
+ /* Ring the bell if scheduled. */
+ if (F_ISSET(gp, G_BELLSCHED))
+ (void)fprintf(stderr, "\07"); /* \a */
+
+ /* If there are any remaining screens, flush their messages. */
+ 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)
+ (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)
+ (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)
+ (void)fprintf(stderr, "%.*s.\n", (int)mp->len, mp->mbuf);
+
+ /*
+ * DON'T FREE THE GLOBAL STRUCTURE -- WE DIDN'T TURN
+ * OFF SIGNALS/TIMERS, SO IT MAY STILL BE REFERENCED.
+ */
+}
+
+/*
+ * exrc_isok --
+ * Check a .exrc file for source-ability.
+ *
+ * !!!
+ * Historically, vi read the $HOME and local .exrc files if they were owned
+ * by the user's real ID, or the "sourceany" option was set, regardless of
+ * any other considerations. We no longer support the sourceany option as
+ * it's a security problem of mammoth proportions. We require the system
+ * .exrc file to be owned by root, the $HOME .exrc file to be owned by the
+ * user's effective ID (or that the user's effective ID be root) and the
+ * local .exrc files to be owned by the user's effective ID. In all cases,
+ * the file cannot be writeable by anyone other than its owner.
+ *
+ * In O'Reilly ("Learning the VI Editor", Fifth Ed., May 1992, page 106),
+ * it notes that System V release 3.2 and later has an option "[no]exrc".
+ * The behavior is that local .exrc files are read only if the exrc option
+ * is set. The default for the exrc option was off, so, by default, local
+ * .exrc files were not read. The problem this was intended to solve was
+ * that System V permitted users to give away files, so there's no possible
+ * ownership or writeability test to ensure that the file is safe.
+ *
+ * POSIX 1003.2-1992 standardized exrc as an option. It required the exrc
+ * option to be off by default, thus local .exrc files are not to be read
+ * by default. The Rationale noted (incorrectly) that this was a change
+ * to historic practice, but correctly noted that a default of off improves
+ * system security. POSIX also required that vi check the effective user
+ * ID instead of the real user ID, which is why we've switched from historic
+ * practice.
+ *
+ * We initialize the exrc variable to off. If it's turned on by the system
+ * or $HOME .exrc files, and the local .exrc file passes the ownership and
+ * writeability tests, then we read it. This breaks historic 4BSD practice,
+ * but it gives us a measure of security on systems where users can give away
+ * files.
+ */
+static enum rc
+exrc_isok(sp, sbp, path, rootown, rootid)
+ SCR *sp;
+ struct stat *sbp;
+ char *path;
+ int rootown, rootid;
+{
+ uid_t euid;
+ char *emsg, buf[MAXPATHLEN];
+
+ /* Check for the file's existence. */
+ if (stat(path, sbp))
+ return (NOEXIST);
+
+ /* Check ownership permissions. */
+ euid = geteuid();
+ if (!(rootown && sbp->st_uid == 0) &&
+ !(rootid && euid == 0) && sbp->st_uid != euid) {
+ emsg = rootown ?
+ "not owned by you or root" : "not owned by you";
+ goto denied;
+ }
+
+ /* Check writeability. */
+ if (sbp->st_mode & (S_IWGRP | S_IWOTH)) {
+ emsg = "writeable by a user other than the owner";
+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 (NOPERM);
+ }
+ return (OK);
+}
+
+static void
+obsolete(argv)
+ char *argv[];
+{
+ size_t len;
+ char *p;
+
+ /*
+ * Translate old style arguments into something getopt will like.
+ * Make sure it's not text space memory, because ex changes the
+ * strings.
+ * Change "+" into "-c$".
+ * Change "+<anything else>" into "-c<anything else>".
+ * Change "-" into "-s"
+ */
+ while (*++argv)
+ if (argv[0][0] == '+') {
+ if (argv[0][1] == '\0') {
+ MALLOC_NOMSG(NULL, argv[0], char *, 4);
+ if (argv[0] == NULL)
+ err(1, NULL);
+ (void)strcpy(argv[0], "-c$");
+ } else {
+ p = argv[0];
+ len = strlen(argv[0]);
+ MALLOC_NOMSG(NULL, argv[0], char *, len + 2);
+ if (argv[0] == NULL)
+ err(1, NULL);
+ argv[0][0] = '-';
+ argv[0][1] = 'c';
+ (void)strcpy(argv[0] + 2, p + 1);
+ }
+ } else if (argv[0][0] == '-' && argv[0][1] == '\0') {
+ MALLOC_NOMSG(NULL, argv[0], char *, 3);
+ if (argv[0] == NULL)
+ err(1, NULL);
+ (void)strcpy(argv[0], "-s");
+ }
+}
+
+static void
+usage(is_ex)
+ int is_ex;
+{
+#define EX_USAGE \
+ "ex [-eFRrsv] [-c command] [-t tag] [-w size] [files ...]"
+#define VI_USAGE \
+ "vi [-eFRrv] [-c command] [-t tag] [-w size] [files ...]"
+
+ (void)fprintf(stderr, "usage: %s\n", is_ex ? EX_USAGE : VI_USAGE);
+ exit(1);
+}
diff --git a/usr.bin/vi/common/mark.c b/usr.bin/vi/common/mark.c
new file mode 100644
index 000000000000..15b04974fc0f
--- /dev/null
+++ b/usr.bin/vi/common/mark.c
@@ -0,0 +1,272 @@
+/*-
+ * 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[] = "@(#)mark.c 8.19 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+static LMARK *mark_find __P((SCR *, EXF *, ARG_CHAR_T));
+
+/*
+ * Marks are maintained in a key sorted doubly linked list. We can't
+ * use arrays because we have no idea how big an index key could be.
+ * The underlying assumption is that users don't have more than, say,
+ * 10 marks at any one time, so this will be is fast enough.
+ *
+ * Marks are fixed, and modifications to the line don't update the mark's
+ * position in the line. This can be hard. If you add text to the line,
+ * place a mark in that text, undo the addition and use ` to move to the
+ * mark, the location will have disappeared. It's tempting to try to adjust
+ * the mark with the changes in the line, but this is hard to do, especially
+ * if we've given the line to v_ntext.c:v_ntext() for editing. Historic vi
+ * would move to the first non-blank on the line when the mark location was
+ * past the end of the line. This can be complicated by deleting to a mark
+ * that has disappeared using the ` command. Historic vi vi treated this as
+ * a line-mode motion and deleted the line. This implementation complains to
+ * the user.
+ *
+ * In historic vi, marks returned if the operation was undone, unless the
+ * mark had been subsequently reset. Tricky. This is hard to start with,
+ * but in the presence of repeated undo it gets nasty. When a line is
+ * 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.
+ *
+ * All of these routines translate ABSMARK2 to ABSMARK1. Setting either of
+ * the absolute mark locations sets both, so that "m'" and "m`" work like
+ * they, ah, for lack of a better word, "should".
+ */
+
+/*
+ * mark_init --
+ * Set up the marks.
+ */
+int
+mark_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ LMARK *lmp;
+
+ /*
+ * Make sure the marks have been set up. If they
+ * haven't, do so, and create the absolute mark.
+ */
+ 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);
+}
+
+/*
+ * mark_end --
+ * Free up the marks.
+ */
+int
+mark_end(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ LMARK *lmp;
+
+ while ((lmp = ep->marks.lh_first) != NULL) {
+ LIST_REMOVE(lmp, q);
+ FREE(lmp, sizeof(LMARK));
+ }
+ return (0);
+}
+
+/*
+ * mark_get --
+ * Get the location referenced by a mark.
+ */
+int
+mark_get(sp, ep, key, mp)
+ SCR *sp;
+ EXF *ep;
+ ARG_CHAR_T key;
+ MARK *mp;
+{
+ LMARK *lmp;
+ size_t len;
+
+ if (key == ABSMARK2)
+ key = ABSMARK1;
+
+ lmp = mark_find(sp, ep, key);
+ if (lmp == NULL || lmp->name != key) {
+ msgq(sp, M_BERR, "Mark %s: not set", KEY_NAME(sp, key));
+ return (1);
+ }
+ if (F_ISSET(lmp, MARK_DELETED)) {
+ msgq(sp, M_BERR,
+ "Mark %s: the line was deleted", KEY_NAME(sp, key));
+ return (1);
+ }
+ 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",
+ KEY_NAME(sp, key));
+ return (1);
+ }
+ mp->lno = lmp->lno;
+ mp->cno = lmp->cno;
+ return (0);
+}
+
+/*
+ * mark_set --
+ * Set the location referenced by a mark.
+ */
+int
+mark_set(sp, ep, key, value, userset)
+ SCR *sp;
+ EXF *ep;
+ ARG_CHAR_T key;
+ MARK *value;
+ int userset;
+{
+ LMARK *lmp, *lmt;
+
+ if (key == ABSMARK2)
+ key = ABSMARK1;
+
+ /*
+ * The rules are simple. If the user is setting a mark (if it's a
+ * new mark this is always true), it always happens. If not, it's
+ * an undo, and we set it if it's not already set or if it was set
+ * by a previous undo.
+ */
+ 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(lmp, lmt, q);
+ lmp = lmt;
+ } else if (!userset &&
+ !F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET))
+ return (0);
+
+ lmp->lno = value->lno;
+ lmp->cno = value->cno;
+ lmp->name = key;
+ lmp->flags = userset ? MARK_USERSET : 0;
+ return (0);
+}
+
+/*
+ * mark_find --
+ * Find the requested mark, or, the slot immediately before
+ * where it would go.
+ */
+static LMARK *
+mark_find(sp, ep, key)
+ SCR *sp;
+ EXF *ep;
+ ARG_CHAR_T key;
+{
+ LMARK *lmp, *lastlmp;
+
+ /*
+ * Return the requested mark or the slot immediately before
+ * where it should go.
+ */
+ 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);
+}
+
+/*
+ * mark_insdel --
+ * Update the marks based on an insertion or deletion.
+ */
+void
+mark_insdel(sp, ep, op, lno)
+ SCR *sp;
+ EXF *ep;
+ enum operation op;
+ recno_t lno;
+{
+ LMARK *lmp;
+
+ switch (op) {
+ case LINE_APPEND:
+ return;
+ case LINE_DELETE:
+ 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
+ --lmp->lno;
+ return;
+ case LINE_INSERT:
+ for (lmp = ep->marks.lh_first;
+ lmp != NULL; lmp = lmp->q.le_next)
+ if (lmp->lno >= lno)
+ ++lmp->lno;
+ return;
+ case LINE_RESET:
+ return;
+ }
+ /* NOTREACHED */
+}
diff --git a/usr.bin/vi/common/mark.h b/usr.bin/vi/common/mark.h
new file mode 100644
index 000000000000..2c42e50372b7
--- /dev/null
+++ b/usr.bin/vi/common/mark.h
@@ -0,0 +1,73 @@
+/*-
+ * 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.
+ *
+ * @(#)mark.h 8.9 (Berkeley) 7/17/94
+ */
+
+/*
+ * 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 {
+#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. */
+#define MARK_USERSET 0x02 /* User set this mark. */
+ u_int8_t flags;
+};
+
+#define ABSMARK1 '\'' /* Absolute mark name. */
+#define ABSMARK2 '`' /* Absolute mark name. */
+
+/* Mark routines. */
+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/common/mem.h b/usr.bin/vi/common/mem.h
new file mode 100644
index 000000000000..e61f7ffb6430
--- /dev/null
+++ b/usr.bin/vi/common/mem.h
@@ -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.
+ *
+ * @(#)mem.h 8.6 (Berkeley) 6/20/94
+ */
+
+/* Increase the size of a malloc'd buffer. Two versions, one that
+ * returns, one that jumps to an error label.
+ */
+#define BINC_GOTO(sp, lp, llen, nlen) { \
+ if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
+ goto binc_err; \
+}
+#define BINC_RET(sp, lp, llen, nlen) { \
+ if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
+ return (1); \
+}
+
+/*
+ * Get some temporary space, preferably from the global temporary buffer,
+ * from a malloc'd buffer otherwise. Two versions, one that returns, one
+ * that jumps to an error label.
+ */
+#define GET_SPACE_GOTO(sp, bp, blen, nlen) { \
+ GS *__gp = (sp)->gp; \
+ if (F_ISSET(__gp, G_TMP_INUSE)) { \
+ bp = NULL; \
+ blen = 0; \
+ BINC_GOTO(sp, bp, blen, nlen); \
+ } else { \
+ BINC_GOTO(sp, __gp->tmp_bp, __gp->tmp_blen, nlen); \
+ bp = __gp->tmp_bp; \
+ blen = __gp->tmp_blen; \
+ F_SET(__gp, G_TMP_INUSE); \
+ } \
+}
+#define GET_SPACE_RET(sp, bp, blen, nlen) { \
+ GS *__gp = (sp)->gp; \
+ if (F_ISSET(__gp, G_TMP_INUSE)) { \
+ bp = NULL; \
+ blen = 0; \
+ BINC_RET(sp, bp, blen, nlen); \
+ } else { \
+ BINC_RET(sp, __gp->tmp_bp, __gp->tmp_blen, nlen); \
+ bp = __gp->tmp_bp; \
+ blen = __gp->tmp_blen; \
+ F_SET(__gp, G_TMP_INUSE); \
+ } \
+}
+
+/*
+ * Add space to a GET_SPACE returned buffer. Two versions, one that
+ * returns, one that jumps to an error label.
+ */
+#define ADD_SPACE_GOTO(sp, bp, blen, nlen) { \
+ GS *__gp = (sp)->gp; \
+ if (bp == __gp->tmp_bp) { \
+ F_CLR(__gp, G_TMP_INUSE); \
+ BINC_GOTO(sp, __gp->tmp_bp, __gp->tmp_blen, nlen); \
+ bp = __gp->tmp_bp; \
+ blen = __gp->tmp_blen; \
+ F_SET(__gp, G_TMP_INUSE); \
+ } else \
+ BINC_GOTO(sp, bp, blen, nlen); \
+}
+#define ADD_SPACE_RET(sp, bp, blen, nlen) { \
+ GS *__gp = (sp)->gp; \
+ if (bp == __gp->tmp_bp) { \
+ F_CLR(__gp, G_TMP_INUSE); \
+ BINC_RET(sp, __gp->tmp_bp, __gp->tmp_blen, nlen); \
+ bp = __gp->tmp_bp; \
+ blen = __gp->tmp_blen; \
+ F_SET(__gp, G_TMP_INUSE); \
+ } else \
+ BINC_RET(sp, bp, blen, nlen); \
+}
+
+/* Free memory, optionally making pointers unusable. */
+#ifdef DEBUG
+#define FREE(p, sz) { \
+ memset(p, 0xff, sz); \
+ free(p); \
+}
+#else
+#define FREE(p, sz) free(p);
+#endif
+
+/* Free a GET_SPACE returned buffer. */
+#define FREE_SPACE(sp, bp, blen) { \
+ if (bp == sp->gp->tmp_bp) \
+ F_CLR(sp->gp, G_TMP_INUSE); \
+ else \
+ FREE(bp, blen); \
+}
+
+/*
+ * Malloc a buffer, casting the return pointer. Various versions.
+ *
+ * !!!
+ * The cast should be unnecessary, malloc(3) and friends return void *'s,
+ * which is all we need. However, some systems that nvi needs to run on
+ * don't do it right yet, resulting in the compiler printing out roughly
+ * a million warnings. After awhile, it seemed easier to put the casts
+ * in instead of explaining it all the time.
+ */
+#define CALLOC_NOMSG(sp, p, cast, nmemb, size) { \
+ p = (cast)calloc(nmemb, size); \
+}
+#define CALLOC(sp, p, cast, nmemb, size) { \
+ if ((p = (cast)calloc(nmemb, size)) == NULL) \
+ msgq(sp, M_SYSERR, NULL); \
+}
+#define CALLOC_RET(sp, p, cast, nmemb, size) { \
+ if ((p = (cast)calloc(nmemb, size)) == NULL) { \
+ msgq(sp, M_SYSERR, NULL); \
+ return (1); \
+ } \
+}
+#define MALLOC_NOMSG(sp, p, cast, size) { \
+ p = (cast)malloc(size); \
+}
+#define MALLOC(sp, p, cast, size) { \
+ if ((p = (cast)malloc(size)) == NULL) \
+ msgq(sp, M_SYSERR, NULL); \
+}
+#define MALLOC_RET(sp, p, cast, size) { \
+ if ((p = (cast)malloc(size)) == NULL) { \
+ msgq(sp, M_SYSERR, NULL); \
+ return (1); \
+ } \
+}
+/*
+ * XXX
+ * Don't depend on realloc(NULL, size) working.
+ */
+#define REALLOC(sp, p, cast, size) { \
+ if ((p = (cast)(p == NULL ? \
+ malloc(size) : realloc(p, size))) == NULL) \
+ 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/common/msg.c b/usr.bin/vi/common/msg.c
new file mode 100644
index 000000000000..f5fe595f44bd
--- /dev/null
+++ b/usr.bin/vi/common/msg.c
@@ -0,0 +1,427 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)msg.c 8.9 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.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>
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * msgq --
+ * Display a message.
+ */
+void
+#ifdef __STDC__
+msgq(SCR *sp, enum msgtype mt, const char *fmt, ...)
+#else
+msgq(sp, mt, fmt, va_alist)
+ SCR *sp;
+ enum msgtype mt;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+ size_t len;
+ char msgbuf[1024];
+
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ /*
+ * It's possible to enter msg when there's no screen to hold
+ * the message. If sp is NULL, ignore the special cases and
+ * just build the message, using __global_list.
+ */
+ if (sp == NULL)
+ goto nullsp;
+
+ switch (mt) {
+ case M_BERR:
+ if (!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 (!O_ISSET(sp, O_VERBOSE))
+ return;
+ mt = M_INFO;
+ /* FALLTHROUGH */
+ case M_INFO:
+ if (F_ISSET(sp, S_EXSILENT))
+ return;
+ break;
+ case M_ERR:
+ case M_SYSERR:
+ break;
+ default:
+ abort();
+ }
+
+nullsp: len = 0;
+
+#define EPREFIX "Error: "
+ if (mt == M_SYSERR) {
+ memmove(msgbuf, EPREFIX, sizeof(EPREFIX) - 1);
+ len += sizeof(EPREFIX) - 1;
+ }
+
+ if (sp != NULL && sp->if_name != NULL) {
+ len += snprintf(msgbuf + len, sizeof(msgbuf) - len,
+ "%s, %d: ", sp->if_name, sp->if_lno);
+ if (len >= sizeof(msgbuf))
+ goto err;
+ }
+
+ if (fmt != NULL) {
+ len += vsnprintf(msgbuf + len, sizeof(msgbuf) - len, fmt, ap);
+ if (len >= sizeof(msgbuf))
+ goto err;
+ }
+
+ if (mt == M_SYSERR) {
+ len += snprintf(msgbuf + len,
+ sizeof(msgbuf) - len, ": %s", strerror(errno));
+ if (len >= sizeof(msgbuf))
+ goto err;
+ }
+
+ /*
+ * If len >= the size, some characters were discarded.
+ * Ignore trailing nul.
+ */
+err: if (len >= sizeof(msgbuf))
+ len = sizeof(msgbuf) - 1;
+
+#ifdef DEBUG
+ if (sp != NULL)
+ TRACE(sp, "%.*s\n", len, msgbuf);
+#endif
+ msg_app(__global_list, sp, mt == M_ERR ? 1 : 0, msgbuf, len);
+}
+
+/*
+ * msg_app --
+ * Append a message into the queue. This can fail, but there's
+ * nothing we can do if it does.
+ */
+void
+msg_app(gp, sp, inv_video, p, len)
+ GS *gp;
+ SCR *sp;
+ int inv_video;
+ char *p;
+ size_t len;
+{
+ static int reenter; /* STATIC: Re-entrancy check. */
+ MSG *mp, *nmp;
+
+ /*
+ * It's possible to reenter msg when it allocates space.
+ * We're probably dead anyway, but no reason to drop core.
+ */
+ if (reenter)
+ return;
+ reenter = 1;
+
+ /*
+ * We can be entered as the result of a signal arriving, trying
+ * to sync the file and failing. This shouldn't be a hot spot,
+ * block the signals.
+ */
+ SIGBLOCK(gp);
+
+ /*
+ * Find an empty structure, or allocate a new one. Use the
+ * screen structure if it exists, otherwise the global one.
+ */
+ if (sp != NULL) {
+ if ((mp = sp->msgq.lh_first) == NULL) {
+ CALLOC(sp, mp, MSG *, 1, sizeof(MSG));
+ if (mp == NULL)
+ goto ret;
+ LIST_INSERT_HEAD(&sp->msgq, mp, q);
+ goto store;
+ }
+ } else if ((mp = gp->msgq.lh_first) == NULL) {
+ CALLOC(sp, mp, MSG *, 1, sizeof(MSG));
+ if (mp == NULL)
+ goto ret;
+ LIST_INSERT_HEAD(&gp->msgq, mp, q);
+ goto store;
+ }
+ while (!F_ISSET(mp, M_EMPTY) && mp->q.le_next != NULL)
+ mp = mp->q.le_next;
+ if (!F_ISSET(mp, M_EMPTY)) {
+ CALLOC(sp, nmp, MSG *, 1, sizeof(MSG));
+ if (nmp == NULL)
+ goto ret;
+ LIST_INSERT_AFTER(mp, nmp, q);
+ mp = nmp;
+ }
+
+ /* Get enough memory for the message. */
+store: if (len > mp->blen && binc(sp, &mp->mbuf, &mp->blen, len))
+ goto ret;
+
+ /* Store the message. */
+ memmove(mp->mbuf, p, len);
+ mp->len = len;
+ mp->flags = inv_video ? M_INV_VIDEO : 0;
+
+ret: reenter = 0;
+ SIGUNBLOCK(gp);
+}
+
+/*
+ * msg_rpt --
+ * Report on the lines that changed.
+ *
+ * !!!
+ * Historic vi documentation (USD:15-8) claimed that "The editor will also
+ * always tell you when a change you make affects text which you cannot see."
+ * 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)
+ SCR *sp;
+ int is_message;
+{
+ static char * const action[] = {
+ "added", "changed", "deleted", "joined", "moved",
+ "left shifted", "right shifted", "yanked",
+ NULL,
+ };
+ recno_t total;
+ u_long rptval;
+ int first, cnt;
+ size_t blen, len;
+ char * const *ap;
+ char *bp, *p, number[40];
+
+ if (F_ISSET(sp, S_EXSILENT))
+ return (0);
+
+ if ((rptval = O_VAL(sp, O_REPORT)) == 0)
+ goto norpt;
+
+ GET_SPACE_RET(sp, bp, blen, 512);
+ p = bp;
+
+ total = 0;
+ for (ap = action, cnt = 0, first = 1; *ap != NULL; ++ap, ++cnt)
+ if (sp->rptlines[cnt] != 0) {
+ total += sp->rptlines[cnt];
+ len = snprintf(number, sizeof(number),
+ "%s%lu lines %s",
+ first ? "" : "; ", sp->rptlines[cnt], *ap);
+ memmove(p, number, len);
+ p += len;
+ first = 0;
+ }
+
+ /*
+ * If nothing to report, return.
+ *
+ * !!!
+ * And now, a special vi clone test. Historically, vi reported if
+ * the number of changed lines was > than the value, not >=. Which
+ * means that users can't report on single line changes, btw.) In
+ * any case, if it was a yank command, it was >=, not >. No lie. I
+ * got complaints, so we do it right.
+ */
+ if (total > rptval || sp->rptlines[L_YANKED] >= rptval) {
+ *p = '\0';
+ if (is_message)
+ msgq(sp, M_INFO, "%s", bp);
+ else
+ ex_printf(EXCOOKIE, "%s\n", bp);
+ }
+
+ FREE_SPACE(sp, bp, blen);
+
+ /* Clear after each report. */
+norpt: sp->rptlchange = OOBLNO;
+ memset(sp->rptlines, 0, sizeof(sp->rptlines));
+ return (0);
+}
+
+/*
+ * msg_status --
+ * Report on the file's status.
+ */
+int
+msg_status(sp, ep, lno, showlast)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ int showlast;
+{
+ recno_t last;
+ char *mo, *nc, *nf, *pid, *ro, *ul;
+#ifdef DEBUG
+ char pbuf[50];
+
+ (void)snprintf(pbuf, sizeof(pbuf), " (pid %u)", getpid());
+ pid = pbuf;
+#else
+ pid = "";
+#endif
+ /*
+ * See nvi/exf.c:file_init() for a description of how and
+ * when the read-only bit is set.
+ *
+ * !!!
+ * The historic display for "name changed" was "[Not edited]".
+ */
+ if (F_ISSET(sp->frp, FR_NEWFILE)) {
+ F_CLR(sp->frp, FR_NEWFILE);
+ nf = "new file";
+ mo = nc = "";
+ } else {
+ nf = "";
+ if (F_ISSET(sp->frp, FR_NAMECHANGE)) {
+ nc = "name changed";
+ mo = F_ISSET(ep, F_MODIFIED) ?
+ ", modified" : ", unmodified";
+ } else {
+ nc = "";
+ mo = F_ISSET(ep, F_MODIFIED) ?
+ "modified" : "unmodified";
+ }
+ }
+ ro = F_ISSET(sp->frp, FR_RDONLY) ? ", readonly" : "";
+ ul = F_ISSET(sp->frp, FR_UNLOCKED) ? ", UNLOCKED" : "";
+ if (showlast) {
+ if (file_lline(sp, ep, &last))
+ return (1);
+ if (last >= 1)
+ msgq(sp, M_INFO,
+ "%s: %s%s%s%s%s: line %lu of %lu [%ld%%]%s",
+ sp->frp->name, nf, nc, mo, ul, ro, lno,
+ last, (lno * 100) / last, pid);
+ else
+ msgq(sp, M_INFO, "%s: %s%s%s%s%s: empty file%s",
+ sp->frp->name, nf, nc, mo, ul, ro, pid);
+ } else
+ msgq(sp, M_INFO, "%s: %s%s%s%s%s: line %lu%s",
+ sp->frp->name, nf, nc, mo, ul, ro, lno, pid);
+ return (0);
+}
+
+#ifdef MSG_CATALOG
+/*
+ * get_msg --
+ * Return a format based on a message number.
+ */
+char *
+get_msg(sp, msgno)
+ SCR *sp;
+ char *s_msgno;
+{
+ DBT data, key;
+ GS *gp;
+ recno_t msgno;
+ char *msg, *p;
+
+ gp = sp == NULL ? __global_list : sp->gp;
+ if (gp->msgdb == NULL) {
+ p = sp == NULL ? _PATH_MSGDEF : O_STR(sp, O_CATALOG);
+ if ((gp->msgdb = dbopen(p,
+ O_NONBLOCK | O_RDONLY, 444, DB_RECNO, NULL)) == NULL) {
+ if ((fmt = malloc(256)) == NULL)
+ return ("");
+ (void)snprintf(fmt,
+ "unable to open %s: %s", p, strerror(errno));
+ return (fmt);
+ }
+ }
+ msgno = atoi(s_msgno);
+ key.data = &msgno;
+ key.size = sizeof(recno_t);
+ switch (gp->msgdb->get(gp->msgdb, &key, &data, 0)) {
+ case 0:
+ return (data.data);
+ case 1:
+ p = "no catalog record %ls";
+ break;
+ case -1:
+ p = "catalog record %s: %s";
+ break;
+ }
+ if ((fmt = malloc(256)) == NULL)
+ return ("");
+ (void)snprintf(fmt, p, msgno, strerror(errno));
+ return (fmt);
+}
+#endif
diff --git a/usr.bin/vi/common/msg.h b/usr.bin/vi/common/msg.h
new file mode 100644
index 000000000000..fc6e365087eb
--- /dev/null
+++ b/usr.bin/vi/common/msg.h
@@ -0,0 +1,82 @@
+/*-
+ * 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.
+ *
+ * @(#)msg.h 8.13 (Berkeley) 8/8/94
+ */
+
+/*
+ * Message types.
+ *
+ * !!!
+ * 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 };
+
+typedef struct _msgh MSGH; /* MESG list head structure. */
+LIST_HEAD(_msgh, _msg);
+
+struct _msg {
+ LIST_ENTRY(_msg) q; /* Linked list of messages. */
+ char *mbuf; /* Message buffer. */
+ size_t blen; /* Message buffer length. */
+ size_t len; /* Message length. */
+
+#define M_EMPTY 0x01 /* No message. */
+#define M_INV_VIDEO 0x02 /* Inverse video. */
+ u_int8_t flags;
+};
+
+/*
+ * Define MSG_CATALOG for the Makefile compile command
+ * line to enable message catalogs.
+ */
+#ifdef MSG_CATALOG
+#define M(number, fmt) number
+char *get_msg __P((SCR *, char *));
+#else
+#define M(number, fmt) fmt
+#endif
+
+/* Messages. */
+void msg_app __P((GS *, SCR *, int, char *, size_t));
+int msg_rpt __P((SCR *, int));
+int msg_status __P((SCR *, EXF *, recno_t, int));
+void msgq __P((SCR *, enum msgtype, const char *, ...));
diff --git a/usr.bin/vi/common/options.awk b/usr.bin/vi/common/options.awk
new file mode 100644
index 000000000000..a6755d9045d2
--- /dev/null
+++ b/usr.bin/vi/common/options.awk
@@ -0,0 +1,9 @@
+# @(#)options.awk 8.1 (Berkeley) 4/17/94
+
+/^\/\* O_[0-9A-Z_]*/ {
+ printf("#define %s %d\n", $2, cnt++);
+ next;
+}
+END {
+ printf("#define O_OPTIONCOUNT %d\n", cnt);
+}
diff --git a/usr.bin/vi/common/options.c b/usr.bin/vi/common/options.c
new file mode 100644
index 000000000000..1c8496d1d01d
--- /dev/null
+++ b/usr.bin/vi/common/options.c
@@ -0,0 +1,890 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)options.c 8.64 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
+#include "vi.h"
+#include "excmd.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 *));
+
+/*
+ * O'Reilly noted options and abbreviations are from "Learning the VI Editor",
+ * Fifth Edition, May 1992. There's no way of knowing what systems they are
+ * actually from.
+ *
+ * HPUX noted options and abbreviations are from "The Ultimate Guide to the
+ * VI and EX Text Editors", 1990.
+ */
+static OPTLIST const optlist[] = {
+/* O_ALTWERASE 4.4BSD */
+ {"altwerase", f_altwerase, OPT_0BOOL, 0},
+/* O_AUTOINDENT 4BSD */
+ {"autoindent", NULL, OPT_0BOOL, 0},
+/* O_AUTOPRINT 4BSD */
+ {"autoprint", NULL, OPT_1BOOL, 0},
+/* O_AUTOWRITE 4BSD */
+ {"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 */
+ {"comment", NULL, OPT_0BOOL, 0},
+/* O_DIGRAPH XXX: Elvis */
+ {"digraph", NULL, OPT_0BOOL, 0},
+/* O_DIRECTORY 4BSD */
+ {"directory", NULL, OPT_STR, 0},
+/* O_EDCOMPATIBLE 4BSD */
+ {"edcompatible",NULL, OPT_0BOOL, 0},
+/* O_ERRORBELLS 4BSD */
+ {"errorbells", NULL, OPT_0BOOL, 0},
+/* O_EXRC System V (undocumented) */
+ {"exrc", NULL, OPT_0BOOL, 0},
+/* O_EXTENDED 4.4BSD */
+ {"extended", NULL, OPT_0BOOL, 0},
+/* O_FLASH HPUX */
+ {"flash", NULL, OPT_1BOOL, 0},
+/* O_HARDTABS 4BSD */
+ {"hardtabs", NULL, OPT_NUM, 0},
+/* O_IGNORECASE 4BSD */
+ {"ignorecase", NULL, OPT_0BOOL, 0},
+/* O_KEYTIME 4.4BSD */
+ {"keytime", NULL, OPT_NUM, 0},
+/* O_LEFTRIGHT 4.4BSD */
+ {"leftright", f_leftright, OPT_0BOOL, 0},
+/* O_LINES 4.4BSD */
+ {"lines", f_lines, OPT_NUM, OPT_NOSAVE},
+/* O_LISP 4BSD */
+/*
+ * 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 */
+ {"magic", NULL, OPT_1BOOL, 0},
+/* O_MATCHTIME 4.4BSD */
+ {"matchtime", NULL, OPT_NUM, 0},
+/* O_MESG 4BSD */
+ {"mesg", f_mesg, OPT_1BOOL, 0},
+/* O_META 4.4BSD */
+ {"meta", NULL, OPT_STR, 0},
+/* O_MODELINE 4BSD */
+ {"modeline", f_modeline, OPT_0BOOL, 0},
+/* O_NUMBER 4BSD */
+ {"number", f_number, OPT_0BOOL, 0},
+/* O_OCTAL 4.4BSD */
+ {"octal", f_octal, OPT_0BOOL, 0},
+/* O_OPEN 4BSD */
+ {"open", NULL, OPT_1BOOL, 0},
+/* O_OPTIMIZE 4BSD */
+ {"optimize", NULL, OPT_1BOOL, 0},
+/* O_PARAGRAPHS 4BSD */
+ {"paragraphs", f_paragraph, OPT_STR, 0},
+/* O_PROMPT 4BSD */
+ {"prompt", NULL, OPT_1BOOL, 0},
+/* O_READONLY 4BSD (undocumented) */
+ {"readonly", f_readonly, OPT_0BOOL, 0},
+/* O_RECDIR 4.4BSD */
+ {"recdir", NULL, OPT_STR, 0},
+/* O_REDRAW 4BSD */
+ {"redraw", NULL, OPT_0BOOL, 0},
+/* O_REMAP 4BSD */
+ {"remap", NULL, OPT_1BOOL, 0},
+/* O_REPORT 4BSD */
+ {"report", NULL, OPT_NUM, OPT_NOSTR},
+/* O_RULER 4.4BSD */
+ {"ruler", NULL, OPT_0BOOL, 0},
+/* O_SCROLL 4BSD */
+ {"scroll", NULL, OPT_NUM, 0},
+/* O_SECTIONS 4BSD */
+ {"sections", f_section, OPT_STR, 0},
+/* O_SHELL 4BSD */
+ {"shell", NULL, OPT_STR, 0},
+/* O_SHIFTWIDTH 4BSD */
+ {"shiftwidth", f_shiftwidth, OPT_NUM, 0},
+/* O_SHOWDIRTY 4.4BSD */
+ {"showdirty", NULL, OPT_0BOOL, 0},
+/* O_SHOWMATCH 4BSD */
+ {"showmatch", NULL, OPT_0BOOL, 0},
+/* O_SHOWMODE 4.4BSD */
+ {"showmode", NULL, OPT_0BOOL, 0},
+/* O_SIDESCROLL 4.4BSD */
+ {"sidescroll", NULL, OPT_NUM, 0},
+/* O_SLOWOPEN 4BSD */
+ {"slowopen", NULL, OPT_0BOOL, 0},
+/* O_SOURCEANY 4BSD (undocumented) */
+ {"sourceany", f_sourceany, OPT_0BOOL, 0},
+/* O_TABSTOP 4BSD */
+ {"tabstop", f_tabstop, OPT_NUM, 0},
+/* O_TAGLENGTH 4BSD */
+ {"taglength", NULL, OPT_NUM, OPT_NOSTR},
+/* O_TAGS 4BSD */
+ {"tags", f_tags, OPT_STR, 0},
+/* O_TERM 4BSD */
+ {"term", f_term, OPT_STR, OPT_NOSAVE},
+/* O_TERSE 4BSD */
+ {"terse", NULL, OPT_0BOOL, 0},
+/* O_TILDEOP 4.4BSD */
+ {"tildeop", NULL, OPT_0BOOL, 0},
+/* O_TIMEOUT 4BSD (undocumented) */
+ {"timeout", NULL, OPT_1BOOL, 0},
+/* O_TTYWERASE 4.4BSD */
+ {"ttywerase", f_ttywerase, OPT_0BOOL, 0},
+/* O_VERBOSE 4.4BSD */
+ {"verbose", NULL, OPT_0BOOL, 0},
+/* O_W1200 4BSD */
+ {"w1200", f_w1200, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
+/* O_W300 4BSD */
+ {"w300", f_w300, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
+/* O_W9600 4BSD */
+ {"w9600", f_w9600, OPT_NUM, OPT_NEVER|OPT_NOSAVE},
+/* O_WARN 4BSD */
+ {"warn", NULL, OPT_1BOOL, 0},
+/* O_WINDOW 4BSD */
+ {"window", f_window, OPT_NUM, 0},
+/* O_WRAPMARGIN 4BSD */
+ {"wrapmargin", NULL, OPT_NUM, OPT_NOSTR},
+/* O_WRAPSCAN 4BSD */
+ {"wrapscan", NULL, OPT_1BOOL, 0},
+/* O_WRITEANY 4BSD */
+ {"writeany", NULL, OPT_0BOOL, 0},
+ {NULL},
+};
+
+typedef struct abbrev {
+ char *name;
+ int offset;
+} OABBREV;
+
+static OABBREV const abbrev[] = {
+ {"ai", O_AUTOINDENT}, /* 4BSD */
+ {"ap", O_AUTOPRINT}, /* 4BSD */
+ {"aw", O_AUTOWRITE}, /* 4BSD */
+ {"bf", O_BEAUTIFY}, /* 4BSD */
+ {"co", O_COLUMNS}, /* 4.4BSD */
+ {"dir", O_DIRECTORY}, /* 4BSD */
+ {"eb", O_ERRORBELLS}, /* 4BSD */
+ {"ed", O_EDCOMPATIBLE}, /* 4BSD */
+ {"ex", O_EXRC}, /* System V (undocumented) */
+ {"ht", O_HARDTABS}, /* 4BSD */
+ {"ic", O_IGNORECASE}, /* 4BSD */
+ {"li", O_LINES}, /* 4.4BSD */
+ {"modelines", O_MODELINE}, /* HPUX */
+ {"nu", O_NUMBER}, /* 4BSD */
+ {"opt", O_OPTIMIZE}, /* 4BSD */
+ {"para", O_PARAGRAPHS}, /* 4BSD */
+ {"re", O_REDRAW}, /* O'Reilly */
+ {"ro", O_READONLY}, /* 4BSD (undocumented) */
+ {"scr", O_SCROLL}, /* 4BSD (undocumented) */
+ {"sect", O_SECTIONS}, /* O'Reilly */
+ {"sh", O_SHELL}, /* 4BSD */
+ {"slow", O_SLOWOPEN}, /* 4BSD */
+ {"sm", O_SHOWMATCH}, /* 4BSD */
+ {"sw", O_SHIFTWIDTH}, /* 4BSD */
+ {"tag", O_TAGS}, /* 4BSD (undocumented) */
+ {"tl", O_TAGLENGTH}, /* 4BSD */
+ {"to", O_TIMEOUT}, /* 4BSD (undocumented) */
+ {"ts", O_TABSTOP}, /* 4BSD */
+ {"tty", O_TERM}, /* 4BSD (undocumented) */
+ {"ttytype", O_TERM}, /* 4BSD (undocumented) */
+ {"w", O_WINDOW}, /* O'Reilly */
+ {"wa", O_WRITEANY}, /* 4BSD */
+ {"wi", O_WINDOW}, /* 4BSD (undocumented) */
+ {"wm", O_WRAPMARGIN}, /* 4BSD */
+ {"ws", O_WRAPSCAN}, /* 4BSD */
+ {NULL},
+};
+
+/*
+ * opts_init --
+ * Initialize some of the options. Since the user isn't really
+ * "setting" these variables, don't set their OPT_SET bits.
+ */
+int
+opts_init(sp)
+ SCR *sp;
+{
+ ARGS *argv[2], a, b;
+ OPTLIST const *op;
+ u_long v;
+ int cnt;
+ char *s, b1[1024];
+
+ a.bp = b1;
+ a.len = 0;
+ b.bp = NULL;
+ b.len = 0;
+ argv[0] = &a;
+ argv[1] = &b;
+
+#define SET_DEF(opt, str) { \
+ if (str != b1) /* GCC puts strings in text-space. */ \
+ (void)strcpy(b1, str); \
+ a.len = strlen(b1); \
+ if (opts_set(sp, NULL, argv)) { \
+ msgq(sp, M_ERR, \
+ "Unable to set default %s option", optlist[opt]); \
+ return (1); \
+ } \
+ F_CLR(&sp->opts[opt], OPT_SET); \
+}
+ /* Set default values. */
+ for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt)
+ if (op->type == OPT_0BOOL)
+ 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
+ * in /tmp by default, hoping it's a memory based file system. There
+ * are two ways to change this -- the user can set either the directory
+ * option or the TMPDIR environmental variable.
+ */
+ (void)snprintf(b1, sizeof(b1), "directory=%s",
+ (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s);
+ SET_DEF(O_DIRECTORY, b1);
+ SET_DEF(O_KEYTIME, "keytime=6");
+ SET_DEF(O_MATCHTIME, "matchtime=7");
+ SET_DEF(O_META, "meta=~{[*?$`'\"\\");
+ SET_DEF(O_REPORT, "report=5");
+ SET_DEF(O_PARAGRAPHS, "paragraphs=IPLPPPQPP LIpplpipbp");
+ (void)snprintf(b1, sizeof(b1), "recdir=%s", _PATH_PRESERVE);
+ SET_DEF(O_RECDIR, b1);
+ SET_DEF(O_SECTIONS, "sections=NHSHH HUnhsh");
+ (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);
+ SET_DEF(O_TERM, b1);
+
+ /*
+ * XXX
+ * Initialize ^D, ^U scrolling value here, after TERM. (We didn't
+ * have the options information when the screen was initialized.)
+ * Initializing term should have created a LINES/COLUMNS value.
+ */
+ sp->defscroll = O_VAL(sp, O_LINES) / 2;
+ (void)snprintf(b1, sizeof(b1), "scroll=%ld", sp->defscroll);
+ SET_DEF(O_SCROLL, b1);
+
+ /*
+ * The default window option values are:
+ * 8 if baud rate <= 600
+ * 16 if baud rate <= 1200
+ * LINES - 1 if baud rate > 1200
+ */
+ v = baud_from_bval(sp);
+ if (v <= 600)
+ v = 8;
+ else if (v <= 1200)
+ v = 16;
+ else
+ v = O_VAL(sp, O_LINES) - 1;
+ (void)snprintf(b1, sizeof(b1), "window=%lu", v);
+ SET_DEF(O_WINDOW, b1);
+
+ SET_DEF(O_WRAPMARGIN, "wrapmargin=0");
+
+ /*
+ * By default, the historic vi always displayed information
+ * about two options, redraw and term. Term seems sufficient.
+ */
+ F_SET(&sp->opts[O_TERM], OPT_SET);
+ return (0);
+}
+
+/*
+ * opts_set --
+ * Change the values of one or more options.
+ */
+int
+opts_set(sp, usage, argv)
+ SCR *sp;
+ char *usage;
+ ARGS *argv[];
+{
+ enum optdisp disp;
+ OABBREV atmp, *ap;
+ OPTLIST const *op;
+ OPTLIST otmp;
+ OPTION *spo;
+ u_long value, turnoff;
+ int ch, equals, offset, qmark, rval;
+ char *endp, *name, *p, *sep;
+
+ disp = NO_DISPLAY;
+ for (rval = 0; argv[0]->len != 0; ++argv) {
+ /*
+ * The historic vi dumped the options for each occurrence of
+ * "all" in the set list. Puhleeze.
+ */
+ if (!strcmp(argv[0]->bp, "all")) {
+ disp = ALL_DISPLAY;
+ continue;
+ }
+
+ /* Find equals sign or question mark. */
+ for (sep = NULL, equals = qmark = 0,
+ p = name = argv[0]->bp; (ch = *p) != '\0'; ++p)
+ if (ch == '=' || ch == '?') {
+ if (p == name) {
+ if (usage != NULL)
+ msgq(sp,
+ M_ERR, "Usage: %s", usage);
+ return (1);
+ }
+ sep = p;
+ if (ch == '=')
+ equals = 1;
+ else
+ qmark = 1;
+ break;
+ }
+
+ turnoff = 0;
+ op = NULL;
+ if (sep != NULL)
+ *sep++ = '\0';
+
+ /* Check list of abbreviations. */
+ atmp.name = name;
+ if ((ap = bsearch(&atmp, abbrev,
+ sizeof(abbrev) / sizeof(OABBREV) - 1,
+ sizeof(OABBREV), opts_abbcmp)) != NULL) {
+ op = optlist + ap->offset;
+ goto found;
+ }
+
+ /* Check list of options. */
+ otmp.name = name;
+ if ((op = bsearch(&otmp, optlist,
+ sizeof(optlist) / sizeof(OPTLIST) - 1,
+ sizeof(OPTLIST), opts_cmp)) != NULL)
+ goto found;
+
+ /* Try the name without any leading "no". */
+ if (name[0] == 'n' && name[1] == 'o') {
+ turnoff = 1;
+ name += 2;
+ } else
+ goto prefix;
+
+ /* Check list of abbreviations. */
+ atmp.name = name;
+ if ((ap = bsearch(&atmp, abbrev,
+ sizeof(abbrev) / sizeof(OABBREV) - 1,
+ sizeof(OABBREV), opts_abbcmp)) != NULL) {
+ op = optlist + ap->offset;
+ goto found;
+ }
+
+ /* Check list of options. */
+ otmp.name = name;
+ if ((op = bsearch(&otmp, optlist,
+ sizeof(optlist) / sizeof(OPTLIST) - 1,
+ sizeof(OPTLIST), opts_cmp)) != NULL)
+ goto found;
+
+ /* Check for prefix match. */
+prefix: op = opts_prefix(name);
+
+found: if (op == NULL) {
+ msgq(sp, M_ERR,
+ "no %s option: 'set all' gives all option values",
+ name);
+ continue;
+ }
+
+ /* Find current option values. */
+ offset = op - optlist;
+ spo = sp->opts + offset;
+
+ /*
+ * !!!
+ * Historically, the question mark could be a separate
+ * argument.
+ */
+ if (!equals && !qmark &&
+ argv[1]->len == 1 && argv[1]->bp[0] == '?') {
+ ++argv;
+ qmark = 1;
+ }
+
+ /* Set name, value. */
+ switch (op->type) {
+ case OPT_0BOOL:
+ case OPT_1BOOL:
+ if (equals) {
+ msgq(sp, M_ERR,
+ "set: [no]%s option doesn't take a value",
+ name);
+ break;
+ }
+ if (qmark) {
+ if (!disp)
+ disp = SELECT_DISPLAY;
+ F_SET(spo, OPT_SELECTED);
+ break;
+ }
+ if (op->func != NULL) {
+ if (op->func(sp, spo, NULL, turnoff)) {
+ rval = 1;
+ break;
+ }
+ } else if (turnoff)
+ O_CLR(sp, offset);
+ else
+ O_SET(sp, offset);
+ goto change;
+ case OPT_NUM:
+ /*
+ * !!!
+ * Extension to historic vi. If the OPT_NOSTR flag is
+ * set, a numeric option may be turned off by using a
+ * "no" prefix, e.g. "nowrapmargin". (We assume that
+ * setting the value to 0 turns a numeric option off.)
+ */
+ if (turnoff) {
+ if (F_ISSET(op, OPT_NOSTR)) {
+ value = 0;
+ goto nostr;
+ }
+ msgq(sp, M_ERR,
+ "set: %s option isn't a boolean", name);
+ break;
+ }
+ if (qmark || !equals) {
+ if (!disp)
+ disp = SELECT_DISPLAY;
+ F_SET(spo, OPT_SELECTED);
+ break;
+ }
+ value = strtol(sep, &endp, 10);
+ if (*endp && !isblank(*endp)) {
+ msgq(sp, M_ERR,
+ "set %s: illegal number %s", name, sep);
+ break;
+ }
+nostr: if (op->func != NULL) {
+ if (op->func(sp, spo, sep, value)) {
+ rval = 1;
+ break;
+ }
+ } else
+ O_VAL(sp, offset) = value;
+ goto change;
+ case OPT_STR:
+ if (turnoff) {
+ msgq(sp, M_ERR,
+ "set: %s option isn't a boolean", name);
+ break;
+ }
+ if (qmark || !equals) {
+ if (!disp)
+ disp = SELECT_DISPLAY;
+ F_SET(spo, OPT_SELECTED);
+ break;
+ }
+ if (op->func != NULL) {
+ if (op->func(sp, spo, sep, (u_long)0)) {
+ rval = 1;
+ break;
+ }
+ } else {
+ if (F_ISSET(&sp->opts[offset], OPT_ALLOCATED))
+ free(O_STR(sp, offset));
+ if ((O_STR(sp, offset) = strdup(sep)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ rval = 1;
+ break;
+ } else
+ F_SET(&sp->opts[offset], OPT_ALLOCATED);
+ }
+change: if (sp->s_optchange != NULL)
+ (void)sp->s_optchange(sp, offset);
+ F_SET(&sp->opts[offset], OPT_SET);
+ break;
+ default:
+ abort();
+ }
+ }
+ if (disp != NO_DISPLAY)
+ opts_dump(sp, disp);
+ return (rval);
+}
+
+/*
+ * opts_dump --
+ * List the current values of selected options.
+ */
+void
+opts_dump(sp, type)
+ SCR *sp;
+ enum optdisp type;
+{
+ OPTLIST const *op;
+ int base, b_num, cnt, col, colwidth, curlen, s_num;
+ int numcols, numrows, row;
+ int b_op[O_OPTIONCOUNT], s_op[O_OPTIONCOUNT];
+ 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.
+ */
+ for (cnt = 6; cnt > 1; --cnt) {
+ colwidth = (sp->cols - 1) / cnt & ~(STANDARD_TAB - 1);
+ if (colwidth >= 10) {
+ colwidth =
+ (colwidth + STANDARD_TAB) & ~(STANDARD_TAB - 1);
+ break;
+ }
+ colwidth = 0;
+ }
+
+ /*
+ * 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 != NULL; ++op) {
+ cnt = op - optlist;
+
+ /* If OPT_NEVER set, it's never displayed. */
+ if (F_ISSET(op, OPT_NEVER))
+ continue;
+
+ switch (type) {
+ case ALL_DISPLAY: /* Display all. */
+ break;
+ case CHANGED_DISPLAY: /* Display changed. */
+ if (!F_ISSET(&sp->opts[cnt], OPT_SET))
+ continue;
+ break;
+ case SELECT_DISPLAY: /* Display selected. */
+ if (!F_ISSET(&sp->opts[cnt], OPT_SELECTED))
+ continue;
+ break;
+ default:
+ case NO_DISPLAY:
+ abort();
+ /* NOTREACHED */
+ }
+ F_CLR(&sp->opts[cnt], OPT_SELECTED);
+
+ curlen = strlen(op->name);
+ switch (op->type) {
+ case OPT_0BOOL:
+ case OPT_1BOOL:
+ if (!O_ISSET(sp, cnt))
+ curlen += 2;
+ break;
+ case OPT_NUM:
+ (void)snprintf(nbuf,
+ sizeof(nbuf), "%ld", O_VAL(sp, cnt));
+ curlen += strlen(nbuf);
+ break;
+ case OPT_STR:
+ curlen += strlen(O_STR(sp, cnt)) + 3;
+ break;
+ }
+ /* Offset by two so there's a gap. */
+ if (curlen < colwidth - 2)
+ s_op[s_num++] = cnt;
+ else
+ b_op[b_num++] = 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");
+ }
+ }
+
+ for (row = 0; row < b_num;) {
+ (void)opts_print(sp, &optlist[b_op[row]]);
+ if (++row < b_num)
+ (void)ex_printf(EXCOOKIE, "\n");
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+}
+
+/*
+ * opts_print --
+ * Print out an option.
+ */
+static int
+opts_print(sp, op)
+ SCR *sp;
+ OPTLIST const *op;
+{
+ int curlen, offset;
+
+ curlen = 0;
+ offset = op - optlist;
+ switch (op->type) {
+ case OPT_0BOOL:
+ case OPT_1BOOL:
+ curlen += ex_printf(EXCOOKIE,
+ "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name);
+ break;
+ case OPT_NUM:
+ curlen += ex_printf(EXCOOKIE,
+ "%s=%ld", op->name, O_VAL(sp, offset));
+ break;
+ case OPT_STR:
+ curlen += ex_printf(EXCOOKIE,
+ "%s=\"%s\"", op->name, O_STR(sp, offset));
+ break;
+ }
+ return (curlen);
+}
+
+/*
+ * opts_save --
+ * Write the current configuration to a file.
+ */
+int
+opts_save(sp, fp)
+ SCR *sp;
+ FILE *fp;
+{
+ OPTLIST const *op;
+ int ch, cnt;
+ char *p;
+
+ for (op = optlist; op->name != NULL; ++op) {
+ if (F_ISSET(op, OPT_NOSAVE))
+ continue;
+ cnt = op - optlist;
+ switch (op->type) {
+ case OPT_0BOOL:
+ case OPT_1BOOL:
+ if (O_ISSET(sp, cnt))
+ (void)fprintf(fp, "set %s\n", op->name);
+ else
+ (void)fprintf(fp, "set no%s\n", op->name);
+ break;
+ case OPT_NUM:
+ (void)fprintf(fp,
+ "set %s=%-3d\n", op->name, O_VAL(sp, cnt));
+ break;
+ case OPT_STR:
+ (void)fprintf(fp, "set ");
+ for (p = op->name; (ch = *p) != '\0'; ++p) {
+ if (isblank(ch) || ch == '\\')
+ (void)putc('\\', fp);
+ (void)putc(ch, fp);
+ }
+ (void)putc('=', fp);
+ for (p = O_STR(sp, cnt); (ch = *p) != '\0'; ++p) {
+ if (isblank(ch) || ch == '\\')
+ (void)putc('\\', fp);
+ (void)putc(ch, fp);
+ }
+ (void)putc('\n', fp);
+ break;
+ }
+ if (ferror(fp)) {
+ msgq(sp, M_ERR, "I/O error: %s", strerror(errno));
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * opts_prefix --
+ * Check to see if the name is the prefix of one (and only one)
+ * option. If so, return the option.
+ */
+static OPTLIST const *
+opts_prefix(name)
+ char *name;
+{
+ OPTLIST const *op, *save_op;
+ size_t len;
+
+ save_op = NULL;
+ len = strlen(name);
+ for (op = optlist; op->name != NULL; ++op) {
+ if (op->name[0] < name[0])
+ continue;
+ if (op->name[0] > name[0])
+ break;
+ if (!memcmp(op->name, name, len)) {
+ if (save_op != NULL)
+ return (NULL);
+ save_op = op;
+ }
+ }
+ return (save_op);
+}
+
+static int
+opts_abbcmp(a, b)
+ const void *a, *b;
+{
+ return(strcmp(((OABBREV *)a)->name, ((OABBREV *)b)->name));
+}
+
+static int
+opts_cmp(a, b)
+ const void *a, *b;
+{
+ return(strcmp(((OPTLIST *)a)->name, ((OPTLIST *)b)->name));
+}
+
+/*
+ * opts_free --
+ * Free all option strings
+ */
+void
+opts_free(sp)
+ SCR *sp;
+{
+ int cnt;
+ char *p;
+
+ for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt)
+ if (F_ISSET(&sp->opts[cnt], OPT_ALLOCATED)) {
+ p = O_STR(sp, cnt);
+ FREE(p, strlen(p) + 1);
+ }
+}
+
+/*
+ * opts_copy --
+ * Copy a screen's OPTION array.
+ */
+int
+opts_copy(orig, sp)
+ SCR *orig, *sp;
+{
+ OPTION *op;
+ int cnt;
+
+ /* Copy most everything without change. */
+ memmove(sp->opts, orig->opts, sizeof(orig->opts));
+
+ /*
+ * Allocate copies of the strings -- keep trying to reallocate
+ * after ENOMEM failure, otherwise end up with more than one
+ * screen referencing the original memory.
+ */
+ for (op = sp->opts, cnt = 0; cnt < O_OPTIONCOUNT; ++cnt, ++op)
+ if (F_ISSET(&sp->opts[cnt], OPT_ALLOCATED) &&
+ (O_STR(sp, cnt) = strdup(O_STR(sp, cnt))) == NULL) {
+ msgq(orig, M_SYSERR, NULL);
+ return (1);
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/common/options.h.stub b/usr.bin/vi/common/options.h.stub
new file mode 100644
index 000000000000..0e2051d76117
--- /dev/null
+++ b/usr.bin/vi/common/options.h.stub
@@ -0,0 +1,108 @@
+/*-
+ * 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.
+ *
+ * @(#)options.h.stub 8.22 (Berkeley) 8/8/94
+ */
+
+struct _option {
+ union {
+ u_long val; /* Value or boolean. */
+ char *str; /* String. */
+ } o_u;
+ size_t len; /* String length. */
+
+#define OPT_ALLOCATED 0x01 /* Allocated space. */
+#define OPT_SELECTED 0x02 /* Selected for display. */
+#define OPT_SET 0x04 /* Set (display for the user). */
+ u_char flags;
+};
+
+struct _optlist {
+ char *name; /* Name. */
+ /* Change function. */
+ int (*func) __P((SCR *, OPTION *, char *, u_long));
+ /* Type of object. */
+ enum { OPT_0BOOL, OPT_1BOOL, OPT_NUM, OPT_STR } type;
+
+#define OPT_NEVER 0x01 /* Never display the option. */
+#define OPT_NOSAVE 0x02 /* Mkexrc command doesn't save. */
+#define OPT_NOSTR 0x04 /* String that takes a "no". */
+ u_int flags;
+};
+
+/* Clear, set, test boolean options. */
+#define O_SET(sp, o) (sp)->opts[(o)].o_u.val = 1
+#define O_CLR(sp, o) (sp)->opts[(o)].o_u.val = 0
+#define O_ISSET(sp, o) ((sp)->opts[(o)].o_u.val)
+
+/* Get option values. */
+#define O_LEN(sp, o) (sp)->opts[(o)].len
+#define O_STR(sp, o) (sp)->opts[(o)].o_u.str
+#define O_VAL(sp, o) (sp)->opts[(o)].o_u.val
+
+/* Option routines. */
+u_long baud_from_bval __P((SCR *));
+
+int opts_copy __P((SCR *, SCR *));
+void opts_free __P((SCR *));
+int opts_init __P((SCR *));
+int opts_save __P((SCR *, FILE *));
+int opts_set __P((SCR *, char *, ARGS *[]));
+
+enum optdisp { NO_DISPLAY, ALL_DISPLAY, CHANGED_DISPLAY, SELECT_DISPLAY };
+void opts_dump __P((SCR *, enum optdisp));
+
+/* 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_leftright __P((SCR *, OPTION *, char *, u_long));
+int f_lines __P((SCR *, OPTION *, char *, u_long));
+int f_lisp __P((SCR *, OPTION *, char *, u_long));
+int f_list __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_octal __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_section __P((SCR *, OPTION *, char *, u_long));
+int f_shiftwidth __P((SCR *, OPTION *, char *, u_long));
+int f_sourceany __P((SCR *, OPTION *, char *, u_long));
+int f_tabstop __P((SCR *, OPTION *, char *, u_long));
+int f_tags __P((SCR *, OPTION *, char *, u_long));
+int f_term __P((SCR *, OPTION *, char *, u_long));
+int f_ttywerase __P((SCR *, OPTION *, char *, u_long));
+int f_w1200 __P((SCR *, OPTION *, char *, u_long));
+int f_w300 __P((SCR *, OPTION *, char *, u_long));
+int f_w9600 __P((SCR *, OPTION *, char *, u_long));
+int f_window __P((SCR *, OPTION *, char *, u_long));
diff --git a/usr.bin/vi/common/options_f.c b/usr.bin/vi/common/options_f.c
new file mode 100644
index 000000000000..6e1f060f284e
--- /dev/null
+++ b/usr.bin/vi/common/options_f.c
@@ -0,0 +1,518 @@
+/*-
+ * 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[] = "@(#)options_f.c 8.34 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "../ex/tag.h"
+
+static int opt_dup __P((SCR *, int, char *));
+static int opt_putenv __P((char *));
+
+#define DECL(f) \
+ int \
+ f(sp, op, str, val) \
+ SCR *sp; \
+ OPTION *op; \
+ char *str; \
+ u_long val;
+#define CALL(f) \
+ f(sp, op, str, val)
+
+#define turnoff val
+
+DECL(f_altwerase)
+{
+ if (turnoff)
+ O_CLR(sp, O_ALTWERASE);
+ else {
+ O_SET(sp, O_ALTWERASE);
+ O_CLR(sp, O_TTYWERASE);
+ }
+ return (0);
+}
+
+DECL(f_cdpath)
+{
+ return (opt_dup(sp, O_CDPATH, str));
+}
+
+DECL(f_columns)
+{
+ char buf[25];
+
+ /* Validate the number. */
+ if (val < MINIMUM_SCREEN_COLS) {
+ msgq(sp, M_ERR, "Screen columns too small, less than %d",
+ MINIMUM_SCREEN_COLS);
+ return (1);
+ }
+ /* Set the columns value in the environment for curses. */
+ (void)snprintf(buf, sizeof(buf), "COLUMNS=%lu", val);
+ if (opt_putenv(buf))
+ return (1);
+
+ /* This is expensive, don't do it unless it's necessary. */
+ if (O_VAL(sp, O_COLUMNS) == val)
+ return (0);
+
+ /* Set the value. */
+ O_VAL(sp, O_COLUMNS) = val;
+
+ F_SET(sp, S_RESIZE);
+ return (0);
+}
+
+DECL(f_leftright)
+{
+ if (turnoff)
+ O_CLR(sp, O_LEFTRIGHT);
+ else
+ O_SET(sp, O_LEFTRIGHT);
+ F_SET(sp, S_REFORMAT | S_REDRAW);
+ return (0);
+}
+
+DECL(f_lines)
+{
+ char buf[25];
+
+ /* Validate the number. */
+ if (val < MINIMUM_SCREEN_ROWS) {
+ msgq(sp, M_ERR, "Screen lines too small, less than %d",
+ MINIMUM_SCREEN_ROWS);
+ return (1);
+ }
+
+ /* Set the rows value in the environment for curses. */
+ (void)snprintf(buf, sizeof(buf), "ROWS=%lu", val);
+ if (opt_putenv(buf))
+ return (1);
+
+ /* This is expensive, don't do it unless it's necessary. */
+ if (O_VAL(sp, O_LINES) == val)
+ return (0);
+
+ /* Set the value. */
+ O_VAL(sp, O_LINES) = val;
+
+ /*
+ * If no window value set, set a new default window and,
+ * optionally, a new scroll value.
+ */
+ if (!F_ISSET(&sp->opts[O_WINDOW], OPT_SET)) {
+ O_VAL(sp, O_WINDOW) = val - 1;
+ if (!F_ISSET(&sp->opts[O_SCROLL], OPT_SET))
+ O_VAL(sp, O_SCROLL) = val / 2;
+ }
+
+ F_SET(sp, S_RESIZE);
+ return (0);
+}
+
+DECL(f_lisp)
+{
+ msgq(sp, M_ERR, "The lisp option is not implemented");
+ return (0);
+}
+
+DECL(f_list)
+{
+ if (turnoff)
+ O_CLR(sp, O_LIST);
+ else
+ O_SET(sp, O_LIST);
+
+ F_SET(sp, S_REFORMAT | S_REDRAW);
+ return (0);
+}
+
+DECL(f_mesg)
+{
+ struct stat sb;
+ char *tty;
+
+ /* Find the tty. */
+ if ((tty = ttyname(STDERR_FILENO)) == NULL) {
+ msgq(sp, M_ERR, "ttyname: %s", strerror(errno));
+ return (1);
+ }
+
+ /* Save the tty mode for later; only save it once. */
+ if (!F_ISSET(sp->gp, G_SETMODE)) {
+ F_SET(sp->gp, G_SETMODE);
+ if (stat(tty, &sb) < 0) {
+ msgq(sp, M_ERR, "%s: %s", tty, strerror(errno));
+ return (1);
+ }
+ sp->gp->origmode = sb.st_mode;
+ }
+
+ if (turnoff) {
+ if (chmod(tty, sp->gp->origmode & ~S_IWGRP) < 0) {
+ msgq(sp, M_ERR, "messages not turned off: %s: %s",
+ tty, strerror(errno));
+ return (1);
+ }
+ O_CLR(sp, O_MESG);
+ } else {
+ if (chmod(tty, sp->gp->origmode | S_IWGRP) < 0) {
+ msgq(sp, M_ERR, "messages not turned on: %s: %s",
+ tty, strerror(errno));
+ return (1);
+ }
+ O_SET(sp, O_MESG);
+ }
+ return (0);
+}
+
+/*
+ * f_modeline --
+ * This has been documented in historical systems as both "modeline"
+ * and as "modelines". Regardless of the name, this option represents
+ * a security problem of mammoth proportions, not to mention a stunning
+ * example of what your intro CS professor referred to as the perils of
+ * mixing code and data. Don't add it, or I will kill you.
+ */
+DECL(f_modeline)
+{
+ if (!turnoff)
+ msgq(sp, M_ERR, "The modeline(s) option may never be set");
+ return (0);
+}
+
+DECL(f_number)
+{
+ if (turnoff)
+ O_CLR(sp, O_NUMBER);
+ else
+ O_SET(sp, O_NUMBER);
+
+ F_SET(sp, S_REFORMAT | S_REDRAW);
+ return (0);
+}
+
+DECL(f_octal)
+{
+ if (turnoff)
+ O_CLR(sp, O_OCTAL);
+ else
+ O_SET(sp, O_OCTAL);
+
+ key_init(sp);
+ F_SET(sp, S_REFORMAT | S_REDRAW);
+ return (0);
+}
+
+DECL(f_paragraph)
+{
+ if (strlen(str) & 1) {
+ msgq(sp, M_ERR,
+ "Paragraph options must be in sets of two characters");
+ return (1);
+ }
+ return (opt_dup(sp, O_PARAGRAPHS, str));
+}
+
+DECL(f_readonly)
+{
+ if (turnoff) {
+ O_CLR(sp, O_READONLY);
+ if (sp->frp != NULL)
+ F_CLR(sp->frp, FR_RDONLY);
+ } else {
+ O_SET(sp, O_READONLY);
+ if (sp->frp != NULL)
+ F_SET(sp->frp, FR_RDONLY);
+ }
+ return (0);
+}
+
+DECL(f_section)
+{
+ if (strlen(str) & 1) {
+ msgq(sp, M_ERR,
+ "Section options must be in sets of two characters");
+ return (1);
+ }
+ return (opt_dup(sp, O_SECTIONS, str));
+}
+
+DECL(f_shiftwidth)
+{
+ if (val == 0) {
+ msgq(sp, M_ERR, "The shiftwidth can't be set to 0");
+ return (1);
+ }
+ O_VAL(sp, O_SHIFTWIDTH) = val;
+ return (0);
+}
+
+/*
+ * f_sourceany --
+ * Historic vi, on startup, source'd $HOME/.exrc and ./.exrc, if they
+ * were owned by the user. The sourceany option was an undocumented
+ * feature of historic vi which permitted the startup source'ing of
+ * .exrc files the user didn't own. This is an obvious security problem,
+ * and we ignore the option.
+ */
+DECL(f_sourceany)
+{
+ if (!turnoff)
+ msgq(sp, M_ERR, "The sourceany option may never be set");
+ return (0);
+}
+
+DECL(f_tabstop)
+{
+ if (val == 0) {
+ msgq(sp, M_ERR, "Tab stops can't be set to 0");
+ return (1);
+ }
+#define MAXTABSTOP 20
+ if (val > MAXTABSTOP) {
+ msgq(sp, M_ERR,
+ "Tab stops can't be larger than %d", MAXTABSTOP);
+ return (1);
+ }
+ O_VAL(sp, O_TABSTOP) = val;
+
+ F_SET(sp, S_REFORMAT | S_REDRAW);
+ return (0);
+}
+
+DECL(f_tags)
+{
+ return (opt_dup(sp, O_TAGS, str));
+}
+
+DECL(f_term)
+{
+ char buf[256];
+
+ if (opt_dup(sp, O_TERM, str))
+ return (1);
+
+ /* Set the terminal value in the environment for curses. */
+ (void)snprintf(buf, sizeof(buf), "TERM=%s", str);
+ if (opt_putenv(buf))
+ return (1);
+ 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. */
+ if (baud_from_bval(sp) >= 1200)
+ return (0);
+
+ if (CALL(f_window))
+ return (1);
+
+ if (val > O_VAL(sp, O_LINES) - 1)
+ val = O_VAL(sp, O_LINES) - 1;
+ O_VAL(sp, O_W300) = val;
+ return (0);
+}
+
+DECL(f_w1200)
+{
+ u_long v;
+
+ /* Historical behavior for w1200 was == 1200. */
+ v = baud_from_bval(sp);
+ if (v < 1200 || v > 4800)
+ return (0);
+
+ if (CALL(f_window))
+ return (1);
+
+ if (val > O_VAL(sp, O_LINES) - 1)
+ val = O_VAL(sp, O_LINES) - 1;
+ O_VAL(sp, O_W1200) = val;
+ return (0);
+}
+
+DECL(f_w9600)
+{
+ speed_t v;
+
+ /* Historical behavior for w9600 was > 1200. */
+ v = baud_from_bval(sp);
+ if (v <= 4800)
+ return (0);
+
+ if (CALL(f_window))
+ return (1);
+
+ if (val > O_VAL(sp, O_LINES) - 1)
+ val = O_VAL(sp, O_LINES) - 1;
+ O_VAL(sp, O_W9600) = val;
+ return (0);
+}
+
+DECL(f_window)
+{
+ if (val < MINIMUM_SCREEN_ROWS) {
+ msgq(sp, M_ERR, "Window too small, less than %d",
+ MINIMUM_SCREEN_ROWS);
+ return (1);
+ }
+ if (val > O_VAL(sp, O_LINES) - 1)
+ val = O_VAL(sp, O_LINES) - 1;
+ O_VAL(sp, O_WINDOW) = val;
+ O_VAL(sp, O_SCROLL) = val / 2;
+
+ return (0);
+}
+
+/*
+ * 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
+ * to keep a reference to the memory passed to putenv(3), instead of
+ * having it allocate its own. Someone clearly needs to get promoted
+ * into management.
+ */
+static int
+opt_putenv(s)
+ char *s;
+{
+ char *t;
+
+ /*
+ * XXX
+ * Memory leak.
+ */
+ if ((t = strdup(s)) == NULL)
+ return (1);
+ return (putenv(t));
+}
+
+/*
+ * baud_from_bval --
+ * Return the baud rate using the standard defines.
+ */
+u_long
+baud_from_bval(sp)
+ SCR *sp;
+{
+ if (!F_ISSET(sp->gp, G_TERMIOS_SET))
+ return (9600);
+
+ /*
+ * XXX
+ * There's no portable way to get a "baud rate" -- cfgetospeed(3)
+ * returns the value associated with some #define, which we may
+ * never have heard of, or which may be a purely local speed. Vi
+ * only cares if it's SLOW (w300), slow (w1200) or fast (w9600).
+ * Try and detect the slow ones, and default to fast.
+ */
+ switch (cfgetospeed(&sp->gp->original_termios)) {
+ case B50:
+ case B75:
+ case B110:
+ case B134:
+ case B150:
+ case B200:
+ case B300:
+ case B600:
+ return (600);
+ case B1200:
+ return (1200);
+ }
+ return (9600);
+}
diff --git a/usr.bin/vi/common/pathnames.h b/usr.bin/vi/common/pathnames.h
new file mode 100644
index 000000000000..6ad165f4bb37
--- /dev/null
+++ b/usr.bin/vi/common/pathnames.h
@@ -0,0 +1,45 @@
+/*-
+ * 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.
+ *
+ * @(#)pathnames.h 8.7 (Berkeley) 3/28/94
+ */
+
+#define _PATH_BSHELL "/bin/sh"
+#define _PATH_DEVNULL "/dev/null"
+#define _PATH_EXRC ".exrc"
+#define _PATH_NEXRC ".nexrc"
+#define _PATH_PRESERVE "/var/tmp/vi.recover"
+#define _PATH_SENDMAIL "/usr/sbin/sendmail"
+#define _PATH_SYSEXRC "/etc/vi.exrc"
+#define _PATH_TAGS "tags"
+#define _PATH_TMP "/tmp"
+#define _PATH_TTY "/dev/tty"
diff --git a/usr.bin/vi/common/put.c b/usr.bin/vi/common/put.c
new file mode 100644
index 000000000000..e6dbf3ae4963
--- /dev/null
+++ b/usr.bin/vi/common/put.c
@@ -0,0 +1,254 @@
+/*-
+ * 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.9 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * put --
+ * Put text buffer contents into the file.
+ */
+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;
+ int rval;
+ 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", KEY_NAME(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.
+ *
+ * !!!
+ * Historically, pasting into a file with no lines in vi would preserve
+ * the single blank line. This is surely a result of the fact that the
+ * 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.
+ *
+ * Historical practice is that the cursor ends at the first character
+ * in the file.
+ */
+ if (cp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ for (; tp != (void *)&cbp->textq;
+ ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next)
+ if (file_aline(sp, ep, 1, lno, tp->lb, tp->len))
+ return (1);
+ rp->lno = 1;
+ rp->cno = 0;
+ return (0);
+ }
+ }
+
+ /* 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, ++sp->rptlines[L_ADDED], 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);
+ return (0);
+ }
+
+ /*
+ * 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.
+ */
+ rval = 0;
+ 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;
+ if (sp->rptlchange != lno) {
+ sp->rptlchange = lno;
+ ++sp->rptlines[L_CHANGED];
+ }
+ } 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;
+ if (sp->rptlchange != lno) {
+ sp->rptlchange = lno;
+ ++sp->rptlines[L_CHANGED];
+ }
+
+ /*
+ * 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, ++sp->rptlines[L_ADDED], 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: rval = 1;
+ ++sp->rptlines[L_ADDED];
+ }
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
diff --git a/usr.bin/vi/common/recover.c b/usr.bin/vi/common/recover.c
new file mode 100644
index 000000000000..f218c0645d3e
--- /dev/null
+++ b/usr.bin/vi/common/recover.c
@@ -0,0 +1,869 @@
+/*-
+ * 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[] = "@(#)recover.c 8.72 (Berkeley) 7/21/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+/*
+ * We include <sys/file.h>, because the open #defines were found there
+ * on historical systems. We also include <fcntl.h> because the open(2)
+ * #defines are found there on newer systems.
+ */
+#include <sys/file.h>
+
+#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 "compat.h"
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
+#include "vi.h"
+
+/*
+ * Recovery code.
+ *
+ * The basic scheme is as follows. In the EXF structure, we maintain full
+ * paths of a b+tree file and a mail recovery file. The former is the file
+ * used as backing store by the DB package. The latter is the file that
+ * contains an email message to be sent to the user if we crash. The two
+ * simple states of recovery are:
+ *
+ * + first starting the edit session:
+ * the b+tree file exists and is mode 700, the mail recovery
+ * file doesn't exist.
+ * + after the file has been modified:
+ * the b+tree file exists and is mode 600, the mail recovery
+ * file exists, and is exclusively locked.
+ *
+ * In the EXF structure we maintain a file descriptor that is the locked
+ * file descriptor for the mail recovery file. NOTE: we sometimes have to
+ * do locking with fcntl(2). This is a problem because if you close(2) any
+ * file descriptor associated with the file, ALL of the locks go away. Be
+ * sure to remember that if you have to modify the recovery code. (It has
+ * been rhetorically asked of what the designers could have been thinking
+ * when they did that interface. The answer is simple: they weren't.)
+ *
+ * To find out if a recovery file/backing file pair are in use, try to get
+ * a lock on the recovery file.
+ *
+ * To find out if a backing file can be deleted at boot time, check for an
+ * owner execute bit. (Yes, I know it's ugly, but it's either that or put
+ * special stuff into the backing file itself, or correlate the files at
+ * boot time, neither or which looks like fun.) Note also that there's a
+ * window between when the file is created and the X bit is set. It's small,
+ * but it's there. To fix the window, check for 0 length files as well.
+ *
+ * To find out if a file can be recovered, check the F_RCV_ON bit. Note,
+ * this DOES NOT mean that any initialization has been done, only that we
+ * haven't yet failed at setting up or doing recovery.
+ *
+ * To preserve a recovery file/backing file pair, set the F_RCV_NORM bit.
+ * If that bit is not set when ending a file session:
+ * If the EXF structure paths (rcv_path and rcv_mpath) are not NULL,
+ * they are unlink(2)'d, and free(3)'d.
+ * If the EXF file descriptor (rcv_fd) is not -1, it is closed.
+ *
+ * The backing b+tree file is set up when a file is first edited, so that
+ * the DB package can use it for on-disk caching and/or to snapshot the
+ * file. When the file is first modified, the mail recovery file is created,
+ * the backing file permissions are updated, the file is sync(2)'d to disk,
+ * and the timer is started. Then, at RCV_PERIOD second intervals, the
+ * b+tree file is synced to disk. RCV_PERIOD is measured using SIGALRM, which
+ * means that the data structures (SCR, EXF, the underlying tree structures)
+ * must be consistent when the signal arrives.
+ *
+ * The recovery mail file contains normal mail headers, with two additions,
+ * which occur in THIS order, as the FIRST TWO headers:
+ *
+ * X-vi-recover-file: file_name
+ * X-vi-recover-path: recover_path
+ *
+ * Since newlines delimit the headers, this means that file names cannot have
+ * newlines in them, but that's probably okay. As these files aren't intended
+ * to be long-lived, changing their format won't be too painful.
+ *
+ * Btree files are named "vi.XXXX" and recovery files are named "recover.XXXX".
+ */
+
+#define VI_FHEADER "X-vi-recover-file: "
+#define VI_PHEADER "X-vi-recover-path: "
+
+static int rcv_copy __P((SCR *, int, char *));
+static void rcv_email __P((SCR *, char *));
+static char *rcv_gets __P((char *, size_t, int));
+static int rcv_mailfile __P((SCR *, EXF *, int, char *));
+static int rcv_mktemp __P((SCR *, char *, char *, int));
+
+/*
+ * rcv_tmp --
+ * Build a file name that will be used as the recovery file.
+ */
+int
+rcv_tmp(sp, ep, name)
+ SCR *sp;
+ EXF *ep;
+ char *name;
+{
+ struct stat sb;
+ int fd;
+ char *dp, *p, path[MAXPATHLEN];
+
+ /*
+ * If the recovery directory doesn't exist, try and create it. As
+ * the recovery files are themselves protected from reading/writing
+ * by other than the owner, the worst that can happen is that a user
+ * would have permission to remove other user's recovery files. If
+ * the sticky bit has the BSD semantics, that too will be impossible.
+ */
+ dp = O_STR(sp, O_RECDIR);
+ if (stat(dp, &sb)) {
+ if (errno != ENOENT || mkdir(dp, 0)) {
+ msgq(sp, M_SYSERR, "%s", dp);
+ goto err;
+ }
+ (void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
+ }
+
+ /* Newlines delimit the mail messages. */
+ for (p = name; *p; ++p)
+ if (*p == '\n') {
+ msgq(sp, M_ERR,
+ "Files with newlines in the name are unrecoverable");
+ goto err;
+ }
+
+ (void)snprintf(path, sizeof(path), "%s/vi.XXXXXX", dp);
+ if ((fd = rcv_mktemp(sp, path, dp, S_IRWXU)) == -1)
+ goto err;
+ (void)close(fd);
+
+ if ((ep->rcv_path = strdup(path)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ (void)unlink(path);
+err: msgq(sp, M_ERR,
+ "Modifications not recoverable if the session fails");
+ return (1);
+ }
+
+ /* We believe the file is recoverable. */
+ F_SET(ep, F_RCV_ON);
+ return (0);
+}
+
+/*
+ * rcv_init --
+ * Force the file to be snapshotted for recovery.
+ */
+int
+rcv_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ recno_t lno;
+ int btear;
+
+ /* Only do this once. */
+ F_CLR(ep, F_FIRSTMODIFY);
+
+ /* If we already know the file isn't recoverable, we're done. */
+ if (!F_ISSET(ep, F_RCV_ON))
+ return (0);
+
+ /* Turn off recoverability until we figure out if this will work. */
+ F_CLR(ep, F_RCV_ON);
+
+ /* Test if we're recovering a file, not editing one. */
+ if (ep->rcv_mpath == NULL) {
+ /* Build a file to mail to the user. */
+ if (rcv_mailfile(sp, ep, 0, NULL))
+ goto err;
+
+ /* Force a read of the entire file. */
+ if (file_lline(sp, ep, &lno))
+ goto err;
+
+ /* Turn on a busy message, and sync it to backing store. */
+ 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));
+ if (btear)
+ busy_off(sp);
+ goto err;
+ }
+ if (btear)
+ busy_off(sp);
+ }
+
+ /* Turn on the recovery timer, if it's not yet running. */
+ if (!F_ISSET(sp->gp, G_RECOVER_SET) && rcv_on(sp, ep)) {
+err: msgq(sp, M_ERR,
+ "Modifications not recoverable if the session fails");
+ return (1);
+ }
+
+ /* Turn off the owner execute bit. */
+ (void)chmod(ep->rcv_path, S_IRUSR | S_IWUSR);
+
+ /* We believe the file is recoverable. */
+ F_SET(ep, F_RCV_ON);
+ return (0);
+}
+
+/*
+ * rcv_sync --
+ * Sync the file, optionally:
+ * flagging the backup file to be preserved
+ * snapshotting the backup file and send email to the user
+ * sending email to the user if the file was modified
+ * ending the file session
+ */
+int
+rcv_sync(sp, ep, flags)
+ SCR *sp;
+ EXF *ep;
+ u_int flags;
+{
+ int btear, fd, rval;
+ char *dp, buf[1024];
+
+ /* Make sure that there's something to recover/sync. */
+ if (ep == NULL || !F_ISSET(ep, F_RCV_ON))
+ return (0);
+
+ /* Sync the file if it's been modified. */
+ if (F_ISSET(ep, F_MODIFIED)) {
+ if (ep->db->sync(ep->db, R_RECNOSYNC)) {
+ F_CLR(ep, F_RCV_ON | F_RCV_NORM);
+ msgq(sp, M_SYSERR,
+ "File backup failed: %s", ep->rcv_path);
+ return (1);
+ }
+
+ /* REQUEST: don't remove backing file on exit. */
+ if (LF_ISSET(RCV_PRESERVE))
+ F_SET(ep, F_RCV_NORM);
+
+ /* REQUEST: send email. */
+ if (LF_ISSET(RCV_EMAIL))
+ rcv_email(sp, ep->rcv_mpath);
+ }
+
+ /*
+ * !!!
+ * Each time the user exec's :preserve, we have to snapshot all of
+ * the recovery information, i.e. it's like the user re-edited the
+ * file. We copy the DB(3) backing file, and then create a new mail
+ * recovery file, it's simpler than exiting and reopening all of the
+ * underlying files.
+ *
+ * REQUEST: snapshot the file.
+ */
+ rval = 0;
+ if (LF_ISSET(RCV_SNAPSHOT)) {
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 :
+ !busy_on(sp, "Copying file for recovery...");
+ dp = O_STR(sp, O_RECDIR);
+ (void)snprintf(buf, sizeof(buf), "%s/vi.XXXXXX", dp);
+ if ((fd = rcv_mktemp(sp, buf, dp, S_IRUSR | S_IWUSR)) == -1)
+ goto e1;
+ if (rcv_copy(sp, fd, ep->rcv_path) || close(fd))
+ goto e2;
+ if (rcv_mailfile(sp, ep, 1, buf)) {
+e2: (void)unlink(buf);
+e1: if (fd != -1)
+ (void)close(fd);
+ rval = 1;
+ }
+ if (btear)
+ busy_off(sp);
+ }
+
+ /* REQUEST: end the file session. */
+ if (LF_ISSET(RCV_ENDSESSION) && file_end(sp, ep, 1))
+ rval = 1;
+
+ return (rval);
+}
+
+/*
+ * rcv_mailfile --
+ * Build the file to mail to the user.
+ */
+static int
+rcv_mailfile(sp, ep, issync, cp_path)
+ SCR *sp;
+ EXF *ep;
+ int issync;
+ char *cp_path;
+{
+ struct passwd *pw;
+ size_t len;
+ time_t now;
+ uid_t uid;
+ int fd;
+ char *dp, *p, *t, buf[4096], host[MAXHOSTNAMELEN], mpath[MAXPATHLEN];
+ char *t1, *t2, *t3;
+
+ if ((pw = getpwuid(uid = getuid())) == NULL) {
+ msgq(sp, M_ERR, "Information on user id %u not found", uid);
+ return (1);
+ }
+
+ dp = O_STR(sp, O_RECDIR);
+ (void)snprintf(mpath, sizeof(mpath), "%s/recover.XXXXXX", dp);
+ if ((fd = rcv_mktemp(sp, mpath, dp, S_IRUSR | S_IWUSR)) == -1)
+ return (1);
+
+ /*
+ * XXX
+ * 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. There's an obvious window between the mkstemp call
+ * and the lock, but it's pretty small.
+ */
+ if (file_lock(NULL, NULL, fd, 1) != LOCK_SUCCESS)
+ msgq(sp, M_SYSERR, "Unable to lock recovery file");
+ if (!issync) {
+ /* Save the recover file descriptor, and mail path. */
+ ep->rcv_fd = fd;
+ if ((ep->rcv_mpath = strdup(mpath)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ goto err;
+ }
+ cp_path = ep->rcv_path;
+ }
+
+ /*
+ * XXX
+ * We can't use stdio(3) here. The problem is that we may be using
+ * fcntl(2), so if ANY file descriptor into the file is closed, the
+ * lock is lost. So, we could never close the FILE *, even if we
+ * dup'd the fd first.
+ */
+ t = sp->frp->name;
+ if ((p = strrchr(t, '/')) == NULL)
+ p = t;
+ else
+ ++p;
+ (void)time(&now);
+ (void)gethostname(host, sizeof(host));
+ len = snprintf(buf, sizeof(buf),
+ "%s%s\n%s%s\n%s\n%s\n%s%s\n%s%s\n%s\n\n",
+ VI_FHEADER, t, /* Non-standard. */
+ VI_PHEADER, cp_path, /* Non-standard. */
+ "Reply-To: root",
+ "From: root (Nvi recovery program)",
+ "To: ", pw->pw_name,
+ "Subject: Nvi saved the file ", p,
+ "Precedence: bulk"); /* For vacation(1). */
+ if (len > sizeof(buf) - 1)
+ goto lerr;
+ if (write(fd, buf, len) != len)
+ goto werr;
+
+ len = snprintf(buf, sizeof(buf), "%s%.24s%s%s%s%s%s%s%s%s%s%s%s\n\n",
+ "On ", ctime(&now), ", the user ", pw->pw_name,
+ " was editing a file named ", t, " on the machine ",
+ host, ", when it was saved for recovery. ",
+ "You can recover most, if not all, of the changes ",
+ "to this file using the -r option to nex or nvi:\n\n",
+ "\tnvi -r ", t);
+ if (len > sizeof(buf) - 1) {
+lerr: msgq(sp, M_ERR, "recovery file buffer overrun");
+ goto err;
+ }
+
+ /*
+ * Format the message. (Yes, I know it's silly.)
+ * Requires that the message end in a <newline>.
+ */
+#define FMTCOLS 60
+ for (t1 = buf; len > 0; len -= t2 - t1, t1 = t2) {
+ /* Check for a short length. */
+ if (len <= FMTCOLS) {
+ t2 = t1 + (len - 1);
+ goto wout;
+ }
+
+ /* Check for a required <newline>. */
+ t2 = strchr(t1, '\n');
+ if (t2 - t1 <= FMTCOLS)
+ goto wout;
+
+ /* Find the closest space, if any. */
+ for (t3 = t2; t2 > t1; --t2)
+ if (*t2 == ' ') {
+ if (t2 - t1 <= FMTCOLS)
+ goto wout;
+ t3 = t2;
+ }
+ t2 = t3;
+
+ /* t2 points to the last character to display. */
+wout: *t2++ = '\n';
+
+ /* t2 points one after the last character to display. */
+ if (write(fd, t1, t2 - t1) != t2 - t1) {
+werr: msgq(sp, M_SYSERR, "recovery file");
+ goto err;
+ }
+ }
+
+ if (issync)
+ rcv_email(sp, mpath);
+
+ return (0);
+
+err: if (!issync)
+ ep->rcv_fd = -1;
+ if (fd != -1)
+ (void)close(fd);
+ return (1);
+}
+
+/*
+ * people making love
+ * never exactly the same
+ * just like a snowflake
+ *
+ * rcv_list --
+ * List the files that can be recovered by this user.
+ */
+int
+rcv_list(sp)
+ SCR *sp;
+{
+ struct dirent *dp;
+ struct stat sb;
+ DIR *dirp;
+ FILE *fp;
+ int found;
+ char *p, *t, file[MAXPATHLEN], path[MAXPATHLEN];
+
+ /*
+ * XXX
+ * Messages aren't yet set up.
+ */
+ if (chdir(O_STR(sp, O_RECDIR)) || (dirp = opendir(".")) == NULL) {
+ (void)fprintf(stderr,
+ "vi: %s: %s\n", O_STR(sp, O_RECDIR), strerror(errno));
+ return (1);
+ }
+
+ for (found = 0; (dp = readdir(dirp)) != NULL;) {
+ if (strncmp(dp->d_name, "recover.", 8))
+ continue;
+
+ /*
+ * If it's readable, it's recoverable.
+ *
+ * XXX
+ * Should be "r", we don't want to write the file. However,
+ * if we're using fcntl(2), there's no way to lock a file
+ * descriptor that's not open for writing.
+ */
+ if ((fp = fopen(dp->d_name, "r+")) == NULL)
+ continue;
+
+ switch (file_lock(NULL, NULL, fileno(fp), 1)) {
+ case LOCK_FAILED:
+ /*
+ * XXX
+ * Assume that a lock can't be acquired, but that we
+ * should permit recovery anyway. If this is wrong,
+ * and someone else is using the file, we're going to
+ * die horribly.
+ */
+ break;
+ case LOCK_SUCCESS:
+ break;
+ case LOCK_UNAVAIL:
+ /* If it's locked, it's live. */
+ (void)fclose(fp);
+ continue;
+ }
+
+ /* Check the headers. */
+ if (fgets(file, sizeof(file), fp) == NULL ||
+ strncmp(file, VI_FHEADER, sizeof(VI_FHEADER) - 1) ||
+ (p = strchr(file, '\n')) == NULL ||
+ fgets(path, sizeof(path), fp) == NULL ||
+ strncmp(path, VI_PHEADER, sizeof(VI_PHEADER) - 1) ||
+ (t = strchr(path, '\n')) == NULL) {
+ msgq(sp, M_ERR,
+ "%s: malformed recovery file", dp->d_name);
+ goto next;
+ }
+ *p = *t = '\0';
+
+ /*
+ * If the file doesn't exist, it's an orphaned recovery file,
+ * toss it.
+ *
+ * XXX
+ * This can occur if the backup file was deleted and we crashed
+ * before deleting the email file.
+ */
+ errno = 0;
+ if (stat(path + sizeof(VI_PHEADER) - 1, &sb) &&
+ errno == ENOENT) {
+ (void)unlink(dp->d_name);
+ goto next;
+ }
+
+ /* Get the last modification time and display. */
+ (void)fstat(fileno(fp), &sb);
+ (void)printf("%s: %s",
+ file + sizeof(VI_FHEADER) - 1, ctime(&sb.st_mtime));
+ found = 1;
+
+ /* Close, discarding lock. */
+next: (void)fclose(fp);
+ }
+ if (found == 0)
+ (void)printf("vi: no files to recover.\n");
+ (void)closedir(dirp);
+ return (0);
+}
+
+/*
+ * rcv_read --
+ * Start a recovered file as the file to edit.
+ */
+int
+rcv_read(sp, frp)
+ SCR *sp;
+ FREF *frp;
+{
+ struct dirent *dp;
+ struct stat sb;
+ DIR *dirp;
+ EXF *ep;
+ time_t rec_mtime;
+ int fd, found, locked, requested, sv_fd;
+ char *name, *p, *t, *recp, *pathp;
+ char file[MAXPATHLEN], path[MAXPATHLEN], recpath[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);
+ }
+
+ name = frp->name;
+ sv_fd = -1;
+ rec_mtime = 0;
+ recp = pathp = NULL;
+ for (found = requested = 0; (dp = readdir(dirp)) != NULL;) {
+ if (strncmp(dp->d_name, "recover.", 8))
+ continue;
+ (void)snprintf(recpath, sizeof(recpath),
+ "%s/%s", O_STR(sp, O_RECDIR), dp->d_name);
+
+ /*
+ * If it's readable, it's recoverable. It would be very
+ * nice to use stdio(3), but, we can't because that would
+ * require closing and then reopening the file so that we
+ * could have a lock and still close the FP. Another tip
+ * of the hat to fcntl(2).
+ *
+ * XXX
+ * Should be O_RDONLY, we don't want to write it. However,
+ * if we're using fcntl(2), there's no way to lock a file
+ * descriptor that's not open for writing.
+ */
+ if ((fd = open(recpath, O_RDWR, 0)) == -1)
+ continue;
+
+ switch (file_lock(NULL, NULL, fd, 1)) {
+ case LOCK_FAILED:
+ /*
+ * XXX
+ * Assume that a lock can't be acquired, but that we
+ * should permit recovery anyway. If this is wrong,
+ * and someone else is using the file, we're going to
+ * die horribly.
+ */
+ locked = 0;
+ break;
+ case LOCK_SUCCESS:
+ locked = 1;
+ break;
+ case LOCK_UNAVAIL:
+ /* If it's locked, it's live. */
+ (void)close(fd);
+ continue;
+ }
+
+ /* Check the headers. */
+ if (rcv_gets(file, sizeof(file), fd) == NULL ||
+ strncmp(file, VI_FHEADER, sizeof(VI_FHEADER) - 1) ||
+ (p = strchr(file, '\n')) == NULL ||
+ rcv_gets(path, sizeof(path), fd) == NULL ||
+ strncmp(path, VI_PHEADER, sizeof(VI_PHEADER) - 1) ||
+ (t = strchr(path, '\n')) == NULL) {
+ msgq(sp, M_ERR,
+ "%s: malformed recovery file", recpath);
+ goto next;
+ }
+ *p = *t = '\0';
+ ++found;
+
+ /*
+ * If the file doesn't exist, it's an orphaned recovery file,
+ * toss it.
+ *
+ * XXX
+ * This can occur if the backup file was deleted and we crashed
+ * before deleting the email file.
+ */
+ errno = 0;
+ if (stat(path + sizeof(VI_PHEADER) - 1, &sb) &&
+ errno == ENOENT) {
+ (void)unlink(dp->d_name);
+ goto next;
+ }
+
+ /* Check the file name. */
+ if (strcmp(file + sizeof(VI_FHEADER) - 1, name))
+ goto next;
+
+ ++requested;
+
+ /*
+ * If we've found more than one, take the most recent.
+ *
+ * XXX
+ * Since we're using st_mtime, for portability reasons,
+ * we only get a single second granularity, instead of
+ * getting it right.
+ */
+ (void)fstat(fd, &sb);
+ if (recp == NULL || rec_mtime < sb.st_mtime) {
+ p = recp;
+ t = pathp;
+ if ((recp = strdup(recpath)) == NULL) {
+ msgq(sp, M_ERR,
+ "vi: Error: %s.\n", strerror(errno));
+ recp = p;
+ goto next;
+ }
+ if ((pathp = strdup(path)) == NULL) {
+ msgq(sp, M_ERR,
+ "vi: Error: %s.\n", strerror(errno));
+ FREE(recp, strlen(recp) + 1);
+ recp = p;
+ pathp = t;
+ goto next;
+ }
+ if (p != NULL) {
+ FREE(p, strlen(p) + 1);
+ FREE(t, strlen(t) + 1);
+ }
+ rec_mtime = sb.st_mtime;
+ if (sv_fd != -1)
+ (void)close(sv_fd);
+ sv_fd = fd;
+ } else
+next: (void)close(fd);
+ }
+ (void)closedir(dirp);
+
+ if (recp == NULL) {
+ msgq(sp, M_INFO,
+ "No files named %s, readable by you, to recover", name);
+ return (1);
+ }
+ if (found) {
+ if (requested > 1)
+ msgq(sp, M_INFO,
+ "There are older versions of this file for you to recover");
+ if (found > requested)
+ msgq(sp, M_INFO,
+ "There are other files for you to recover");
+ }
+
+ /*
+ * Create the FREF structure, start the btree file.
+ *
+ * XXX
+ * file_init() is going to set ep->rcv_path.
+ */
+ if (file_init(sp, frp, pathp + sizeof(VI_PHEADER) - 1, 0)) {
+ free(recp);
+ free(pathp);
+ (void)close(sv_fd);
+ 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, just copy it.
+ */
+ ep = sp->ep;
+ ep->rcv_mpath = recp;
+ ep->rcv_fd = sv_fd;
+ if (!locked)
+ F_SET(frp, FR_UNLOCKED);
+
+ /* We believe the file is recoverable. */
+ F_SET(ep, F_RCV_ON);
+ return (0);
+}
+
+/*
+ * rcv_copy --
+ * Copy a recovery file.
+ */
+static int
+rcv_copy(sp, wfd, fname)
+ SCR *sp;
+ int wfd;
+ char *fname;
+{
+ int nr, nw, off, rfd;
+ char buf[8 * 1024];
+
+ if ((rfd = open(fname, O_RDONLY, 0)) == -1)
+ goto err;
+ while ((nr = read(rfd, buf, sizeof(buf))) > 0)
+ for (off = 0; nr; nr -= nw, off += nw)
+ if ((nw = write(wfd, buf + off, nr)) < 0)
+ goto err;
+ if (nr == 0)
+ return (0);
+
+err: msgq(sp, M_SYSERR, "%s", fname);
+ return (1);
+}
+
+/*
+ * rcv_gets --
+ * Fgets(3) for a file descriptor.
+ */
+static char *
+rcv_gets(buf, len, fd)
+ char *buf;
+ size_t len;
+ int fd;
+{
+ ssize_t nr;
+ char *p;
+
+ if ((nr = read(fd, buf, len - 1)) == -1)
+ return (NULL);
+ if ((p = strchr(buf, '\n')) == NULL)
+ return (NULL);
+ (void)lseek(fd, (off_t)((p - buf) + 1), SEEK_SET);
+ return (buf);
+}
+
+/*
+ * rcv_mktemp --
+ * Paranoid make temporary file routine.
+ */
+static int
+rcv_mktemp(sp, path, dname, perms)
+ SCR *sp;
+ char *path, *dname;
+ int perms;
+{
+ int fd;
+
+ /*
+ * !!!
+ * We expect mkstemp(3) to set the permissions correctly. On
+ * historic System V systems, mkstemp didn't. Do it here, on
+ * GP's.
+ *
+ * XXX
+ * The variable perms should really be a mode_t, and it would
+ * be nice to use fchmod(2) instead of chmod(2), here.
+ */
+ if ((fd = mkstemp(path)) == -1)
+ msgq(sp, M_SYSERR, "%s", dname);
+ else
+ (void)chmod(path, perms);
+ return (fd);
+}
+
+/*
+ * rcv_email --
+ * Send email.
+ */
+static void
+rcv_email(sp, fname)
+ SCR *sp;
+ char *fname;
+{
+ struct stat sb;
+ char buf[MAXPATHLEN * 2 + 20];
+
+ if (stat(_PATH_SENDMAIL, &sb))
+ msgq(sp, M_SYSERR, "not sending email: %s", _PATH_SENDMAIL);
+ else {
+ /*
+ * !!!
+ * If you need to port this to a system that doesn't have
+ * sendmail, the -t flag causes sendmail to read the message
+ * for the recipients instead of specifying them some other
+ * way.
+ */
+ (void)snprintf(buf, sizeof(buf),
+ "%s -t < %s", _PATH_SENDMAIL, fname);
+ (void)system(buf);
+ }
+}
diff --git a/usr.bin/vi/common/screen.c b/usr.bin/vi/common/screen.c
new file mode 100644
index 000000000000..d3e27e7da217
--- /dev/null
+++ b/usr.bin/vi/common/screen.c
@@ -0,0 +1,309 @@
+/*-
+ * 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[] = "@(#)screen.c 8.64 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "../vi/vcmd.h"
+#include "excmd.h"
+#include "../ex/tag.h"
+
+/*
+ * screen_init --
+ * Do the default initialization of an SCR structure.
+ */
+int
+screen_init(orig, spp, flags)
+ SCR *orig, **spp;
+ u_int flags;
+{
+ SCR *sp;
+ size_t len;
+
+ *spp = NULL;
+ CALLOC_RET(orig, sp, SCR *, 1, sizeof(SCR));
+ *spp = sp;
+
+/* INITIALIZED AT SCREEN CREATE. */
+ sp->gp = __global_list; /* All ref the GS structure. */
+
+ LIST_INIT(&sp->msgq);
+ CIRCLEQ_INIT(&sp->frefq);
+
+ sp->ccnt = 2; /* Anything > 1 */
+
+ FD_ZERO(&sp->rdfd);
+
+ /*
+ * XXX
+ * sp->defscroll is initialized by the opts_init() code because
+ * we don't have the option information yet.
+ */
+
+ sp->tiqp = &sp->__tiq;
+ CIRCLEQ_INIT(&sp->__tiq);
+
+/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
+ if (orig == NULL) {
+ sp->searchdir = NOTSET;
+
+ switch (flags & S_SCREENS) {
+ case S_EX:
+ if (sex_screen_init(sp))
+ return (1);
+ break;
+ case S_VI_CURSES:
+ if (svi_screen_init(sp))
+ return (1);
+ break;
+ case S_VI_XAW:
+ if (xaw_screen_init(sp))
+ return (1);
+ break;
+ default:
+ abort();
+ }
+
+ sp->flags = flags;
+ } else {
+ if (orig->alt_name != NULL &&
+ (sp->alt_name = strdup(orig->alt_name)) == NULL)
+ goto mem;
+
+ /* Retain all searching/substitution information. */
+ if (F_ISSET(orig, S_SRE_SET)) {
+ F_SET(sp, S_SRE_SET);
+ sp->sre = orig->sre;
+ }
+ if (F_ISSET(orig, S_SUBRE_SET)) {
+ F_SET(sp, S_SUBRE_SET);
+ sp->subre = orig->subre;
+ }
+ sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD;
+
+ if (orig->repl_len) {
+ MALLOC(sp, sp->repl, char *, orig->repl_len);
+ if (sp->repl == NULL)
+ goto mem;
+ sp->repl_len = orig->repl_len;
+ memmove(sp->repl, orig->repl, orig->repl_len);
+ }
+ if (orig->newl_len) {
+ len = orig->newl_len * sizeof(size_t);
+ MALLOC(sp, sp->newl, size_t *, len);
+ if (sp->newl == NULL)
+ goto mem;
+ sp->newl_len = orig->newl_len;
+ sp->newl_cnt = orig->newl_cnt;
+ memmove(sp->newl, orig->newl, len);
+ }
+
+ sp->saved_vi_mode = orig->saved_vi_mode;
+
+ if (opts_copy(orig, sp)) {
+mem: msgq(orig, M_SYSERR, "new screen attributes");
+ (void)screen_end(sp);
+ return (1);
+ }
+
+ sp->s_bell = orig->s_bell;
+ sp->s_bg = orig->s_bg;
+ sp->s_busy = orig->s_busy;
+ sp->s_change = orig->s_change;
+ 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_edit = orig->s_edit;
+ sp->s_end = orig->s_end;
+ sp->s_ex_cmd = orig->s_ex_cmd;
+ sp->s_ex_run = orig->s_ex_run;
+ sp->s_ex_write = orig->s_ex_write;
+ sp->s_fg = orig->s_fg;
+ sp->s_fill = orig->s_fill;
+ sp->s_get = orig->s_get;
+ sp->s_key_read = orig->s_key_read;
+ sp->s_fmap = orig->s_fmap;
+ 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_scroll = orig->s_scroll;
+ sp->s_split = orig->s_split;
+ sp->s_suspend = orig->s_suspend;
+ sp->s_window = orig->s_window;
+
+ F_SET(sp, F_ISSET(orig, S_SCREENS));
+ }
+
+ if (xaw_screen_copy(orig, sp)) /* Init S_VI_XAW screen. */
+ return (1);
+ if (svi_screen_copy(orig, sp)) /* Init S_VI_CURSES screen. */
+ return (1);
+ if (sex_screen_copy(orig, sp)) /* Init S_EX screen. */
+ return (1);
+ if (v_screen_copy(orig, sp)) /* Init vi. */
+ return (1);
+ if (ex_screen_copy(orig, sp)) /* Init ex. */
+ return (1);
+
+ *spp = sp;
+ return (0);
+}
+
+/*
+ * screen_end --
+ * Release a screen.
+ */
+int
+screen_end(sp)
+ SCR *sp;
+{
+ int rval;
+
+ rval = 0;
+ if (xaw_screen_end(sp)) /* End S_VI_XAW screen. */
+ rval = 1;
+ if (svi_screen_end(sp)) /* End S_VI_CURSES screen. */
+ rval = 1;
+ if (sex_screen_end(sp)) /* End S_EX screen. */
+ rval = 1;
+ if (v_screen_end(sp)) /* End vi. */
+ rval = 1;
+ if (ex_screen_end(sp)) /* End ex. */
+ rval = 1;
+
+ /* Free FREF's. */
+ { FREF *frp;
+ while ((frp = sp->frefq.cqh_first) != (FREF *)&sp->frefq) {
+ CIRCLEQ_REMOVE(&sp->frefq, frp, q);
+ if (frp->name != NULL)
+ free(frp->name);
+ if (frp->tname != NULL)
+ free(frp->tname);
+ FREE(frp, sizeof(FREF));
+ }
+ }
+
+ /* Free file names. */
+ { char **ap;
+ if (!F_ISSET(sp, S_ARGNOFREE) && sp->argv != NULL) {
+ for (ap = sp->argv; *ap != NULL; ++ap)
+ free(*ap);
+ free(sp->argv);
+ }
+ }
+
+ /* Free any text input. */
+ text_lfree(&sp->__tiq);
+
+ /* Free any script information. */
+ if (F_ISSET(sp, S_SCRIPT))
+ sscr_end(sp);
+
+ /* Free alternate file name. */
+ if (sp->alt_name != NULL)
+ free(sp->alt_name);
+
+ /* Free up search information. */
+ if (sp->repl != NULL)
+ FREE(sp->repl, sp->repl_len);
+ if (sp->newl != NULL)
+ FREE(sp->newl, sp->newl_len);
+
+ /* Free all the options */
+ opts_free(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.
+ */
+ { SCR *c_sp; MSG *mp, *next;
+ if ((c_sp = sp->q.cqe_prev) != (void *)&sp->gp->dq) {
+ if (F_ISSET(sp, S_BELLSCHED))
+ F_SET(c_sp, S_BELLSCHED);
+ } else if ((c_sp = sp->q.cqe_next) != (void *)&sp->gp->dq) {
+ if (F_ISSET(sp, S_BELLSCHED))
+ F_SET(c_sp, S_BELLSCHED);
+ } else if ((c_sp =
+ sp->gp->hq.cqh_first) != (void *)&sp->gp->hq) {
+ if (F_ISSET(sp, S_BELLSCHED))
+ F_SET(c_sp, S_BELLSCHED);
+ } else {
+ c_sp = NULL;
+ if (F_ISSET(sp, S_BELLSCHED))
+ F_SET(sp->gp, G_BELLSCHED);
+ }
+
+ for (mp = sp->msgq.lh_first; mp != NULL; mp = next) {
+ if (!F_ISSET(mp, M_EMPTY))
+ msg_app(sp->gp, c_sp,
+ mp->flags & M_INV_VIDEO, mp->mbuf, mp->len);
+ next = mp->q.le_next;
+ if (mp->mbuf != NULL)
+ FREE(mp->mbuf, mp->blen);
+ FREE(mp, sizeof(MSG));
+ }
+ }
+
+ /* Remove the screen from the displayed queue. */
+ CIRCLEQ_REMOVE(&sp->gp->dq, sp, q);
+
+ /* Free the screen itself. */
+ FREE(sp, sizeof(SCR));
+
+ return (rval);
+}
diff --git a/usr.bin/vi/common/screen.h b/usr.bin/vi/common/screen.h
new file mode 100644
index 000000000000..31df988ece3a
--- /dev/null
+++ b/usr.bin/vi/common/screen.h
@@ -0,0 +1,342 @@
+/*-
+ * 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.
+ *
+ * @(#)screen.h 8.127 (Berkeley) 8/8/94
+ */
+
+/*
+ * There are minimum values that vi has to have to display a screen. The
+ * row minimum is fixed at 1 line for the text, and 1 line for any error
+ * messages. The column calculation is a lot trickier. For example, you
+ * have to have enough columns to display the line number, not to mention
+ * guaranteeing that tabstop and shiftwidth values are smaller than the
+ * current column value. It's a lot simpler to have a fixed value and not
+ * worry about it.
+ *
+ * XXX
+ * MINIMUM_SCREEN_COLS is probably wrong.
+ */
+#define MINIMUM_SCREEN_ROWS 2
+#define MINIMUM_SCREEN_COLS 20
+
+enum adjust { /* Screen adjustment operations. */
+ A_DECREASE, A_INCREASE, A_SET };
+enum operation { /* Line operations. */
+ LINE_APPEND, LINE_DELETE, LINE_INSERT, LINE_RESET };
+enum position { /* Position operations. */
+ P_BOTTOM, P_FILL, P_MIDDLE, P_TOP };
+enum sctype { /* Scroll operations. */
+ CNTRL_B, CNTRL_D, CNTRL_E, CNTRL_F, CNTRL_U, CNTRL_Y, Z_CARAT, Z_PLUS };
+
+/*
+ * Structure for holding file references. Each SCR structure contains a
+ * linked list of these. The structure contains the name of the file,
+ * along with the information that follows the name.
+ *
+ * !!!
+ * The read-only bit follows the file name, not the file itself.
+ *
+ * XXX
+ * The mtime field should be a struct timespec, but time_t is more portable.
+ */
+struct _fref {
+ CIRCLEQ_ENTRY(_fref) q; /* Linked list of file references. */
+ char *name; /* File name. */
+ char *tname; /* Backing temporary file name. */
+
+ recno_t lno; /* 1-N: file cursor line. */
+ size_t cno; /* 0-N: file cursor column. */
+
+#define FR_CURSORSET 0x001 /* If lno/cno values valid. */
+#define FR_DONTDELETE 0x002 /* Don't delete the temporary file. */
+#define FR_FNONBLANK 0x004 /* Move to the first non-<blank>. */
+#define FR_NAMECHANGE 0x008 /* If the name changed. */
+#define FR_NEWFILE 0x010 /* File doesn't really exist yet. */
+#define FR_RDONLY 0x020 /* File is read-only. */
+#define FR_READNAMED 0x040 /* Read renamed the file. */
+#define FR_RECOVER 0x080 /* File is being recovered. */
+#define FR_TMPEXIT 0x100 /* Modified temporary file, no exit. */
+#define FR_TMPFILE 0x200 /* If file has no name. */
+#define FR_UNLOCKED 0x400 /* File couldn't be locked. */
+ u_int16_t flags;
+};
+
+#define TEMPORARY_FILE_STRING "/tmp" /* Default temporary file name. */
+
+/*
+ * SCR --
+ * The screen structure. To the extent possible, all screen information
+ * is stored in the various private areas. The only information here
+ * is used by global routines or is shared by too many screens.
+ */
+struct _scr {
+/* INITIALIZED AT SCREEN CREATE. */
+ CIRCLEQ_ENTRY(_scr) q; /* Screens. */
+
+ GS *gp; /* Pointer to global area. */
+
+ SCR *nextdisp; /* Next display screen. */
+
+ EXF *ep; /* Screen's current EXF structure. */
+
+ MSGH msgq; /* Message list. */
+ /* FREF list. */
+ CIRCLEQ_HEAD(_frefh, _fref) frefq;
+ FREF *frp; /* FREF being edited. */
+
+ char **argv; /* NULL terminated file name array. */
+ char **cargv; /* Current file name. */
+
+ u_long ccnt; /* Command count. */
+ u_long q_ccnt; /* Quit or ZZ command count. */
+
+ /* Screen's: */
+ size_t rows; /* 1-N: number of rows. */
+ size_t cols; /* 1-N: number of columns. */
+ size_t woff; /* 0-N: row offset in screen. */
+ size_t t_rows; /* 1-N: cur number of text rows. */
+ size_t t_maxrows; /* 1-N: max number of text rows. */
+ size_t t_minrows; /* 1-N: min number of text rows. */
+
+ /* Cursor's: */
+ recno_t lno; /* 1-N: file line. */
+ size_t cno; /* 0-N: file character in line. */
+
+ size_t rcm; /* Vi: 0-N: Most attractive column. */
+ int rcm_last; /* Cursor drawn to the last column. */
+
+#define L_ADDED 0 /* Added lines. */
+#define L_CHANGED 1 /* Changed lines. */
+#define L_DELETED 2 /* Deleted lines. */
+#define L_JOINED 3 /* Joined lines. */
+#define L_MOVED 4 /* Moved lines. */
+#define L_LSHIFT 5 /* Left shift lines. */
+#define L_RSHIFT 6 /* Right shift lines. */
+#define L_YANKED 7 /* Yanked lines. */
+ recno_t rptlchange; /* Ex/vi: last L_CHANGED lno. */
+ recno_t rptlines[L_YANKED + 1];/* Ex/vi: lines changed by last op. */
+
+ FILE *stdfp; /* Ex output file pointer. */
+
+ char *if_name; /* Ex input file name, for messages. */
+ recno_t if_lno; /* Ex input file line, for messages. */
+
+ fd_set rdfd; /* Ex/vi: read fd select mask. */
+
+ TEXTH __tiq; /* Ex/vi: text input queue. */
+ TEXTH *tiqp; /* Ex/vi: text input queue reference. */
+
+ SCRIPT *script; /* Vi: script mode information .*/
+
+ recno_t defscroll; /* Vi: ^D, ^U scroll information. */
+
+ struct timeval busy_tod; /* ITIMER_REAL: busy time-of-day. */
+ char const *busy_msg; /* ITIMER_REAL: busy message. */
+
+ /* Display character. */
+ CHAR_T cname[MAX_CHARACTER_COLUMNS + 1];
+ size_t clen; /* Length of display character. */
+
+#define MAX_MODE_NAME 12
+ char *showmode; /* Mode. */
+
+ void *ex_private; /* Ex private area. */
+ void *sex_private; /* Ex screen private area. */
+ void *vi_private; /* Vi private area. */
+ void *svi_private; /* Vi curses screen private area. */
+ void *xaw_private; /* Vi XAW screen private area. */
+
+/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
+ char *alt_name; /* Ex/vi: alternate file name. */
+
+ /* Ex/vi: search/substitute info. */
+ regex_t sre; /* Last search RE. */
+ regex_t subre; /* Last substitute RE. */
+ enum direction searchdir; /* File search direction. */
+ char *repl; /* Substitute replacement. */
+ size_t repl_len; /* Substitute replacement length.*/
+ size_t *newl; /* Newline offset array. */
+ size_t newl_len; /* Newline array size. */
+ size_t newl_cnt; /* Newlines in replacement. */
+ u_char c_suffix; /* Edcompatible 'c' suffix value. */
+ u_char g_suffix; /* Edcompatible 'g' suffix value. */
+
+ u_int saved_vi_mode; /* Saved vi display type. */
+
+ OPTION opts[O_OPTIONCOUNT]; /* Options. */
+
+/*
+ * SCREEN SUPPORT ROUTINES.
+ *
+ * A SCR * MUST be the first argument to these routines.
+ */
+ /* Ring the screen bell. */
+ void (*s_bell) __P((SCR *));
+ /* Background the screen. */
+ int (*s_bg) __P((SCR *));
+ /* Put up a busy message. */
+ int (*s_busy) __P((SCR *, char const *));
+ /* Change a screen line. */
+ int (*s_change) __P((SCR *, EXF *, recno_t, enum operation));
+ /* Clear the screen. */
+ 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 *));
+ enum confirm /* Confirm an action with the user. */
+ (*s_confirm) __P((SCR *, EXF *, MARK *, MARK *));
+ /* Change the relative screen size. */
+ int (*s_crel) __P((SCR *, long));
+ /* Edit a file. */
+ int (*s_edit) __P((SCR *, EXF *));
+ /* End a screen. */
+ int (*s_end) __P((SCR *));
+ /* Run a single ex command. */
+ int (*s_ex_cmd) __P((SCR *, EXF *, EXCMDARG *, MARK *));
+ /* Run user's ex commands. */
+ int (*s_ex_run) __P((SCR *, EXF *, MARK *));
+ /* Screen's ex write function. */
+ int (*s_ex_write) __P((void *, const char *, int));
+ /* Foreground the screen. */
+ int (*s_fg) __P((SCR *, CHAR_T *));
+ /* Fill the screen's map. */
+ int (*s_fill) __P((SCR *, EXF *, recno_t, enum position));
+ enum input /* Get a line from the user. */
+ (*s_get) __P((SCR *, EXF *, TEXTH *, ARG_CHAR_T, u_int));
+ enum input /* Get a key from the user. */
+ (*s_key_read) __P((SCR *, int *, struct timeval *));
+ /* Map a function key. */
+ int (*s_fmap) __P((SCR *,
+ enum seqtype, CHAR_T *, size_t, CHAR_T *, size_t));
+ /* Tell the screen an option changed. */
+ int (*s_optchange) __P((SCR *, int));
+ /* Return column at screen position. */
+ int (*s_position) __P((SCR *, EXF *,
+ MARK *, u_long, enum position));
+ /* Change the absolute screen size. */
+ 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 *));
+ /* Move down the screen. */
+ int (*s_scroll) __P((SCR *, EXF *, MARK *, recno_t, enum sctype));
+ /* Split the screen. */
+ int (*s_split) __P((SCR *, ARGS *[], int));
+ /* Suspend the screen. */
+ int (*s_suspend) __P((SCR *));
+ /* Set the window size. */
+ int (*s_window) __P((SCR *, int));
+
+/* Editor screens. */
+#define S_EX 0x0000001 /* Ex screen. */
+#define S_VI_CURSES 0x0000002 /* Vi: curses screen. */
+#define S_VI_XAW 0x0000004 /* Vi: Athena widgets screen. */
+
+#define IN_EX_MODE(sp) /* If in ex mode. */ \
+ (F_ISSET(sp, S_EX))
+#define IN_VI_MODE(sp) /* If in vi mode. */ \
+ (F_ISSET(sp, S_VI_CURSES | S_VI_XAW))
+#define S_SCREENS /* Screens. */ \
+ (S_EX | S_VI_CURSES | S_VI_XAW)
+
+/* Major screen/file changes. */
+#define S_EXIT 0x0000008 /* Exiting (not forced). */
+#define S_EXIT_FORCE 0x0000010 /* Exiting (forced). */
+#define S_FSWITCH 0x0000020 /* Switch files. */
+#define S_SSWITCH 0x0000040 /* Switch screens. */
+#define S_MAJOR_CHANGE /* Screen or file changes. */ \
+ (S_EXIT | S_EXIT_FORCE | S_FSWITCH | S_SSWITCH)
+
+#define S_ARGNOFREE 0x0000080 /* Argument list wasn't allocated. */
+#define S_ARGRECOVER 0x0000100 /* Argument list is recovery files. */
+#define S_BELLSCHED 0x0000200 /* Bell scheduled. */
+#define S_CONTINUE 0x0000400 /* Need to ask the user to continue. */
+#define S_EXSILENT 0x0000800 /* Ex batch script. */
+#define S_GLOBAL 0x0001000 /* Doing a global command. */
+#define S_INPUT 0x0002000 /* Doing text input. */
+#define S_INTERRUPTED 0x0004000 /* If have been interrupted. */
+#define S_INTERRUPTIBLE 0x0008000 /* If can be interrupted. */
+#define S_IVIDEO 0x0010000 /* Display in inverse video. */
+#define S_REDRAW 0x0020000 /* Redraw the screen. */
+#define S_REFORMAT 0x0040000 /* Reformat the screen. */
+#define S_REFRESH 0x0080000 /* Refresh the screen. */
+#define S_RENUMBER 0x0100000 /* Renumber the screen. */
+#define S_RESIZE 0x0200000 /* Resize the screen. */
+#define S_SCRIPT 0x0400000 /* Window is a shell script. */
+#define S_SRE_SET 0x0800000 /* The search RE has been set. */
+#define S_SUBRE_SET 0x1000000 /* The substitute RE has been set. */
+#define S_UPDATE_MODE 0x2000000 /* Don't repaint modeline. */
+#define S_VLITONLY 0x4000000 /* ^V literal next only. */
+ u_int32_t flags;
+};
+
+/*
+ * Signals/timers have no structure, so it's all here.
+ *
+ * Block all signals that are being handled. Used to keep the underlying DB
+ * system calls from being interrupted and not restarted, as it could cause
+ * consistency problems. Also used when vi forks child processes, to avoid
+ * a signal arriving after the fork and before the exec, causing both parent
+ * and child to attempt recovery processing.
+ */
+#define SIGBLOCK(gp) \
+ (void)sigprocmask(SIG_BLOCK, &(gp)->blockset, NULL);
+#define SIGUNBLOCK(gp) \
+ (void)sigprocmask(SIG_UNBLOCK, &(gp)->blockset, NULL);
+
+void busy_off __P((SCR *));
+int busy_on __P((SCR *, char const *));
+void sig_end __P((void));
+int sig_init __P((SCR *));
+
+/* Generic routines to start/stop a screen. */
+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 *));
diff --git a/usr.bin/vi/common/search.c b/usr.bin/vi/common/search.c
new file mode 100644
index 000000000000..72d9e4b2b9de
--- /dev/null
+++ b/usr.bin/vi/common/search.c
@@ -0,0 +1,833 @@
+/*-
+ * 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[] = "@(#)search.c 8.46 (Berkeley) 7/2/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.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 *));
+
+/*
+ * resetup --
+ * Set up a search for a regular expression.
+ */
+static int
+resetup(sp, rep, dir, ptrn, epp, deltap, flagp)
+ SCR *sp;
+ regex_t **rep;
+ enum direction dir;
+ char *ptrn, **epp;
+ long *deltap;
+ u_int *flagp;
+{
+ u_int flags;
+ int delim, eval, re_flags, replaced;
+ char *p, *t;
+
+ /* Set return information the default. */
+ *deltap = 0;
+
+ /*
+ * Use saved pattern if no pattern supplied, or if only a delimiter
+ * character is supplied. Only the pattern was saved, historic vi
+ * did not reuse any delta supplied.
+ */
+ flags = *flagp;
+ if (ptrn == NULL)
+ goto prev;
+ if (ptrn[1] == '\0') {
+ if (epp != NULL)
+ *epp = ptrn + 1;
+ goto prev;
+ }
+ if (ptrn[0] == ptrn[1] && ptrn[2] == '\0') {
+ if (epp != NULL)
+ *epp = ptrn + 2;
+prev: if (!F_ISSET(sp, S_SRE_SET)) {
+ msgq(sp, M_ERR, "No previous search pattern");
+ return (1);
+ }
+ *rep = &sp->sre;
+
+ /* Empty patterns set the direction. */
+ if (LF_ISSET(SEARCH_SET)) {
+ F_SET(sp, S_SRE_SET);
+ sp->searchdir = dir;
+ sp->sre = **rep;
+ }
+ return (0);
+ }
+
+ re_flags = 0; /* Set RE flags. */
+ if (O_ISSET(sp, O_EXTENDED))
+ re_flags |= REG_EXTENDED;
+ if (O_ISSET(sp, O_IGNORECASE))
+ re_flags |= REG_ICASE;
+
+ replaced = 0;
+ if (LF_ISSET(SEARCH_PARSE)) { /* Parse the string. */
+ /* Set delimiter. */
+ delim = *ptrn++;
+
+ /* Find terminating delimiter, handling escaped delimiters. */
+ for (p = t = ptrn;;) {
+ if (p[0] == '\0' || p[0] == delim) {
+ if (p[0] == delim)
+ ++p;
+ *t = '\0';
+ break;
+ }
+ if (p[1] == delim && p[0] == '\\')
+ ++p;
+ *t++ = *p++;
+ }
+
+ /*
+ * If characters after the terminating delimiter, it may
+ * be an error, or may be an offset. In either case, we
+ * return the end of the string, whatever it may be.
+ */
+ if (*p) {
+ if (get_delta(sp, &p, deltap, flagp))
+ return (1);
+ if (*p && LF_ISSET(SEARCH_TERM)) {
+ msgq(sp, M_ERR,
+ "Characters after search string and/or delta");
+ return (1);
+ }
+ }
+ if (epp != NULL)
+ *epp = p;
+
+ /* Check for "/ " or other such silliness. */
+ if (*ptrn == '\0')
+ goto prev;
+
+ if (re_conv(sp, &ptrn, &replaced))
+ return (1);
+ } else if (LF_ISSET(SEARCH_TAG)) {
+ if (ctag_conv(sp, &ptrn, &replaced))
+ return (1);
+ re_flags &= ~(REG_EXTENDED | REG_ICASE);
+ }
+
+ /* Compile the RE. */
+ if (eval = regcomp(*rep, ptrn, re_flags))
+ re_error(sp, eval, *rep);
+ else if (LF_ISSET(SEARCH_SET)) {
+ F_SET(sp, S_SRE_SET);
+ sp->searchdir = dir;
+ sp->sre = **rep;
+ }
+
+ /* Free up any extra memory. */
+ if (replaced)
+ FREE_SPACE(sp, ptrn, 0);
+ return (eval);
+}
+
+/*
+ * ctag_conv --
+ * Convert a tags search path into something that the POSIX
+ * 1003.2 RE functions can handle.
+ */
+static int
+ctag_conv(sp, ptrnp, replacedp)
+ SCR *sp;
+ char **ptrnp;
+ int *replacedp;
+{
+ size_t blen, len;
+ int lastdollar;
+ char *bp, *p, *t;
+
+ *replacedp = 0;
+
+ len = strlen(p = *ptrnp);
+
+ /* Max memory usage is 2 times the length of the string. */
+ GET_SPACE_RET(sp, bp, blen, len * 2);
+
+ t = bp;
+
+ /* The last character is a '/' or '?', we just strip it. */
+ if (p[len - 1] == '/' || p[len - 1] == '?')
+ p[len - 1] = '\0';
+
+ /* The next-to-last character is a '$', and it's magic. */
+ if (p[len - 2] == '$') {
+ lastdollar = 1;
+ p[len - 2] = '\0';
+ } else
+ lastdollar = 0;
+
+ /* The first character is a '/' or '?', we just strip it. */
+ if (p[0] == '/' || p[0] == '?')
+ ++p;
+
+ /* 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
+ * characters.
+ */
+ while (p[0]) {
+ /* Ctags escapes the search delimiter characters. */
+ if (p[0] == '\\' && (p[1] == '/' || p[1] == '?'))
+ ++p;
+ else if (strchr("^.[]$*", p[0]))
+ *t++ = '\\';
+ *t++ = *p++;
+ }
+ if (lastdollar)
+ *t++ = '$';
+ *t++ = '\0';
+
+ *ptrnp = bp;
+ *replacedp = 1;
+ return (0);
+}
+
+#define EMPTYMSG "File empty; nothing to search"
+#define EOFMSG "Reached end-of-file without finding the pattern"
+#define NOTFOUND "Pattern not found"
+#define SOFMSG "Reached top-of-file without finding the pattern"
+#define WRAPMSG "Search wrapped"
+
+int
+f_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
+ SCR *sp;
+ EXF *ep;
+ MARK *fm, *rm;
+ char *ptrn, **eptrn;
+ u_int *flagp;
+{
+ regmatch_t match[1];
+ regex_t *re, lre;
+ recno_t lno;
+ size_t coff, len;
+ long delta;
+ u_int flags;
+ int btear, eval, rval, wrapped;
+ char *l;
+
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ flags = *flagp;
+ if (lno == 0) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, EMPTYMSG);
+ return (1);
+ }
+
+ re = &lre;
+ if (resetup(sp, &re, FORWARD, ptrn, eptrn, &delta, flagp))
+ return (1);
+
+ /*
+ * Start searching immediately after the cursor. If at the end of the
+ * line, start searching on the next line. This is incompatible (read
+ * bug fix) with the historic vi -- searches for the '$' pattern never
+ * moved forward, and "-t foo" didn't work if "foo" was the first thing
+ * in the file.
+ */
+ if (LF_ISSET(SEARCH_FILE)) {
+ lno = 1;
+ coff = 0;
+ } else {
+ if ((l = file_gline(sp, ep, fm->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, fm->lno);
+ return (1);
+ }
+ if (fm->cno + 1 >= len) {
+ if (fm->lno == lno) {
+ if (!O_ISSET(sp, O_WRAPSCAN)) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, EOFMSG);
+ return (1);
+ }
+ lno = 1;
+ } else
+ lno = fm->lno + 1;
+ coff = 0;
+ } else {
+ lno = fm->lno;
+ coff = fm->cno + 1;
+ }
+ }
+
+ /* Turn on busy message. */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching...");
+
+ for (rval = 1, wrapped = 0;; ++lno, coff = 0) {
+ if (INTERRUPTED(sp)) {
+ msgq(sp, M_INFO, "Interrupted.");
+ break;
+ }
+ if (wrapped && lno > fm->lno ||
+ (l = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (wrapped) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, NOTFOUND);
+ break;
+ }
+ if (!O_ISSET(sp, O_WRAPSCAN)) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, EOFMSG);
+ break;
+ }
+ lno = 0;
+ wrapped = 1;
+ continue;
+ }
+
+ /* If already at EOL, just keep going. */
+ if (len && coff == len)
+ continue;
+
+ /* Set the termination. */
+ match[0].rm_so = coff;
+ match[0].rm_eo = len;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "F search: %lu from %u to %u\n",
+ lno, coff, len ? len - 1 : len);
+#endif
+ /* Search the line. */
+ eval = regexec(re, l, 1, match,
+ (match[0].rm_so == 0 ? 0 : REG_NOTBOL) | REG_STARTEND);
+ if (eval == REG_NOMATCH)
+ continue;
+ if (eval != 0) {
+ re_error(sp, eval, re);
+ break;
+ }
+
+ /* Warn if wrapped. */
+ if (wrapped && O_ISSET(sp, O_WARN) && LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_VINFO, WRAPMSG);
+
+ /*
+ * If an offset, see if it's legal. It's possible to match
+ * past the end of the line with $, so check for that case.
+ */
+ if (delta) {
+ if (check_delta(sp, ep, delta, lno))
+ break;
+ rm->lno = delta + lno;
+ rm->cno = 0;
+ } else {
+#if defined(DEBUG) && 0
+ TRACE(sp, "found: %qu to %qu\n",
+ match[0].rm_so, match[0].rm_eo);
+#endif
+ rm->lno = lno;
+ rm->cno = match[0].rm_so;
+
+ /*
+ * If a change command, it's possible to move beyond
+ * the end of a line. Historic vi generally got this
+ * wrong (try "c?$<cr>"). Not all that sure this gets
+ * it right, there are lots of strange cases.
+ */
+ if (!LF_ISSET(SEARCH_EOL) && rm->cno >= len)
+ rm->cno = len ? len - 1 : 0;
+ }
+ rval = 0;
+ break;
+ }
+
+ /* Turn off busy message, interrupts. */
+ if (btear)
+ busy_off(sp);
+ return (rval);
+}
+
+int
+b_search(sp, ep, fm, rm, ptrn, eptrn, flagp)
+ SCR *sp;
+ EXF *ep;
+ MARK *fm, *rm;
+ char *ptrn, **eptrn;
+ u_int *flagp;
+{
+ regmatch_t match[1];
+ regex_t *re, lre;
+ recno_t lno;
+ size_t coff, len, last;
+ long delta;
+ u_int flags;
+ int btear, eval, rval, wrapped;
+ char *l;
+
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ flags = *flagp;
+ if (lno == 0) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, EMPTYMSG);
+ return (1);
+ }
+
+ re = &lre;
+ if (resetup(sp, &re, BACKWARD, ptrn, eptrn, &delta, flagp))
+ return (1);
+
+ /* If in the first column, start searching on the previous line. */
+ if (fm->cno == 0) {
+ if (fm->lno == 1) {
+ if (!O_ISSET(sp, O_WRAPSCAN)) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, SOFMSG);
+ return (1);
+ }
+ } else
+ lno = fm->lno - 1;
+ } else
+ lno = fm->lno;
+
+ /* Turn on busy message. */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching...");
+
+ for (rval = 1, wrapped = 0, coff = fm->cno;; --lno, coff = 0) {
+ if (INTERRUPTED(sp)) {
+ msgq(sp, M_INFO, "Interrupted.");
+ break;
+ }
+ if (wrapped && lno < fm->lno || lno == 0) {
+ if (wrapped) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, NOTFOUND);
+ break;
+ }
+ if (!O_ISSET(sp, O_WRAPSCAN)) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, SOFMSG);
+ break;
+ }
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (lno == 0) {
+ if (LF_ISSET(SEARCH_MSG))
+ msgq(sp, M_INFO, EMPTYMSG);
+ break;
+ }
+ ++lno;
+ wrapped = 1;
+ continue;
+ }
+
+ if ((l = file_gline(sp, ep, lno, &len)) == NULL)
+ goto err;
+
+ /* Set the termination. */
+ match[0].rm_so = 0;
+ match[0].rm_eo = len;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "B search: %lu from 0 to %qu\n", lno, match[0].rm_eo);
+#endif
+ /* Search the line. */
+ eval = regexec(re, l, 1, match,
+ (match[0].rm_eo == len ? 0 : REG_NOTEOL) | REG_STARTEND);
+ if (eval == REG_NOMATCH)
+ continue;
+ if (eval != 0) {
+ re_error(sp, eval, re);
+ 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_VINFO, WRAPMSG);
+
+ if (delta) {
+ if (check_delta(sp, ep, delta, lno))
+ break;
+ rm->lno = delta + lno;
+ rm->cno = 0;
+ } else {
+#if defined(DEBUG) && 0
+ TRACE(sp, "found: %qu to %qu\n",
+ match[0].rm_so, match[0].rm_eo);
+#endif
+ /*
+ * 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++;
+ if (match[0].rm_so >= len)
+ break;
+ match[0].rm_eo = len;
+ eval = regexec(re, l, 1, match,
+ (match[0].rm_so == 0 ? 0 : REG_NOTBOL) |
+ REG_STARTEND);
+ if (eval == REG_NOMATCH)
+ break;
+ if (eval != 0) {
+ re_error(sp, eval, re);
+ goto err;
+ }
+ if (coff && match[0].rm_so >= coff)
+ break;
+ }
+ rm->lno = lno;
+
+ /* See comment in f_search(). */
+ if (!LF_ISSET(SEARCH_EOL) && last >= len)
+ rm->cno = len ? len - 1 : 0;
+ else
+ rm->cno = last;
+ }
+ rval = 0;
+ break;
+ }
+
+ /* Turn off busy message, interrupts. */
+err: if (btear)
+ busy_off(sp);
+ return (rval);
+}
+
+/*
+ * re_conv --
+ * Convert vi's regular expressions into something that the
+ * the POSIX 1003.2 RE functions can handle.
+ *
+ * There are three conversions we make to make vi's RE's (specifically
+ * 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.
+ * 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 "~".
+ * 3: The pattern \<ptrn\> does "word" searches, convert it to use the
+ * new RE escapes.
+ */
+int
+re_conv(sp, ptrnp, replacedp)
+ SCR *sp;
+ char **ptrnp;
+ int *replacedp;
+{
+ size_t blen, needlen;
+ int magic;
+ char *bp, *p, *t;
+
+ /*
+ * First pass through, we figure out how much space we'll need.
+ * We do it in two passes, on the grounds that most of the time
+ * the user is doing a search and won't have magic characters.
+ * That way we can skip the malloc and memmove's.
+ */
+ for (p = *ptrnp, magic = 0, needlen = 0; *p != '\0'; ++p)
+ switch (*p) {
+ case '\\':
+ switch (*++p) {
+ case '<':
+ magic = 1;
+ needlen += sizeof(RE_WSTART);
+ break;
+ case '>':
+ magic = 1;
+ needlen += sizeof(RE_WSTOP);
+ break;
+ case '~':
+ if (!O_ISSET(sp, O_MAGIC)) {
+ magic = 1;
+ needlen += sp->repl_len;
+ }
+ break;
+ case '.':
+ case '[':
+ case ']':
+ case '*':
+ if (!O_ISSET(sp, O_MAGIC)) {
+ magic = 1;
+ needlen += 1;
+ }
+ break;
+ default:
+ needlen += 2;
+ }
+ break;
+ case '~':
+ if (O_ISSET(sp, O_MAGIC)) {
+ magic = 1;
+ needlen += sp->repl_len;
+ }
+ break;
+ case '.':
+ case '[':
+ case ']':
+ case '*':
+ if (!O_ISSET(sp, O_MAGIC)) {
+ magic = 1;
+ needlen += 2;
+ }
+ break;
+ default:
+ needlen += 1;
+ break;
+ }
+
+ if (!magic) {
+ *replacedp = 0;
+ return (0);
+ }
+
+ /*
+ * Get enough memory to hold the final pattern.
+ *
+ * XXX
+ * It's nul-terminated, for now.
+ */
+ GET_SPACE_RET(sp, bp, blen, needlen + 1);
+
+ for (p = *ptrnp, t = bp; *p != '\0'; ++p)
+ switch (*p) {
+ case '\\':
+ switch (*++p) {
+ case '<':
+ memmove(t, RE_WSTART, sizeof(RE_WSTART) - 1);
+ t += sizeof(RE_WSTART) - 1;
+ break;
+ case '>':
+ memmove(t, RE_WSTOP, sizeof(RE_WSTOP) - 1);
+ t += sizeof(RE_WSTOP) - 1;
+ break;
+ case '~':
+ if (O_ISSET(sp, O_MAGIC))
+ *t++ = '~';
+ else {
+ memmove(t, sp->repl, sp->repl_len);
+ t += sp->repl_len;
+ }
+ break;
+ case '.':
+ case '[':
+ case ']':
+ case '*':
+ if (O_ISSET(sp, O_MAGIC))
+ *t++ = '\\';
+ *t++ = *p;
+ break;
+ default:
+ *t++ = '\\';
+ *t++ = *p;
+ }
+ break;
+ case '~':
+ if (O_ISSET(sp, O_MAGIC)) {
+ memmove(t, sp->repl, sp->repl_len);
+ t += sp->repl_len;
+ } else
+ *t++ = '~';
+ break;
+ case '.':
+ case '[':
+ case ']':
+ case '*':
+ if (!O_ISSET(sp, O_MAGIC))
+ *t++ = '\\';
+ *t++ = *p;
+ break;
+ default:
+ *t++ = *p;
+ break;
+ }
+ *t = '\0';
+
+ *ptrnp = bp;
+ *replacedp = 1;
+ return (0);
+}
+
+/*
+ * get_delta --
+ * Get a line delta. The trickiness is that the delta can be pretty
+ * complicated, i.e. "+3-2+3++- ++" is allowed.
+ *
+ * !!!
+ * In historic vi, if you had a delta on a search pattern which was used as
+ * a motion command, the command became a line mode command regardless of the
+ * cursor positions. A fairly common trick is to use a delta of "+0" to make
+ * the command a line mode command. This is the only place that knows about
+ * delta's, so we set the return flag information here.
+ */
+static int
+get_delta(sp, dp, valp, flagp)
+ SCR *sp;
+ char **dp;
+ long *valp;
+ u_int *flagp;
+{
+ char *p;
+ long val, tval;
+
+ for (tval = 0, p = *dp; *p != '\0'; *flagp |= SEARCH_DELTA) {
+ if (isblank(*p)) {
+ ++p;
+ continue;
+ }
+ if (*p == '+' || *p == '-') {
+ if (!isdigit(*(p + 1))) {
+ if (*p == '+') {
+ if (tval == LONG_MAX)
+ goto overflow;
+ ++tval;
+ } else {
+ if (tval == LONG_MIN)
+ goto underflow;
+ --tval;
+ }
+ ++p;
+ continue;
+ }
+ } else
+ if (!isdigit(*p))
+ break;
+
+ errno = 0;
+ val = strtol(p, &p, 10);
+ if (errno == ERANGE) {
+ if (val == LONG_MAX)
+overflow: msgq(sp, M_ERR, "Delta value overflow");
+ else if (val == LONG_MIN)
+underflow: msgq(sp, M_ERR, "Delta value underflow");
+ else
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ if (val >= 0) {
+ if (LONG_MAX - val < tval)
+ goto overflow;
+ } else
+ if (-(LONG_MIN - tval) > val)
+ goto underflow;
+ tval += val;
+ }
+ *dp = p;
+ *valp = tval;
+ return (0);
+}
+
+/*
+ * check_delta --
+ * Check a line delta to see if it's legal.
+ */
+static int
+check_delta(sp, ep, delta, lno)
+ SCR *sp;
+ EXF *ep;
+ long delta;
+ recno_t lno;
+{
+ /* A delta can overflow a record number. */
+ if (delta < 0) {
+ if (lno < LONG_MAX && delta >= (long)lno) {
+ msgq(sp, M_ERR, "Search offset before line 1");
+ return (1);
+ }
+ } else {
+ if (ULONG_MAX - lno < delta) {
+ msgq(sp, M_ERR, "Delta value overflow");
+ return (1);
+ }
+ if (file_gline(sp, ep, lno + delta, NULL) == NULL) {
+ msgq(sp, M_ERR, "Search offset past end-of-file");
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * re_error --
+ * Report a regular expression error.
+ */
+void
+re_error(sp, errcode, preg)
+ SCR *sp;
+ int errcode;
+ regex_t *preg;
+{
+ size_t s;
+ char *oe;
+
+ s = regerror(errcode, preg, "", 0);
+ if ((oe = malloc(s)) == NULL)
+ msgq(sp, M_SYSERR, NULL);
+ else {
+ (void)regerror(errcode, preg, oe, s);
+ msgq(sp, M_ERR, "RE error: %s", oe);
+ }
+ free(oe);
+}
diff --git a/usr.bin/vi/common/search.h b/usr.bin/vi/common/search.h
new file mode 100644
index 000000000000..1483a04c7b71
--- /dev/null
+++ b/usr.bin/vi/common/search.h
@@ -0,0 +1,54 @@
+/*-
+ * 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.
+ *
+ * @(#)search.h 8.9 (Berkeley) 3/16/94
+ */
+
+#define RE_WSTART "[[:<:]]" /* Not-in-word search patterns. */
+#define RE_WSTOP "[[:>:]]"
+
+#define SEARCH_DELTA 0x001 /* A delta part of the search.*/
+#define SEARCH_EOL 0x002 /* Offset past EOL is okay. */
+#define SEARCH_FILE 0x004 /* Search the entire file. */
+#define SEARCH_MSG 0x008 /* Display search warning messages. */
+#define SEARCH_PARSE 0x010 /* Parse the search pattern. */
+#define SEARCH_SET 0x020 /* Set search direction. */
+#define SEARCH_TAG 0x040 /* Search pattern is a tag pattern. */
+#define SEARCH_TERM 0x080 /* Search pattern should terminate. */
+
+enum direction { NOTSET, FORWARD, BACKWARD };
+
+/* Search functions. */
+int b_search __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *));
+int f_search __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *));
+int re_conv __P((SCR *, char **, int *));
+void re_error __P((SCR *, int, regex_t *));
diff --git a/usr.bin/vi/common/seq.c b/usr.bin/vi/common/seq.c
new file mode 100644
index 000000000000..7b217084aaa0
--- /dev/null
+++ b/usr.bin/vi/common/seq.c
@@ -0,0 +1,350 @@
+/*-
+ * 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[] = "@(#)seq.c 8.30 (Berkeley) 7/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * seq_set --
+ * Internal version to enter a sequence.
+ */
+int
+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 flags;
+{
+ SEQ *lastqp, *qp;
+ CHAR_T *p;
+ int sv_errno;
+
+ /*
+ * 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 (output == NULL || olen == 0) {
+ p = NULL;
+ olen = 0;
+ } else if ((p = v_strdup(sp, output, olen)) == NULL) {
+ sv_errno = errno;
+ goto mem1;
+ }
+ if (qp->output != NULL)
+ free(qp->output);
+ qp->olen = olen;
+ qp->output = p;
+ return (0);
+ }
+
+ /* Allocate and initialize SEQ structure. */
+ CALLOC(sp, qp, SEQ *, 1, sizeof(SEQ));
+ if (qp == NULL) {
+ sv_errno = errno;
+ goto mem1;
+ }
+
+ /* Name. */
+ if (name == NULL || nlen == 0)
+ qp->name = NULL;
+ else if ((qp->name = v_strdup(sp, name, nlen)) == NULL) {
+ sv_errno = errno;
+ goto mem2;
+ }
+ qp->nlen = nlen;
+
+ /* Input. */
+ if ((qp->input = v_strdup(sp, input, ilen)) == NULL) {
+ sv_errno = errno;
+ goto mem3;
+ }
+ 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);
+mem2: FREE(qp, sizeof(SEQ));
+mem1: errno = sv_errno;
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ qp->olen = olen;
+
+ /* Type, flags. */
+ qp->stype = stype;
+ qp->flags = flags;
+
+ /* Link into the chain. */
+ if (lastqp == NULL) {
+ LIST_INSERT_HEAD(&sp->gp->seqq, qp, q);
+ } else {
+ LIST_INSERT_AFTER(lastqp, qp, q);
+ }
+
+ /* Set the fast lookup bit. */
+ bit_set(sp->gp->seqb, qp->input[0]);
+
+ return (0);
+}
+
+/*
+ * seq_delete --
+ * Delete a sequence.
+ */
+int
+seq_delete(sp, input, ilen, stype)
+ SCR *sp;
+ char *input;
+ size_t ilen;
+ enum seqtype stype;
+{
+ SEQ *qp;
+
+ if ((qp = seq_find(sp, NULL, input, ilen, stype, NULL)) == NULL)
+ return (1);
+ return (seq_mdel(qp));
+}
+
+/*
+ * seq_mdel --
+ * Delete a map entry, without lookup.
+ */
+int
+seq_mdel(qp)
+ SEQ *qp;
+{
+ LIST_REMOVE(qp, q);
+ if (qp->name != NULL)
+ free(qp->name);
+ free(qp->input);
+ if (qp->output != NULL)
+ free(qp->output);
+ FREE(qp, sizeof(SEQ));
+ return (0);
+}
+
+/*
+ * seq_find --
+ * Search the sequence list for a match to a buffer, if ispartial
+ * isn't NULL, partial matches count.
+ */
+SEQ *
+seq_find(sp, lastqp, input, ilen, stype, ispartialp)
+ SCR *sp;
+ SEQ **lastqp;
+ char *input;
+ size_t ilen;
+ enum seqtype stype;
+ int *ispartialp;
+{
+ SEQ *lqp, *qp;
+ int diff;
+
+ /*
+ * 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,
+ * i.e. ilen may be longer than the match.
+ */
+ if (ispartialp != NULL)
+ *ispartialp = 0;
+ for (lqp = NULL, qp = sp->gp->seqq.lh_first;
+ qp != NULL; lqp = qp, qp = qp->q.le_next) {
+ /* Fast checks on the first character and type. */
+ if (qp->input[0] > input[0])
+ break;
+ if (qp->input[0] < input[0] ||
+ qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
+ continue;
+
+ /* Check on the real comparison. */
+ diff = memcmp(qp->input, input, MIN(qp->ilen, ilen));
+ if (diff > 0)
+ break;
+ if (diff < 0)
+ continue;
+ /*
+ * If the entry is the same length as the string, return a
+ * match. If the entry is shorter than the string, return a
+ * match if called from the terminal key routine. Otherwise,
+ * keep searching for a complete match.
+ */
+ if (qp->ilen <= ilen) {
+ if (qp->ilen == ilen || ispartialp != NULL) {
+ if (lastqp != NULL)
+ *lastqp = lqp;
+ return (qp);
+ }
+ continue;
+ }
+ /*
+ * If the entry longer than the string, return partial match
+ * if called from the terminal key routine. Otherwise, no
+ * match.
+ */
+ if (ispartialp != NULL)
+ *ispartialp = 1;
+ break;
+ }
+ if (lastqp != NULL)
+ *lastqp = lqp;
+ return (NULL);
+}
+
+/*
+ * seq_dump --
+ * Display the sequence entries of a specified type.
+ */
+int
+seq_dump(sp, stype, isname)
+ SCR *sp;
+ enum seqtype stype;
+ int isname;
+{
+ SEQ *qp;
+ int cnt, len, olen;
+ CHAR_T *p;
+
+ cnt = 0;
+ for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
+ if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP))
+ continue;
+ ++cnt;
+ for (p = qp->input,
+ olen = qp->ilen, len = 0; olen > 0; --olen, ++p)
+ len += ex_printf(EXCOOKIE, "%s", KEY_NAME(sp, *p));
+ for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
+ len -= ex_printf(EXCOOKIE, " ");
+
+ if (qp->output != NULL)
+ for (p = qp->output,
+ olen = qp->olen, len = 0; olen > 0; --olen, ++p)
+ len +=
+ ex_printf(EXCOOKIE, "%s", KEY_NAME(sp, *p));
+ else
+ len = 0;
+
+ if (isname && qp->name != NULL) {
+ for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
+ len -= ex_printf(EXCOOKIE, " ");
+ for (p = qp->name,
+ olen = qp->nlen; olen > 0; --olen, ++p)
+ (void)ex_printf(EXCOOKIE,
+ "%s", KEY_NAME(sp, *p));
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+ }
+ return (cnt);
+}
+
+/*
+ * seq_save --
+ * Save the sequence entries to a file.
+ */
+int
+seq_save(sp, fp, prefix, stype)
+ SCR *sp;
+ FILE *fp;
+ char *prefix;
+ enum seqtype stype;
+{
+ SEQ *qp;
+ size_t olen;
+ int ch;
+ char *p;
+
+ /* Write a sequence command for all keys the user defined. */
+ for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
+ if (stype != qp->stype ||
+ F_ISSET(qp, SEQ_FUNCMAP) || !F_ISSET(qp, SEQ_USERDEF))
+ continue;
+ if (prefix)
+ (void)fprintf(fp, "%s", prefix);
+ for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
+ ch = *p++;
+ if (ch == CH_LITERAL || ch == '|' ||
+ isblank(ch) || KEY_VAL(sp, ch) == K_NL)
+ (void)putc(CH_LITERAL, fp);
+ (void)putc(ch, fp);
+ }
+ (void)putc(' ', fp);
+ if (qp->output != NULL)
+ for (p = qp->output,
+ olen = qp->olen; olen > 0; --olen) {
+ ch = *p++;
+ if (ch == CH_LITERAL || ch == '|' ||
+ KEY_VAL(sp, ch) == K_NL)
+ (void)putc(CH_LITERAL, fp);
+ (void)putc(ch, fp);
+ }
+ (void)putc('\n', fp);
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/common/seq.h b/usr.bin/vi/common/seq.h
new file mode 100644
index 000000000000..38c197cd7543
--- /dev/null
+++ b/usr.bin/vi/common/seq.h
@@ -0,0 +1,79 @@
+/*-
+ * 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.
+ *
+ * @(#)seq.h 8.11 (Berkeley) 7/17/94
+ */
+
+/*
+ * Map and abbreviation structures.
+ *
+ * The map structure is doubly linked list, sorted by input string and by
+ * input length within the string. (The latter is necessary so that short
+ * matches will happen before long matches when the list is searched.)
+ * Additionally, there is a bitmap which has bits set if there are entries
+ * 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.
+ */
+ /* Sequence type. */
+enum seqtype { SEQ_ABBREV, SEQ_COMMAND, SEQ_INPUT };
+
+struct _seq {
+ LIST_ENTRY(_seq) q; /* Linked list of all sequences. */
+ enum seqtype stype; /* Sequence type. */
+ char *name; /* Sequence name (if any). */
+ size_t nlen; /* Name length. */
+ char *input; /* Sequence input keys. */
+ size_t ilen; /* Input keys length. */
+ char *output; /* Sequence output keys. */
+ size_t olen; /* Output keys length. */
+
+#define SEQ_FUNCMAP 0x01 /* If unresolved function key.*/
+#define SEQ_SCREEN 0x02 /* If screen specific. */
+#define SEQ_USERDEF 0x04 /* If user defined. */
+ u_int8_t flags;
+};
+
+int seq_delete __P((SCR *, char *, size_t, enum seqtype));
+int seq_dump __P((SCR *, enum seqtype, int));
+SEQ *seq_find __P((SCR *, SEQ **, char *, size_t, enum seqtype, int *));
+void seq_init __P((SCR *));
+int seq_mdel __P((SEQ *));
+int seq_save __P((SCR *, FILE *, char *, enum seqtype));
+int seq_set __P((SCR *, char *, size_t,
+ char *, size_t, char *, size_t, enum seqtype, int));
diff --git a/usr.bin/vi/common/signal.c b/usr.bin/vi/common/signal.c
new file mode 100644
index 000000000000..68f25891616c
--- /dev/null
+++ b/usr.bin/vi/common/signal.c
@@ -0,0 +1,569 @@
+/*-
+ * 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[] = "@(#)signal.c 8.32 (Berkeley) 7/23/94";
+#endif /* not lint */
+
+#include <sys/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 <unistd.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+static void h_alrm __P((int));
+static void h_hup __P((int));
+static void h_int __P((int));
+static void h_term __P((int));
+static void h_winch __P((int));
+static void sig_sync __P((int, u_int));
+
+/*
+ * There are seven normally asynchronous actions about which vi cares:
+ * SIGALRM, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP and SIGWINCH.
+ *
+ * The assumptions:
+ * 1: The DB routines are not reentrant.
+ * 2: The curses routines may not be reentrant.
+ *
+ * SIGALRM, SIGHUP, SIGTERM
+ * Used for file recovery. The DB routines can't be reentered, so
+ * the vi routines that call DB block all three signals (see line.c).
+ * This means that DB routines can be called at interrupt time.
+ *
+ * SIGALRM
+ * Used to paint busy messages on the screen. The curses routines
+ * can't be reentered, so this function of SIGALRM can only be used
+ * in sections of code that do not use any curses functions (see
+ * busy_on, busy_off in signal.c). This means that curses can be
+ * called at interrupt time.
+ *
+ * SIGQUIT
+ * Disabled by the signal initialization routines. Historically,
+ * ^\ switched vi into ex mode, and we continue that practice.
+ *
+ * SIGWINCH:
+ * The interrupt routine sets a global bit which is checked by the
+ * key-read routine, so there are no reentrancy issues. This means
+ * that the screen will not resize until vi runs out of keys, but
+ * that doesn't seem like a problem.
+ *
+ * SIGINT and SIGTSTP are a much more difficult issue to resolve. Vi has
+ * to permit the user to interrupt long-running operations. Generally, a
+ * search, substitution or read/write is done on a large file, or, the user
+ * creates a key mapping with an infinite loop. This problem will become
+ * worse as more complex semantics are added to vi. There are four major
+ * solutions on the table, each of which have minor permutations.
+ *
+ * 1: Run in raw mode.
+ *
+ * The up side is that there's no asynchronous behavior to worry about,
+ * and obviously no reentrancy problems. The down side is that it's easy
+ * to misinterpret characters (e.g. :w big_file^Mi^V^C is going to look
+ * like an interrupt) and it's easy to get into places where we won't see
+ * interrupt characters (e.g. ":map a ixx^[hxxaXXX" infinitely loops in
+ * historic implementations of vi). Periodically reading the terminal
+ * input buffer might solve the latter problem, but it's not going to be
+ * pretty.
+ *
+ * Also, we're going to be checking for ^C's and ^Z's both, all over
+ * the place -- I hate to litter the source code with that. For example,
+ * the historic version of vi didn't permit you to suspend the screen if
+ * you were on the colon command line. This isn't right. ^Z isn't a vi
+ * command, it's a terminal event. (Dammit.)
+ *
+ * 2: Run in cbreak mode. There are two problems in this area. First, the
+ * current curses implementations (both System V and Berkeley) don't give
+ * you clean cbreak modes. For example, the IEXTEN bit is left on, turning
+ * on DISCARD and LNEXT. To clarify, what vi WANTS is 8-bit clean, with
+ * the exception that flow control and signals are turned on, and curses
+ * cbreak mode doesn't give you this.
+ *
+ * We can either set raw mode and twiddle the tty, or cbreak mode and
+ * twiddle the tty. I chose to use raw mode, on the grounds that raw
+ * mode is better defined and I'm less likely to be surprised by a curses
+ * implementation down the road. The twiddling consists of setting ISIG,
+ * IXON/IXOFF, and disabling some of the interrupt characters (see the
+ * comments in svi/svi_screen.c). This is all found in historic System
+ * V (SVID 3) and POSIX 1003.1-1992, so it should be fairly portable.
+ *
+ * The second problem is that vi permits you to enter literal signal
+ * characters, e.g. ^V^C. There are two possible solutions. First, you
+ * can turn off signals when you get a ^V, but that means that a network
+ * packet containing ^V and ^C will lose, since the ^C may take effect
+ * before vi reads the ^V. (This is particularly problematic if you're
+ * talking over a protocol that recognizes signals locally and sends OOB
+ * packets when it sees them.) Second, you can turn the ^C into a literal
+ * character in vi, but that means that there's a race between entering
+ * ^V<character>^C, i.e. the sequence may end up being ^V^C<character>.
+ * Also, the second solution doesn't work for flow control characters, as
+ * they aren't delivered to the program as signals.
+ *
+ * Generally, this is what historic vi did. (It didn't have the curses
+ * problems because it didn't use curses.) It entered signals following
+ * ^V characters into the input stream, (which is why there's no way to
+ * enter a literal flow control character).
+ *
+ * 3: Run in mostly raw mode; turn signals on when doing an operation the
+ * user might want to interrupt, but leave them off most of the time.
+ *
+ * This works well for things like file reads and writes. This doesn't
+ * work well for trying to detect infinite maps. The problem is that
+ * you can write the code so that you don't have to turn on interrupts
+ * per keystroke, but the code isn't pretty and it's hard to make sure
+ * that an optimization doesn't cover up an infinite loop. This also
+ * requires interaction or state between the vi parser and the key
+ * reading routines, as an infinite loop may still be returning keys
+ * to the parser.
+ *
+ * Also, if the user inserts an interrupt into the tty queue while the
+ * interrupts are turned off, the key won't be treated as an interrupt,
+ * and requiring the user to pound the keyboard to catch an interrupt
+ * window is nasty.
+ *
+ * 4: Run in mostly raw mode, leaving signals on all of the time. Done
+ * by setting raw mode, and twiddling the tty's termios ISIG bit.
+ *
+ * This works well for the interrupt cases, because the code only has
+ * to check to see if the interrupt flag has been set, and can otherwise
+ * ignore signals. It's also less likely that we'll miss a case, and we
+ * don't have to worry about synchronizing between the vi parser and the
+ * key read routines.
+ *
+ * The down side is that we have to turn signals off if the user wants
+ * to enter a literal character (e.g. ^V^C). If the user enters the
+ * combination fast enough, or as part of a single network packet,
+ * the text input routines will treat it as a signal instead of as a
+ * literal character. To some extent, we have this problem already,
+ * since we turn off flow control so that the user can enter literal
+ * XON/XOFF characters.
+ *
+ * This is probably the easiest to code, and provides the smoothest
+ * programming interface.
+ *
+ * There are a couple of other problems to consider.
+ *
+ * First, System V's curses doesn't handle SIGTSTP correctly. If you use the
+ * newterm() interface, the TSTP signal will leave you in raw mode, and the
+ * final endwin() will leave you in the correct shell mode. If you use the
+ * initscr() interface, the TSTP signal will return you to the correct shell
+ * mode, but the final endwin() will leave you in raw mode. There you have
+ * it: proof that drug testing is not making any significant headway in the
+ * computer industry. The 4BSD curses is deficient in that it does not have
+ * an interface to the terminal keypad. So, regardless, we have to do our
+ * own SIGTSTP handling.
+ *
+ * The problem with this is that if we do our own SIGTSTP handling, in either
+ * models #3 or #4, we're going to have to call curses routines at interrupt
+ * time, which means that we might be reentering curses, which is something we
+ * don't want to do.
+ *
+ * Second, SIGTSTP has its own little problems. It's broadcast to the entire
+ * process group, not sent to a single process. The scenario goes something
+ * like this: the shell execs the mail program, which execs vi. The user hits
+ * ^Z, and all three programs get the signal, in some random order. The mail
+ * program goes to sleep immediately (since it probably didn't have a SIGTSTP
+ * handler in place). The shell gets a SIGCHLD, does a wait, and finds out
+ * that the only child in its foreground process group (of which it's aware)
+ * is asleep. It then optionally resets the terminal (because the modes aren't
+ * how it left them), and starts prompting the user for input. The problem is
+ * that somewhere in the middle of all of this, vi is resetting the terminal,
+ * and getting ready to send a SIGTSTP to the process group in order to put
+ * itself to sleep. There's a solution to all of this: when vi starts, it puts
+ * itself into its own process group, and then only it (and possible child
+ * processes) receive the SIGTSTP. This permits it to clean up the terminal
+ * and switch back to the original process group, where it sends that process
+ * group a SIGTSTP, putting everyone to sleep and waking the shell.
+ *
+ * Third, handing SIGTSTP asynchronously is further complicated by the child
+ * processes vi may fork off. If vi calls ex, ex resets the terminal and
+ * starts running some filter, and SIGTSTP stops them both, vi has to know
+ * when it restarts that it can't repaint the screen until ex's child has
+ * finished running. This is solveable, but it's annoying.
+ *
+ * Well, somebody had to make a decision, and this is the way it's going to be
+ * (unless I get talked out of it). SIGINT is handled asynchronously, so
+ * that we can pretty much guarantee that the user can interrupt any operation
+ * at any time. SIGTSTP is handled synchronously, so that we don't have to
+ * reenter curses and so that we don't have to play the process group games.
+ * ^Z is recognized in the standard text input and command modes. (^Z should
+ * also be recognized during operations that may potentially take a long time.
+ * The simplest solution is probably to twiddle the tty, install a handler for
+ * SIGTSTP, and then restore normal tty modes when the operation is complete.)
+ */
+
+/*
+ * sig_init --
+ * Initialize signals.
+ */
+int
+sig_init(sp)
+ SCR *sp;
+{
+ GS *gp;
+ struct sigaction act;
+
+ /* Initialize the signals. */
+ gp = sp->gp;
+ (void)sigemptyset(&gp->blockset);
+
+ /*
+ * Use sigaction(2), not signal(3), since we don't always want to
+ * restart system calls. The example is when waiting for a command
+ * mode keystroke and SIGWINCH arrives. Try to set the restart bit
+ * (SA_RESTART) on SIGALRM anyway, it should result in a lot fewer
+ * interruptions. We also block every other signal that we can block
+ * when a signal arrives. This is because the signal functions call
+ * other nvi functions, which aren't guaranteed to be reentrant.
+ */
+
+#ifndef SA_RESTART
+#define SA_RESTART 0
+#endif
+#define SETSIG(signal, flags, handler) { \
+ if (sigaddset(&gp->blockset, signal)) \
+ goto err; \
+ act.sa_handler = handler; \
+ sigfillset(&act.sa_mask); \
+ act.sa_flags = flags; \
+ if (sigaction(signal, &act, NULL)) \
+ goto err; \
+}
+ SETSIG(SIGALRM, SA_RESTART, h_alrm);
+ SETSIG(SIGHUP, 0, h_hup);
+ SETSIG(SIGINT, 0, h_int);
+ SETSIG(SIGTERM, 0, h_term);
+ SETSIG(SIGWINCH, 0, h_winch);
+ return (0);
+
+err: msgq(sp, M_SYSERR, "signal init");
+ return (1);
+}
+
+/*
+ * sig_end --
+ * End signal setup.
+ */
+void
+sig_end()
+{
+ /*
+ * POSIX 1003.1-1990 requires that fork (and, presumably, vfork) clear
+ * pending alarms, and that the exec functions clear pending signals.
+ * In addition, after an exec, the child continues to ignore signals
+ * ignored in the parent, and the child's action for signals caught in
+ * the parent is set to the default action. So, as we currently don't
+ * ignore any signals, there's no cleanup to be done. This routine is
+ * left here as a stub function.
+ */
+ return;
+}
+
+/*
+ * busy_on --
+ * Set a busy message timer.
+ */
+int
+busy_on(sp, msg)
+ SCR *sp;
+ char const *msg;
+{
+ struct itimerval value;
+ struct timeval tod;
+
+ /*
+ * Give the oldest busy message precedence, since it's
+ * the longer running operation.
+ */
+ if (sp->busy_msg != NULL)
+ return (1);
+
+ /* 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;
+
+ /*
+ * Busy messages turn around fast. Reset the timer regardless
+ * of its current state.
+ */
+ 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 = 0;
+ if (setitimer(ITIMER_REAL, &value, NULL))
+ msgq(sp, M_SYSERR, "timer: setitimer");
+ return (0);
+}
+
+/*
+ * busy_off --
+ * Turn off a busy message timer.
+ */
+void
+busy_off(sp)
+ SCR *sp;
+{
+ /* We depend on this being an atomic instruction. */
+ sp->busy_msg = NULL;
+}
+
+/*
+ * rcv_on --
+ * Turn on recovery timer.
+ */
+int
+rcv_on(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct itimerval value;
+ struct timeval tod;
+
+ /* Get the current time of day. */
+ if (gettimeofday(&tod, NULL))
+ return (1);
+
+ /* Create target time of day. */
+ ep->rcv_tod.tv_sec = tod.tv_sec + RCV_PERIOD;
+ ep->rcv_tod.tv_usec = 0;
+
+ /*
+ * If there's a busy message happening, we're done, the
+ * interrupt handler will start our timer as necessary.
+ */
+ if (sp->busy_msg != NULL)
+ return (0);
+
+ 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);
+}
+
+/*
+ * h_alrm --
+ * Handle SIGALRM.
+ *
+ * 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. The SCR
+ * structure has a wall clock timer structure for each of these. 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.
+ *
+ * XXX
+ * It would be nice to reimplement this with two timers, a la POSIX 1003.1,
+ * but not many systems offer them yet.
+ */
+static void
+h_alrm(signo)
+ int signo;
+{
+ struct itimerval value;
+ struct timeval ntod, tod;
+ SCR *sp;
+ EXF *ep;
+ int sverrno;
+
+ sverrno = errno;
+
+ /* XXX: Get the current time of day; if this fails, we're dead. */
+ if (gettimeofday(&tod, NULL))
+ goto ret;
+
+ /*
+ * 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;
+ }
+
+ /*
+ * Sync the file if the recovery timer has fired. If
+ * the sync fails, we don't reschedule future sync's.
+ */
+skip_busy: ep = sp->ep;
+ 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 + 100000L) {
+ if (rcv_sync(sp, ep, 0))
+ continue;
+ 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)
+ goto ret;
+
+ /* 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);
+
+ret: errno = sverrno;
+}
+
+/*
+ * h_hup --
+ * Handle SIGHUP.
+ */
+static void
+h_hup(signo)
+ int signo;
+{
+ sig_sync(SIGHUP, RCV_EMAIL);
+ /* NOTREACHED */
+}
+
+/*
+ * h_int --
+ * Handle SIGINT.
+ *
+ * XXX
+ * This isn't right if windows are independent of each other.
+ */
+static void
+h_int(signo)
+ int signo;
+{
+ F_SET(__global_list, G_SIGINT);
+}
+
+/*
+ * h_term --
+ * Handle SIGTERM.
+ */
+static void
+h_term(signo)
+ int signo;
+{
+ sig_sync(SIGTERM, 0);
+ /* NOTREACHED */
+}
+
+/*
+ * h_winch --
+ * Handle SIGWINCH.
+ *
+ * XXX
+ * This isn't right if windows are independent of each other.
+ */
+static void
+h_winch(signo)
+ int signo;
+{
+ F_SET(__global_list, G_SIGWINCH);
+}
+
+
+/*
+ * sig_sync --
+ *
+ * Sync the files based on a signal.
+ */
+static void
+sig_sync(signo, flags)
+ int signo;
+ u_int flags;
+{
+ SCR *sp;
+
+ /*
+ * Walk the lists of screens, sync'ing the files; only sync
+ * each file once.
+ */
+ for (sp = __global_list->dq.cqh_first;
+ sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
+ rcv_sync(sp, sp->ep, RCV_ENDSESSION | RCV_PRESERVE | flags);
+ for (sp = __global_list->hq.cqh_first;
+ sp != (void *)&__global_list->hq; sp = sp->q.cqe_next)
+ rcv_sync(sp, sp->ep, RCV_ENDSESSION | RCV_PRESERVE | flags);
+
+ /*
+ * Die with the proper exit status. Don't bother using
+ * sigaction(2) 'cause we want the default behavior.
+ */
+ (void)signal(signo, SIG_DFL);
+ (void)kill(getpid(), signo);
+ /* NOTREACHED */
+
+ exit (1);
+}
diff --git a/usr.bin/vi/common/term.c b/usr.bin/vi/common/term.c
new file mode 100644
index 000000000000..457e368b6831
--- /dev/null
+++ b/usr.bin/vi/common/term.c
@@ -0,0 +1,732 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)term.c 8.79 (Berkeley) 8/2/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "compat.h"
+/*
+ * XXX
+ * DON'T INCLUDE <curses.h> HERE, IT BREAKS OSF1 V2.0 WHERE IT
+ * CHANGES THE VALUES OF VERASE/VKILL/VWERASE TO INCORRECT ONES.
+ */
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+static int keycmp __P((const void *, const void *));
+static enum input term_key_queue __P((SCR *));
+static void term_key_set __P((GS *, int, int));
+
+/*
+ * If we're reading less than 20 characters, up the size of the tty buffer.
+ * This shouldn't ever happen, other than the first time through, but it's
+ * possible if a map is large enough.
+ */
+#define term_read_grow(sp, tty) \
+ (tty)->nelem - ((tty)->cnt + (tty)->next) >= 20 ? \
+ 0 : __term_read_grow(sp, tty, 64)
+static int __term_read_grow __P((SCR *, IBUF *, int));
+
+/*
+ * !!!
+ * Historic 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. Nvi wires
+ * down the above characters, but in addition permits the VEOF, VERASE, VKILL
+ * and VWERASE characters described by the user's termios structure.
+ *
+ * Ex was not consistent with this scheme, as it historically ran in tty
+ * cooked mode. This meant that the scroll command and autoindent erase
+ * characters were mapped to the user's EOF character, and the character
+ * and word deletion characters were the user's tty character and word
+ * deletion characters. This implementation makes it all consistent, as
+ * described above for vi.
+ *
+ * XXX
+ * THIS REQUIRES THAT ALL SCREENS SHARE A SPECIAL KEY SET.
+ */
+KEYLIST keylist[] = {
+ {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_HEXCHAR, '\030'}, /* ^X */
+ {K_NL, '\n'}, /* \n */
+ {K_RIGHTBRACE, '}'}, /* } */
+ {K_RIGHTPAREN, ')'}, /* ) */
+ {K_TAB, '\t'}, /* \t */
+ {K_VERASE, '\b'}, /* \b */
+ {K_VKILL, '\025'}, /* ^U */
+ {K_VLNEXT, '\021'}, /* ^Q */
+ {K_VLNEXT, '\026'}, /* ^V */
+ {K_VWERASE, '\027'}, /* ^W */
+ {K_ZERO, '0'}, /* 0 */
+ {K_NOTUSED, 0}, /* VEOF, VERASE, VKILL, VWERASE */
+ {K_NOTUSED, 0},
+ {K_NOTUSED, 0},
+ {K_NOTUSED, 0},
+};
+static int nkeylist = (sizeof(keylist) / sizeof(keylist[0])) - 4;
+
+/*
+ * term_init --
+ * Initialize the special key lookup table.
+ */
+int
+term_init(sp)
+ SCR *sp;
+{
+ GS *gp;
+ KEYLIST *kp;
+ int cnt;
+
+ /*
+ * XXX
+ * 8-bit only, for now. Recompilation should get you any
+ * 8-bit character set, as long as nul isn't a character.
+ */
+ (void)setlocale(LC_ALL, "");
+ key_init(sp);
+
+ gp = sp->gp;
+#ifdef VEOF
+ term_key_set(gp, VEOF, K_CNTRLD);
+#endif
+#ifdef VERASE
+ term_key_set(gp, VERASE, K_VERASE);
+#endif
+#ifdef VKILL
+ term_key_set(gp, VKILL, K_VKILL);
+#endif
+#ifdef VWERASE
+ term_key_set(gp, VWERASE, K_VWERASE);
+#endif
+
+ /* Sort the special key list. */
+ qsort(keylist, nkeylist, sizeof(keylist[0]), keycmp);
+
+ /* Initialize the fast lookup table. */
+ 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;
+ }
+ return (0);
+}
+
+/*
+ * term_key_set --
+ * Set keys found in the termios structure. VERASE and VKILL are required
+ * by POSIX 1003.1-1990, VWERASE is a 4.4BSD extension. We've left three
+ * 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
+term_key_set(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;
+ }
+}
+
+/*
+ * key_init --
+ * Build the fast-lookup key display array.
+ */
+void
+key_init(sp)
+ SCR *sp;
+{
+ CHAR_T ch;
+
+ for (ch = 0; ch <= MAX_FAST_KEY; ++ch) {
+ (void)__key_name(sp, ch);
+ (void)memmove(sp->gp->cname[ch].name, sp->cname, sp->clen);
+ sp->gp->cname[ch].len = sp->clen;
+ }
+}
+
+/*
+ * __key_len --
+ * Return the length of the string that will display the key.
+ * This routine is the backup for the KEY_LEN() macro.
+ */
+size_t
+__key_len(sp, ch)
+ SCR *sp;
+ ARG_CHAR_T ch;
+{
+ (void)__key_name(sp, ch);
+ return (sp->clen);
+}
+
+/*
+ * __key_name --
+ * Return the string that will display the key. This routine
+ * is the backup for the KEY_NAME() macro.
+ */
+CHAR_T *
+__key_name(sp, ach)
+ SCR *sp;
+ ARG_CHAR_T ach;
+{
+ static const CHAR_T hexdigit[] = "0123456789abcdef";
+ static const CHAR_T octdigit[] = "01234567";
+ CHAR_T ch, *chp, mask;
+ size_t len;
+ int cnt, shift;
+
+ /*
+ * Historical (ARPA standard) mappings. Printable characters are left
+ * alone. Control characters less than '\177' are represented as '^'
+ * followed by the character offset from the '@' character in the ASCII
+ * map. '\177' is represented as '^' followed by '?'.
+ *
+ * XXX
+ * The following code depends on the current locale being identical to
+ * the ASCII map from '\100' to '\076' (\076 since that's the largest
+ * character for which we can offset from '@' and get something that's
+ * a printable character in ASCII. I'm told that this is a reasonable
+ * assumption...
+ *
+ * XXX
+ * This code will only work with CHAR_T's that are multiples of 8-bit
+ * bytes.
+ *
+ * XXX
+ * NB: There's an assumption here that all printable characters take
+ * up a single column on the screen. This is not always correct.
+ */
+ ch = ach;
+ if (isprint(ch)) {
+ sp->cname[0] = ch;
+ len = 1;
+ } else if (ch <= '\076' && iscntrl(ch)) {
+ sp->cname[0] = '^';
+ sp->cname[1] = ch == '\177' ? '?' : '@' + ch;
+ len = 2;
+ } else if (O_ISSET(sp, O_OCTAL)) {
+#define BITS (sizeof(CHAR_T) * 8)
+#define SHIFT (BITS - BITS % 3)
+#define TOPMASK (BITS % 3 == 2 ? 3 : 1) << (BITS - BITS % 3)
+ sp->cname[0] = '\\';
+ sp->cname[1] = octdigit[(ch & TOPMASK) >> SHIFT];
+ shift = SHIFT - 3;
+ for (len = 2, mask = 7 << (SHIFT - 3),
+ cnt = BITS / 3; cnt-- > 0; mask >>= 3, shift -= 3)
+ sp->cname[len++] = octdigit[(ch & mask) >> shift];
+ } else {
+ sp->cname[0] = '0';
+ sp->cname[1] = 'x';
+ for (len = 2, chp = (u_int8_t *)&ch,
+ cnt = sizeof(CHAR_T); cnt-- > 0; ++chp) {
+ sp->cname[len++] = hexdigit[(*chp & 0xf0) >> 4];
+ sp->cname[len++] = hexdigit[*chp & 0x0f];
+ }
+ }
+ sp->cname[sp->clen = len] = '\0';
+ return (sp->cname);
+}
+
+/*
+ * 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 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, nchars, flags)
+ SCR *sp;
+ CHAR_T *s; /* Characters. */
+ size_t nchars; /* Number of chars. */
+ u_int flags; /* CH_* flags. */
+{
+ IBUF *tty;
+ size_t total;
+
+ /* If we have room, stuff the keys into the buffer. */
+ tty = sp->gp->tty;
+ if (nchars <= tty->next ||
+ (tty->ch != NULL && tty->cnt == 0 && nchars <= tty->nelem)) {
+ if (tty->cnt != 0)
+ tty->next -= nchars;
+ tty->cnt += nchars;
+ MEMMOVE(tty->ch + tty->next, s, nchars);
+ MEMSET(tty->chf + tty->next, flags, nchars);
+ return (0);
+ }
+
+ /*
+ * If there are currently characters in the queue, shift them up,
+ * leaving some extra room. Get enough space plus a little extra.
+ */
+#define TERM_PUSH_SHIFT 30
+ total = tty->cnt + tty->next + nchars + TERM_PUSH_SHIFT;
+ if (total >= tty->nelem && __term_read_grow(sp, tty, MAX(total, 64)))
+ return (1);
+ if (tty->cnt) {
+ 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);
+ }
+
+ /* Put the new characters into the queue. */
+ tty->next = TERM_PUSH_SHIFT;
+ tty->cnt += nchars;
+ MEMMOVE(tty->ch + TERM_PUSH_SHIFT, s, nchars);
+ MEMSET(tty->chf + TERM_PUSH_SHIFT, flags, nchars);
+ return (0);
+}
+
+/*
+ * Remove characters from the queue, simultaneously clearing the flag
+ * and map counts.
+ */
+#define QREM_HEAD(q, len) { \
+ size_t __off = (q)->next; \
+ if (len == 1) \
+ tty->chf[__off] = 0; \
+ else \
+ MEMSET(tty->chf + __off, 0, len); \
+ if (((q)->cnt -= len) == 0) \
+ (q)->next = 0; \
+ else \
+ (q)->next += len; \
+}
+#define QREM_TAIL(q, len) { \
+ size_t __off = (q)->next + (q)->cnt - 1; \
+ if (len == 1) \
+ tty->chf[__off] = 0; \
+ else \
+ MEMSET(tty->chf + __off, 0, len); \
+ if (((q)->cnt -= len) == 0) \
+ (q)->next = 0; \
+}
+
+/*
+ * term_key --
+ * Get the next key.
+ *
+ * !!!
+ * The flag TXT_MAPNODIGIT probably needs some explanation. First, the idea
+ * of mapping keys is that one or more keystrokes act like a function key.
+ * What's going on is that vi is reading a number, and the character following
+ * the number may or may not be mapped (TXT_MAPCOMMAND). For example, if the
+ * user is entering the z command, a valid command is "z40+", and we don't want
+ * to map the '+', i.e. if '+' is mapped to "xxx", we don't want to change it
+ * into "z40xxx". However, if the user enters "35x", we want to put all of the
+ * characters through the mapping code.
+ *
+ * Historical practice is a bit muddled here. (Surprise!) It always permitted
+ * mapping digits as long as they weren't the first character of the map, e.g.
+ * ":map ^A1 xxx" was okay. It also permitted the mapping of the digits 1-9
+ * (the digit 0 was a special case as it doesn't indicate the start of a count)
+ * as the first character of the map, but then ignored those mappings. While
+ * it's probably stupid to map digits, vi isn't your mother.
+ *
+ * The way this works is that the TXT_MAPNODIGIT causes term_key to return the
+ * end-of-digit without "looking" at the next character, i.e. leaving it as the
+ * user entered it. Presumably, the next term_key call will tell us how the
+ * user wants it handled.
+ *
+ * There is one more complication. Users might map keys to digits, and, as
+ * it's described above, the commands "map g 1G|d2g" would return the keys
+ * "d2<end-of-digits>1G", when the user probably wanted "d21<end-of-digits>G".
+ * So, if a map starts off with a digit we continue as before, otherwise, we
+ * pretend that we haven't mapped the character and return <end-of-digits>.
+ *
+ * Now that that's out of the way, let's talk about Energizer Bunny macros.
+ * It's easy to create macros that expand to a loop, e.g. map x 3x. It's
+ * fairly easy to detect this example, because it's all internal to term_key.
+ * If we're expanding a macro and it gets big enough, at some point we can
+ * assume it's looping and kill it. The examples that are tough are the ones
+ * where the parser is involved, e.g. map x "ayyx"byy. We do an expansion
+ * on 'x', and get "ayyx"byy. We then return the first 4 characters, and then
+ * find the looping macro again. There is no way that we can detect this
+ * without doing a full parse of the command, because the character that might
+ * cause the loop (in this case 'x') may be a literal character, e.g. the map
+ * map x "ayy"xyy"byy is perfectly legal and won't cause a loop.
+ *
+ * Historic vi tried to detect looping macros by disallowing obvious cases in
+ * the map command, maps that that ended with the same letter as they started
+ * (which wrongly disallowed "map x 'x"), and detecting macros that expanded
+ * too many times before keys were returned to the command parser. It didn't
+ * get many (most?) of the tricky cases right, however, and it was certainly
+ * possible to create macros that ran forever. And, even if it did figure out
+ * what was going on, the user was usually tossed into ex mode. Finally, any
+ * changes made before vi realized that the macro was recursing were left in
+ * place. We recover gracefully, but the only recourse the user has in an
+ * infinite macro loop is to interrupt.
+ *
+ * !!!
+ * It is historic practice that mapping characters to themselves as the first
+ * part of the mapped string was legal, and did not cause infinite loops, i.e.
+ * ":map! { {^M^T" and ":map n nz." were known to work. The initial, matching
+ * characters were returned instead of being remapped.
+ *
+ * XXX
+ * The final issue is recovery. It would be possible to undo all of the work
+ * that was done by the macro if we entered a record into the log so that we
+ * knew when the macro started, and, in fact, this might be worth doing at some
+ * point. Given that this might make the log grow unacceptably (consider that
+ * cursor keys are done with maps), for now we leave any changes made in place.
+ */
+enum input
+term_key(sp, chp, flags)
+ SCR *sp;
+ CH *chp;
+ u_int flags;
+{
+ enum input rval;
+ struct timeval t, *tp;
+ CHAR_T ch;
+ GS *gp;
+ IBUF *tty;
+ SEQ *qp;
+ int init_nomap, ispartial, nr;
+
+ /* If we've been interrupted, return an error. */
+ if (INTERRUPTED(sp))
+ return (INP_INTR);
+
+ gp = sp->gp;
+ tty = gp->tty;
+
+ /*
+ * If the queue is empty, read more keys in. Since no timeout is
+ * requested, s_key_read will either return an error or will read
+ * some number of characters.
+ */
+loop: if (tty->cnt == 0) {
+ if (term_read_grow(sp, tty))
+ return (INP_ERR);
+ if ((rval = sp->s_key_read(sp, &nr, NULL)) != INP_OK)
+ return (rval);
+ /*
+ * If there's something on the mode line that we wanted
+ * the user to see, they just entered a character so we
+ * can presume they saw it.
+ */
+ if (F_ISSET(sp, S_UPDATE_MODE))
+ F_CLR(sp, S_UPDATE_MODE);
+ }
+
+ /* 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)) {
+ /* Set up timeout value. */
+ if (O_ISSET(sp, O_TIMEOUT)) {
+ tp = &t;
+ t.tv_sec = O_VAL(sp, O_KEYTIME) / 10;
+ t.tv_usec = (O_VAL(sp, O_KEYTIME) % 10) * 100000L;
+ } else
+ tp = NULL;
+
+ /* Get the next key. */
+newmap: ch = tty->ch[tty->next];
+ if (ch < MAX_BIT_SEQ && !bit_test(gp->seqb, ch))
+ goto nomap;
+
+ /* Search the map. */
+remap: qp = seq_find(sp, NULL, &tty->ch[tty->next], tty->cnt,
+ LF_ISSET(TXT_MAPCOMMAND) ? SEQ_COMMAND : SEQ_INPUT,
+ &ispartial);
+
+ /* If we've been interrupted, return an error. */
+ if (INTERRUPTED(sp))
+ return (INP_INTR);
+
+ /*
+ * If get a partial match, read more characters and retry
+ * the map. If no characters read, return the characters
+ * unmapped.
+ */
+ if (ispartial) {
+ if (term_read_grow(sp, tty))
+ return (INP_ERR);
+ if ((rval = sp->s_key_read(sp, &nr, tp)) != INP_OK)
+ return (rval);
+ if (nr)
+ goto remap;
+ goto nomap;
+ }
+
+ /* If no map, return the character. */
+ if (qp == NULL)
+ goto nomap;
+
+ /*
+ * If looking for the end of a digit string, and the first
+ * character of the map is it, pretend we haven't seen the
+ * character.
+ */
+ if (LF_ISSET(TXT_MAPNODIGIT) &&
+ qp->output != NULL && !isdigit(qp->output[0]))
+ goto not_digit_ch;
+
+ /* Find out if the initial segments are identical. */
+ init_nomap = !memcmp(&tty->ch[tty->next], qp->output, qp->ilen);
+
+ /* 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 (init_nomap) {
+ if (term_push(sp, qp->output + qp->ilen,
+ qp->olen - qp->ilen, CH_MAPPED))
+ return (INP_ERR);
+ if (term_push(sp,
+ qp->output, qp->ilen, CH_NOMAP | CH_MAPPED))
+ return (INP_ERR);
+ goto nomap;
+ } else
+ if (term_push(sp,
+ qp->output, qp->olen, CH_MAPPED))
+ return (INP_ERR);
+ goto newmap;
+ }
+
+ /* Else, push the characters on the queue and return one. */
+ if (term_push(sp, qp->output, qp->olen, CH_MAPPED | CH_NOMAP))
+ return (INP_ERR);
+ }
+
+nomap: ch = tty->ch[tty->next];
+ if (LF_ISSET(TXT_MAPNODIGIT) && !isdigit(ch)) {
+not_digit_ch: chp->ch = CH_NOT_DIGIT;
+ chp->value = 0;
+ chp->flags = 0;
+ return (INP_OK);
+ }
+
+ /* Fill in the return information. */
+ chp->ch = ch;
+ chp->flags = tty->chf[tty->next];
+ chp->value = KEY_VAL(sp, ch);
+
+ /* Delete the character from the queue. */
+ QREM_HEAD(tty, 1);
+ return (INP_OK);
+}
+
+/*
+ * term_flush --
+ * Flush any flagged keys.
+ */
+void
+term_flush(sp, msg, flags)
+ SCR *sp;
+ char *msg;
+ u_int flags;
+{
+ IBUF *tty;
+
+ tty = sp->gp->tty;
+ if (!tty->cnt || !(tty->chf[tty->next] & flags))
+ return;
+ do {
+ QREM_HEAD(tty, 1);
+ } while (tty->cnt && tty->chf[tty->next] & flags);
+ msgq(sp, M_ERR, "%s: keys flushed", msg);
+}
+
+/*
+ * term_user_key --
+ * Get the next key, but require the user enter one.
+ */
+enum input
+term_user_key(sp, chp)
+ SCR *sp;
+ CH *chp;
+{
+ enum input rval;
+ IBUF *tty;
+ int nr;
+
+ /*
+ * Read any keys the user has waiting. Make the race
+ * condition as short as possible.
+ */
+ if ((rval = term_key_queue(sp)) != INP_OK)
+ return (rval);
+
+ /* Wait and read another key. */
+ if ((rval = sp->s_key_read(sp, &nr, NULL)) != INP_OK)
+ return (rval);
+
+ /* Fill in the return information. */
+ tty = sp->gp->tty;
+ chp->ch = tty->ch[tty->next + (tty->cnt - 1)];
+ chp->flags = 0;
+ chp->value = KEY_VAL(sp, chp->ch);
+
+ QREM_TAIL(tty, 1);
+ return (INP_OK);
+}
+
+/*
+ * term_key_queue --
+ * Read the keys off of the terminal queue until it's empty.
+ */
+static enum input
+term_key_queue(sp)
+ SCR *sp;
+{
+ enum input rval;
+ struct timeval t;
+ IBUF *tty;
+ int nr;
+
+ t.tv_sec = 0;
+ t.tv_usec = 0;
+ for (tty = sp->gp->tty;;) {
+ if (term_read_grow(sp, tty))
+ return (INP_ERR);
+ if ((rval = sp->s_key_read(sp, &nr, &t)) != INP_OK)
+ return (rval);
+ if (nr == 0)
+ break;
+ }
+ return (INP_OK);
+}
+
+/*
+ * __key_val --
+ * Fill in the value for a key. This routine is the backup
+ * for the KEY_VAL() macro.
+ */
+int
+__key_val(sp, ch)
+ SCR *sp;
+ ARG_CHAR_T ch;
+{
+ KEYLIST k, *kp;
+
+ k.ch = ch;
+ kp = bsearch(&k, keylist, nkeylist, sizeof(keylist[0]), keycmp);
+ return (kp == NULL ? K_NOTUSED : kp->value);
+}
+
+/*
+ * __term_read_grow --
+ * Grow the terminal queue. This routine is the backup for
+ * the term_read_grow() macro.
+ */
+static int
+__term_read_grow(sp, tty, add)
+ SCR *sp;
+ IBUF *tty;
+ int add;
+{
+ size_t new_nelem, olen;
+
+ new_nelem = tty->nelem + add;
+ olen = tty->nelem * sizeof(tty->ch[0]);
+ BINC_RET(sp, tty->ch, olen, new_nelem * sizeof(tty->ch[0]));
+
+ olen = tty->nelem * sizeof(tty->chf[0]);
+ BINC_RET(sp, tty->chf, olen, new_nelem * sizeof(tty->chf[0]));
+
+ tty->nelem = olen / sizeof(tty->chf[0]);
+ return (0);
+}
+
+static int
+keycmp(ap, bp)
+ const void *ap, *bp;
+{
+ return (((KEYLIST *)ap)->ch - ((KEYLIST *)bp)->ch);
+}
diff --git a/usr.bin/vi/common/term.h b/usr.bin/vi/common/term.h
new file mode 100644
index 000000000000..623a94c8cffd
--- /dev/null
+++ b/usr.bin/vi/common/term.h
@@ -0,0 +1,205 @@
+/*-
+ * 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.
+ *
+ * @(#)term.h 8.48 (Berkeley) 7/25/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_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_HEXCHAR 10
+#define K_NL 11
+#define K_RIGHTBRACE 12
+#define K_RIGHTPAREN 13
+#define K_TAB 14
+#define K_VERASE 15
+#define K_VKILL 16
+#define K_VLNEXT 17
+#define K_VWERASE 18
+#define K_ZERO 19
+ u_int8_t value; /* Special character flag values. */
+
+#define CH_ABBREVIATED 0x01 /* Character from an abbreviation. */
+#define CH_MAPPED 0x02 /* Character from a map. */
+#define CH_NOMAP 0x04 /* Do not map the character. */
+#define CH_QUOTED 0x08 /* Character is already quoted. */
+ u_int8_t flags;
+};
+
+typedef struct _keylist {
+ u_int8_t value; /* Special value. */
+ CHAR_T ch; /* Key. */
+} KEYLIST;
+
+extern KEYLIST keylist[];
+
+/* Structure for the key input buffer. */
+struct _ibuf {
+ CHAR_T *ch; /* Array of characters. */
+ u_int8_t *chf; /* Array of character flags (CH_*). */
+
+ size_t cnt; /* Count of remaining characters. */
+ size_t nelem; /* Numer of array elements. */
+ size_t next; /* Offset of next array entry. */
+};
+ /* Return if more keys in queue. */
+#define KEYS_WAITING(sp) ((sp)->gp->tty->cnt)
+#define MAPPED_KEYS_WAITING(sp) \
+ (KEYS_WAITING(sp) && sp->gp->tty->chf[sp->gp->tty->next] & CH_MAPPED)
+
+/*
+ * Routines that return a key as a side-effect return:
+ *
+ * INP_OK Returning a character; must be 0.
+ * INP_EOF EOF.
+ * INP_ERR Error.
+ * INP_INTR Interrupted.
+ *
+ * The vi structure depends on the key routines being able to return INP_EOF
+ * multiple times without failing -- eventually enough things will end due to
+ * INP_EOF that vi will reach the command level for the screen, at which point
+ * the exit flags will be set and vi will exit.
+ */
+enum input { INP_OK=0, INP_EOF, INP_ERR, INP_INTR };
+
+/*
+ * Routines that return a confirmation return:
+ *
+ * CONF_NO User answered no.
+ * CONF_QUIT User answered quit, eof or an error.
+ * CONF_YES User answered yes.
+ */
+enum confirm { CONF_NO, CONF_QUIT, CONF_YES };
+
+/*
+ * Ex/vi commands are generally separated by whitespace characters. We
+ * can't use the standard isspace(3) macro because it returns true for
+ * characters like ^K in the ASCII character set. The 4.4BSD isblank(3)
+ * macro does exactly what we want, but it's not portable yet.
+ *
+ * XXX
+ * Note side effect, ch is evaluated multiple times.
+ */
+#ifndef isblank
+#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 CH_BSEARCH '?' /* Backward search prompt. */
+#define CH_CURSOR ' ' /* Cursor character. */
+#define CH_ENDMARK '$' /* End of a range. */
+#define CH_EXPROMPT ':' /* Ex prompt. */
+#define CH_FSEARCH '/' /* Forward search prompt. */
+#define CH_HEX '\030' /* Leading hex character. */
+#define CH_LITERAL '\026' /* ASCII ^V. */
+#define CH_NO 'n' /* No. */
+#define CH_NOT_DIGIT 'a' /* A non-isdigit() character. */
+#define CH_QUIT 'q' /* Quit. */
+#define CH_YES 'y' /* Yes. */
+
+#define STR_CONFIRM "confirm? [ynq]"
+#define STR_CMSG "Enter return to continue: "
+#define STR_QMSG "Enter return to continue [q to quit]: "
+
+/* Flags describing how input is handled. */
+#define TXT_AICHARS 0x00000001 /* Leading autoindent chars. */
+#define TXT_ALTWERASE 0x00000002 /* Option: altwerase. */
+#define TXT_APPENDEOL 0x00000004 /* Appending after EOL. */
+#define TXT_AUTOINDENT 0x00000008 /* Autoindent set this line. */
+#define TXT_BACKSLASH 0x00000010 /* Backslashes escape characters. */
+#define TXT_BEAUTIFY 0x00000020 /* Only printable characters. */
+#define TXT_BS 0x00000040 /* Backspace returns the buffer. */
+#define TXT_CNTRLD 0x00000080 /* Control-D is a special command. */
+#define TXT_CNTRLT 0x00000100 /* Control-T is an indent special. */
+#define TXT_CR 0x00000200 /* CR returns the buffer. */
+#define TXT_DOTTERM 0x00000400 /* Leading '.' terminates the input. */
+#define TXT_EMARK 0x00000800 /* End of replacement mark. */
+#define TXT_ESCAPE 0x00001000 /* Escape returns the buffer. */
+#define TXT_EXSUSPEND 0x00002000 /* ^Z should suspend the session. */
+#define TXT_INFOLINE 0x00004000 /* Editing the info line. */
+#define TXT_MAPCOMMAND 0x00008000 /* Apply the command map. */
+#define TXT_MAPINPUT 0x00010000 /* Apply the input map. */
+#define TXT_MAPNODIGIT 0x00020000 /* Return to a digit. */
+#define TXT_NLECHO 0x00040000 /* Echo the newline. */
+#define TXT_OVERWRITE 0x00080000 /* Overwrite characters. */
+#define TXT_PROMPT 0x00100000 /* Display a prompt. */
+#define TXT_RECORD 0x00200000 /* Record for replay. */
+#define TXT_REPLACE 0x00400000 /* Replace; don't delete overwrite. */
+#define TXT_REPLAY 0x00800000 /* Replay the last input. */
+#define TXT_RESOLVE 0x01000000 /* Resolve the text into the file. */
+#define TXT_SHOWMATCH 0x02000000 /* Option: showmatch. */
+#define TXT_TTYWERASE 0x04000000 /* Option: ttywerase. */
+#define TXT_WRAPMARGIN 0x08000000 /* Option: wrapmargin. */
+
+/* Support keyboard routines. */
+size_t __key_len __P((SCR *, ARG_CHAR_T));
+CHAR_T *__key_name __P((SCR *, ARG_CHAR_T));
+int __key_val __P((SCR *, ARG_CHAR_T));
+void key_init __P((SCR *));
+void term_flush __P((SCR *, char *, u_int));
+enum input term_key __P((SCR *, CH *, u_int));
+enum input term_user_key __P((SCR *, CH *));
+int term_init __P((SCR *));
+int term_push __P((SCR *, CHAR_T *, size_t, u_int));
diff --git a/usr.bin/vi/common/trace.c b/usr.bin/vi/common/trace.c
new file mode 100644
index 000000000000..1f63f6628a2e
--- /dev/null
+++ b/usr.bin/vi/common/trace.c
@@ -0,0 +1,84 @@
+/*-
+ * 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.
+ *
+ * @(#)trace.c 8.2 (Berkeley) 3/8/94
+ */
+
+#ifdef DEBUG
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#ifdef __STDC__
+TRACE(SCR *sp, const char *fmt, ...)
+#else
+TRACE(sp, fmt, va_alist)
+ SCR *sp;
+ char *fmt;
+ va_dcl
+#endif
+{
+ FILE *tfp;
+ va_list ap;
+
+ if ((tfp = sp->gp->tracefp) == NULL)
+ return;
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)vfprintf(tfp, fmt, ap);
+ va_end(ap);
+
+ (void)fflush(tfp);
+}
+#endif
diff --git a/usr.bin/vi/common/util.c b/usr.bin/vi/common/util.c
new file mode 100644
index 000000000000..9845e644955e
--- /dev/null
+++ b/usr.bin/vi/common/util.c
@@ -0,0 +1,215 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)util.c 8.71 (Berkeley) 8/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 <unistd.h>
+
+#include "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * binc --
+ * Increase the size of a buffer.
+ */
+int
+binc(sp, argp, bsizep, min)
+ SCR *sp; /* sp MAY BE NULL!!! */
+ void *argp;
+ size_t *bsizep, min;
+{
+ size_t csize;
+ void *bpp;
+
+ /* If already larger than the minimum, just return. */
+ if (min && *bsizep >= min)
+ return (0);
+
+ bpp = *(char **)argp;
+ csize = *bsizep + MAX(min, 256);
+ REALLOC(sp, bpp, void *, csize);
+
+ if (bpp == 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
+ * including or after the starting column. On error, set
+ * the column to 0, it's safest.
+ */
+int
+nonblank(sp, ep, lno, cnop)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ size_t *cnop;
+{
+ char *p;
+ size_t cnt, len, off;
+
+ /* Default. */
+ off = *cnop;
+ *cnop = 0;
+
+ /* Get the line. */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ return (0);
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+
+ /* Set the offset. */
+ if (len == 0 || off >= len)
+ return (0);
+
+ for (cnt = off, p = &p[off],
+ len -= off; len && isblank(*p); ++cnt, ++p, --len);
+
+ /* Set the return. */
+ *cnop = len ? cnt : cnt - 1;
+ return (0);
+}
+
+/*
+ * tail --
+ * Return tail of a path.
+ */
+char *
+tail(path)
+ char *path;
+{
+ char *p;
+
+ if ((p = strrchr(path, '/')) == NULL)
+ return (path);
+ return (p + 1);
+}
+
+/*
+ * set_alt_name --
+ * Set the alternate file name.
+ *
+ * Swap the alternate file name. It's a routine because I wanted some place
+ * to hang this comment. The alternate file name (normally referenced using
+ * the special character '#' during file expansion) is set by many
+ * operations. In the historic vi, the commands "ex", and "edit" obviously
+ * set the alternate file name because they switched the underlying file.
+ * Less obviously, the "read", "file", "write" and "wq" commands set it as
+ * well. In this implementation, some new commands have been added to the
+ * list. Where it gets interesting is that the alternate file name is set
+ * multiple times by some commands. If an edit attempt fails (for whatever
+ * reason, like the current file is modified but as yet unwritten), it is
+ * set to the file name that the user was unable to edit. If the edit
+ * succeeds, it is set to the last file name that was edited. Good fun.
+ *
+ * If the user edits a temporary file, there are time when there isn't an
+ * alternative file name. A name argument of NULL turns it off.
+ */
+void
+set_alt_name(sp, name)
+ SCR *sp;
+ char *name;
+{
+ if (sp->alt_name != NULL)
+ free(sp->alt_name);
+ if (name == NULL)
+ sp->alt_name = NULL;
+ else if ((sp->alt_name = strdup(name)) == NULL)
+ msgq(sp, M_SYSERR, NULL);
+}
+
+/*
+ * v_strdup --
+ * Strdup for wide character strings with an associated length.
+ */
+CHAR_T *
+v_strdup(sp, str, len)
+ SCR *sp;
+ CHAR_T *str;
+ size_t len;
+{
+ CHAR_T *copy;
+
+ MALLOC(sp, copy, CHAR_T *, len + 1);
+ if (copy == NULL)
+ return (NULL);
+ memmove(copy, str, len * sizeof(CHAR_T));
+ copy[len] = '\0';
+ return (copy);
+}
+
+/*
+ * vi_putchar --
+ * Functional version of putchar, for tputs.
+ */
+void
+vi_putchar(ch)
+ int ch;
+{
+ (void)putchar(ch);
+}
diff --git a/usr.bin/vi/common/vi.h b/usr.bin/vi/common/vi.h
new file mode 100644
index 000000000000..f98b8701edc5
--- /dev/null
+++ b/usr.bin/vi/common/vi.h
@@ -0,0 +1,124 @@
+/*-
+ * 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.
+ *
+ * @(#)vi.h 8.46 (Berkeley) 8/8/94
+ */
+
+/*
+ * Forward structure declarations. Not pretty, but the include files
+ * are far too interrelated for a clean solution.
+ */
+typedef struct _cb CB;
+typedef struct _ch CH;
+typedef struct _excmdarg EXCMDARG;
+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;
+typedef struct _optlist OPTLIST;
+typedef struct _scr SCR;
+typedef struct _script SCRIPT;
+typedef struct _seq SEQ;
+typedef struct _tag TAG;
+typedef struct _tagf TAGF;
+typedef struct _text TEXT;
+
+/*
+ * Local includes.
+ */
+#include "term.h" /* Required by args.h. */
+#include "args.h" /* Required by options.h. */
+#include "options.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 "seq.h" /* Required by screen.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 "log.h"
+#include "mem.h"
+
+#if FWOPEN_NOT_AVAILABLE /* See PORT/clib/fwopen.c. */
+#define EXCOOKIE sp
+int ex_fflush __P((SCR *));
+int ex_printf __P((SCR *, const char *, ...));
+FILE *fwopen __P((SCR *, void *));
+#else
+#define EXCOOKIE sp->stdfp
+#define ex_fflush fflush
+#define ex_printf fprintf
+#endif
+
+/* Macros to set/clear/test flags. */
+#define F_SET(p, f) (p)->flags |= (f)
+#define F_CLR(p, f) (p)->flags &= ~(f)
+#define F_ISSET(p, f) ((p)->flags & (f))
+
+#define LF_INIT(f) flags = (f)
+#define LF_SET(f) flags |= (f)
+#define LF_CLR(f) flags &= ~(f)
+#define LF_ISSET(f) (flags & (f))
+
+/*
+ * XXX
+ * MIN/MAX have traditionally been in <sys/param.h>. Don't
+ * try to get them from there, it's just not worth the effort.
+ */
+#ifndef MAX
+#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a))
+#endif
+#ifndef MIN
+#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
+#endif
+
+/* Function prototypes that don't seem to belong anywhere else. */
+int nonblank __P((SCR *, EXF *, recno_t, size_t *));
+void set_alt_name __P((SCR *, char *));
+char *tail __P((char *));
+CHAR_T *v_strdup __P((SCR *, CHAR_T *, size_t));
+void vi_putchar __P((int));
+
+#ifdef DEBUG
+void TRACE __P((SCR *, const char *, ...));
+#endif
+
+/* Digraphs (not currently real). */
+int digraph __P((SCR *, int, int));
+int digraph_init __P((SCR *));
+void digraph_save __P((SCR *, int));
diff --git a/usr.bin/vi/docs/README b/usr.bin/vi/docs/README
new file mode 100644
index 000000000000..5bece9929082
--- /dev/null
+++ b/usr.bin/vi/docs/README
@@ -0,0 +1,200 @@
+# @(#)README 8.84 (Berkeley) 8/15/94
+
+This is the README for version 1.32 of nex/nvi, a freely redistributable
+replacement for the Berkeley ex and vi text editors. The compressed or
+gzip'd archive, for this and future versions, can be retrieved by using
+anonymous ftp to ftp.cs.berkeley.edu, from the file ucb/4bsd/nvi.tar.Z,
+or ucb/4bsd/nvi.tar.gz.
+
+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, 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.
+ */
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+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 pretty stable. Almost all of
+the historic functionality in ex/vi is there, the only major missing
+pieces are open mode and the lisp option. (Also, the options hardtabs,
+optimize, redraw, and slowopen are recognized, but ignored.)
+
+Nvi is mostly 8-bit clean. This isn't difficult to fix, and was left
+in during initial development to keep things simple. Wide character
+support will be integrated at the same time that 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. The "Additional Features" section of the reference page
+(USD.doc/vi.ref/vi.ref.txt, USD.doc/vi.ref/vi.ref.ps) has more information.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Porting information:
+
+The directory "PORT" has directories for specific OS/machine combinations,
+including V7-style Makefiles, for building nex/nvi on different machines.
+See the file PORT/README for detailed information.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Debugging:
+
+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. Stack traces of core dumps
+are only rarely helpful -- an example file with a set of keystrokes that
+causes the problem is almost invariably necessary.
+
+Please include the following in the bug report;
+
+ o The version of nvi you're running (use :version to get it).
+ o The row/column dimensions of the screen (80 x 32).
+ o Unless you're confident that they're not part of the problem,
+ your startup files (.exrc, .nexrc) and the environment variable
+ (EXININT, NEXINIT) values. (Cutting and pasting the output
+ of ":set all" is usually sufficient.)
+
+If you're running a memory checker (e.g. Purify) on nvi, you will want
+to recompile everything with "-DPURIFY" in the CFLAGS, first. By
+default, allocated pages are not initialized by the DB code, and they
+will show up as reads of uninitialized memory in the buffer write routines.
+
+=-=-=-=-=-=-=-=-=-=-=
+o Directory layout:
+
+nvi/USD.doc:
+ Ex/vi documentation, both historic and current.
+
+ edit/ Roff source for "Edit: A tutorial", USD:14 in the
+ 4.3BSD manuals.
+ ex/ Roff source for "Ex Reference Manual -- Version
+ 3.7", USD:16 in the 4.3BSD manuals.
+ vi/ Roff source for "An Introduction to Display
+ Editing with Vi", USD:15 in the 4.3BSD manuals.
+ Includes the "Vi Quick Reference" card.
+ vi.man/ Manual page for nex/nvi; an updated version of
+ the document distributed with 4.4BSD-Lite.
+ vi.ref/ Reference document for nex/nvi; an updated version
+ of the document distributed with 4.4BSD-Lite.
+
+nvi/common:
+ 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
+ interface code for modifying "records" in the underlying database.
+
+nvi/docs:
+ Random nvi documentation:
+
+ README -- Nvi main README file.
+ bugs.current -- Major known bugs in the current nvi.
+ 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 -- Out-of-date nvi internal structure description.
+ tutorial/ -- Historic vi tutorial(s), of unknown quality.
+
+nvi/ex:
+ 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/install:
+ Things to install on the local system.
+
+ recover.script -- Vi recovery script.
+
+nvi/PORT:
+ Porting directories, one per OS/architecture combination. See
+ nvi/PORT/README for porting information.
+
+ curses/ -- 4.4BSD curses implementation
+ db/ -- 4.4BSD DB routines.
+ regex/ -- Henry Spencer's POSIX.2 RE support.
+
+nvi/sex:
+ The screen support for the ex editor.
+
+nvi/svi:
+ The screen support for a curses based vi editor.
+
+nvi/vi:
+ The vi source code.
+
+nvi/xaw:
+ Place reserved for an X11 (Athena Widget) screen.
diff --git a/usr.bin/vi/docs/bugs.current b/usr.bin/vi/docs/bugs.current
new file mode 100644
index 000000000000..92b2a5c3b43b
--- /dev/null
+++ b/usr.bin/vi/docs/bugs.current
@@ -0,0 +1,47 @@
+List of known bugs:
+
++ The number option doesn't display line numbers in ex append/insert
+ mode.
+
++ The option sidescroll is completely wrong, and setting it does more
+ harm than good.
+
++ We're not blocking signals when manipulating the SCR/EXF chains.
+ This is necessary, since we walk them on signal receipt.
+
++ When nvi edits files that don't have trailing newlines, it appends
+ one, regardless.
+
++ Open mode is not yet implemented.
+
++ ^C isn't passed to the shell in the script windows as an interrupt
+ character.
+
++ The options:
+
+ hardtabs, lisp, optimize, redraw, slowopen
+
+ are recognized, but not implemented. These options are unlikely to
+ be implemented, so if you want them you might want to say something!
+ I will implement lisp if anyone ever documents how it worked.
+
++ Screen repainting over slow lines, for some screen changes, isn't
+ as good as the historic vi's.
+
++ The line movement commands ('k', 'j' are easy examples) don't find the
+ most attractive cursor position correctly when wrapped lines are longer
+ than 80 characters, and they're on the second or subsequent lines.
+
++ Colon commands longer than a single line cause the display to be
+ incorrect.
+
++ 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..335acd863921
--- /dev/null
+++ b/usr.bin/vi/docs/changelog
@@ -0,0 +1,519 @@
+1.31 -> 1.32 Mon Aug 15 14:27:49 1994
+ + Turn off recno mmap call for Solaris 2.4/SunOS 5.4.
+1.30 -> 1.31 Sun Aug 14 13:13:35 1994
+ + Fix bug were cG on the last line of a file wasn't done in line mode,
+ and where the cursor wasn't positioned correctly after exiting text
+ insert mode.
+ + Add termcap workaround to make function keys greater than 9 work
+ correctly (or fail if old-style termcap support).
+ + Change ex/vi to not flush mapped keys on error -- this is historic
+ practice, and people depended on it.
+ + Rework vi parser so that no command including a mapped key ever
+ becomes the '.' command, matching historic practice.
+ + Make <escape> cancellation in the vi parser match POSIX 1003.2.
+ + Fix curses bug where standout string was written for each standout
+ character, and where standout mode was never exited explicitly.
+ Fix bugs in curses SF/sf and SR/sr scrolling, as seen on Sun and
+ x86 consoles.
+ + The v/global commands execute the print command by default.
+ + The number option historically applies to ex as well as vi.
+1.29 -> 1.30 Mon Aug 8 10:30:42 1994
+ + Make first read into a temporary set the file's name.
+ + Permit any key to continue scrolling or ex commands -- this
+ allows stacked colon commands, and matches historic practice.
+ + Don't output normal ! command commentary in ex silent mode.
+ + Allow +/- flags after substitute commands, make line (flag)
+ offsets from vi mode match historic practice.
+ + Return <eof> to ex immediately, even if preceded by spaces. Rework
+ ex parser to do erase the prompt instead of depending on the print
+ routines to do it. Minor fixes to the ex parser for display of
+ default and scrolling commands. MORE EX PARSER CHANGES.
+1.28 -> 1.29 Fri Aug 5 10:18:07 1994
+ + Make the abbreviated ex delete command work (:dele---###lll for
+ example, is historically legal.
+ + When autoprint fires, multiple flags may be set, use ex_print
+ directly instead of the stub routines.
+ + Change v/global commands to turn off autoprint while running.
+ + Minor changes to make the ! command display match historic output.
+ + Rework the ex parser to permit multiple command separators without
+ commands -- MAJOR CHANGE, likely to introduce all sorts of new bugs.
+ + Fix cd command to expand argument in the context of each element
+ of the cdpath option, make relative paths always relative to the
+ current directory.
+ + Rework write/quit cases for temporary files, so that user's don't
+ discard them accidentally.
+ + Check for window size changes when continuing after a suspend.
+ + Fix memory problem in svi_screen, used free'd memory.
+ + Change the ex change, insert, append commands to match historic
+ cursor positions if no data entered by the user.
+ + Change ex format flags (#, l, p) to affect future commands, not
+ just the current one, to match historic practice.
+ + Make the user's EOF character an additional scroll character in ex.
+ + Fix ex ^D scrolling to be the value of the scroll option, not half
+ the screen.
+ + Fix buffer execution to match historic practice -- bugs where the
+ '*' command didn't work, and @<carriage-return> didn't work.
+ + Fix doubled reporting of deleted lines in filters.
+ + Rework the % ` / ? ( ) N n { and ^A commands to always cut into
+ numeric buffers regardless of the location or length of the cut.
+ This matches historic practice.
+ + Fix the { command to check the current line if the cursor doesn't
+ start on the first character of the line.
+ + Do '!' expansion in the ex read command arguments, it's historic
+ practice. In addition, it sets the last '!' command.
+1.27 -> 1.28 Wed Jul 27 21:29:18 1994
+ + Add support for scrolling using the CS and SF/sf/SR/sr termcap
+ strings to the 4BSD curses.
+ + Rework of getkey() introduced a bug where command interrupt put
+ nvi into an infinite loop.
+ + Piping through a filter historically cut the replaced lines into
+ the default buffer, although not the numeric ones.
+ + Read of a filter and !! historically moved to the first nonblank
+ of the resulting cursor line (most of the time).
+ + Rework cursor motion flags, to support '!' as a motion command.
+1.26 -> 1.27 Tue Jul 26 10:27:58 1994
+ + Add the meta option, to specify characters the shell will expand.
+ + Fix the read command to match historic practice, the white space
+ and bang characters weren't getting parsed correctly.
+ + Change SIGALRM handler to save and restore errno.
+ + Change SunOS include/compat.h to include <vfork.h> so that the
+ ex/filter.c code works again.
+ + Don't put lines deleted by the ex delete command into the numeric
+ buffers, matching historic practice.
+ + Fix; if appending to a buffer, default buffer historically only
+ references the appended text, not the resulting text.
+ + Support multiple, semi-colon separated search strings, and 'z'
+ commands after search strings.
+ + Make previous context mark setting match historic practice (see
+ docs/internals/context).
+ + Fix the set command to permit whitespace between the option and
+ the question mark, fix question marks in general.
+ + Fix bug where ex error messages could be accidentally preceded
+ by a single space.
+ + Fix bug where curses reorganization could lose screen specific
+ mappings as soon as any screen exited.
+ + Fix bug in paragraph code where invalid macros could be matched.
+ Make paragraph motions stop at formfeed (^L) characters.
+ + Change 'c' to match historic practice, it cut text into numeric
+ buffers.
+1.25 -> 1.26 Tue Jul 19 17:46:24 1994
+ + Ignore SIGWINCH if the screen size is unchanged; SunOS systems
+ deliver one when a screen is uncovered.
+ + Fix: don't permit a command with a motion component to wrap due
+ to wrapscan and return to the original cursor position.
+ + Fix: ^E wasn't beeping when reaching the bottom of the file.
+ + Fix bg/fg bug where tmp file exiting caused a NULL dereference.
+ + Rework file locking code to use fcntl(2) explicitly.
+ + Fix bug in section code where invalid macros could be matched.
+ + Fix bug where line number reset by vi's Q command.
+ + Add explicit character mode designation to character mode buffers.
+ + Add <sys/ioctl.h> include to sex/sex_window.c, needed by NET/2
+ vintage systems.
+ + Change to always flush a character during suspend, 4BSD curses
+ has the optimization where it doesn't flush after a standend().
+ + Fix bug on OSF1 where <curses.h> changes the values of VERASE,
+ VKILL and VWERASE to incorrect ones.
+ + Fix bug where optarg used incorrectly in main.c.
+ + Block all signals when acting on a signal delivery.
+ + Fix recovery bug where RCV_EMAIL could fire even if there wasn't
+ a backing file; format recovery message.
+1.24 -> 1.25 Sun Jul 17 14:33:38 1994
+ + Stop allowing keyboard suspends (^Z) in insert mode, it's hard
+ to get autowrite correct, and it's not historic practice.
+ + Fix z^, z+ to match historic practice.
+ + Bug in message handling, "vi +35 non-existent_file" lost the
+ status message because the "+35" pushed onto the stack erased
+ it. For now, change so that messages aren't displayed if there
+ are keys waiting -- may need to add a "don't-erase" bit to the
+ character in the stack instead.
+ + Bug in svi_msgflush(), where error messages could come out in
+ normal video.
+1.23 -> 1.24 Sat Jul 16 18:30:18 1994
+ + Fix core dump in exf.c, where editing a non-existent file and
+ exiting could cause already free'd memory to be free'd.
+ + Clean up numerous memory errors, courtesy of Purify.
+ + Change process wait code to fail if wait fails, and not attempt
+ to interpret the wait return information.
+ + Open recovery and DB files for writing as well as reading, System
+ V (fcntl) won't let you acquire LOCK_EX locks otherwise.
+ + Fix substitute bug where could malloc 0 bytes (AIX breaks).
+ + Permit the mapping of <carriage-return>, it's historic practice.
+ + Historic vi didn't eat <blank> characters before the force
+ flag, match historic practice.
+ + Bug in ex argument parsing, corrected for literal characters
+ twice.
+ + Delete screen specific maps when the screen closes.
+ + Move to the first non-<blank> in the line on startup; historic
+ practice.
+ + Change the ex visual command to move directly to a line if no
+ trailing 'z' command.
+ + Fix "[[" and "]]" to match historic practice (yet again...).
+ + Fix "yb" and "y{" commands to update the cursor correctly.
+ + Change "~<motion>" to match the yank cursor movement semantics
+ exactly.
+ + Move all of the curses related code into sex/svi -- major rework,
+ but should help in future ports.
+ + Fix bug in split code caused by new file naming code, where would
+ drop core when a split screen exited.
+ + Change svi_ex_write to do character display translation, so that
+ messages with file names in them are displayed correctly.
+ + Display the file name on split screens instead of a divider line.
+ + Fix move bug, wasn't copying lines before putting them.
+ + Fix bug were :n dropped core if no arguments supplied.
+ + Don't quote characters in executed buffer: "ifoo<esc>" should leave
+ insert mode after the buffer is executed.
+ + Tagpop and tagpush should set the absolute mark in case only moving
+ within a file.
+ + Skip leading whitespace characters before tags and cursor word
+ searches.
+ + Fix bug in ex_global where re_conv() was allocating the temporary
+ buffer and not freeing it.
+1.22 -> 1.23: Wed Jun 29 19:22:33 1994
+ + New <sys/cdefs.h> required "inline" to change to "__inline"
+ + Fix System V curses code for new ^Z support.
+ + Fix off-by-one in the move code, avoid ":1,$mo$" with only one
+ line in the buffer.
+ + Line orientation of motion commands was remembered too long,
+ i.e. '.' command could be incorrectly marked as line oriented.
+ + Move file modification time into EXF, so it's shared across
+ split screens.
+ + Put the prev[ious] command back in, people complained.
+ + Random fixes to next/prev semantics changed in 1.22.
+ + Historically vi doesn't only move to the last address if there's
+ ANYTHING after the addresses, e.g. ":3" moves to line 3, ":3|"
+ prints line 3.
+1.21 -> 1.22: Mon Jun 27 11:01:41 1994
+ + Make the line between split screens inverse video again.
+ + Delete the prev[ious] command, it's not useful enough to keep.
+ + Rework :args/file name handling from scratch -- MAJOR CHANGE,
+ likely to introduce all sorts of new bugs.
+ + Fix RE bug where no subexpressions in the pattern but there were
+ subexpressions referenced in the replacement, e.g. "s/XXX/\1/g".
+ + Change recovery to not leave unmodified files around after a
+ crash, by using the owner 'x' bit on unmodified backup files.
+ MAJOR CHANGE, the system recovery script has to change!
+ + Change -r option to delete recovery.* files that reference non-
+ existent vi.* files.
+ + Rework recovery locking so that fcntl(2) locking will work.
+ + Fix append (upper-case) buffers, broken by cut fixes.
+ + Fix | to not set the absolute motion mark.
+ + Read $HOME/.exrc file on startup if the effective user ID is
+ root. This makes running vi while su(1)'d work correctly.
+ + Use the full pathname of the file as the recovery name, not
+ just the last component. Matches historic practice.
+ + Keep marks in empty files from being destroyed.
+ + Block all caught signals before calling the DB routines.
+ + Make the line change report match historic practice (yanked
+ lines were different than everything else).
+ + Add section on multiple screens to the reference manual.
+ + Display all messages at once, combine onto a single line if
+ possible. Delete the trailing period from all messages.
+1.20 -> 1.21: Thu May 19 12:21:58 1994
+ + Delete the -l flag from the recover mail.
+ + Send the user email if ex command :preserve executed, this matches
+ historic practice. Lots of changes to the preserve and recovery
+ code, change preserve to snapshot files (again, historic practice).
+ + Make buffers match historic practice: "add logically stores text
+ into buffer a, buffer 1, and the unnamed buffer.
+ + Print <tab> characters as ^I on the colon command line if the
+ list option set.
+ + Adjust ^F and ^B scroll values in the presence of split screens
+ and small windows.
+ + Break msg* routines out from util.c into msg.c, start thinking
+ about message catalogs.
+ + Add tildeop set option, based on stevie's option of the same name.
+ Changes the ~ command into "[count] ~ motion", i.e. ~ takes a
+ trailing motion.
+ + Chose NOT to match historic practice on cursor positioning after
+ consecutive undo commands on a single line; see vi/v_undo.c for
+ the comment.
+ + Add a one line cache so that multiple changes to the same line
+ are only counted once (e.g. "dl35p" changes one line, not 35).
+ + Rework signals some more. Block file sync signals in vi routines
+ that interface to DB, so can sync the files at interrupt time.
+ Write up all of the signal handling arguments, see signal.c.
+1.19 -> 1.20: Thu May 5 19:24:57 1994
+ + Return ^Z to synchronous handling. See the dicussion in signal.c
+ and svi_screen.c:svi_curses_init().
+ + Fix bug where line change report was wrong in util.c:msg_rpt().
+1.18 -> 1.19: Thu May 5 12:59:51 1994
+ + Block DSUSP so that ^Y isn't delivered at SIGTSTP.
+ + Fix bug -- put into an empty file leaves the cursor at 1,0,
+ not the first nonblank.
+ + Fix bug were number of lines reported for the 'P' command was
+ off-by-one.
+ + Fix bug were 0^D wasn't being handled correctly.
+ + Delete remnants of ^Z as a raw character.
+ + Fix bug where if a map was an entire colon command, it may never
+ have been displayed.
+ + Final cursor position fixes for the vi T and t commands.
+ + The ex :next command took an optional ex command as it's first
+ argument similar to the :edit commands. Match historic practice.
+1.17 -> 1.18: Wed May 4 13:57:10 1994
+ + Rework curses information in the PORT/Makefile's.
+ + Minor fixes to ^Z asynchronous code.
+1.16 -> 1.17: Wed May 4 11:15:56 1994
+ + Make ex comment handling match historic practice.
+ + Make ^Z work asynchronously, we can no longer use the SIGTSTP
+ handler in the curses library.
+1.15 -> 1.16: Mon May 2 19:42:07 1994
+ + Make the 'p' and 'P' commands support counts, i.e. "Y10p" works.
+ + Make characters that map to themselves as the first part of the
+ mapping work, it's historic practice.
+ + Fix bug where "s/./\& /" discarded the space in the replacement
+ string.
+ + Add support for up/down cursor arrows in text input mode, rework
+ left/right support to match industry practice.
+ + Fix bug were enough character remapping could corrupt memory.
+ + Delete O_REMAPMAX in favor of setting interrupts after N mapped
+ characters without a read, delete the map counter per character.
+ MAJOR CHANGE. All of the interrupt signal handling has been
+ reworked so that interrupts are always turned on instead of
+ being turned on periodically, when an interruptible operation is
+ pending.
+ + Fix bug where vi wait() was interrupted by the recovery alarm.
+ + Make +cmd's and initial commands execute with the current line
+ set to the last line of the file. This is historic practice.
+ + Change "lock failed" error message to a file status message.
+ It always fails over NFS, and making all NFS files readonly
+ isn't going to fly.
+ + Use the historic line number format, but check for overflow.
+ + Fix bug where vi command parser ignored buffers specified as
+ part of the motion command.
+ + Make [@*]buffer commands on character mode buffers match historic
+ practice.
+ + Fix bug where the cmap/chf entries of the tty structure weren't
+ being cleared when new characters were read.
+ + Fix bug where the default command motion flags were being set
+ when the command was a motion component.
+ + Fix wrapmargin bug; if appending characters, and wrapmargin breaks
+ the line, an additional space is eaten.
+1.14 -> 1.15: Fri Apr 29 07:44:57 1994
+ + Make the ex delete command work in any empty file.
+ + Fix bug where 't' command placed the cursor on the character
+ instead of to its left.
+ + ^D and ^U didn't set the scroll option value historically.
+ Note, this change means that any user set value (e.g. 15^D)
+ will be lost when splitting the screen, since the split code
+ now resets the scroll value regardless.
+ + Fix the ( command to set the absolute movement mark.
+ + Only use TIOCGWINSZ for window information if SIGWINCH signal
+ caught.
+ + Delete the -l flag, and make -r work for multiple arguments.
+ Add the ex "recover[!] file" command.
+ + Switch into ex terminal mode and use the sex routines when
+ append/change/insert called from vi mode.
+ + Make ^F and ^B match historic practice. This required a fairly
+ extensive rework of the svi scrolling code.
+ + Cursor positioning in H, M, L, G (first non-blank for 1G) wasn't
+ being done correctly. Delete the SETLFNB flag. H, M, and L stay
+ logical movements (SETNNB) and G always moves to the first nonblank.
+ + System V uses "lines" and "cols", not "li" and "co", change as
+ necessary. Check termcap function returns for errors.
+ + Fix `<character> command to do start/end of line correction,
+ and to set line mode if starting and stopping at column 0.
+ + Fix bug in delete code where dropped core if deleted in character
+ mode to an empty line. (Rework the delete code for efficiency.)
+ + Give up on SunOS 4.1.X, and use "cc" instead of /usr/5bin/cc.
+ + Protect ex_getline routine from interrupted system calls (if
+ possible, set SA_RESTART on SIGALRM, too).
+ + Fix leftright scrolling bug, when moving to a shorter line.
+ + Do validity checking on the copy, move, t command target line
+ numbers.
+ + Change for System V % pattern broke trailing flags for empty
+ replacement strings.
+ + Fix bug when RCM flags retained in the saved dot structure.
+ + Make the ex '=' command work for empty files.
+ + Fix bug where special_key array was being free'd (it's no longer
+ allocated).
+ + Matches cut in line mode only if the starting cursor is at or
+ before the first nonblank in its line, and the ending cursor is
+ at or after the last nonblank in its line.
+ + Add the :wn command, so you can write a file and switch to a new
+ file in one command.
+ + Allow only a single key as an argument to :viusage.
+ + New movement code broke filter/paragraph operations in empty
+ files ("!}date" in an empty file was dropping core).
+1.12 -> 1.14: Mon Apr 18 11:05:10 1994 (PUBLICLY AVAILABLE VERSION, 4.4BSD)
+ + Fix FILE structure leakage in the ex filter code.
+ + Rework suspend code for System V curses. Nvi has to do the
+ the work, there's no way to get curses to do it right.
+ + Revert SunOS 4.1.X ports to the distributed curses. There's
+ a bug in Sun's implementation that we can't live with.
+ + Quit immediately if row/column values are unreasonable.
+ + Fix the function keys to match vi historic behavior.
+ + Replace the echo/awk magic in the Makefile's with awk scripts.
+1.11 -> 1.12: Thu Apr 14 11:10:19 1994
+ + Fix bug where only the first vi key was checked for validity.
+ + Make 'R' continue to overwrite after a <carriage-return>.
+ + Only display the "no recovery" message once.
+ + Rework line backup code to restore the line to its previous
+ condition.
+ + Don't permit :q in a .exrc file or EXINIT variable.
+ + Fix wrapscan option bug where forward searches become backward
+ searches and do cursor correction accordingly.
+ + Change "dd" to move the cursor to the first non-blank on the line.
+ + Delete cursor attraction to the first non-blank, change non-blank
+ motions to set the most attractive cursor position instead.
+ + Fix 'r' substitute option to set the RE to the last RE, not the
+ last substitute RE.
+ + Fix 'c' and 'g' substitute options to always toggle, and fix
+ edcompatible option to not reset them.
+ + Display ex error messages in inverse video.
+ + Fix errorbells option to match historic practice.
+ + Delete fixed character display table in favor of table built based
+ on the current locale.
+ + Add ":set octal" option, that displays unknown characters as octal
+ values instead of the default hexadecimal.
+ + Make all command and text input modes interruptible.
+ + Fix ex input mode to display error messages immediately, instead
+ of waiting for the lines to be resolved.
+ + Fix bug where vi calling append could overwrite the command.
+ + Fix off-by-one in the ex print routine tab code.
+ + Fix incorrect ^D test in vi text input routines.
+ + Add autoindent support for ex text insert routines.
+ + Add System V substitute command replacement pattern semantics,
+ where '%' means the last replacement pattern.
+ + Fix bug that \ didn't escape newlines in ex commands.
+ + Regularize the names of special characters to CH_*.
+ + Change hex insert character from ^Vx<hex_char> to ^X<hex_char>
+ + Integrate System V style curses, so SunOS and Solaris ports can
+ use the native curses implementation.
+1.10 -> 1.11: Thu Mar 24 16:07:45 EST 1994 (PUBLICLY AVAILABLE VERSION)
+ + 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/ev b/usr.bin/vi/docs/ev
new file mode 100644
index 000000000000..144295a319f2
--- /dev/null
+++ b/usr.bin/vi/docs/ev
@@ -0,0 +1,55 @@
+# @(#)ev 8.4 (Berkeley) 4/29/94
+
+Ev: Vi: Result:
+<CK> <CK> (Cursor keys). Move around the file.
+
+Meta key commands:
+^A<#> <#>G Goto line #.
+^A$ G Goto the end of the file.
+^A/ / Prompt and execute a forward search.
+^A: : Prompt and execute an ex command.
+^A? ? Prompt and execute a backward search.
+^Ac y'<c> Copy to mark in line mode (or copy the current line).
+^AC y`<c> Copy to mark in character mode.
+^Ad d'<c> Delete to mark in line mode (or delete the current line).
+^AD d`<c> Delete to mark in character mode.
+^Aj J Join lines.
+^Am m<c> Mark the current cursor position.
+^AN N Repeat search in the reverse direction.
+^An ^A Search for the word under the cursor.
+^Ar u Redo a command.
+^Au u Undo a command.
+
+Single key commands:
+^B ^B Page up a screen.
+^C ^C Interrupt long-running commands.
+^D ^D Page down a half-screen.
+^E $ End of line.
+^F ^F Page down a screen.
+^G ^G File status/information.
+^H X Delete the character to the left of the cursor.
+^I (TAB)
+^J j Cursor down one line.
+^K k Cursor up one line.
+^L ^L Redraw the screen.
+^M (CR) ^M In insert mode, split the line at the current cursor,
+ creating a new line.
+ In overwrite mode, cursor down one line.
+^N n Repeat previous search, in previous direction.
+^O (UNUSED)
+^P p Paste the cut text at the cursor position.
+^Q (XON/XOFF)
+^R (UNUSED)
+^S (XON/XOFF)
+^T D Truncate the line at the cursor position.
+^U ^U Page up a half-screen.
+^V<c> ^V<c> Insert/overwrite with a literal next character.
+^W w Move forward one whitespace separated word.
+^X x Delete the current character.
+^Y (UNUSED)
+^Z ^Z Suspend.
+
+New ex mode commands:
+
+^A:set ov[erwrite] Toggle "insert" mode, so that input keys overwrite
+ the existing characters.
diff --git a/usr.bin/vi/docs/features b/usr.bin/vi/docs/features
new file mode 100644
index 000000000000..d410722db5d6
--- /dev/null
+++ b/usr.bin/vi/docs/features
@@ -0,0 +1,92 @@
+List of things that should be added at some point:
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
++ X11 interface.
+
++ Message catalogs.
+
++ 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.
+
++ Full editing capability on the : command line.
+
++ Rob Pike's sam RE's.
+
++ Filename completion. While on the subject of completion, it would be
+ nice to have the completion mechanism found in tcsh version >= 6.03.
+ For instance, the completion for the `:cd' command will be directories
+ only. The completion for the `:set' command will be all options not
+ set at that moment, and for `:set un' will be all options that are set
+ at that moment. The completion for `:< count' will be the flags.
+
+List of suggested features:
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
++ Add a "push" command that would push a file on the tags stack.
+ (Essentially make tags a special case of the stack, and make
+ the stack more general purpose.)
+
++ Make :script just run a command and edit the output, and :interactive,
+ which allows interactive shell session, instead of just the current
+ :script.
+
++ 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 tagging information to the man page so that users can display
+ the part of the man page that discusses the command in which they're
+ interested.
+
++ Add a zone option so that you can declare that top/bottom few lines
+ of the screen aren't filled except by accident, so that the text
+ you ask for is always concentrated in the center of the screen.
+
++ 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.
+
++ 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.
+
++ An option to turn on a ``quarter plane'' model so that you can
+ go as far to the right or down as you wish. The File or the
+ current line is only extended if you actually put down a char at
+ the new location. Very handy for ascii graphics and tables.
+
++ Some way of replacing the command bindings. For this to work
+ cleanly the notion of a command must be separate from that of a
+ key. (Simulate the Rand editor?)
+
++ Vertical splitting, so you can see files side by side.
+
++ Tracking. Two or more files are associated so that when one file
+ is scrolled up/down/left/right other files track by the same amount.
+ Tracking may be constrained such that two files only track vertically
+ or horizontally. This is relatively easy to implement.
+
++ A status file so that the next time invocation of the editor returns
+ to the same place, with the same number of windows etc. In case of
+ change of the screen size, reasonable defaults are used. For each
+ window size and location of the window, name of the file and position
+ in it, any tab settings, any other settings for the window (such as
+ insert/overwrite mode, auto indent etc). Last search RE and maybe
+ direction. If a file does not exist the next time you invoke the
+ editor, its window is left in the same place but with some default
+ message.
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/context b/usr.bin/vi/docs/internals/context
new file mode 100644
index 000000000000..139a1c3fdb41
--- /dev/null
+++ b/usr.bin/vi/docs/internals/context
@@ -0,0 +1,32 @@
+# @(#)context 8.5 (Berkeley) 7/23/94
+
+In historic vi, the previous context mark was always set:
+
+ex address:
+ any number, <question-mark>, <slash>, <dollar-sign>,
+ <single-quote>, <backslash>
+
+ex commands: undo, "z.", global, vglobal
+
+vi commands: (, ), {, }, %, [[, ]], ^]
+
+nvi adds the vi command ^T to this list.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+In historic vi, the previous context mark was set if the
+line changed:
+
+vi commands: '<mark>, G, H, L, M, z
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+In historic vi, the previous context mark was set if the
+line or column changed:
+
+vi commands: `<mark>, /, ?, N, n
+
+nvi adds the vi command ^A to this list.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+In historic vi, the previous context mark was set in non-visual
+mode for ^R and ^L if the line changed, but I have yet to figure
+out how the line could change.
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..9a7506ee2337
--- /dev/null
+++ b/usr.bin/vi/docs/internals/input
@@ -0,0 +1,350 @@
+# @(#)input 5.5 (Berkeley) 7/2/94
+
+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.
+7: Characters in executable buffers are remapped.
+8: Characters in executable buffers are not quoted.
+
+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.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+7: Characters in executable buffers are remapped.
+
+=== test file ===
+abcdefghijklmnnop
+ggg
+=== end test file ===
+
+:map g x
+2G"ay$1G@a
+
+ The output should be:
+
+=== output file ===
+defghijklmnnop
+ggg
+=== end output file ===
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+8: Characters in executable buffers are not quoted.
+
+=== test file ===
+iFOO^[
+
+=== end test file ===
+
+1G"ay$2G@a
+
+ The output should be:
+
+=== output file ===
+iFOO^[
+FOO
+=== end output file ===
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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/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 100755
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/ex/ex.c b/usr.bin/vi/ex/ex.c
new file mode 100644
index 000000000000..c0455a1f996a
--- /dev/null
+++ b/usr.bin/vi/ex/ex.c
@@ -0,0 +1,1866 @@
+/*-
+ * 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.c 8.155 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static void badlno __P((SCR *, recno_t));
+static __inline EXCMDLIST const *
+ ex_comm_search __P((char *, size_t));
+static int ep_line __P((SCR *, EXF *, MARK *, char **, size_t *, int *));
+static int ep_range __P((SCR *, EXF *, EXCMDARG *, char **, size_t *));
+
+/*
+ * ex --
+ * Read an ex command and execute it.
+ */
+int
+ex(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ enum input irval;
+ TEXT *tp;
+ u_int flags, saved_mode;
+ int eval;
+
+ if (ex_init(sp, ep))
+ return (1);
+
+ if (sp->s_refresh(sp, ep))
+ return (ex_end(sp));
+
+ /* If reading from a file, messages should have line info. */
+ 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_BACKSLASH | TXT_CNTRLD | TXT_CR | TXT_EXSUSPEND);
+
+ for (eval = 0;; ++sp->if_lno) {
+ /* Set the flags that the user can change. */
+ if (O_ISSET(sp, O_BEAUTIFY))
+ LF_SET(TXT_BEAUTIFY);
+ else
+ LF_CLR(TXT_BEAUTIFY);
+ if (O_ISSET(sp, O_PROMPT))
+ LF_SET(TXT_PROMPT);
+ else
+ LF_CLR(TXT_PROMPT);
+
+ /*
+ * Get the next command. Interrupt flag manipulation is
+ * safe because ex_icmd clears them all.
+ */
+ CLR_INTERRUPT(sp);
+ F_SET(sp, S_INTERRUPTIBLE);
+ irval = sp->s_get(sp, ep, sp->tiqp, ':', flags);
+ if (INTERRUPTED(sp)) {
+ (void)fputc('\n', stdout);
+ (void)fflush(stdout);
+ goto refresh;
+ }
+ switch (irval) {
+ case INP_OK:
+ break;
+ case INP_EOF:
+ case INP_ERR:
+ F_SET(sp, S_EXIT_FORCE);
+ /* FALLTHROUGH */
+ case INP_INTR:
+ goto ret;
+ }
+
+ /*
+ * If the user entered a carriage return, send ex_cmd()
+ * a separator -- it discards single newlines.
+ */
+ tp = sp->tiqp->cqh_first;
+ if (tp->len == 0) {
+ tp->len = 1;
+ tp->lb[0] = ' ';
+ }
+
+ saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
+ if (ex_icmd(sp, ep,
+ tp->lb, tp->len, 1) && !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;
+
+refresh: if (sp->s_refresh(sp, ep)) {
+ eval = 1;
+ break;
+ }
+ }
+ret: if (sp->if_name != NULL) {
+ FREE(sp->if_name, strlen(sp->if_name) + 1);
+ sp->if_name = NULL;
+ }
+ return (ex_end(sp) || eval);
+}
+
+/*
+ * ex_cfile --
+ * Execute ex commands from a file.
+ */
+int
+ex_cfile(sp, ep, filename, needsep)
+ SCR *sp;
+ EXF *ep;
+ char *filename;
+ int needsep;
+{
+ struct stat sb;
+ int fd, len, rval;
+ char *bp;
+
+ bp = NULL;
+ if ((fd = open(filename, O_RDONLY, 0)) < 0 || fstat(fd, &sb))
+ goto err;
+
+ /*
+ * XXX
+ * We'd like to test if the file is too big to malloc. Since we don't
+ * know what size or type off_t's or size_t's are, what the largest
+ * unsigned integral type is, or what random insanity the local C
+ * compiler will perpetrate, doing the comparison in a portable way
+ * is flatly impossible. Hope that malloc fails if the file is too
+ * large.
+ */
+ MALLOC(sp, bp, char *, (size_t)sb.st_size + 1);
+ if (bp == NULL)
+ goto err;
+
+ len = read(fd, bp, (int)sb.st_size);
+ if (len == -1 || len != sb.st_size) {
+ if (len != sb.st_size)
+ errno = EIO;
+err: rval = 1;
+ msgq(sp, M_SYSERR, filename);
+ } else {
+ bp[sb.st_size] = '\0'; /* XXX */
+
+ /*
+ * 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, needsep);
+ F_CLR(sp, S_VLITONLY);
+ free(sp->if_name);
+ sp->if_name = NULL;
+ }
+
+ /*
+ * !!!
+ * THE UNDERLYING EXF MAY HAVE CHANGED.
+ */
+ if (bp != NULL)
+ FREE(bp, sb.st_size);
+ if (fd >= 0)
+ (void)close(fd);
+ return (rval);
+}
+
+/*
+ * ex_icmd --
+ * Call ex_cmd() after turning off interruptible bits.
+ */
+int
+ex_icmd(sp, ep, cmd, len, needsep)
+ SCR *sp;
+ EXF *ep;
+ char *cmd;
+ size_t len;
+ int needsep;
+{
+ /*
+ * Ex goes through here for each vi :colon command and for each ex
+ * command, however, globally executed commands don't go through
+ * here, instead, they call ex_cmd directly. So, reset all of the
+ * interruptible flags now.
+ *
+ * !!!
+ * Previous versions of nvi cleared mapped characters on error. This
+ * feature was removed when users complained that it wasn't historic
+ * practice.
+ */
+ CLR_INTERRUPT(sp);
+ return (ex_cmd(sp, ep, cmd, len, needsep));
+}
+
+/* Special command structure for :s as a repeat substitution command. */
+static EXCMDLIST const cmd_subagain =
+ {"s", ex_subagain, E_ADDR2|E_NORC,
+ "s",
+ "[line [,line]] s [cgr] [count] [#lp]",
+ "repeat the last subsitution"};
+
+/* Special command structure for :d[flags]. */
+static EXCMDLIST const cmd_del2 =
+ {"delete", ex_delete, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "1bca1",
+ "[line [,line]] d[elete][flags] [buffer] [count] [flags]",
+ "delete lines from the file"};
+
+/*
+ * ex_cmd --
+ * Parse and execute a string containing ex commands.
+ */
+int
+ex_cmd(sp, ep, cmd, cmdlen, needsep)
+ SCR *sp;
+ EXF *ep;
+ char *cmd;
+ size_t cmdlen;
+ int needsep;
+{
+ enum { NOTSET, NEEDSEP_N, NEEDSEP_NR, NONE } sep;
+ EX_PRIVATE *exp;
+ EXCMDARG exc;
+ EXCMDLIST const *cp;
+ MARK cur;
+ recno_t lno, num;
+ size_t arg1_len, len, save_cmdlen;
+ long flagoff;
+ u_int saved_mode;
+ int blank, ch, cnt, delim, flags, namelen, nl;
+ int optnum, uselastcmd, tmp, vi_address;
+ char *arg1, *save_cmd, *p, *s, *t;
+
+ /* Init. */
+ nl = 0;
+ sep = needsep ? NOTSET : NONE;
+loop: if (nl) {
+ nl = 0;
+ ++sp->if_lno;
+ }
+ arg1 = NULL;
+ save_cmdlen = 0;
+
+ /* It's possible that we've been interrupted during a command. */
+ if (INTERRUPTED(sp))
+ return (0);
+
+ /* Skip <blank>s, empty lines. */
+ for (blank = 0; cmdlen > 0; ++cmd, --cmdlen)
+ if ((ch = *cmd) == '\n')
+ ++sp->if_lno;
+ else if (isblank(ch))
+ blank = 1;
+ else
+ break;
+
+ /*
+ * !!!
+ * Permit extra colons at the start of the line. Historically,
+ * ex/vi allowed a single extra one. It's simpler not to count.
+ * The stripping is done here because, historically, any command
+ * could have preceding colons, e.g. ":g/pattern/:p" worked.
+ */
+ if (cmdlen != 0 && ch == ':') {
+ if (sep == NOTSET)
+ sep = NEEDSEP_N;
+ while (--cmdlen > 0 && (ch = *++cmd) == ':');
+ }
+
+ /*
+ * Command lines that start with a double-quote are comments.
+ *
+ * !!!
+ * Historically, there was no escape or delimiter for a comment,
+ * e.g. :"foo|set was a single comment and nothing was output.
+ * Since nvi permits users to escape <newline> characters into
+ * command lines, we have to check for that case.
+ */
+ if (cmdlen != 0 && ch == '"') {
+ while (--cmdlen > 0 && *++cmd != '\n');
+ if (*cmd == '\n') {
+ nl = 1;
+ ++cmd;
+ --cmdlen;
+ }
+ goto loop;
+ }
+
+ /* Skip whitespace. */
+ for (; cmdlen > 0; ++cmd, --cmdlen) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+
+ /*
+ * The last point at which an empty line can mean do nothing.
+ *
+ * !!!
+ * Historically, in ex mode, lines containing only <blank> characters
+ * were the same as a single <carriage-return>, i.e. a default command.
+ * In vi mode, they were ignored.
+ *
+ * In .exrc files this was a serious annoyance, as vi kept trying to
+ * treat them as print commands. We ignore backward compatibility in
+ * this case, and discard lines containing only <blank> characters from
+ * .exrc files.
+ */
+ if (cmdlen == 0 && (!IN_EX_MODE(sp) || ep == NULL || !blank))
+ return (0);
+
+ /* Initialize the structure passed to underlying functions. */
+ memset(&exc, 0, sizeof(EXCMDARG));
+ exp = EXP(sp);
+ if (argv_init(sp, ep, &exc))
+ goto err;
+
+ /*
+ * Check to see if this is a command for which we may want to output
+ * a \r separator instead of a \n. (The command :1<CR> puts out a \n,
+ * but the command :<CR> puts out a \r.) If the line is empty except
+ * for <blank>s, <carriage-return> or <eof>, we'll probably want to
+ * output \r. I don't think there's any way to get <blank> characters
+ * *after* the command character, but this is the ex parser, and I've
+ * been wrong before.
+ */
+ if (sep == NOTSET)
+ sep = cmdlen == 0 || cmdlen == 1 && cmd[0] == '\004' ?
+ NEEDSEP_NR : NEEDSEP_N;
+
+ /* Parse command addresses. */
+ if (ep_range(sp, ep, &exc, &cmd, &cmdlen))
+ goto err;
+
+ /* Skip whitespace. */
+ for (; cmdlen > 0; ++cmd, --cmdlen) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+
+ /*
+ * If no command, ex does the last specified of p, l, or #, and vi
+ * moves to the line. Otherwise, determine the length of the command
+ * name by looking for the first non-alphabetic character. (There
+ * are a few non-alphabetic characters in command names, but they're
+ * all single character commands.) This isn't a great test, because
+ * it means that, for the command ":e +cut.c file", we'll report that
+ * the command "cut" wasn't known. However, it makes ":e+35 file" work
+ * correctly.
+ *
+ * !!!
+ * Historically, lines with multiple adjacent (or <blank> separated)
+ * command separators were very strange. For example, the command
+ * |||<carriage-return>, when the cursor was on line 1, displayed
+ * lines 2, 3 and 5 of the file. In addition, the command " | "
+ * would only display the line after the next line, instead of the
+ * next two lines. No ideas why. It worked reasonably when executed
+ * from vi mode, and displayed lines 2, 3, and 4, so we do a default
+ * command for each separator.
+ */
+#define SINGLE_CHAR_COMMANDS "\004!#&*<=>@~"
+ if (cmdlen != 0 && cmd[0] != '|' && cmd[0] != '\n') {
+ if (strchr(SINGLE_CHAR_COMMANDS, *cmd)) {
+ p = cmd;
+ ++cmd;
+ --cmdlen;
+ namelen = 1;
+ } else {
+ for (p = cmd; cmdlen > 0; --cmdlen, ++cmd)
+ if (!isalpha(*cmd))
+ break;
+ if ((namelen = cmd - p) == 0) {
+ msgq(sp, M_ERR, "Unknown command name");
+ goto err;
+ }
+ }
+
+ /*
+ * !!!
+ * Historic vi permitted flags to immediately follow any
+ * subset of the 'delete' command, but then did not permit
+ * further arguments (flag, buffer, count). Make it work.
+ * Permit further arguments for the few shreds of dignity
+ * it offers.
+ *
+ * !!!
+ * Note, adding commands that start with 'd', and match
+ * "delete" up to a l, p, +, - or # character can break
+ * this code.
+ */
+ if (p[0] == 'd') {
+ for (s = p,
+ t = cmds[C_DELETE].name; *s == *t; ++s, ++t);
+ if (s[0] == 'l' || s[0] == 'p' ||
+ s[0] == '+' || s[0] == '-' || s[0] == '#') {
+ len = (cmd - p) - (s - p);
+ cmd -= len;
+ cmdlen += len;
+ cp = &cmd_del2;
+ goto skip;
+ }
+ }
+
+ /*
+ * Search the table for the command.
+ *
+ * !!!
+ * Historic vi permitted the mark to immediately follow the
+ * 'k' in the 'k' command. Make it work.
+ *
+ * !!!
+ * Historic vi permitted pretty much anything to follow the
+ * substitute command, e.g. "s/e/E/|s|sgc3p" was fine. Make
+ * the command "sgc" work.
+ */
+ if ((cp = ex_comm_search(p, namelen)) == NULL)
+ switch (p[0]) {
+ case 's':
+ cmd -= namelen - 1;
+ cmdlen += namelen - 1;
+ cp = &cmd_subagain;
+ break;
+ case 'k':
+ if (p[1] && !p[2]) {
+ cmd -= namelen - 1;
+ cmdlen += namelen - 1;
+ cp = &cmds[C_K];
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ msgq(sp, M_ERR,
+ "The %.*s command is unknown", namelen, p);
+ goto err;
+ }
+
+ /* Some commands are either not implemented or turned off. */
+skip: if (F_ISSET(cp, E_NOPERM)) {
+ msgq(sp, M_ERR,
+ "The %s command is not currently supported",
+ cp->name);
+ goto err;
+ }
+
+ /* Some commands aren't okay in globals. */
+ if (F_ISSET(sp, S_GLOBAL) && F_ISSET(cp, E_NOGLOBAL)) {
+ msgq(sp, M_ERR,
+ "The %s command can't be used as part of a global command",
+ cp->name);
+ goto err;
+ }
+
+ /*
+ * Multiple < and > characters; another "feature". Note,
+ * The string passed to the underlying function may not be
+ * nul terminated in this case.
+ */
+ if ((cp == &cmds[C_SHIFTL] && *p == '<') ||
+ (cp == &cmds[C_SHIFTR] && *p == '>')) {
+ for (ch = *p; cmdlen > 0; --cmdlen, ++cmd)
+ if (*cmd != ch)
+ break;
+ if (argv_exp0(sp, ep, &exc, p, cmd - p))
+ goto err;
+ }
+
+ /*
+ * The visual command has a different syntax when called
+ * from ex than when called from a vi colon command. FMH.
+ */
+ if (cp == &cmds[C_VISUAL_EX] && IN_VI_MODE(sp))
+ cp = &cmds[C_VISUAL_VI];
+
+ /* Set the format style flags for the next command. */
+ if (cp == &cmds[C_HASH])
+ exp->fdef = E_F_HASH;
+ else if (cp == &cmds[C_LIST])
+ exp->fdef = E_F_LIST;
+ else if (cp == &cmds[C_PRINT])
+ exp->fdef = E_F_PRINT;
+ uselastcmd = 0;
+ } else {
+ /* Print is the default command. */
+ cp = &cmds[C_PRINT];
+
+ /* Set the saved format flags. */
+ F_SET(&exc, exp->fdef);
+
+ /*
+ * !!!
+ * If no address was specified, and it's not a global command,
+ * we up the address by one. (I have not an idea why global
+ * commands are exempted, but it's (ahem) historic practice.
+ */
+ if (exc.addrcnt == 0 && !F_ISSET(sp, S_GLOBAL)) {
+ exc.addrcnt = 1;
+ exc.addr1.lno = sp->lno + 1;
+ exc.addr1.cno = sp->cno;
+ }
+
+ uselastcmd = 1;
+ }
+
+ /*
+ * !!!
+ * Historically, the number option applied to both ex and vi. One
+ * strangeness was that ex didn't switch display formats until a
+ * command was entered, e.g. <CR>'s after the set didn't change to
+ * the new format, but :1p would.
+ */
+ if (O_ISSET(sp, O_NUMBER)) {
+ optnum = 1;
+ F_SET(&exc, E_F_HASH);
+ } else
+ optnum = 0;
+
+ /* Initialize local flags to the command flags. */
+ LF_INIT(cp->flags);
+
+ /*
+ * File state must be checked throughout this code, because it is
+ * 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. 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 have already been read in",
+ cp->name);
+ goto err;
+ }
+
+ /*
+ * There are three normal termination cases for an ex command. They
+ * are the end of the string (cmdlen), or unescaped (by literal next
+ * characters) newline or '|' characters. As we're past any addresses,
+ * we can now determine how long the command is, so we don't have to
+ * look for all the possible terminations. There are three exciting
+ * special cases:
+ *
+ * 1: The bang, global, vglobal and the filter versions of the read and
+ * write commands are delimited by newlines (they can contain shell
+ * pipes).
+ * 2: The ex, edit, next and visual in vi mode commands all take ex
+ * commands as their first arguments.
+ * 3: The substitute command takes an RE as its first argument, and
+ * wants it to be specially delimited.
+ *
+ * Historically, '|' characters in the first argument of the ex, edit,
+ * next, vi visual, and substitute commands didn't delimit the command.
+ * And, in the filter cases for read and write, and the bang, global
+ * and vglobal commands, they did not delimit the command at all.
+ *
+ * For example, the following commands were legal:
+ *
+ * :edit +25|s/abc/ABC/ file.c
+ * :substitute s/|/PIPE/
+ * :read !spell % | columnate
+ * :global/pattern/p|l
+ *
+ * It's not quite as simple as it sounds, however. The command:
+ *
+ * :substitute s/a/b/|s/c/d|set
+ *
+ * was also legal, i.e. the historic ex parser (using the word loosely,
+ * since "parser" implies some regularity) delimited the RE's based on
+ * its delimiter and not anything so irretrievably vulgar as a command
+ * syntax.
+ *
+ * One thing that makes this easier is that we can ignore most of the
+ * command termination conditions for the commands that want to take
+ * the command up to the next newline. None of them are legal in .exrc
+ * files, so if we're here, we only dealing with a single line, and we
+ * can just eat it.
+ *
+ * Anyhow, the following code makes this all work. First, for the
+ * special cases we move past their special argument(s). Then, we
+ * do normal command processing on whatever is left. Barf-O-Rama.
+ */
+ arg1_len = 0;
+ save_cmd = cmd;
+ if (cp == &cmds[C_EDIT] || cp == &cmds[C_EX] ||
+ cp == &cmds[C_NEXT] || cp == &cmds[C_VISUAL_VI]) {
+ /*
+ * Move to the next non-whitespace character. A '!'
+ * immediately following the command is eaten as a
+ * force flag.
+ */
+ if (cmdlen > 0 && *cmd == '!') {
+ ++cmd;
+ --cmdlen;
+ F_SET(&exc, E_FORCE);
+
+ /* Reset, don't reparse. */
+ save_cmd = cmd;
+ }
+ for (tmp = 0; cmdlen > 0; --cmdlen, ++cmd)
+ if (!isblank(*cmd))
+ break;
+ /*
+ * QUOTING NOTE:
+ *
+ * The historic implementation ignored all escape characters
+ * so there was no way to put a space or newline into the +cmd
+ * field. We do a simplistic job of fixing it by moving to the
+ * first whitespace character that isn't escaped by a literal
+ * next character. The literal next characters are stripped
+ * as they're no longer useful.
+ */
+ if (cmdlen > 0 && *cmd == '+') {
+ ++cmd;
+ --cmdlen;
+ for (arg1 = p = cmd; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ --cmdlen;
+ ch = *++cmd;
+ } else if (isblank(ch))
+ break;
+ *p++ = ch;
+ }
+ arg1_len = cmd - arg1;
+
+ /* Reset, so the first argument isn't reparsed. */
+ save_cmd = cmd;
+ }
+ } else if (cp == &cmds[C_BANG] ||
+ cp == &cmds[C_GLOBAL] || cp == &cmds[C_VGLOBAL]) {
+ cmd += cmdlen;
+ cmdlen = 0;
+ } else if (cp == &cmds[C_READ] || cp == &cmds[C_WRITE]) {
+ /*
+ * Move to the next character. If it's a '!', it's a filter
+ * command and we want to eat it all, otherwise, we're done.
+ */
+ for (; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+ if (cmdlen > 0 && ch == '!') {
+ cmd += cmdlen;
+ cmdlen = 0;
+ }
+ } else if (cp == &cmds[C_SUBSTITUTE]) {
+ /*
+ * Move to the next non-whitespace character, we'll use it as
+ * the delimiter. If the character isn't an alphanumeric or
+ * a '|', it's the delimiter, so parse it. Otherwise, we're
+ * into something like ":s g", so use the special substitute
+ * command.
+ */
+ for (; cmdlen > 0; --cmdlen, ++cmd)
+ if (!isblank(cmd[0]))
+ break;
+
+ if (isalnum(cmd[0]) || cmd[0] == '|')
+ cp = &cmd_subagain;
+ else if (cmdlen > 0) {
+ /*
+ * QUOTING NOTE:
+ *
+ * Backslashes quote delimiter characters for RE's.
+ * The backslashes are NOT removed since they'll be
+ * used by the RE code. Move to the third delimiter
+ * that's not escaped (or the end of the command).
+ */
+ delim = *cmd;
+ ++cmd;
+ --cmdlen;
+ for (cnt = 2; cmdlen > 0 && cnt; --cmdlen, ++cmd)
+ if (cmd[0] == '\\' && cmdlen > 1) {
+ ++cmd;
+ --cmdlen;
+ } else if (cmd[0] == delim)
+ --cnt;
+ }
+ }
+ /*
+ * Use normal quoting and termination rules to find the end of this
+ * command.
+ *
+ * QUOTING NOTE:
+ *
+ * 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
+ * delimiters. Literal next quote characters in front of the newlines,
+ * '|' characters or literal next characters are stripped as as they're
+ * no longer useful.
+ */
+ vi_address = cmdlen != 0 && cmd[0] != '\n';
+ for (p = cmd, cnt = 0; cmdlen > 0; --cmdlen, ++cmd) {
+ 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;
+ ch = tmp;
+ }
+ } else if (ch == '\n' || ch == '|') {
+ if (ch == '\n')
+ nl = 1;
+ --cmdlen;
+ break;
+ }
+ *p++ = ch;
+ }
+
+ /*
+ * Save off the next command information, go back to the
+ * original start of the command.
+ */
+ p = cmd + 1;
+ cmd = save_cmd;
+ save_cmd = p;
+ save_cmdlen = cmdlen;
+ cmdlen = ((save_cmd - cmd) - 1) - cnt;
+
+ /*
+ * !!!
+ * The "set tags" command historically used a backslash, not the
+ * user's literal next character, to escape whitespace. Handle
+ * it here instead of complicating the argv_exp3() code. Note,
+ * this isn't a particularly complex trap, and if backslashes were
+ * legal in set commands, this would have to be much more complicated.
+ */
+ if (cp == &cmds[C_SET])
+ for (p = cmd, len = cmdlen; len > 0; --len, ++p)
+ if (*p == '\\')
+ *p = CH_LITERAL;
+
+ /*
+ * Set the default addresses. It's an error to specify an address for
+ * a command that doesn't take them. If two addresses are specified
+ * for a command that only takes one, lose the first one. Two special
+ * cases here, some commands take 0 or 2 addresses. For most of them
+ * (the E_ADDR2_ALL flag), 0 defaults to the entire file. For one
+ * (the `!' command, the E_ADDR2_NONE flag), 0 defaults to no lines.
+ *
+ * Also, if the file is empty, some commands want to use an address of
+ * 0, i.e. the entire file is 0 to 0, and the default first address is
+ * 0. Otherwise, an entire file is 1 to N and the default line is 1.
+ * Note, we also add the E_ZERO flag to the command flags, for the case
+ * where the 0 address is only valid if it's a default address.
+ *
+ * Also, set a flag if we set the default addresses. Some commands
+ * (ex: z) care if the user specified an address of if we just used
+ * the current cursor.
+ */
+ switch (LF_ISSET(E_ADDR1|E_ADDR2|E_ADDR2_ALL|E_ADDR2_NONE)) {
+ case E_ADDR1: /* One address: */
+ switch (exc.addrcnt) {
+ case 0: /* Default cursor/empty file. */
+ exc.addrcnt = 1;
+ F_SET(&exc, E_ADDRDEF);
+ if (LF_ISSET(E_ZERODEF)) {
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (lno == 0) {
+ exc.addr1.lno = 0;
+ LF_SET(E_ZERO);
+ } else
+ exc.addr1.lno = sp->lno;
+ } else
+ exc.addr1.lno = sp->lno;
+ exc.addr1.cno = sp->cno;
+ break;
+ case 1:
+ break;
+ case 2: /* Lose the first address. */
+ exc.addrcnt = 1;
+ exc.addr1 = exc.addr2;
+ }
+ break;
+ case E_ADDR2_NONE: /* Zero/two addresses: */
+ if (exc.addrcnt == 0) /* Default to nothing. */
+ break;
+ goto two;
+ case E_ADDR2_ALL: /* Zero/two addresses: */
+ if (exc.addrcnt == 0) { /* Default entire/empty file. */
+ exc.addrcnt = 2;
+ F_SET(&exc, E_ADDRDEF);
+ if (file_lline(sp, ep, &exc.addr2.lno))
+ goto err;
+ if (LF_ISSET(E_ZERODEF) && exc.addr2.lno == 0) {
+ exc.addr1.lno = 0;
+ LF_SET(E_ZERO);
+ } else
+ exc.addr1.lno = 1;
+ exc.addr1.cno = exc.addr2.cno = 0;
+ F_SET(&exc, E_ADDR2_ALL);
+ break;
+ }
+ /* FALLTHROUGH */
+ case E_ADDR2: /* Two addresses: */
+two: switch (exc.addrcnt) {
+ case 0: /* Default cursor/empty file. */
+ exc.addrcnt = 2;
+ F_SET(&exc, E_ADDRDEF);
+ if (LF_ISSET(E_ZERODEF) && sp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (lno == 0) {
+ exc.addr1.lno = exc.addr2.lno = 0;
+ LF_SET(E_ZERO);
+ } else
+ exc.addr1.lno = exc.addr2.lno = sp->lno;
+ } else
+ exc.addr1.lno = exc.addr2.lno = sp->lno;
+ exc.addr1.cno = exc.addr2.cno = sp->cno;
+ break;
+ case 1: /* Default to first address. */
+ exc.addrcnt = 2;
+ exc.addr2 = exc.addr1;
+ break;
+ case 2:
+ break;
+ }
+ break;
+ default:
+ if (exc.addrcnt) /* Error. */
+ goto usage;
+ }
+
+ /*
+ * !!!
+ * The ^D scroll command historically scrolled the value of the scroll
+ * option 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 + O_VAL(sp, O_SCROLL);
+ 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) {
+ /*
+ * The force flag is sensitive to leading whitespace, i.e.
+ * "next !" is different from "next!". Handle it before
+ * skipping leading <blank>s.
+ */
+ if (*p == '!') {
+ if (cmdlen > 0 && *cmd == '!') {
+ ++cmd;
+ --cmdlen;
+ F_SET(&exc, E_FORCE);
+ }
+ continue;
+ }
+
+ /* Skip leading <blank>s. */
+ for (; cmdlen > 0; --cmdlen, ++cmd)
+ if (!isblank(*cmd))
+ break;
+
+ /*
+ * Quit when reach the end of the command, unless it's a
+ * command that does its own parsing, in which case we want
+ * to build a reasonable argv for it. This code guarantees
+ * that there will be an argv when the function gets called,
+ * so the correct test is for a length of 0, not for the
+ * argc > 0. Since '!' can precede commands that do their
+ * own parsing, we have to have already handled it.
+ */
+ if (cmdlen == 0 && *p != 'S' && *p != 's')
+ break;
+
+ switch (*p) {
+ case '1': /* +, -, #, l, p */
+ /*
+ * !!!
+ * Historically, some flags were ignored depending
+ * on where they occurred in the command line. For
+ * example, in the command, ":3+++p--#", historic vi
+ * acted on the '#' flag, but ignored the '-' flags.
+ * It's unambiguous what the flags mean, so we just
+ * handle them regardless of the stupidity of their
+ * location.
+ */
+ for (; cmdlen; --cmdlen, ++cmd)
+ switch (*cmd) {
+ case '+':
+ ++flagoff;
+ break;
+ case '-':
+ --flagoff;
+ break;
+ case '#':
+ optnum = 0;
+ F_SET(&exc, E_F_HASH);
+ exp->fdef |= E_F_HASH;
+ break;
+ case 'l':
+ F_SET(&exc, E_F_LIST);
+ exp->fdef |= E_F_LIST;
+ break;
+ case 'p':
+ F_SET(&exc, E_F_PRINT);
+ exp->fdef |= E_F_PRINT;
+ break;
+ default:
+ goto end1;
+ }
+end1: break;
+ case '2': /* -, ., +, ^ */
+ case '3': /* -, ., +, ^, = */
+ for (; cmdlen; --cmdlen, ++cmd)
+ switch (*cmd) {
+ case '-':
+ F_SET(&exc, E_F_DASH);
+ break;
+ case '.':
+ F_SET(&exc, E_F_DOT);
+ break;
+ case '+':
+ F_SET(&exc, E_F_PLUS);
+ break;
+ case '^':
+ F_SET(&exc, E_F_CARAT);
+ break;
+ case '=':
+ if (*p == '3') {
+ F_SET(&exc, E_F_EQUAL);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ goto end2;
+ }
+end2: break;
+ case 'b': /* buffer */
+ /*
+ * !!!
+ * Historically, "d #" was a delete with a flag, not a
+ * delete into the '#' buffer. If the current command
+ * permits a flag, don't use one as a buffer. However,
+ * the 'l' and 'p' flags were legal buffer names in the
+ * historic ex, and were used as buffers, not flags.
+ */
+ if ((cmd[0] == '+' || cmd[0] == '-' || cmd[0] == '#') &&
+ strchr(p, '1') != NULL)
+ break;
+ /*
+ * !!!
+ * Digits can't be buffer names in ex commands, or the
+ * command "d2" would be a delete into buffer '2', and
+ * not a two-line deletion.
+ */
+ if (!isdigit(cmd[0])) {
+ exc.buffer = *cmd;
+ ++cmd;
+ --cmdlen;
+ F_SET(&exc, E_BUFFER);
+ }
+ 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;
+ }
+ cmdlen -= (t - cmd);
+ cmd = t;
+ /*
+ * Count as address offsets occur in commands taking
+ * two addresses. Historic vi practice was to use
+ * the count as an offset from the *second* address.
+ *
+ * Set a count flag; some underlying commands (see
+ * join) do different things with counts than with
+ * line addresses.
+ */
+ if (*p == 'a') {
+ exc.addr1 = exc.addr2;
+ exc.addr2.lno = exc.addr1.lno + lno - 1;
+ } else
+ exc.count = lno;
+ F_SET(&exc, E_COUNT);
+ break;
+ case 'f': /* file */
+ if (argv_exp2(sp, ep,
+ &exc, cmd, cmdlen, cp == &cmds[C_BANG]))
+ goto err;
+ goto countchk;
+ case 'l': /* line */
+ if (ep_line(sp, ep, &cur, &cmd, &cmdlen, &tmp))
+ goto err;
+ /* Line specifications are always required. */
+ if (!tmp) {
+ msgq(sp, M_ERR,
+ "%s: bad line specification", cmd);
+ goto err;
+ }
+ /* The line must exist for these commands. */
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (cur.lno > lno) {
+ badlno(sp, lno);
+ goto err;
+ }
+ exc.lineno = cur.lno;
+ break;
+ case 'S': /* string, file exp. */
+ if (argv_exp1(sp, ep,
+ &exc, cmd, cmdlen, cp == &cmds[C_BANG]))
+ goto err;
+ goto addr2;
+ case 's': /* string */
+ if (argv_exp0(sp, ep, &exc, cmd, cmdlen))
+ goto err;
+ goto addr2;
+ case 'W': /* word string */
+ /*
+ * QUOTING NOTE:
+ *
+ * Literal next characters escape the following
+ * character. Quoting characters are stripped
+ * here since they are no longer useful.
+ *
+ * First there was the word.
+ */
+ for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ --cmdlen;
+ *p++ = *++cmd;
+ } else if (isblank(ch)) {
+ ++cmd;
+ --cmdlen;
+ break;
+ } else
+ *p++ = ch;
+ }
+ if (argv_exp0(sp, ep, &exc, t, p - t))
+ goto err;
+
+ /* Delete intervening whitespace. */
+ for (; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+ if (cmdlen == 0)
+ goto usage;
+
+ /* Followed by the string. */
+ 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;
+ case 'w': /* word */
+ if (argv_exp3(sp, ep, &exc, cmd, cmdlen))
+ goto err;
+countchk: if (*++p != 'N') { /* N */
+ /*
+ * If a number is specified, must either be
+ * 0 or that number, if optional, and that
+ * number, if required.
+ */
+ num = *p - '0';
+ if ((*++p != 'o' || exp->argsoff != 0) &&
+ exp->argsoff != num)
+ goto usage;
+ }
+ goto addr2;
+ default:
+ msgq(sp, M_ERR,
+ "Internal syntax table error (%s: %c)",
+ cp->name, *p);
+ }
+ }
+
+ /* Skip trailing whitespace. */
+ for (; cmdlen; --cmdlen) {
+ ch = *cmd++;
+ if (!isblank(ch))
+ break;
+ }
+
+ /*
+ * There shouldn't be anything left, and no more required
+ * fields, i.e neither 'l' or 'r' in the syntax string.
+ */
+ if (cmdlen || strpbrk(p, "lr")) {
+usage: msgq(sp, M_ERR, "Usage: %s", cp->usage);
+ goto err;
+ }
+
+ /* Verify that the addresses are legal. */
+addr2: switch (exc.addrcnt) {
+ case 2:
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ /*
+ * Historic ex/vi permitted commands with counts to go past
+ * EOF. So, for example, if the file only had 5 lines, the
+ * ex command "1,6>" would fail, but the command ">300"
+ * would succeed. Since we don't want to have to make all
+ * of the underlying commands handle random line numbers,
+ * fix it here.
+ */
+ if (exc.addr2.lno > lno)
+ if (F_ISSET(&exc, E_COUNT))
+ exc.addr2.lno = lno;
+ else {
+ badlno(sp, lno);
+ goto err;
+ }
+ /* FALLTHROUGH */
+ case 1:
+ num = exc.addr1.lno;
+ /*
+ * If it's a "default vi command", zero is okay. Historic
+ * vi allowed this, note, it's also the hack that allows
+ * "vi +100 nonexistent_file" to work.
+ */
+ if (num == 0 && (IN_EX_MODE(sp) || uselastcmd != 1) &&
+ !LF_ISSET(E_ZERO)) {
+ msgq(sp, M_ERR,
+ "The %s command doesn't permit an address of 0",
+ cp->name);
+ goto err;
+ }
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (num > lno) {
+ badlno(sp, lno);
+ goto err;
+ }
+ break;
+ }
+
+ /*
+ * If doing a default command and there's nothing left on the line,
+ * vi just moves to the line. For example, ":3" and ":'a,'b" just
+ * move to line 3 and line 'b, respectively, but ":3|" prints line 3.
+ *
+ * !!!
+ * This is done before the absolute mark gets set; historically,
+ * "/a/,/b/" did NOT set vi's absolute mark, but "/a/,/b/d" did.
+ */
+ if (IN_VI_MODE(sp) && uselastcmd && vi_address == 0) {
+ switch (exc.addrcnt) {
+ case 2:
+ sp->lno = exc.addr2.lno ? exc.addr2.lno : 1;
+ sp->cno = exc.addr2.cno;
+ break;
+ case 1:
+ sp->lno = exc.addr1.lno ? exc.addr1.lno : 1;
+ sp->cno = exc.addr1.cno;
+ break;
+ }
+ cmd = save_cmd;
+ cmdlen = save_cmdlen;
+ goto loop;
+ }
+
+ /*
+ * Set the absolute mark -- we have to set it for vi here, in case
+ * it's a compound command, e.g. ":5p|6" should set the absolute
+ * mark for vi.
+ */
+ if (F_ISSET(exp, EX_ABSMARK)) {
+ cur.lno = sp->lno;
+ cur.cno = sp->cno;
+ F_CLR(exp, EX_ABSMARK);
+ if (mark_set(sp, ep, ABSMARK1, &cur, 1))
+ goto err;
+ }
+
+ /* Final setup for the command. */
+ exc.cmd = cp;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "ex_cmd: %s", exc.cmd->name);
+ if (exc.addrcnt > 0) {
+ TRACE(sp, "\taddr1 %d", exc.addr1.lno);
+ if (exc.addrcnt > 1)
+ TRACE(sp, " addr2: %d", exc.addr2.lno);
+ TRACE(sp, "\n");
+ }
+ if (exc.lineno)
+ TRACE(sp, "\tlineno %d", exc.lineno);
+ if (exc.flags)
+ TRACE(sp, "\tflags %0x", exc.flags);
+ if (F_ISSET(&exc, E_BUFFER))
+ TRACE(sp, "\tbuffer %c", exc.buffer);
+ TRACE(sp, "\n");
+ if (exc.argc) {
+ for (cnt = 0; cnt < exc.argc; ++cnt)
+ TRACE(sp, "\targ %d: {%s}", cnt, exc.argv[cnt]);
+ TRACE(sp, "\n");
+ }
+#endif
+ /* Clear autoprint flag. */
+ F_CLR(exp, EX_AUTOPRINT);
+
+ /* Increment the command count if not called from vi. */
+ if (IN_EX_MODE(sp))
+ ++sp->ccnt;
+
+ /*
+ * If file state available, and not doing a global command,
+ * log the start of an action.
+ */
+ if (ep != NULL && !F_ISSET(sp, S_GLOBAL))
+ (void)log_cursor(sp, ep);
+
+ /*
+ * !!!
+ * There are two special commands for the purposes of this code: the
+ * default command (<carriage-return>) or the scrolling commands (^D
+ * and <EOF>) as the first non-<blank> characters in the line.
+ *
+ * If this is the first command in the command line, we received the
+ * command from the ex command loop and we're talking to a tty, and
+ * and there's nothing else on the command line, and it's one of the
+ * special commands, we erase the prompt character with a '\r'. Else,
+ * we put out a newline character to separate the command from the
+ * output from the command. It's OK if vi calls us -- we won't be in
+ * ex mode so we'll do nothing.
+ *
+ * !!!
+ * Historically, ex only put out a \r, so, if the displayed line was
+ * only a single character long, and <eof> was represented as ^D, the
+ * output wouldn't overwrite the user's input. Sex currently doesn't
+ * display the <eof> character if it's going to be the scroll command,
+ * i.e. if it's the first non-<blank> character in the line. If sex
+ * is changed to run in cooked mode, i.e. <eof> is displayed, this code
+ * will have to overwrite it. We also don't treat lines with extra
+ * prompt characters as empty -- it's not worth the effort since we'd
+ * have to overwrite some indeterminate number of columns with spaces
+ * to clean up. For now, put out enough spaces to overwrite the prompt.
+ */
+ if (sep != NONE) {
+ if (ep != NULL &&
+ IN_EX_MODE(sp) && F_ISSET(sp->gp, G_STDIN_TTY))
+ if (sep == NEEDSEP_NR &&
+ (uselastcmd || cp == &cmds[C_SCROLL])) {
+ (void)putchar('\r');
+ for (len = KEY_LEN(sp, PROMPTCHAR); len--;)
+ (void)putchar(' ');
+ (void)putchar('\r');
+ } else
+ (void)putchar('\n');
+ sep = NONE;
+ }
+
+ /* Save the current mode. */
+ saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
+
+ /* Do the command. */
+ if (cp->fn(sp, ep, &exc))
+ goto err;
+
+#ifdef DEBUG
+ /* Make sure no function left the temporary space locked. */
+ if (F_ISSET(sp->gp, G_TMP_INUSE)) {
+ F_CLR(sp->gp, G_TMP_INUSE);
+ msgq(sp, M_ERR, "Error: ex: temporary buffer not released");
+ goto err;
+ }
+#endif
+ if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE)) {
+ /*
+ * Only here if the mode of the underlying file changed, e.g.
+ * the user switched files or is exiting. Two things that we
+ * might have to save: first, any "+cmd" field set up for an
+ * ex/edit command will have to be saved for later, also, any
+ * part of the current ex command that hasn't been executed
+ * yet. For example:
+ *
+ * :edit +25 file.c|s/abc/ABC/|1
+ *
+ * !!!
+ * The historic vi just hung, of course; nvi handles it by
+ * pushing the keys onto the tty queue. Since the commands
+ * are intended as ex commands, add additional characters
+ * to make it all work if we're switching modes to vi. Also,
+ * + commands were oriented to the last line in the file,
+ * historically, make the cursor start out there.
+ *
+ * For the fun of it, if you want to see if a vi clone got the
+ * ex argument parsing right, try:
+ *
+ * echo 'foo|bar' > file1; echo 'foo/bar' > file2;
+ * vi
+ * :edit +1|s/|/PIPE/|w file1| e file2|1 | s/\//SLASH/|wq
+ */
+ if (arg1_len == 0 && save_cmdlen == 0)
+ return (0);
+ if (term_push(sp, "\n", 1, 0))
+ goto err;
+ if (save_cmdlen != 0)
+ if (term_push(sp, save_cmd, save_cmdlen, 0))
+ goto err;
+ if (arg1 != NULL) {
+ if (IN_VI_MODE(sp) && save_cmdlen != 0 &&
+ term_push(sp, "|", 1, 0))
+ goto err;
+ if (term_push(sp, arg1, arg1_len, 0))
+ goto err;
+ if (file_lline(sp, ep, &sp->frp->lno))
+ goto err;
+ F_SET(sp->frp, FR_CURSORSET);
+ }
+ if (IN_VI_MODE(sp) && term_push(sp, ":", 1, 0))
+ goto err;
+ return (0);
+ }
+
+ /*
+ * Integrate any offset parsed by the underlying command, and make
+ * sure the referenced line exists.
+ *
+ * XXX
+ * May not match historic practice (I've never been able to completely
+ * figure it out.) For example, the '=' command from vi mode often
+ * got the offset wrong, and complained it was too large, but didn't
+ * seem to have a problem with the cursor. If anyone complains, ask
+ * them how it's supposed to work, they probably know.
+ */
+ if (ep != NULL && (flagoff += exc.flagoff)) {
+ if (flagoff < 0) {
+ if (sp->lno <= -flagoff) {
+ msgq(sp, M_ERR, "Flag offset before line 1");
+ goto err;
+ }
+ } else {
+ if (file_lline(sp, ep, &lno))
+ goto err;
+ if (sp->lno + flagoff > lno) {
+ msgq(sp, M_ERR, "Flag offset past end-of-file");
+ goto err;
+ }
+ }
+ sp->lno += flagoff;
+ }
+
+ /*
+ * If the command was successful and we're in ex command mode, we
+ * may want to display a line. Make sure there's a line to display.
+ */
+ if (ep != NULL &&
+ IN_EX_MODE(sp) && !F_ISSET(sp, S_GLOBAL) && sp->lno != 0) {
+ /*
+ * The print commands have already handled the `print' flags.
+ * If so, clear them.
+ */
+ if (LF_ISSET(E_F_PRCLEAR))
+ F_CLR(&exc, E_F_HASH | E_F_LIST | E_F_PRINT);
+
+ /* If hash only set because of the number option, discard it. */
+ if (optnum)
+ F_CLR(&exc, E_F_HASH);
+
+ /*
+ * If there was an explicit flag to display the new cursor
+ * line, or we're in ex mode, autoprint is set, and a change
+ * was made, display the line. If any print flags set use
+ * them, otherwise default to print.
+ */
+ LF_INIT(F_ISSET(&exc, E_F_HASH | E_F_LIST | E_F_PRINT));
+ if (!LF_ISSET(E_F_HASH | E_F_LIST | E_F_PRINT) &&
+ O_ISSET(sp, O_AUTOPRINT) &&
+ (F_ISSET(exp, EX_AUTOPRINT) || F_ISSET(cp, E_AUTOPRINT)))
+ LF_INIT(E_F_PRINT);
+
+ if (LF_ISSET(E_F_HASH | E_F_LIST | E_F_PRINT)) {
+ memset(&exc, 0, sizeof(EXCMDARG));
+ exc.addrcnt = 2;
+ exc.addr1.lno = exc.addr2.lno = sp->lno;
+ exc.addr1.cno = exc.addr2.cno = sp->cno;
+ (void)ex_print(sp, ep, &exc.addr1, &exc.addr2, flags);
+ }
+ }
+
+ cmd = save_cmd;
+ cmdlen = save_cmdlen;
+ goto loop;
+ /* NOTREACHED */
+
+ /*
+ * If we haven't put out a separator line, do it now. For more
+ * detailed comments, see above.
+ */
+err: if (sep != NONE &&
+ ep != NULL && IN_EX_MODE(sp) && F_ISSET(sp->gp, G_STDIN_TTY))
+ (void)fputc('\n', stdout);
+ /*
+ * On error, we discard any keys we have left, as well as any keys
+ * that were mapped. The test of save_cmdlen isn't necessarily
+ * correct. If we fail early enough we don't know if the entire
+ * string was a single command or not. Try and guess, it's useful
+ * to know if part of the command was discarded.
+ */
+ if (save_cmdlen == 0)
+ for (; cmdlen; --cmdlen) {
+ ch = *cmd++;
+ if (IS_ESCAPE(sp, ch) && cmdlen > 1) {
+ --cmdlen;
+ ++cmd;
+ } else if (ch == '\n' || ch == '|') {
+ if (cmdlen > 1)
+ save_cmdlen = 1;
+ break;
+ }
+ }
+ if (save_cmdlen != 0)
+ msgq(sp, M_ERR,
+ "Ex command failed: remaining command input discarded");
+ /*
+ * !!!
+ * Previous versions of nvi cleared mapped characters on error. This
+ * feature was removed when users complained that it wasn't historic
+ * practice.
+ */
+ return (1);
+}
+
+/*
+ * ep_range --
+ * Get a line range for ex commands.
+ */
+static int
+ep_range(sp, ep, excp, cmdp, cmdlenp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char **cmdp;
+ size_t *cmdlenp;
+{
+ MARK cur, savecursor;
+ size_t cmdlen;
+ int savecursor_set, tmp;
+ char *cmd;
+
+ /* Percent character is all lines in the file. */
+ cmd = *cmdp;
+ cmdlen = *cmdlenp;
+ if (*cmd == '%') {
+ excp->addr1.lno = 1;
+ if (file_lline(sp, ep, &excp->addr2.lno))
+ return (1);
+
+ /* If an empty file, then the first line is 0, not 1. */
+ if (excp->addr2.lno == 0)
+ excp->addr1.lno = 0;
+ excp->addr1.cno = excp->addr2.cno = 0;
+ excp->addrcnt = 2;
+
+ ++*cmdp;
+ --*cmdlenp;
+ return (0);
+ }
+
+ /* Parse comma or semi-colon delimited line specs. */
+ for (savecursor_set = 0, excp->addrcnt = 0; cmdlen > 0;)
+ switch (*cmd) {
+ case ';': /* Semi-colon delimiter. */
+ /*
+ * Comma delimiters delimit; semi-colon delimiters
+ * change the current address for the 2nd address
+ * to be the first address. Trailing or multiple
+ * delimiters are discarded.
+ */
+ if (excp->addrcnt == 0)
+ goto done;
+ if (!savecursor_set) {
+ savecursor.lno = sp->lno;
+ savecursor.cno = sp->cno;
+ sp->lno = excp->addr1.lno;
+ sp->cno = excp->addr1.cno;
+ savecursor_set = 1;
+ }
+ ++cmd;
+ --cmdlen;
+ break;
+ case ',': /* Comma delimiter. */
+ /* If no addresses yet, defaults to ".". */
+ if (excp->addrcnt == 0) {
+ excp->addr1.lno = sp->lno;
+ excp->addr1.cno = sp->cno;
+ excp->addrcnt = 1;
+ }
+ /* FALLTHROUGH */
+ case ' ': /* Whitespace. */
+ case '\t': /* Whitespace. */
+ ++cmd;
+ --cmdlen;
+ break;
+ default:
+ if (ep_line(sp, ep, &cur, &cmd, &cmdlen, &tmp))
+ return (1);
+ if (!tmp)
+ goto done;
+
+ /*
+ * Extra addresses are discarded, starting with
+ * the first.
+ */
+ switch (excp->addrcnt) {
+ case 0:
+ excp->addr1 = cur;
+ excp->addrcnt = 1;
+ break;
+ case 1:
+ excp->addr2 = cur;
+ excp->addrcnt = 2;
+ break;
+ case 2:
+ excp->addr1 = excp->addr2;
+ excp->addr2 = cur;
+ break;
+ }
+ break;
+ }
+
+ /*
+ * XXX
+ * This is probably not the right behavior for savecursor --
+ * need to figure out what the historical ex did for ";,;,;5p"
+ * or similar stupidity.
+ */
+done: if (savecursor_set) {
+ sp->lno = savecursor.lno;
+ sp->cno = savecursor.cno;
+ }
+ if (excp->addrcnt == 2 && excp->addr2.lno < excp->addr1.lno) {
+ msgq(sp, M_ERR,
+ "The second address is smaller than the first");
+ return (1);
+ }
+ *cmdp = cmd;
+ *cmdlenp = cmdlen;
+ return (0);
+}
+
+/*
+ * Get a single line address specifier.
+ *
+ * The way the "previous context" mark worked was that any "non-relative"
+ * motion set it. While ex/vi wasn't totally consistent about this, ANY
+ * numeric address, search pattern, '$', or mark reference in an address
+ * was considered non-relative, and set the value. Which should explain
+ * why we're hacking marks down here. The problem was that the mark was
+ * only set if the command was called, i.e. we have to set a flag and test
+ * it later.
+ *
+ * XXX
+ * This is not exactly historic practice, although it's fairly close.
+ */
+static int
+ep_line(sp, ep, cur, cmdp, cmdlenp, addr_found)
+ SCR *sp;
+ EXF *ep;
+ MARK *cur;
+ char **cmdp;
+ size_t *cmdlenp;
+ int *addr_found;
+{
+ EX_PRIVATE *exp;
+ MARK m;
+ long total;
+ u_int flags;
+ size_t cmdlen;
+ int (*sf) __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *));
+ char *cmd, *endp;
+
+ exp = EXP(sp);
+ *addr_found = 0;
+
+ cmd = *cmdp;
+ cmdlen = *cmdlenp;
+ switch (*cmd) {
+ case '$': /* Last line in the file. */
+ *addr_found = 1;
+ F_SET(exp, EX_ABSMARK);
+
+ cur->cno = 0;
+ if (file_lline(sp, ep, &cur->lno))
+ return (1);
+ ++cmd;
+ --cmdlen;
+ break; /* Absolute line number. */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ *addr_found = 1;
+ F_SET(exp, EX_ABSMARK);
+
+ cur->cno = 0;
+/* 8-bit XXX */ cur->lno = strtol(cmd, &endp, 10);
+ cmdlen -= (endp - cmd);
+ cmd = endp;
+ break;
+ case '\'': /* Use a mark. */
+ *addr_found = 1;
+ F_SET(exp, EX_ABSMARK);
+
+ if (cmdlen == 1) {
+ msgq(sp, M_ERR, "No mark name supplied");
+ return (1);
+ }
+ if (mark_get(sp, ep, cmd[1], cur))
+ return (1);
+ cmd += 2;
+ cmdlen -= 2;
+ break;
+ case '\\': /* Search: forward/backward. */
+ /*
+ * !!!
+ * I can't find any difference between // and \/ or between
+ * ?? and \?. Mark Horton doesn't remember there being any
+ * difference. C'est la vie.
+ */
+ if (cmdlen < 2 || cmd[1] != '/' && cmd[1] != '?') {
+ msgq(sp, M_ERR, "\\ not followed by / or ?");
+ return (1);
+ }
+ ++cmd;
+ --cmdlen;
+ sf = cmd[0] == '/' ? f_search : b_search;
+ goto search;
+ case '/': /* Search forward. */
+ sf = f_search;
+ goto search;
+ case '?': /* Search backward. */
+ sf = b_search;
+search: F_SET(exp, EX_ABSMARK);
+
+ 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 (sf(sp, ep, &m, &m, cmd, &endp, &flags))
+ return (1);
+ cur->lno = m.lno;
+ cur->cno = m.cno;
+ cmdlen -= (endp - cmd);
+ cmd = endp;
+ break;
+ case '.': /* Current position. */
+ *addr_found = 1;
+ cur->cno = sp->cno;
+
+ /* If an empty file, then '.' is 0, not 1. */
+ if (sp->lno == 1) {
+ if (file_lline(sp, ep, &cur->lno))
+ return (1);
+ if (cur->lno != 0)
+ cur->lno = 1;
+ } else
+ cur->lno = sp->lno;
+ ++cmd;
+ --cmdlen;
+ break;
+ }
+
+ /*
+ * Evaluate any offset. Offsets are +/- any number, or any number
+ * of +/- signs, or any combination thereof. If no address found
+ * yet, offset is relative to ".".
+ */
+ for (total = 0; cmdlen > 0 && (cmd[0] == '-' || cmd[0] == '+');) {
+ if (!*addr_found) {
+ cur->lno = sp->lno;
+ cur->cno = sp->cno;
+ *addr_found = 1;
+ }
+
+ if (cmdlen > 1 && isdigit(cmd[1])) {
+/* 8-bit XXX */ total += strtol(cmd, &endp, 10);
+ cmdlen -= (endp - cmd);
+ cmd = endp;
+ } else {
+ total += cmd[0] == '-' ? -1 : 1;
+ --cmdlen;
+ ++cmd;
+ }
+ }
+
+ 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);
+}
+
+/*
+ * ex_is_abbrev -
+ * The vi text input routine needs to know if ex thinks this is
+ * an [un]abbreviate command, so it can turn off abbreviations.
+ * Usual ranting in the vi/v_ntext:txt_abbrev() routine.
+ */
+int
+ex_is_abbrev(name, len)
+ char *name;
+ size_t len;
+{
+ EXCMDLIST const *cp;
+
+ return ((cp = ex_comm_search(name, len)) != NULL &&
+ (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;
+ size_t len;
+{
+ EXCMDLIST const *cp;
+
+ for (cp = cmds; cp->name != NULL; ++cp) {
+ if (cp->name[0] > name[0])
+ return (NULL);
+ if (cp->name[0] != name[0])
+ continue;
+ if (!memcmp(name, cp->name, len))
+ return (cp);
+ }
+ return (NULL);
+}
+
+static void
+badlno(sp, lno)
+ SCR *sp;
+ recno_t lno;
+{
+ if (lno == 0)
+ msgq(sp, M_ERR, "Illegal address: the file is empty");
+ else
+ msgq(sp, M_ERR, "Illegal address: only %lu line%s in the file",
+ lno, lno > 1 ? "s" : "");
+}
diff --git a/usr.bin/vi/ex/ex_abbrev.c b/usr.bin/vi/ex/ex_abbrev.c
new file mode 100644
index 000000000000..a0af8cd8d13b
--- /dev/null
+++ b/usr.bin/vi/ex/ex_abbrev.c
@@ -0,0 +1,129 @@
+/*-
+ * 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_abbrev.c 8.12 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../vi/vcmd.h"
+
+/*
+ * ex_abbr -- :abbreviate [key replacement]
+ * Create an abbreviation or display abbreviations.
+ */
+int
+ex_abbr(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ CHAR_T *p;
+ size_t len;
+
+ switch (cmdp->argc) {
+ case 0:
+ if (seq_dump(sp, SEQ_ABBREV, 0) == 0)
+ msgq(sp, M_INFO, "No abbreviations to display");
+ return (0);
+ case 2:
+ break;
+ default:
+ abort();
+ }
+
+ /* Check for illegal characters. */
+ for (p = cmdp->argv[0]->bp, len = cmdp->argv[0]->len; len--; ++p)
+ if (!inword(*p)) {
+ msgq(sp, M_ERR,
+ "%s may not be part of an abbreviated word",
+ KEY_NAME(sp, *p));
+ return (1);
+ }
+
+ if (seq_set(sp, NULL, 0, cmdp->argv[0]->bp, cmdp->argv[0]->len,
+ cmdp->argv[1]->bp, cmdp->argv[1]->len, SEQ_ABBREV, SEQ_USERDEF))
+ return (1);
+
+ F_SET(sp->gp, G_ABBREV);
+ return (0);
+}
+
+/*
+ * ex_unabbr -- :unabbreviate key
+ * Delete an abbreviation.
+ */
+int
+ex_unabbr(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS *ap;
+
+ ap = cmdp->argv[0];
+ if (!F_ISSET(sp->gp, G_ABBREV) ||
+ seq_delete(sp, ap->bp, ap->len, SEQ_ABBREV)) {
+ msgq(sp, M_ERR, "\"%s\" is not an abbreviation", ap->bp);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * abbr_save --
+ * Save the abbreviation sequences to a file.
+ */
+int
+abbr_save(sp, fp)
+ SCR *sp;
+ FILE *fp;
+{
+ return (seq_save(sp, fp, "abbreviate ", SEQ_ABBREV));
+}
diff --git a/usr.bin/vi/ex/ex_append.c b/usr.bin/vi/ex/ex_append.c
new file mode 100644
index 000000000000..97172dc4ab0d
--- /dev/null
+++ b/usr.bin/vi/ex/ex_append.c
@@ -0,0 +1,220 @@
+/*-
+ * 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_append.c 8.22 (Berkeley) 8/7/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 <unistd.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../sex/sex_screen.h"
+
+enum which {APPEND, CHANGE, INSERT};
+
+static int aci __P((SCR *, EXF *, EXCMDARG *, enum which));
+
+/*
+ * ex_append -- :[line] a[ppend][!]
+ * Append one or more lines of new text after the specified line,
+ * or the current line if no address is specified.
+ */
+int
+ex_append(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (aci(sp, ep, cmdp, APPEND));
+}
+
+/*
+ * ex_change -- :[line[,line]] c[hange][!] [count]
+ * Change one or more lines to the input text.
+ */
+int
+ex_change(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (aci(sp, ep, cmdp, CHANGE));
+}
+
+/*
+ * ex_insert -- :[line] i[nsert][!]
+ * Insert one or more lines of new text before the specified line,
+ * or the current line if no address is specified.
+ */
+int
+ex_insert(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (aci(sp, ep, cmdp, INSERT));
+}
+
+static int
+aci(sp, ep, cmdp, cmd)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ enum which cmd;
+{
+ MARK m;
+ TEXTH *sv_tiqp, tiq;
+ TEXT *tp;
+ struct termios t;
+ u_int flags;
+ int rval;
+
+ rval = 0;
+
+ /*
+ * Set input flags; the ! flag turns off autoindent for append,
+ * change and insert.
+ */
+ LF_INIT(TXT_DOTTERM | TXT_NLECHO);
+ if (!F_ISSET(cmdp, E_FORCE) && O_ISSET(sp, O_AUTOINDENT))
+ LF_SET(TXT_AUTOINDENT);
+ if (O_ISSET(sp, O_BEAUTIFY))
+ LF_SET(TXT_BEAUTIFY);
+
+ /* Input is interruptible. */
+ F_SET(sp, S_INTERRUPTIBLE);
+
+ /*
+ * If this code is called by vi, the screen TEXTH structure (sp->tiqp)
+ * may already be in use, e.g. ":append|s/abc/ABC/" would fail as we're
+ * only halfway through the line when the append code fires. Use the
+ * local structure instead.
+ *
+ * If this code is called by vi, we want to reset the terminal and use
+ * ex's s_get() routine. It actually works fine if we use vi's s_get()
+ * routine, but it doesn't look as nice. Maybe if we had a separate
+ * window or something, but getting a line at a time looks awkward.
+ */
+ if (IN_VI_MODE(sp)) {
+ memset(&tiq, 0, sizeof(TEXTH));
+ CIRCLEQ_INIT(&tiq);
+ sv_tiqp = sp->tiqp;
+ sp->tiqp = &tiq;
+
+ if (F_ISSET(sp->gp, G_STDIN_TTY))
+ SEX_RAW(t);
+ (void)write(STDOUT_FILENO, "\n", 1);
+ LF_SET(TXT_NLECHO);
+
+ }
+
+ /* Set the line number, so that autoindent works correctly. */
+ sp->lno = cmdp->addr1.lno;
+
+ if (sex_get(sp, ep, sp->tiqp, 0, flags) != INP_OK)
+ goto err;
+
+ /*
+ * If doing a change, replace lines for as long as possible. Then,
+ * append more lines or delete remaining lines. Changes to an empty
+ * file are just appends, and inserts are the same as appends to the
+ * previous line.
+ *
+ * !!!
+ * Adjust the current line number for the commands to match historic
+ * practice if the user doesn't enter anything, and set the address
+ * to which we'll append. This is safe because an address of 0 is
+ * illegal for change and insert.
+ */
+ m = cmdp->addr1;
+ switch (cmd) {
+ case INSERT:
+ --m.lno;
+ /* FALLTHROUGH */
+ case APPEND:
+ if (sp->lno == 0)
+ sp->lno = 1;
+ break;
+ case CHANGE:
+ --m.lno;
+ if (sp->lno != 1)
+ --sp->lno;
+ break;
+ }
+
+ /*
+ * !!!
+ * Cut into the unnamed buffer.
+ */
+ if (cmd == CHANGE &&
+ (cut(sp, ep, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) ||
+ delete(sp, ep, &cmdp->addr1, &cmdp->addr2, 1)))
+ goto err;
+
+ for (tp = sp->tiqp->cqh_first;
+ tp != (TEXT *)sp->tiqp; tp = tp->q.cqe_next) {
+ if (file_aline(sp, ep, 1, m.lno, tp->lb, tp->len)) {
+err: rval = 1;
+ break;
+ }
+ sp->lno = ++m.lno;
+ }
+
+ if (IN_VI_MODE(sp)) {
+ sp->tiqp = sv_tiqp;
+ text_lfree(&tiq);
+
+ /* Reset the terminal state. */
+ if (F_ISSET(sp->gp, G_STDIN_TTY)) {
+ if (SEX_NORAW(t))
+ rval = 1;
+ F_SET(sp, S_REFRESH);
+ }
+ }
+ return (rval);
+}
diff --git a/usr.bin/vi/ex/ex_args.c b/usr.bin/vi/ex/ex_args.c
new file mode 100644
index 000000000000..9213e84417a3
--- /dev/null
+++ b/usr.bin/vi/ex/ex_args.c
@@ -0,0 +1,263 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_args.c 8.27 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_next -- :next [+cmd] [files]
+ * Edit the next file, optionally setting the list of files.
+ *
+ * !!!
+ * The :next command behaved differently from the :rewind command in
+ * historic vi. See nvi/docs/autowrite for details, but the basic
+ * idea was that it ignored the force flag if the autowrite flag was
+ * set. This implementation handles them all identically.
+ */
+int
+ex_next(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS **argv, **pc;
+ FREF *frp;
+ int noargs;
+ char **ap;
+
+ if (file_m1(sp, ep, F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE))
+ return (1);
+
+ /*
+ * If the first argument is a plus sign, '+', it's an initial
+ * ex command.
+ */
+ argv = cmdp->argv;
+ if (cmdp->argc && argv[0]->bp[0] == '+') {
+ --cmdp->argc;
+ pc = argv++;
+ } else
+ pc = NULL;
+
+ /* Any other arguments are a replacement file list. */
+ if (cmdp->argc) {
+ /* Free the current list. */
+ if (!F_ISSET(sp, S_ARGNOFREE) && sp->argv != NULL) {
+ for (ap = sp->argv; *ap != NULL; ++ap)
+ free(*ap);
+ free(sp->argv);
+ }
+ F_CLR(sp, S_ARGNOFREE | S_ARGRECOVER);
+ sp->cargv = NULL;
+
+ /* Create a new list. */
+ CALLOC_RET(sp,
+ sp->argv, char **, cmdp->argc + 1, sizeof(char *));
+ for (ap = sp->argv,
+ argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv)
+ if ((*ap =
+ v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL)
+ return (1);
+ *ap = NULL;
+
+ /* Switch to the first one. */
+ sp->cargv = sp->argv;
+ if ((frp = file_add(sp, *sp->cargv)) == NULL)
+ return (1);
+ noargs = 0;
+ } else {
+ if (sp->cargv == NULL || sp->cargv[1] == NULL) {
+ msgq(sp, M_ERR, "No more files to edit");
+ return (1);
+ }
+ if ((frp = file_add(sp, sp->cargv[1])) == NULL)
+ return (1);
+ if (F_ISSET(sp, S_ARGRECOVER))
+ F_SET(frp, FR_RECOVER);
+ noargs = 1;
+ }
+
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+ if (noargs)
+ ++sp->cargv;
+
+ /* Push the initial command onto the stack. */
+ if (pc != NULL)
+ if (IN_EX_MODE(sp))
+ (void)term_push(sp, pc[0]->bp, pc[0]->len, 0);
+ else if (IN_VI_MODE(sp)) {
+ (void)term_push(sp, "\n", 1, 0);
+ (void)term_push(sp, pc[0]->bp, pc[0]->len, 0);
+ (void)term_push(sp, ":", 1, 0);
+ (void)file_lline(sp, sp->ep, &sp->frp->lno);
+ F_SET(sp->frp, FR_CURSORSET);
+ }
+
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
+
+/*
+ * ex_prev -- :prev
+ * Edit the previous file.
+ */
+int
+ex_prev(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ FREF *frp;
+
+ if (file_m1(sp, ep, F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE))
+ return (1);
+
+ if (sp->cargv == sp->argv) {
+ msgq(sp, M_ERR, "No previous files to edit");
+ return (1);
+ }
+ if ((frp = file_add(sp, sp->cargv[-1])) == NULL)
+ return (1);
+
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+
+ --sp->cargv;
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
+
+/*
+ * ex_rew -- :rew
+ * Re-edit the list of files.
+ */
+int
+ex_rew(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ FREF *frp;
+
+ /*
+ * !!!
+ * Historic practice -- you can rewind to the current file.
+ */
+ if (sp->argv == NULL) {
+ msgq(sp, M_ERR, "No previous files to rewind");
+ return (1);
+ }
+
+ if (file_m1(sp, ep, F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE))
+ return (1);
+
+ /*
+ * !!!
+ * Historic practice, start at the beginning of the file.
+ */
+ for (frp = sp->frefq.cqh_first;
+ frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next)
+ F_CLR(frp, FR_CURSORSET | FR_FNONBLANK);
+
+ /* Switch to the first one. */
+ sp->cargv = sp->argv;
+ if ((frp = file_add(sp, *sp->cargv)) == NULL)
+ return (1);
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
+
+/*
+ * ex_args -- :args
+ * Display the list of files.
+ */
+int
+ex_args(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ int cnt, col, len, sep;
+ char **ap;
+
+ if (sp->argv == NULL) {
+ (void)ex_printf(EXCOOKIE, "No file list to display.\n");
+ return (0);
+ }
+
+ col = len = sep = 0;
+ for (cnt = 1, ap = sp->argv; *ap != NULL; ++ap) {
+ col += len = strlen(*ap) + sep + (ap == sp->cargv ? 2 : 0);
+ if (col >= sp->cols - 1) {
+ col = len;
+ sep = 0;
+ (void)ex_printf(EXCOOKIE, "\n");
+ } else if (cnt != 1) {
+ sep = 1;
+ (void)ex_printf(EXCOOKIE, " ");
+ }
+ ++cnt;
+
+ if (ap == sp->cargv)
+ (void)ex_printf(EXCOOKIE, "[%s]", *ap);
+ else
+ (void)ex_printf(EXCOOKIE, "%s", *ap);
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_argv.c b/usr.bin/vi/ex/ex_argv.c
new file mode 100644
index 000000000000..f93aa76e3039
--- /dev/null
+++ b/usr.bin/vi/ex/ex_argv.c
@@ -0,0 +1,609 @@
+/*-
+ * 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_argv.c 8.36 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static int argv_alloc __P((SCR *, size_t));
+static int argv_fexp __P((SCR *, EXCMDARG *,
+ char *, size_t, char *, size_t *, char **, size_t *, int));
+static int argv_sexp __P((SCR *, char **, size_t *, size_t *));
+
+/*
+ * argv_init --
+ * Build a prototype arguments list.
+ */
+int
+argv_init(sp, ep, excp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+{
+ EX_PRIVATE *exp;
+
+ exp = EXP(sp);
+ exp->argsoff = 0;
+ argv_alloc(sp, 1);
+
+ excp->argv = exp->args;
+ excp->argc = exp->argsoff;
+ return (0);
+}
+
+/*
+ * argv_exp0 --
+ * Append a string to the argument list.
+ */
+int
+argv_exp0(sp, ep, excp, cmd, cmdlen)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char *cmd;
+ size_t cmdlen;
+{
+ EX_PRIVATE *exp;
+
+ exp = EXP(sp);
+ argv_alloc(sp, cmdlen);
+ memmove(exp->args[exp->argsoff]->bp, cmd, cmdlen);
+ exp->args[exp->argsoff]->bp[cmdlen] = '\0';
+ exp->args[exp->argsoff]->len = cmdlen;
+ ++exp->argsoff;
+ excp->argv = exp->args;
+ excp->argc = exp->argsoff;
+ return (0);
+}
+
+/*
+ * argv_exp1 --
+ * Do file name expansion on a string, and append it to the
+ * argument list.
+ */
+int
+argv_exp1(sp, ep, excp, cmd, cmdlen, is_bang)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char *cmd;
+ size_t cmdlen;
+ int is_bang;
+{
+ EX_PRIVATE *exp;
+ size_t blen, len;
+ char *bp, *p, *t;
+
+ GET_SPACE_RET(sp, bp, blen, 512);
+
+ len = 0;
+ exp = EXP(sp);
+ if (argv_fexp(sp, excp, cmd, cmdlen, bp, &len, &bp, &blen, is_bang)) {
+ FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+
+ /* If it's empty, we're done. */
+ if (len != 0) {
+ for (p = bp, t = bp + len; p < t; ++p)
+ if (!isblank(*p))
+ break;
+ if (p == t)
+ goto ret;
+ } else
+ goto ret;
+
+ (void)argv_exp0(sp, ep, excp, bp, len);
+
+ret: FREE_SPACE(sp, bp, blen);
+ return (0);
+}
+
+/*
+ * argv_exp2 --
+ * Do file name and shell expansion on a string, and append it to
+ * the argument list.
+ */
+int
+argv_exp2(sp, ep, excp, cmd, cmdlen, is_bang)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char *cmd;
+ size_t cmdlen;
+ int is_bang;
+{
+ size_t blen, len, n;
+ int rval;
+ char *bp, *mp, *p;
+
+ GET_SPACE_RET(sp, bp, blen, 512);
+
+#define SHELLECHO "echo "
+#define SHELLOFFSET (sizeof(SHELLECHO) - 1)
+ memmove(bp, SHELLECHO, SHELLOFFSET);
+ p = bp + SHELLOFFSET;
+ len = SHELLOFFSET;
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "file_argv: {%.*s}\n", (int)cmdlen, cmd);
+#endif
+
+ if (argv_fexp(sp, excp, cmd, cmdlen, p, &len, &bp, &blen, is_bang)) {
+ rval = 1;
+ goto err;
+ }
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "before shell: %d: {%s}\n", len, bp);
+#endif
+
+ /*
+ * Do shell word expansion -- it's very, very hard to figure out what
+ * magic characters the user's shell expects. Historically, it was a
+ * union of v7 shell and csh meta characters. We match that practice
+ * by default, so ":read \%" tries to read a file named '%'. It would
+ * make more sense to pass any special characters through the shell,
+ * but then, if your shell was csh, the above example will behave
+ * differently in nvi than in vi. If you want to get other characters
+ * passed through to your shell, change the "meta" option.
+ *
+ * To avoid a function call per character, we do a first pass through
+ * the meta characters looking for characters that aren't expected
+ * to be there.
+ */
+ for (p = mp = O_STR(sp, O_META); *p != '\0'; ++p)
+ if (isblank(*p) || isalnum(*p))
+ break;
+ if (*p != '\0') {
+ for (p = bp, n = len; n > 0; --n, ++p)
+ if (strchr(mp, *p) != NULL)
+ break;
+ } else
+ for (p = bp, n = len; n > 0; --n, ++p)
+ if (!isblank(*p) &&
+ !isalnum(*p) && strchr(mp, *p) != NULL)
+ break;
+ if (n > 0) {
+ if (argv_sexp(sp, &bp, &blen, &len)) {
+ rval = 1;
+ goto err;
+ }
+ p = bp;
+ } else {
+ p = bp + SHELLOFFSET;
+ len -= SHELLOFFSET;
+ }
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "after shell: %d: {%s}\n", len, bp);
+#endif
+
+ rval = argv_exp3(sp, ep, excp, p, len);
+
+err: FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * argv_exp3 --
+ * Take a string and break it up into an argv, which is appended
+ * to the argument list.
+ */
+int
+argv_exp3(sp, ep, excp, cmd, cmdlen)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *excp;
+ char *cmd;
+ size_t cmdlen;
+{
+ EX_PRIVATE *exp;
+ size_t len;
+ int ch, off;
+ char *ap, *p;
+
+ for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) {
+ /* Skip any leading whitespace. */
+ for (; cmdlen > 0; --cmdlen, ++cmd) {
+ ch = *cmd;
+ if (!isblank(ch))
+ break;
+ }
+ if (cmdlen == 0)
+ break;
+
+ /*
+ * Determine the length of this whitespace delimited
+ * argument.
+ *
+ * QUOTING NOTE:
+ *
+ * Skip any character preceded by the user's quoting
+ * character.
+ */
+ 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.
+ *
+ * QUOTING NOTE:
+ *
+ * Lose quote chars.
+ */
+ argv_alloc(sp, len);
+ off = exp->argsoff;
+ exp->args[off]->len = len;
+ for (p = exp->args[off]->bp; len > 0; --len, *p++ = *ap++)
+ if (IS_ESCAPE(sp, *ap))
+ ++ap;
+ *p = '\0';
+ }
+ excp->argv = exp->args;
+ excp->argc = exp->argsoff;
+
+#if defined(DEBUG) && 0
+ for (cnt = 0; cnt < exp->argsoff; ++cnt)
+ TRACE(sp, "arg %d: {%s}\n", cnt, exp->argv[cnt]);
+#endif
+ return (0);
+}
+
+/*
+ * argv_fexp --
+ * Do file name and bang command expansion.
+ */
+static int
+argv_fexp(sp, excp, cmd, cmdlen, p, lenp, bpp, blenp, is_bang)
+ SCR *sp;
+ EXCMDARG *excp;
+ char *cmd, *p, **bpp;
+ size_t cmdlen, *lenp, *blenp;
+ int is_bang;
+{
+ EX_PRIVATE *exp;
+ char *bp, *t;
+ size_t blen, len, tlen;
+
+ /* Replace file name characters. */
+ for (bp = *bpp, blen = *blenp, len = *lenp; cmdlen > 0; --cmdlen, ++cmd)
+ switch (*cmd) {
+ case '!':
+ if (!is_bang)
+ goto ins_ch;
+ exp = EXP(sp);
+ if (exp->lastbcomm == NULL) {
+ msgq(sp, M_ERR,
+ "No previous command to replace \"!\"");
+ return (1);
+ }
+ len += tlen = strlen(exp->lastbcomm);
+ ADD_SPACE_RET(sp, bp, blen, len);
+ memmove(p, exp->lastbcomm, tlen);
+ p += tlen;
+ F_SET(excp, E_MODIFY);
+ break;
+ case '%':
+ if ((t = sp->frp->name) == NULL) {
+ msgq(sp, M_ERR,
+ "No filename to substitute for %%");
+ return (1);
+ }
+ tlen = strlen(t);
+ len += tlen;
+ ADD_SPACE_RET(sp, bp, blen, len);
+ memmove(p, t, tlen);
+ p += tlen;
+ F_SET(excp, E_MODIFY);
+ break;
+ case '#':
+ if ((t = sp->alt_name) == NULL) {
+ msgq(sp, M_ERR,
+ "No filename to substitute for #");
+ return (1);
+ }
+ len += tlen = strlen(t);
+ ADD_SPACE_RET(sp, bp, blen, len);
+ memmove(p, t, tlen);
+ p += tlen;
+ F_SET(excp, E_MODIFY);
+ break;
+ case '\\':
+ /*
+ * QUOTING NOTE:
+ *
+ * Strip any backslashes that protected the file
+ * expansion characters.
+ */
+ if (cmdlen > 1 && (cmd[1] == '%' || cmd[1] == '#')) {
+ ++cmd;
+ --cmdlen;
+ }
+ /* FALLTHROUGH */
+ default:
+ins_ch: ++len;
+ ADD_SPACE_RET(sp, bp, blen, len);
+ *p++ = *cmd;
+ }
+
+ /* Nul termination. */
+ ++len;
+ ADD_SPACE_RET(sp, bp, blen, len);
+ *p = '\0';
+
+ /* Return the new string length, buffer, buffer length. */
+ *lenp = len - 1;
+ *bpp = bp;
+ *blenp = blen;
+ return (0);
+}
+
+/*
+ * argv_alloc --
+ * Make more space for arguments.
+ */
+static int
+argv_alloc(sp, len)
+ SCR *sp;
+ size_t len;
+{
+ ARGS *ap;
+ EX_PRIVATE *exp;
+ int cnt, off;
+
+ /*
+ * Allocate room for another argument, always leaving
+ * enough room for an ARGS structure with a length of 0.
+ */
+#define INCREMENT 20
+ exp = EXP(sp);
+ off = exp->argsoff;
+ if (exp->argscnt == 0 || off + 2 >= exp->argscnt - 1) {
+ cnt = exp->argscnt + INCREMENT;
+ REALLOC(sp, exp->args, ARGS **, cnt * sizeof(ARGS *));
+ if (exp->args == NULL) {
+ (void)argv_free(sp);
+ goto mem;
+ }
+ memset(&exp->args[off], 0, INCREMENT * sizeof(ARGS *));
+ exp->argscnt = cnt;
+ }
+
+ /* First argument. */
+ if (exp->args[off] == NULL) {
+ CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
+ if (exp->args[off] == NULL)
+ goto mem;
+ }
+
+ /* First argument buffer. */
+ 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);
+ }
+
+ /* Second argument. */
+ if (exp->args[++off] == NULL) {
+ CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
+ if (exp->args[off] == NULL)
+ goto mem;
+ }
+ /* 0 length serves as end-of-argument marker. */
+ exp->args[off]->len = 0;
+ return (0);
+}
+
+/*
+ * argv_free --
+ * Free up argument structures.
+ */
+int
+argv_free(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ int off;
+
+ exp = EXP(sp);
+ if (exp->args != NULL) {
+ for (off = 0; off < exp->argscnt; ++off) {
+ if (exp->args[off] == NULL)
+ continue;
+ if (F_ISSET(exp->args[off], A_ALLOCATED))
+ free(exp->args[off]->bp);
+ FREE(exp->args[off], sizeof(ARGS));
+ }
+ FREE(exp->args, exp->argscnt * sizeof(ARGS *));
+ }
+ exp->args = NULL;
+ exp->argscnt = 0;
+ exp->argsoff = 0;
+ return (0);
+}
+
+/*
+ * argv_sexp --
+ * Fork a shell, pipe a command through it, and read the output into
+ * a buffer.
+ */
+static int
+argv_sexp(sp, bpp, blenp, lenp)
+ SCR *sp;
+ char **bpp;
+ size_t *blenp, *lenp;
+{
+ FILE *ifp;
+ pid_t pid;
+ size_t blen, len;
+ int ch, rval, output[2];
+ char *bp, *p, *sh, *sh_path;
+
+ bp = *bpp;
+ blen = *blenp;
+
+ sh_path = O_STR(sp, O_SHELL);
+ if ((sh = strrchr(sh_path, '/')) == NULL)
+ sh = sh_path;
+ else
+ ++sh;
+
+ /*
+ * There are two different processes running through this code.
+ * They are named the utility and the parent. The utility reads
+ * from standard input and writes to the parent. The parent reads
+ * from the utility and writes into the buffer. The parent reads
+ * from output[0], and the utility writes to output[1].
+ */
+ if (pipe(output) < 0) {
+ msgq(sp, M_SYSERR, "pipe");
+ return (1);
+ }
+ if ((ifp = fdopen(output[0], "r")) == NULL) {
+ 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.
+ */
+ SIGBLOCK(sp->gp);
+ switch (pid = vfork()) {
+ case -1: /* Error. */
+ SIGUNBLOCK(sp->gp);
+
+ msgq(sp, M_SYSERR, "vfork");
+err: (void)close(output[0]);
+ (void)close(output[1]);
+ return (1);
+ case 0: /* Utility. */
+ /* The utility has default signal behavior. */
+ sig_end();
+
+ /* Redirect stdout/stderr to the write end of the pipe. */
+ (void)dup2(output[1], STDOUT_FILENO);
+ (void)dup2(output[1], STDERR_FILENO);
+
+ /* Close the utility's file descriptors. */
+ (void)close(output[0]);
+ (void)close(output[1]);
+
+ /* Assumes that all shells have -c. */
+ execl(sh_path, sh, "-c", bp, NULL);
+ msgq(sp, M_ERR,
+ "Error: execl: %s: %s", sh_path, strerror(errno));
+ _exit(127);
+ default: /* Parent. */
+ SIGUNBLOCK(sp->gp);
+
+ /* Close the pipe end the parent won't use. */
+ (void)close(output[1]);
+ break;
+ }
+
+ rval = 0;
+
+ /*
+ * Copy process output into a buffer.
+ *
+ * !!!
+ * Historic vi apparently discarded leading \n and \r's from
+ * the shell output stream. We don't on the grounds that any
+ * shell that does that is broken.
+ */
+ for (p = bp, len = 0, ch = EOF;
+ (ch = getc(ifp)) != EOF; *p++ = ch, --blen, ++len)
+ if (blen < 5) {
+ ADD_SPACE_GOTO(sp, bp, blen, *blenp * 2);
+ p = bp + len;
+ blen = *blenp - len;
+ }
+
+ /* Delete the final newline, nul terminate the string. */
+ if (p > bp && (p[-1] == '\n' || p[-1] == '\r')) {
+ --len;
+ *--p = '\0';
+ } else
+ *p = '\0';
+ *lenp = len;
+
+ if (ferror(ifp)) {
+ msgq(sp, M_ERR, "I/O error: %s", sh);
+binc_err: rval = 1;
+ }
+ (void)fclose(ifp);
+
+ *bpp = bp; /* *blenp is already updated. */
+
+ /* Wait for the process. */
+ return (proc_wait(sp, (long)pid, sh, 0) || rval);
+}
diff --git a/usr.bin/vi/ex/ex_at.c b/usr.bin/vi/ex/ex_at.c
new file mode 100644
index 000000000000..fc5922fb61f9
--- /dev/null
+++ b/usr.bin/vi/ex/ex_at.c
@@ -0,0 +1,118 @@
+/*-
+ * 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_at.c 8.25 (Berkeley) 8/1/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_at -- :@[@ | buffer]
+ * :*[* | buffer]
+ *
+ * Execute the contents of the buffer.
+ */
+int
+ex_at(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ CB *cbp;
+ EX_PRIVATE *exp;
+ TEXT *tp;
+ int name;
+
+ exp = EXP(sp);
+
+ /*
+ * !!!
+ * Historically, [@*]<carriage-return> and [@*][@*] executed the most
+ * recently executed buffer in ex mode. In vi mode, only @@ repeated
+ * the last buffer. We change historic practice and make @* work from
+ * vi mode as well, it's simpler and more consistent.
+ */
+ name = F_ISSET(cmdp, E_BUFFER) ? cmdp->buffer : '@';
+ if (name == '@' || name == '*') {
+ if (!exp->at_lbuf_set) {
+ msgq(sp, M_ERR, "No previous buffer to execute");
+ return (1);
+ }
+ name = exp->at_lbuf;
+ }
+
+ CBNAME(sp, cbp, name);
+ if (cbp == NULL) {
+ msgq(sp, M_ERR, "Buffer %s is empty", KEY_NAME(sp, name));
+ return (1);
+ }
+
+ /* Save for reuse. */
+ exp->at_lbuf = name;
+ exp->at_lbuf_set = 1;
+
+ /*
+ * !!!
+ * Historic practice is that if the buffer was cut in line mode,
+ * <newlines> were appended to each line as it was pushed onto
+ * the stack. If the buffer was cut in character mode, <newlines>
+ * were appended to all lines but the last one.
+ */
+ for (tp = cbp->textq.cqh_last;
+ tp != (void *)&cbp->textq; tp = tp->q.cqe_prev)
+ if ((F_ISSET(cbp, CB_LMODE) ||
+ tp->q.cqe_next != (void *)&cbp->textq) &&
+ term_push(sp, "\n", 1, 0) ||
+ term_push(sp, tp->lb, tp->len, 0))
+ return (1);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_bang.c b/usr.bin/vi/ex/ex_bang.c
new file mode 100644
index 000000000000..70bbb57c0522
--- /dev/null
+++ b/usr.bin/vi/ex/ex_bang.c
@@ -0,0 +1,242 @@
+/*-
+ * 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_bang.c 8.33 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../sex/sex_screen.h"
+
+/*
+ * ex_bang -- :[line [,line]] ! command
+ *
+ * Pass the rest of the line after the ! character to the program named by
+ * the O_SHELL option.
+ *
+ * Historical vi did NOT do shell expansion on the arguments before passing
+ * them, only file name expansion. This means that the O_SHELL program got
+ * "$t" as an argument if that is what the user entered. Also, there's a
+ * special expansion done for the bang command. Any exclamation points in
+ * the user's argument are replaced by the last, expanded ! command.
+ *
+ * There's some fairly amazing slop in this routine to make the different
+ * ways of getting here display the right things. It took a long time to
+ * get it right (wrong?), so be careful.
+ */
+int
+ex_bang(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ enum filtertype ftype;
+ ARGS *ap;
+ EX_PRIVATE *exp;
+ MARK rm;
+ recno_t lno;
+ size_t blen;
+ int rval;
+ char *bp, *msg;
+
+ ap = cmdp->argv[0];
+ if (ap->len == 0) {
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+
+ /* Set the last bang command. */
+ exp = EXP(sp);
+ if (exp->lastbcomm != NULL)
+ free(exp->lastbcomm);
+ if ((exp->lastbcomm = strdup(ap->bp)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ /*
+ * If the command was modified by the expansion, we redisplay it.
+ * Redisplaying it in vi mode is tricky, and handled separately
+ * in each case below. If we're in ex mode, it's easy, so we just
+ * do it here.
+ */
+ bp = NULL;
+ if (F_ISSET(cmdp, E_MODIFY) && !F_ISSET(sp, S_EXSILENT)) {
+ if (IN_EX_MODE(sp)) {
+ (void)ex_printf(EXCOOKIE, "!%s\n", ap->bp);
+ (void)ex_fflush(EXCOOKIE);
+ }
+ /*
+ * Vi: Display the command if modified. Historic vi displayed
+ * the command if it was modified due to file name and/or bang
+ * expansion. If piping lines, it was immediately overwritten
+ * by any error or line change reporting. We don't the user to
+ * have to page through the responses, so we only post it until
+ * it's erased by something else. Otherwise, pass it on to the
+ * ex_exec_proc routine to display after the screen has been
+ * cleaned up.
+ */
+ if (IN_VI_MODE(sp)) {
+ GET_SPACE_RET(sp, bp, blen, ap->len + 3);
+ bp[0] = '!';
+ memmove(bp + 1, ap->bp, ap->len);
+ bp[ap->len + 1] = '\n';
+ bp[ap->len + 2] = '\0';
+ }
+ }
+
+ /*
+ * If addresses were specified, pipe lines from the file through the
+ * command.
+ *
+ * Historically, vi lines were replaced by both the stdout and stderr
+ * lines of the command, but ex by only the stdout lines. This makes
+ * no sense to me, so nvi makes it consistent for both, and matches
+ * vi's historic behavior.
+ */
+ if (cmdp->addrcnt != 0) {
+ /* Autoprint is set historically, even if the command fails. */
+ F_SET(exp, EX_AUTOPRINT);
+
+ /* Vi gets a busy message. */
+ if (bp != NULL)
+ (void)sp->s_busy(sp, bp);
+
+ /*
+ * !!!
+ * Historical vi permitted "!!" in an empty file. When it
+ * happens, we get called with two addresses of 1,1 and a
+ * bad attitude. The simple solution is to turn it into a
+ * FILTER_READ operation, but that means that we don't put
+ * an empty line into the default cut buffer as did historic
+ * vi. Tough.
+ */
+ ftype = FILTER;
+ if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ cmdp->addr1.lno = cmdp->addr2.lno = 0;
+ ftype = FILTER_READ;
+ }
+ }
+ rval = filtercmd(sp, ep,
+ &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype);
+
+ /*
+ * If in vi mode, move to the first nonblank.
+ *
+ * !!!
+ * Historic vi wasn't consistent in this area -- if you used
+ * a forward motion it moved to the first nonblank, but if you
+ * did a backward motion it didn't. And, if you followed a
+ * backward motion with a forward motion, it wouldn't move to
+ * the nonblank for either. Going to the nonblank generally
+ * seems more useful, so we do it.
+ */
+ if (rval == 0) {
+ sp->lno = rm.lno;
+ if (IN_VI_MODE(sp)) {
+ sp->cno = 0;
+ (void)nonblank(sp, ep, sp->lno, &sp->cno);
+ }
+ }
+ goto ret2;
+ }
+
+ /*
+ * If no addresses were specified, run the command. If the file
+ * has been modified and autowrite is set, write the file back.
+ * If the file has been modified, autowrite is not set and the
+ * warn option is set, tell the user about the file.
+ */
+ msg = NULL;
+ if (F_ISSET(ep, F_MODIFIED))
+ if (O_ISSET(sp, O_AUTOWRITE)) {
+ if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL)) {
+ rval = 1;
+ goto ret1;
+ }
+ } else if (O_ISSET(sp, O_WARN) && !F_ISSET(sp, S_EXSILENT))
+ msg = "File modified since last write.\n";
+
+ /* Run the command. */
+ rval = ex_exec_proc(sp, ap->bp, bp, msg);
+
+ /* Vi requires user permission to continue. */
+ if (IN_VI_MODE(sp))
+ F_SET(sp, S_CONTINUE);
+
+ret2: if (IN_EX_MODE(sp)) {
+ /*
+ * Put ex error messages out so they aren't confused with
+ * the autoprint output.
+ */
+ if (rval)
+ (void)sex_refresh(sp, sp->ep);
+
+ /* Ex terminates with a bang, even if the command fails. */
+ if (!F_ISSET(sp, S_EXSILENT))
+ (void)write(STDOUT_FILENO, "!\n", 2);
+ }
+
+ /* Free the extra space. */
+ret1: if (bp != NULL)
+ FREE_SPACE(sp, bp, blen);
+
+ /*
+ * XXX
+ * The ! commands never return an error, so that autoprint always
+ * happens in the ex parser.
+ */
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_cd.c b/usr.bin/vi/ex/ex_cd.c
new file mode 100644
index 000000000000..3732f7b2465f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_cd.c
@@ -0,0 +1,223 @@
+/*-
+ * 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.16 (Berkeley) 8/8/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <errno.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 "compat.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;
+{
+ struct passwd *pw;
+ ARGS *ap;
+ CDPATH *cdp;
+ char *dir; /* XXX END OF THE STACK, DON'T TRUST GETCWD. */
+ char buf[MAXPATHLEN * 2];
+
+ /*
+ * !!!
+ * Historic practice is that the cd isn't attempted if the file has
+ * been modified, unless its name begins with a leading '/' or the
+ * force flag is set.
+ */
+ if (F_ISSET(ep, F_MODIFIED) &&
+ !F_ISSET(cmdp, E_FORCE) && sp->frp->name[0] != '/') {
+ msgq(sp, M_ERR,
+ "File modified since last complete write; write or use ! to override");
+ return (1);
+ }
+
+ switch (cmdp->argc) {
+ case 0:
+ /* If no argument, change to the user's home directory. */
+ if ((dir = getenv("HOME")) == NULL) {
+ if ((pw = getpwuid(getuid())) == NULL ||
+ pw->pw_dir == NULL || pw->pw_dir[0] == '\0') {
+ msgq(sp, M_ERR,
+ "Unable to find home directory location");
+ return (1);
+ }
+ dir = pw->pw_dir;
+ }
+ break;
+ case 1:
+ dir = cmdp->argv[0]->bp;
+ break;
+ default:
+ abort();
+ }
+
+ /* Try the current directory first. */
+ if (!chdir(dir))
+ goto ret;
+
+ /*
+ * If moving to the user's home directory, or, the path begins with
+ * "/", "./" or "../", it's the only place we try.
+ */
+ if (cmdp->argc == 0 ||
+ (ap = cmdp->argv[0])->bp[0] == '/' ||
+ ap->len == 1 && ap->bp[0] == '.' ||
+ ap->len >= 2 && ap->bp[0] == '.' && ap->bp[1] == '.' &&
+ (ap->bp[2] == '/' || ap->bp[2] == '\0'))
+ goto err;
+
+ /* If the user has a CDPATH variable, try its elements. */
+ for (cdp = EXP(sp)->cdq.tqh_first; cdp != NULL; cdp = cdp->q.tqe_next) {
+ (void)snprintf(buf, sizeof(buf), "%s/%s", cdp->path, dir);
+ if (!chdir(buf)) {
+ret: if (getcwd(buf, sizeof(buf)) != NULL)
+ msgq(sp, M_INFO, "New directory: %s", buf);
+ return (0);
+ }
+ }
+err: msgq(sp, M_SYSERR, "%s", dir);
+ return (1);
+}
+
+#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/ex/ex_delete.c b/usr.bin/vi/ex/ex_delete.c
new file mode 100644
index 000000000000..08c4250e3c12
--- /dev/null
+++ b/usr.bin/vi/ex/ex_delete.c
@@ -0,0 +1,92 @@
+/*-
+ * 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_delete.c 8.12 (Berkeley) 8/5/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_delete: [line [,line]] d[elete] [buffer] [count] [flags]
+ *
+ * Delete lines from the file.
+ */
+int
+ex_delete(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t lno;
+
+ /*
+ * !!!
+ * Historically, lines deleted in ex were not placed in the numeric
+ * buffers. We follow historic practice so that we don't overwrite
+ * vi buffers accidentally.
+ */
+ if (cut(sp, ep,
+ F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
+ &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE))
+ return (1);
+
+ /* Delete the lines. */
+ if (delete(sp, ep, &cmdp->addr1, &cmdp->addr2, 1))
+ return (1);
+
+ /* Set the cursor to the line after the last line deleted. */
+ sp->lno = cmdp->addr1.lno;
+
+ /* Or the last line in the file if deleted to the end of the file. */
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (sp->lno > lno)
+ sp->lno = lno;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_digraph.c b/usr.bin/vi/ex/ex_digraph.c
new file mode 100644
index 000000000000..07399234ba9e
--- /dev/null
+++ b/usr.bin/vi/ex/ex_digraph.c
@@ -0,0 +1,324 @@
+/*-
+ * 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_digraph.c 8.6 (Berkeley) 3/25/94";
+#endif /* not lint */
+
+#ifndef NO_DIGRAPH
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static void do_digraph __P((SCR *, EXF *, int, u_char *));
+
+/* This stuff is used to build the default digraphs table. */
+static u_char digtable[][4] = {
+# ifdef CS_IBMPC
+ "C,\200", "u\"\1", "e'\2", "a^\3",
+ "a\"\4", "a`\5", "a@\6", "c,\7",
+ "e^\10", "e\"\211", "e`\12", "i\"\13",
+ "i^\14", "i`\15", "A\"\16", "A@\17",
+ "E'\20", "ae\21", "AE\22", "o^\23",
+ "o\"\24", "o`\25", "u^\26", "u`\27",
+ "y\"\30", "O\"\31", "U\"\32", "a'\240",
+ "i'!", "o'\"", "u'#", "n~$",
+ "N~%", "a-&", "o-'", "~?(",
+ "~!-", "\"<.", "\">/",
+# ifdef CS_SPECIAL
+ "2/+", "4/,", "^+;", "^q<",
+ "^c=", "^r>", "^t?", "pp]",
+ "^^^", "oo_", "*a`", "*ba",
+ "*pc", "*Sd", "*se", "*uf",
+ "*tg", "*Ph", "*Ti", "*Oj",
+ "*dk", "*Hl", "*hm", "*En",
+ "*No", "eqp", "pmq", "ger",
+ "les", "*It", "*iu", "*/v",
+ "*=w", "sq{", "^n|", "^2}",
+ "^3~", "^_\377",
+# endif /* CS_SPECIAL */
+# endif /* CS_IBMPC */
+# ifdef CS_LATIN1
+ "~!!", "a-*", "\">+", "o-:",
+ "\"<>", "~??",
+
+ "A`@", "A'A", "A^B", "A~C",
+ "A\"D", "A@E", "AEF", "C,G",
+ "E`H", "E'I", "E^J", "E\"K",
+ "I`L", "I'M", "I^N", "I\"O",
+ "-DP", "N~Q", "O`R", "O'S",
+ "O^T", "O~U", "O\"V", "O/X",
+ "U`Y", "U'Z", "U^[", "U\"\\",
+ "Y'_",
+
+ "a``", "a'a", "a^b", "a~c",
+ "a\"d", "a@e", "aef", "c,g",
+ "e`h", "e'i", "e^j", "e\"k",
+ "i`l", "i'm", "i^n", "i\"o",
+ "-dp", "n~q", "o`r", "o's",
+ "o^t", "o~u", "o\"v", "o/x",
+ "u`y", "u'z", "u^{", "u\"|",
+ "y'~",
+# endif /* CS_LATIN1 */
+ ""
+};
+
+int
+digraph_init(sp)
+ SCR *sp;
+{
+ int i;
+
+ for (i = 0; *digtable[i]; i++)
+ do_digraph(sp, NULL, 0, digtable[i]);
+ do_digraph(sp, NULL, 0, NULL);
+ return (0);
+}
+
+int
+ex_digraph(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ do_digraph(sp, ep, F_ISSET(cmdp, E_FORCE), cmdp->argv[0]->bp);
+ return (0);
+}
+
+static struct _DIG
+{
+ struct _DIG *next;
+ char key1;
+ char key2;
+ char dig;
+ char save;
+} *digs;
+
+int
+digraph(sp, key1, key2)
+ SCR *sp;
+ char key1; /* the underlying character */
+ char key2; /* the second character */
+{
+ int new_key;
+ register struct _DIG *dp;
+
+ /* if digraphs are disabled, then just return the new char */
+ if (O_ISSET(sp, O_DIGRAPH))
+ {
+ return key2;
+ }
+
+ /* remember the new key, so we can return it if this isn't a digraph */
+ new_key = key2;
+
+ /* sort key1 and key2, so that their original order won't matter */
+ if (key1 > key2)
+ {
+ key2 = key1;
+ key1 = new_key;
+ }
+
+ /* scan through the digraph chart */
+ for (dp = digs;
+ dp && (dp->key1 != key1 || dp->key2 != key2);
+ dp = dp->next)
+ {
+ }
+
+ /* if this combination isn't in there, just use the new key */
+ if (!dp)
+ {
+ return new_key;
+ }
+
+ /* else use the digraph key */
+ return dp->dig;
+}
+
+/* this function lists or defines digraphs */
+static void
+do_digraph(sp, ep, bang, extra)
+ SCR *sp;
+ EXF *ep;
+ int bang;
+ u_char *extra;
+{
+ int dig;
+ register struct _DIG *dp;
+ struct _DIG *prev;
+ static int user_defined = 0; /* boolean: are all later digraphs user-defined? */
+ char listbuf[8];
+
+ /* if "extra" is NULL, then we've reached the end of the built-ins */
+ if (!extra)
+ {
+ user_defined = 1;
+ return;
+ }
+
+ /* if no args, then display the existing digraphs */
+ if (*extra < ' ')
+ {
+ listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
+ listbuf[7] = '\0';
+ for (dig = 0, dp = digs; dp; dp = dp->next)
+ {
+ if (dp->save || bang)
+ {
+ dig += 7;
+ if (dig >= sp->cno)
+ {
+ addch('\n');
+ refresh();
+ dig = 7;
+ }
+ listbuf[3] = dp->key1;
+ listbuf[4] = dp->key2;
+ listbuf[6] = dp->dig;
+ addstr(listbuf);
+ }
+ }
+ addch('\n');
+ refresh();
+ return;
+ }
+
+ /* make sure we have at least two characters */
+ if (!extra[1])
+ {
+ msgq(sp, M_ERR,
+ "Digraphs must be composed of two characters");
+ return;
+ }
+
+ /* sort key1 and key2, so that their original order won't matter */
+ if (extra[0] > extra[1])
+ {
+ dig = extra[0];
+ extra[0] = extra[1];
+ extra[1] = dig;
+ }
+
+ /* locate the new digraph character */
+ for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
+ {
+ }
+ dig = extra[dig];
+ if (!bang && dig)
+ {
+ dig |= 0x80;
+ }
+
+ /* search for the digraph */
+ for (prev = (struct _DIG *)0, dp = digs;
+ dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
+ prev = dp, dp = dp->next)
+ {
+ }
+
+ /* deleting the digraph? */
+ if (!dig)
+ {
+ if (!dp)
+ {
+#ifndef CRUNCH
+ msgq(sp, M_ERR,
+ "%c%c not a digraph", extra[0], extra[1]);
+#endif
+ return;
+ }
+ if (prev)
+ prev->next = dp->next;
+ else
+ digs = dp->next;
+ free(dp);
+ return;
+ }
+
+ /* if necessary, create a new digraph struct for the new digraph */
+ if (dig && !dp)
+ {
+ MALLOC(sp, dp, struct _DIG *, sizeof(struct _DIG));
+ if (dp == NULL)
+ return;
+ if (prev)
+ prev->next = dp;
+ else
+ digs = dp;
+ dp->next = (struct _DIG *)0;
+ }
+
+ /* assign it the new digraph value */
+ dp->key1 = extra[0];
+ dp->key2 = extra[1];
+ dp->dig = dig;
+ dp->save = user_defined;
+}
+
+void
+digraph_save(sp, fd)
+ SCR *sp;
+ int fd;
+{
+ static char buf[] = "digraph! XX Y\n";
+ register struct _DIG *dp;
+
+ for (dp = digs; dp; dp = dp->next)
+ {
+ if (dp->save)
+ {
+ buf[9] = dp->key1;
+ buf[10] = dp->key2;
+ buf[12] = dp->dig;
+ write(fd, buf, (unsigned)14);
+ }
+ }
+}
+#endif
diff --git a/usr.bin/vi/ex/ex_display.c b/usr.bin/vi/ex/ex_display.c
new file mode 100644
index 000000000000..139127e602b3
--- /dev/null
+++ b/usr.bin/vi/ex/ex_display.c
@@ -0,0 +1,169 @@
+/*-
+ * 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_display.c 8.21 (Berkeley) 8/3/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "tag.h"
+#include "excmd.h"
+
+static int bdisplay __P((SCR *, EXF *));
+static void db __P((SCR *, CB *, CHAR_T *));
+
+/*
+ * ex_display -- :display b[uffers] | s[creens] | t[ags]
+ *
+ * Display buffers, tags or screens.
+ */
+int
+ex_display(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ switch (cmdp->argv[0]->bp[0]) {
+ case 'b':
+#undef ARG
+#define ARG "buffers"
+ if (cmdp->argv[0]->len >= sizeof(ARG) ||
+ memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len))
+ break;
+ return (bdisplay(sp, ep));
+ case 's':
+#undef ARG
+#define ARG "screens"
+ if (cmdp->argv[0]->len >= sizeof(ARG) ||
+ memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len))
+ break;
+ return (ex_sdisplay(sp, ep));
+ case 't':
+#undef ARG
+#define ARG "tags"
+ if (cmdp->argv[0]->len >= sizeof(ARG) ||
+ memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len))
+ break;
+ return (ex_tagdisplay(sp, ep));
+ }
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+}
+
+/*
+ * bdisplay --
+ *
+ * Display buffers.
+ */
+static int
+bdisplay(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ CB *cbp;
+
+ if (sp->gp->cutq.lh_first == NULL && sp->gp->dcbp == NULL) {
+ (void)ex_printf(EXCOOKIE, "No cut buffers to display.\n");
+ return (0);
+ }
+
+ /* Buffers can be infinitely long, make it interruptible. */
+ F_SET(sp, S_INTERRUPTIBLE);
+
+ /* Display regular cut buffers. */
+ for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) {
+ if (isdigit(cbp->name))
+ continue;
+ if (cbp->textq.cqh_first != (void *)&cbp->textq)
+ db(sp, cbp, NULL);
+ if (INTERRUPTED(sp))
+ return (0);
+ }
+ /* Display numbered buffers. */
+ for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) {
+ if (!isdigit(cbp->name))
+ continue;
+ if (cbp->textq.cqh_first != (void *)&cbp->textq)
+ db(sp, cbp, NULL);
+ if (INTERRUPTED(sp))
+ return (0);
+ }
+ /* Display default buffer. */
+ if ((cbp = sp->gp->dcbp) != NULL)
+ db(sp, cbp, "default buffer");
+ return (0);
+}
+
+/*
+ * db --
+ * Display a buffer.
+ */
+static void
+db(sp, cbp, name)
+ SCR *sp;
+ CB *cbp;
+ CHAR_T *name;
+{
+ CHAR_T *p;
+ TEXT *tp;
+ size_t len;
+
+ (void)ex_printf(EXCOOKIE, "********** %s%s\n",
+ name == NULL ? KEY_NAME(sp, cbp->name) : name,
+ F_ISSET(cbp, CB_LMODE) ? " (line mode)" : " (character mode)");
+ for (tp = cbp->textq.cqh_first;
+ tp != (void *)&cbp->textq; tp = tp->q.cqe_next) {
+ for (len = tp->len, p = tp->lb; len--; ++p) {
+ (void)ex_printf(EXCOOKIE, "%s", KEY_NAME(sp, *p));
+ if (INTERRUPTED(sp))
+ return;
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+ }
+}
diff --git a/usr.bin/vi/ex/ex_edit.c b/usr.bin/vi/ex/ex_edit.c
new file mode 100644
index 000000000000..bfe0a2ae24ae
--- /dev/null
+++ b/usr.bin/vi/ex/ex_edit.c
@@ -0,0 +1,122 @@
+/*-
+ * 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_edit.c 8.18 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_edit -- :e[dit][!] [+cmd] [file]
+ * :vi[sual][!] [+cmd] [file]
+ *
+ * Edit a file; if none specified, re-edit the current file. The second
+ * form of the command can only be executed while in vi mode. See the
+ * hack in ex.c:ex_cmd().
+ *
+ * !!!
+ * Historic vi didn't permit the '+' command form without specifying
+ * a file name as well.
+ */
+int
+ex_edit(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS *ap;
+ FREF *frp;
+
+ frp = sp->frp;
+ switch (cmdp->argc) {
+ case 0:
+ /*
+ * If the name has been changed, we edit that file, not the
+ * original name. If the user was editing a temporary file,
+ * create another one. The reason for this is that we do
+ * special exit processing of temporary files, and reusing
+ * them is tricky.
+ */
+ if (F_ISSET(frp, FR_TMPFILE)) {
+ if ((frp = file_add(sp, NULL)) == NULL)
+ return (1);
+ } else {
+ if ((frp = file_add(sp, frp->name)) == NULL)
+ return (1);
+ set_alt_name(sp, sp->frp->name);
+ }
+ break;
+ case 1:
+ ap = cmdp->argv[0];
+ if ((frp = file_add(sp, ap->bp)) == NULL)
+ return (1);
+ set_alt_name(sp, ap->bp);
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * Check for modifications.
+ *
+ * !!!
+ * Contrary to POSIX 1003.2-1992, autowrite did not affect :edit.
+ */
+ if (file_m2(sp, ep, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+
+ /* Switch files. */
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_equal.c b/usr.bin/vi/ex/ex_equal.c
new file mode 100644
index 000000000000..a80d72352db8
--- /dev/null
+++ b/usr.bin/vi/ex/ex_equal.c
@@ -0,0 +1,86 @@
+/*-
+ * 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_equal.c 8.6 (Berkeley) 4/26/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_equal -- :address =
+ */
+int
+ex_equal(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t lno;
+
+ /*
+ * Print out the line number matching the specified address,
+ * or the number of the last line in the file if no address
+ * specified.
+ *
+ * !!!
+ * Historically, ":0=" displayed 0, and ":=" or ":1=" in an
+ * empty file displayed 1. Until somebody complains loudly,
+ * we're going to do it right. The tables in excmd.c permit
+ * lno to get away with any address from 0 to the end of the
+ * file, which, in an empty file, is 0.
+ */
+ if (F_ISSET(cmdp, E_ADDRDEF)) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ } else
+ lno = cmdp->addr1.lno;
+
+ (void)ex_printf(EXCOOKIE, "%ld\n", lno);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_exit.c b/usr.bin/vi/ex/ex_exit.c
new file mode 100644
index 000000000000..3f0a3622a2ab
--- /dev/null
+++ b/usr.bin/vi/ex/ex_exit.c
@@ -0,0 +1,79 @@
+/*-
+ * 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_exit.c 8.13 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_quit -- :quit[!]
+ * Quit.
+ */
+int
+ex_quit(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ int force;
+
+ force = F_ISSET(cmdp, E_FORCE);
+
+ /* Check for modifications. */
+ if (file_m2(sp, ep, force))
+ return (1);
+
+ /* Check for more files to edit. */
+ if (ex_ncheck(sp, force))
+ return (1);
+
+ F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_file.c b/usr.bin/vi/ex/ex_file.c
new file mode 100644
index 000000000000..b2c68e762dc1
--- /dev/null
+++ b/usr.bin/vi/ex/ex_file.c
@@ -0,0 +1,103 @@
+/*-
+ * 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_file.c 8.10 (Berkeley) 8/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_file -- :f[ile] [name]
+ * Change the file's name and display the status line.
+ */
+int
+ex_file(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ CHAR_T *p;
+ FREF *frp;
+
+ switch (cmdp->argc) {
+ case 0:
+ break;
+ case 1:
+ frp = sp->frp;
+
+ /* Make sure can allocate enough space. */
+ if ((p = v_strdup(sp,
+ cmdp->argv[0]->bp, cmdp->argv[0]->len)) == NULL)
+ return (1);
+
+ /* If already have a file name, it becomes the alternate. */
+ if (!F_ISSET(frp, FR_TMPFILE))
+ set_alt_name(sp, frp->name);
+
+ /* Free the previous name. */
+ free(frp->name);
+ frp->name = p;
+
+ /*
+ * The read-only bit follows the file name; clear it.
+ * The file has a real name, it's no longer a temporary.
+ */
+ F_CLR(frp, FR_RDONLY | FR_TMPFILE);
+
+ /* Have to force a write if the file exists, next time. */
+ F_SET(frp, FR_NAMECHANGE);
+ break;
+ default:
+ abort();
+ }
+ return (msg_status(sp, ep, sp->lno, 1));
+}
diff --git a/usr.bin/vi/ex/ex_global.c b/usr.bin/vi/ex/ex_global.c
new file mode 100644
index 000000000000..624bf8e51136
--- /dev/null
+++ b/usr.bin/vi/ex/ex_global.c
@@ -0,0 +1,400 @@
+/*-
+ * 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_global.c 8.41 (Berkeley) 8/9/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+enum which {GLOBAL, VGLOBAL};
+
+static int global __P((SCR *, EXF *, EXCMDARG *, enum which));
+
+/*
+ * ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands]
+ * Exec on lines matching a pattern.
+ */
+int
+ex_global(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (global(sp, ep,
+ cmdp, F_ISSET(cmdp, E_FORCE) ? VGLOBAL : GLOBAL));
+}
+
+/*
+ * ex_vglobal -- [line [,line]] v[global] /pattern/ [commands]
+ * Exec on lines not matching a pattern.
+ */
+int
+ex_vglobal(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (global(sp, ep, cmdp, VGLOBAL));
+}
+
+static int
+global(sp, ep, cmdp, cmd)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ enum which cmd;
+{
+ MARK abs;
+ 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;
+ char *cb, *ptrn, *p, *t;
+
+ /*
+ * Skip leading white space. Historic vi allowed any non-
+ * alphanumeric to serve as the global command delimiter.
+ */
+ for (p = cmdp->argv[0]->bp; isblank(*p); ++p);
+ if (*p == '\0' || isalnum(*p)) {
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+ delim = *p++;
+
+ /*
+ * Get the pattern string, toss escaped characters.
+ *
+ * QUOTING NOTE:
+ * Only toss an escaped character if it escapes a delimiter.
+ */
+ for (ptrn = t = p;;) {
+ if (p[0] == '\0' || p[0] == delim) {
+ if (p[0] == delim)
+ ++p;
+ /*
+ * !!!
+ * Nul terminate the pattern string -- it's passed
+ * to regcomp which doesn't understand anything else.
+ */
+ *t = '\0';
+ break;
+ }
+ if (p[0] == '\\' && p[1] == delim)
+ ++p;
+ *t++ = *p++;
+ }
+
+ /* If the pattern string is empty, use the last one. */
+ if (*ptrn == '\0') {
+ if (!F_ISSET(sp, S_SRE_SET)) {
+ msgq(sp, M_ERR, "No previous regular expression");
+ return (1);
+ }
+ re = &sp->sre;
+ } else {
+ /* Set RE flags. */
+ reflags = 0;
+ if (O_ISSET(sp, O_EXTENDED))
+ reflags |= REG_EXTENDED;
+ if (O_ISSET(sp, O_IGNORECASE))
+ reflags |= REG_ICASE;
+
+ /* Convert vi-style RE's to POSIX 1003.2 RE's. */
+ if (re_conv(sp, &ptrn, &replaced))
+ return (1);
+
+ /* Compile the RE. */
+ re = &lre;
+ eval = regcomp(re, ptrn, reflags);
+
+ /* Free up any allocated memory. */
+ if (replaced)
+ FREE_SPACE(sp, ptrn, 0);
+
+ if (eval) {
+ re_error(sp, eval, re);
+ return (1);
+ }
+
+ /*
+ * Set saved RE. Historic practice is that
+ * globals set direction as well as the RE.
+ */
+ sp->sre = lre;
+ sp->searchdir = FORWARD;
+ F_SET(sp, S_SRE_SET);
+ }
+
+ /*
+ * Get a copy of the command string; the default command is print.
+ * Don't worry about a set of <blank>s with no command, that will
+ * default to print in the ex parser.
+ */
+ if ((clen = strlen(p)) == 0) {
+ p = "p";
+ clen = 1;
+ }
+ MALLOC_RET(sp, cb, char *, clen);
+ memmove(cb, p, clen);
+
+ /*
+ * The global commands sets the substitute RE as well as
+ * the everything-else RE.
+ */
+ sp->subre = sp->sre;
+ F_SET(sp, S_SUBRE_SET);
+
+ /* Set the global flag. */
+ F_SET(sp, S_GLOBAL);
+
+ /* The global commands always set the previous context mark. */
+ abs.lno = sp->lno;
+ abs.cno = sp->cno;
+ if (mark_set(sp, ep, ABSMARK1, &abs, 1))
+ goto err;
+
+ /*
+ * For each line... The semantics of global matching are that we first
+ * have to decide which lines are going to get passed to the command,
+ * and then pass them to the command, ignoring other changes. There's
+ * really no way to do this in a single pass, since arbitrary line
+ * creation, deletion and movement can be done in the ex command. For
+ * example, a good vi clone test is ":g/X/mo.-3", or "g/X/.,.+1d".
+ * 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.
+ */
+ exp = EXP(sp);
+ for (rval = 0, lno = cmdp->addr1.lno,
+ elno = cmdp->addr2.lno; lno <= elno; ++lno) {
+ /* Someone's unhappy, time to stop. */
+ if (INTERRUPTED(sp))
+ goto interrupted;
+
+ /* Get the line and search for a match. */
+ if ((t = file_gline(sp, ep, lno, &len)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ goto err;
+ }
+ match[0].rm_so = 0;
+ match[0].rm_eo = len;
+ switch(eval = regexec(re, t, 1, match, REG_STARTEND)) {
+ case 0:
+ if (cmd == VGLOBAL)
+ continue;
+ break;
+ case REG_NOMATCH:
+ if (cmd == GLOBAL)
+ continue;
+ break;
+ default:
+ re_error(sp, eval, re);
+ goto err;
+ }
+
+ /* If follows the last entry, extend the last entry's range. */
+ if ((rp = exp->rangeq.cqh_last) != (void *)&exp->rangeq &&
+ rp->stop == lno - 1) {
+ ++rp->stop;
+ continue;
+ }
+
+ /* Allocate a new range, and append it to the list. */
+ CALLOC(sp, rp, RANGE *, 1, sizeof(RANGE));
+ if (rp == NULL)
+ goto err;
+ rp->start = rp->stop = lno;
+ CIRCLEQ_INSERT_TAIL(&exp->rangeq, rp, q);
+ }
+
+ exp = EXP(sp);
+ exp->range_lno = OOBLNO;
+ for (;;) {
+ /*
+ * Start at the beginning of the range each time, it may have
+ * been changed (or exhausted) if lines were inserted/deleted.
+ */
+ if ((rp = exp->rangeq.cqh_first) == (void *)&exp->rangeq)
+ break;
+ if (rp->start > rp->stop) {
+ CIRCLEQ_REMOVE(&exp->rangeq, exp->rangeq.cqh_first, q);
+ free(rp);
+ continue;
+ }
+
+ /*
+ * Execute the command, setting the cursor to the line so that
+ * relative addressing works. This means that the cursor moves
+ * to the last line sent to the command, by default, even if
+ * the command fails.
+ */
+ exp->range_lno = sp->lno = rp->start++;
+ if (ex_cmd(sp, ep, cb, clen, 0))
+ goto err;
+
+ /* Someone's unhappy, time to stop. */
+ if (INTERRUPTED(sp)) {
+interrupted: msgq(sp, M_INFO, "Interrupted");
+ break;
+ }
+ }
+
+ /* Set the cursor to the new value, making sure it exists. */
+ if (exp->range_lno != OOBLNO) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ sp->lno =
+ lno < exp->range_lno ? (lno ? lno : 1) : exp->range_lno;
+ }
+ if (0) {
+err: rval = 1;
+ }
+
+ /* Command we ran may have set the autoprint flag, clear it. */
+ F_CLR(exp, EX_AUTOPRINT);
+
+ /* Clear the global flag. */
+ F_CLR(sp, S_GLOBAL);
+
+ /* Free any remaining ranges and the command buffer. */
+ while ((rp = exp->rangeq.cqh_first) != (void *)&exp->rangeq) {
+ CIRCLEQ_REMOVE(&exp->rangeq, exp->rangeq.cqh_first, q);
+ free(rp);
+ }
+ free(cb);
+ return (rval);
+}
+
+/*
+ * global_insdel --
+ * Update the ranges based on an insertion or deletion.
+ */
+void
+global_insdel(sp, ep, op, lno)
+ SCR *sp;
+ EXF *ep;
+ enum operation op;
+ recno_t lno;
+{
+ EX_PRIVATE *exp;
+ RANGE *nrp, *rp;
+
+ exp = EXP(sp);
+
+ switch (op) {
+ case LINE_APPEND:
+ return;
+ case LINE_DELETE:
+ for (rp = exp->rangeq.cqh_first;
+ rp != (void *)&exp->rangeq; rp = nrp) {
+ nrp = rp->q.cqe_next;
+ /* If range less than the line, ignore it. */
+ if (rp->stop < lno)
+ continue;
+ /* If range greater than the line, decrement range. */
+ if (rp->start > lno) {
+ --rp->start;
+ --rp->stop;
+ continue;
+ }
+ /* Lno is inside the range, decrement the end point. */
+ if (rp->start > --rp->stop) {
+ CIRCLEQ_REMOVE(&exp->rangeq, rp, q);
+ free(rp);
+ }
+ }
+ break;
+ case LINE_INSERT:
+ for (rp = exp->rangeq.cqh_first;
+ rp != (void *)&exp->rangeq; rp = rp->q.cqe_next) {
+ /* If range less than the line, ignore it. */
+ if (rp->stop < lno)
+ continue;
+ /* If range greater than the line, increment range. */
+ if (rp->start >= lno) {
+ ++rp->start;
+ ++rp->stop;
+ continue;
+ }
+ /*
+ * Lno is inside the range, so the range must be split.
+ * Since we're inserting a new element, neither range
+ * can be exhausted.
+ */
+ CALLOC(sp, nrp, RANGE *, 1, sizeof(RANGE));
+ if (nrp == NULL) {
+ F_SET(sp, S_INTERRUPTED);
+ return;
+ }
+ nrp->start = lno + 1;
+ nrp->stop = rp->stop + 1;
+ rp->stop = lno - 1;
+ CIRCLEQ_INSERT_AFTER(&exp->rangeq, rp, nrp, q);
+ rp = nrp;
+ }
+ break;
+ case LINE_RESET:
+ return;
+ }
+ /*
+ * If the command deleted/inserted lines, the cursor moves to
+ * the line after the deleted/inserted line.
+ */
+ exp->range_lno = lno;
+}
diff --git a/usr.bin/vi/ex/ex_init.c b/usr.bin/vi/ex/ex_init.c
new file mode 100644
index 000000000000..79b0e4b9a4af
--- /dev/null
+++ b/usr.bin/vi/ex/ex_init.c
@@ -0,0 +1,202 @@
+/*-
+ * 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_init.c 8.16 (Berkeley) 8/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "tag.h"
+
+/*
+ * ex_screen_copy --
+ * Copy ex screen.
+ */
+int
+ex_screen_copy(orig, sp)
+ SCR *orig, *sp;
+{
+ EX_PRIVATE *oexp, *nexp;
+
+ /* Create the private ex structure. */
+ CALLOC_RET(orig, nexp, EX_PRIVATE *, 1, sizeof(EX_PRIVATE));
+ sp->ex_private = nexp;
+
+ /* Initialize queues. */
+ TAILQ_INIT(&nexp->tagq);
+ TAILQ_INIT(&nexp->tagfq);
+ TAILQ_INIT(&nexp->cdq);
+ CIRCLEQ_INIT(&nexp->rangeq);
+
+ if (orig == NULL) {
+ nexp->at_lbuf_set = 0;
+ } else {
+ oexp = EXP(orig);
+
+ nexp->at_lbuf = oexp->at_lbuf;
+ nexp->at_lbuf_set = oexp->at_lbuf_set;
+
+ if (oexp->lastbcomm != NULL &&
+ (nexp->lastbcomm = strdup(oexp->lastbcomm)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return(1);
+ }
+
+ if (ex_tagcopy(orig, sp))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * ex_screen_end --
+ * End a vi screen.
+ */
+int
+ex_screen_end(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ int rval;
+
+ rval = 0;
+ exp = EXP(sp);
+
+ if (argv_free(sp))
+ rval = 1;
+
+ if (exp->ibp != NULL)
+ FREE(exp->ibp, exp->ibp_len);
+
+ 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;
+
+ return (rval);
+}
+
+/*
+ * ex_init --
+ * Initialize ex.
+ */
+int
+ex_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ size_t len;
+
+ /*
+ * The default address is the last line of the file. If the address
+ * set bit is on for this file, load the address, ensuring that it
+ * exists.
+ */
+ if (F_ISSET(sp->frp, FR_CURSORSET)) {
+ sp->lno = sp->frp->lno;
+ sp->cno = sp->frp->cno;
+
+ if (file_gline(sp, ep, sp->lno, &len) == NULL) {
+ if (file_lline(sp, ep, &sp->lno))
+ return (1);
+ if (sp->lno == 0)
+ sp->lno = 1;
+ sp->cno = 0;
+ } else if (sp->cno >= len)
+ sp->cno = 0;
+ } else {
+ if (file_lline(sp, ep, &sp->lno))
+ return (1);
+ if (sp->lno == 0)
+ sp->lno = 1;
+ sp->cno = 0;
+ }
+
+ /* Display the status line. */
+ return (msg_status(sp, ep, sp->lno, 0));
+}
+
+/*
+ * ex_end --
+ * End ex session.
+ */
+int
+ex_end(sp)
+ SCR *sp;
+{
+ return (0);
+}
+
+/*
+ * ex_optchange --
+ * Handle change of options for vi.
+ */
+int
+ex_optchange(sp, opt)
+ SCR *sp;
+ 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)));
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_join.c b/usr.bin/vi/ex/ex_join.c
new file mode 100644
index 000000000000..d561f0a5bd61
--- /dev/null
+++ b/usr.bin/vi/ex/ex_join.c
@@ -0,0 +1,200 @@
+/*-
+ * 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_join.c 8.12 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_join -- :[line [,line]] j[oin][!] [count] [flags]
+ * Join lines.
+ */
+int
+ex_join(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t from, to;
+ size_t blen, clen, len, tlen;
+ int echar, extra, first;
+ char *bp, *p, *tbp;
+
+ from = cmdp->addr1.lno;
+ to = cmdp->addr2.lno;
+
+ /* Check for no lines to join. */
+ if ((p = file_gline(sp, ep, from + 1, &len)) == NULL) {
+ msgq(sp, M_ERR, "No following lines to join");
+ return (1);
+ }
+
+ GET_SPACE_RET(sp, bp, blen, 256);
+
+ /*
+ * The count for the join command was off-by-one,
+ * historically, to other counts for other commands.
+ */
+ if (F_ISSET(cmdp, E_COUNT))
+ ++cmdp->addr2.lno;
+
+ /*
+ * If only a single address specified, or, the same address
+ * specified twice, the from/two addresses will be the same.
+ */
+ if (cmdp->addr1.lno == cmdp->addr2.lno)
+ ++cmdp->addr2.lno;
+
+ clen = tlen = 0;
+ 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.
+ */
+ if ((p = file_gline(sp, ep, from, &len)) == NULL) {
+ cmdp->addr2.lno = from - 1;
+ break;
+ }
+
+ /* Empty lines just go away. */
+ if (len == 0)
+ continue;
+
+ /*
+ * Get more space if necessary. Note, tlen isn't the length
+ * of the new line, it's roughly the amount of space needed.
+ * tbp - bp is the length of the new line.
+ */
+ tlen += len + 2;
+ ADD_SPACE_RET(sp, bp, blen, tlen);
+ tbp = bp + clen;
+
+ /*
+ * Historic practice:
+ *
+ * If force specified, join without modification.
+ * If the current line ends with whitespace, strip leading
+ * whitespace from the joined line.
+ * If the next line starts with a ), do nothing.
+ * If the current line ends with ., ? or !, insert two spaces.
+ * Else, insert one space.
+ *
+ * Echar is the last character in the last line joined.
+ */
+ extra = 0;
+ if (!first && !F_ISSET(cmdp, E_FORCE)) {
+ if (isblank(echar))
+ for (; len && isblank(*p); --len, ++p);
+ else if (p[0] != ')') {
+ if (strchr(".?!", echar)) {
+ *tbp++ = ' ';
+ ++clen;
+ extra = 1;
+ }
+ *tbp++ = ' ';
+ ++clen;
+ for (; len && isblank(*p); --len, ++p);
+ }
+ }
+
+ if (len != 0) {
+ memmove(tbp, p, len);
+ tbp += len;
+ clen += len;
+ echar = p[len - 1];
+ } else
+ echar = ' ';
+
+ /*
+ * Historic practice for vi was to put the cursor at the first
+ * inserted whitespace character, if there was one, or the
+ * first character of the joined line, if there wasn't, or the
+ * last character of the line if joined to an empty line. If
+ * a count was specified, the cursor was moved as described
+ * for the first line joined, ignoring subsequent lines. If
+ * the join was a ':' command, the cursor was placed at the
+ * first non-blank character of the line unless the cursor was
+ * "attracted" to the end of line when the command was executed
+ * in which case it moved to the new end of line. There are
+ * probably several more special cases, but frankly, my dear,
+ * I don't give a damn. This implementation puts the cursor
+ * on the first inserted whitespace character, the first
+ * character of the joined line, or the last character of the
+ * line regardless. Note, if the cursor isn't on the joined
+ * line (possible with : commands), it is reset to the starting
+ * line.
+ */
+ if (first) {
+ sp->cno = (tbp - bp) - (1 + extra);
+ first = 0;
+ } else
+ sp->cno = (tbp - bp) - len - (1 + extra);
+ }
+ sp->lno = cmdp->addr1.lno;
+
+ /* Delete the joined lines. */
+ for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to)
+ if (file_dline(sp, ep, to))
+ goto err;
+
+ /* 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);
+ }
+ FREE_SPACE(sp, bp, blen);
+
+ sp->rptlines[L_JOINED] += (cmdp->addr2.lno - cmdp->addr1.lno) + 1;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_map.c b/usr.bin/vi/ex/ex_map.c
new file mode 100644
index 000000000000..a1f1915bc703
--- /dev/null
+++ b/usr.bin/vi/ex/ex_map.c
@@ -0,0 +1,160 @@
+/*-
+ * 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_map.c 8.17 (Berkeley) 7/16/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_map -- :map[!] [input] [replacement]
+ * Map a key/string or display mapped keys.
+ *
+ * Historical note:
+ * Historic vi maps were fairly bizarre, and likely to differ in
+ * very subtle and strange ways from this implementation. Two
+ * things worth noting are that vi would often hang or drop core
+ * if the map was strange enough (ex: map X "xy$@x^V), or, simply
+ * not work. One trick worth remembering is that if you put a
+ * mark at the start of the map, e.g. map X mx"xy ...), or if you
+ * put the map in a .exrc file, things would often work much better.
+ * No clue why.
+ */
+int
+ex_map(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ enum seqtype stype;
+ CHAR_T *input, *p;
+
+ stype = F_ISSET(cmdp, E_FORCE) ? SEQ_INPUT : SEQ_COMMAND;
+
+ switch (cmdp->argc) {
+ case 0:
+ if (seq_dump(sp, stype, 1) == 0)
+ msgq(sp, M_INFO, "No %s map entries",
+ stype == SEQ_INPUT ? "input" : "command");
+ return (0);
+ case 2:
+ input = cmdp->argv[0]->bp;
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * If the mapped string is #[0-9]* (and wasn't quoted) then store
+ * the function key mapping, and call the screen specific routine.
+ * Note, if the screen specific routine is able to create the
+ * mapping, the SEQ_FUNCMAP type stays around, maybe the next screen
+ * type can get it right.
+ */
+ if (input[0] == '#') {
+ for (p = input + 1; isdigit(*p); ++p);
+ if (p[0] != '\0')
+ goto nofunc;
+
+ if (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len,
+ cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, SEQ_FUNCMAP))
+ return (1);
+ return (sp->s_fmap(sp, stype, input, cmdp->argv[0]->len,
+ cmdp->argv[1]->bp, cmdp->argv[1]->len));
+ }
+
+ /* Some single keys may not be remapped in command mode. */
+nofunc: if (stype == SEQ_COMMAND && input[1] == '\0')
+ switch (KEY_VAL(sp, input[0])) {
+ case K_COLON:
+ case K_ESCAPE:
+ case K_NL:
+ msgq(sp, M_ERR, "The %s character may not be remapped",
+ KEY_NAME(sp, input[0]));
+ return (1);
+ }
+ return (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len,
+ cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, SEQ_USERDEF));
+}
+
+/*
+ * ex_unmap -- (:unmap[!] key)
+ * Unmap a key.
+ */
+int
+ex_unmap(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (seq_delete(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len,
+ F_ISSET(cmdp, E_FORCE) ? SEQ_INPUT : SEQ_COMMAND)) {
+ msgq(sp, M_INFO, "\"%s\" isn't mapped", cmdp->argv[0]->bp);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * map_save --
+ * Save the mapped sequences to a file.
+ */
+int
+map_save(sp, fp)
+ SCR *sp;
+ FILE *fp;
+{
+ if (seq_save(sp, fp, "map ", SEQ_COMMAND))
+ return (1);
+ return (seq_save(sp, fp, "map! ", SEQ_INPUT));
+}
diff --git a/usr.bin/vi/ex/ex_mark.c b/usr.bin/vi/ex/ex_mark.c
new file mode 100644
index 000000000000..bd1e0fd5140b
--- /dev/null
+++ b/usr.bin/vi/ex/ex_mark.c
@@ -0,0 +1,66 @@
+/*-
+ * 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_mark.c 8.6 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+int
+ex_mark(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (cmdp->argv[0]->len != 1) {
+ msgq(sp, M_ERR, "Mark names must be a single character");
+ return (1);
+ }
+ return (mark_set(sp, ep, cmdp->argv[0]->bp[0], &cmdp->addr1, 1));
+}
diff --git a/usr.bin/vi/ex/ex_mkexrc.c b/usr.bin/vi/ex/ex_mkexrc.c
new file mode 100644
index 000000000000..095d51e55862
--- /dev/null
+++ b/usr.bin/vi/ex/ex_mkexrc.c
@@ -0,0 +1,130 @@
+/*-
+ * 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_mkexrc.c 8.12 (Berkeley) 7/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_mkexrc -- :mkexrc[!] [file]
+ *
+ * Create (or overwrite) a .exrc file with the current info.
+ */
+int
+ex_mkexrc(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ struct stat sb;
+ FILE *fp;
+ int fd, sverrno;
+ char *fname;
+
+ switch (cmdp->argc) {
+ case 0:
+ fname = _PATH_EXRC;
+ break;
+ case 1:
+ fname = cmdp->argv[0]->bp;
+ set_alt_name(sp, fname);
+ break;
+ default:
+ abort();
+ }
+
+ if (!F_ISSET(cmdp, E_FORCE) && !stat(fname, &sb)) {
+ msgq(sp, M_ERR,
+ "%s exists, not written; use ! to override", fname);
+ return (1);
+ }
+
+ /* Create with max permissions of rw-r--r--. */
+ if ((fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+ msgq(sp, M_SYSERR, fname);
+ return (1);
+ }
+
+ if ((fp = fdopen(fd, "w")) == NULL) {
+ sverrno = errno;
+ (void)close(fd);
+ errno = sverrno;
+ goto e2;
+ }
+
+ if (abbr_save(sp, fp) || ferror(fp))
+ goto e1;
+ if (map_save(sp, fp) || ferror(fp))
+ goto e1;
+ if (opts_save(sp, fp) || ferror(fp))
+ goto e1;
+#ifndef NO_DIGRAPH
+ digraph_save(sp, fd);
+#endif
+ if (fclose(fp))
+ goto e2;
+
+ msgq(sp, M_INFO, "New .exrc file: %s. ", fname);
+ return (0);
+
+e1: sverrno = errno;
+ (void)fclose(fp);
+ errno = sverrno;
+e2: msgq(sp, M_ERR, "%s: incomplete: %s", fname, strerror(errno));
+ return (1);
+}
diff --git a/usr.bin/vi/ex/ex_move.c b/usr.bin/vi/ex/ex_move.c
new file mode 100644
index 000000000000..98225089d321
--- /dev/null
+++ b/usr.bin/vi/ex/ex_move.c
@@ -0,0 +1,222 @@
+/*-
+ * 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.17 (Berkeley) 8/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.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;
+
+ rval = 0;
+
+ /*
+ * 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);
+ for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt)
+ if (cut_line(sp, ep, cnt, 0, 0, &cb)) {
+ rval = 1;
+ goto err;
+ }
+ cb.flags |= CB_LMODE;
+
+ /* 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;
+ }
+err: 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 blen, len;
+ int mark_reset;
+ char *bp, *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);
+ }
+
+ /* Get memory for the copy. */
+ GET_SPACE_RET(sp, bp, blen, 256);
+
+ /* 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);
+ BINC_RET(sp, bp, blen, len);
+ memmove(bp, p, len);
+ if (file_aline(sp, ep, 1, tl, bp, 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);
+ BINC_RET(sp, bp, blen, len);
+ memmove(bp, p, len);
+ if (file_aline(sp, ep, 1, tl++, bp, 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);
+ }
+ }
+ FREE_SPACE(sp, bp, blen);
+
+ 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/ex/ex_open.c b/usr.bin/vi/ex/ex_open.c
new file mode 100644
index 000000000000..385fdd3cd922
--- /dev/null
+++ b/usr.bin/vi/ex/ex_open.c
@@ -0,0 +1,75 @@
+/*-
+ * 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_open.c 8.4 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_open -- :[line] o[pen] [/pattern/] [flags]
+ *
+ * Switch to single line "open" mode.
+ */
+int
+ex_open(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ /* If open option off, disallow open command. */
+ if (!O_ISSET(sp, O_OPEN)) {
+ msgq(sp, M_ERR,
+ "The open command requires that the open option be set");
+ return (1);
+ }
+
+ msgq(sp, M_ERR, "The open command is not yet implemented");
+ return (1);
+}
diff --git a/usr.bin/vi/ex/ex_preserve.c b/usr.bin/vi/ex/ex_preserve.c
new file mode 100644
index 000000000000..8960f98adf84
--- /dev/null
+++ b/usr.bin/vi/ex/ex_preserve.c
@@ -0,0 +1,128 @@
+/*-
+ * 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_preserve.c 8.12 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_preserve -- :pre[serve]
+ * Push the file to recovery.
+ */
+int
+ex_preserve(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ recno_t lno;
+
+ if (!F_ISSET(ep, F_RCV_ON)) {
+ msgq(sp, M_ERR, "Preservation of this file not possible");
+ return (1);
+ }
+
+ /* If recovery not initialized, do so. */
+ if (F_ISSET(ep, F_FIRSTMODIFY) && rcv_init(sp, ep))
+ return (1);
+
+ /* Force the file to be read in, in case it hasn't yet. */
+ if (file_lline(sp, ep, &lno))
+ return (1);
+
+ /* Sync to disk. */
+ if (rcv_sync(sp, ep, RCV_SNAPSHOT))
+ return (1);
+
+ msgq(sp, M_INFO, "File preserved");
+ return (0);
+}
+
+/*
+ * ex_recover -- :rec[over][!] file
+ *
+ * Recover the file.
+ */
+int
+ex_recover(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS *ap;
+ FREF *frp;
+
+ ap = cmdp->argv[0];
+
+ /* Set the alternate file name. */
+ set_alt_name(sp, ap->bp);
+
+ /*
+ * Check for modifications. Autowrite did not historically
+ * affect :recover.
+ */
+ if (file_m2(sp, ep, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+
+ /* Get a file structure for the file. */
+ if ((frp = file_add(sp, ap->bp)) == NULL)
+ return (1);
+
+ /* Set the recover bit. */
+ F_SET(frp, FR_RECOVER);
+
+ /* Switch files. */
+ if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE)))
+ return (1);
+ F_SET(sp, S_FSWITCH);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_print.c b/usr.bin/vi/ex/ex_print.c
new file mode 100644
index 000000000000..c3aa22f00c07
--- /dev/null
+++ b/usr.bin/vi/ex/ex_print.c
@@ -0,0 +1,212 @@
+/*-
+ * 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_print.c 8.14 (Berkeley) 8/7/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_list -- :[line [,line]] l[ist] [count] [flags]
+ *
+ * Display the addressed lines such that the output is unambiguous.
+ */
+int
+ex_list(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (ex_print(sp, ep,
+ &cmdp->addr1, &cmdp->addr2, cmdp->flags | E_F_LIST))
+ return (1);
+ sp->lno = cmdp->addr2.lno;
+ sp->cno = cmdp->addr2.cno;
+ return (0);
+}
+
+/*
+ * ex_number -- :[line [,line]] nu[mber] [count] [flags]
+ *
+ * Display the addressed lines with a leading line number.
+ */
+int
+ex_number(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (ex_print(sp, ep,
+ &cmdp->addr1, &cmdp->addr2, cmdp->flags | E_F_HASH))
+ return (1);
+ sp->lno = cmdp->addr2.lno;
+ sp->cno = cmdp->addr2.cno;
+ return (0);
+}
+
+/*
+ * ex_pr -- :[line [,line]] p[rint] [count] [flags]
+ *
+ * Display the addressed lines.
+ */
+int
+ex_pr(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (ex_print(sp, ep, &cmdp->addr1, &cmdp->addr2, cmdp->flags))
+ return (1);
+ sp->lno = cmdp->addr2.lno;
+ sp->cno = cmdp->addr2.cno;
+ return (0);
+}
+
+/*
+ * ex_print --
+ * Print the selected lines.
+ */
+int
+ex_print(sp, ep, fp, tp, flags)
+ SCR *sp;
+ EXF *ep;
+ MARK *fp, *tp;
+ register int flags;
+{
+ recno_t from, to;
+ size_t col, len;
+ char *p;
+
+ F_SET(sp, S_INTERRUPTIBLE);
+ for (from = fp->lno, to = tp->lno; from <= to; ++from) {
+ /*
+ * Display the line number. The %6 format is specified
+ * by POSIX 1003.2, and is almost certainly large enough.
+ * Check, though, just in case.
+ */
+ if (LF_ISSET(E_F_HASH))
+ if (from <= 999999)
+ col = ex_printf(EXCOOKIE, "%6ld ", from);
+ else
+ col = ex_printf(EXCOOKIE, "TOOBIG ");
+ 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
+ * backward compatible.
+ */
+ if ((p = file_gline(sp, ep, from, &len)) == NULL) {
+ GETLINE_ERR(sp, from);
+ return (1);
+ }
+
+ if (len == 0 && !LF_ISSET(E_F_LIST))
+ (void)ex_printf(EXCOOKIE, "\n");
+ else if (ex_ldisplay(sp, p, len, col, flags))
+ return (1);
+
+ if (INTERRUPTED(sp))
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * ex_ldisplay --
+ * Display a line.
+ */
+int
+ex_ldisplay(sp, lp, len, col, flags)
+ SCR *sp;
+ CHAR_T *lp;
+ size_t len, col;
+ u_int flags;
+{
+ CHAR_T ch, *kp;
+ u_long ts;
+ size_t tlen;
+
+ ts = O_VAL(sp, O_TABSTOP);
+ for (;; --len) {
+ if (len > 0)
+ ch = *lp++;
+ else if (LF_ISSET(E_F_LIST))
+ ch = '$';
+ else
+ break;
+ if (ch == '\t' && !LF_ISSET(E_F_LIST))
+ for (tlen = ts - col % ts;
+ col < sp->cols && tlen--; ++col)
+ (void)ex_printf(EXCOOKIE, " ");
+ else {
+ kp = KEY_NAME(sp, ch);
+ tlen = KEY_LEN(sp, ch);
+ if (col + tlen < sp->cols) {
+ (void)ex_printf(EXCOOKIE, "%s", kp);
+ col += tlen;
+ } else
+ for (; tlen--; ++kp, ++col) {
+ if (col == sp->cols) {
+ col = 0;
+ (void)ex_printf(EXCOOKIE, "\n");
+ }
+ (void)ex_printf(EXCOOKIE, "%c", *kp);
+ }
+ }
+ if (len == 0)
+ break;
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_put.c b/usr.bin/vi/ex/ex_put.c
new file mode 100644
index 000000000000..ce44b5faa278
--- /dev/null
+++ b/usr.bin/vi/ex/ex_put.c
@@ -0,0 +1,78 @@
+/*-
+ * 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_put.c 8.6 (Berkeley) 7/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_put -- [line] pu[t] [buffer]
+ *
+ * Append a cut buffer into the file.
+ */
+int
+ex_put(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ MARK m;
+
+ m.lno = sp->lno;
+ m.cno = sp->cno;
+ if (put(sp, ep, NULL, F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
+ &cmdp->addr1, &m, 1))
+ return (1);
+ sp->lno = m.lno;
+ sp->cno = m.cno;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_read.c b/usr.bin/vi/ex/ex_read.c
new file mode 100644
index 000000000000..dafc4adfba92
--- /dev/null
+++ b/usr.bin/vi/ex/ex_read.c
@@ -0,0 +1,300 @@
+/*-
+ * 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_read.c 8.39 (Berkeley) 8/9/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_read -- :read [file]
+ * :read [!cmd]
+ * Read from a file or utility.
+ *
+ * !!!
+ * Historical vi wouldn't undo a filter read, for no apparent reason.
+ */
+int
+ex_read(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ struct stat sb;
+ CHAR_T *arg, *name;
+ EX_PRIVATE *exp;
+ FILE *fp;
+ MARK rm;
+ recno_t nlines;
+ size_t arglen, blen, len;
+ int btear, farg, rval;
+ char *p;
+
+ /*
+ * 0 args: we're done.
+ * 1 args: check for "read !arg".
+ * 2 args: check for "read ! arg".
+ * >2 args: object, too many args.
+ */
+ farg = 0;
+ switch (cmdp->argc) {
+ case 0:
+ break;
+ case 1:
+ arg = cmdp->argv[0]->bp;
+ arglen = cmdp->argv[0]->len;
+ if (*arg == '!') {
+ ++arg;
+ --arglen;
+ farg = 1;
+ }
+ break;
+ case 2:
+ if (cmdp->argv[0]->len == 1 && cmdp->argv[0]->bp[0] == '!') {
+ arg = cmdp->argv[1]->bp;
+ arglen = cmdp->argv[1]->len;
+ farg = 2;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ goto badarg;
+ }
+
+ if (farg != 0) {
+ /* File name and bang expand the user's argument. */
+ if (argv_exp1(sp, ep, cmdp, arg, arglen, 1))
+ return (1);
+
+ /* If argc unchanged, there wasn't anything to expand. */
+ if (cmdp->argc == farg)
+ goto usage;
+
+ /* Set the last bang command. */
+ exp = EXP(sp);
+ if (exp->lastbcomm != NULL)
+ free(exp->lastbcomm);
+ if ((exp->lastbcomm = strdup(cmdp->argv[farg]->bp)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ /* Redisplay the user's argument if it's changed. */
+ if (F_ISSET(cmdp, E_MODIFY) && IN_VI_MODE(sp)) {
+ len = cmdp->argv[farg]->len;
+ GET_SPACE_RET(sp, p, blen, len + 2);
+ p[0] = '!';
+ memmove(p + 1,
+ cmdp->argv[farg]->bp, cmdp->argv[farg]->len + 1);
+ (void)sp->s_busy(sp, p);
+ FREE_SPACE(sp, p, blen);
+ }
+
+ if (filtercmd(sp, ep, &cmdp->addr1,
+ NULL, &rm, cmdp->argv[farg]->bp, FILTER_READ))
+ return (1);
+
+ /* The filter version of read set the autoprint flag. */
+ F_SET(EXP(sp), EX_AUTOPRINT);
+
+ /* If in vi mode, move to the first nonblank. */
+ sp->lno = rm.lno;
+ if (IN_VI_MODE(sp)) {
+ sp->cno = 0;
+ (void)nonblank(sp, ep, sp->lno, &sp->cno);
+ }
+ return (0);
+ }
+
+ /* Shell and file name expand the user's argument. */
+ if (argv_exp2(sp, ep, cmdp, arg, arglen, 0))
+ return (1);
+
+ /*
+ * 0 args: no arguments, read the current file, don't set the
+ * alternate file name.
+ * 1 args: read it, switching to it or settgin the alternate file
+ * name.
+ * >1 args: object, too many args.
+ */
+ switch (cmdp->argc) {
+ case 1:
+ name = sp->frp->name;
+ break;
+ case 2:
+ name = cmdp->argv[1]->bp;
+ /*
+ * !!!
+ * Historically, if you had an "unnamed" file, the read command
+ * renamed the file.
+ */
+ if (F_ISSET(sp->frp, FR_TMPFILE) &&
+ !F_ISSET(sp->frp, FR_READNAMED)) {
+ if ((p = v_strdup(sp,
+ cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) {
+ free(sp->frp->name);
+ sp->frp->name = p;
+ }
+ F_SET(sp->frp, FR_NAMECHANGE | FR_READNAMED);
+ } else
+ set_alt_name(sp, name);
+ break;
+ default:
+badarg: msgq(sp, M_ERR,
+ "%s expanded into too many file names", cmdp->argv[0]->bp);
+usage: msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Historically, vi did not permit reads from non-regular files,
+ * nor did it distinguish between "read !" and "read!", so there
+ * was no way to "force" it.
+ */
+ if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
+ msgq(sp, M_SYSERR, "%s", name);
+ return (1);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ (void)fclose(fp);
+ msgq(sp, M_ERR, "Only regular files may be read");
+ return (1);
+ }
+
+ /* Turn on busy message. */
+ btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Reading...");
+ rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1);
+ if (btear)
+ busy_off(sp);
+
+ /*
+ * Set the cursor to the first line read in, if anything read
+ * in, otherwise, the address. (Historic vi set it to the
+ * line after the address regardless, but since that line may
+ * not exist we don't bother.)
+ */
+ sp->lno = cmdp->addr1.lno;
+ if (nlines)
+ ++sp->lno;
+
+ return (rval);
+}
+
+/*
+ * ex_readfp --
+ * Read lines into the file.
+ */
+int
+ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
+ SCR *sp;
+ EXF *ep;
+ char *name;
+ FILE *fp;
+ MARK *fm;
+ recno_t *nlinesp;
+ int success_msg;
+{
+ EX_PRIVATE *exp;
+ recno_t lcnt, lno;
+ size_t len;
+ 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;
+ lcnt = 0;
+ for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
+ if (INTERRUPTED(sp)) {
+ if (!success_msg)
+ msgq(sp, M_INFO, "Interrupted");
+ break;
+ }
+ if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
+ rval = 1;
+ break;
+ }
+ ccnt += len;
+ }
+
+ if (ferror(fp)) {
+ msgq(sp, M_SYSERR, "%s", name);
+ rval = 1;
+ }
+
+ if (fclose(fp)) {
+ msgq(sp, M_SYSERR, "%s", name);
+ return (1);
+ }
+
+ if (rval)
+ return (1);
+
+ /* Return the number of lines read in. */
+ if (nlinesp != NULL)
+ *nlinesp = lcnt;
+
+ if (success_msg)
+ msgq(sp, M_INFO, "%s%s: %lu line%s, %lu characters",
+ INTERRUPTED(sp) ? "Interrupted read: " : "",
+ name, lcnt, lcnt == 1 ? "" : "s", ccnt);
+
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_screen.c b/usr.bin/vi/ex/ex_screen.c
new file mode 100644
index 000000000000..179ed07a0afe
--- /dev/null
+++ b/usr.bin/vi/ex/ex_screen.c
@@ -0,0 +1,155 @@
+/*-
+ * 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_screen.c 8.13 (Berkeley) 6/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_split -- :s[plit] [file ...]
+ * Split the screen, optionally setting the file list.
+ */
+int
+ex_split(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (sp->s_split(sp, cmdp->argc ? cmdp->argv : NULL, cmdp->argc));
+}
+
+/*
+ * ex_bg -- :bg
+ * Hide the screen.
+ */
+int
+ex_bg(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (sp->s_bg(sp));
+}
+
+/*
+ * ex_fg -- :fg [file]
+ * Show the screen.
+ */
+int
+ex_fg(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (sp->s_fg(sp, cmdp->argc ? cmdp->argv[0]->bp : NULL));
+}
+
+/*
+ * ex_resize -- :resize [+-]rows
+ * Change the screen size.
+ */
+int
+ex_resize(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ 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));
+}
+
+/*
+ * ex_sdisplay --
+ * Display the list of screens.
+ */
+int
+ex_sdisplay(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SCR *tsp;
+ int cnt, col, len, sep;
+
+ if ((tsp = sp->gp->hq.cqh_first) == (void *)&sp->gp->hq) {
+ (void)ex_printf(EXCOOKIE,
+ "No backgrounded screens to display.\n");
+ return (0);
+ }
+
+ col = len = sep = 0;
+ for (cnt = 1; tsp != (void *)&sp->gp->hq; tsp = tsp->q.cqe_next) {
+ col += len = strlen(tsp->frp->name) + sep;
+ if (col >= sp->cols - 1) {
+ col = len;
+ sep = 0;
+ (void)ex_printf(EXCOOKIE, "\n");
+ } else if (cnt != 1) {
+ sep = 1;
+ (void)ex_printf(EXCOOKIE, " ");
+ }
+ (void)ex_printf(EXCOOKIE, "%s", tsp->frp->name);
+ ++cnt;
+ }
+ (void)ex_printf(EXCOOKIE, "\n");
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_script.c b/usr.bin/vi/ex/ex_script.c
new file mode 100644
index 000000000000..59586f1e1765
--- /dev/null
+++ b/usr.bin/vi/ex/ex_script.c
@@ -0,0 +1,582 @@
+/*-
+ * 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_script.c 8.17 (Berkeley) 7/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "script.h"
+
+/*
+ * XXX
+ */
+int openpty __P((int *, int *, char *, struct termios *, struct winsize *));
+
+static int sscr_getprompt __P((SCR *, EXF *));
+static int sscr_init __P((SCR *, EXF *));
+static int sscr_matchprompt __P((SCR *, char *, size_t, size_t *));
+static int sscr_setprompt __P((SCR *, char *, size_t));
+
+/*
+ * ex_script -- : sc[ript][!] [file]
+ *
+ * Switch to script mode.
+ */
+int
+ex_script(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ /* Vi only command. */
+ if (!IN_VI_MODE(sp)) {
+ msgq(sp, M_ERR,
+ "The script command is only available in vi mode");
+ return (1);
+ }
+
+ /* Switch to the new file. */
+ if (cmdp->argc != 0 && ex_edit(sp, ep, cmdp))
+ return (1);
+
+ /*
+ * Create the shell, figure out the prompt.
+ *
+ * !!!
+ * The files just switched, use sp->ep.
+ */
+ if (sscr_init(sp, sp->ep))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * sscr_init --
+ * Create a pty setup for a shell.
+ */
+static int
+sscr_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SCRIPT *sc;
+ char *sh, *sh_path;
+
+ MALLOC_RET(sp, sc, SCRIPT *, sizeof(SCRIPT));
+ sp->script = sc;
+ sc->sh_prompt = NULL;
+ sc->sh_prompt_len = 0;
+
+ /*
+ * There are two different processes running through this code.
+ * They are the shell and the parent.
+ */
+ sc->sh_master = sc->sh_slave = -1;
+
+ if (tcgetattr(STDIN_FILENO, &sc->sh_term) == -1) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ goto err;
+ }
+
+ /*
+ * Turn off output postprocessing and echo.
+ */
+ sc->sh_term.c_oflag &= ~OPOST;
+ sc->sh_term.c_cflag &= ~(ECHO|ECHOE|ECHONL|ECHOK);
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &sc->sh_win) == -1) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ goto err;
+ }
+
+ if (openpty(&sc->sh_master,
+ &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) {
+ msgq(sp, M_SYSERR, "openpty");
+ goto err;
+ }
+
+ /*
+ * Don't use vfork() here, because the signal semantics differ from
+ * implementation to implementation.
+ */
+ SIGBLOCK(sp->gp);
+ switch (sc->sh_pid = fork()) {
+ case -1: /* Error. */
+ SIGUNBLOCK(sp->gp);
+
+ msgq(sp, M_SYSERR, "fork");
+err: if (sc->sh_master != -1)
+ (void)close(sc->sh_master);
+ if (sc->sh_slave != -1)
+ (void)close(sc->sh_slave);
+ return (1);
+ case 0: /* Utility. */
+ /* The utility has default signal behavior. */
+ sig_end();
+
+ /*
+ * XXX
+ * So that shells that do command line editing turn it off.
+ */
+ (void)putenv("TERM=emacs");
+ (void)putenv("TERMCAP=emacs:");
+ (void)putenv("EMACS=t");
+
+ (void)setsid();
+#ifdef TIOCSCTTY
+ /*
+ * 4.4BSD allocates a controlling terminal using the TIOCSCTTY
+ * ioctl, not by opening a terminal device file. POSIX 1003.1
+ * doesn't define a portable way to do this. If TIOCSCTTY is
+ * not available, hope that the open does it.
+ */
+ (void)ioctl(sc->sh_slave, TIOCSCTTY, 0);
+#endif
+ (void)close(sc->sh_master);
+ (void)dup2(sc->sh_slave, STDIN_FILENO);
+ (void)dup2(sc->sh_slave, STDOUT_FILENO);
+ (void)dup2(sc->sh_slave, STDERR_FILENO);
+ (void)close(sc->sh_slave);
+
+ /* Assumes that all shells have -i. */
+ sh_path = O_STR(sp, O_SHELL);
+ if ((sh = strrchr(sh_path, '/')) == NULL)
+ sh = sh_path;
+ else
+ ++sh;
+ execl(sh_path, sh, "-i", NULL);
+ msgq(sp, M_ERR,
+ "Error: execl: %s: %s", sh_path, strerror(errno));
+ _exit(127);
+ default: /* Parent. */
+ SIGUNBLOCK(sp->gp);
+ break;
+ }
+
+ if (sscr_getprompt(sp, ep))
+ return (1);
+
+ F_SET(sp, S_REDRAW | S_SCRIPT);
+ return (0);
+
+}
+
+/*
+ * sscr_getprompt --
+ * Eat lines printed by the shell until a line with no trailing
+ * carriage return comes; set the prompt from that line.
+ */
+static int
+sscr_getprompt(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct timeval tv;
+ CHAR_T *endp, *p, *t, buf[1024];
+ SCRIPT *sc;
+ fd_set fdset;
+ recno_t lline;
+ size_t llen, len;
+ u_int value;
+ int nr;
+
+ FD_ZERO(&fdset);
+ endp = buf;
+ len = sizeof(buf);
+
+ /* Wait up to a second for characters to read. */
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ sc = sp->script;
+ FD_SET(sc->sh_master, &fdset);
+ switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) {
+ case -1: /* Error or interrupt. */
+ msgq(sp, M_SYSERR, "select");
+ goto prompterr;
+ case 0: /* Timeout */
+ msgq(sp, M_ERR, "Error: timed out");
+ goto prompterr;
+ case 1: /* Characters to read. */
+ break;
+ }
+
+ /* Read the characters. */
+more: len = sizeof(buf) - (endp - buf);
+ switch (nr = read(sc->sh_master, endp, len)) {
+ case 0: /* EOF. */
+ msgq(sp, M_ERR, "Error: shell: EOF");
+ goto prompterr;
+ case -1: /* Error or interrupt. */
+ msgq(sp, M_SYSERR, "shell");
+ goto prompterr;
+ default:
+ endp += nr;
+ break;
+ }
+
+ /* If any complete lines, push them into the file. */
+ for (p = t = buf; p < endp; ++p) {
+ value = KEY_VAL(sp, *p);
+ if (value == K_CR || value == K_NL) {
+ if (file_lline(sp, ep, &lline) ||
+ file_aline(sp, ep, 0, lline, t, p - t))
+ goto prompterr;
+ t = p + 1;
+ }
+ }
+ if (p > buf) {
+ memmove(buf, t, endp - t);
+ endp = buf + (endp - t);
+ }
+ if (endp == buf)
+ goto more;
+
+ /* Wait up 1/10 of a second to make sure that we got it all. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) {
+ case -1: /* Error or interrupt. */
+ msgq(sp, M_SYSERR, "select");
+ goto prompterr;
+ case 0: /* Timeout */
+ break;
+ case 1: /* Characters to read. */
+ goto more;
+ }
+
+ /* Timed out, so theoretically we have a prompt. */
+ llen = endp - buf;
+ endp = buf;
+
+ /* Append the line into the file. */
+ if (file_lline(sp, ep, &lline) ||
+ file_aline(sp, ep, 0, lline, buf, llen)) {
+prompterr: sscr_end(sp);
+ return (1);
+ }
+
+ return (sscr_setprompt(sp, buf, llen));
+}
+
+/*
+ * sscr_exec --
+ * Take a line and hand it off to the shell.
+ */
+int
+sscr_exec(sp, ep, lno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+{
+ SCRIPT *sc;
+ recno_t last_lno;
+ size_t blen, len, last_len, tlen;
+ int matchprompt, nw, rval;
+ char *bp, *p;
+
+ /* If there's a prompt on the last line, append the command. */
+ if (file_lline(sp, ep, &last_lno))
+ return (1);
+ if ((p = file_gline(sp, ep, last_lno, &last_len)) == NULL) {
+ GETLINE_ERR(sp, last_lno);
+ return (1);
+ }
+ if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) {
+ matchprompt = 1;
+ GET_SPACE_RET(sp, bp, blen, last_len + 128);
+ memmove(bp, p, last_len);
+ } else
+ matchprompt = 0;
+
+ /* Get something to execute. */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ goto err1;
+ if (lno == 0)
+ goto empty;
+ else
+ GETLINE_ERR(sp, lno);
+ goto err1;
+ }
+
+ /* Empty lines aren't interesting. */
+ if (len == 0)
+ goto empty;
+
+ /* Delete any prompt. */
+ if (sscr_matchprompt(sp, p, len, &tlen)) {
+ if (tlen == len) {
+empty: msgq(sp, M_BERR, "Nothing to execute");
+ goto err1;
+ }
+ p += (len - tlen);
+ len = tlen;
+ }
+
+ /* Push the line to the shell. */
+ sc = sp->script;
+ if ((nw = write(sc->sh_master, p, len)) != len)
+ goto err2;
+ rval = 0;
+ if (write(sc->sh_master, "\n", 1) != 1) {
+err2: if (nw == 0)
+ errno = EIO;
+ msgq(sp, M_SYSERR, "shell");
+ goto err1;
+ }
+
+ if (matchprompt) {
+ ADD_SPACE_RET(sp, bp, blen, last_len + len);
+ memmove(bp + last_len, p, len);
+ if (file_sline(sp, ep, last_lno, bp, last_len + len))
+err1: rval = 1;
+ }
+ if (matchprompt)
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * sscr_input --
+ * Take a line from the shell and insert it into the file.
+ */
+int
+sscr_input(sp)
+ SCR *sp;
+{
+ struct timeval tv;
+ CHAR_T *endp, *p, *t;
+ EXF *ep;
+ SCRIPT *sc;
+ recno_t lno;
+ size_t blen, len, tlen;
+ u_int value;
+ int nr, rval;
+ char *bp;
+
+ /* Find out where the end of the file is. */
+ ep = sp->ep;
+ if (file_lline(sp, ep, &lno))
+ return (1);
+
+#define MINREAD 1024
+ GET_SPACE_RET(sp, bp, blen, MINREAD);
+ endp = bp;
+
+ /* Read the characters. */
+ rval = 1;
+ sc = sp->script;
+more: switch (nr = read(sc->sh_master, endp, MINREAD)) {
+ case 0: /* EOF; shell just exited. */
+ sscr_end(sp);
+ F_CLR(sp, S_SCRIPT);
+ rval = 0;
+ goto ret;
+ case -1: /* Error or interrupt. */
+ msgq(sp, M_SYSERR, "shell");
+ goto ret;
+ default:
+ endp += nr;
+ break;
+ }
+
+ /* Append the lines into the file. */
+ for (p = t = bp; p < endp; ++p) {
+ value = KEY_VAL(sp, *p);
+ if (value == K_CR || value == K_NL) {
+ len = p - t;
+ if (file_aline(sp, ep, 1, lno++, t, len))
+ goto ret;
+ t = p + 1;
+ }
+ }
+ if (p > t) {
+ len = p - t;
+ /*
+ * If the last thing from the shell isn't another prompt, wait
+ * up to 1/10 of a second for more stuff to show up, so that
+ * we don't break the output into two separate lines. Don't
+ * want to hang indefinitely because some program is hanging,
+ * confused the shell, or whatever.
+ */
+ if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ FD_SET(sc->sh_master, &sp->rdfd);
+ FD_CLR(STDIN_FILENO, &sp->rdfd);
+ if (select(sc->sh_master + 1,
+ &sp->rdfd, NULL, NULL, &tv) == 1) {
+ memmove(bp, t, len);
+ endp = bp + len;
+ goto more;
+ }
+ }
+ if (sscr_setprompt(sp, t, len))
+ return (1);
+ if (file_aline(sp, ep, 1, lno++, t, len))
+ goto ret;
+ }
+
+ /* The cursor moves to EOF. */
+ sp->lno = lno;
+ sp->cno = len ? len - 1 : 0;
+ rval = sp->s_refresh(sp, ep);
+
+ret: FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * sscr_setprompt --
+ *
+ * Set the prompt to the last line we got from the shell.
+ *
+ */
+static int
+sscr_setprompt(sp, buf, len)
+ SCR *sp;
+ char* buf;
+ size_t len;
+{
+ SCRIPT *sc;
+
+ sc = sp->script;
+ if (sc->sh_prompt)
+ FREE(sc->sh_prompt, sc->sh_prompt_len);
+ MALLOC(sp, sc->sh_prompt, char *, len + 1);
+ if (sc->sh_prompt == NULL) {
+ sscr_end(sp);
+ return (1);
+ }
+ memmove(sc->sh_prompt, buf, len);
+ sc->sh_prompt_len = len;
+ sc->sh_prompt[len] = '\0';
+ return (0);
+}
+
+/*
+ * sscr_matchprompt --
+ * Check to see if a line matches the prompt. Nul's indicate
+ * parts that can change, in both content and size.
+ */
+static int
+sscr_matchprompt(sp, lp, line_len, lenp)
+ SCR *sp;
+ char *lp;
+ size_t line_len, *lenp;
+{
+ SCRIPT *sc;
+ size_t prompt_len;
+ char *pp;
+
+ sc = sp->script;
+ if (line_len < (prompt_len = sc->sh_prompt_len))
+ return (0);
+
+ for (pp = sc->sh_prompt;
+ prompt_len && line_len; --prompt_len, --line_len) {
+ if (*pp == '\0') {
+ for (; prompt_len && *pp == '\0'; --prompt_len, ++pp);
+ if (!prompt_len)
+ return (0);
+ for (; line_len && *lp != *pp; --line_len, ++lp);
+ if (!line_len)
+ return (0);
+ }
+ if (*pp++ != *lp++)
+ break;
+ }
+
+ if (prompt_len)
+ return (0);
+ if (lenp != NULL)
+ *lenp = line_len;
+ return (1);
+}
+
+/*
+ * sscr_end --
+ * End the pipe to a shell.
+ */
+int
+sscr_end(sp)
+ SCR *sp;
+{
+ SCRIPT *sc;
+ int rval;
+
+ if ((sc = sp->script) == NULL)
+ return (0);
+
+ /* 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);
+ if (sc->sh_slave != -1)
+ (void)close(sc->sh_slave);
+
+ /* This should have killed the child. */
+ rval = proc_wait(sp, (long)sc->sh_pid, "script-shell", 0);
+
+ /* Free memory. */
+ FREE(sc->sh_prompt, sc->sh_prompt_len);
+ FREE(sc, sizeof(SCRIPT));
+ sp->script = NULL;
+
+ return (rval);
+}
diff --git a/usr.bin/vi/ex/ex_set.c b/usr.bin/vi/ex/ex_set.c
new file mode 100644
index 000000000000..1ad19f71ae91
--- /dev/null
+++ b/usr.bin/vi/ex/ex_set.c
@@ -0,0 +1,70 @@
+/*-
+ * 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_set.c 8.4 (Berkeley) 7/22/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+int
+ex_set(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ switch(cmdp->argc) {
+ case 0:
+ opts_dump(sp, CHANGED_DISPLAY);
+ break;
+ default:
+ opts_set(sp, cmdp->cmd->usage, cmdp->argv);
+ break;
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_shell.c b/usr.bin/vi/ex/ex_shell.c
new file mode 100644
index 000000000000..bcbb97d317fd
--- /dev/null
+++ b/usr.bin/vi/ex/ex_shell.c
@@ -0,0 +1,150 @@
+/*-
+ * 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_shell.c 8.24 (Berkeley) 8/5/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../svi/svi_screen.h"
+
+/*
+ * ex_shell -- :sh[ell]
+ * Invoke the program named in the SHELL environment variable
+ * with the argument -i.
+ */
+int
+ex_shell(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ char buf[MAXPATHLEN];
+
+ (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
+ return (ex_exec_proc(sp, buf, "\n", NULL));
+}
+
+/*
+ * ex_exec_proc --
+ * Run a separate process.
+ */
+int
+ex_exec_proc(sp, cmd, p1, p2)
+ SCR *sp;
+ char *cmd, *p1, *p2;
+{
+ const char *name;
+ pid_t pid;
+ 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. */
+ teardown = !ex_sleave(sp);
+
+ /*
+ * Flush waiting messages (autowrite, for example) so the output
+ * matches historic practice.
+ */
+ (void)sex_refresh(sp, sp->ep);
+
+ /* Put out various messages. */
+ if (p1 != NULL)
+ (void)write(STDOUT_FILENO, p1, strlen(p1));
+ if (p2 != NULL)
+ (void)write(STDOUT_FILENO, p2, strlen(p2));
+
+ SIGBLOCK(sp->gp);
+ switch (pid = vfork()) {
+ case -1: /* Error. */
+ SIGUNBLOCK(sp->gp);
+
+ msgq(sp, M_SYSERR, "vfork");
+ rval = 1;
+ break;
+ case 0: /* Utility. */
+ /* The utility has default signal behavior. */
+ sig_end();
+
+ if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
+ name = O_STR(sp, O_SHELL);
+ else
+ ++name;
+ execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
+ msgq(sp, M_ERR, "Error: execl: %s: %s",
+ O_STR(sp, O_SHELL), strerror(errno));
+ _exit(127);
+ /* NOTREACHED */
+ default: /* Parent. */
+ SIGUNBLOCK(sp->gp);
+
+ rval = proc_wait(sp, (long)pid, cmd, 0);
+ break;
+ }
+
+ /* Restore ex/vi terminal settings. */
+ if (teardown)
+ ex_rleave(sp);
+
+ /*
+ * XXX
+ * 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);
+
+ return (rval);
+}
diff --git a/usr.bin/vi/ex/ex_shift.c b/usr.bin/vi/ex/ex_shift.c
new file mode 100644
index 000000000000..41cb557d7c58
--- /dev/null
+++ b/usr.bin/vi/ex/ex_shift.c
@@ -0,0 +1,204 @@
+/*-
+ * 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_shift.c 8.14 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+enum which {LEFT, RIGHT};
+static int shift __P((SCR *, EXF *, EXCMDARG *, enum which));
+
+int
+ex_shiftl(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (shift(sp, ep, cmdp, LEFT));
+}
+
+int
+ex_shiftr(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (shift(sp, ep, cmdp, RIGHT));
+}
+
+static int
+shift(sp, ep, cmdp, rl)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ enum which rl;
+{
+ recno_t from, to;
+ size_t blen, len, newcol, newidx, oldcol, oldidx, sw;
+ int curset;
+ char *p, *bp, *tbp;
+
+ if (O_VAL(sp, O_SHIFTWIDTH) == 0) {
+ msgq(sp, M_INFO, "shiftwidth option set to 0");
+ return (0);
+ }
+
+ /*
+ * The historic version of vi permitted the user to string any number
+ * of '>' or '<' characters together, resulting in an indent of the
+ * appropriate levels. There's a special hack in ex_cmd() so that
+ * cmdp->argv[0] points to the string of '>' or '<' characters.
+ *
+ * Q: What's the difference between the people adding features
+ * to vi and the Girl Scouts?
+ * A: The Girl Scouts have mint cookies and adult supervision.
+ */
+ for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p)
+ sw += O_VAL(sp, O_SHIFTWIDTH);
+
+ GET_SPACE_RET(sp, bp, blen, 256);
+
+ curset = 0;
+ for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
+ if ((p = file_gline(sp, ep, from, &len)) == NULL)
+ goto err;
+ if (!len) {
+ if (sp->lno == from)
+ curset = 1;
+ continue;
+ }
+
+ /*
+ * Calculate the old indent amount and the number of
+ * characters it used.
+ */
+ for (oldidx = 0, oldcol = 0; oldidx < len; ++oldidx)
+ if (p[oldidx] == ' ')
+ ++oldcol;
+ else if (p[oldidx] == '\t')
+ oldcol += O_VAL(sp, O_TABSTOP) -
+ oldcol % O_VAL(sp, O_TABSTOP);
+ else
+ break;
+
+ /* Calculate the new indent amount. */
+ if (rl == RIGHT)
+ newcol = oldcol + sw;
+ else {
+ newcol = oldcol < sw ? 0 : oldcol - sw;
+ if (newcol == oldcol) {
+ if (sp->lno == from)
+ curset = 1;
+ continue;
+ }
+ }
+
+ /* Get a buffer that will hold the new line. */
+ ADD_SPACE_RET(sp, bp, blen, newcol + len);
+
+ /*
+ * Build a new indent string and count the number of
+ * characters it uses.
+ */
+ for (tbp = bp, newidx = 0;
+ newcol >= O_VAL(sp, O_TABSTOP); ++newidx) {
+ *tbp++ = '\t';
+ newcol -= O_VAL(sp, O_TABSTOP);
+ }
+ for (; newcol > 0; --newcol, ++newidx)
+ *tbp++ = ' ';
+
+ /* Add the original line. */
+ memmove(tbp, p + oldidx, len - oldidx);
+
+ /* Set the replacement line. */
+ if (file_sline(sp, ep, from, bp, (tbp + (len - oldidx)) - bp)) {
+err: FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * The shift command in historic vi had the usual bizarre
+ * collection of cursor semantics. If called from vi, the
+ * cursor was repositioned to the first non-blank character
+ * of the lowest numbered line shifted. If called from ex,
+ * the cursor was repositioned to the first non-blank of the
+ * highest numbered line shifted. Here, if the cursor isn't
+ * part of the set of lines that are moved, move it to the
+ * first non-blank of the last line shifted. (This makes
+ * ":3>>" in vi work reasonably.) If the cursor is part of
+ * the shifted lines, it doesn't get moved at all. This
+ * permits shifting of marked areas, i.e. ">'a." shifts the
+ * marked area twice, something that couldn't be done with
+ * historic vi.
+ */
+ if (sp->lno == from) {
+ curset = 1;
+ if (newidx > oldidx)
+ sp->cno += newidx - oldidx;
+ else if (sp->cno >= oldidx - newidx)
+ sp->cno -= oldidx - newidx;
+ }
+ }
+ if (!curset) {
+ sp->lno = to;
+ sp->cno = 0;
+ (void)nonblank(sp, ep, to, &sp->cno);
+ }
+
+ FREE_SPACE(sp, bp, blen);
+
+ sp->rptlines[rl == RIGHT ? L_RSHIFT : L_LSHIFT] +=
+ cmdp->addr2.lno - cmdp->addr1.lno + 1;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_source.c b/usr.bin/vi/ex/ex_source.c
new file mode 100644
index 000000000000..70b85b9568b1
--- /dev/null
+++ b/usr.bin/vi/ex/ex_source.c
@@ -0,0 +1,66 @@
+/*-
+ * 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_source.c 8.5 (Berkeley) 8/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_source -- :source file
+ * Execute ex commands from a file.
+ */
+int
+ex_source(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (ex_cfile(sp, ep, cmdp->argv[0]->bp, 0));
+}
diff --git a/usr.bin/vi/ex/ex_stop.c b/usr.bin/vi/ex/ex_stop.c
new file mode 100644
index 000000000000..3487bbb6d753
--- /dev/null
+++ b/usr.bin/vi/ex/ex_stop.c
@@ -0,0 +1,76 @@
+/*-
+ * 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_stop.c 8.7 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../sex/sex_screen.h"
+
+/*
+ * ex_stop -- :stop[!]
+ * :suspend[!]
+ * Suspend execution.
+ */
+int
+ex_stop(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ /* For some strange reason, the force flag turns off autowrite. */
+ if (!F_ISSET(cmdp, E_FORCE) &&
+ F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE) &&
+ file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
+ return (1);
+ return (sp->s_suspend(sp));
+}
diff --git a/usr.bin/vi/ex/ex_subst.c b/usr.bin/vi/ex/ex_subst.c
new file mode 100644
index 000000000000..54b6ee85097e
--- /dev/null
+++ b/usr.bin/vi/ex/ex_subst.c
@@ -0,0 +1,1001 @@
+/*-
+ * 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_subst.c 8.57 (Berkeley) 8/7/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+#define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */
+#define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */
+
+static __inline int regsub __P((SCR *, char *,
+ char **, size_t *, size_t *, regmatch_t [10]));
+static int substitute __P((SCR *, EXF *,
+ EXCMDARG *, char *, regex_t *, u_int));
+
+/*
+ * ex_substitute --
+ * [line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]]
+ *
+ * Substitute on lines matching a pattern.
+ */
+int
+ex_substitute(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ regex_t *re, lre;
+ size_t blen, len;
+ u_int flags;
+ int delim, eval, reflags, replaced;
+ char *bp, *ptrn, *rep, *p, *t;
+
+ /*
+ * Skip leading white space.
+ *
+ * !!!
+ * Historic vi allowed any non-alphanumeric to serve as the
+ * substitution command delimiter.
+ *
+ * !!!
+ * If the arguments are empty, it's the same as &, i.e. we
+ * repeat the last substitution.
+ */
+ for (p = cmdp->argv[0]->bp,
+ len = cmdp->argv[0]->len; len > 0; --len, ++p) {
+ if (!isblank(*p))
+ break;
+ }
+ if (len == 0)
+ return (ex_subagain(sp, ep, cmdp));
+ delim = *p++;
+ if (isalnum(delim))
+ return (substitute(sp, ep,
+ cmdp, p, &sp->subre, SUB_MUSTSETR));
+
+ /*
+ * !!!
+ * The full-blown substitute command reset the remembered
+ * state of the 'c' and 'g' suffices.
+ */
+ sp->c_suffix = sp->g_suffix = 0;
+
+ /*
+ * Get the pattern string, toss escaped characters.
+ *
+ * !!!
+ * Historic vi accepted any of the following forms:
+ *
+ * :s/abc/def/ change "abc" to "def"
+ * :s/abc/def change "abc" to "def"
+ * :s/abc/ delete "abc"
+ * :s/abc delete "abc"
+ *
+ * QUOTING NOTE:
+ *
+ * Only toss an escape character if it escapes a delimiter.
+ * This means that "s/A/\\\\f" replaces "A" with "\\f". It
+ * would be nice to be more regular, i.e. for each layer of
+ * escaping a single escape character is removed, but that's
+ * not how the historic vi worked.
+ */
+ for (ptrn = t = p;;) {
+ if (p[0] == '\0' || p[0] == delim) {
+ if (p[0] == delim)
+ ++p;
+ /*
+ * !!!
+ * Nul terminate the pattern string -- it's passed
+ * to regcomp which doesn't understand anything else.
+ */
+ *t = '\0';
+ break;
+ }
+ if (p[0] == '\\')
+ if (p[1] == delim)
+ ++p;
+ else if (p[1] == '\\')
+ *t++ = *p++;
+ *t++ = *p++;
+ }
+
+ /*
+ * If the pattern string is empty, use the last RE (not just the
+ * last substitution RE).
+ */
+ if (*ptrn == '\0') {
+ if (!F_ISSET(sp, S_SRE_SET)) {
+ msgq(sp, M_ERR, "No previous regular expression");
+ return (1);
+ }
+ re = &sp->sre;
+ flags = 0;
+ } else {
+ /* Set RE flags. */
+ reflags = 0;
+ if (O_ISSET(sp, O_EXTENDED))
+ reflags |= REG_EXTENDED;
+ if (O_ISSET(sp, O_IGNORECASE))
+ reflags |= REG_ICASE;
+
+ /* Convert vi-style RE's to POSIX 1003.2 RE's. */
+ if (re_conv(sp, &ptrn, &replaced))
+ return (1);
+
+ /* Compile the RE. */
+ eval = regcomp(&lre, (char *)ptrn, reflags);
+
+ /* Free up any allocated memory. */
+ if (replaced)
+ FREE_SPACE(sp, ptrn, 0);
+
+ if (eval) {
+ re_error(sp, eval, &lre);
+ return (1);
+ }
+
+ /*
+ * Set saved RE.
+ *
+ * !!!
+ * Historic practice is that substitutes set the search
+ * direction as well as both substitute and search RE's.
+ */
+ sp->searchdir = FORWARD;
+ sp->sre = lre;
+ F_SET(sp, S_SRE_SET);
+ sp->subre = lre;
+ F_SET(sp, S_SUBRE_SET);
+
+ re = &lre;
+ flags = SUB_FIRST;
+ }
+
+ /*
+ * Get the 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
+ * if O_MAGIC is set and it escapes a tilde.
+ *
+ * !!!
+ * If the entire replacement pattern is "%", then use the last
+ * replacement pattern. This semantic was added to vi in System
+ * V and then percolated elsewhere, presumably around the time
+ * that it was added to their version of ed(1).
+ */
+ if (p[0] == '\0' || p[0] == delim) {
+ if (p[0] == delim)
+ ++p;
+ if (sp->repl != NULL)
+ FREE(sp->repl, sp->repl_len);
+ sp->repl = NULL;
+ sp->repl_len = 0;
+ } else if (p[0] == '%' && (p[1] == '\0' || p[1] == delim))
+ p += p[1] == delim ? 2 : 1;
+ else {
+ for (rep = p, len = 0;
+ p[0] != '\0' && p[0] != delim; ++p, ++len)
+ if (p[0] == '~')
+ len += sp->repl_len;
+ GET_SPACE_RET(sp, bp, blen, len);
+ for (t = bp, len = 0, p = rep;;) {
+ if (p[0] == '\0' || p[0] == delim) {
+ if (p[0] == delim)
+ ++p;
+ break;
+ }
+ if (p[0] == '\\') {
+ if (p[1] == delim)
+ ++p;
+ else if (p[1] == '\\') {
+ *t++ = *p++;
+ ++len;
+ } else if (p[1] == '~') {
+ ++p;
+ if (!O_ISSET(sp, O_MAGIC))
+ goto tilde;
+ }
+ } else if (p[0] == '~' && O_ISSET(sp, O_MAGIC)) {
+tilde: ++p;
+ memmove(t, sp->repl, sp->repl_len);
+ t += sp->repl_len;
+ len += sp->repl_len;
+ continue;
+ }
+ *t++ = *p++;
+ ++len;
+ }
+ if ((sp->repl_len = len) != 0) {
+ if (sp->repl != NULL)
+ free(sp->repl);
+ if ((sp->repl = malloc(len)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ FREE_SPACE(sp, bp, blen);
+ return (1);
+ }
+ memmove(sp->repl, bp, len);
+ }
+ FREE_SPACE(sp, bp, blen);
+ }
+ return (substitute(sp, ep, cmdp, p, re, flags));
+}
+
+/*
+ * ex_subagain --
+ * [line [,line]] & [cgr] [count] [#lp]]
+ *
+ * Substitute using the last substitute RE and replacement pattern.
+ */
+int
+ex_subagain(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (!F_ISSET(sp, S_SUBRE_SET)) {
+ msgq(sp, M_ERR, "No previous regular expression");
+ return (1);
+ }
+ return (substitute(sp, ep, cmdp, cmdp->argv[0]->bp, &sp->subre, 0));
+}
+
+/*
+ * ex_subtilde --
+ * [line [,line]] ~ [cgr] [count] [#lp]]
+ *
+ * Substitute using the last RE and last substitute replacement pattern.
+ */
+int
+ex_subtilde(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (!F_ISSET(sp, S_SRE_SET)) {
+ msgq(sp, M_ERR, "No previous regular expression");
+ return (1);
+ }
+ 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
+ * to build a set of newline offsets which we use to break the line up later,
+ * when the replacement is done. Don't change it unless you're pretty damned
+ * confident.
+ */
+#define NEEDNEWLINE(sp) { \
+ if (sp->newl_len == sp->newl_cnt) { \
+ sp->newl_len += 25; \
+ REALLOC(sp, sp->newl, size_t *, \
+ sp->newl_len * sizeof(size_t)); \
+ if (sp->newl == NULL) { \
+ sp->newl_len = 0; \
+ return (1); \
+ } \
+ } \
+}
+
+#define BUILD(sp, l, len) { \
+ if (lbclen + (len) > lblen) { \
+ lblen += MAX(lbclen + (len), 256); \
+ REALLOC(sp, lb, char *, lblen); \
+ if (lb == NULL) { \
+ lbclen = 0; \
+ return (1); \
+ } \
+ } \
+ memmove(lb + lbclen, l, len); \
+ lbclen += len; \
+}
+
+#define NEEDSP(sp, len, pnt) { \
+ if (lbclen + (len) > lblen) { \
+ lblen += MAX(lbclen + (len), 256); \
+ REALLOC(sp, lb, char *, lblen); \
+ if (lb == NULL) { \
+ lbclen = 0; \
+ return (1); \
+ } \
+ pnt = lb + lbclen; \
+ } \
+}
+
+/*
+ * substitute --
+ * Do the substitution. This stuff is *really* tricky. There are
+ * lots of special cases, and general nastiness. Don't mess with it
+ * unless you're pretty confident.
+ */
+static int
+substitute(sp, ep, cmdp, s, re, flags)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ char *s;
+ regex_t *re;
+ u_int flags;
+{
+ MARK from, to;
+ recno_t elno, lno;
+ regmatch_t match[10];
+ size_t blen, cnt, last, lbclen, lblen, len, llen, offset, saved_offset;
+ int cflag, lflag, nflag, pflag, rflag;
+ int didsub, do_eol_match, eflags, empty_ok, eval;
+ int linechanged, matched, quit, rval;
+ char *bp, *lb;
+
+ /*
+ * !!!
+ * Historically, the 'g' and 'c' suffices were always toggled as flags,
+ * so ":s/A/B/" was the same as ":s/A/B/ccgg". If O_EDCOMPATIBLE was
+ * not set, they were initialized to 0 for all substitute commands. If
+ * O_EDCOMPATIBLE was set, they were initialized to 0 only if the user
+ * specified substitute/replacement patterns (see ex_substitute()).
+ */
+ if (!O_ISSET(sp, O_EDCOMPATIBLE))
+ sp->c_suffix = sp->g_suffix = 0;
+
+ /*
+ * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but
+ * it only displayed the last change. I'd disallow them, but they are
+ * useful in combination with the [v]global commands. In the current
+ * model the problem is combining them with the 'c' flag -- the screen
+ * would have to flip back and forth between the confirm screen and the
+ * ex print screen, which would be pretty awful. We do display all
+ * changes, though, for what that's worth.
+ *
+ * !!!
+ * Historic vi was fairly strict about the order of "options", the
+ * count, and "flags". I'm somewhat fuzzy on the difference between
+ * options and flags, anyway, so this is a simpler approach, and we
+ * just take it them in whatever order the user gives them. (The ex
+ * usage statement doesn't reflect this.)
+ */
+ cflag = lflag = nflag = pflag = rflag = 0;
+ for (lno = OOBLNO; *s != '\0'; ++s)
+ switch (*s) {
+ case ' ':
+ case '\t':
+ continue;
+ case '+':
+ ++cmdp->flagoff;
+ break;
+ case '-':
+ --cmdp->flagoff;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (lno != OOBLNO)
+ goto usage;
+ errno = 0;
+ lno = strtoul(s, &s, 10);
+ if (*s == '\0') /* Loop increment correction. */
+ --s;
+ if (errno == ERANGE) {
+ if (lno == LONG_MAX)
+ msgq(sp, M_ERR, "Count overflow");
+ else if (lno == LONG_MIN)
+ msgq(sp, M_ERR, "Count underflow");
+ else
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ /*
+ * In historic vi, the count was inclusive from the
+ * second address.
+ */
+ cmdp->addr1.lno = cmdp->addr2.lno;
+ cmdp->addr2.lno += lno - 1;
+ break;
+ case '#':
+ nflag = 1;
+ break;
+ case 'c':
+ sp->c_suffix = !sp->c_suffix;
+ break;
+ case 'g':
+ sp->g_suffix = !sp->g_suffix;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ if (LF_ISSET(SUB_FIRST)) {
+ msgq(sp, M_ERR,
+ "Regular expression specified; r flag meaningless");
+ return (1);
+ }
+ if (!F_ISSET(sp, S_SRE_SET)) {
+ msgq(sp, M_ERR,
+ "No previous regular expression");
+ return (1);
+ }
+ rflag = 1;
+ re = &sp->sre;
+ break;
+ default:
+ goto usage;
+ }
+
+ if (*s != '\0' || !rflag && LF_ISSET(SUB_MUSTSETR)) {
+usage: msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+
+ if (IN_VI_MODE(sp) && sp->c_suffix && (lflag || nflag || pflag)) {
+ msgq(sp, M_ERR,
+ "The #, l and p flags may not be combined with the c flag in vi mode");
+ return (1);
+ }
+
+ /*
+ * bp: if interactive, line cache
+ * blen: if interactive, line cache length
+ * lb: build buffer pointer.
+ * lbclen: current length of built buffer.
+ * lblen; length of build buffer.
+ */
+ bp = lb = NULL;
+ blen = lbclen = lblen = 0;
+
+ /* For each line... */
+ for (matched = quit = 0, lno = cmdp->addr1.lno,
+ elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) {
+
+ /* Someone's unhappy, time to stop. */
+ if (INTERRUPTED(sp)) {
+ if (!F_ISSET(sp, S_GLOBAL))
+ msgq(sp, M_INFO, "Interrupted");
+ break;
+ }
+
+ /* Get the line. */
+ if ((s = file_gline(sp, ep, lno, &llen)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ goto ret1;
+ }
+
+ /*
+ * Make a local copy if doing confirmation -- when calling
+ * the confirm routine we're likely to lose the cached copy.
+ */
+ if (sp->c_suffix) {
+ if (bp == NULL) {
+ GET_SPACE_RET(sp, bp, blen, llen);
+ } else
+ ADD_SPACE_RET(sp, bp, blen, llen);
+ memmove(bp, s, llen);
+ s = bp;
+ }
+
+ /* Start searching from the beginning. */
+ offset = 0;
+ len = llen;
+
+ /* Reset the build buffer offset. */
+ lbclen = 0;
+
+ /* Reset empty match flag. */
+ empty_ok = 1;
+
+ /*
+ * We don't want to have to do a setline if the line didn't
+ * change -- keep track of whether or not this line changed.
+ * If doing confirmations, don't want to keep setting the
+ * line if change is refused -- keep track of substitutions.
+ */
+ didsub = linechanged = 0;
+
+ /* New line, do an EOL match. */
+ do_eol_match = 1;
+
+ /* It's not nul terminated, but we pretend it is. */
+ eflags = REG_STARTEND;
+
+ /*
+ * The search area is from s + offset to the EOL.
+ *
+ * Generally, match[0].rm_so is the offset of the start
+ * of the match from the start of the search, and offset
+ * is the offset of the start of the last search.
+ */
+nextmatch: match[0].rm_so = 0;
+ match[0].rm_eo = len;
+
+ /* Get the next match. */
+ eval = regexec(re, (char *)s + offset, 10, match, eflags);
+
+ /*
+ * There wasn't a match or if there was an error, deal with
+ * it. If there was a previous match in this line, resolve
+ * the changes into the database. Otherwise, just move on.
+ */
+ if (eval == REG_NOMATCH)
+ goto endmatch;
+ if (eval != 0) {
+ re_error(sp, eval, re);
+ goto ret1;
+ }
+ matched = 1;
+
+ /* Only the first search can match an anchored expression. */
+ eflags |= REG_NOTBOL;
+
+ /*
+ * !!!
+ * It's possible to match 0-length strings -- for example, the
+ * command s;a*;X;, when matched against the string "aabb" will
+ * result in "XbXbX", i.e. the matches are "aa", the space
+ * between the b's and the space between the b's and the end of
+ * the string. There is a similar space between the beginning
+ * of the string and the a's. The rule that we use (because vi
+ * historically used it) is that any 0-length match, occurring
+ * immediately after a match, is ignored. Otherwise, the above
+ * example would have resulted in "XXbXbX". Another example is
+ * incorrectly using " *" to replace groups of spaces with one
+ * space.
+ *
+ * The way we do this is that if we just had a successful match,
+ * the starting offset does not skip characters, and the match
+ * is empty, ignore the match and move forward. If there's no
+ * more characters in the string, we were attempting to match
+ * after the last character, so quit.
+ */
+ if (!empty_ok && match[0].rm_so == 0 && match[0].rm_eo == 0) {
+ empty_ok = 1;
+ if (len == 0)
+ goto endmatch;
+ BUILD(sp, s + offset, 1)
+ ++offset;
+ --len;
+ goto nextmatch;
+ }
+
+ /* Confirm change. */
+ if (sp->c_suffix) {
+ /*
+ * Set the cursor position for confirmation. Note,
+ * if we matched on a '$', the cursor may be past
+ * the end of line.
+ *
+ * XXX
+ * We may want to "fix" this in the confirm routine,
+ * if the confirm routine should be able to display
+ * a cursor past EOL.
+ */
+ from.lno = to.lno = lno;
+ from.cno = match[0].rm_so + offset;
+ to.cno = match[0].rm_eo;
+ if (llen == 0)
+ from.cno = to.cno = 0;
+ else {
+ if (to.cno >= llen)
+ to.cno = llen - 1;
+ if (from.cno >= llen)
+ from.cno = llen - 1;
+ }
+ switch (sp->s_confirm(sp, ep, &from, &to)) {
+ case CONF_YES:
+ break;
+ case CONF_NO:
+ didsub = 0;
+ BUILD(sp, s +offset, match[0].rm_eo);
+ goto skip;
+ case CONF_QUIT:
+ /* Set the quit flag. */
+ quit = 1;
+
+ /* 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.
+ */
+ goto endmatch;
+ }
+ }
+
+ /* Copy the bytes before the match into the build buffer. */
+ BUILD(sp, s + offset, match[0].rm_so);
+
+ /* Substitute the matching bytes. */
+ didsub = 1;
+ if (regsub(sp, s + offset, &lb, &lbclen, &lblen, match))
+ goto ret1;
+
+ /* Set the change flag so we know this line was modified. */
+ linechanged = 1;
+
+ /* Move past the matched bytes. */
+skip: offset += match[0].rm_eo;
+ len -= match[0].rm_eo;
+
+ /* A match cannot be followed by an empty pattern. */
+ empty_ok = 0;
+
+ /*
+ * If doing a global change with confirmation, we have to
+ * update the screen. The basic idea is to store the line
+ * so the screen update routines can find it, and restart.
+ */
+ if (didsub && sp->c_suffix && sp->g_suffix) {
+ /*
+ * The new search offset will be the end of the
+ * modified line.
+ */
+ saved_offset = lbclen;
+
+ /* Copy the rest of the line. */
+ if (len)
+ BUILD(sp, s + offset, len)
+
+ /* Set the new offset. */
+ offset = saved_offset;
+
+ /* Store inserted lines, adjusting the build buffer. */
+ last = 0;
+ if (sp->newl_cnt) {
+ for (cnt = 0;
+ cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
+ if (file_iline(sp, ep, lno,
+ lb + last, sp->newl[cnt] - last))
+ goto ret1;
+ last = sp->newl[cnt] + 1;
+ ++sp->rptlines[L_ADDED];
+ }
+ lbclen -= last;
+ offset -= last;
+ sp->newl_cnt = 0;
+ }
+
+ /* Store and retrieve the line. */
+ if (file_sline(sp, ep, lno, lb + last, lbclen))
+ goto ret1;
+ if ((s = file_gline(sp, ep, lno, &llen)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ goto ret1;
+ }
+ ADD_SPACE_RET(sp, bp, blen, llen)
+ memmove(bp, s, llen);
+ s = bp;
+ len = llen - offset;
+
+ /* Restart the build. */
+ lbclen = 0;
+ BUILD(sp, s, offset);
+
+ /*
+ * If we haven't already done the after-the-string
+ * match, do one. Set REG_NOTEOL so the '$' pattern
+ * only matches once.
+ */
+ if (!do_eol_match)
+ goto endmatch;
+ if (offset == len) {
+ do_eol_match = 0;
+ eflags |= REG_NOTEOL;
+ }
+ goto nextmatch;
+ }
+
+ /*
+ * If it's a global:
+ *
+ * If at the end of the string, do a test for the after
+ * the string match. Set REG_NOTEOL so the '$' pattern
+ * only matches once.
+ */
+ if (sp->g_suffix && do_eol_match) {
+ if (len == 0) {
+ do_eol_match = 0;
+ eflags |= REG_NOTEOL;
+ }
+ goto nextmatch;
+ }
+
+endmatch: if (!linechanged)
+ continue;
+
+ /* Copy any remaining bytes into the build buffer. */
+ if (len)
+ BUILD(sp, s + offset, len)
+
+ /* Store inserted lines, adjusting the build buffer. */
+ last = 0;
+ if (sp->newl_cnt) {
+ for (cnt = 0;
+ cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
+ if (file_iline(sp, ep,
+ lno, lb + last, sp->newl[cnt] - last))
+ goto ret1;
+ last = sp->newl[cnt] + 1;
+ ++sp->rptlines[L_ADDED];
+ }
+ lbclen -= last;
+ sp->newl_cnt = 0;
+ }
+
+ /* Store the changed line. */
+ if (file_sline(sp, ep, lno, lb + last, lbclen))
+ goto ret1;
+
+ /* Update changed line counter. */
+ if (sp->rptlchange != lno) {
+ sp->rptlchange = lno;
+ ++sp->rptlines[L_CHANGED];
+ }
+
+ /*
+ * !!!
+ * Display as necessary. Historic practice is to only
+ * display the last line of a line split into multiple
+ * lines.
+ */
+ if (lflag || nflag || pflag) {
+ from.lno = to.lno = lno;
+ from.cno = to.cno = 0;
+ if (lflag)
+ ex_print(sp, ep, &from, &to, E_F_LIST);
+ if (nflag)
+ ex_print(sp, ep, &from, &to, E_F_HASH);
+ if (pflag)
+ ex_print(sp, ep, &from, &to, E_F_PRINT);
+ }
+
+ if (!sp->c_suffix)
+ sp->lno = lno;
+
+ /*
+ * !!!
+ * Move the cursor to the last line changed.
+ */
+ if (!sp->c_suffix)
+ sp->lno = lno;
+ }
+
+ /*
+ * !!!
+ * Move the cursor to the first non-blank of the last line change.
+ *
+ * XXX
+ * This is NOT backward compatible with historic vi, which always
+ * moved to the last line actually changed.
+ */
+ if (!sp->c_suffix) {
+ sp->cno = 0;
+ (void)nonblank(sp, ep, sp->lno, &sp->cno);
+ }
+
+ /*
+ * If not in a global command, and nothing matched, say so.
+ * Else, if none of the lines displayed, put something up.
+ */
+ if (!matched) {
+ if (!F_ISSET(sp, S_GLOBAL))
+ msgq(sp, M_INFO, "No match found");
+ } else if (!lflag && !nflag && !pflag)
+ F_SET(EXP(sp), EX_AUTOPRINT);
+
+ rval = 0;
+ if (0) {
+ret1: rval = 1;
+ }
+
+ if (bp != NULL)
+ FREE_SPACE(sp, bp, blen);
+ if (lb != NULL)
+ free(lb);
+ return (rval);
+}
+
+/*
+ * regsub --
+ * Do the substitution for a regular expression.
+ */
+static __inline int
+regsub(sp, ip, lbp, lbclenp, lblenp, match)
+ SCR *sp;
+ char *ip; /* Input line. */
+ char **lbp;
+ size_t *lbclenp, *lblenp;
+ regmatch_t match[10];
+{
+ enum { C_NOTSET, C_LOWER, C_ONELOWER, C_ONEUPPER, C_UPPER } conv;
+ size_t lbclen, lblen; /* Local copies. */
+ size_t mlen; /* Match length. */
+ size_t rpl; /* Remaining replacement length. */
+ char *rp; /* Replacement pointer. */
+ int ch;
+ int no; /* Match replacement offset. */
+ char *p, *t; /* Buffer pointers. */
+ char *lb; /* Local copies. */
+
+ lb = *lbp; /* Get local copies. */
+ lbclen = *lbclenp;
+ lblen = *lblenp;
+
+ /*
+ * QUOTING NOTE:
+ *
+ * There are some special sequences that vi provides in the
+ * replacement patterns.
+ * & string the RE matched (\& if nomagic set)
+ * \# n-th regular subexpression
+ * \E end \U, \L conversion
+ * \e end \U, \L conversion
+ * \l convert the next character to lower-case
+ * \L convert to lower-case, until \E, \e, or end of replacement
+ * \u convert the next character to upper-case
+ * \U convert to upper-case, until \E, \e, or end of replacement
+ *
+ * Otherwise, since this is the lowest level of replacement, discard
+ * all escape characters. This (hopefully) follows historic practice.
+ */
+#define ADDCH(ch) { \
+ CHAR_T __ch = (ch); \
+ u_int __value = KEY_VAL(sp, __ch); \
+ if (__value == K_CR || __value == K_NL) { \
+ NEEDNEWLINE(sp); \
+ sp->newl[sp->newl_cnt++] = lbclen; \
+ } else if (conv != C_NOTSET) { \
+ switch (conv) { \
+ case C_ONELOWER: \
+ conv = C_NOTSET; \
+ /* FALLTHROUGH */ \
+ case C_LOWER: \
+ if (isupper(__ch)) \
+ __ch = tolower(__ch); \
+ break; \
+ case C_ONEUPPER: \
+ conv = C_NOTSET; \
+ /* FALLTHROUGH */ \
+ case C_UPPER: \
+ if (islower(__ch)) \
+ __ch = toupper(__ch); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ } \
+ NEEDSP(sp, 1, p); \
+ *p++ = __ch; \
+ ++lbclen; \
+}
+ conv = C_NOTSET;
+ for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) {
+ switch (ch = *rp++) {
+ case '&':
+ if (O_ISSET(sp, O_MAGIC)) {
+ no = 0;
+ goto subzero;
+ }
+ break;
+ case '\\':
+ if (rpl == 0)
+ break;
+ --rpl;
+ switch (ch = *rp) {
+ case '&':
+ ++rp;
+ if (!O_ISSET(sp, O_MAGIC)) {
+ no = 0;
+ goto subzero;
+ }
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ no = *rp++ - '0';
+subzero: if (match[no].rm_so == -1 ||
+ match[no].rm_eo == -1)
+ break;
+ mlen = match[no].rm_eo - match[no].rm_so;
+ for (t = ip + match[no].rm_so; mlen--; ++t)
+ ADDCH(*t);
+ continue;
+ case 'e':
+ case 'E':
+ ++rp;
+ conv = C_NOTSET;
+ continue;
+ case 'l':
+ ++rp;
+ conv = C_ONELOWER;
+ continue;
+ case 'L':
+ ++rp;
+ conv = C_LOWER;
+ continue;
+ case 'u':
+ ++rp;
+ conv = C_ONEUPPER;
+ continue;
+ case 'U':
+ ++rp;
+ conv = C_UPPER;
+ continue;
+ default:
+ ++rp;
+ break;
+ }
+ }
+ ADDCH(ch);
+ }
+
+ *lbp = lb; /* Update caller's information. */
+ *lbclenp = lbclen;
+ *lblenp = lblen;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_tag.c b/usr.bin/vi/ex/ex_tag.c
new file mode 100644
index 000000000000..0bb8c3e6982f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_tag.c
@@ -0,0 +1,905 @@
+/*-
+ * 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
+ * David Hitz of Auspex Systems, Inc.
+ *
+ * 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_tag.c 8.43 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "tag.h"
+
+static char *binary_search __P((char *, char *, char *));
+static int compare __P((char *, char *, char *));
+static char *linear_search __P((char *, char *, char *));
+static int search __P((SCR *, char *, char *, char **));
+static int tag_get __P((SCR *, char *, char **, char **, char **));
+
+/*
+ * ex_tagfirst --
+ * The tag code can be entered from main, i.e. "vi -t tag".
+ */
+int
+ex_tagfirst(sp, tagarg)
+ SCR *sp;
+ char *tagarg;
+{
+ FREF *frp;
+ MARK m;
+ long tl;
+ u_int flags;
+ int sval;
+ char *p, *tag, *name, *search;
+
+ /* Taglength may limit the number of characters. */
+ if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(tagarg) > tl)
+ tagarg[tl] = '\0';
+
+ /* Get the tag information. */
+ if (tag_get(sp, tagarg, &tag, &name, &search))
+ return (1);
+
+ /* Create the file entry. */
+ if ((frp = file_add(sp, name)) == NULL)
+ return (1);
+ if (file_init(sp, frp, NULL, 0))
+ return (1);
+
+ /*
+ * !!!
+ * 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);
+ m.cno = 0;
+ } else {
+ /*
+ * Search for the tag; cheap fallback for C functions if
+ * the name is the same but the arguments have changed.
+ */
+ m.lno = 1;
+ m.cno = 0;
+ flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM;
+ sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags);
+ if (sval && (p = strrchr(search, '(')) != NULL) {
+ p[1] = '\0';
+ sval = f_search(sp, sp->ep,
+ &m, &m, search, NULL, &flags);
+ }
+ if (sval)
+ msgq(sp, M_ERR, "%s: search pattern not found", tag);
+ }
+
+ /* Set up the screen. */
+ frp->lno = m.lno;
+ frp->cno = m.cno;
+ F_SET(frp, FR_CURSORSET);
+
+ /* Might as well make this the default tag. */
+ if ((EXP(sp)->tlast = strdup(tagarg)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ 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.
+ *
+ * The tags stacks in nvi are a bit tricky. Each tag contains a file name,
+ * search string, and line/column numbers. The search string is only used
+ * for the first access and for user display. The first record on the stack
+ * is the place where we first did a tag, so it has no search string. The
+ * second record is the first tag, and so on. Note, this means that the
+ * "current" tag is always on the stack. Each tag has a line/column which is
+ * the location from which the user tagged the following TAG entry, and which
+ * is used as the return location.
+ */
+int
+ex_tagpush(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ enum {TC_CHANGE, TC_CURRENT} which;
+ EX_PRIVATE *exp;
+ FREF *frp;
+ MARK m;
+ TAG *tp;
+ u_int flags;
+ int sval;
+ long tl;
+ char *name, *p, *search, *tag;
+
+ exp = EXP(sp);
+ switch (cmdp->argc) {
+ case 1:
+ if (exp->tlast != NULL)
+ FREE(exp->tlast, strlen(exp->tlast) + 1);
+ if ((exp->tlast = strdup(cmdp->argv[0]->bp)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ break;
+ case 0:
+ if (exp->tlast == NULL) {
+ msgq(sp, M_ERR, "No previous tag entered");
+ return (1);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ /* Taglength may limit the number of characters. */
+ if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(exp->tlast) > tl)
+ exp->tlast[tl] = '\0';
+
+ /* Get the tag information. */
+ if (tag_get(sp, exp->tlast, &tag, &name, &search))
+ return (1);
+
+ /* Get the (possibly new) FREF structure. */
+ if ((frp = file_add(sp, name)) == NULL)
+ goto err;
+
+ if (sp->frp == frp)
+ which = TC_CURRENT;
+ else {
+ if (file_m1(sp, sp->ep,
+ F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE))
+ goto err;
+ which = TC_CHANGE;
+ }
+
+ /*
+ * Get a tag structure -- if this is the first tag, push it on the
+ * stack as a placeholder and get another tag structure. Set the
+ * line/column of the most recent element on the stack to be the
+ * current values, including the file pointer. Then push the new
+ * TAG onto the stack with the new file and search string for user
+ * display.
+ */
+ CALLOC(sp, tp, TAG *, 1, sizeof(TAG));
+ if (tp != NULL && exp->tagq.tqh_first == NULL) {
+ TAILQ_INSERT_HEAD(&exp->tagq, tp, q);
+ CALLOC(sp, tp, TAG *, 1, sizeof(TAG));
+ }
+ if (exp->tagq.tqh_first != NULL) {
+ exp->tagq.tqh_first->frp = sp->frp;
+ exp->tagq.tqh_first->lno = sp->lno;
+ exp->tagq.tqh_first->cno = sp->cno;
+ }
+ if (tp != NULL) {
+ if ((tp->search = strdup(search)) == NULL)
+ msgq(sp, M_SYSERR, NULL);
+ else
+ tp->slen = strlen(search);
+ tp->frp = frp;
+ TAILQ_INSERT_HEAD(&exp->tagq, tp, q);
+ }
+
+ /* 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);
+err: free(tag);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Historic vi accepted a line number as well as a search
+ * string, and people are apparently still using the format.
+ */
+ if (isdigit(search[0])) {
+ m.lno = atoi(search);
+ m.cno = 0;
+ sval = 0;
+ } else {
+ /*
+ * Search for the tag; cheap fallback for C functions
+ * if the name is the same but the arguments have changed.
+ */
+ m.lno = 1;
+ m.cno = 0;
+ flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM;
+ sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags);
+ if (sval && (p = strrchr(search, '(')) != NULL) {
+ p[1] = '\0';
+ sval = f_search(sp, sp->ep,
+ &m, &m, search, NULL, &flags);
+ p[1] = '(';
+ }
+ if (sval)
+ msgq(sp, M_ERR, "%s: search pattern not found", tag);
+ }
+ free(tag);
+
+ switch (which) {
+ case TC_CHANGE:
+ frp->lno = m.lno;
+ frp->cno = m.cno;
+ F_SET(frp, FR_CURSORSET);
+ F_SET(sp, S_FSWITCH);
+ break;
+ case TC_CURRENT:
+ if (sval)
+ return (1);
+ sp->lno = m.lno;
+ sp->cno = m.cno;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * ex_tagpop -- :tagp[op][!] [number | file]
+ * Pop the tag stack.
+ */
+int
+ex_tagpop(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ EX_PRIVATE *exp;
+ TAG *ntp, *tp;
+ long off;
+ size_t arglen;
+ char *arg, *p, *t;
+
+ /* Check for an empty stack. */
+ exp = EXP(sp);
+ if (exp->tagq.tqh_first == NULL) {
+ msgq(sp, M_INFO, "The tags stack is empty");
+ return (1);
+ }
+
+ switch (cmdp->argc) {
+ case 0: /* Pop one tag. */
+ ntp = exp->tagq.tqh_first;
+ break;
+ case 1: /* Name or number. */
+ arg = cmdp->argv[0]->bp;
+ off = strtol(arg, &p, 10);
+ if (*p == '\0') {
+ if (off < 1)
+ return (0);
+ for (tp = exp->tagq.tqh_first;
+ tp != NULL && --off > 1; tp = tp->q.tqe_next);
+ if (tp == NULL) {
+ msgq(sp, M_ERR,
+"Less than %s entries on the tags stack; use :display to see the tags stack",
+ arg);
+ return (1);
+ }
+ ntp = tp;
+ } else {
+ arglen = strlen(arg);
+ for (tp = exp->tagq.tqh_first;
+ 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))
+ break;
+ }
+ if (tp == NULL) {
+ msgq(sp, M_ERR,
+"No file named %s on the tags stack; use :display to see the tags stack",
+ arg);
+ return (1);
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+
+ /* Update the cursor from the saved TAG information. */
+ tp = ntp->q.tqe_next;
+ if (tp->frp == sp->frp) {
+ sp->lno = tp->lno;
+ sp->cno = tp->cno;
+ } else {
+ if (file_m1(sp, ep,
+ F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE))
+ return (1);
+ if (file_init(sp, tp->frp, NULL, 0))
+ return (1);
+
+ tp->frp->lno = tp->lno;
+ tp->frp->cno = tp->cno;
+ F_SET(sp->frp, FR_CURSORSET);
+
+ F_SET(sp, S_FSWITCH);
+ }
+
+ /* 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;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ EX_PRIVATE *exp;
+ TAG *tp;
+
+ /* Find oldest saved information. */
+ exp = EXP(sp);
+ 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 (tp->frp == sp->frp) {
+ sp->lno = tp->lno;
+ sp->cno = tp->cno;
+ } else {
+ if (file_m1(sp, sp->ep,
+ F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE))
+ return (1);
+ if (file_init(sp, tp->frp, NULL, 0))
+ return (1);
+
+ 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);
+}
+
+/*
+ * ex_tagdisplay --
+ * Display the list of tags.
+ */
+int
+ex_tagdisplay(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ EX_PRIVATE *exp;
+ TAG *tp;
+ size_t len, maxlen;
+ int cnt;
+ char *name;
+
+ exp = EXP(sp);
+ if ((tp = exp->tagq.tqh_first) == NULL) {
+ (void)ex_printf(EXCOOKIE, "No tags to display.\n");
+ return (0);
+ }
+
+ /*
+ * Figure out the formatting. MNOC is the maximum
+ * number of file name columns before we split the line.
+ */
+#define MNOC 15
+ for (maxlen = 0,
+ tp = exp->tagq.tqh_first; tp != NULL; tp = tp->q.tqe_next) {
+ len = strlen(name = tp->frp->name); /* The original name. */
+ if (maxlen < len && len < MNOC)
+ maxlen = len;
+ }
+
+ for (cnt = 1, tp = exp->tagq.tqh_first; tp != NULL;
+ ++cnt, tp = tp->q.tqe_next) {
+ len = strlen(name = tp->frp->name); /* The original name. */
+ if (len > maxlen || len + tp->slen > sp->cols)
+ if (tp == NULL || tp->search == NULL)
+ (void)ex_printf(EXCOOKIE,
+ "%2d %s\n", cnt, name);
+ else
+ (void)ex_printf(EXCOOKIE,
+ "%2d %s\n** %*.*s %s\n", cnt, name,
+ (int)maxlen, (int)maxlen, "", tp->search);
+ else
+ if (tp == NULL || tp->search == NULL)
+ (void)ex_printf(EXCOOKIE, "%2d %*.*s\n",
+ cnt, (int)maxlen, (int)len, name);
+ else
+ (void)ex_printf(EXCOOKIE, "%2d %*.*s %s\n",
+ cnt, (int)maxlen, (int)len, name,
+ tp->search);
+ }
+ return (0);
+}
+
+/*
+ * ex_tagalloc --
+ * Create a new list of tag files.
+ */
+int
+ex_tagalloc(sp, str)
+ SCR *sp;
+ char *str;
+{
+ EX_PRIVATE *exp;
+ TAGF *tp;
+ size_t len;
+ char *p, *t;
+
+ /* Free current queue. */
+ exp = EXP(sp);
+ while ((tp = exp->tagfq.tqh_first) != NULL)
+ FREETAGF(tp);
+
+ /* Create new queue. */
+ for (p = t = str;; ++p) {
+ if (*p == '\0' || isblank(*p)) {
+ if ((len = p - t) > 1) {
+ MALLOC_RET(sp, tp, TAGF *, sizeof(TAGF));
+ MALLOC(sp, tp->name, char *, len + 1);
+ if (tp->name == NULL) {
+ FREE(tp, sizeof(TAGF));
+ return (1);
+ }
+ memmove(tp->name, t, len);
+ tp->name[len] = '\0';
+ tp->flags = 0;
+ TAILQ_INSERT_TAIL(&exp->tagfq, tp, q);
+ }
+ t = p + 1;
+ }
+ if (*p == '\0')
+ break;
+ }
+ return (0);
+}
+ /* Free previous queue. */
+/*
+ * ex_tagfree --
+ * Free the tags file list.
+ */
+int
+ex_tagfree(sp)
+ SCR *sp;
+{
+ EX_PRIVATE *exp;
+ TAG *tp;
+ TAGF *tfp;
+
+ /* Free up tag information. */
+ exp = EXP(sp);
+ while ((tp = exp->tagq.tqh_first) != NULL)
+ FREETAG(tp);
+ while ((tfp = exp->tagfq.tqh_first) != NULL)
+ FREETAGF(tfp);
+ if (exp->tlast != NULL)
+ free(exp->tlast);
+ return (0);
+}
+
+/*
+ * ex_tagcopy --
+ * Copy a screen's tag structures.
+ */
+int
+ex_tagcopy(orig, sp)
+ SCR *orig, *sp;
+{
+ EX_PRIVATE *oexp, *nexp;
+ TAG *ap, *tp;
+ TAGF *atfp, *tfp;
+
+ /* Copy tag stack. */
+ oexp = EXP(orig);
+ nexp = EXP(sp);
+ for (ap = oexp->tagq.tqh_first; ap != NULL; ap = ap->q.tqe_next) {
+ MALLOC(sp, tp, TAG *, sizeof(TAG));
+ if (tp == NULL)
+ goto nomem;
+ *tp = *ap;
+ if (ap->search != NULL &&
+ (tp->search = strdup(ap->search)) == NULL)
+ goto nomem;
+ TAILQ_INSERT_TAIL(&nexp->tagq, tp, q);
+ }
+
+ /* Copy list of tag files. */
+ for (atfp = oexp->tagfq.tqh_first;
+ atfp != NULL; atfp = atfp->q.tqe_next) {
+ MALLOC(sp, tfp, TAGF *, sizeof(TAGF));
+ if (tfp == NULL)
+ goto nomem;
+ *tfp = *atfp;
+ if ((tfp->name = strdup(atfp->name)) == NULL)
+ goto nomem;
+ TAILQ_INSERT_TAIL(&nexp->tagfq, tfp, q);
+ }
+
+ /* Copy the last tag. */
+ if (oexp->tlast != NULL &&
+ (nexp->tlast = strdup(oexp->tlast)) == NULL) {
+nomem: msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * tag_get --
+ * Get a tag from the tags files.
+ */
+static int
+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, pbuf[MAXPATHLEN];
+
+ /*
+ * Find the tag, only display missing file messages once, and
+ * then only if we didn't find the tag.
+ */
+ dne = 0;
+ exp = EXP(sp);
+ for (p = NULL, tfp = exp->tagfq.tqh_first;
+ tfp != NULL && p == NULL; tfp = tfp->q.tqe_next) {
+ errno = 0;
+ F_CLR(tfp, TAGF_DNE);
+ if (search(sp, tfp->name, tag, &p))
+ if (errno == ENOENT) {
+ if (!F_ISSET(tfp, TAGF_DNE_WARN)) {
+ dne = 1;
+ F_SET(tfp, TAGF_DNE);
+ }
+ } 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)
+ for (tfp = exp->tagfq.tqh_first;
+ tfp != NULL; tfp = tfp->q.tqe_next)
+ if (F_ISSET(tfp, TAGF_DNE)) {
+ errno = ENOENT;
+ msgq(sp, M_SYSERR, tfp->name);
+ F_SET(tfp, TAGF_DNE_WARN);
+ }
+ return (1);
+ }
+
+ /*
+ * Set the return pointers; tagp points to the tag, and, incidentally
+ * 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')
+ goto malformed;
+ for (*p++ = '\0'; isblank(*p); ++p);
+ for (*filep = p; *p && !isblank(*p); ++p);
+ if (*p == '\0')
+ goto malformed;
+ for (*p++ = '\0'; isblank(*p); ++p);
+ *searchp = p;
+ if (*p == '\0') {
+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);
+}
+
+#define EQUAL 0
+#define GREATER 1
+#define LESS (-1)
+
+/*
+ * search --
+ * Search a file for a tag.
+ */
+static int
+search(sp, name, tname, tag)
+ SCR *sp;
+ char *name, *tname, **tag;
+{
+ struct stat sb;
+ int fd, len;
+ char *endp, *back, *front, *map, *p;
+
+ if ((fd = open(name, O_RDONLY, 0)) < 0)
+ return (1);
+
+ /*
+ * XXX
+ * We'd like to test if the file is too big to mmap. Since we don't
+ * know what size or type off_t's or size_t's are, what the largest
+ * unsigned integral type is, or what random insanity the local C
+ * compiler will perpetrate, doing the comparison in a portable way
+ * is flatly impossible. Hope that malloc fails if the file is too
+ * large.
+ */
+ if (fstat(fd, &sb) || (map = mmap(NULL, (size_t)sb.st_size,
+ PROT_READ, MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) {
+ (void)close(fd);
+ return (1);
+ }
+ front = map;
+ back = front + sb.st_size;
+
+ front = binary_search(tname, front, back);
+ front = linear_search(tname, front, back);
+
+ if (front == NULL || (endp = strchr(front, '\n')) == NULL) {
+ *tag = NULL;
+ goto done;
+ }
+
+ len = endp - front;
+ MALLOC(sp, p, char *, len + 1);
+ if (p == NULL) {
+ *tag = NULL;
+ goto done;
+ }
+ memmove(p, front, len);
+ p[len] = '\0';
+ *tag = p;
+
+done: if (munmap(map, (size_t)sb.st_size))
+ msgq(sp, M_SYSERR, "munmap");
+ if (close(fd))
+ msgq(sp, M_SYSERR, "close");
+ return (0);
+}
+
+/*
+ * 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
+ * matching string.
+ *
+ * back points to the beginning of a line at or after the first
+ * matching line.
+ *
+ * Base of the Invariants.
+ * 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,
+ * p is the new front. Otherwise it is the new back.
+ *
+ * Termination:
+ *
+ * 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
+ * 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
+ * more trouble than it's worth.
+ */
+#define SKIP_PAST_NEWLINE(p, back) while (p < back && *p++ != '\n');
+
+static char *
+binary_search(string, front, back)
+ register char *string, *front, *back;
+{
+ register char *p;
+
+ p = front + (back - front) / 2;
+ SKIP_PAST_NEWLINE(p, back);
+
+ while (p != back) {
+ if (compare(string, p, back) == GREATER)
+ front = p;
+ else
+ back = p;
+ p = front + (back - front) / 2;
+ SKIP_PAST_NEWLINE(p, back);
+ }
+ return (front);
+}
+
+/*
+ * 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 is before or at the first line to be printed.
+ */
+static char *
+linear_search(string, front, back)
+ char *string, *front, *back;
+{
+ while (front < back) {
+ switch (compare(string, front, back)) {
+ case EQUAL: /* Found it. */
+ return (front);
+ case LESS: /* No such string. */
+ return (NULL);
+ case GREATER: /* Keep going. */
+ break;
+ }
+ SKIP_PAST_NEWLINE(front, back);
+ }
+ return (NULL);
+}
+
+/*
+ * 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(s2) are GREATER.
+ *
+ * The string "s1" is null terminated. The string s2 is '\t', space, (or
+ * "back") terminated.
+ *
+ * !!!
+ * Reasonably modern ctags programs use tabs as separators, not spaces.
+ * However, historic programs did use spaces, and, I got complaints.
+ */
+static int
+compare(s1, s2, back)
+ register char *s1, *s2, *back;
+{
+ for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2)
+ if (*s1 != *s2)
+ return (*s1 < *s2 ? LESS : GREATER);
+ return (*s1 ? GREATER : s2 < back &&
+ (*s2 != '\t' && *s2 != ' ') ? LESS : EQUAL);
+}
diff --git a/usr.bin/vi/ex/ex_undo.c b/usr.bin/vi/ex/ex_undo.c
new file mode 100644
index 000000000000..433169670509
--- /dev/null
+++ b/usr.bin/vi/ex/ex_undo.c
@@ -0,0 +1,103 @@
+/*-
+ * 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_undo.c 8.7 (Berkeley) 8/9/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_undo -- u
+ * Undo the last change.
+ */
+int
+ex_undo(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ MARK m;
+
+ /*
+ * !!!
+ * Historic undo always set the previous context mark.
+ */
+ m.lno = sp->lno;
+ m.cno = sp->cno;
+ if (mark_set(sp, ep, ABSMARK1, &m, 1))
+ return (1);
+
+ /*
+ * !!!
+ * Multiple undo isn't available in ex, as there's no '.' command.
+ * Whether 'u' is undo or redo is toggled each time, unless there
+ * was a change since the last undo, in which case it's an undo.
+ */
+ if (!F_ISSET(ep, F_UNDO)) {
+ F_SET(ep, F_UNDO);
+ ep->lundo = FORWARD;
+ }
+ switch (ep->lundo) {
+ case BACKWARD:
+ if (log_forward(sp, ep, &m))
+ return (1);
+ ep->lundo = FORWARD;
+ break;
+ case FORWARD:
+ if (log_backward(sp, ep, &m))
+ return (1);
+ ep->lundo = BACKWARD;
+ break;
+ case NOTSET:
+ abort();
+ }
+ sp->lno = m.lno;
+ sp->cno = m.cno;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_usage.c b/usr.bin/vi/ex/ex_usage.c
new file mode 100644
index 000000000000..b6031b5caa1a
--- /dev/null
+++ b/usr.bin/vi/ex/ex_usage.c
@@ -0,0 +1,197 @@
+/*-
+ * 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_usage.c 8.19 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../vi/vcmd.h"
+
+/*
+ * ex_help -- :help
+ * Display help message.
+ */
+int
+ex_help(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ (void)ex_printf(EXCOOKIE,
+ "To see the list of vi commands, enter \":viusage<CR>\"\n");
+ (void)ex_printf(EXCOOKIE,
+ "To see the list of ex commands, enter \":exusage<CR>\"\n");
+ (void)ex_printf(EXCOOKIE,
+ "For an ex command usage statement enter \":exusage [cmd]<CR>\"\n");
+ (void)ex_printf(EXCOOKIE,
+ "For a vi key usage statement enter \":viusage [key]<CR>\"\n");
+ (void)ex_printf(EXCOOKIE, "To exit, enter \":q!\"\n");
+ return (0);
+}
+
+/*
+ * ex_usage -- :exusage [cmd]
+ * Display ex usage strings.
+ */
+int
+ex_usage(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ ARGS *ap;
+ EXCMDLIST const *cp;
+ char *name;
+
+ switch (cmdp->argc) {
+ case 1:
+ ap = cmdp->argv[0];
+ for (cp = cmds; cp->name != NULL &&
+ memcmp(ap->bp, cp->name, ap->len); ++cp);
+ if (cp->name == NULL)
+ (void)ex_printf(EXCOOKIE,
+ "The %.*s command is unknown",
+ (int)ap->len, ap->bp);
+ else {
+ (void)ex_printf(EXCOOKIE,
+ "Command: %s\n Usage: %s\n", cp->help, cp->usage);
+ /*
+ * !!!
+ * The "visual" command has two modes, one from ex,
+ * one from the vi colon line. Don't ask.
+ */
+ if (cp != &cmds[C_VISUAL_EX] &&
+ cp != &cmds[C_VISUAL_VI])
+ break;
+ if (cp == &cmds[C_VISUAL_EX])
+ cp = &cmds[C_VISUAL_VI];
+ else
+ cp = &cmds[C_VISUAL_EX];
+ (void)ex_printf(EXCOOKIE,
+ "Command: %s\n Usage: %s\n", cp->help, cp->usage);
+ }
+ break;
+ case 0:
+ 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, name, cp->help);
+ }
+ break;
+ default:
+ abort();
+ }
+ return (0);
+}
+
+/*
+ * ex_viusage -- :viusage [key]
+ * Display vi usage strings.
+ */
+int
+ex_viusage(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ VIKEYS const *kp;
+ int key;
+
+ switch (cmdp->argc) {
+ case 1:
+ if (cmdp->argv[0]->len != 1) {
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+ key = cmdp->argv[0]->bp[0];
+ if (key > MAXVIKEY)
+ goto nokey;
+
+ /* Special case: '[' and ']' commands. */
+ if ((key == '[' || key == ']') && cmdp->argv[0]->bp[1] != key)
+ goto nokey;
+
+ /* Special case: ~ command. */
+ if (key == '~' && O_ISSET(sp, O_TILDEOP))
+ kp = &tmotion;
+ else
+ kp = &vikeys[key];
+
+ if (kp->func == NULL)
+nokey: (void)ex_printf(EXCOOKIE,
+ "The %s key has no current meaning",
+ KEY_NAME(sp, key));
+ else
+ (void)ex_printf(EXCOOKIE,
+ " Key:%s%s\nUsage: %s\n",
+ isblank(*kp->help) ? "" : " ", kp->help, kp->usage);
+ break;
+ case 0:
+ F_SET(sp, S_INTERRUPTIBLE);
+ for (key = 0; key <= MAXVIKEY; ++key) {
+ /* Special case: ~ command. */
+ if (key == '~' && O_ISSET(sp, O_TILDEOP))
+ kp = &tmotion;
+ else
+ kp = &vikeys[key];
+ if (kp->help != NULL)
+ (void)ex_printf(EXCOOKIE, "%s\n", kp->help);
+ }
+ break;
+ default:
+ abort();
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_util.c b/usr.bin/vi/ex/ex_util.c
new file mode 100644
index 000000000000..e88c28f0e806
--- /dev/null
+++ b/usr.bin/vi/ex/ex_util.c
@@ -0,0 +1,189 @@
+/*-
+ * 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.12 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.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 (errno = 0, off = 0, p = exp->ibp;;) {
+ if (off >= exp->ibp_len) {
+ BINC_RET(sp, exp->ibp, exp->ibp_len, off + 1);
+ p = exp->ibp + off;
+ }
+ if ((ch = getc(fp)) == EOF && !feof(fp)) {
+ if (errno == EINTR) {
+ errno = 0;
+ clearerr(fp);
+ continue;
+ }
+ return (1);
+ }
+ if (ch == EOF || ch == '\n') {
+ if (ch == EOF && !off)
+ return (1);
+ *lenp = off;
+ return (0);
+ }
+ *p++ = ch;
+ ++off;
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * ex_sleave --
+ * Save the terminal/signal state, screen modification time.
+ * Specific to ex/filter.c and ex/ex_shell.c.
+ */
+int
+ex_sleave(sp)
+ SCR *sp;
+{
+ struct stat sb;
+ EX_PRIVATE *exp;
+
+ /* Ignore sessions not using tty's. */
+ if (!F_ISSET(sp->gp, G_STDIN_TTY))
+ return (1);
+
+ exp = EXP(sp);
+ if (tcgetattr(STDIN_FILENO, &exp->leave_term)) {
+ msgq(sp, M_SYSERR, "tcgetattr");
+ return (1);
+ }
+ if (tcsetattr(STDIN_FILENO,
+ TCSANOW | TCSASOFT, &sp->gp->original_termios)) {
+ msgq(sp, M_SYSERR, "tcsetattr");
+ 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);
+
+ /* Restore the terminal modes. */
+ if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, &exp->leave_term))
+ msgq(sp, M_SYSERR, "tcsetattr");
+
+ /* 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);
+}
+
+/*
+ * ex_ncheck --
+ * Check for more files to edit.
+ */
+int
+ex_ncheck(sp, force)
+ SCR *sp;
+ int force;
+{
+ /*
+ * !!!
+ * Historic practice: quit! or two quit's done in succession
+ * (where ZZ counts as a quit) didn't check for other files.
+ */
+ if (!force && sp->ccnt != sp->q_ccnt + 1 &&
+ sp->cargv != NULL && sp->cargv[1] != NULL) {
+ sp->q_ccnt = sp->ccnt;
+ msgq(sp, M_ERR,
+ "More files to edit; use n[ext] to go to the next file, q[uit]! to quit");
+ return (1);
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_version.c b/usr.bin/vi/ex/ex_version.c
new file mode 100644
index 000000000000..31c2cb711ca5
--- /dev/null
+++ b/usr.bin/vi/ex/ex_version.c
@@ -0,0 +1,71 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ex_version.c 8.62 (Berkeley) 8/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_version -- :version
+ * Display the program version.
+ */
+int
+ex_version(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ static time_t then = 776975285;
+
+ (void)ex_printf(EXCOOKIE,
+"Version 1.32, %sThe CSRG, University of California, Berkeley.\n",
+ ctime(&then));
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_visual.c b/usr.bin/vi/ex/ex_visual.c
new file mode 100644
index 000000000000..cfb0c139f77f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_visual.c
@@ -0,0 +1,137 @@
+/*-
+ * 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_visual.c 8.13 (Berkeley) 7/18/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags]
+ *
+ * Switch to visual mode.
+ */
+int
+ex_visual(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ size_t len;
+ int pos;
+ char buf[256];
+
+ /* If open option off, disallow visual command. */
+ if (!O_ISSET(sp, O_OPEN)) {
+ msgq(sp, M_ERR,
+ "The visual command requires that the open option be set");
+ return (1);
+ }
+
+ /* If a line specified, move to that line. */
+ if (cmdp->addrcnt)
+ sp->lno = cmdp->addr1.lno;
+
+ /*
+ * Push a command based on the line position flags. If no
+ * flag specified, the line goes at the top of the screen.
+ */
+ switch (F_ISSET(cmdp, E_F_CARAT | E_F_DASH | E_F_DOT | E_F_PLUS)) {
+ case E_F_CARAT:
+ pos = '^';
+ break;
+ case E_F_DASH:
+ pos = '-';
+ break;
+ case E_F_DOT:
+ pos = '.';
+ break;
+ case E_F_PLUS:
+ pos = '+';
+ break;
+ default:
+ sp->frp->lno = sp->lno;
+ sp->frp->cno = 0;
+ F_SET(sp->frp, FR_CURSORSET | FR_FNONBLANK);
+ goto nopush;
+ }
+
+ if (F_ISSET(cmdp, E_COUNT))
+ len = snprintf(buf, sizeof(buf),
+ "%luz%c%lu", sp->lno, pos, cmdp->count);
+ else
+ len = snprintf(buf, sizeof(buf), "%luz%c", sp->lno, pos);
+ (void)term_push(sp, buf, len, CH_NOMAP | CH_QUOTED);
+
+ /*
+ * !!!
+ * Historically, if no line address was specified, the [p#l] flags
+ * caused the cursor to be moved to the last line of the file, which
+ * was then positioned as described above. This seems useless, so
+ * I haven't implemented it.
+ */
+ switch (F_ISSET(cmdp, E_F_HASH | E_F_LIST | E_F_PRINT)) {
+ case E_F_HASH:
+ O_SET(sp, O_NUMBER);
+ break;
+ case E_F_LIST:
+ O_SET(sp, O_LIST);
+ break;
+ case E_F_PRINT:
+ break;
+ }
+
+ /* Switch modes. */
+nopush: F_CLR(sp, S_SCREENS);
+ F_SET(sp, sp->saved_vi_mode);
+
+ return (0);
+}
diff --git a/usr.bin/vi/ex/ex_write.c b/usr.bin/vi/ex/ex_write.c
new file mode 100644
index 000000000000..3dbb6e84a08f
--- /dev/null
+++ b/usr.bin/vi/ex/ex_write.c
@@ -0,0 +1,327 @@
+/*-
+ * 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_write.c 8.36 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+enum which {WN, WQ, WRITE, XIT};
+
+static int exwr __P((SCR *, EXF *, EXCMDARG *, enum which));
+
+/*
+ * ex_wn -- :wn[!] [>>] [file]
+ * Write to a file and switch to the next one.
+ */
+int
+ex_wn(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ if (exwr(sp, ep, cmdp, WN))
+ return (1);
+ if (file_m3(sp, ep, 0))
+ return (1);
+
+ /* The file name isn't a new file to edit. */
+ cmdp->argc = 0;
+
+ return (ex_next(sp, ep, cmdp));
+}
+
+/*
+ * ex_wq -- :wq[!] [>>] [file]
+ * Write to a file and quit.
+ */
+int
+ex_wq(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ int force;
+
+ if (exwr(sp, ep, cmdp, WQ))
+ return (1);
+ if (file_m3(sp, ep, 0))
+ return (1);
+
+ force = F_ISSET(cmdp, E_FORCE);
+
+ if (ex_ncheck(sp, force))
+ return (1);
+
+ F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
+ return (0);
+}
+
+/*
+ * ex_write -- :write[!] [>>] [file]
+ * :write [!] [cmd]
+ * Write to a file.
+ */
+int
+ex_write(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (exwr(sp, ep, cmdp, WRITE));
+}
+
+
+/*
+ * ex_xit -- :x[it]! [file]
+ *
+ * Write out any modifications and quit.
+ */
+int
+ex_xit(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ int force;
+
+ if (F_ISSET((ep), F_MODIFIED) && exwr(sp, ep, cmdp, XIT))
+ return (1);
+ if (file_m3(sp, ep, 0))
+ return (1);
+
+ force = F_ISSET(cmdp, E_FORCE);
+
+ if (ex_ncheck(sp, force))
+ return (1);
+
+ F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
+ return (0);
+}
+
+/*
+ * exwr --
+ * The guts of the ex write commands.
+ */
+static int
+exwr(sp, ep, cmdp, cmd)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+ enum which cmd;
+{
+ EX_PRIVATE *exp;
+ MARK rm;
+ int flags;
+ char *name, *p;
+
+ /* All write commands can have an associated '!'. */
+ LF_INIT(FS_POSSIBLE);
+ if (F_ISSET(cmdp, E_FORCE))
+ LF_SET(FS_FORCE);
+
+ /* Skip any leading whitespace. */
+ if (cmdp->argc != 0)
+ for (p = cmdp->argv[0]->bp; *p && isblank(*p); ++p);
+
+ /* If no arguments, just write the file back. */
+ if (cmdp->argc == 0 || *p == '\0') {
+ if (F_ISSET(cmdp, E_ADDR2_ALL))
+ LF_SET(FS_ALL);
+ return (file_write(sp, ep,
+ &cmdp->addr1, &cmdp->addr2, NULL, flags));
+ }
+
+ /* If "write !" it's a pipe to a utility. */
+ exp = EXP(sp);
+ if (cmd == WRITE && *p == '!') {
+ for (++p; *p && isblank(*p); ++p);
+ if (*p == '\0') {
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+ /* Expand the argument. */
+ if (argv_exp1(sp, ep, cmdp, p, strlen(p), 0))
+ return (1);
+ if (filtercmd(sp, ep, &cmdp->addr1, &cmdp->addr2,
+ &rm, cmdp->argv[1]->bp, FILTER_WRITE))
+ return (1);
+ sp->lno = rm.lno;
+ return (0);
+ }
+
+ /* If "write >>" it's an append to a file. */
+ if (cmd != XIT && p[0] == '>' && p[1] == '>') {
+ LF_SET(FS_APPEND);
+
+ /* Skip ">>" and whitespace. */
+ for (p += 2; *p && isblank(*p); ++p);
+ }
+
+ /* Build an argv so we get an argument count and file expansion. */
+ if (argv_exp2(sp, ep, cmdp, p, strlen(p), 0))
+ return (1);
+
+ switch (cmdp->argc) {
+ case 1:
+ /*
+ * Nothing to expand, write the current file.
+ * XXX
+ * Should never happen, already checked this case.
+ */
+ name = NULL;
+ break;
+ case 2:
+ /* One new argument, write it. */
+ name = cmdp->argv[exp->argsoff - 1]->bp;
+ set_alt_name(sp, name);
+ break;
+ default:
+ /* If expanded to more than one argument, object. */
+ msgq(sp, M_ERR, "%s expanded into too many file names",
+ cmdp->argv[0]->bp);
+ msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
+ return (1);
+ }
+
+ if (F_ISSET(cmdp, E_ADDR2_ALL))
+ LF_SET(FS_ALL);
+ return (file_write(sp, ep, &cmdp->addr1, &cmdp->addr2, name, flags));
+}
+
+/*
+ * ex_writefp --
+ * Write a range of lines to a FILE *.
+ */
+int
+ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
+ SCR *sp;
+ EXF *ep;
+ char *name;
+ FILE *fp;
+ MARK *fm, *tm;
+ u_long *nlno, *nch;
+{
+ 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;
+ tline = tm->lno;
+
+ if (nlno != NULL) {
+ *nch = 0;
+ *nlno = 0;
+ }
+
+ /*
+ * The vi filter code has multiple processes running simultaneously,
+ * and one of them calls ex_writefp(). The "unsafe" function calls
+ * in this code are to file_gline() and msgq(). File_gline() is safe,
+ * see the comment in filter.c:filtercmd() for details. We don't call
+ * msgq if the multiple process bit in the EXF is set.
+ *
+ * !!!
+ * Historic vi permitted files of 0 length to be written. However,
+ * since the way vi got around dealing with "empty" files was to
+ * always have a line in the file no matter what, it wrote them as
+ * files of a single, empty line. We write empty files.
+ *
+ * "Alex, I'll take vi trivia for $1000."
+ */
+ ccnt = 0;
+ lcnt = 0;
+ if (tline != 0) {
+ for (; fline <= tline; ++fline, ++lcnt) {
+ /* Caller has to provide any interrupt message. */
+ if (INTERRUPTED(sp))
+ break;
+ if ((p = file_gline(sp, ep, fline, &len)) == NULL)
+ break;
+ if (fwrite(p, 1, len, fp) != len) {
+ msgq(sp, M_SYSERR, name);
+ (void)fclose(fp);
+ return (1);
+ }
+ ccnt += len;
+ if (putc('\n', fp) != '\n')
+ break;
+ ++ccnt;
+ }
+ }
+
+ /* 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 = lcnt;
+ }
+ return (0);
+
+err: if (!F_ISSET(ep, F_MULTILOCK))
+ msgq(sp, M_SYSERR, name);
+ return (1);
+}
diff --git a/usr.bin/vi/ex/ex_yank.c b/usr.bin/vi/ex/ex_yank.c
new file mode 100644
index 000000000000..7f5d28002945
--- /dev/null
+++ b/usr.bin/vi/ex/ex_yank.c
@@ -0,0 +1,69 @@
+/*-
+ * 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_yank.c 8.5 (Berkeley) 5/17/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_yank -- :[line [,line]] ya[nk] [buffer] [count]
+ *
+ * Yank the lines into a buffer.
+ */
+int
+ex_yank(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ return (cut(sp, ep,
+ F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL,
+ &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE));
+}
diff --git a/usr.bin/vi/ex/ex_z.c b/usr.bin/vi/ex/ex_z.c
new file mode 100644
index 000000000000..a5917b315974
--- /dev/null
+++ b/usr.bin/vi/ex/ex_z.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_z.c 8.6 (Berkeley) 7/23/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * ex_z -- :[line] z [^-.+=] [count] [flags]
+ *
+ * Adjust window.
+ */
+int
+ex_z(sp, ep, cmdp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *cmdp;
+{
+ MARK abs;
+ recno_t cnt, equals, lno;
+ int eofcheck;
+
+ /*
+ * !!!
+ * If no count specified, use either two times the size of the
+ * scrolling region, or the size of the window option. POSIX
+ * 1003.2 claims that the latter is correct, but historic ex/vi
+ * documentation and practice appear to use the scrolling region.
+ * I'm using the window size as it means that the entire screen
+ * is used instead of losing a line to roundoff. Note, we drop
+ * a line from the cnt if using the window size to leave room for
+ * the next ex prompt.
+ */
+ if (F_ISSET(cmdp, E_COUNT))
+ cnt = cmdp->count;
+ else
+#ifdef HISTORIC_PRACTICE
+ cnt = O_VAL(sp, O_SCROLL) * 2;
+#else
+ cnt = O_VAL(sp, O_WINDOW) - 1;
+#endif
+
+ equals = 0;
+ eofcheck = 0;
+ lno = cmdp->addr1.lno;
+
+ switch (F_ISSET(cmdp,
+ E_F_CARAT | E_F_DASH | E_F_DOT | E_F_EQUAL | E_F_PLUS)) {
+ case E_F_CARAT: /* Display cnt * 2 before the line. */
+ eofcheck = 1;
+ if (lno > cnt * 2)
+ cmdp->addr1.lno = (lno - cnt * 2) + 1;
+ else
+ cmdp->addr1.lno = 1;
+ cmdp->addr2.lno = (cmdp->addr1.lno + cnt) - 1;
+ break;
+ case E_F_DASH: /* Line goes at the bottom of the screen. */
+ cmdp->addr1.lno = lno > cnt ? (lno - cnt) + 1 : 1;
+ cmdp->addr2.lno = lno;
+ break;
+ case E_F_DOT: /* Line goes in the middle of the screen. */
+ /*
+ * !!!
+ * Historically, the "middleness" of the line overrode the
+ * count, so that "3z.19" or "3z.20" would display the first
+ * 12 lines of the file, i.e. (N - 1) / 2 lines before and
+ * after the specified line.
+ */
+ eofcheck = 1;
+ cnt = (cnt - 1) / 2;
+ cmdp->addr1.lno = lno > cnt ? lno - cnt : 1;
+ cmdp->addr2.lno = lno + cnt;
+
+ /*
+ * !!!
+ * Historically, z. set the absolute cursor mark.
+ */
+ abs.lno = sp->lno;
+ abs.cno = sp->cno;
+ (void)mark_set(sp, ep, ABSMARK1, &abs, 1);
+ break;
+ case E_F_EQUAL: /* Center with hyphens. */
+ /*
+ * !!!
+ * Strangeness. The '=' flag is like the '.' flag (see the
+ * above comment, it applies here as well) but with a special
+ * little hack. Print out lines of hyphens before and after
+ * the specified line. Additionally, the cursor remains set
+ * on that line.
+ */
+ eofcheck = 1;
+ cnt = (cnt - 1) / 2;
+ cmdp->addr1.lno = lno > cnt ? lno - cnt : 1;
+ cmdp->addr2.lno = lno - 1;
+ if (ex_pr(sp, ep, cmdp))
+ return (1);
+ (void)ex_printf(EXCOOKIE,
+ "%s", "----------------------------------------\n");
+ cmdp->addr2.lno = cmdp->addr1.lno = equals = lno;
+ if (ex_pr(sp, ep, cmdp))
+ return (1);
+ (void)ex_printf(EXCOOKIE,
+ "%s", "----------------------------------------\n");
+ cmdp->addr1.lno = lno + 1;
+ cmdp->addr2.lno = (lno + cnt) - 1;
+ break;
+ default:
+ /* If no line specified, move to the next one. */
+ if (F_ISSET(cmdp, E_ADDRDEF))
+ ++lno;
+ /* FALLTHROUGH */
+ case E_F_PLUS: /* Line goes at the top of the screen. */
+ eofcheck = 1;
+ cmdp->addr1.lno = lno;
+ cmdp->addr2.lno = (lno + cnt) - 1;
+ break;
+ }
+
+ if (eofcheck) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (cmdp->addr2.lno > lno)
+ cmdp->addr2.lno = lno;
+ }
+
+ if (ex_pr(sp, ep, cmdp))
+ return (1);
+ if (equals)
+ sp->lno = equals;
+ return (0);
+}
diff --git a/usr.bin/vi/ex/excmd.awk b/usr.bin/vi/ex/excmd.awk
new file mode 100644
index 000000000000..289022051cdd
--- /dev/null
+++ b/usr.bin/vi/ex/excmd.awk
@@ -0,0 +1,6 @@
+# @(#)excmd.awk 8.1 (Berkeley) 4/17/94
+
+/^\/\* C_[0-9A-Z_]* \*\/$/ {
+ printf("#define %s %d\n", $2, cnt++);
+ next;
+}
diff --git a/usr.bin/vi/ex/excmd.c b/usr.bin/vi/ex/excmd.c
new file mode 100644
index 000000000000..384576862348
--- /dev/null
+++ b/usr.bin/vi/ex/excmd.c
@@ -0,0 +1,458 @@
+/*-
+ * 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[] = "@(#)excmd.c 8.58 (Berkeley) 8/9/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+/*
+ * This array maps ex command names to command functions.
+ *
+ * The order in which command names are listed below is important --
+ * ambiguous abbreviations are resolved to be the first possible match,
+ * 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
+ * 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:
+ *
+ * ! -- ! flag
+ * 1 -- flags: [+-]*[pl#][+-]*
+ * 2 -- flags: [-.+^]
+ * 3 -- flags: [-.+^=]
+ * b -- buffer
+ * c[01+a] -- count (0-N, 1-N, signed 1-N, address offset)
+ * f[N#][or] -- file (a number or N, optional or required)
+ * l -- line
+ * S -- string with file name expansion
+ * s -- string
+ * W -- word string
+ * 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",
+ "[line [,line]] ! command",
+ "filter lines through commands or run commands"},
+/* C_HASH */
+ {"#", ex_number, E_ADDR2|E_F_PRCLEAR|E_NORC,
+ "ca1",
+ "[line [,line]] # [count] [l]",
+ "display numbered lines"},
+/* C_SUBAGAIN */
+ {"&", ex_subagain, E_ADDR2|E_NORC,
+ "s",
+ "[line [,line]] & [cgr] [count] [#lp]",
+ "repeat the last subsitution"},
+/* C_STAR */
+ {"*", ex_at, 0,
+ "b",
+ "* [buffer]",
+ "execute a buffer"},
+/* C_SHIFTL */
+ {"<", ex_shiftl, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "ca1",
+ "[line [,line]] <[<...] [count] [flags]",
+ "shift lines left"},
+/* C_EQUAL */
+ {"=", ex_equal, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF,
+ "1",
+ "[line] = [flags]",
+ "display line number"},
+/* C_SHIFTR */
+ {">", ex_shiftr, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "ca1",
+ "[line [,line]] >[>...] [count] [flags]",
+ "shift lines right"},
+/* C_AT */
+ {"@", ex_at, 0,
+ "b",
+ "@ [buffer]",
+ "execute a buffer"},
+/* C_APPEND */
+ {"append", ex_append, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF,
+ "!",
+ "[line] a[ppend][!]",
+ "append input to a line"},
+/* C_ABBR */
+ {"abbreviate", ex_abbr, E_NOGLOBAL,
+ "W",
+ "ab[brev] [word replace]",
+ "specify an input abbreviation"},
+/* C_ARGS */
+ {"args", ex_args, E_NOGLOBAL|E_NORC,
+ "",
+ "ar[gs]",
+ "display file argument list"},
+/* C_BG */
+ {"bg", ex_bg, E_NOGLOBAL|E_NORC,
+ "",
+ "bg",
+ "background the current screen"},
+/* C_CHANGE */
+ {"change", ex_change, E_ADDR2|E_NORC|E_ZERODEF,
+ "!ca",
+ "[line [,line]] c[hange][!] [count]",
+ "change lines to input"},
+/* C_CD */
+ {"cd", ex_cd, E_NOGLOBAL,
+ "!f1o",
+ "cd[!] [directory]",
+ "change the current directory"},
+/* C_CHDIR */
+ {"chdir", ex_cd, E_NOGLOBAL,
+ "!f1o",
+ "chd[ir][!] [directory]",
+ "change the current directory"},
+/* C_COPY */
+ {"copy", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "l1",
+ "[line [,line]] co[py] line [flags]",
+ "copy lines elsewhere in the file"},
+/*
+ * !!!
+ * Adding new commands starting with 'd' may break the delete command code
+ * in ex_cmd() (the ex parser). Read through the comments there, first.
+ */
+/* C_DELETE */
+ {"delete", ex_delete, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "bca1",
+ "[line [,line]] d[elete][flags] [buffer] [count] [flags]",
+ "delete lines from the file"},
+/* C_DISPLAY */
+ {"display", ex_display, E_NOGLOBAL|E_NORC,
+ "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 */
+ {"edit", ex_edit, E_NOGLOBAL|E_NORC,
+ "f1o",
+ "e[dit][!] [+cmd] [file]",
+ "begin editing another file"},
+/* C_EX */
+ {"ex", ex_edit, E_NOGLOBAL|E_NORC,
+ "f1o",
+ "ex[!] [+cmd] [file]",
+ "begin editing another file"},
+/* C_EXUSAGE */
+ {"exusage", ex_usage, E_NOGLOBAL|E_NORC,
+ "w1o",
+ "[exu]sage [command]",
+ "display ex command usage statement"},
+/* C_FILE */
+ {"file", ex_file, E_NOGLOBAL|E_NORC,
+ "f1o",
+ "f[ile] [name]",
+ "display (and optionally set) file name"},
+/* C_FG */
+ {"fg", ex_fg, E_NOGLOBAL|E_NORC,
+ "f1o",
+ "fg [file]",
+ "switch the current screen and a backgrounded screen"},
+/* C_GLOBAL */
+ {"global", ex_global, E_ADDR2_ALL|E_NOGLOBAL|E_NORC,
+ "!s",
+ "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]",
+ "execute a global command on lines matching an RE"},
+/* C_HELP */
+ {"help", ex_help, E_NOGLOBAL|E_NORC,
+ "",
+ "he[lp]",
+ "display help statement"},
+/* C_INSERT */
+ {"insert", ex_insert, E_ADDR1|E_NORC,
+ "!",
+ "[line] i[nsert][!]",
+ "insert input before a line"},
+/* C_JOIN */
+ {"join", ex_join, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "!ca1",
+ "[line [,line]] j[oin][!] [count] [flags]",
+ "join lines into a single line"},
+/* C_K */
+ {"k", ex_mark, E_ADDR1|E_NORC,
+ "w1r",
+ "[line] k key",
+ "mark a line position"},
+/* C_LIST */
+ {"list", ex_list, E_ADDR2|E_F_PRCLEAR|E_NORC,
+ "ca1",
+ "[line [,line]] l[ist] [count] [#]",
+ "display lines in an unambiguous form"},
+/* C_MOVE */
+ {"move", ex_move, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "l",
+ "[line [,line]] m[ove] line",
+ "move lines elsewhere in the file"},
+/* C_MARK */
+ {"mark", ex_mark, E_ADDR1|E_NORC,
+ "w1r",
+ "[line] ma[rk] key",
+ "mark a line position"},
+/* C_MAP */
+ {"map", ex_map, 0,
+ "!W",
+ "map[!] [keys replace]",
+ "map input or commands to one or more keys"},
+/* C_MKEXRC */
+ {"mkexrc", ex_mkexrc, E_NOGLOBAL|E_NORC,
+ "!f1r",
+ "mkexrc[!] file",
+ "write a .exrc file"},
+/* C_NEXT */
+ {"next", ex_next, E_NOGLOBAL|E_NORC,
+ "!fN",
+ "n[ext][!] [+cmd] [file ...]",
+ "edit (and optionally specify) the next file"},
+/* C_NUMBER */
+ {"number", ex_number, E_ADDR2|E_F_PRCLEAR|E_NORC,
+ "ca1",
+ "[line [,line]] nu[mber] [count] [l]",
+ "change display to number lines"},
+/* C_OPEN */
+ {"open", ex_open, E_ADDR1,
+ "s",
+ "[line] o[pen] [/RE/] [flags]",
+ "enter \"open\" mode (not implemented)"},
+/* C_PRINT */
+ {"print", ex_pr, E_ADDR2|E_F_PRCLEAR|E_NORC,
+ "ca1",
+ "[line [,line]] p[rint] [count] [#l]",
+ "display lines"},
+/* C_PRESERVE */
+ {"preserve", ex_preserve, E_NOGLOBAL|E_NORC,
+ "",
+ "pre[serve]",
+ "preserve an edit session for recovery"},
+/* C_PREVIOUS */
+ {"previous", ex_prev, E_NOGLOBAL|E_NORC,
+ "!",
+ "prev[ious][!]",
+ "edit the previous file in the file argument list"},
+/* C_PUT */
+ {"put", ex_put, E_ADDR1|E_AUTOPRINT|E_NORC|E_ZERO,
+ "b",
+ "[line] pu[t] [buffer]",
+ "append a cut buffer to the line"},
+/* C_QUIT */
+ {"quit", ex_quit, E_NOGLOBAL|E_NORC,
+ "!",
+ "q[uit][!]",
+ "exit ex/vi"},
+/* C_READ */
+ {"read", ex_read, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF,
+ "s",
+ "[line] r[ead] [!cmd | [file]]",
+ "append input from a command or file to the line"},
+/* C_RECOVER */
+ {"recover", ex_recover, E_NOGLOBAL|E_NORC,
+ "!f1r",
+ "recover[!] file",
+ "recover a saved file"},
+/* C_RESIZE */
+ {"resize", ex_resize, E_NOGLOBAL|E_NORC,
+ "c+",
+ "resize [+-]rows",
+ "grow or shrink the current screen"},
+/* C_REWIND */
+ {"rewind", ex_rew, E_NOGLOBAL|E_NORC,
+ "!",
+ "rew[ind][!]",
+ "re-edit all the files in the file argument list"},
+/* C_SUBSTITUTE */
+ {"substitute", ex_substitute, E_ADDR2|E_NORC,
+ "s",
+"[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",
+ "sc[ript][!] [file]",
+ "run a shell in a screen"},
+/* C_SET */
+ {"set", ex_set, E_NOGLOBAL,
+ "wN",
+ "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]",
+ "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",
+ "so[urce] file",
+ "read a file of ex commands"},
+/* C_SPLIT */
+ {"split", ex_split, E_NOGLOBAL|E_NORC,
+ "fNo",
+ "sp[lit] [file ...]",
+ "split the current screen into two screens"},
+/* C_STOP */
+ {"stop", ex_stop, E_NOGLOBAL|E_NORC,
+ "!",
+ "st[op][!]",
+ "suspend the edit session"},
+/* C_SUSPEND */
+ {"suspend", ex_stop, E_NOGLOBAL|E_NORC,
+ "!",
+ "su[spend][!]",
+ "suspend the edit session"},
+/* C_T */
+ {"t", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC,
+ "l1",
+ "[line [,line]] t line [flags]",
+ "copy lines elsewhere in the file"},
+/* C_TAG */
+ {"tag", ex_tagpush, E_NOGLOBAL,
+ "!w1o",
+ "ta[g][!] [string]",
+ "edit the file containing the tag"},
+/* C_TAGPOP */
+ {"tagpop", ex_tagpop, E_NOGLOBAL|E_NORC,
+ "!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_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",
+ "una[bbrev] word",
+ "delete an abbreviation"},
+/* C_UNMAP */
+ {"unmap", ex_unmap, E_NOGLOBAL,
+ "!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] [;/]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",
+ "[line] vi[sual] [-|.|+|^] [window_size] [flags]",
+ "enter visual (vi) mode from ex mode"},
+/* C_VISUAL_VI */
+ {"visual", ex_edit, E_NOGLOBAL|E_NORC,
+ "f1o",
+ "vi[sual][!] [+cmd] [file]",
+ "edit another file (from vi mode only)"},
+/* C_VIUSAGE */
+ {"viusage", ex_viusage, E_NOGLOBAL|E_NORC,
+ "w1o",
+ "[viu]sage [key]",
+ "display vi key usage statement"},
+/* C_WRITE */
+ {"write", ex_write, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
+ "!s",
+ "[line [,line]] w[rite][!] [!cmd | [>>] [file]]",
+ "write the file"},
+/* C_WN */
+ {"wn", ex_wn, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
+ "!s",
+ "[line [,line]] wn[!] [>>] [file]",
+ "write the file and switch to the next file"},
+/* C_WQ */
+ {"wq", ex_wq, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
+ "!s",
+ "[line [,line]] wq[!] [>>] [file]",
+ "write the file and exit"},
+/* C_XIT */
+ {"xit", ex_xit, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF,
+ "!f1o",
+ "[line [,line]] x[it][!] [file]",
+ "exit"},
+/* C_YANK */
+ {"yank", ex_yank, E_ADDR2|E_NORC,
+ "bca",
+ "[line [,line]] ya[nk] [buffer] [count]",
+ "copy lines to a cut buffer"},
+/* C_Z */
+ {"z", ex_z, E_ADDR1|E_NOGLOBAL|E_NORC,
+ "3c01",
+ "[line] z [-|.|+|^|=] [count] [flags]",
+ "display different screens of the file"},
+/* C_SUBTILDE */
+ {"~", ex_subtilde, E_ADDR2|E_NORC,
+ "s",
+ "[line [,line]] ~ [cgr] [count] [#lp]",
+ "replace previous RE with previous replacement string,"},
+ {NULL},
+};
diff --git a/usr.bin/vi/ex/excmd.h.stub b/usr.bin/vi/ex/excmd.h.stub
new file mode 100644
index 000000000000..3b4051b0f960
--- /dev/null
+++ b/usr.bin/vi/ex/excmd.h.stub
@@ -0,0 +1,285 @@
+/*-
+ * 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.
+ *
+ * @(#)excmd.h.stub 8.73 (Berkeley) 8/9/94
+ */
+
+#define PROMPTCHAR ':' /* Prompt character. */
+
+/* Ex command structure. */
+typedef struct _excmdlist {
+ char *name; /* Command name. */
+ /* Underlying function. */
+ int (*fn) __P((SCR *, EXF *, EXCMDARG *));
+
+#define E_ADDR1 0x0000001 /* One address. */
+#define E_ADDR2 0x0000002 /* Two address. */
+#define E_ADDR2_ALL 0x0000004 /* Zero/two addresses; zero == all. */
+#define E_ADDR2_NONE 0x0000008 /* Zero/two addresses; zero == none. */
+#define E_ADDRDEF 0x0000010 /* Default addresses used. */
+#define E_AUTOPRINT 0x0000020 /* Command always sets autoprint. */
+#define E_BUFFER 0x0000040 /* Buffer name supplied. */
+#define E_COUNT 0x0000080 /* Count supplied. */
+#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 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 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_ZERO 0x1000000 /* 0 is a legal addr1. */
+#define E_ZERODEF 0x2000000 /* 0 is default addr1 of empty files. */
+ u_int32_t flags;
+ char *syntax; /* Syntax script. */
+ char *usage; /* Usage line. */
+ char *help; /* Help line. */
+} EXCMDLIST;
+#define MAXCMDNAMELEN 12 /* Longest command name. */
+extern EXCMDLIST const cmds[]; /* List of ex commands. */
+
+/*
+ * Structure passed around to functions implementing ex commands.
+ * There are several commands in vi that build one of these and
+ * call ex directly. See vi/v_ex.c for details.
+ */
+struct _excmdarg {
+ EXCMDLIST const *cmd; /* Command entry in command table. */
+ CHAR_T buffer; /* Named buffer. */
+ recno_t lineno; /* Line number. */
+ long count; /* Signed, specified count. */
+ long flagoff; /* Signed, flag offset parsed by command. */
+ int addrcnt; /* Number of addresses (0, 1 or 2). */
+ MARK addr1; /* 1st address. */
+ MARK addr2; /* 2nd address. */
+ ARGS **argv; /* Array of arguments. */
+ int argc; /* Count of arguments. */
+ u_int32_t flags; /* Selected flags from EXCMDLIST. */
+};
+
+/* Global ranges. */
+typedef struct _range RANGE;
+struct _range {
+ CIRCLEQ_ENTRY(_range) q; /* Linked list of ranges. */
+ 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. */
+ int argscnt; /* Argument count. */
+ int argsoff; /* Offset into arguments. */
+
+ CHAR_T at_lbuf; /* Last executed at buffer's name. */
+ int at_lbuf_set; /* If at_lbuf is set. */
+
+ char *ibp; /* Line input buffer. */
+ size_t ibp_len; /* Line input buffer length. */
+
+ u_int32_t fdef; /* Default command flags. */
+
+ CHAR_T *lastbcomm; /* Last bang command. */
+
+ 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. */
+
+#define EX_ABSMARK 0x01 /* Set the absolute mark. */
+#define EX_AUTOPRINT 0x02 /* Autoprint flag. */
+ u_int8_t flags;
+} EX_PRIVATE;
+#define EXP(sp) ((EX_PRIVATE *)((sp)->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) == CH_LITERAL : KEY_VAL(sp, ch) == K_VLNEXT)
+
+/*
+ * Filter actions:
+ *
+ * FILTER Filter text through the utility.
+ * FILTER_READ Read from the utility into the file.
+ * FILTER_WRITE Write to the utility, display its output.
+ */
+enum filtertype { FILTER, FILTER_READ, FILTER_WRITE };
+int filtercmd __P((SCR *, EXF *,
+ MARK *, MARK *, MARK *, char *, enum filtertype));
+
+/* Argument expansion routines. */
+int argv_init __P((SCR *, EXF *, EXCMDARG *));
+int argv_exp0 __P((SCR *, EXF *, EXCMDARG *, char *, size_t));
+int argv_exp1 __P((SCR *, EXF *, EXCMDARG *, char *, size_t, int));
+int argv_exp2 __P((SCR *, EXF *, EXCMDARG *, char *, size_t, int));
+int argv_exp3 __P((SCR *, EXF *, EXCMDARG *, char *, size_t));
+int argv_free __P((SCR *));
+
+/* Ex function prototypes. */
+int ex __P((SCR *, EXF *));
+int ex_cfile __P((SCR *, EXF *, char *, int));
+int ex_cmd __P((SCR *, EXF *, char *, size_t, int));
+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));
+int ex_getline __P((SCR *, FILE *, size_t *));
+int ex_icmd __P((SCR *, EXF *, char *, size_t, int));
+int ex_init __P((SCR *, EXF *));
+int ex_is_abbrev __P((char *, size_t));
+int ex_is_unmap __P((char *, size_t));
+int ex_ldisplay __P((SCR *, CHAR_T *, size_t, size_t, u_int));
+int ex_ncheck __P((SCR *, int));
+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 *,
+ char *, FILE *, MARK *, MARK *, u_long *, u_long *));
+void global_insdel __P((SCR *, EXF *, enum operation, recno_t));
+int proc_wait __P((SCR *, long, const char *, int));
+int sscr_end __P((SCR *));
+int sscr_exec __P((SCR *, EXF *, recno_t));
+int sscr_input __P((SCR *));
+
+int abbr_save __P((SCR *, FILE *));
+int map_save __P((SCR *, FILE *));
+
+#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_recover);
+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_unmap);
+EXPROTO(ex_usage);
+EXPROTO(ex_validate);
+EXPROTO(ex_version);
+EXPROTO(ex_vglobal);
+EXPROTO(ex_visual);
+EXPROTO(ex_viusage);
+EXPROTO(ex_wn);
+EXPROTO(ex_wq);
+EXPROTO(ex_write);
+EXPROTO(ex_xit);
+EXPROTO(ex_yank);
+EXPROTO(ex_z);
diff --git a/usr.bin/vi/ex/filter.c b/usr.bin/vi/ex/filter.c
new file mode 100644
index 000000000000..59a221c01cbb
--- /dev/null
+++ b/usr.bin/vi/ex/filter.c
@@ -0,0 +1,414 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)filter.c 8.43 (Berkeley) 8/7/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+#include <pathnames.h>
+
+#include "vi.h"
+#include "excmd.h"
+
+static int filter_ldisplay __P((SCR *, FILE *));
+
+/*
+ * filtercmd --
+ * Run a range of lines through a filter utility and optionally
+ * replace the original text with the stdout/stderr output of
+ * the utility.
+ */
+int
+filtercmd(sp, ep, fm, tm, rp, cmd, ftype)
+ SCR *sp;
+ EXF *ep;
+ MARK *fm, *tm, *rp;
+ char *cmd;
+ enum filtertype ftype;
+{
+ FILE *ifp, *ofp;
+ pid_t parent_writer_pid, utility_pid;
+ recno_t nread;
+ int input[2], output[2], rval, teardown;
+ char *name;
+
+ /* Set return cursor position; guard against a line number of zero. */
+ *rp = *fm;
+ if (fm->lno == 0)
+ rp->lno = 1;
+
+ /*
+ * There are three different processes running through this code.
+ * They are the utility, the parent-writer and the parent-reader.
+ * The parent-writer is the process that writes from the file to
+ * the utility, the parent reader is the process that reads from
+ * the utility.
+ *
+ * Input and output are named from the utility's point of view.
+ * The utility reads from input[0] and the parent(s) write to
+ * input[1]. The parent(s) read from output[0] and the utility
+ * writes to output[1].
+ *
+ * In the FILTER_READ case, the utility isn't expected to want
+ * input. Redirect its input from /dev/null. Otherwise open
+ * up utility input pipe.
+ */
+ teardown = 0;
+ ofp = NULL;
+ input[0] = input[1] = output[0] = output[1] = -1;
+ if (ftype == FILTER_READ) {
+ if ((input[0] = open(_PATH_DEVNULL, O_RDONLY, 0)) < 0) {
+ msgq(sp, M_ERR,
+ "filter: %s: %s", _PATH_DEVNULL, strerror(errno));
+ return (1);
+ }
+ } else
+ if (pipe(input) < 0) {
+ msgq(sp, M_SYSERR, "pipe");
+ goto err;
+ }
+
+ /* Open up utility output pipe. */
+ if (pipe(output) < 0) {
+ msgq(sp, M_SYSERR, "pipe");
+ goto err;
+ }
+ if ((ofp = fdopen(output[0], "r")) == NULL) {
+ msgq(sp, M_SYSERR, "fdopen");
+ goto err;
+ }
+
+ /*
+ * Save ex/vi terminal settings, and restore the original ones.
+ * Restoration so that users can do things like ":r! cat /dev/tty".
+ */
+ teardown = ftype != FILTER_WRITE && !ex_sleave(sp);
+
+ /* Fork off the utility process. */
+ SIGBLOCK(sp->gp);
+ switch (utility_pid = vfork()) {
+ case -1: /* Error. */
+ SIGUNBLOCK(sp->gp);
+
+ msgq(sp, M_SYSERR, "vfork");
+err: if (input[0] != -1)
+ (void)close(input[0]);
+ if (input[1] != -1)
+ (void)close(input[1]);
+ if (ofp != NULL)
+ (void)fclose(ofp);
+ else if (output[0] != -1)
+ (void)close(output[0]);
+ if (output[1] != -1)
+ (void)close(output[1]);
+ rval = 1;
+ goto ret;
+ case 0: /* Utility. */
+ /* The utility has default signal behavior. */
+ sig_end();
+
+ /*
+ * Redirect stdin from the read end of the input pipe, and
+ * redirect stdout/stderr to the write end of the output pipe.
+ *
+ * !!!
+ * Historically, ex only directed stdout into the input pipe,
+ * letting stderr come out on the terminal as usual. Vi did
+ * not, directing both stdout and stderr into the input pipe.
+ * We match that practice for both ex and vi for consistency.
+ */
+ (void)dup2(input[0], STDIN_FILENO);
+ (void)dup2(output[1], STDOUT_FILENO);
+ (void)dup2(output[1], STDERR_FILENO);
+
+ /* Close the utility's file descriptors. */
+ (void)close(input[0]);
+ (void)close(input[1]);
+ (void)close(output[0]);
+ (void)close(output[1]);
+
+ if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
+ name = O_STR(sp, O_SHELL);
+ else
+ ++name;
+
+ execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
+ msgq(sp, M_ERR, "Error: execl: %s: %s",
+ O_STR(sp, O_SHELL), strerror(errno));
+ _exit (127);
+ /* NOTREACHED */
+ default: /* Parent-reader, parent-writer. */
+ SIGUNBLOCK(sp->gp);
+
+ /* Close the pipe ends neither parent will use. */
+ (void)close(input[0]);
+ (void)close(output[1]);
+ break;
+ }
+
+ /*
+ * FILTER_READ:
+ *
+ * Reading is the simple case -- we don't need a parent writer,
+ * so the parent reads the output from the read end of the output
+ * pipe until it finishes, then waits for the child. Ex_readfp
+ * appends to the MARK, and closes ofp.
+ *
+ * !!!
+ * Set the return cursor to the last line read in. Historically,
+ * this behaves differently from ":r file" command, which leaves
+ * the cursor at the first line read in. Check to make sure that
+ * it's not past EOF because we were reading into an empty file.
+ */
+ if (ftype == FILTER_READ) {
+ rval = ex_readfp(sp, ep, "filter", ofp, fm, &nread, 0);
+ sp->rptlines[L_ADDED] += nread;
+ if (fm->lno == 0)
+ rp->lno = nread;
+ else
+ rp->lno += nread;
+ goto uwait;
+ }
+
+ /*
+ * FILTER, FILTER_WRITE
+ *
+ * Here we need both a reader and a writer. Temporary files are
+ * expensive and we'd like to avoid disk I/O. Using pipes has the
+ * obvious starvation conditions. It's done as follows:
+ *
+ * fork
+ * child
+ * write lines out
+ * exit
+ * parent
+ * FILTER:
+ * read lines into the file
+ * delete old lines
+ * FILTER_WRITE
+ * read and display lines
+ * wait for child
+ *
+ * XXX
+ * We get away without locking the underlying database because we know
+ * that none of the records that we're reading will be modified until
+ * after we've read them. This depends on the fact that the current
+ * B+tree implementation doesn't balance pages or similar things when
+ * it inserts new records. When the DB code has locking, we should
+ * treat vi as if it were multiple applications sharing a database, and
+ * do the required locking. If necessary a work-around would be to do
+ * explicit locking in the line.c:file_gline() code, based on the flag
+ * set here.
+ */
+ rval = 0;
+ F_SET(ep, F_MULTILOCK);
+
+ SIGBLOCK(sp->gp);
+ switch (parent_writer_pid = fork()) {
+ case -1: /* Error. */
+ SIGUNBLOCK(sp->gp);
+
+ msgq(sp, M_SYSERR, "fork");
+ (void)close(input[1]);
+ (void)close(output[0]);
+ rval = 1;
+ break;
+ case 0: /* Parent-writer. */
+ /*
+ * Write the selected lines to the write end of the input
+ * pipe. This instance of ifp is closed by ex_writefp.
+ */
+ (void)close(output[0]);
+ if ((ifp = fdopen(input[1], "w")) == NULL)
+ _exit (1);
+ _exit(ex_writefp(sp, ep, "filter", ifp, fm, tm, NULL, NULL));
+
+ /* NOTREACHED */
+ default: /* Parent-reader. */
+ SIGUNBLOCK(sp->gp);
+
+ (void)close(input[1]);
+ if (ftype == FILTER_WRITE)
+ /*
+ * Read the output from the read end of the output
+ * pipe and display it. Filter_ldisplay closes ofp.
+ */
+ rval = filter_ldisplay(sp, ofp);
+ else {
+ /*
+ * Read the output from the read end of the output
+ * pipe. Ex_readfp appends to the MARK and closes
+ * ofp.
+ */
+ rval = ex_readfp(sp, ep, "filter", ofp, tm, &nread, 0);
+ sp->rptlines[L_ADDED] += nread;
+ }
+
+ /* Wait for the parent-writer. */
+ rval |= proc_wait(sp,
+ (long)parent_writer_pid, "parent-writer", 1);
+
+ /* Delete any lines written to the utility. */
+ if (rval == 0 && ftype == FILTER &&
+ (cut(sp, ep, NULL, fm, tm, CUT_LINEMODE) ||
+ delete(sp, ep, fm, tm, 1))) {
+ rval = 1;
+ break;
+ }
+
+ /*
+ * If the filter had no output, we may have just deleted
+ * the cursor. Don't do any real error correction, we'll
+ * try and recover later.
+ */
+ if (rp->lno > 1 && file_gline(sp, ep, rp->lno, NULL) == NULL)
+ --rp->lno;
+ break;
+ }
+ F_CLR(ep, F_MULTILOCK);
+
+uwait: rval |= proc_wait(sp, (long)utility_pid, cmd, 0);
+
+ /* Restore ex/vi terminal settings. */
+ret: if (teardown)
+ ex_rleave(sp);
+ return (rval);
+}
+
+/*
+ * proc_wait --
+ * Wait for one of the processes.
+ *
+ * !!!
+ * The pid_t type varies in size from a short to a long depending on the
+ * system. It has to be cast into something or the standard promotion
+ * rules get you. I'm using a long based on the belief that nobody is
+ * going to make it unsigned and it's unlikely to be a quad.
+ */
+int
+proc_wait(sp, pid, cmd, okpipe)
+ SCR *sp;
+ long pid;
+ const char *cmd;
+ int okpipe;
+{
+ extern const char *const sys_siglist[];
+ size_t len;
+ int pstat;
+
+ /*
+ * Wait for the utility to finish. We can get interrupted
+ * by SIGALRM, just ignore it.
+ */
+ for (;;) {
+ errno = 0;
+ if (waitpid((pid_t)pid, &pstat, 0) != -1)
+ break;
+ if (errno != EINTR) {
+ msgq(sp, M_SYSERR, "wait error");
+ return (1);
+ }
+ }
+
+ /*
+ * Display the utility's exit status. Ignore SIGPIPE from the
+ * parent-writer, as that only means that the utility chose to
+ * exit before reading all of its input.
+ */
+ if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
+ for (; isblank(*cmd); ++cmd);
+ len = strlen(cmd);
+ msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
+ MIN(len, 20), cmd, len > 20 ? "..." : "",
+ sys_siglist[WTERMSIG(pstat)],
+ WCOREDUMP(pstat) ? "; core dumped" : "");
+ return (1);
+ }
+ if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
+ for (; isblank(*cmd); ++cmd);
+ len = strlen(cmd);
+ msgq(sp, M_ERR, "%.*s%s: exited with status %d",
+ MIN(len, 20), cmd, len > 20 ? "..." : "",
+ WEXITSTATUS(pstat));
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * filter_ldisplay --
+ * Display output from a utility.
+ *
+ * !!!
+ * Historically, the characters were passed unmodified to the terminal.
+ * We use the ex print routines to make sure they're printable.
+ */
+static int
+filter_ldisplay(sp, fp)
+ SCR *sp;
+ FILE *fp;
+{
+ size_t len;
+
+ EX_PRIVATE *exp;
+
+ F_SET(sp, S_INTERRUPTIBLE);
+ for (exp = EXP(sp); !ex_getline(sp, fp, &len);) {
+ if (ex_ldisplay(sp, exp->ibp, len, 0, 0))
+ break;
+ if (INTERRUPTED(sp))
+ break;
+ }
+ if (ferror(fp))
+ msgq(sp, M_SYSERR, "filter input");
+ (void)fclose(fp);
+ return (0);
+}
diff --git a/usr.bin/vi/ex/script.h b/usr.bin/vi/ex/script.h
new file mode 100644
index 000000000000..b21c63a2071c
--- /dev/null
+++ b/usr.bin/vi/ex/script.h
@@ -0,0 +1,45 @@
+/*-
+ * 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.
+ *
+ * @(#)script.h 8.2 (Berkeley) 4/17/94
+ */
+
+struct _script {
+ pid_t sh_pid; /* Shell pid. */
+ int sh_master; /* Master pty fd. */
+ int sh_slave; /* Slave pty fd. */
+ char *sh_prompt; /* Prompt. */
+ size_t sh_prompt_len; /* Prompt length. */
+ char sh_name[64]; /* Pty name */
+ struct winsize sh_win; /* Window size. */
+ struct termios sh_term; /* Terminal information. */
+};
diff --git a/usr.bin/vi/ex/tag.h b/usr.bin/vi/ex/tag.h
new file mode 100644
index 000000000000..a9fd59d0730b
--- /dev/null
+++ b/usr.bin/vi/ex/tag.h
@@ -0,0 +1,58 @@
+/*-
+ * 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.
+ *
+ * @(#)tag.h 8.13 (Berkeley) 7/17/94
+ */
+
+struct _tagf { /* Tag file. */
+ TAILQ_ENTRY(_tagf) q; /* Linked list of tag files. */
+ char *name; /* Tag file name. */
+
+#define TAGF_DNE 0x01 /* Didn't exist. */
+#define TAGF_DNE_WARN 0x02 /* DNE error reported. */
+ u_int8_t flags;
+};
+
+struct _tag { /* Tag stack. */
+ TAILQ_ENTRY(_tag) q; /* Linked list of tags. */
+ FREF *frp; /* Saved file name. */
+ recno_t lno; /* Saved line number. */
+ size_t cno; /* Saved column number. */
+ char *search; /* Search string. */
+ size_t slen; /* Search string length. */
+};
+
+int ex_tagalloc __P((SCR *, char *));
+int ex_tagcopy __P((SCR *, SCR *));
+int ex_tagdisplay __P((SCR *, EXF *));
+int ex_tagfirst __P((SCR *, char *));
+int ex_tagfree __P((SCR *));
diff --git a/usr.bin/vi/install/recover.script b/usr.bin/vi/install/recover.script
new file mode 100644
index 000000000000..9f91e4e2bcc1
--- /dev/null
+++ b/usr.bin/vi/install/recover.script
@@ -0,0 +1,32 @@
+# @(#)recover.script 8.4 (Berkeley) 8/13/94
+#
+# Recover nvi editor files:
+RECDIR=/var/tmp/vi.recover
+SENDMAIL=/usr/lib/sendmail
+echo 'Recovering nvi editor sessions.'
+
+# Unmodified nvi editor backup files are either zero length or
+# have the execute bit set. Delete both cases.
+vibackup=`echo $RECDIR/vi.*`
+if [ "$vibackup" != "$RECDIR/vi.*" ]; then
+ for i in $vibackup; do
+ if test -x $i -o ! -s $i; then
+ rm $i
+ fi
+ done
+fi
+
+# It is possible to get incomplete recovery files, if the editor
+# crashes at the right time. Delete any recovery files without
+# corresponding backup files, otherwise send mail to the user.
+virecovery=`echo $RECDIR/recover.*`
+if [ "$virecovery" != "$RECDIR/recover.*" ]; then
+ for i in $virecovery; do
+ recfile=`awk '/^X-vi-recover-path:/{print $2}' < $i`
+ if test ! -n $recfile -a -s $recfile; then
+ $SENDMAIL -t < $i
+ else
+ rm $i
+ fi
+ done
+fi
diff --git a/usr.bin/vi/sex/sex_confirm.c b/usr.bin/vi/sex/sex_confirm.c
new file mode 100644
index 000000000000..2900928963d5
--- /dev/null
+++ b/usr.bin/vi/sex/sex_confirm.c
@@ -0,0 +1,86 @@
+/*-
+ * 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[] = "@(#)sex_confirm.c 8.7 (Berkeley) 4/13/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "sex_screen.h"
+
+enum confirm
+sex_confirm(sp, ep, fp, tp)
+ SCR *sp;
+ EXF *ep;
+ MARK *fp, *tp;
+{
+ CH ikey;
+ recno_t cnt;
+
+ if (ex_print(sp, ep, fp, tp, 0))
+ return (CONF_QUIT);
+
+ for (cnt = fp->cno; cnt; --cnt)
+ (void)putc(' ', stdout);
+ for (cnt = tp->cno; cnt; --cnt)
+ (void)putc('^', stdout);
+ (void)fprintf(stdout, "[ynq]");
+
+ if (term_key(sp, &ikey, 0) != INP_OK)
+ return (CONF_QUIT);
+ switch (ikey.ch) {
+ case CH_YES:
+ return (CONF_YES);
+ case CH_QUIT:
+ return (CONF_QUIT);
+ default:
+ case CH_NO:
+ return (CONF_NO);
+ }
+ /* NOTREACHED */
+}
diff --git a/usr.bin/vi/sex/sex_get.c b/usr.bin/vi/sex/sex_get.c
new file mode 100644
index 000000000000..a29be5ce0821
--- /dev/null
+++ b/usr.bin/vi/sex/sex_get.c
@@ -0,0 +1,514 @@
+/*-
+ * 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[] = "@(#)sex_get.c 8.37 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../vi/vcmd.h"
+#include "sex_screen.h"
+
+/*
+ * !!!
+ * The ex input didn't have escape characters like ^V. The only special
+ * character was the backslash character, and that only when it preceded
+ * a newline as part of a substitution replacement pattern. For example,
+ * the command input ":a\<cr>" failed immediately with an error, as the
+ * <cr> wasn't part of a substitution replacement pattern. This implies
+ * a frightening integration of the editor and the RE engine. There's no
+ * way we're going to reproduce those semantics. So, if backslashes are
+ * special, this code inserts the backslash and the next character into the
+ * string, without regard for the character or the command being entered.
+ * Since "\<cr>" was illegal historically (except for the one special case),
+ * and the command will fail eventually, historical scripts shouldn't break
+ * (presuming they didn't depend on the failure mode itself or the characters
+ * remaining when failure occurred.
+ */
+static void txt_display __P((SCR *, TEXT *, size_t, size_t *));
+static int txt_outdent __P((SCR *, TEXT *));
+
+#define ERASECH { \
+ for (cnt = tp->wd[tp->len]; cnt-- > 0; --col) \
+ (void)printf("\b \b"); \
+}
+
+/*
+ * sex_get --
+ * Get lines from the terminal for ex.
+ */
+enum input
+sex_get(sp, ep, tiqh, prompt, flags)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+ ARG_CHAR_T prompt;
+ u_int flags;
+{
+ /* State of the "[^0]^D" sequences. */
+ enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;
+ TEXT *ntp, *tp, ait; /* Input and autoindent text structures. */
+ CH ikey; /* Input character. */
+ size_t col; /* 0-N: screen column. */
+ size_t cnt;
+ int rval, istty;
+
+ /*
+ * !!!
+ * Most of the special capabilities (like autoindent, erase,
+ * etc.) are turned off if ex isn't talking to a terminal.
+ */
+ istty = F_ISSET(sp->gp, G_STDIN_TTY);
+
+ /*
+ * Get a TEXT structure with some initial buffer space, reusing
+ * the last one if it's big enough. (All TEXT bookkeeping fields
+ * default to 0 -- text_init() handles this.)
+ */
+ if (tiqh->cqh_first != (void *)tiqh) {
+ tp = tiqh->cqh_first;
+ if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < 32) {
+ text_lfree(tiqh);
+ goto newtp;
+ }
+ tp->len = 0;
+ } else {
+newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
+ return (INP_ERR);
+ CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
+ }
+
+ if (istty) {
+ /* Display the prompt. */
+ if (LF_ISSET(TXT_PROMPT)) {
+ col = KEY_LEN(sp, prompt);
+ (void)printf("%s", KEY_NAME(sp, prompt));
+ }
+
+ /* Initialize autoindent value and print it out. */
+ if (LF_ISSET(TXT_AUTOINDENT)) {
+ if (txt_auto(sp, ep, sp->lno, NULL, 0, tp))
+ return (INP_ERR);
+ BINC_GOTO(sp, tp->wd, tp->wd_len, tp->len + 1);
+ for (cnt = 0; cnt < tp->ai; ++cnt)
+ txt_display(sp, tp, cnt, &col);
+ }
+ } else {
+ col = 0;
+
+ /* Turn off autoindent here, less special casing below. */
+ LF_CLR(TXT_AUTOINDENT);
+ }
+
+ for (carat_st = C_NOTSET;;) {
+ if (istty)
+ (void)fflush(stdout);
+ /*
+ * !!!
+ * Historically, ex never mapped commands or keys.
+ */
+ if (rval = term_key(sp, &ikey, 0))
+ return (rval);
+
+ if (INTERRUPTED(sp))
+ return (INP_INTR);
+
+ BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
+ BINC_GOTO(sp, tp->wd, tp->wd_len, tp->len + 1);
+
+ switch (ikey.value) {
+ case K_CR:
+ case K_NL:
+ /* '\' can escape <carriage-return>/<newline>. */
+ if (LF_ISSET(TXT_BACKSLASH) &&
+ tp->len != 0 && tp->lb[tp->len - 1] == '\\')
+ goto ins_ch;
+
+ /* Echo the newline if requested. */
+ if (istty && LF_ISSET(TXT_NLECHO)) {
+ (void)putc('\r', stdout);
+ (void)putc('\n', stdout);
+ (void)fflush(stdout);
+ }
+
+ /*
+ * CR returns from the ex command line, interrupt
+ * always returns.
+ */
+ if (LF_ISSET(TXT_CR)) {
+ /* Terminate with a nul, needed by filter. */
+ tp->lb[tp->len] = '\0';
+ return (INP_OK);
+ }
+
+ /* '.' terminates ex input modes. */
+ if (LF_ISSET(TXT_DOTTERM) &&
+ tp->len == tp->ai + 1 &&
+ tp->lb[tp->len - 1] == '.') {
+ /* Release the current TEXT. */
+ ntp = tp->q.cqe_prev;
+ CIRCLEQ_REMOVE(tiqh, tp, q);
+ text_free(tp);
+ tp = ntp;
+ return (INP_OK);
+ }
+
+ /*
+ * If we echoed the newline, display any accumulated
+ * error messages.
+ */
+ if (LF_ISSET(TXT_NLECHO) && sex_refresh(sp, ep))
+ return (INP_ERR);
+
+ /* Set up bookkeeping for the new line. */
+ if ((ntp = text_init(sp, NULL, 0, 32)) == NULL)
+ return (INP_ERR);
+ ntp->lno = tp->lno + 1;
+
+ /*
+ * Reset the autoindent line value. 0^D keeps the ai
+ * line from changing, ^D changes the level, even if
+ * there are no characters in the old line. Note,
+ * if using the current tp structure, use the cursor
+ * as the length, the user may have erased autoindent
+ * characters.
+ */
+ col = 0;
+ if (LF_ISSET(TXT_AUTOINDENT)) {
+ if (carat_st == C_NOCHANGE) {
+ if (txt_auto(sp, ep,
+ OOBLNO, &ait, ait.ai, ntp))
+ return (INP_ERR);
+ FREE_SPACE(sp, ait.lb, ait.lb_len);
+ } else
+ if (txt_auto(sp, ep,
+ OOBLNO, tp, tp->len, ntp))
+ return (INP_ERR);
+ carat_st = C_NOTSET;
+
+ if (ntp->ai) {
+ BINC_GOTO(sp,
+ ntp->wd, ntp->wd_len, ntp->len + 1);
+ for (cnt = 0; cnt < ntp->ai; ++cnt)
+ txt_display(sp, ntp, cnt, &col);
+ }
+ }
+ /*
+ * Swap old and new TEXT's, and insert the new TEXT
+ * into the queue.
+ */
+ tp = ntp;
+ CIRCLEQ_INSERT_TAIL(tiqh, tp, q);
+ break;
+ case K_CARAT: /* Delete autoindent chars. */
+ if (LF_ISSET(TXT_AUTOINDENT) && tp->len <= tp->ai)
+ carat_st = C_CARATSET;
+ goto ins_ch;
+ case K_ZERO: /* Delete autoindent chars. */
+ if (LF_ISSET(TXT_AUTOINDENT) && tp->len <= tp->ai)
+ carat_st = C_ZEROSET;
+ goto ins_ch;
+ case K_CNTRLD: /* Delete autoindent char. */
+ /*
+ * !!!
+ * Historically, the ^D command took (but then ignored)
+ * a count. For simplicity, we don't return it unless
+ * it's the first character entered. The check for len
+ * equal to 0 is okay, TXT_AUTOINDENT won't be set.
+ */
+ if (LF_ISSET(TXT_CNTRLD)) {
+ for (cnt = 0; cnt < tp->len; ++cnt)
+ if (!isblank(tp->lb[cnt]))
+ break;
+ if (cnt == tp->len) {
+ tp->len = 1;
+ tp->lb[0] = '\004';
+ tp->lb[1] = '\0';
+ return (INP_OK);
+ }
+ }
+
+ /*
+ * If in the first column or no characters to erase,
+ * ignore the ^D (this matches historic practice). If
+ * not doing autoindent or already inserted non-ai
+ * characters, it's a literal. The latter test is done
+ * in the switch, as the CARAT forms are N + 1, not N.
+ */
+ if (!LF_ISSET(TXT_AUTOINDENT))
+ goto ins_ch;
+ if (tp->len == 0)
+ break;
+ switch (carat_st) {
+ case C_CARATSET: /* ^^D */
+ if (tp->len > tp->ai + 1)
+ goto ins_ch;
+ /* Save the ai string for later. */
+ ait.lb = NULL;
+ ait.lb_len = 0;
+ BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai);
+ memmove(ait.lb, tp->lb, tp->ai);
+ ait.ai = ait.len = tp->ai;
+
+ carat_st = C_NOCHANGE;
+ goto leftmargin;
+ case C_ZEROSET: /* 0^D */
+ if (tp->len > tp->ai + 1)
+ goto ins_ch;
+ carat_st = C_NOTSET;
+leftmargin: (void)printf("\b \r");
+ tp->ai = tp->len = 0;
+ break;
+ case C_NOTSET: /* ^D */
+ if (tp->len > tp->ai)
+ goto ins_ch;
+ if (txt_outdent(sp, tp))
+ return (INP_ERR);
+ break;
+ default:
+ abort();
+ }
+ break;
+ case K_VERASE:
+ if (!istty)
+ goto ins_ch;
+ if (tp->len) {
+ --tp->len;
+ if (tp->lb[tp->len] == '\n' ||
+ tp->lb[tp->len] == '\r')
+ goto repaint;
+ ERASECH;
+ }
+ break;
+ case K_VWERASE:
+ if (!istty)
+ goto ins_ch;
+
+ /* Move to the last non-space character. */
+ while (tp->len) {
+ --tp->len;
+ if (tp->lb[tp->len] == '\n' ||
+ tp->lb[tp->len] == '\r')
+ goto repaint;
+ if (!isblank(tp->lb[tp->len])) {
+ ++tp->len;
+ break;
+ } else
+ ERASECH;
+ }
+
+ /* Move to the last space character. */
+ while (tp->len) {
+ --tp->len;
+ if (tp->lb[tp->len] == '\n' ||
+ tp->lb[tp->len] == '\r')
+ goto repaint;
+ if (isblank(tp->lb[tp->len])) {
+ ++tp->len;
+ break;
+ } else
+ ERASECH;
+ }
+ break;
+ case K_VKILL:
+ if (!istty)
+ goto ins_ch;
+ while (tp->len) {
+ --tp->len;
+ if (tp->lb[tp->len] == '\n' ||
+ tp->lb[tp->len] == '\r') {
+ tp->len = 0;
+ goto repaint;
+ }
+ ERASECH;
+ }
+ break;
+ /*
+ * XXX
+ * Historic practice is that ^Z suspended command mode, and
+ * that it was unaffected by the autowrite option. ^Z ended
+ * insert mode, retaining all but the current line of input,
+ * which was discarded. When ex was foregrounded, it was in
+ * command mode. I don't want to discard input because a user
+ * tried to enter a ^Z, and I'd like to be consistent with vi.
+ * So, nex matches vi's historic practice, and doesn't permit
+ * ^Z in input mode.
+ */
+ case K_CNTRLZ:
+ if (!istty || !LF_ISSET(TXT_EXSUSPEND))
+ goto ins_ch;
+ sex_suspend(sp);
+ goto repaint;
+ case K_CNTRLR:
+ if (!istty)
+ goto ins_ch;
+repaint: if (LF_ISSET(TXT_PROMPT)) {
+ col = KEY_LEN(sp, prompt);
+ (void)printf("\r%s", KEY_NAME(sp, prompt));
+ } else {
+ col = 0;
+ (void)putc('\r', stdout);
+ }
+ for (cnt = 0; cnt < tp->len; ++cnt)
+ txt_display(sp, tp, cnt, &col);
+ break;
+ default:
+ /*
+ * See the TXT_BEAUTIFY comment in vi/v_ntext.c.
+ *
+ * Silently eliminate any iscntrl() character that
+ * wasn't already handled specially, except for <tab>
+ * and <ff>.
+ */
+ins_ch: if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ikey.ch) &&
+ ikey.value != K_FORMFEED && ikey.value != K_TAB)
+ break;
+ tp->lb[tp->len] = ikey.ch;
+ if (istty)
+ txt_display(sp, tp, tp->len, &col);
+ ++tp->len;
+ break;
+ }
+ }
+ /* NOTREACHED */
+
+binc_err:
+ return (INP_ERR);
+}
+
+/*
+ * txt_display --
+ * Display the character.
+ */
+static void
+txt_display(sp, tp, off, colp)
+ SCR *sp;
+ TEXT *tp;
+ size_t off, *colp;
+{
+ CHAR_T ch;
+ size_t width;
+
+ switch (ch = tp->lb[off]) {
+ case '\t':
+ *colp += tp->wd[off] = width =
+ O_VAL(sp, O_TABSTOP) - *colp % O_VAL(sp, O_TABSTOP);
+ while (width--)
+ putc(' ', stdout);
+ break;
+ case '\n':
+ case '\r':
+ (void)putc('\r', stdout);
+ (void)putc('\n', stdout);
+ break;
+ default:
+ *colp += tp->wd[off] = KEY_LEN(sp, ch);
+ (void)printf("%s", KEY_NAME(sp, ch));
+ }
+}
+
+/*
+ * txt_outdent --
+ * Handle ^D outdents.
+ *
+ * Ex version of vi/v_ntext.c:txt_outdent(). See that code for the
+ * usual ranting and raving.
+ */
+static int
+txt_outdent(sp, tp)
+ SCR *sp;
+ TEXT *tp;
+{
+ u_long sw, ts;
+ size_t cno, cnt, off, scno, spaces;
+
+ ts = O_VAL(sp, O_TABSTOP);
+ sw = O_VAL(sp, O_SHIFTWIDTH);
+
+ /* Get the current screen column. */
+ for (off = scno = 0; off < tp->len; ++off)
+ if (tp->lb[off] == '\t')
+ scno += STOP_OFF(scno, ts);
+ else
+ ++scno;
+
+ /* Get the previous shiftwidth column. */
+ for (cno = scno; --scno % sw != 0;);
+
+ /* Decrement characters until less than or equal to that slot. */
+ for (; cno > scno; --tp->ai) {
+ for (cnt = tp->wd[--tp->len]; cnt-- > 0;)
+ (void)printf("\b \b");
+ if (tp->lb[--off] == '\t')
+ cno -= STOP_OFF(cno, ts);
+ else
+ --cno;
+ }
+
+ /* Spaces needed to get to the target. */
+ spaces = scno - cno;
+
+ /* Maybe just a delete. */
+ if (spaces == 0)
+ return (0);
+
+ /* Make sure there's enough room. */
+ BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);
+
+ /* Maybe that was enough. */
+ if (spaces == 0)
+ return (0);
+
+ /* Add new space characters. */
+ for (; spaces--; ++tp->ai)
+ tp->lb[tp->len++] = ' ';
+ return (0);
+}
diff --git a/usr.bin/vi/sex/sex_refresh.c b/usr.bin/vi/sex/sex_refresh.c
new file mode 100644
index 000000000000..c1be816b4e4c
--- /dev/null
+++ b/usr.bin/vi/sex/sex_refresh.c
@@ -0,0 +1,140 @@
+/*-
+ * 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[] = "@(#)sex_refresh.c 8.14 (Berkeley) 7/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "sex_screen.h"
+
+#ifndef SYSV_CURSES
+#define A_NORMAL 1
+#define A_STANDOUT 2
+#define vidattr(attr) Xvidattr(sp, attr)
+
+static int Xvidattr __P((SCR *, int));
+#endif
+
+/*
+ * sex_refresh --
+ * In ex, just display any messages.
+ */
+int
+sex_refresh(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ MSG *mp;
+
+ /* Check for screen resize. */
+ if (F_ISSET(sp, S_RESIZE)) {
+ sp->rows = O_VAL(sp, O_LINES);
+ sp->cols = O_VAL(sp, O_COLUMNS);
+ F_CLR(sp, S_RESIZE);
+ }
+
+ /* Ring the bell. */
+ if (F_ISSET(sp, S_BELLSCHED)) {
+ sex_bell(sp);
+ F_CLR(sp, S_BELLSCHED);
+ }
+
+ /* Display messages. */
+ for (mp = sp->msgq.lh_first;
+ mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next) {
+ if (F_ISSET(mp, M_INV_VIDEO) &&
+ vidattr(A_STANDOUT) == ERR && O_ISSET(sp, O_ERRORBELLS))
+ (void)printf("\07");
+ (void)printf("%.*s.\n", (int)mp->len, mp->mbuf);
+ F_SET(mp, M_EMPTY);
+
+ if (F_ISSET(mp, M_INV_VIDEO))
+ vidattr(A_NORMAL);
+ (void)fflush(stdout);
+ }
+ return (0);
+}
+
+#ifndef SYSV_CURSES
+/*
+ * Xvidattr --
+ * Set the video attributes to a value.
+ *
+ * XXX
+ * Just enough to make the above code work when using non-System V
+ * curses.
+ */
+static int
+Xvidattr(sp, attr)
+ SCR *sp;
+ int attr;
+{
+ SEX_PRIVATE *sxp;
+
+ sxp = SXP(sp);
+
+ /* Check to see if standout isn't available. */
+ if (sxp->SO == NULL)
+ return (ERR);
+
+ switch (attr) {
+ case A_NORMAL:
+ (void)tputs(SXP(sp)->SE, 1, vi_putchar);
+ break;
+ case A_STANDOUT:
+ (void)tputs(SXP(sp)->SO, 1, vi_putchar);
+ break;
+ default:
+ abort();
+ }
+ return (0);
+}
+#endif
diff --git a/usr.bin/vi/sex/sex_screen.c b/usr.bin/vi/sex/sex_screen.c
new file mode 100644
index 000000000000..433899819adf
--- /dev/null
+++ b/usr.bin/vi/sex/sex_screen.c
@@ -0,0 +1,340 @@
+/*-
+ * 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[] = "@(#)sex_screen.c 8.47 (Berkeley) 7/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 <unistd.h>
+
+#include "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "sex_screen.h"
+#include "../svi/svi_screen.h"
+
+static void sex_abort __P((void));
+static int sex_noop __P((void));
+static int sex_nope __P((SCR *));
+static int sex_term_init __P((SCR *));
+static void so_se_init __P((SCR *));
+
+/*
+ * sex_screen_init --
+ * Initialize the ex screen.
+ */
+int
+sex_screen_init(sp)
+ SCR *sp;
+{
+ /* Initialize support routines. */
+ 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_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_edit = sex_screen_edit;
+ sp->s_end = (int (*)())sex_noop;
+ sp->s_ex_cmd = (int (*)())sex_abort;
+ sp->s_ex_run = (int (*)())sex_abort;
+ sp->s_ex_write = (int (*)())sex_abort;
+ sp->s_fg = (int (*)())sex_nope;
+ sp->s_fill = (int (*)())sex_abort;
+ sp->s_get = sex_get;
+ sp->s_key_read = sex_key_read;
+ sp->s_optchange = sex_optchange;
+ sp->s_fmap = (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_scroll = (int (*)())sex_abort;
+ sp->s_split = (int (*)())sex_nope;
+ sp->s_suspend = sex_suspend;
+ sp->s_window = sex_window;
+
+ return (0);
+}
+
+/*
+ * sex_screen_copy --
+ * Copy to a new screen.
+ */
+int
+sex_screen_copy(orig, sp)
+ SCR *orig, *sp;
+{
+ SEX_PRIVATE *osex, *nsex;
+
+ /* Create the private screen structure. */
+ CALLOC_RET(orig, nsex, SEX_PRIVATE *, 1, sizeof(SEX_PRIVATE));
+ sp->sex_private = nsex;
+
+/* INITIALIZED AT SCREEN CREATE. */
+
+/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
+ if (orig == NULL) {
+ } else {
+ osex = SXP(orig);
+#ifndef SYSV_CURSES
+ if (osex->SE != NULL && (nsex->SE = strdup(osex->SE)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+ if (osex->SO != NULL && (nsex->SO = strdup(osex->SO)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ free(osex->SE);
+ return (1);
+ }
+#endif
+ }
+
+ return (0);
+}
+
+/*
+ * sex_screen_end --
+ * End a screen.
+ */
+int
+sex_screen_end(sp)
+ SCR *sp;
+{
+#ifndef SYSV_CURSES
+ /* Free inverse video strings. */
+ if (SXP(sp)->SE != NULL)
+ free(SXP(sp)->SE);
+ if (SXP(sp)->SO != NULL)
+ free(SXP(sp)->SO);
+#endif
+
+ /* Free private memory. */
+ FREE(SXP(sp), sizeof(SEX_PRIVATE));
+ sp->sex_private = NULL;
+
+ return (0);
+}
+
+/*
+ * sex_screen_edit --
+ * Main ex screen loop. The ex screen is relatively uncomplicated.
+ * As long as it has a stdio FILE pointer for output, it's happy.
+ */
+int
+sex_screen_edit(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct termios t;
+ GS *gp;
+ int force, rval;
+
+ /* Initialize the terminal state. */
+ gp = sp->gp;
+ if (F_ISSET(gp, G_STDIN_TTY))
+ SEX_RAW(t);
+
+ /* Write to the terminal. */
+ sp->stdfp = stdout;
+
+ /*
+ * The resize bit is probably set, but clear it, we're
+ * going to initialize the screen right now.
+ */
+ F_CLR(sp, S_RESIZE);
+
+ /* Initialize the termcap buffer. */
+ if (sex_term_init(sp))
+ return (1);
+
+ for (;;) {
+ /*
+ * Run ex. If ex fails, sex data structures
+ * may be corrupted, be careful what you do.
+ */
+ if (rval = ex(sp, sp->ep)) {
+ (void)rcv_sync(sp, sp->ep,
+ RCV_EMAIL | RCV_ENDSESSION | RCV_PRESERVE);
+ (void)screen_end(sp); /* General SCR info. */
+ break;
+ }
+
+ force = 0;
+ switch (F_ISSET(sp, S_MAJOR_CHANGE)) {
+ case S_EXIT_FORCE:
+ force = 1;
+ /* FALLTHROUGH */
+ case S_EXIT:
+ F_CLR(sp, S_EXIT_FORCE | S_EXIT);
+ if (file_end(sp, sp->ep, force))
+ break;
+ (void)screen_end(sp); /* General SCR info. */
+ goto ret;
+ case 0: /* Changing from ex mode. */
+ goto ret;
+ case S_FSWITCH:
+ F_CLR(sp, S_FSWITCH);
+ break;
+ case S_SSWITCH:
+ default:
+ abort();
+ }
+ }
+
+ /* Reset the terminal state. */
+ret: if (F_ISSET(gp, G_STDIN_TTY) && SEX_NORAW(t))
+ rval = 1;
+ return (rval);
+}
+
+/*
+ * sex_term_init --
+ * Initialize ex's relationship with the termcap/terminfo entry.
+ */
+static int
+sex_term_init(sp)
+ SCR *sp;
+{
+
+#ifndef SYSV_CURSES
+ /* Initialize standout information. */
+ so_se_init(sp);
+#endif
+
+ sp->rows = O_VAL(sp, O_LINES);
+ sp->cols = O_VAL(sp, O_COLUMNS);
+ return (0);
+}
+
+#ifndef SYSV_CURSES
+/*
+ * so_se_init --
+ * Initialize the inverse video strings.
+ */
+static void
+so_se_init(sp)
+ SCR *sp;
+{
+ SEX_PRIVATE *sxp;
+ size_t len;
+ char *s, *t, buf[128], tbuf[2048];
+
+ if (tgetent(tbuf, O_STR(sp, O_TERM)) != 1)
+ return;
+
+ sxp = SXP(sp);
+
+ /* Get SE. */
+ t = buf;
+ if ((t = tgetstr("se", &t)) == NULL)
+ return;
+ if ((len = strlen(t)) == 0)
+ return;
+ MALLOC_NOMSG(sp, s, char *, len + 1);
+ if (s == NULL)
+ return;
+ memmove(s, buf, len);
+ s[len] = '\0';
+ sxp->SE = s;
+
+ /* Get SO. */
+ t = buf;
+ if ((t = tgetstr("so", &t)) == NULL)
+ goto err;
+ if ((len = strlen(t)) == 0)
+ goto err;
+ MALLOC_NOMSG(sp, s, char *, len + 1);
+ if (s == NULL)
+ goto err;
+ memmove(s, buf, len);
+ s[len] = '\0';
+ sxp->SO = s;
+
+ return;
+
+err: free(sxp->SE);
+ sxp->SE = NULL;
+ return;
+}
+#endif
+
+/*
+ * sex_abort --
+ * Fake function. Die.
+ */
+static void
+sex_abort()
+{
+ abort();
+}
+
+/*
+ * sex_noop --
+ * Fake function. Do nothing.
+ */
+static int
+sex_noop()
+{
+ return (0);
+}
+
+/*
+ * sex_nope --
+ * Fake function. Not in ex, you don't.
+ */
+static int
+sex_nope(sp)
+ SCR *sp;
+{
+ msgq(sp, M_ERR, "Command not applicable to ex mode");
+ return (1);
+}
diff --git a/usr.bin/vi/sex/sex_screen.h b/usr.bin/vi/sex/sex_screen.h
new file mode 100644
index 000000000000..150e38f8c18e
--- /dev/null
+++ b/usr.bin/vi/sex/sex_screen.h
@@ -0,0 +1,79 @@
+/*-
+ * 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.
+ *
+ * @(#)sex_screen.h 8.20 (Berkeley) 8/8/94
+ */
+
+#define SEX_NORAW(t) \
+ tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &(t))
+
+#define SEX_RAW(t) { \
+ struct termios __rawt; \
+ if (tcgetattr(STDIN_FILENO, &(t))) \
+ return (1); \
+ __rawt = (t); \
+ __rawt.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INLCR|IGNCR|ICRNL); \
+ __rawt.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); \
+ __rawt.c_oflag |= OPOST | ONLCR; \
+ __rawt.c_cc[VMIN] = 1; \
+ __rawt.c_cc[VTIME] = 0; \
+ if (tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &__rawt)) \
+ return (1); \
+}
+
+typedef struct _sex_private {
+/* INITIALIZED AT SCREEN CREATE. */
+ int __unused; /* Make sure it's not empty. */
+
+/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
+#ifndef SYSV_CURSES
+ char *SE, *SO; /* Inverse video termcap strings. */
+#endif
+} SEX_PRIVATE;
+
+#define SXP(sp) ((SEX_PRIVATE *)((sp)->sex_private))
+
+void sex_bell __P((SCR *));
+void sex_busy __P((SCR *, char const *));
+enum confirm
+ sex_confirm __P((SCR *, EXF *, MARK *, MARK *));
+enum input
+ sex_get __P((SCR *, EXF *, TEXTH *, ARG_CHAR_T, u_int));
+enum input
+ sex_key_read __P((SCR *, int *, struct timeval *));
+int sex_optchange __P((SCR *, int));
+int sex_refresh __P((SCR *, EXF *));
+int sex_screen_copy __P((SCR *, SCR *));
+int sex_screen_edit __P((SCR *, EXF *));
+int sex_screen_end __P((SCR *));
+int sex_suspend __P((SCR *));
+int sex_window __P((SCR *, int));
diff --git a/usr.bin/vi/sex/sex_term.c b/usr.bin/vi/sex/sex_term.c
new file mode 100644
index 000000000000..93ca048928c3
--- /dev/null
+++ b/usr.bin/vi/sex/sex_term.c
@@ -0,0 +1,217 @@
+/*-
+ * 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[] = "@(#)sex_term.c 8.38 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "../ex/script.h"
+
+/*
+ * sex_key_read --
+ * Read characters from the input.
+ */
+enum input
+sex_key_read(sp, nrp, timeout)
+ SCR *sp;
+ int *nrp;
+ struct timeval *timeout;
+{
+ struct timeval t, *tp;
+ GS *gp;
+ IBUF *tty;
+ int maxfd, nr;
+
+ *nrp = 0;
+ gp = sp->gp;
+ tty = gp->tty;
+
+ /*
+ * We're about to block; check for signals. If a signal received,
+ * clear it immediately, so that if it's reset while being serviced
+ * we won't miss it.
+ *
+ * These signal recipients set global flags. None of this has
+ * anything to do with input keys, but it's something that can't
+ * be done asynchronously without adding locking to handle race
+ * conditions, and which needs to be done periodically.
+ */
+sigchk: while (F_ISSET(gp, G_SIGINT | G_SIGWINCH)) {
+ if (F_ISSET(gp, G_SIGINT))
+ return (INP_INTR);
+ if (F_ISSET(gp, G_SIGWINCH)) {
+ F_CLR(gp, G_SIGWINCH);
+ if (!sp->s_window(sp, 1))
+ (void)sp->s_refresh(sp, sp->ep);
+ }
+ }
+
+ /*
+ * There are three cases here:
+ *
+ * 1: A read from a file or a pipe. In this case, the reads
+ * never timeout regardless. This means that we can hang
+ * when trying to complete a map, but we're going to hang
+ * on the next read anyway.
+ */
+ if (!F_ISSET(gp, G_STDIN_TTY)) {
+ if ((nr = read(STDIN_FILENO,
+ tty->ch + tty->next + tty->cnt,
+ tty->nelem - (tty->next + tty->cnt))) > 0)
+ goto success;
+ return (INP_EOF);
+ }
+
+ /*
+ * 2: A read with an associated timeout. In this case, we are trying
+ * to complete a map sequence. Ignore script windows and timeout
+ * as specified. If input arrives, we fall into #3, but because
+ * timeout isn't NULL, don't read anything but command input.
+ *
+ * If interrupted, go back and check to see what it was.
+ */
+ if (timeout != NULL) {
+ if (F_ISSET(sp, S_SCRIPT))
+ FD_CLR(sp->script->sh_master, &sp->rdfd);
+ FD_SET(STDIN_FILENO, &sp->rdfd);
+ for (;;) {
+ switch (select(STDIN_FILENO + 1,
+ &sp->rdfd, NULL, NULL, timeout)) {
+ case -1: /* Error or interrupt. */
+ if (errno == EINTR)
+ goto sigchk;
+ goto err;
+ case 1: /* Characters ready. */
+ break;
+ case 0: /* Timeout. */
+ return (INP_OK);
+ }
+ break;
+ }
+ }
+
+ /*
+ * 3: At this point, we'll take anything that comes. Select on the
+ * command file descriptor and the file descriptor for the script
+ * window if there is one. Poll the fd's, increasing the timeout
+ * each time each time we don't get anything until we're blocked
+ * on I/O.
+ *
+ * If interrupted, go back and check to see what it was.
+ */
+ for (t.tv_sec = t.tv_usec = 0;;) {
+ /*
+ * Reset each time -- sscr_input() may call other
+ * routines which could reset bits.
+ */
+ if (timeout == NULL && F_ISSET(sp, S_SCRIPT)) {
+ tp = &t;
+
+ FD_SET(STDIN_FILENO, &sp->rdfd);
+ if (F_ISSET(sp, S_SCRIPT)) {
+ FD_SET(sp->script->sh_master, &sp->rdfd);
+ maxfd =
+ MAX(STDIN_FILENO, sp->script->sh_master);
+ } else
+ maxfd = STDIN_FILENO;
+ } else {
+ tp = NULL;
+
+ FD_SET(STDIN_FILENO, &sp->rdfd);
+ if (F_ISSET(sp, S_SCRIPT))
+ 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)
+ goto sigchk;
+err: msgq(sp, M_SYSERR, "select");
+ return (INP_ERR);
+ case 0: /* Timeout. */
+ if (t.tv_usec) {
+ ++t.tv_sec;
+ t.tv_usec = 0;
+ } else
+ t.tv_usec += 500000;
+ continue;
+ }
+
+ if (timeout == NULL && F_ISSET(sp, S_SCRIPT) &&
+ FD_ISSET(sp->script->sh_master, &sp->rdfd)) {
+ sscr_input(sp);
+ continue;
+ }
+
+ switch (nr = read(STDIN_FILENO,
+ tty->ch + tty->next + tty->cnt,
+ tty->nelem - (tty->next + tty->cnt))) {
+ case 0: /* EOF. */
+ return (INP_EOF);
+ case -1: /* Error or interrupt. */
+ if (errno == EINTR)
+ goto sigchk;
+ msgq(sp, M_SYSERR, "read");
+ return (INP_ERR);
+ default:
+ goto success;
+ }
+ /* NOTREACHED */
+ }
+
+success:
+ MEMSET(tty->chf + tty->next + tty->cnt, 0, nr);
+ tty->cnt += *nrp = nr;
+ return (INP_OK);
+}
diff --git a/usr.bin/vi/sex/sex_util.c b/usr.bin/vi/sex/sex_util.c
new file mode 100644
index 000000000000..5acd788f617a
--- /dev/null
+++ b/usr.bin/vi/sex/sex_util.c
@@ -0,0 +1,148 @@
+/*-
+ * 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[] = "@(#)sex_util.c 8.15 (Berkeley) 7/16/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "sex_screen.h"
+
+/*
+ * sex_bell --
+ * Ring the bell.
+ */
+void
+sex_bell(sp)
+ SCR *sp;
+{
+ (void)write(STDOUT_FILENO, "\07", 1); /* \a */
+}
+
+void
+sex_busy(sp, msg)
+ SCR *sp;
+ char const *msg;
+{
+ (void)fprintf(stdout, "%s\n", msg);
+ (void)fflush(stdout);
+}
+
+/*
+ * sex_optchange --
+ * Screen specific "option changed" routine.
+ */
+int
+sex_optchange(sp, opt)
+ SCR *sp;
+ int opt;
+{
+ switch (opt) {
+ case O_TERM:
+ /* Reset the screen size. */
+ if (sp->s_window(sp, 0))
+ return (1);
+ F_SET(sp, S_RESIZE);
+ break;
+ }
+
+ (void)ex_optchange(sp, opt);
+
+ return (0);
+}
+
+/*
+ * sex_suspend --
+ * Suspend an ex screen.
+ */
+int
+sex_suspend(sp)
+ SCR *sp;
+{
+ struct termios t;
+ GS *gp;
+ int rval;
+
+ rval = 0;
+
+ /* Save current terminal settings, and restore the original ones. */
+ gp = sp->gp;
+ if (F_ISSET(gp, G_STDIN_TTY)) {
+ if (tcgetattr(STDIN_FILENO, &t)) {
+ msgq(sp, M_SYSERR, "suspend: tcgetattr");
+ return (1);
+ }
+ if (F_ISSET(gp, G_TERMIOS_SET) && tcsetattr(STDIN_FILENO,
+ TCSASOFT | TCSADRAIN, &gp->original_termios)) {
+ msgq(sp, M_SYSERR, "suspend: tcsetattr original");
+ return (1);
+ }
+ }
+
+ /* Push out any waiting messages. */
+ (void)sex_refresh(sp, sp->ep);
+
+ /* Stop the process group. */
+ if (kill(0, SIGTSTP)) {
+ msgq(sp, M_SYSERR, "suspend: kill");
+ rval = 1;
+ }
+
+ /* Time passes ... */
+
+ /* Restore current terminal settings. */
+ if (F_ISSET(gp, G_STDIN_TTY) &&
+ tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t)) {
+ msgq(sp, M_SYSERR, "suspend: tcsetattr current");
+ rval = 1;
+ }
+ return (rval);
+}
diff --git a/usr.bin/vi/sex/sex_window.c b/usr.bin/vi/sex/sex_window.c
new file mode 100644
index 000000000000..37fc8edadf21
--- /dev/null
+++ b/usr.bin/vi/sex/sex_window.c
@@ -0,0 +1,194 @@
+/*-
+ * 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[] = "@(#)sex_window.c 8.6 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/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 <unistd.h>
+
+#include "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * sex_window --
+ * Set the window size.
+ */
+int
+sex_window(sp, sigwinch)
+ SCR *sp;
+ int sigwinch;
+{
+ struct winsize win;
+ size_t col, row;
+ int rval, user_set;
+ ARGS *argv[2], a, b;
+ char *s, buf[2048];
+
+ /*
+ * Get the screen rows and columns. If the values are wrong, it's
+ * not a big deal -- as soon as the user sets them explicitly the
+ * environment will be set and the screen package will use the new
+ * values.
+ *
+ * Try TIOCGWINSZ.
+ */
+ row = col = 0;
+#ifdef TIOCGWINSZ
+ if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1) {
+ row = win.ws_row;
+ col = win.ws_col;
+ }
+#endif
+ /* If here because of a signal, TIOCGWINSZ is all we trust. */
+ if (sigwinch) {
+ if (row == 0 || col == 0) {
+ msgq(sp, M_SYSERR, "TIOCGWINSZ");
+ return (1);
+ }
+
+ /*
+ * !!!
+ * SunOS systems deliver SIGWINCH when windows are uncovered
+ * as well as when they change size. In addition, we call
+ * here when continuing after being suspended since the window
+ * may have changed size. Since we don't want to background
+ * all of the screens just because the window was uncovered,
+ * ignore the signal if there's no change.
+ */
+ if (row == O_VAL(sp, O_LINES) && col == O_VAL(sp, O_COLUMNS))
+ return (1);
+
+ goto sigw;
+ }
+
+ /*
+ * !!!
+ * If TIOCGWINSZ failed, or had entries of 0, try termcap. This
+ * routine is called before any termcap or terminal information
+ * has been set up. If there's no TERM environmental variable set,
+ * let it go, at least ex can run.
+ */
+ if (row == 0 || col == 0) {
+ if ((s = getenv("TERM")) == NULL)
+ goto noterm;
+#ifdef SYSV_CURSES
+ if (row == 0)
+ if ((rval = tigetnum("lines")) < 0)
+ msgq(sp, M_SYSERR, "tigetnum: lines");
+ else
+ row = rval;
+ if (col == 0)
+ if ((rval = tigetnum("cols")) < 0)
+ msgq(sp, M_SYSERR, "tigetnum: cols");
+ else
+ col = rval;
+#else
+ switch (tgetent(buf, s)) {
+ case -1:
+ msgq(sp, M_SYSERR, "tgetent: %s", s);
+ return (1);
+ case 0:
+ msgq(sp, M_ERR, "%s: unknown terminal type", s);
+ return (1);
+ }
+ if (row == 0)
+ if ((rval = tgetnum("li")) < 0)
+ msgq(sp, M_ERR,
+ "no \"li\" capability for %s", s);
+ else
+ row = rval;
+ if (col == 0)
+ if ((rval = tgetnum("co")) < 0)
+ msgq(sp, M_ERR,
+ "no \"co\" capability for %s", s);
+ else
+ col = rval;
+#endif
+ }
+
+ /* If nothing else, well, it's probably a VT100. */
+noterm: if (row == 0)
+ row = 24;
+ if (col == 0)
+ col = 80;
+
+ /* POSIX 1003.2 requires the environment to override. */
+ if ((s = getenv("LINES")) != NULL)
+ row = strtol(s, NULL, 10);
+ if ((s = getenv("COLUMNS")) != NULL)
+ col = strtol(s, NULL, 10);
+
+sigw: a.bp = buf;
+ b.bp = NULL;
+ b.len = 0;
+ argv[0] = &a;
+ argv[1] = &b;;
+
+ /*
+ * Tell the options code that the screen size has changed.
+ * Since the user didn't do the set, clear the set bits.
+ */
+ user_set = F_ISSET(&sp->opts[O_LINES], OPT_SET);
+ a.len = snprintf(buf, sizeof(buf), "lines=%u", row);
+ if (opts_set(sp, NULL, argv))
+ return (1);
+ if (user_set)
+ F_CLR(&sp->opts[O_LINES], OPT_SET);
+
+ user_set = F_ISSET(&sp->opts[O_COLUMNS], OPT_SET);
+ a.len = snprintf(buf, sizeof(buf), "columns=%u", col);
+ if (opts_set(sp, NULL, argv))
+ return (1);
+ if (user_set)
+ F_CLR(&sp->opts[O_COLUMNS], OPT_SET);
+
+ F_SET(sp, S_RESIZE);
+ return (0);
+}
diff --git a/usr.bin/vi/svi/svi_confirm.c b/usr.bin/vi/svi/svi_confirm.c
new file mode 100644
index 000000000000..06ef25c1bb8d
--- /dev/null
+++ b/usr.bin/vi/svi/svi_confirm.c
@@ -0,0 +1,95 @@
+/*-
+ * 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[] = "@(#)svi_confirm.c 8.8 (Berkeley) 4/13/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "svi_screen.h"
+
+enum confirm
+svi_confirm(sp, ep, fp, tp)
+ SCR *sp;
+ EXF *ep;
+ MARK *fp, *tp;
+{
+ CH ikey;
+ size_t oldy, oldx;
+
+ /*
+ * Refresh the cursor first -- this means that we won't have to
+ * set S_UPDATE_MODE to keep refresh from erasing the mode line
+ * or SVI_CUR_INVALID because we sneaked the cursor off somewhere
+ * else.
+ */
+ sp->lno = fp->lno;
+ sp->cno = fp->cno;
+ if (svi_paint(sp, ep))
+ return (CONF_QUIT);
+
+ getyx(stdscr, oldy, oldx);
+ MOVE(sp, INFOLINE(sp), 0);
+ clrtoeol();
+ ADDNSTR(STR_CONFIRM, sizeof(STR_CONFIRM) - 1);
+ MOVEA(sp, oldy, oldx);
+ refresh();
+
+ if (term_key(sp, &ikey, 0) != INP_OK)
+ return (CONF_QUIT);
+ switch (ikey.ch) {
+ case CH_YES:
+ return (CONF_YES);
+ case CH_QUIT:
+ return (CONF_QUIT);
+ default:
+ case CH_NO:
+ return (CONF_NO);
+ }
+ /* NOTREACHED */
+}
diff --git a/usr.bin/vi/svi/svi_curses.c b/usr.bin/vi/svi/svi_curses.c
new file mode 100644
index 000000000000..523fff99856a
--- /dev/null
+++ b/usr.bin/vi/svi/svi_curses.c
@@ -0,0 +1,252 @@
+/*-
+ * 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[] = "@(#)svi_curses.c 8.3 (Berkeley) 8/7/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "svi_screen.h"
+
+/*
+ * svi_curses_init --
+ * Initialize curses.
+ */
+int
+svi_curses_init(sp)
+ SCR *sp;
+{
+ struct termios t;
+ char *p;
+
+#ifdef SYSV_CURSES
+ /*
+ * The SunOS/System V initscr() isn't reentrant. Don't even think
+ * about trying to use it. It fails in subtle ways (e.g. select(2)
+ * on fileno(stdin) stops working). We don't care about the SCREEN
+ * reference returned by newterm, we never have more than one SCREEN
+ * at a time.
+ */
+ errno = 0;
+ if (newterm(O_STR(sp, O_TERM), stdout, stdin) == NULL) {
+ msgq(sp, errno ? M_SYSERR : M_ERR, "newterm failed");
+ return (1);
+ }
+#else
+ /*
+ * Initscr() doesn't provide useful error values or messages. The
+ * reasonable guess is that either malloc failed or the terminal was
+ * unknown or lacking some essential feature. Try and guess so the
+ * user isn't even more pissed off because of the error message.
+ */
+ errno = 0;
+ if (initscr() == NULL) {
+ char kbuf[2048];
+ msgq(sp, errno ? M_SYSERR : M_ERR, "initscr failed");
+ if ((p = getenv("TERM")) == NULL || !strcmp(p, "unknown"))
+ msgq(sp, M_ERR,
+ "No TERM environment variable set, or TERM set to \"unknown\"");
+ else if (tgetent(kbuf, p) != 1)
+ msgq(sp, M_ERR,
+"%s: unknown terminal type, or terminal lacks necessary features", p);
+ else
+ msgq(sp, M_ERR,
+ "%s: terminal type lacks necessary features", p);
+ return (1);
+ }
+#endif
+ /*
+ * We use raw mode. What we want is 8-bit clean, however, signals
+ * and flow control should continue to work. Admittedly, it sounds
+ * like cbreak, but it isn't. Using cbreak() can get you additional
+ * things like IEXTEN, which turns on things like DISCARD and LNEXT.
+ *
+ * !!!
+ * If raw isn't turning off echo and newlines, something's wrong.
+ * However, it doesn't hurt.
+ */
+ noecho(); /* No character echo. */
+ nonl(); /* No CR/NL translation. */
+ raw(); /* 8-bit clean. */
+ idlok(stdscr, 1); /* Use hardware insert/delete line. */
+
+ /*
+ * XXX
+ * Historic implementations of curses handled SIGTSTP signals
+ * in one of three ways. They either:
+ *
+ * 1: Set their own handler, regardless.
+ * 2: Did not set a handler if a handler was already installed.
+ * 3: Set their own handler, but then called any previously set
+ * handler after completing their own cleanup.
+ *
+ * We don't try and figure out which behavior is in place, we
+ * just set it to SIG_DFL after initializing the curses interface.
+ */
+ (void)signal(SIGTSTP, SIG_DFL);
+
+ /*
+ * If flow control was on, turn it back on. Turn signals on. ISIG
+ * turns on VINTR, VQUIT, VDSUSP and VSUSP. See signal.c:sig_init()
+ * for a discussion of what's going on here. To sum up, sig_init()
+ * already installed a handler for VINTR. We're going to disable the
+ * other three.
+ *
+ * XXX
+ * We want to use ^Y as a vi scrolling command. If the user has the
+ * DSUSP character set to ^Y (common practice) clean it up. As it's
+ * equally possible that the user has VDSUSP set to 'a', we disable
+ * it regardless. It doesn't make much sense to suspend vi at read,
+ * so I don't think anyone will care. Alternatively, we could look
+ * it up in the table of legal command characters and turn it off if
+ * it matches one. VDSUSP wasn't in POSIX 1003.1-1990, so we test for
+ * it.
+ *
+ * XXX
+ * We don't check to see if the user had signals enabled to start with.
+ * If they didn't, it's unclear what we're supposed to do here, but it
+ * is also pretty unlikely.
+ */
+ if (!tcgetattr(STDIN_FILENO, &t)) {
+ if (sp->gp->original_termios.c_iflag & IXON)
+ t.c_iflag |= IXON;
+ if (sp->gp->original_termios.c_iflag & IXOFF)
+ t.c_iflag |= IXOFF;
+
+ t.c_lflag |= ISIG;
+#ifdef VDSUSP
+ t.c_cc[VDSUSP] = _POSIX_VDISABLE;
+#endif
+ t.c_cc[VQUIT] = _POSIX_VDISABLE;
+ t.c_cc[VSUSP] = _POSIX_VDISABLE;
+
+ (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
+ }
+
+ /* Put the cursor keys into application mode. */
+ svi_keypad(sp, 1);
+
+ /*
+ * The first screen in the list gets it all. All other screens
+ * are hidden and lose their maps.
+ */
+ svi_dtoh(sp, "Window resize");
+
+ /* Initialize terminal values. */
+ SVP(sp)->srows = O_VAL(sp, O_LINES);
+
+ /*
+ * Initialize screen values.
+ *
+ * Small windows: see svi/svi_refresh.c:svi_refresh, section 3b.
+ *
+ * Setup:
+ * t_minrows is the minimum rows to display
+ * t_maxrows is the maximum rows to display (rows - 1)
+ * t_rows is the rows currently being displayed
+ */
+ sp->rows = SVP(sp)->srows;
+ sp->cols = O_VAL(sp, O_COLUMNS);
+ sp->woff = 0;
+ sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW);
+ if (sp->t_rows > sp->rows - 1) {
+ sp->t_minrows = sp->t_rows = sp->rows - 1;
+ msgq(sp, M_INFO,
+ "Windows option value is too large, max is %u", sp->t_rows);
+ }
+ sp->t_maxrows = sp->rows - 1;
+
+ /* Create the screen map. */
+ CALLOC(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
+ if (HMAP == NULL) {
+ if (endwin() == ERR)
+ msgq(sp, M_SYSERR, "endwin");
+ return (1);
+ }
+ TMAP = HMAP + (sp->t_rows - 1);
+
+ F_SET(SVP(sp), SVI_CUR_INVALID); /* Cursor is invalid. */
+ F_SET(SVP(sp), SVI_CURSES_INIT); /* It's initialized. */
+
+ return (0);
+}
+
+/*
+ * svi_curses_end --
+ * Move to the bottom of the screen, end curses.
+ */
+int
+svi_curses_end(sp)
+ SCR *sp;
+{
+ /*
+ * XXX
+ * By the time we get here, the screen private area (SVI_PRIVATE)
+ * is probably gone. Don't use it, and don't call any routines
+ * that do.
+ *
+ * Restore the cursor keys to normal mode.
+ */
+ svi_keypad(sp, 0);
+
+ /* Move to the bottom of the screen. */
+ if (move(INFOLINE(sp), 0) == OK) {
+ clrtoeol();
+ refresh();
+ }
+
+ /* End curses window. */
+ if (endwin() == ERR)
+ msgq(sp, M_SYSERR, "endwin");
+
+ return (0);
+}
diff --git a/usr.bin/vi/svi/svi_ex.c b/usr.bin/vi/svi/svi_ex.c
new file mode 100644
index 000000000000..9b81080bcb0e
--- /dev/null
+++ b/usr.bin/vi/svi/svi_ex.c
@@ -0,0 +1,650 @@
+/*-
+ * 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[] = "@(#)svi_ex.c 8.54 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "../vi/vcmd.h"
+#include "excmd.h"
+#include "svi_screen.h"
+#include "../sex/sex_screen.h"
+
+static int svi_ex_divider __P((SCR *));
+static int svi_ex_done __P((SCR *, EXF *, MARK *));
+static int svi_ex_inv __P((SCR *));
+static int svi_ex_scroll __P((SCR *, int, CH *));
+
+#define MSGS_WAITING(sp) \
+ ((sp)->msgq.lh_first != NULL && \
+ !F_ISSET((sp)->msgq.lh_first, M_EMPTY))
+
+/*
+ * svi_ex_cmd --
+ * Execute an ex command.
+ */
+int
+svi_ex_cmd(sp, ep, exp, rp)
+ SCR *sp;
+ EXF *ep;
+ EXCMDARG *exp;
+ MARK *rp;
+{
+ SVI_PRIVATE *svp;
+ int rval;
+
+ svp = SVP(sp);
+ svp->exlcontinue = svp->exlinecount = svp->extotalcount = 0;
+
+ (void)svi_busy(sp, NULL);
+ rval = exp->cmd->fn(sp, ep, exp);
+
+ (void)msg_rpt(sp, 0);
+ (void)ex_fflush(EXCOOKIE);
+
+ /*
+ * If displayed anything, figure out if we have to wait. If the
+ * screen wasn't trashed, only one line output and there are no
+ * waiting messages, don't wait, but don't overwrite it with mode
+ * information either.
+ */
+ if (svp->extotalcount > 0)
+ if (!F_ISSET(sp, S_REFRESH) &&
+ svp->extotalcount == 1 && !MSGS_WAITING(sp)) {
+ F_SET(sp, S_UPDATE_MODE);
+ if (sp->q.cqe_next != (void *)&sp->gp->dq)
+ (void)svi_ex_inv(sp);
+ } else {
+ /* This message isn't interruptible. */
+ F_CLR(sp, S_INTERRUPTIBLE);
+ (void)svi_ex_scroll(sp, 1, NULL);
+ }
+ return (svi_ex_done(sp, ep, rp) || rval);
+}
+
+/*
+ * svi_ex_run --
+ * Execute strings of ex commands.
+ */
+int
+svi_ex_run(sp, ep, rp)
+ SCR *sp;
+ EXF *ep;
+ MARK *rp;
+{
+ enum input (*get) __P((SCR *, EXF *, TEXTH *, ARG_CHAR_T, u_int));
+ struct termios t;
+ CH ikey;
+ SVI_PRIVATE *svp;
+ TEXT *tp;
+ int flags, in_exmode, rval;
+
+ svp = SVP(sp);
+ svp->exlcontinue = svp->exlinecount = svp->extotalcount = 0;
+
+ /*
+ * There's some tricky stuff going on here to handle when a user has
+ * mapped a key to multiple ex commands. Historic practice was that
+ * vi ran without any special actions, as if the user were entering
+ * the characters, until ex trashed the screen, e.g. something like a
+ * '!' command. At that point, we no longer know what the screen
+ * looks like, so we can't afford to overwrite anything. The solution
+ * is to go into real ex mode until we get to the end of the command
+ * strings.
+ */
+ get = svi_get;
+ flags = TXT_BS | TXT_PROMPT;
+ for (in_exmode = rval = 0;;) {
+ /*
+ * Get the next command. Interrupt flag manipulation is safe
+ * because ex_icmd clears them all.
+ */
+ F_SET(sp, S_INTERRUPTIBLE);
+ if (get(sp, ep, sp->tiqp, ':', flags) != INP_OK) {
+ rval = 1;
+ break;
+ }
+ if (INTERRUPTED(sp))
+ break;
+
+ /*
+ * Len is 0 if the user backspaced over the prompt,
+ * 1 if only a CR was entered.
+ */
+ tp = sp->tiqp->cqh_first;
+ if (tp->len == 0)
+ break;
+
+ if (!in_exmode)
+ (void)svi_busy(sp, NULL);
+
+ /* Ignore return, presumably an error message was displayed. */
+ (void)ex_icmd(sp, ep, tp->lb, tp->len, 0);
+ (void)ex_fflush(EXCOOKIE);
+
+ /*
+ * The file or screen may have changed, in which case, the
+ * main editor loop takes care of it.
+ */
+ 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
+ * it with mode information either.
+ */
+ if (!F_ISSET(sp, S_CONTINUE) && (svp->extotalcount == 0 ||
+ svp->extotalcount == 1 && !MSGS_WAITING(sp))) {
+ if (svp->extotalcount == 1) {
+ F_SET(sp, S_UPDATE_MODE);
+ if (sp->q.cqe_next != (void *)&sp->gp->dq)
+ svi_ex_inv(sp);
+ }
+ break;
+ }
+
+ if (INTERRUPTED(sp))
+ break;
+
+ /*
+ * If the screen is trashed, or there are messages waiting,
+ * go into ex mode.
+ */
+ if (!in_exmode &&
+ (F_ISSET(sp, S_REFRESH) || MSGS_WAITING(sp))) {
+ /* Initialize the terminal state. */
+ if (F_ISSET(sp->gp, G_STDIN_TTY))
+ SEX_RAW(t);
+ get = sex_get;
+ flags = TXT_CR | TXT_NLECHO | TXT_PROMPT;
+ in_exmode = 1;
+ }
+
+ /* Display any waiting messages. */
+ if (MSGS_WAITING(sp))
+ (void)sex_refresh(sp, ep);
+
+ /*
+ * Get a continue character; users may continue in ex mode by
+ * entering a ':'.
+ *
+ * !!!
+ * Historic practice is that any key can be used to continue.
+ * Nvi used to require that the user enter a <carriage-return>
+ * or <newline>, but this broke historic users.
+ */
+ if (in_exmode) {
+ (void)write(STDOUT_FILENO,
+ STR_CMSG, sizeof(STR_CMSG) - 1);
+ if (term_key(sp, &ikey, 0) != INP_OK) {
+ rval = 1;
+ goto ret;
+ }
+ } else {
+ /* This message isn't interruptible. */
+ F_CLR(sp, S_INTERRUPTIBLE);
+ (void)svi_ex_scroll(sp, 1, &ikey);
+ }
+ if (ikey.ch != ':')
+ break;
+
+ if (in_exmode)
+ (void)write(STDOUT_FILENO, "\n", 1);
+ else {
+ ++svp->extotalcount;
+ ++svp->exlinecount;
+ }
+ }
+
+ret: if (in_exmode) {
+ /* Reset the terminal state. */
+ if (F_ISSET(sp->gp, G_STDIN_TTY) && SEX_NORAW(t))
+ rval = 1;
+ F_SET(sp, S_REFRESH);
+ } else
+ if (svi_ex_done(sp, ep, rp))
+ rval = 1;
+
+ F_CLR(sp, S_CONTINUE);
+ return (rval);
+}
+
+/*
+ * svi_msgflush --
+ * Flush any accumulated messages.
+ */
+int
+svi_msgflush(sp)
+ SCR *sp;
+{
+ enum {INVERSE, NORMAL} inverse;
+ SVI_PRIVATE *svp;
+ MSG *mp;
+ int rval;
+
+ svp = SVP(sp);
+ svp->exlcontinue = svp->exlinecount = svp->extotalcount = 0;
+
+ /*
+ * XXX
+ * S_IVIDEO is a bit of a kluge. We can only pass a single magic
+ * cookie into the svi_ex_write routine, and it has to be the SCR
+ * structure. So, the inverse video bit has to be there.
+ */
+ inverse = NORMAL;
+ for (mp = sp->msgq.lh_first;
+ mp != NULL && !F_ISSET(mp, M_EMPTY); mp = mp->q.le_next) {
+ /*
+ * If the second and subsequent messages fit on the current
+ * line, write a separator. Otherwise, put out a newline
+ * and break the line.
+ */
+ if (mp != sp->msgq.lh_first)
+ if (mp->len + svp->exlcontinue + 3 >= sp->cols) {
+ if (inverse == INVERSE)
+ F_SET(sp, S_IVIDEO);
+ (void)svi_ex_write(sp, ".\n", 2);
+ F_CLR(sp, S_IVIDEO);
+ } else {
+ if (inverse == INVERSE)
+ F_SET(sp, S_IVIDEO);
+ (void)svi_ex_write(sp, ";", 1);
+ F_CLR(sp, S_IVIDEO);
+ (void)svi_ex_write(sp, " ", 2);
+ }
+
+ inverse = F_ISSET(mp, M_INV_VIDEO) ? INVERSE : NORMAL;
+ if (inverse == INVERSE)
+ F_SET(sp, S_IVIDEO);
+ (void)svi_ex_write(sp, mp->mbuf, mp->len);
+ F_CLR(sp, S_IVIDEO);
+
+ F_SET(mp, M_EMPTY);
+ }
+
+ /*
+ * None of the messages end with periods, we do it in the message
+ * flush routine, which makes it possible to join messages.
+ */
+ if (inverse == INVERSE)
+ F_SET(sp, S_IVIDEO);
+ (void)svi_ex_write(sp, ".", 1);
+ F_CLR(sp, S_IVIDEO);
+
+ /*
+ * Figure out if we have to wait. Don't wait for only one line,
+ * but don't overwrite it with mode information either.
+ */
+ if (svp->extotalcount == 1) {
+ F_SET(sp, S_UPDATE_MODE);
+ if (sp->q.cqe_next != (void *)&sp->gp->dq)
+ svi_ex_inv(sp);
+ return (0);
+ }
+
+ rval = svi_ex_scroll(sp, 1, NULL);
+ if (svi_ex_done(sp, sp->ep, NULL))
+ rval = 1;
+ MOVE(sp, INFOLINE(sp), 0);
+ clrtoeol();
+ return (rval);
+}
+
+/*
+ * svi_ex_done --
+ * Cleanup from dipping into ex.
+ */
+static int
+svi_ex_done(sp, ep, rp)
+ SCR *sp;
+ EXF *ep;
+ MARK *rp;
+{
+ SMAP *smp;
+ SVI_PRIVATE *svp;
+ recno_t lno;
+ size_t cnt, len;
+
+ /*
+ * The file or screen may have changed, in which case,
+ * the main editor loop takes care of it.
+ */
+ if (F_ISSET(sp, S_MAJOR_CHANGE))
+ return (0);
+
+ /*
+ * Otherwise, the only cursor modifications will be real, however, the
+ * underlying line may have changed; don't trust anything. This code
+ * has been a remarkably fertile place for bugs.
+ *
+ * Repaint the entire screen if at least half the screen is trashed.
+ * Else, repaint only over the overwritten lines. The "-2" comes
+ * from one for the mode line and one for the fact that it's an offset.
+ * Note the check for small screens.
+ *
+ * Don't trust ANYTHING.
+ */
+ svp = SVP(sp);
+ if (svp->extotalcount >= HALFTEXT(sp))
+ F_SET(sp, S_REDRAW);
+ else
+ for (cnt = sp->rows - 2; svp->extotalcount--; --cnt)
+ if (cnt > sp->t_rows) {
+ MOVE(sp, cnt, 0);
+ clrtoeol();
+ } else {
+ smp = HMAP + cnt;
+ SMAP_FLUSH(smp);
+ if (svi_line(sp, ep, smp, NULL, NULL))
+ return (1);
+ }
+
+ /* Ignore the cursor if the caller doesn't care. */
+ if (rp == NULL)
+ return (0);
+
+ /*
+ * Do a reality check on a cursor value, and make sure it's okay.
+ * If necessary, change it. Ex keeps track of the line number,
+ * but it doesn't care about the column and it may have disappeared.
+ */
+ if (file_gline(sp, ep, sp->lno, &len) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0)
+ GETLINE_ERR(sp, sp->lno);
+ sp->lno = 1;
+ sp->cno = 0;
+ } else if (sp->cno >= len)
+ sp->cno = len ? len - 1 : 0;
+
+ rp->lno = sp->lno;
+ rp->cno = sp->cno;
+ return (0);
+}
+
+/*
+ * svi_ex_write --
+ * Write out the ex messages.
+ */
+int
+svi_ex_write(cookie, line, llen)
+ void *cookie;
+ const char *line;
+ int llen;
+{
+ SCR *sp;
+ SVI_PRIVATE *svp;
+ size_t oldy, oldx;
+ int len, rlen, tlen;
+ const char *p, *t;
+
+ /*
+ * XXX
+ * If it's a 4.4BSD system, we could just use fpurge(3).
+ * This shouldn't be too expensive, though.
+ */
+ sp = cookie;
+ svp = SVP(sp);
+ if (INTERRUPTED(sp))
+ return (llen);
+
+ p = line; /* In case of a write of 0. */
+ for (rlen = llen; llen;) {
+ /* Get the next line. */
+ if ((p = memchr(line, '\n', llen)) == NULL)
+ len = llen;
+ else
+ len = p - line;
+
+ /*
+ * The max is sp->cols characters, and we may
+ * have already written part of the line.
+ */
+ if (len + svp->exlcontinue > sp->cols)
+ len = sp->cols - svp->exlcontinue;
+
+ /*
+ * If the first line output, do nothing.
+ * If the second line output, draw the divider line.
+ * If drew a full screen, remove the divider line.
+ * If it's a continuation line, move to the continuation
+ * point, else, move the screen up.
+ */
+ if (svp->exlcontinue == 0) {
+ if (svp->extotalcount == 1) {
+ MOVE(sp, INFOLINE(sp) - 1, 0);
+ clrtoeol();
+ if (svi_ex_divider(sp))
+ return (-1);
+ F_SET(svp, SVI_DIVIDER);
+ ++svp->extotalcount;
+ ++svp->exlinecount;
+ }
+ if (svp->extotalcount == sp->t_maxrows &&
+ F_ISSET(svp, SVI_DIVIDER)) {
+ --svp->extotalcount;
+ --svp->exlinecount;
+ F_CLR(svp, SVI_DIVIDER);
+ }
+ if (svp->extotalcount != 0 &&
+ svi_ex_scroll(sp, 0, NULL))
+ return (-1);
+ MOVE(sp, INFOLINE(sp), 0);
+ ++svp->extotalcount;
+ ++svp->exlinecount;
+ if (F_ISSET(sp, S_INTERRUPTIBLE) && INTERRUPTED(sp))
+ break;
+ } else
+ MOVE(sp, INFOLINE(sp), svp->exlcontinue);
+
+ /* Display the line, doing character translation. */
+ if (F_ISSET(sp, S_IVIDEO))
+ standout();
+ for (t = line, tlen = len; tlen--; ++t)
+ ADDCH(*t);
+ if (F_ISSET(sp, S_IVIDEO))
+ standend();
+
+ /* Clear to EOL. */
+ getyx(stdscr, oldy, oldx);
+ if (oldx < sp->cols)
+ clrtoeol();
+
+ /* If we loop, it's a new line. */
+ svp->exlcontinue = 0;
+
+ /* Reset for the next line. */
+ line += len;
+ llen -= len;
+ if (p != NULL) {
+ ++line;
+ --llen;
+ }
+ }
+ /* Refresh the screen, even if it's a partial. */
+ refresh();
+
+ /* Set up next continuation line. */
+ if (p == NULL)
+ getyx(stdscr, oldy, svp->exlcontinue);
+ return (rlen);
+}
+
+/*
+ * svi_ex_scroll --
+ * Scroll the screen for ex output.
+ */
+static int
+svi_ex_scroll(sp, mustwait, chp)
+ SCR *sp;
+ int mustwait;
+ CH *chp;
+{
+ CH ikey;
+ SVI_PRIVATE *svp;
+
+ /*
+ * Scroll the screen. Instead of scrolling the entire screen, delete
+ * the line above the first line output so preserve the maximum amount
+ * of the screen.
+ */
+ svp = SVP(sp);
+ if (svp->extotalcount >= sp->rows) {
+ MOVE(sp, 0, 0);
+ } else
+ MOVE(sp, INFOLINE(sp) - svp->extotalcount, 0);
+
+ deleteln();
+
+ /* If there are screens below us, push them back into place. */
+ if (sp->q.cqe_next != (void *)&sp->gp->dq) {
+ MOVE(sp, INFOLINE(sp), 0);
+ insertln();
+ }
+
+ /* If just displayed a full screen, wait. */
+ if (mustwait || svp->exlinecount == sp->t_maxrows) {
+ MOVE(sp, INFOLINE(sp), 0);
+ if (F_ISSET(sp, S_INTERRUPTIBLE)) {
+ ADDNSTR(STR_QMSG, (int)sizeof(STR_QMSG) - 1);
+ } else {
+ ADDNSTR(STR_CMSG, (int)sizeof(STR_CMSG) - 1);
+ }
+ clrtoeol();
+ refresh();
+ /*
+ * !!!
+ * Historic practice is that any key can be used to continue.
+ * Nvi used to require that the user enter a <carriage-return>
+ * or <newline>, but this broke historic users.
+ */
+ if (term_key(sp, &ikey, 0) != INP_OK)
+ return (-1);
+ if (ikey.ch == CH_QUIT && F_ISSET(sp, S_INTERRUPTIBLE))
+ F_SET(sp, S_INTERRUPTED);
+ if (chp != NULL)
+ *chp = ikey;
+ svp->exlinecount = 0;
+ }
+ return (0);
+}
+
+/*
+ * svi_ex_inv --
+ * Change whatever is on the info line to inverse video so we have
+ * a divider line between split screens.
+ */
+static int
+svi_ex_inv(sp)
+ SCR *sp;
+{
+ CHAR_T ch;
+ size_t spcnt, col, row;
+
+ row = INFOLINE(sp);
+
+ /*
+ * Walk through the line, retrieving each character and writing
+ * it back out in inverse video. Since curses doesn't have an
+ * EOL marker, only put out trailing spaces if we find another
+ * character.
+ *
+ * XXX
+ * This is a major kluge -- curses should have an interface
+ * that allows us to change attributes on a per line basis.
+ */
+ MOVE(sp, row, 0);
+ standout();
+ for (spcnt = col = 0;;) {
+ ch = winch(stdscr);
+ if (isspace(ch)) {
+ ++spcnt;
+ if (++col >= sp->cols)
+ break;
+ MOVE(sp, row, col);
+ } else {
+ if (spcnt) {
+ MOVE(sp, row, col - spcnt);
+ for (; spcnt > 0; --spcnt)
+ ADDCH(' ');
+ }
+ ADDCH(ch);
+ if (++col >= sp->cols)
+ break;
+ }
+ }
+ standend();
+ return (0);
+}
+
+/*
+ * svi_ex_divider --
+ * Draw a dividing line between the screens.
+ */
+static int
+svi_ex_divider(sp)
+ SCR *sp;
+{
+ size_t len;
+
+#define DIVIDESTR "+=+=+=+=+=+=+=+"
+ len = sizeof(DIVIDESTR) - 1 > sp->cols ?
+ sp->cols : sizeof(DIVIDESTR) - 1;
+ standout();
+ ADDNSTR(DIVIDESTR, len);
+ standend();
+ return (0);
+}
diff --git a/usr.bin/vi/svi/svi_get.c b/usr.bin/vi/svi/svi_get.c
new file mode 100644
index 000000000000..db790a954eee
--- /dev/null
+++ b/usr.bin/vi/svi/svi_get.c
@@ -0,0 +1,161 @@
+/*-
+ * 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[] = "@(#)svi_get.c 8.25 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 <termios.h>
+
+#include "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "../vi/vcmd.h"
+#include "svi_screen.h"
+
+/*
+ * svi_get --
+ * Fill a buffer from the terminal for vi.
+ */
+enum input
+svi_get(sp, ep, tiqh, prompt, flags)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+ ARG_CHAR_T prompt;
+ u_int flags;
+{
+ MARK save;
+ SMAP *esmp;
+ recno_t bot_lno;
+ size_t bot_off, cnt;
+ int eval;
+
+ /*
+ * The approach used is to fake like the user is doing input on
+ * the last line of the screen. This makes all of the scrolling
+ * work correctly, and allows us the use of the vi text editing
+ * routines, not to mention practically infinite length ex commands.
+ *
+ * Save the current location.
+ */
+ bot_lno = TMAP->lno;
+ bot_off = TMAP->off;
+ save.lno = sp->lno;
+ save.cno = sp->cno;
+
+ /*
+ * If it's a small screen, TMAP may be small for the screen.
+ * Fix it, filling in fake lines as we go.
+ */
+ if (ISSMALLSCREEN(sp))
+ for (esmp = HMAP + (sp->t_maxrows - 1); TMAP < esmp; ++TMAP) {
+ TMAP[1].lno = TMAP[0].lno + 1;
+ TMAP[1].off = 1;
+ }
+
+ /* Build the fake entry. */
+ TMAP[1].lno = TMAP[0].lno + 1;
+ TMAP[1].off = 1;
+ SMAP_FLUSH(&TMAP[1]);
+ ++TMAP;
+
+ /* Move to it. */
+ sp->lno = TMAP[0].lno;
+ sp->cno = 0;
+
+ if (O_ISSET(sp, O_ALTWERASE))
+ LF_SET(TXT_ALTWERASE);
+ if (O_ISSET(sp, O_TTYWERASE))
+ LF_SET(TXT_TTYWERASE);
+ LF_SET(TXT_APPENDEOL |
+ TXT_CR | TXT_ESCAPE | TXT_INFOLINE | TXT_MAPINPUT);
+
+ /* Don't update the modeline for now. */
+ F_SET(SVP(sp), SVI_INFOLINE);
+
+ eval = v_ntext(sp, ep, tiqh, NULL, NULL, 0, NULL, prompt, 0, flags);
+
+ F_CLR(SVP(sp), SVI_INFOLINE);
+
+ /* Put it all back. */
+ --TMAP;
+ sp->lno = save.lno;
+ sp->cno = save.cno;
+
+ /*
+ * If it's a small screen, TMAP may be wrong. Clear any
+ * lines that might have been overwritten.
+ */
+ if (ISSMALLSCREEN(sp)) {
+ for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) {
+ MOVE(sp, cnt, 0);
+ clrtoeol();
+ }
+ TMAP = HMAP + (sp->t_rows - 1);
+ }
+
+ /*
+ * The map may be wrong if the user entered more than one
+ * (logical) line. Fix it. If the user entered a whole
+ * screen, this will be slow, but it's not worth caring.
+ */
+ while (bot_lno != TMAP->lno || bot_off != TMAP->off)
+ if (svi_sm_1down(sp, ep))
+ return (INP_ERR);
+
+ /*
+ * 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
new file mode 100644
index 000000000000..8b437e5690de
--- /dev/null
+++ b/usr.bin/vi/svi/svi_line.c
@@ -0,0 +1,441 @@
+/*-
+ * 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[] = "@(#)svi_line.c 8.25 (Berkeley) 5/16/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "svi_screen.h"
+
+#if defined(DEBUG) && 0
+#define TABCH '-'
+#define TABSTR "--------------------"
+#else
+#define TABSTR " "
+#define TABCH ' '
+#endif
+
+/*
+ * svi_line --
+ * Update one line on the screen.
+ */
+int
+svi_line(sp, ep, smp, yp, xp)
+ SCR *sp;
+ EXF *ep;
+ SMAP *smp;
+ size_t *xp, *yp;
+{
+ SMAP *tsmp;
+ size_t chlen, cols_per_screen, cno_cnt, len, scno, skip_screens;
+ size_t offset_in_char, offset_in_line;
+ size_t oldy, oldx;
+ int ch, is_cached, is_infoline, is_partial, is_tab;
+ int list_tab, list_dollar;
+ char *p, nbuf[10];
+
+#if defined(DEBUG) && 0
+ TRACE(sp, "svi_line: row %u: line: %u off: %u\n",
+ smp - HMAP, smp->lno, smp->off);
+#endif
+
+ /*
+ * Assume that, if the cache entry for the line is filled in, the
+ * line is already on the screen, and all we need to do is return
+ * the cursor position. If the calling routine doesn't need the
+ * cursor position, we can just return.
+ */
+ is_cached = SMAP_CACHE(smp);
+ if (yp == NULL && is_cached)
+ return (0);
+
+ /*
+ * A nasty side effect of this routine is that it returns the screen
+ * position for the "current" character. Not pretty, but this is the
+ * only routine that really knows what's out there.
+ *
+ * Move to the line. This routine can be called by svi_sm_position(),
+ * which uses it to fill in the cache entry so it can figure out what
+ * the real contents of the screen are. Because of this, we have to
+ * return to whereever we started from.
+ */
+ getyx(stdscr, oldy, oldx);
+ MOVE(sp, smp - HMAP, 0);
+
+ /* Get a copy of the line. */
+ p = file_gline(sp, ep, smp->lno, &len);
+
+ /*
+ * Special case if we're printing the info/mode line. Skip printing
+ * the leading number, as well as other minor setup. If painting the
+ * line between two screens, it's always in reverse video. The only
+ * time this code paints the mode line is when the user is entering
+ * text for a ":" command, so we can put the code here instead of
+ * dealing with the empty line logic below. This is a kludge, but it's
+ * pretty much confined to this module.
+ *
+ * Set the number of screens to skip until a character is displayed.
+ * Left-right screens are special, because we don't bother building
+ * a buffer to be skipped over.
+ *
+ * Set the number of columns for this screen.
+ */
+ cols_per_screen = sp->cols;
+ list_tab = O_ISSET(sp, O_LIST);
+ if (is_infoline = ISINFOLINE(sp, smp)) {
+ list_dollar = 0;
+ if (O_ISSET(sp, O_LEFTRIGHT))
+ skip_screens = 0;
+ else
+ skip_screens = smp->off - 1;
+ } else {
+ list_dollar = list_tab;
+ skip_screens = smp->off - 1;
+
+ /*
+ * If O_NUMBER is set and it's line number 1 or the line exists
+ * and this is the first screen of a folding line or any left-
+ * right line, display the line number.
+ */
+ if (O_ISSET(sp, O_NUMBER)) {
+ cols_per_screen -= O_NUMBER_LENGTH;
+ if ((smp->lno == 1 || p != NULL) && skip_screens == 0) {
+ (void)snprintf(nbuf,
+ sizeof(nbuf), O_NUMBER_FMT, smp->lno);
+ ADDSTR(nbuf);
+ }
+ }
+ }
+
+ /*
+ * Special case non-existent lines and the first line of an empty
+ * file. In both cases, the cursor position is 0, but corrected
+ * for the O_NUMBER field if it was displayed.
+ */
+ if (p == NULL || len == 0) {
+ /* Fill in the cursor. */
+ if (yp != NULL && smp->lno == sp->lno) {
+ *yp = smp - HMAP;
+ *xp = sp->cols - cols_per_screen;
+ }
+
+ /* If the line is on the screen, quit. */
+ if (is_cached)
+ goto ret;
+
+ /* Set line cacheing information. */
+ smp->c_sboff = smp->c_eboff = 0;
+ smp->c_scoff = smp->c_eclen = 0;
+
+ /* Lots of special cases for empty lines. */
+ if (skip_screens == 0)
+ if (p == NULL) {
+ if (smp->lno == 1) {
+ if (list_dollar) {
+ ch = '$';
+ goto empty;
+ }
+ } else {
+ ch = '~';
+ goto empty;
+ }
+ } else
+ if (list_dollar) {
+ ch = '$';
+empty: ADDCH(ch);
+ }
+
+ clrtoeol();
+ MOVEA(sp, oldy, oldx);
+ return (0);
+ }
+
+ /*
+ * If we wrote a line that's this or a previous one, we can do this
+ * much more quickly -- we cached the starting and ending positions
+ * of that line. The way it works is we keep information about the
+ * lines displayed in the SMAP. If we're painting the screen in
+ * the forward, this saves us from reformatting the physical line for
+ * every line on the screen. This wins big on binary files with 10K
+ * lines.
+ *
+ * Test for the first screen of the line, then the current screen line,
+ * then the line behind us, then do the hard work. Note, it doesn't
+ * do us any good to have a line in front of us -- it would be really
+ * hard to try and figure out tabs in the reverse direction, i.e. how
+ * many spaces a tab takes up in the reverse direction depends on
+ * what characters preceded it.
+ */
+ if (smp->off == 1) {
+ smp->c_sboff = offset_in_line = 0;
+ smp->c_scoff = offset_in_char = 0;
+ p = &p[offset_in_line];
+ } else if (is_cached) {
+ offset_in_line = smp->c_sboff;
+ offset_in_char = smp->c_scoff;
+ p = &p[offset_in_line];
+ if (skip_screens != 0)
+ cols_per_screen = sp->cols;
+ } else if (smp != HMAP &&
+ SMAP_CACHE(tsmp = smp - 1) && tsmp->lno == smp->lno) {
+ if (tsmp->c_eclen != tsmp->c_ecsize) {
+ offset_in_line = tsmp->c_eboff;
+ offset_in_char = tsmp->c_eclen;
+ } else {
+ offset_in_line = tsmp->c_eboff + 1;
+ offset_in_char = 0;
+ }
+
+ /* Put starting info for this line in the cache. */
+ smp->c_sboff = offset_in_line;
+ smp->c_scoff = offset_in_char;
+ p = &p[offset_in_line];
+ if (skip_screens != 0)
+ cols_per_screen = sp->cols;
+ } else {
+ offset_in_line = 0;
+ offset_in_char = 0;
+
+ /* This is the loop that skips through screens. */
+ if (skip_screens == 0) {
+ smp->c_sboff = offset_in_line;
+ smp->c_scoff = offset_in_char;
+ } else for (scno = 0; offset_in_line < len; ++offset_in_line) {
+ scno += chlen =
+ (ch = *(u_char *)p++) == '\t' && !list_tab ?
+ TAB_OFF(sp, scno) : KEY_LEN(sp, ch);
+ if (scno < cols_per_screen)
+ continue;
+ /*
+ * Reset cols_per_screen to second and subsequent line
+ * length.
+ */
+ scno -= cols_per_screen;
+ cols_per_screen = sp->cols;
+
+ /*
+ * If crossed the last skipped screen boundary, start
+ * displaying the characters.
+ */
+ if (--skip_screens)
+ continue;
+
+ /* Put starting info for this line in the cache. */
+ if (scno) {
+ smp->c_sboff = offset_in_line;
+ smp->c_scoff = offset_in_char = chlen - scno;
+ --p;
+ } else {
+ smp->c_sboff = ++offset_in_line;
+ smp->c_scoff = 0;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Set the number of characters to skip before reaching the cursor
+ * character. Offset by 1 and use 0 as a flag value. Svi_line is
+ * called repeatedly with a valid pointer to a cursor position.
+ * Don't fill anything in unless it's the right line and the right
+ * character, and the right part of the character...
+ */
+ if (yp == NULL ||
+ smp->lno != sp->lno || sp->cno < offset_in_line ||
+ offset_in_line + cols_per_screen < sp->cno) {
+ cno_cnt = 0;
+ /* If the line is on the screen, quit. */
+ if (is_cached)
+ goto ret;
+ } else
+ cno_cnt = (sp->cno - offset_in_line) + 1;
+
+ /* This is the loop that actually displays characters. */
+ for (is_partial = 0, scno = 0;
+ offset_in_line < len; ++offset_in_line, offset_in_char = 0) {
+ if ((ch = *(u_char *)p++) == '\t' && !list_tab) {
+ scno += chlen = TAB_OFF(sp, scno) - offset_in_char;
+ is_tab = 1;
+ } else {
+ scno += chlen = KEY_LEN(sp, ch) - offset_in_char;
+ is_tab = 0;
+ }
+
+ /*
+ * Only display up to the right-hand column. Set a flag if
+ * the entire character wasn't displayed for use in setting
+ * the cursor. If reached the end of the line, set the cache
+ * info for the screen. Don't worry about there not being
+ * characters to display on the next screen, its lno/off won't
+ * match up in that case.
+ */
+ if (scno >= cols_per_screen) {
+ smp->c_ecsize = chlen;
+ chlen -= scno - cols_per_screen;
+ smp->c_eclen = chlen;
+ smp->c_eboff = offset_in_line;
+ if (scno > cols_per_screen)
+ is_partial = 1;
+
+ /* Terminate the loop. */
+ offset_in_line = len;
+ }
+
+ /*
+ * If the caller wants the cursor value, and this was the
+ * cursor character, set the value. There are two ways to
+ * put the cursor on a character -- if it's normal display
+ * mode, it goes on the last column of the character. If
+ * it's input mode, it goes on the first. In normal mode,
+ * set the cursor only if the entire character was displayed.
+ */
+ if (cno_cnt &&
+ --cno_cnt == 0 && (F_ISSET(sp, S_INPUT) || !is_partial)) {
+ *yp = smp - HMAP;
+ if (F_ISSET(sp, S_INPUT))
+ *xp = scno - chlen;
+ else
+ *xp = scno - 1;
+ if (O_ISSET(sp, O_NUMBER) &&
+ !is_infoline && smp->off == 1)
+ *xp += O_NUMBER_LENGTH;
+
+ /* If the line is on the screen, quit. */
+ if (is_cached)
+ goto ret;
+ }
+
+ /* If the line is on the screen, don't display anything. */
+ if (is_cached)
+ continue;
+
+ /*
+ * Display the character. If it's a tab and tabs aren't some
+ * ridiculous length, do it fast. (We do tab expansion here
+ * because curses doesn't have a way to set the tab length.)
+ */
+ if (is_tab) {
+ if (chlen <= sizeof(TABSTR) - 1) {
+ ADDNSTR(TABSTR, chlen);
+ } else
+ while (chlen--)
+ ADDCH(TABCH);
+ } else
+ ADDNSTR(KEY_NAME(sp, ch) + offset_in_char, chlen);
+ }
+
+ if (scno < cols_per_screen) {
+ /* If didn't paint the whole line, update the cache. */
+ smp->c_ecsize = smp->c_eclen = KEY_LEN(sp, ch);
+ smp->c_eboff = len - 1;
+
+ /*
+ * If not the info/mode line, and O_LIST set, and at the
+ * end of the line, and the line ended on this screen,
+ * add a trailing $.
+ */
+ if (list_dollar) {
+ ++scno;
+ ADDCH('$');
+ }
+
+ /* If still didn't paint the whole line, clear the rest. */
+ if (scno < cols_per_screen)
+ clrtoeol();
+ }
+
+ret: MOVEA(sp, oldy, oldx);
+ return (0);
+}
+
+/*
+ * svi_number --
+ * Repaint the numbers on all the lines.
+ */
+int
+svi_number(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SMAP *smp;
+ size_t oldy, oldx;
+ char *lp, nbuf[10];
+
+ /*
+ * Try and avoid getting the last line in the file, by getting the
+ * line after the last line in the screen -- if it exists, we know
+ * we have to to number all the lines in the screen. Get the one
+ * after the last instead of the last, so that the info line doesn't
+ * fool us.
+ *
+ * If that test fails, we have to check each line for existence.
+ *
+ * XXX
+ * The problem is that file_lline will lie, and tell us that the
+ * info line is the last line in the file.
+ */
+ lp = file_gline(sp, ep, TMAP->lno + 1, NULL);
+
+ getyx(stdscr, oldy, oldx);
+ for (smp = HMAP; smp <= TMAP; ++smp) {
+ if (smp->off != 1)
+ continue;
+ if (ISINFOLINE(sp, smp))
+ break;
+ if (smp->lno != 1 && lp == 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);
+ ADDSTR(nbuf);
+ }
+ MOVEA(sp, oldy, oldx);
+ return (0);
+}
diff --git a/usr.bin/vi/svi/svi_refresh.c b/usr.bin/vi/svi/svi_refresh.c
new file mode 100644
index 000000000000..bc8bd92c1acd
--- /dev/null
+++ b/usr.bin/vi/svi/svi_refresh.c
@@ -0,0 +1,818 @@
+/*-
+ * 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[] = "@(#)svi_refresh.c 8.60 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "svi_screen.h"
+#include "../sex/sex_screen.h"
+
+static int svi_modeline __P((SCR *, EXF *));
+
+int
+svi_refresh(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SCR *tsp;
+ u_int paintbits;
+
+ /*
+ * 1: Resize the screen.
+ *
+ * Notice that a resize is requested, and set up everything so that
+ * the file gets reinitialized. Done here, instead of in the vi loop
+ * because there may be other initialization that other screens need
+ * to do. The actual changing of the row/column values was done by
+ * calling the ex options code which put them into the environment,
+ * which is used by curses. Stupid, but ugly.
+ */
+ if (F_ISSET(sp, S_RESIZE)) {
+ /* Reinitialize curses. */
+ if (svi_curses_end(sp) || svi_curses_init(sp))
+ return (1);
+
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(SVP(sp));
+
+ /*
+ * Fill the map, incidentally losing any svi_line()
+ * cached information.
+ */
+ if (svi_sm_fill(sp, ep, sp->lno, P_FILL))
+ return (1);
+ F_CLR(sp, S_RESIZE | S_REFORMAT);
+ F_SET(sp, S_REDRAW);
+ }
+
+ /*
+ * 2: S_REFRESH
+ *
+ * If S_REFRESH is set in the current screen, repaint everything
+ * that we can find.
+ */
+ if (F_ISSET(sp, S_REFRESH))
+ for (tsp = sp->gp->dq.cqh_first;
+ tsp != (void *)&sp->gp->dq; tsp = tsp->q.cqe_next)
+ if (tsp != sp)
+ F_SET(tsp, S_REDRAW);
+ /*
+ * 3: Related or dirtied screens, or screens with messages.
+ *
+ * If related screens share a view into a file, they may have been
+ * modified as well. Refresh any screens with paint or dirty bits
+ * set, or where messages are waiting. Finally, if we refresh any
+ * screens other than the current one, the cursor will be trashed.
+ */
+ paintbits = S_REDRAW | S_REFORMAT | S_REFRESH;
+ if (O_ISSET(sp, O_NUMBER))
+ paintbits |= S_RENUMBER;
+ for (tsp = sp->gp->dq.cqh_first;
+ tsp != (void *)&sp->gp->dq; tsp = tsp->q.cqe_next)
+ if (tsp != sp &&
+ (F_ISSET(tsp, paintbits) ||
+ F_ISSET(SVP(tsp), SVI_SCREENDIRTY) ||
+ tsp->msgq.lh_first != NULL &&
+ !F_ISSET(tsp->msgq.lh_first, M_EMPTY))) {
+ (void)svi_paint(tsp, tsp->ep);
+ F_CLR(SVP(tsp), SVI_SCREENDIRTY);
+ F_SET(SVP(sp), SVI_CUR_INVALID);
+ }
+
+ /*
+ * 4: Refresh the current screen.
+ *
+ * Always refresh the current screen, it may be a cursor movement.
+ * Also, always do it last -- that way, S_REFRESH can be set in
+ * the current screen only, and the screen won't flash.
+ */
+ F_CLR(sp, SVI_SCREENDIRTY);
+ return (svi_paint(sp, ep));
+}
+
+/*
+ * svi_paint --
+ * This is the guts of the vi curses screen code. The idea is that
+ * the SCR structure passed in contains the new coordinates of the
+ * screen. What makes this hard is that we don't know how big
+ * characters are, doing input can put the cursor in illegal places,
+ * and we're frantically trying to avoid repainting unless it's
+ * absolutely necessary. If you change this code, you'd better know
+ * what you're doing. It's subtle and quick to anger.
+ */
+int
+svi_paint(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SMAP *smp, tmp;
+ SVI_PRIVATE *svp;
+ recno_t lastline, lcnt;
+ size_t cwtotal, cnt, len, x, y;
+ int ch, didpaint, leftright_warp;
+ char *p;
+
+#define LNO sp->lno
+#define OLNO svp->olno
+#define CNO sp->cno
+#define OCNO svp->ocno
+#define SCNO svp->sc_col
+
+ didpaint = leftright_warp = 0;
+ svp = SVP(sp);
+
+ /*
+ * 1: Reformat the lines.
+ *
+ * If the lines themselves have changed (:set list, for example),
+ * fill in the map from scratch. Adjust the screen that's being
+ * displayed if the leftright flag is set.
+ */
+ if (F_ISSET(sp, S_REFORMAT)) {
+ /* 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_opt_screens(sp, ep, LNO, &CNO)) != 1)
+ for (smp = HMAP; smp <= TMAP; ++smp)
+ smp->off = cnt;
+ F_CLR(sp, S_REFORMAT);
+ F_SET(sp, S_REDRAW);
+ }
+
+ /*
+ * 2: Line movement.
+ *
+ * Line changes can cause the top line to change as well. As
+ * before, if the movement is large, the screen is repainted.
+ *
+ * 2a: Tiny screens.
+ *
+ * Tiny screens cannot be permitted into the "scrolling" parts of
+ * the smap code for two reasons. If the screen size is 1 line,
+ * HMAP == TMAP and the code will quickly drop core. If the screen
+ * size is 2, none of the divisions by 2 will work, and scrolling
+ * won't work. In fact, because no line change will be less than
+ * HALFTEXT(sp), we always ending up "filling" the map, with a
+ * P_MIDDLE flag, which isn't what the user wanted. Tiny screens
+ * can go into the "fill" portions of the smap code, however.
+ */
+ if (sp->t_rows <= 2) {
+ if (LNO < HMAP->lno) {
+ if (svi_sm_fill(sp, ep, LNO, P_TOP))
+ return (1);
+ } else if (LNO > TMAP->lno)
+ if (svi_sm_fill(sp, ep, LNO, P_BOTTOM))
+ return (1);
+ if (sp->t_rows == 1) {
+ HMAP->off = svi_opt_screens(sp, ep, LNO, &CNO);
+ goto paint;
+ }
+ F_SET(sp, S_REDRAW);
+ goto adjust;
+ }
+
+ /*
+ * 2b: Small screens.
+ *
+ * Users can use the window, w300, w1200 and w9600 options to make
+ * the screen artificially small. The behavior of these options
+ * in the historic vi wasn't all that consistent, and, in fact, it
+ * was never documented how various screen movements affected the
+ * screen size. Generally, one of three things would happen:
+ * 1: The screen would expand in size, showing the line
+ * 2: The screen would scroll, showing the line
+ * 3: The screen would compress to its smallest size and
+ * repaint.
+ * In general, scrolling didn't cause compression (200^D was handled
+ * the same as ^D), movement to a specific line would (:N where N
+ * was 1 line below the screen caused a screen compress), and cursor
+ * movement would scroll if it was 11 lines or less, and compress if
+ * it was more than 11 lines. (And, no, I have no idea where the 11
+ * comes from.)
+ *
+ * What we do is try and figure out if the line is less than half of
+ * a full screen away. If it is, we expand the screen if there's
+ * room, and then scroll as necessary. The alternative is to compress
+ * and repaint.
+ *
+ * !!!
+ * This code is a special case from beginning to end. Unfortunately,
+ * home modems are still slow enough that it's worth having.
+ *
+ * XXX
+ * If the line a really long one, i.e. part of the line is on the
+ * screen but the column offset is not, we'll end up in the adjust
+ * code, when we should probably have compressed the screen.
+ */
+ if (ISSMALLSCREEN(sp))
+ if (LNO < HMAP->lno) {
+ lcnt = svi_sm_nlines(sp, ep, HMAP, LNO, sp->t_maxrows);
+ if (lcnt <= HALFSCREEN(sp))
+ for (; lcnt && sp->t_rows != sp->t_maxrows;
+ --lcnt, ++sp->t_rows) {
+ ++TMAP;
+ if (svi_sm_1down(sp, ep))
+ return (1);
+ }
+ else
+ goto small_fill;
+ } else if (LNO > TMAP->lno) {
+ lcnt = svi_sm_nlines(sp, ep, TMAP, LNO, sp->t_maxrows);
+ if (lcnt <= HALFSCREEN(sp))
+ for (; lcnt && sp->t_rows != sp->t_maxrows;
+ --lcnt, ++sp->t_rows) {
+ if (svi_sm_next(sp, ep, TMAP, TMAP + 1))
+ return (1);
+ ++TMAP;
+ if (svi_line(sp, ep, TMAP, NULL, NULL))
+ return (1);
+ }
+ else {
+small_fill: MOVE(sp, INFOLINE(sp), 0);
+ clrtoeol();
+ for (; sp->t_rows > sp->t_minrows;
+ --sp->t_rows, --TMAP) {
+ MOVE(sp, TMAP - HMAP, 0);
+ clrtoeol();
+ }
+ if (svi_sm_fill(sp, ep, LNO, P_FILL))
+ return (1);
+ F_SET(sp, S_REDRAW);
+ goto adjust;
+ }
+ }
+
+ /*
+ * 3a: Line down, or current screen.
+ */
+ if (LNO >= HMAP->lno) {
+ /* Current screen. */
+ if (LNO <= TMAP->lno)
+ goto adjust;
+
+ /*
+ * 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)) {
+ while (lcnt--)
+ if (svi_sm_1up(sp, ep))
+ 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 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_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;
+ lcnt = svi_sm_nlines(sp, ep, &tmp, lastline, sp->t_rows);
+ if (lcnt < sp->t_rows) {
+ if (svi_sm_fill(sp, ep, lastline, P_BOTTOM))
+ return (1);
+ F_SET(sp, S_REDRAW);
+ goto adjust;
+ }
+ /* It's not close, just put the line in the middle. */
+ goto middle;
+ }
+
+ /*
+ * 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.
+ */
+ tmp.lno = 1;
+ tmp.off = 1;
+ lcnt = svi_sm_nlines(sp, ep, &tmp, LNO, HALFTEXT(sp));
+ if (lcnt < HALFTEXT(sp)) {
+ if (svi_sm_fill(sp, ep, 1, P_TOP))
+ return (1);
+ } else
+middle: if (svi_sm_fill(sp, ep, LNO, P_MIDDLE))
+ return (1);
+ F_SET(sp, S_REDRAW);
+
+ /*
+ * At this point we know part of the line is on the screen. Since
+ * scrolling is done using logical lines, not physical, all of the
+ * line may not be on the screen. While that's not necessarily bad,
+ * if the part the cursor is on isn't there, we're going to lose.
+ * This can be tricky; if the line covers the entire screen, lno
+ * may be the same as both ends of the map, that's why we test BOTH
+ * the top and the bottom of the map. This isn't a problem for
+ * left-right scrolling, the cursor movement code handles the problem.
+ *
+ * There's a performance issue here if editing *really* long lines.
+ * This gets to the right spot by scrolling, and, in a binary, by
+ * scrolling hundreds of lines. If the adjustment looks like it's
+ * going to be a serious problem, refill the screen and repaint.
+ */
+adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
+ (LNO == HMAP->lno || LNO == TMAP->lno)) {
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO);
+ if (LNO == HMAP->lno && cnt < HMAP->off)
+ if ((HMAP->off - cnt) > HALFTEXT(sp)) {
+ HMAP->off = cnt;
+ svi_sm_fill(sp, ep, OOBLNO, P_TOP);
+ F_SET(sp, S_REDRAW);
+ } else
+ while (cnt < HMAP->off)
+ if (svi_sm_1down(sp, ep))
+ return (1);
+ if (LNO == TMAP->lno && cnt > TMAP->off)
+ if ((cnt - TMAP->off) > HALFTEXT(sp)) {
+ TMAP->off = cnt;
+ svi_sm_fill(sp, ep, OOBLNO, P_BOTTOM);
+ F_SET(sp, S_REDRAW);
+ } else
+ while (cnt > TMAP->off)
+ if (svi_sm_1up(sp, ep))
+ return (1);
+ }
+
+ /*
+ * If the screen needs to be repainted, skip cursor optimization.
+ * However, in the code above we skipped leftright scrolling on
+ * the grounds that the cursor code would handle it. Make sure
+ * the right screen is up.
+ */
+ if (F_ISSET(sp, S_REDRAW)) {
+ if (O_ISSET(sp, O_LEFTRIGHT)) {
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO);
+ if (HMAP->off != cnt)
+ for (smp = HMAP; smp <= TMAP; ++smp)
+ smp->off = cnt;
+ }
+ goto paint;
+ }
+
+ /*
+ * 4: Cursor movements.
+ *
+ * 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. 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
+ * least in obvious situations, like moving right and encountering
+ * a tab, without reparsing the whole line.
+ */
+
+ /* If the line we're working with has changed, reparse. */
+ if (F_ISSET(SVP(sp), SVI_CUR_INVALID) || LNO != OLNO) {
+ F_CLR(SVP(sp), SVI_CUR_INVALID);
+ goto slow;
+ }
+
+ /* Otherwise, if nothing's changed, go fast. */
+ if (CNO == OCNO)
+ goto fast;
+
+ /*
+ * Get the current line. If this fails, we either have an empty
+ * file and can just repaint, or there's a real problem. This
+ * isn't a performance issue because there aren't any ways to get
+ * here repeatedly.
+ */
+ if ((p = file_gline(sp, ep, LNO, &len)) == NULL) {
+ if (file_lline(sp, ep, &lastline))
+ return (1);
+ if (lastline == 0)
+ goto slow;
+ GETLINE_ERR(sp, LNO);
+ return (1);
+ }
+
+#ifdef DEBUG
+ /* This is just a test. */
+ if (CNO >= len && len != 0) {
+ msgq(sp, M_ERR, "Error: %s/%d: cno (%u) >= len (%u)",
+ tail(__FILE__), __LINE__, CNO, len);
+ return (1);
+ }
+#endif
+ /*
+ * The basic scheme here is to look at the characters in between
+ * the old and new positions and decide how big they are on the
+ * screen, and therefore, how many screen positions to move.
+ */
+ if (CNO < OCNO) {
+ /*
+ * 4a: Cursor moved left.
+ *
+ * Point to the old character. The old cursor position can
+ * be past EOL if, for example, we just deleted the rest of
+ * the line. In this case, since we don't know the width of
+ * the characters we traversed, we have to do it slowly.
+ */
+ p += OCNO;
+ cnt = (OCNO - CNO) + 1;
+ if (OCNO >= len)
+ goto slow;
+
+ /*
+ * 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.
+ */
+ if (SCNO + 1 + MAX_CHARACTER_COLUMNS < cnt)
+ goto lscreen;
+
+ /*
+ * Count up the widths of the characters. If it's a tab
+ * character, go do it the the slow way.
+ */
+ for (cwtotal = 0; cnt--; cwtotal += KEY_LEN(sp, ch))
+ if ((ch = *(u_char *)p--) == '\t')
+ goto slow;
+
+ /*
+ * Decrement the screen cursor by the total width of the
+ * characters minus 1.
+ */
+ cwtotal -= 1;
+
+ /*
+ * If we're moving left, and there's a wide character in the
+ * current position, go to the end of the character.
+ */
+ if (KEY_LEN(sp, ch) > 1)
+ cwtotal -= KEY_LEN(sp, ch) - 1;
+
+ /*
+ * 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 = cnt;
+ leftright_warp = 1;
+ goto paint;
+ }
+ goto slow;
+ }
+ SCNO -= cwtotal;
+ } else {
+ /*
+ * 4b: Cursor moved right.
+ *
+ * Point to the first character to the right.
+ */
+ p += OCNO + 1;
+ cnt = CNO - OCNO;
+
+ /*
+ * Count up the widths of the characters. If it's a tab
+ * character, go do it the the slow way. If we cross a
+ * screen boundary, we can quit.
+ */
+ for (cwtotal = SCNO; cnt--;) {
+ if ((ch = *(u_char *)p++) == '\t')
+ goto slow;
+ if ((cwtotal += KEY_LEN(sp, ch)) >= SCREEN_COLS(sp))
+ break;
+ }
+
+ /*
+ * Increment the screen cursor by the total width of the
+ * characters.
+ */
+ SCNO = cwtotal;
+
+ /* See screen change comment in section 4a. */
+ if (SCNO >= SCREEN_COLS(sp)) {
+ if (O_ISSET(sp, O_LEFTRIGHT)) {
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO);
+ for (smp = HMAP; smp <= TMAP; ++smp)
+ smp->off = cnt;
+ leftright_warp = 1;
+ goto paint;
+ }
+ goto slow;
+ }
+ }
+
+ /*
+ * 4c: Fast cursor update.
+ *
+ * Retrieve the current cursor position, and correct it
+ * for split screens.
+ */
+fast: getyx(stdscr, y, x);
+ y -= sp->woff;
+ goto number;
+
+ /*
+ * 4d: Slow cursor update.
+ *
+ * Walk through the map and find the current line. If doing left-right
+ * scrolling and the cursor movement has changed the screen displayed,
+ * scroll the screen left or right, unless we're updating the info line
+ * in which case we just scroll that one line. Then update the screen
+ * lines for this file line until we have a new screen cursor position.
+ */
+slow: for (smp = HMAP; smp->lno != LNO; ++smp);
+ if (O_ISSET(sp, O_LEFTRIGHT)) {
+ cnt = svi_opt_screens(sp, ep, LNO, &CNO) % SCREEN_COLS(sp);
+ if (cnt != HMAP->off) {
+ if (ISINFOLINE(sp, smp))
+ smp->off = cnt;
+ else {
+ for (smp = HMAP; smp <= TMAP; ++smp)
+ smp->off = cnt;
+ leftright_warp = 1;
+ }
+ goto paint;
+ }
+ }
+ for (y = -1; smp <= TMAP && smp->lno == LNO; ++smp) {
+ if (svi_line(sp, ep, smp, &y, &SCNO))
+ return (1);
+ if (y != -1)
+ break;
+ }
+ goto number;
+
+ /*
+ * 5: Repaint the entire screen.
+ *
+ * Lost big, do what you have to do. We flush the cache as S_REDRAW
+ * gets set when the screen isn't worth fixing, and it's simpler to
+ * repaint. So, don't trust anything that we think we know about it.
+ */
+paint: for (smp = HMAP; smp <= TMAP; ++smp)
+ SMAP_FLUSH(smp);
+ for (smp = HMAP; smp <= TMAP; ++smp)
+ if (svi_line(sp, ep, smp, &y, &SCNO))
+ return (1);
+ /*
+ * If it's a small screen and we're redrawing, clear the unused lines,
+ * ex may have overwritten them.
+ */
+ if (F_ISSET(sp, S_REDRAW)) {
+ if (ISSMALLSCREEN(sp))
+ for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) {
+ MOVE(sp, cnt, 0);
+ clrtoeol();
+ }
+ F_CLR(sp, S_REDRAW);
+ }
+
+ didpaint = 1;
+
+ /*
+ * 6: Repaint the line numbers.
+ *
+ * If O_NUMBER is set and the S_RENUMBER bit is set, and we didn't
+ * repaint the screen, repaint all of the line numbers, they've
+ * changed.
+ */
+number: if (O_ISSET(sp, O_NUMBER) && F_ISSET(sp, S_RENUMBER) && !didpaint) {
+ if (svi_number(sp, ep))
+ return (1);
+ F_CLR(sp, S_RENUMBER);
+ }
+
+ /*
+ * 7: Refresh the screen.
+ *
+ * If the screen was corrupted, refresh it.
+ */
+ if (F_ISSET(sp, S_REFRESH)) {
+ wrefresh(curscr);
+ F_CLR(sp, S_REFRESH);
+ }
+
+ if (F_ISSET(sp, S_BELLSCHED))
+ svi_bell(sp);
+ /*
+ * If the bottom line isn't in use by the colon command, and
+ * we're not in the middle of a map:
+ *
+ * Display any messages. Don't test S_UPDATE_MODE. The
+ * message printing routine set it to avoid anyone else
+ * destroying the message we're about to display.
+ *
+ * If the bottom line isn't in use by anyone, put out the
+ * standard status line.
+ */
+ if (!F_ISSET(SVP(sp), SVI_INFOLINE) && !KEYS_WAITING(sp))
+ if (sp->msgq.lh_first != NULL &&
+ !F_ISSET(sp->msgq.lh_first, M_EMPTY))
+ svi_msgflush(sp);
+ else if (!F_ISSET(sp, S_UPDATE_MODE))
+ svi_modeline(sp, ep);
+
+ /* Update saved information. */
+ OCNO = CNO;
+ OLNO = LNO;
+
+ /* Place the cursor. */
+ MOVE(sp, y, SCNO);
+
+ /* 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);
+}
+
+/*
+ * svi_modeline --
+ * Update the mode line.
+ */
+static int
+svi_modeline(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ size_t cols, curlen, endpoint, len, midpoint;
+ char *p, buf[20];
+
+ /* Clear the mode line. */
+ MOVE(sp, INFOLINE(sp), 0);
+ clrtoeol();
+
+ /*
+ * We put down the file name, the ruler, the mode and the dirty flag.
+ * If there's not enough room, there's not enough room, we don't play
+ * any special games. We try to put the ruler in the middle and the
+ * mode and dirty flag at the end.
+ *
+ * !!!
+ * Leave the last character blank, in case it's a really dumb terminal
+ * with hardware scroll. Second, don't paint the last character in the
+ * screen, SunOS 4.1.1 and Ultrix 4.2 curses won't let you.
+ */
+ cols = sp->cols - 1;
+
+ curlen = 0;
+ if (sp->q.cqe_next != (void *)&sp->gp->dq) {
+ for (p = sp->frp->name; *p != '\0'; ++p);
+ while (--p > sp->frp->name) {
+ if (*p == '/') {
+ ++p;
+ break;
+ }
+ if ((curlen += KEY_LEN(sp, *p)) > cols) {
+ curlen -= KEY_LEN(sp, *p);
+ ++p;
+ break;
+ }
+ }
+
+ MOVE(sp, INFOLINE(sp), 0);
+ standout();
+ for (; *p != '\0'; ++p)
+ ADDCH(*p);
+ standend();
+ }
+
+ /*
+ * Display the ruler. If we're not at the midpoint yet, move there.
+ * Otherwise, just add in two extra spaces.
+ *
+ * XXX
+ * Assume that numbers, commas, and spaces only take up a single
+ * column on the screen.
+ */
+ if (O_ISSET(sp, O_RULER)) {
+ len = snprintf(buf,
+ sizeof(buf), "%lu,%lu", sp->lno, sp->cno + 1);
+ midpoint = (cols - ((len + 1) / 2)) / 2;
+ if (curlen < midpoint) {
+ MOVE(sp, INFOLINE(sp), midpoint);
+ ADDSTR(buf);
+ curlen += len;
+ } else if (curlen + 2 + len < cols) {
+ ADDSTR(" ");
+ ADDSTR(buf);
+ curlen += 2 + len;
+ }
+ }
+
+ /*
+ * Display the mode and the modified flag, as close to the end of the
+ * line as possible, but guaranteeing at least two spaces between the
+ * ruler and the modified flag.
+ *
+ * XXX
+ * Assume that mode name characters, asterisks, and spaces only take
+ * up a single column on the screen.
+ */
+ endpoint = cols;
+ if (O_ISSET(sp, O_SHOWDIRTY) && F_ISSET(ep, F_MODIFIED))
+ --endpoint;
+
+#define MODESIZE 9
+ if (O_ISSET(sp, O_SHOWMODE))
+ endpoint -= MAX_MODE_NAME;
+
+ if (endpoint < curlen + 2)
+ return (0);
+
+ MOVE(sp, INFOLINE(sp), endpoint);
+ if (O_ISSET(sp, O_SHOWDIRTY) && F_ISSET(ep, F_MODIFIED))
+ ADDSTR("*");
+ if (O_ISSET(sp, O_SHOWMODE))
+ ADDSTR(sp->showmode);
+ return (0);
+}
diff --git a/usr.bin/vi/svi/svi_relative.c b/usr.bin/vi/svi/svi_relative.c
new file mode 100644
index 000000000000..a1af33fe9c91
--- /dev/null
+++ b/usr.bin/vi/svi/svi_relative.c
@@ -0,0 +1,334 @@
+/*-
+ * 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[] = "@(#)svi_relative.c 8.16 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "svi_screen.h"
+
+static size_t svi_screens
+ __P((SCR *, EXF *, char *, size_t, recno_t, size_t *));
+
+/*
+ * svi_column --
+ * Return the logical column of the cursor.
+ */
+int
+svi_column(sp, ep, cp)
+ SCR *sp;
+ EXF *ep;
+ size_t *cp;
+{
+ size_t col;
+
+ col = SVP(sp)->sc_col;
+ if (O_ISSET(sp, O_NUMBER))
+ col -= O_NUMBER_LENGTH;
+ *cp = col;
+ return (0);
+}
+
+/*
+ * 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_opt_screens(sp, ep, lno, cnop)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ size_t *cnop;
+{
+ size_t cols, screens;
+
+ /*
+ * 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);
+
+ /* 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 += KEY_LEN(sp, '$');
+
+ 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_screens --
+ * Return the screen columns necessary to display the line, or,
+ * if specified, the physical character column within the line.
+ */
+static size_t
+svi_screens(sp, ep, lp, llen, lno, cnop)
+ SCR *sp;
+ EXF *ep;
+ char *lp;
+ size_t llen;
+ recno_t lno;
+ size_t *cnop;
+{
+ size_t chlen, cno, len, scno, tab_off;
+ int ch, listset;
+ char *p;
+
+ /* Need the line to go any further. */
+ if (lp == NULL)
+ lp = file_gline(sp, ep, lno, &llen);
+
+ /* Missing or empty lines are easy. */
+ if (lp == NULL || llen == 0)
+ return (0);
+
+ listset = O_ISSET(sp, O_LIST);
+
+#define SET_CHLEN { \
+ chlen = (ch = *(u_char *)p++) == '\t' && \
+ !listset ? TAB_OFF(sp, tab_off) : KEY_LEN(sp, ch); \
+}
+#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 len;
+
+ /* Last character is easy, and common. */
+ if (sp->rcm_last)
+ return (file_gline(sp,
+ ep, lno, &len) == NULL || len == 0 ? 0 : len - 1);
+
+ /* First character is easy, and common. */
+ if (HMAP->off == 1 && sp->rcm == 0)
+ return (0);
+
+ /*
+ * 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_cm_public --
+ * Return the physical column from the line that will display a
+ * 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_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;
+{
+ size_t chlen, len, llen, scno, tab_off;
+ int ch, listset;
+ char *lp, *p;
+
+ /* Need the line to go any further. */
+ lp = file_gline(sp, ep, lno, &llen);
+
+ /* Missing or empty lines are easy. */
+ if (lp == NULL || llen == 0)
+ return (0);
+
+ listset = O_ISSET(sp, O_LIST);
+
+ /* Discard screen (logical) lines. */
+ for (scno = 0, p = lp, len = llen; --off;) {
+ for (; len && scno < sp->cols; --len)
+ scno += (ch = *(u_char *)p++) == '\t' &&
+ !listset ? TAB_OFF(sp, scno) : KEY_LEN(sp, ch);
+
+ /*
+ * 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 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
new file mode 100644
index 000000000000..05e07eaeb6f1
--- /dev/null
+++ b/usr.bin/vi/svi/svi_screen.c
@@ -0,0 +1,332 @@
+/*-
+ * 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[] = "@(#)svi_screen.c 8.91 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "../vi/vcmd.h"
+#include "svi_screen.h"
+#include "../sex/sex_screen.h"
+
+/*
+ * svi_screen_init --
+ * Initialize a screen.
+ */
+int
+svi_screen_init(sp)
+ SCR *sp;
+{
+ /* Initialize support routines. */
+ sp->s_bell = svi_bell;
+ sp->s_bg = svi_bg;
+ sp->s_busy = svi_busy;
+ sp->s_change = svi_change;
+ 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_edit = svi_screen_edit;
+ sp->s_end = svi_screen_end;
+ sp->s_ex_cmd = svi_ex_cmd;
+ sp->s_ex_run = svi_ex_run;
+ sp->s_ex_write = svi_ex_write;
+ sp->s_fg = svi_fg;
+ sp->s_fill = svi_sm_fill;
+ sp->s_get = svi_get;
+ sp->s_key_read = sex_key_read;
+ sp->s_optchange = svi_optchange;
+ sp->s_fmap = svi_fmap;
+ sp->s_position = svi_sm_position;
+ sp->s_rabs = svi_rabs;
+ sp->s_rcm = svi_rcm;
+ sp->s_refresh = svi_refresh;
+ sp->s_scroll = svi_sm_scroll;
+ sp->s_split = svi_split;
+ sp->s_suspend = svi_suspend;
+ sp->s_window = sex_window;
+
+ return (0);
+}
+
+/*
+ * svi_screen_copy --
+ * Copy to a new screen.
+ */
+int
+svi_screen_copy(orig, sp)
+ SCR *orig, *sp;
+{
+ SVI_PRIVATE *osvi, *nsvi;
+
+ /* Create the private screen structure. */
+ CALLOC_RET(orig, nsvi, SVI_PRIVATE *, 1, sizeof(SVI_PRIVATE));
+ sp->svi_private = nsvi;
+
+/* INITIALIZED AT SCREEN CREATE. */
+ /* Invalidate the line size cache. */
+ SVI_SCR_CFLUSH(nsvi);
+
+/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
+ if (orig == NULL) {
+ } else {
+ osvi = SVP(orig);
+ nsvi->srows = osvi->srows;
+ if (osvi->VB != NULL && (nsvi->VB = strdup(osvi->VB)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ F_SET(nsvi, F_ISSET(osvi, SVI_CURSES_INIT));
+ }
+ return (0);
+}
+
+/*
+ * svi_screen_end --
+ * End a screen.
+ */
+int
+svi_screen_end(sp)
+ SCR *sp;
+{
+ SVI_PRIVATE *svp;
+
+ svp = SVP(sp);
+
+ /* Free the screen map. */
+ if (HMAP != NULL)
+ FREE(HMAP, SIZE_HMAP(sp) * sizeof(SMAP));
+
+ /* Free the visual bell string. */
+ if (svp->VB != NULL)
+ free(svp->VB);
+
+ /* Free private memory. */
+ FREE(svp, sizeof(SVI_PRIVATE));
+ sp->svi_private = NULL;
+
+ return (0);
+}
+
+/*
+ * We use a single curses "window" for each vi screen. The model would be
+ * simpler with two windows (one for the text, and one for the modeline)
+ * because scrolling the text window down would work correctly then, not
+ * affecting the mode line. As it is we have to play games to make it look
+ * right. The reason for this choice is that it would be difficult for
+ * curses to optimize the movement, i.e. detect that the downward scroll
+ * isn't going to change the modeline, set the scrolling region on the
+ * terminal and only scroll the first part of the text window. (Even if
+ * curses did detect it, the set-scrolling-region terminal commands can't
+ * be used by curses because it's indeterminate where the cursor ends up
+ * after they are sent.)
+ */
+/*
+ * svi_screen_edit --
+ * Main vi curses screen loop.
+ */
+int
+svi_screen_edit(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SCR *tsp;
+ int ecurses, escreen, force, rval;
+
+ escreen = ecurses = rval = 0;
+
+ /* Initialize curses. */
+ if (svi_curses_init(sp)) {
+ escreen = 1;
+ goto err;
+ }
+ ecurses = 1;
+
+ /*
+ * The resize bit is probably set, as a result of the terminal being
+ * set. We clear it as we just finished initializing the screen.
+ * However, we will want to fill in the map from scratch, so provide
+ * a line number just in case, and set the reformat flag.
+ */
+ HMAP->lno = 1;
+ F_CLR(sp, S_RESIZE);
+ F_SET(sp, S_REFORMAT);
+
+ /*
+ * The historic 4BSD curses had an uneasy relationship with termcap.
+ * Termcap used a static buffer to hold the terminal information,
+ * which was was then used by the curses functions. We want to use
+ * it too, for lots of random things, but we've put it off until after
+ * svi_curses_init:initscr() was called. Do it now.
+ */
+ if (svi_term_init(sp))
+ goto err;
+
+ for (;;) {
+ /* Reset the cursor. */
+ F_SET(SVP(sp), SVI_CUR_INVALID);
+
+ /*
+ * Run vi. If vi fails, svi data structures may be
+ * corrupted, be extremely careful what you free up.
+ */
+ if (vi(sp, sp->ep)) {
+ (void)rcv_sync(sp, sp->ep,
+ RCV_EMAIL | RCV_ENDSESSION | RCV_PRESERVE);
+ escreen = 1;
+ goto err;
+ }
+
+ force = 0;
+ switch (F_ISSET(sp, S_MAJOR_CHANGE)) {
+ case S_EXIT_FORCE:
+ force = 1;
+ /* FALLTHROUGH */
+ case S_EXIT:
+ F_CLR(sp, S_EXIT_FORCE | S_EXIT);
+ if (file_end(sp, sp->ep, force))/* File end. */
+ break;
+ /*
+ * !!!
+ * NB: sp->frp may now be NULL, if it was a tmp file.
+ */
+ (void)svi_join(sp, &tsp); /* Find a new screen. */
+ if (tsp == NULL)
+ (void)svi_swap(sp, &tsp, NULL);
+ if (tsp == NULL) {
+ escreen = 1;
+ goto ret;
+ }
+ (void)screen_end(sp); /* Screen end. */
+ sp = tsp;
+ break;
+ case 0: /* Exit vi mode. */
+ svi_dtoh(sp, "Exit from vi");
+ goto ret;
+ case S_FSWITCH: /* File switch. */
+ F_CLR(sp, S_FSWITCH);
+ F_SET(sp, S_REFORMAT);
+ break;
+ case S_SSWITCH: /* Screen switch. */
+ F_CLR(sp, S_SSWITCH);
+ sp = sp->nextdisp;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if (0) {
+err: rval = 1;
+ }
+
+ret: if (svi_term_end(sp)) /* Terminal end (uses sp). */
+ rval = 1;
+ if (ecurses && svi_curses_end(sp)) /* Curses end (uses sp). */
+ rval = 1;
+ if (escreen && screen_end(sp)) /* Screen end. */
+ rval = 1;
+ return (rval);
+}
+
+/*
+ * svi_crel --
+ * Change the relative size of the current screen.
+ */
+int
+svi_crel(sp, count)
+ SCR *sp;
+ long count;
+{
+ /* Can't grow beyond the size of the window. */
+ if (count > O_VAL(sp, O_WINDOW))
+ count = O_VAL(sp, O_WINDOW);
+
+ sp->t_minrows = sp->t_rows = count;
+ if (sp->t_rows > sp->rows - 1)
+ sp->t_minrows = sp->t_rows = sp->rows - 1;
+ TMAP = HMAP + (sp->t_rows - 1);
+ F_SET(sp, S_REDRAW);
+ return (0);
+}
+
+/*
+ * svi_dtoh --
+ * Move all but the current screen to the hidden queue.
+ */
+void
+svi_dtoh(sp, emsg)
+ SCR *sp;
+ char *emsg;
+{
+ SCR *tsp;
+ int hidden;
+
+ for (hidden = 0;
+ (tsp = sp->gp->dq.cqh_first) != (void *)&sp->gp->dq; ++hidden) {
+ 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);
+ }
+ CIRCLEQ_REMOVE(&sp->gp->hq, sp, q);
+ CIRCLEQ_INSERT_TAIL(&sp->gp->dq, sp, q);
+ if (hidden > 1)
+ msgq(sp, M_INFO,
+ "%s backgrounded %d screens; use :display to list the screens",
+ emsg, hidden - 1);
+}
diff --git a/usr.bin/vi/svi/svi_screen.h b/usr.bin/vi/svi/svi_screen.h
new file mode 100644
index 000000000000..3b4643dc10d1
--- /dev/null
+++ b/usr.bin/vi/svi/svi_screen.h
@@ -0,0 +1,262 @@
+/*-
+ * 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.
+ *
+ * @(#)svi_screen.h 8.52 (Berkeley) 7/20/94
+ */
+
+/*
+ * Structure for mapping lines to the screen. An SMAP is an array, with one
+ * structure element per screen line, which holds information describing the
+ * physical line which is displayed in the screen line. The first two fields
+ * (lno and off) are all that are necessary to describe a line. The rest of
+ * the information is useful to keep information from being re-calculated.
+ *
+ * Lno is the line number. Off is the screen offset into the line. For
+ * example, the pair 2:1 would be the first screen of line 2, and 2:2 would
+ * be the second. If doing left-right scrolling, all of the offsets will be
+ * the same, i.e. for the second screen, 1:2, 2:2, 3:2, etc. If doing the
+ * standard vi scrolling, it will be staggered, i.e. 1:1, 1:2, 1:3, 2:1, 3:1,
+ * etc.
+ *
+ * The SMAP is always as large as the physical screen, plus a slot for the
+ * info line, so that there is room to add any screen into another one at
+ * screen exit.
+ */
+typedef struct _smap {
+ recno_t lno; /* 1-N: Physical file line number. */
+ size_t off; /* 1-N: Screen offset in the line. */
+
+ /* svi_line() cache information. */
+ size_t c_sboff; /* 0-N: offset of first character byte. */
+ size_t c_eboff; /* 0-N: offset of last character byte. */
+ u_char c_scoff; /* 0-N: offset into the first character. */
+ u_char c_eclen; /* 1-N: columns from the last character. */
+ u_char c_ecsize; /* 1-N: size of the last character. */
+} SMAP;
+
+ /* Macros to flush/test cached information. */
+#define SMAP_CACHE(smp) ((smp)->c_ecsize != 0)
+#define SMAP_FLUSH(smp) ((smp)->c_ecsize = 0)
+
+typedef struct _svi_private {
+/* INITIALIZED AT SCREEN CREATE. */
+ SMAP *h_smap; /* First slot of the line map. */
+ SMAP *t_smap; /* Last slot of the line map. */
+
+ size_t exlinecount; /* Ex overwrite count. */
+ size_t extotalcount; /* Ex overwrite count. */
+ size_t exlcontinue; /* Ex line continue value. */
+
+ /* 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. */
+
+ recno_t olno; /* 1-N: old cursor file line. */
+ size_t ocno; /* 0-N: old file cursor column. */
+ size_t sc_col; /* 0-N: LOGICAL screen column. */
+
+/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
+ size_t srows; /* 1-N: Rows in the terminal/window. */
+
+ char *VB; /* Visual bell termcap string. */
+
+#define SVI_CURSES_INIT 0x001 /* Curses/termcap initialized. */
+#define SVI_CUR_INVALID 0x002 /* Cursor position is unknown. */
+#define SVI_DIVIDER 0x004 /* Screen divider is displayed. */
+#define SVI_INFOLINE 0x008 /* The infoline is being used by v_ntext(). */
+#define SVI_SCREENDIRTY 0x010 /* Screen needs refreshing. */
+ u_int8_t flags;
+} SVI_PRIVATE;
+
+#define SVP(sp) ((SVI_PRIVATE *)((sp)->svi_private))
+#define HMAP (SVP(sp)->h_smap)
+#define TMAP (SVP(sp)->t_smap)
+#define _HMAP(sp) (SVP(sp)->h_smap)
+#define _TMAP(sp) (SVP(sp)->t_smap)
+
+/*
+ * One extra slot is always allocated for the map so that we can use
+ * it to do vi :colon command input; see svi_get().
+ */
+#define SIZE_HMAP(sp) (SVP(sp)->srows + 1)
+
+#define O_NUMBER_FMT "%7lu " /* O_NUMBER format, length. */
+#define O_NUMBER_LENGTH 8
+ /* Columns on a screen. */
+#define SCREEN_COLS(sp) \
+ ((O_ISSET(sp, O_NUMBER) ? (sp)->cols - O_NUMBER_LENGTH : (sp)->cols))
+
+#define HALFSCREEN(sp) ((sp)->t_maxrows / 2) /* Half the screen. */
+#define HALFTEXT(sp) ((sp)->t_rows / 2) /* Half the text. */
+
+#define INFOLINE(sp) ((sp)->t_maxrows) /* Info line test, offset. */
+#define ISINFOLINE(sp, smp) (((smp) - HMAP) == INFOLINE(sp))
+
+ /* Small screen test. */
+#define ISSMALLSCREEN(sp) ((sp)->t_minrows != (sp)->t_maxrows)
+
+/*
+ * 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))
+
+/* Move in a screen (absolute), and fail if it doesn't work. */
+#ifdef DEBUG
+#define MOVEA(sp, lno, cno) { \
+ if (move(lno, cno) == ERR) { \
+ msgq(sp, M_ERR, \
+ "Error: %s/%d: move:l(%u), c(%u), abs", \
+ tail(__FILE__), __LINE__, lno, cno); \
+ return (1); \
+ } \
+}
+#else
+#define MOVEA(sp, lno, cno) (void)move(lno, cno)
+#endif
+
+/* Move in a window, and fail if it doesn't work. */
+#ifdef DEBUG
+#define MOVE(sp, lno, cno) { \
+ size_t __lno = (sp)->woff + (lno); \
+ if (move(__lno, cno) == ERR) { \
+ msgq(sp, M_ERR, \
+ "Error: %s/%d: move:l(%u), c(%u), o(%u)", \
+ tail(__FILE__), __LINE__, lno, cno, sp->woff); \
+ return (1); \
+ } \
+}
+#else
+#define MOVE(sp, lno, cno) (void)move((sp)->woff + (lno), cno)
+#endif
+
+/* Add a character. */
+#define ADDCH(ch) { \
+ CHAR_T __ch = ch; \
+ ADDNSTR(KEY_NAME(sp, __ch), KEY_LEN(sp, __ch)); \
+}
+
+/* Add a string len bytes long. */
+#ifdef DEBUG
+#define ADDNSTR(str, len) { \
+ if (addnstr(str, len) == ERR) { \
+ int __x, __y; \
+ getyx(stdscr, __y, __x); \
+ msgq(sp, M_ERR, "Error: %s/%d: addnstr: (%d/%u)", \
+ tail(__FILE__), __LINE__, __y, __x); \
+ return (1); \
+ } \
+}
+#else
+#define ADDNSTR(str, len) (void)addnstr(str, len)
+#endif
+
+/* Add a string. */
+#ifdef DEBUG
+#define ADDSTR(str) { \
+ if (addstr(str) == ERR) { \
+ int __x, __y; \
+ getyx(stdscr, __y, __x); \
+ msgq(sp, M_ERR, "Error: %s/%d: addstr: (%d/%u)", \
+ tail(__FILE__), __LINE__, __y, __x); \
+ return (1); \
+ } \
+}
+#else
+#define ADDSTR(str) (void)addstr(str);
+#endif
+
+/* Public routines. */
+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_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));
+int svi_fg __P((SCR *, CHAR_T *));
+int svi_fmap __P((SCR *, enum seqtype, CHAR_T *, size_t, CHAR_T *, size_t));
+enum input
+ svi_get __P((SCR *, EXF *, TEXTH *, ARG_CHAR_T, u_int));
+int svi_optchange __P((SCR *, int));
+int svi_rabs __P((SCR *, long, enum adjust));
+size_t svi_rcm __P((SCR *, EXF *, recno_t));
+int svi_refresh __P((SCR *, EXF *));
+int svi_screen_copy __P((SCR *, SCR *));
+int svi_screen_edit __P((SCR *, EXF *));
+int svi_screen_end __P((SCR *));
+int svi_sm_fill __P((SCR *, EXF *, recno_t, enum position));
+int svi_sm_position __P((SCR *, EXF *, MARK *, u_long, enum position));
+int svi_sm_scroll __P((SCR *, EXF *, MARK *, recno_t, enum sctype));
+int svi_split __P((SCR *, ARGS *[], int));
+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 *));
+void svi_dtoh __P((SCR *, char *));
+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 *));
+int svi_msgflush __P((SCR *));
+int svi_number __P((SCR *, EXF *));
+size_t svi_opt_screens __P((SCR *, EXF *, recno_t, size_t *));
+int svi_paint __P((SCR *, EXF *));
+int svi_sm_1down __P((SCR *, EXF *));
+int svi_sm_1up __P((SCR *, EXF *));
+int svi_sm_cursor __P((SCR *, EXF *, SMAP **));
+int svi_sm_next __P((SCR *, EXF *, SMAP *, SMAP *));
+recno_t svi_sm_nlines __P((SCR *, EXF *, SMAP *, recno_t, size_t));
+int svi_sm_prev __P((SCR *, EXF *, SMAP *, SMAP *));
+int svi_term_end __P((SCR *sp));
+int svi_term_init __P((SCR *sp));
+
+/* Private debugging routines. */
+#ifdef DEBUG
+int svi_gdbrefresh __P((void));
+#endif
diff --git a/usr.bin/vi/svi/svi_smap.c b/usr.bin/vi/svi/svi_smap.c
new file mode 100644
index 000000000000..6d06d8ecd784
--- /dev/null
+++ b/usr.bin/vi/svi/svi_smap.c
@@ -0,0 +1,1216 @@
+/*-
+ * 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[] = "@(#)svi_smap.c 8.46 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "../vi/vcmd.h"
+#include "svi_screen.h"
+
+static int svi_deleteln __P((SCR *, int));
+static int svi_insertln __P((SCR *, int));
+static int svi_sm_delete __P((SCR *, EXF *, recno_t));
+static int svi_sm_down __P((SCR *, EXF *,
+ MARK *, recno_t, enum sctype, SMAP *));
+static int svi_sm_erase __P((SCR *));
+static int svi_sm_insert __P((SCR *, EXF *, recno_t));
+static int svi_sm_reset __P((SCR *, EXF *, recno_t));
+static int svi_sm_up __P((SCR *, EXF *,
+ MARK *, recno_t, enum sctype, SMAP *));
+
+/*
+ * svi_change --
+ * Make a change to the screen.
+ */
+int
+svi_change(sp, ep, lno, op)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ enum operation op;
+{
+ SMAP *p;
+ size_t oldy, oldx;
+
+ /* Appending is the same as inserting, if the line is incremented. */
+ if (op == LINE_APPEND) {
+ ++lno;
+ op = LINE_INSERT;
+ }
+
+ /* Ignore the change if the line is after the map. */
+ if (lno > TMAP->lno)
+ return (0);
+
+ /*
+ * If the line is before the map, and it's a decrement, decrement
+ * the map. If it's an increment, increment the map. Otherwise,
+ * ignore it.
+ */
+ if (lno < HMAP->lno) {
+ switch (op) {
+ case LINE_APPEND:
+ abort();
+ /* NOTREACHED */
+ case LINE_DELETE:
+ for (p = HMAP; p <= TMAP; ++p)
+ --p->lno;
+ if (sp->lno >= lno)
+ --sp->lno;
+ F_SET(sp, S_RENUMBER);
+ break;
+ case LINE_INSERT:
+ for (p = HMAP; p <= TMAP; ++p)
+ ++p->lno;
+ if (sp->lno >= lno)
+ ++sp->lno;
+ F_SET(sp, S_RENUMBER);
+ break;
+ case LINE_RESET:
+ break;
+ }
+ return (0);
+ }
+
+ F_SET(SVP(sp), SVI_SCREENDIRTY);
+
+ /* 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) {
+ case LINE_DELETE:
+ if (svi_sm_delete(sp, ep, lno))
+ return (1);
+ F_SET(sp, S_RENUMBER);
+ break;
+ case LINE_INSERT:
+ if (svi_sm_insert(sp, ep, lno))
+ return (1);
+ F_SET(sp, S_RENUMBER);
+ break;
+ case LINE_RESET:
+ if (svi_sm_reset(sp, ep, lno))
+ return (1);
+ break;
+ default:
+ abort();
+ }
+
+ MOVEA(sp, oldy, oldx);
+
+ return (0);
+}
+
+/*
+ * svi_sm_fill --
+ * Fill in the screen map, placing the specified line at the
+ * right position. There isn't any way to tell if an SMAP
+ * entry has been filled in, so this routine had better be
+ * called with P_FILL set before anything else is done.
+ *
+ * !!!
+ * Unexported interface: if lno is OOBLNO, P_TOP means that the HMAP
+ * slot is already filled in, P_BOTTOM means that the TMAP slot is
+ * already filled in, and we just finish up the job.
+ */
+int
+svi_sm_fill(sp, ep, lno, pos)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ enum position pos;
+{
+ SMAP *p, tmp;
+
+ /* Flush all cached information from the SMAP. */
+ for (p = HMAP; p <= TMAP; ++p)
+ SMAP_FLUSH(p);
+
+ /* If the map is filled, the screen must be redrawn. */
+ F_SET(sp, S_REDRAW);
+
+ switch (pos) {
+ case P_FILL:
+ tmp.lno = 1;
+ tmp.off = 1;
+
+ /* See if less than half a screen from the top. */
+ if (svi_sm_nlines(sp, ep,
+ &tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) {
+ lno = 1;
+ goto top;
+ }
+
+ /* See if less than half a screen from the bottom. */
+ if (file_lline(sp, ep, &tmp.lno))
+ return (1);
+ if (!O_ISSET(sp, O_LEFTRIGHT))
+ 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;
+ if (!O_ISSET(sp, O_LEFTRIGHT))
+ TMAP->off = tmp.off;
+ goto bottom;
+ }
+ goto middle;
+ case P_TOP:
+ if (lno != OOBLNO) {
+top: HMAP->lno = lno;
+ HMAP->off = 1;
+ }
+ /* If we fail, just punt. */
+ for (p = HMAP; p < TMAP; ++p)
+ if (svi_sm_next(sp, ep, p, p + 1))
+ goto err;
+ break;
+ case P_MIDDLE:
+ /* If we fail, guess that the file is too small. */
+middle: p = HMAP + (TMAP - HMAP) / 2;
+ for (p->lno = lno, p->off = 1; p > HMAP; --p)
+ if (svi_sm_prev(sp, ep, p, p - 1)) {
+ lno = 1;
+ goto top;
+ }
+
+ /* If we fail, just punt. */
+ p = HMAP + (TMAP - HMAP) / 2;
+ for (; p < TMAP; ++p)
+ if (svi_sm_next(sp, ep, p, p + 1))
+ goto err;
+ break;
+ case P_BOTTOM:
+ if (lno != OOBLNO) {
+ TMAP->lno = lno;
+ if (!O_ISSET(sp, O_LEFTRIGHT))
+ 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)
+ if (svi_sm_prev(sp, ep, p, p - 1)) {
+ lno = 1;
+ goto top;
+ }
+ break;
+ default:
+ abort();
+ }
+ return (0);
+
+ /*
+ * Try and put *something* on the screen. If this fails,
+ * we have a serious hard error.
+ */
+err: HMAP->lno = 1;
+ HMAP->off = 1;
+ for (p = HMAP; p < TMAP; ++p)
+ if (svi_sm_next(sp, ep, p, p + 1))
+ return (1);
+ return (0);
+}
+
+/*
+ * For the routines svi_sm_reset, svi_sm_delete and svi_sm_insert: if the
+ * screen only contains one line, or, if the line is the entire screen, this
+ * gets fairly exciting. Skip the fun and simply return if there's only one
+ * line in the screen, or just call fill. Fill may not be entirely accurate,
+ * i.e. we may be painting the screen with something not even close to the
+ * cursor, but it's not like we're into serious performance issues here, and
+ * the refresh routine will fix it for us.
+ */
+#define TOO_WEIRD { \
+ if (cnt_orig >= sp->t_rows) { \
+ if (cnt_orig == 1) \
+ return (0); \
+ if (file_gline(sp, ep, lno, NULL) == NULL) \
+ if (file_lline(sp, ep, &lno)) \
+ return (1); \
+ F_SET(sp, S_REDRAW); \
+ return (svi_sm_fill(sp, ep, lno, P_TOP)); \
+ } \
+}
+
+/*
+ * svi_sm_delete --
+ * Delete a line out of the SMAP.
+ */
+static int
+svi_sm_delete(sp, ep, lno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+{
+ SMAP *p, *t;
+ size_t cnt_orig;
+
+ /*
+ * 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);
+ 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;
+
+ /* Delete that many lines from the screen. */
+ 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));
+
+ /* Decrement the line numbers for the rest of the map. */
+ for (t = TMAP - cnt_orig; p <= t; ++p)
+ --p->lno;
+
+ /* Display the new lines. */
+ for (p = TMAP - cnt_orig;;) {
+ if (p < TMAP && svi_sm_next(sp, ep, p, p + 1))
+ return (1);
+ /* svi_sm_next() flushed the cache. */
+ if (svi_line(sp, ep, ++p, NULL, NULL))
+ return (1);
+ if (p == TMAP)
+ break;
+ }
+ return (0);
+}
+
+/*
+ * svi_sm_insert --
+ * Insert a line into the SMAP.
+ */
+static int
+svi_sm_insert(sp, ep, lno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+{
+ SMAP *p, *t;
+ size_t cnt_orig, cnt;
+
+ /*
+ * Find the line in the map, find out how many screen lines
+ * needed to display the line.
+ */
+ 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;
+
+ /*
+ * The lines left in the screen override the number of screen
+ * lines in the inserted line.
+ */
+ cnt = (TMAP - p) + 1;
+ if (cnt_orig > cnt)
+ cnt_orig = cnt;
+
+ /* Push down that many lines. */
+ MOVE(sp, p - HMAP, 0);
+ if (svi_insertln(sp, cnt_orig))
+ return (1);
+
+ /* Shift the screen map down. */
+ memmove(p + cnt_orig, p, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP));
+
+ /* Increment the line numbers for the rest of the map. */
+ for (t = p + cnt_orig; t <= TMAP; ++t)
+ ++t->lno;
+
+ /* Fill in the SMAP for the new lines, and display. */
+ for (cnt = 1, t = p; cnt <= cnt_orig; ++t, ++cnt) {
+ t->lno = lno;
+ t->off = cnt;
+ SMAP_FLUSH(t);
+ if (svi_line(sp, ep, t, NULL, NULL))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * svi_sm_reset --
+ * Reset a line in the SMAP.
+ */
+static int
+svi_sm_reset(sp, ep, lno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+{
+ SMAP *p, *t;
+ size_t cnt_orig, cnt_new, cnt, diff;
+
+ /*
+ * See if the number of on-screen rows taken up by the old display
+ * 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);
+ 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;
+
+ if (cnt_orig == cnt_new) {
+ do {
+ SMAP_FLUSH(p);
+ if (svi_line(sp, ep, p, NULL, NULL))
+ return (1);
+ } while (++p < t);
+ return (0);
+ }
+
+ if (cnt_orig < cnt_new) {
+ /* Get the difference. */
+ diff = cnt_new - cnt_orig;
+
+ /*
+ * The lines left in the screen override the number of screen
+ * lines in the inserted line.
+ */
+ cnt = (TMAP - p) + 1;
+ if (diff > cnt)
+ diff = cnt;
+
+ /* Push down the extra lines. */
+ MOVE(sp, p - HMAP, 0);
+ if (svi_insertln(sp, diff))
+ return (1);
+
+ /* Shift the screen map down. */
+ memmove(p + diff, p, (((TMAP - p) - diff) + 1) * sizeof(SMAP));
+
+ /* Fill in the SMAP for the replaced line, and display. */
+ for (cnt = 1, t = p; cnt_new-- && t <= TMAP; ++t, ++cnt) {
+ t->lno = lno;
+ t->off = cnt;
+ SMAP_FLUSH(t);
+ if (svi_line(sp, ep, t, NULL, NULL))
+ return (1);
+ }
+ } else {
+ /* Get the difference. */
+ diff = cnt_orig - cnt_new;
+
+ /* Delete that many lines from the screen. */
+ 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));
+
+ /* Fill in the SMAP for the replaced line, and display. */
+ for (cnt = 1, t = p; cnt_new--; ++t, ++cnt) {
+ t->lno = lno;
+ t->off = cnt;
+ SMAP_FLUSH(t);
+ if (svi_line(sp, ep, t, NULL, NULL))
+ return (1);
+ }
+
+ /* Display the new lines at the bottom of the screen. */
+ for (t = TMAP - diff;;) {
+ if (t < TMAP && svi_sm_next(sp, ep, t, t + 1))
+ return (1);
+ /* svi_sm_next() flushed the cache. */
+ if (svi_line(sp, ep, ++t, NULL, NULL))
+ return (1);
+ if (t == TMAP)
+ break;
+ }
+ }
+ return (0);
+}
+
+/*
+ * svi_sm_scroll
+ * Scroll the SMAP up/down count logical lines. Different
+ * semantics based on the vi command, *sigh*.
+ */
+int
+svi_sm_scroll(sp, ep, rp, count, scmd)
+ SCR *sp;
+ EXF *ep;
+ MARK *rp;
+ recno_t count;
+ enum sctype scmd;
+{
+ SMAP *smp;
+
+ /*
+ * Invalidate the cursor. The line is probably going to change,
+ * (although for ^E and ^Y it may not). In any case, the scroll
+ * routines move the cursor to draw things.
+ */
+ F_SET(SVP(sp), SVI_CUR_INVALID);
+
+ /* Find the cursor in the screen. */
+ if (svi_sm_cursor(sp, ep, &smp))
+ return (1);
+
+ switch (scmd) {
+ case CNTRL_B:
+ case CNTRL_U:
+ case CNTRL_Y:
+ case Z_CARAT:
+ if (svi_sm_down(sp, ep, rp, count, scmd, smp))
+ return (1);
+ break;
+ case CNTRL_D:
+ case CNTRL_E:
+ case CNTRL_F:
+ case Z_PLUS:
+ if (svi_sm_up(sp, ep, rp, count, scmd, smp))
+ return (1);
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * !!!
+ * If we're at the start of a line, go for the first non-blank.
+ * This makes it look like the old vi, even though we're moving
+ * around by logical lines, not physical ones.
+ *
+ * XXX
+ * In the presence of a long line, which has more than a screen
+ * width of leading spaces, this code can cause a cursor warp.
+ * Live with it.
+ */
+ if (scmd != CNTRL_E && scmd != CNTRL_Y &&
+ rp->cno == 0 && nonblank(sp, ep, rp->lno, &rp->cno))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * svi_sm_up --
+ * Scroll the SMAP up count logical lines.
+ */
+static int
+svi_sm_up(sp, ep, rp, count, scmd, smp)
+ SCR *sp;
+ EXF *ep;
+ MARK *rp;
+ enum sctype scmd;
+ recno_t count;
+ SMAP *smp;
+{
+ int cursor_set, echanged, zset;
+ SMAP s1, s2;
+
+ /*
+ * Check to see if movement is possible.
+ *
+ * Get the line after the map. If that line is a new one (and if
+ * O_LEFTRIGHT option is set, this has to be true), and the next
+ * line doesn't exist, and the cursor doesn't move, or the cursor
+ * isn't even on the screen, or the cursor is already at the last
+ * line in the map, it's an error. If that test succeeded because
+ * the cursor wasn't at the end of the map, test to see if the map
+ * is mostly empty.
+ */
+ if (svi_sm_next(sp, ep, TMAP, &s1))
+ return (1);
+ if (s1.lno > TMAP->lno && !file_gline(sp, ep, s1.lno, NULL)) {
+ if (scmd == CNTRL_E || scmd == Z_PLUS || smp == TMAP) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
+ if (svi_sm_next(sp, ep, smp, &s1))
+ return (1);
+ if (s1.lno > smp->lno && !file_gline(sp, ep, s1.lno, NULL)) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
+ }
+
+ /*
+ * Small screens: see svi/svi_refresh.c:svi_refresh, section 2b.
+ *
+ * If it's a small screen, and the movement isn't larger than a
+ * screen, i.e some context will remain, open up the screen and
+ * display by scrolling. In this case, the cursor moves to the
+ * first line displayed. Otherwise, erase/compress and repaint,
+ * and move the cursor to the first line in the screen. Note,
+ * the ^F command is always in the latter case, for historical
+ * reasons.
+ */
+ cursor_set = 0;
+ if (ISSMALLSCREEN(sp)) {
+ if (count >= sp->t_maxrows || scmd == CNTRL_F) {
+ s1 = TMAP[0];
+ if (svi_sm_erase(sp))
+ return (1);
+ for (; count--; s1 = s2) {
+ if (svi_sm_next(sp, ep, &s1, &s2))
+ return (1);
+ if (s2.lno != s1.lno &&
+ !file_gline(sp, ep, s2.lno, NULL))
+ break;
+ }
+ TMAP[0] = s2;
+ if (svi_sm_fill(sp, ep, OOBLNO, P_BOTTOM))
+ return (1);
+ return (svi_sm_position(sp, ep, rp, 0, P_TOP));
+ }
+ for (; count &&
+ sp->t_rows != sp->t_maxrows; --count, ++sp->t_rows) {
+ if (svi_sm_next(sp, ep, TMAP, &s1))
+ return (1);
+ if (TMAP->lno != s1.lno &&
+ !file_gline(sp, ep, s1.lno, NULL))
+ break;
+ *++TMAP = s1;
+ /* svi_sm_next() flushed the cache. */
+ if (svi_line(sp, ep, TMAP, NULL, NULL))
+ return (1);
+
+ if (scmd != CNTRL_E && !cursor_set) {
+ cursor_set = 1;
+ rp->lno = TMAP->lno;
+ rp->cno = TMAP->c_sboff;
+ }
+ }
+ if (count == 0)
+ return (0);
+ }
+
+ for (echanged = zset = 0; count; --count) {
+ /* Decide what would show up on the screen. */
+ if (svi_sm_next(sp, ep, TMAP, &s1))
+ return (1);
+
+ /* If the line doesn't exist, we're done. */
+ if (TMAP->lno != s1.lno && !file_gline(sp, ep, s1.lno, NULL))
+ break;
+
+ /* Scroll the screen cursor up one logical line. */
+ if (svi_sm_1up(sp, ep))
+ return (1);
+ switch (scmd) {
+ case CNTRL_E:
+ if (smp > HMAP)
+ --smp;
+ else
+ echanged = 1;
+ break;
+ case Z_PLUS:
+ if (zset) {
+ if (smp > HMAP)
+ --smp;
+ } else {
+ smp = TMAP;
+ zset = 1;
+ }
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ }
+
+ if (cursor_set)
+ return(0);
+
+ switch (scmd) {
+ case CNTRL_E:
+ /*
+ * On a ^E that was forced to change lines, try and keep the
+ * cursor as close as possible to the last position, but also
+ * set it up so that the next "real" movement will return the
+ * cursor to the closest position to the last real movement.
+ */
+ if (echanged) {
+ rp->lno = smp->lno;
+ rp->cno =
+ svi_cm_private(sp, ep, smp->lno, smp->off, sp->rcm);
+ }
+ return (0);
+ case CNTRL_F:
+ /*
+ * If there are more lines, the ^F command is always
+ * positioned at the first line of the screen.
+ */
+ if (!count) {
+ smp = HMAP;
+ break;
+ }
+ /* FALLTHROUGH */
+ case CNTRL_D:
+ /*
+ * The ^D and ^F commands move the cursor towards EOF
+ * if there are more lines to move. Check to be sure
+ * the lines actually exist. (They may not if the
+ * file is smaller than the screen.)
+ */
+ for (; count; --count, ++smp)
+ if (smp == TMAP ||
+ !file_gline(sp, ep, smp[1].lno, NULL))
+ break;
+ break;
+ case Z_PLUS:
+ /* The z+ command moves the cursor to the first new line. */
+ break;
+ default:
+ abort();
+ }
+
+ if (!SMAP_CACHE(smp) && svi_line(sp, ep, smp, NULL, NULL))
+ return (1);
+ rp->lno = smp->lno;
+ rp->cno = smp->c_sboff;
+ return (0);
+}
+
+/*
+ * svi_sm_1up --
+ * Scroll the SMAP up one.
+ */
+int
+svi_sm_1up(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ /*
+ * Delete the top line of the screen. Shift the screen map up.
+ * Display a new line at the bottom of the screen.
+ */
+ MOVE(sp, 0, 0);
+ if (svi_deleteln(sp, 1))
+ return (1);
+
+ /* One-line screens can fail. */
+ if (HMAP == TMAP) {
+ if (svi_sm_next(sp, ep, TMAP, TMAP))
+ return (1);
+ } else {
+ memmove(HMAP, HMAP + 1, (sp->rows - 1) * sizeof(SMAP));
+ if (svi_sm_next(sp, ep, TMAP - 1, TMAP))
+ return (1);
+ }
+ /* svi_sm_next() flushed the cache. */
+ if (svi_line(sp, ep, TMAP, NULL, NULL))
+ return (1);
+ return (0);
+}
+
+/*
+ * svi_deleteln --
+ * Delete a line a la curses, make sure to put the information
+ * line and other screens back.
+ */
+static int
+svi_deleteln(sp, cnt)
+ SCR *sp;
+ int cnt;
+{
+ size_t oldy, oldx;
+
+ getyx(stdscr, oldy, oldx);
+ while (cnt--) {
+ deleteln();
+ MOVE(sp, INFOLINE(sp) - 1, 0);
+ insertln();
+ MOVEA(sp, oldy, oldx);
+ }
+ return (0);
+}
+
+/*
+ * svi_sm_down --
+ * Scroll the SMAP down count logical lines.
+ */
+static int
+svi_sm_down(sp, ep, rp, count, scmd, smp)
+ SCR *sp;
+ EXF *ep;
+ MARK *rp;
+ recno_t count;
+ SMAP *smp;
+ enum sctype scmd;
+{
+ SMAP s1, s2;
+ int cursor_set, ychanged, zset;
+
+ /* Check to see if movement is possible. */
+ if (HMAP->lno == 1 && HMAP->off == 1 &&
+ (scmd == CNTRL_Y || scmd == Z_CARAT || smp == HMAP)) {
+ v_sof(sp, NULL);
+ return (1);
+ }
+
+ /*
+ * Small screens: see svi/svi_refresh.c:svi_refresh, section 2b.
+ *
+ * If it's a small screen, and the movement isn't larger than a
+ * screen, i.e some context will remain, open up the screen and
+ * display by scrolling. In this case, the cursor moves to the
+ * first line displayed. Otherwise, erase/compress and repaint,
+ * and move the cursor to the first line in the screen. Note,
+ * the ^B command is always in the latter case, for historical
+ * reasons.
+ */
+ cursor_set = scmd == CNTRL_Y;
+ if (ISSMALLSCREEN(sp)) {
+ if (count >= sp->t_maxrows || scmd == CNTRL_B) {
+ s1 = HMAP[0];
+ if (svi_sm_erase(sp))
+ return (1);
+ for (; count--; s1 = s2) {
+ if (svi_sm_prev(sp, ep, &s1, &s2))
+ return (1);
+ if (s2.lno == 1 && s2.off == 1)
+ break;
+ }
+ HMAP[0] = s2;
+ if (svi_sm_fill(sp, ep, OOBLNO, P_TOP))
+ return (1);
+ return (svi_sm_position(sp, ep, rp, 0, P_BOTTOM));
+ }
+ for (; count &&
+ sp->t_rows != sp->t_maxrows; --count, ++sp->t_rows) {
+ if (HMAP->lno == 1 || HMAP->off == 1)
+ break;
+ ++TMAP;
+ if (svi_sm_1down(sp, ep))
+ return (1);
+ if (scmd != CNTRL_Y && !cursor_set) {
+ cursor_set = 1;
+ if (svi_sm_position(sp, ep, rp, 0, P_BOTTOM))
+ return (1);
+ }
+ }
+ if (count == 0)
+ return (0);
+ }
+
+ for (ychanged = zset = 0; count; --count) {
+ /* 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);
+ switch (scmd) {
+ case CNTRL_Y:
+ if (smp < TMAP)
+ ++smp;
+ else
+ ychanged = 1;
+ break;
+ case Z_CARAT:
+ if (zset) {
+ if (smp < TMAP)
+ ++smp;
+ } else {
+ smp = HMAP;
+ zset = 1;
+ }
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ }
+
+ if (scmd != CNTRL_Y && cursor_set)
+ return(0);
+
+ switch (scmd) {
+ case CNTRL_B:
+ /*
+ * If there are more lines, the ^B command is always
+ * positioned at the last line of the screen.
+ */
+ if (!count) {
+ smp = TMAP;
+ break;
+ }
+ /* FALLTHROUGH */
+ case CNTRL_U:
+ /*
+ * The ^B and ^U commands move the cursor towards SOF
+ * if there are more lines to move.
+ */
+ if (count < smp - HMAP)
+ smp -= count;
+ else
+ smp = HMAP;
+ break;
+ case CNTRL_Y:
+ /*
+ * On a ^Y that was forced to change lines, try and keep the
+ * cursor as close as possible to the last position, but also
+ * set it up so that the next "real" movement will return the
+ * cursor to the closest position to the last real movement.
+ */
+ if (ychanged) {
+ rp->lno = smp->lno;
+ rp->cno =
+ svi_cm_private(sp, ep, smp->lno, smp->off, sp->rcm);
+ }
+ return (0);
+ case Z_CARAT:
+ /* The z^ command moves the cursor to the first new line. */
+ break;
+ default:
+ abort();
+ }
+
+ if (!SMAP_CACHE(smp) && svi_line(sp, ep, smp, NULL, NULL))
+ return (1);
+ rp->lno = smp->lno;
+ rp->cno = smp->c_sboff;
+ return (0);
+}
+
+/*
+ * svi_sm_erase --
+ * Erase the small screen area for the scrolling functions.
+ */
+static int
+svi_sm_erase(sp)
+ SCR *sp;
+{
+ MOVE(sp, INFOLINE(sp), 0);
+ clrtoeol();
+ for (; sp->t_rows > sp->t_minrows; --sp->t_rows, --TMAP) {
+ MOVE(sp, TMAP - HMAP, 0);
+ clrtoeol();
+ }
+ return (0);
+}
+
+/*
+ * svi_sm_1down --
+ * Scroll the SMAP down one.
+ */
+int
+svi_sm_1down(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ /*
+ * Clear the bottom line of the screen, insert a line at the top
+ * of the screen. Shift the screen map down, display a new line
+ * at the top of the screen.
+ */
+ MOVE(sp, sp->t_rows, 0);
+ clrtoeol();
+ MOVE(sp, 0, 0);
+ if (svi_insertln(sp, 1))
+ return (1);
+ memmove(HMAP + 1, HMAP, (sp->rows - 1) * sizeof(SMAP));
+ if (svi_sm_prev(sp, ep, HMAP + 1, HMAP))
+ return (1);
+ /* svi_sm_prev() flushed the cache. */
+ if (svi_line(sp, ep, HMAP, NULL, NULL))
+ return (1);
+ return (0);
+}
+
+/*
+ * svi_insertln --
+ * Insert a line a la curses, make sure to put the information
+ * line and other screens back.
+ */
+static int
+svi_insertln(sp, cnt)
+ SCR *sp;
+ int cnt;
+{
+ size_t oldy, oldx;
+
+ getyx(stdscr, oldy, oldx);
+ while (cnt--) {
+ MOVE(sp, INFOLINE(sp) - 1, 0);
+ deleteln();
+ MOVEA(sp, oldy, oldx);
+ insertln();
+ }
+ return (0);
+}
+
+/*
+ * svi_sm_next --
+ * Fill in the next entry in the SMAP.
+ */
+int
+svi_sm_next(sp, ep, p, t)
+ SCR *sp;
+ EXF *ep;
+ SMAP *p, *t;
+{
+ size_t lcnt;
+
+ SMAP_FLUSH(t);
+ if (O_ISSET(sp, O_LEFTRIGHT)) {
+ t->lno = p->lno + 1;
+ t->off = p->off;
+ } else {
+ lcnt = svi_opt_screens(sp, ep, p->lno, NULL);
+ if (lcnt == p->off) {
+ t->lno = p->lno + 1;
+ t->off = 1;
+ } else {
+ t->lno = p->lno;
+ t->off = p->off + 1;
+ }
+ }
+ return (0);
+}
+
+/*
+ * svi_sm_prev --
+ * Fill in the previous entry in the SMAP.
+ */
+int
+svi_sm_prev(sp, ep, p, t)
+ SCR *sp;
+ EXF *ep;
+ SMAP *p, *t;
+{
+ SMAP_FLUSH(t);
+ if (O_ISSET(sp, O_LEFTRIGHT)) {
+ t->lno = p->lno - 1;
+ t->off = p->off;
+ } else if (p->off != 1) {
+ t->lno = p->lno;
+ t->off = p->off - 1;
+ } else {
+ t->lno = p->lno - 1;
+ t->off = svi_opt_screens(sp, ep, t->lno, NULL);
+ }
+ return (t->lno == 0);
+}
+
+/*
+ * svi_sm_cursor --
+ * Return the SMAP entry referenced by the cursor.
+ */
+int
+svi_sm_cursor(sp, ep, smpp)
+ SCR *sp;
+ EXF *ep;
+ SMAP **smpp;
+{
+ SMAP *p;
+
+ /* See if the cursor is not in the map. */
+ if (sp->lno < HMAP->lno || sp->lno > TMAP->lno)
+ return (1);
+
+ /* Find the first occurence of the line. */
+ for (p = HMAP; p->lno != sp->lno; ++p);
+
+ /* Fill in the map information until we find the right line. */
+ for (; p <= TMAP; ++p) {
+ /* Short lines are common and easy to detect. */
+ if (p != TMAP && (p + 1)->lno != p->lno) {
+ *smpp = p;
+ return (0);
+ }
+ if (!SMAP_CACHE(p) && svi_line(sp, ep, p, NULL, NULL))
+ return (1);
+ if (p->c_eboff >= sp->cno) {
+ *smpp = p;
+ return (0);
+ }
+ }
+
+ /* It was past the end of the map after all. */
+ return (1);
+}
+
+/*
+ * svi_sm_position --
+ * Return the line/column of the top, middle or last line on the screen.
+ * (The vi H, M and L commands.) Here because only the screen routines
+ * know what's really out there.
+ */
+int
+svi_sm_position(sp, ep, rp, cnt, pos)
+ SCR *sp;
+ EXF *ep;
+ MARK *rp;
+ u_long cnt;
+ enum position 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 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:
+ /*
+ * !!!
+ * 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:
+ /*
+ * !!!
+ * 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;
+ 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;
+ rp->cno = smp->c_sboff;
+
+ return (0);
+}
+
+/*
+ * svi_sm_nlines --
+ * Return the number of screen lines from an SMAP entry to the
+ * start of some file line, less than a maximum value.
+ */
+recno_t
+svi_sm_nlines(sp, ep, from_sp, to_lno, max)
+ SCR *sp;
+ EXF *ep;
+ SMAP *from_sp;
+ recno_t to_lno;
+ size_t max;
+{
+ recno_t lno, lcnt;
+
+ if (O_ISSET(sp, O_LEFTRIGHT))
+ return (from_sp->lno > to_lno ?
+ from_sp->lno - to_lno : to_lno - from_sp->lno);
+
+ if (from_sp->lno == to_lno)
+ return (from_sp->off - 1);
+
+ 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_opt_screens(sp, ep, lno, NULL);
+ } else {
+ lno = from_sp->lno;
+ lcnt = (svi_opt_screens(sp, ep, lno, NULL) - from_sp->off) + 1;
+ for (; ++lno < to_lno && lcnt <= max;)
+ 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
new file mode 100644
index 000000000000..160f49556c42
--- /dev/null
+++ b/usr.bin/vi/svi/svi_split.c
@@ -0,0 +1,627 @@
+/*-
+ * 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[] = "@(#)svi_split.c 8.46 (Berkeley) 8/9/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "svi_screen.h"
+
+/*
+ * svi_split --
+ * Split the screen.
+ */
+int
+svi_split(sp, argv, argc)
+ SCR *sp;
+ ARGS *argv[];
+ int argc;
+{
+ MSG *mp, *next;
+ SCR *tsp, saved_sp;
+ SVI_PRIVATE saved_svp;
+ SMAP *smp;
+ size_t cnt, half;
+ int issmallscreen, splitup;
+ char **ap;
+
+ /* Check to see if it's possible. */
+ half = sp->rows / 2;
+ if (half < MINIMUM_SCREEN_ROWS) {
+ msgq(sp, M_ERR, "Screen must be larger than %d to split",
+ MINIMUM_SCREEN_ROWS);
+ return (1);
+ }
+
+ /* Get a new screen. */
+ if (screen_init(sp, &tsp, 0))
+ return (1);
+ CALLOC(sp, _HMAP(tsp), SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
+ if (_HMAP(tsp) == NULL)
+ return (1);
+
+ /*
+ * We're about to modify the current screen. Save the contents
+ * in case something goes horribly, senselessly wrong.
+ */
+ saved_sp = *sp;
+ saved_svp = *SVP(sp);
+
+/* INITIALIZED AT SCREEN CREATE. */
+
+/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
+ /*
+ * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
+ * Set a flag so we know to fix the screen up later.
+ */
+ issmallscreen = ISSMALLSCREEN(sp);
+
+ /*
+ * Split the screen, and link the screens together. If the cursor
+ * is in the top half of the current screen, the new screen goes
+ * under the current screen. Else, it goes above the current screen.
+ *
+ * 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. */
+ tsp->rows = sp->rows - half;
+ tsp->woff = sp->woff + half;
+ tsp->t_maxrows = tsp->rows - 1;
+
+ /* Parent. */
+ sp->rows = half;
+ sp->t_maxrows = sp->rows - 1;
+
+ splitup = 0;
+ } else { /* Parent is bottom half. */
+ /* Child. */
+ tsp->rows = sp->rows - half;
+ tsp->woff = sp->woff;
+ tsp->t_maxrows = tsp->rows - 1;
+
+ /* Parent. */
+ sp->rows = half;
+ sp->woff += tsp->rows;
+ sp->t_maxrows = sp->rows - 1;
+
+ /* Shift the parent's map down. */
+ memmove(_HMAP(sp),
+ _HMAP(sp) + tsp->rows, sp->t_maxrows * sizeof(SMAP));
+
+ splitup = 1;
+ }
+
+ /*
+ * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
+ *
+ * The child may have different screen options sizes than the
+ * parent, so use them. Make sure that the text counts aren't
+ * larger than the new screen sizes.
+ */
+ if (issmallscreen) {
+ /* Fix the text line count for the parent. */
+ if (splitup)
+ sp->t_rows -= tsp->rows;
+
+ /* Fix the parent screen. */
+ if (sp->t_rows > sp->t_maxrows)
+ sp->t_rows = sp->t_maxrows;
+ if (sp->t_minrows > sp->t_maxrows)
+ sp->t_minrows = sp->t_maxrows;
+
+ /* Fix the child screen. */
+ tsp->t_minrows = tsp->t_rows = O_VAL(sp, O_WINDOW);
+ if (tsp->t_rows > tsp->t_maxrows)
+ tsp->t_rows = tsp->t_maxrows;
+ if (tsp->t_minrows > tsp->t_maxrows)
+ tsp->t_minrows = tsp->t_maxrows;
+
+ /*
+ * If we split up, i.e. the child is on top, lines that
+ * were painted in the parent may not be painted in the
+ * child. Clear any lines not being used in the child
+ * screen.
+ *
+ */
+ if (splitup)
+ for (cnt = tsp->t_rows; ++cnt <= tsp->t_maxrows;) {
+ MOVE(tsp, cnt, 0);
+ clrtoeol();
+ }
+ } else {
+ sp->t_minrows = sp->t_rows = sp->rows - 1;
+
+ /*
+ * The new screen may be a small screen, even though the
+ * parent was not. Don't complain if O_WINDOW is too large,
+ * we're splitting the screen so the screen is much smaller
+ * than normal. Clear any lines not being used in the child
+ * screen.
+ */
+ tsp->t_minrows = tsp->t_rows = O_VAL(sp, O_WINDOW);
+ if (tsp->t_rows > tsp->rows - 1)
+ tsp->t_minrows = tsp->t_rows = tsp->rows - 1;
+ else
+ for (cnt = tsp->t_rows; ++cnt <= tsp->t_maxrows;) {
+ MOVE(tsp, cnt, 0);
+ clrtoeol();
+ }
+ }
+
+ /* Adjust the ends of both maps. */
+ _TMAP(sp) = _HMAP(sp) + (sp->t_rows - 1);
+ _TMAP(tsp) = _HMAP(tsp) + (tsp->t_rows - 1);
+
+ /* Reset the length of the default scroll. */
+ sp->defscroll = sp->t_maxrows / 2;
+ tsp->defscroll = tsp->t_maxrows / 2;
+
+ /*
+ * If files specified, build the file list, else, link to the
+ * current file.
+ */
+ if (argv == NULL) {
+ if ((tsp->frp = file_add(tsp, sp->frp->name)) == NULL)
+ goto err;
+ } else {
+ /* Create a new argument list. */
+ CALLOC(sp, tsp->argv, char **, argc + 1, sizeof(char *));
+ if (tsp->argv == NULL)
+ goto err;
+ for (ap = tsp->argv, argv; argv[0]->len != 0; ++ap, ++argv)
+ if ((*ap =
+ v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL)
+ goto err;
+ *ap = NULL;
+
+ /* Switch to the first one. */
+ tsp->cargv = tsp->argv;
+ if ((tsp->frp = file_add(tsp, *tsp->cargv)) == NULL)
+ goto err;
+ }
+
+ /*
+ * Copy the file state flags, start the file. Fill the child's
+ * screen map. If the file is unchanged, keep the screen and
+ * cursor the same.
+ */
+ if (argv == NULL) {
+ tsp->ep = sp->ep;
+ ++sp->ep->refcnt;
+
+ tsp->frp->flags = sp->frp->flags;
+ tsp->frp->lno = sp->lno;
+ tsp->frp->cno = sp->cno;
+ F_SET(tsp->frp, FR_CURSORSET);
+
+ /* Copy the parent's map into the child's map. */
+ memmove(_HMAP(tsp), _HMAP(sp), tsp->t_rows * sizeof(SMAP));
+ } else {
+ if (file_init(tsp, tsp->frp, NULL, 0))
+ goto err;
+ (void)svi_sm_fill(tsp, tsp->ep, 1, P_TOP);
+ }
+
+ /* Everything's initialized, put the screen on the displayed queue.*/
+ if (splitup) {
+ /* Link in before the parent. */
+ CIRCLEQ_INSERT_BEFORE(&sp->gp->dq, sp, tsp, q);
+ } else {
+ /* Link in after the parent. */
+ CIRCLEQ_INSERT_AFTER(&sp->gp->dq, sp, tsp, q);
+ }
+
+ /* Clear the current information lines in both screens. */
+ MOVE(sp, INFOLINE(sp), 0);
+ clrtoeol();
+ MOVE(tsp, INFOLINE(tsp), 0);
+ clrtoeol();
+
+ /* Redraw the status line for the parent screen. */
+ (void)msg_status(sp, sp->ep, sp->lno, 0);
+
+ /* Save the parent screen's cursor information. */
+ sp->frp->lno = sp->lno;
+ sp->frp->cno = sp->cno;
+ F_SET(sp->frp, FR_CURSORSET);
+
+ /* Completely redraw the child screen. */
+ F_SET(tsp, S_REDRAW);
+
+ /* Switch screens. */
+ sp->nextdisp = tsp;
+ F_SET(sp, S_SSWITCH);
+ return (0);
+
+ /* Recover the original screen. */
+err: *sp = saved_sp;
+ *SVP(sp) = saved_svp;
+
+ /* Copy any (probably error) messages in the new screen. */
+ for (mp = tsp->msgq.lh_first; mp != NULL; mp = next) {
+ if (!F_ISSET(mp, M_EMPTY))
+ msg_app(sp->gp, sp,
+ mp->flags & M_INV_VIDEO, mp->mbuf, mp->len);
+ next = mp->q.le_next;
+ if (mp->mbuf != NULL)
+ free(mp->mbuf);
+ free(mp);
+ }
+
+ /* Free the new screen. */
+ if (tsp->argv != NULL) {
+ for (ap = tsp->argv; *ap != NULL; ++ap)
+ free(*ap);
+ free(tsp->argv);
+ }
+ free(_HMAP(tsp));
+ free(SVP(tsp));
+ FREE(tsp, sizeof(SCR));
+ return (1);
+}
+
+/*
+ * svi_bg --
+ * Background the screen, and switch to the next one.
+ */
+int
+svi_bg(csp)
+ SCR *csp;
+{
+ SCR *sp;
+
+ /* Try and join with another screen. */
+ if ((svi_join(csp, &sp)))
+ return (1);
+ if (sp == NULL) {
+ msgq(csp, M_ERR,
+ "You may not background your only displayed screen");
+ return (1);
+ }
+
+ /* Move the old screen to the hidden queue. */
+ CIRCLEQ_REMOVE(&csp->gp->dq, csp, q);
+ CIRCLEQ_INSERT_TAIL(&csp->gp->hq, csp, q);
+
+ /* Switch screens. */
+ csp->nextdisp = sp;
+ F_SET(csp, S_SSWITCH);
+
+ return (0);
+}
+
+/*
+ * svi_join --
+ * Join the screen into a related screen, if one exists,
+ * and return that screen.
+ */
+int
+svi_join(csp, nsp)
+ SCR *csp, **nsp;
+{
+ SCR *sp;
+ size_t cnt;
+
+ /*
+ * If a split screen, add space to parent/child. Make no effort
+ * to clean up the screen's values. If it's not exiting, we'll
+ * get it when the user asks to show it again.
+ */
+ if ((sp = csp->q.cqe_prev) == (void *)&csp->gp->dq) {
+ if ((sp = csp->q.cqe_next) == (void *)&csp->gp->dq) {
+ *nsp = NULL;
+ return (0);
+ }
+ sp->woff = csp->woff;
+ }
+ sp->rows += csp->rows;
+ if (ISSMALLSCREEN(sp)) {
+ sp->t_maxrows += csp->rows;
+ for (cnt = sp->t_rows; ++cnt <= sp->t_maxrows;) {
+ MOVE(sp, cnt, 0);
+ clrtoeol();
+ }
+ TMAP = HMAP + (sp->t_rows - 1);
+ } else {
+ sp->t_maxrows += csp->rows;
+ sp->t_rows = sp->t_minrows = sp->t_maxrows;
+ TMAP = HMAP + (sp->t_rows - 1);
+ if (svi_sm_fill(sp, sp->ep, sp->lno, P_FILL))
+ return (1);
+ F_SET(sp, S_REDRAW);
+ }
+
+ /* Reset the length of the default scroll. */
+ sp->defscroll = sp->t_maxrows / 2;
+
+ /*
+ * Save the old screen's cursor information.
+ *
+ * XXX
+ * If called after file_end(), if the underlying file was a tmp
+ * file it may have gone away.
+ */
+ if (csp->frp != NULL) {
+ csp->frp->lno = csp->lno;
+ csp->frp->cno = csp->cno;
+ F_SET(csp->frp, FR_CURSORSET);
+ }
+
+ *nsp = sp;
+ return (0);
+}
+
+/*
+ * svi_fg --
+ * Background the current screen, and foreground a new one.
+ */
+int
+svi_fg(csp, name)
+ SCR *csp;
+ CHAR_T *name;
+{
+ SCR *sp;
+
+ if (svi_swap(csp, &sp, name))
+ return (1);
+ if (sp == NULL) {
+ if (name == NULL)
+ msgq(csp, M_ERR, "There are no background screens");
+ else
+ msgq(csp, M_ERR,
+ "There's no background screen editing a file named %s",
+ name);
+ return (1);
+ }
+
+ /* Move the old screen to the hidden queue. */
+ CIRCLEQ_REMOVE(&csp->gp->dq, csp, q);
+ CIRCLEQ_INSERT_TAIL(&csp->gp->hq, csp, q);
+
+ return (0);
+}
+
+/*
+ * svi_swap --
+ * Swap the current screen with a hidden one.
+ */
+int
+svi_swap(csp, nsp, name)
+ SCR *csp, **nsp;
+ char *name;
+{
+ SCR *sp;
+ int issmallscreen;
+
+ /* Find the screen, or, if name is NULL, the first screen. */
+ for (sp = csp->gp->hq.cqh_first;
+ sp != (void *)&csp->gp->hq; sp = sp->q.cqe_next)
+ if (name == NULL || !strcmp(sp->frp->name, name))
+ break;
+ if (sp == (void *)&csp->gp->hq) {
+ *nsp = NULL;
+ return (0);
+ }
+ *nsp = sp;
+
+ /*
+ * Save the old screen's cursor information.
+ *
+ * XXX
+ * If called after file_end(), if the underlying file was a tmp
+ * file it may have gone away.
+ */
+ if (csp->frp != NULL) {
+ csp->frp->lno = csp->lno;
+ csp->frp->cno = csp->cno;
+ F_SET(csp->frp, FR_CURSORSET);
+ }
+
+ /* Switch screens. */
+ csp->nextdisp = sp;
+ F_SET(csp, S_SSWITCH);
+
+ /* Initialize terminal information. */
+ SVP(sp)->srows = SVP(csp)->srows;
+
+ issmallscreen = ISSMALLSCREEN(sp);
+
+ /* Initialize screen information. */
+ sp->rows = csp->rows;
+ sp->cols = csp->cols;
+ sp->woff = csp->woff;
+
+ /*
+ * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
+ *
+ * The new screens may have different screen options sizes than the
+ * old one, so use them. Make sure that text counts aren't larger
+ * than the new screen sizes.
+ */
+ if (issmallscreen) {
+ sp->t_minrows = sp->t_rows = O_VAL(sp, O_WINDOW);
+ if (sp->t_rows > csp->t_maxrows)
+ sp->t_rows = sp->t_maxrows;
+ if (sp->t_minrows > csp->t_maxrows)
+ sp->t_minrows = sp->t_maxrows;
+ } else
+ sp->t_rows = sp->t_maxrows = sp->t_minrows = sp->rows - 1;
+
+ /* Reset the length of the default scroll. */
+ sp->defscroll = sp->t_maxrows / 2;
+
+ /*
+ * Don't change the screen's cursor information other than to
+ * note that the cursor is wrong.
+ */
+ F_SET(SVP(sp), SVI_CUR_INVALID);
+
+ /*
+ * The HMAP may be NULL, if the screen got resized and
+ * a bunch of screens had to be hidden.
+ */
+ if (HMAP == NULL)
+ CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
+ TMAP = HMAP + (sp->t_rows - 1);
+
+ /* Fill the map. */
+ if (svi_sm_fill(sp, sp->ep, sp->lno, P_FILL))
+ return (1);
+
+ /*
+ * The new screen replaces the old screen in the parent/child list.
+ * We insert the new screen after the old one. If we're exiting,
+ * the exit will delete the old one, if we're foregrounding, the fg
+ * code will move the old one to the hidden queue.
+ */
+ CIRCLEQ_REMOVE(&sp->gp->hq, sp, q);
+ CIRCLEQ_INSERT_AFTER(&csp->gp->dq, csp, sp, q);
+
+ F_SET(sp, S_REDRAW);
+ return (0);
+}
+
+/*
+ * svi_rabs --
+ * Change the absolute size of the current screen.
+ */
+int
+svi_rabs(sp, count, adj)
+ SCR *sp;
+ long count;
+ enum adjust adj;
+{
+ SCR *g, *s;
+
+ /*
+ * Figure out which screens will grow, which will shrink, and
+ * make sure it's possible.
+ */
+ if (count == 0)
+ return (0);
+ 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;
+ if ((g = sp->q.cqe_prev) == (void *)&sp->gp->dq) {
+ if ((g = sp->q.cqe_next) == (void *)&sp->gp->dq)
+ goto toobig;
+ g->woff -= count;
+ } else
+ s->woff += count;
+ } else {
+ g = sp;
+ if ((s = sp->q.cqe_next) != (void *)&sp->gp->dq)
+ if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count)
+ s = NULL;
+ else
+ s->woff += count;
+ else
+ s = NULL;
+ if (s == NULL) {
+ if ((s = sp->q.cqe_prev) == (void *)&sp->gp->dq) {
+toobig: msgq(sp, M_BERR, "The screen cannot %s",
+ adj == A_DECREASE ? "shrink" : "grow");
+ return (1);
+ }
+ if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) {
+toosmall: msgq(sp, M_BERR,
+ "The screen can only shrink to %d rows",
+ MINIMUM_SCREEN_ROWS);
+ return (1);
+ }
+ g->woff -= count;
+ }
+ }
+
+ /*
+ * 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) += count;
+ (void)msg_status(g, g->ep, g->lno, 0);
+ 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) -= count;
+ (void)msg_status(s, s->ep, s->lno, 0);
+ F_SET(s, S_REFORMAT);
+
+ return (0);
+}
diff --git a/usr.bin/vi/svi/svi_term.c b/usr.bin/vi/svi/svi_term.c
new file mode 100644
index 000000000000..baedfa7f931f
--- /dev/null
+++ b/usr.bin/vi/svi/svi_term.c
@@ -0,0 +1,310 @@
+/*-
+ * 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[] = "@(#)svi_term.c 8.5 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "../vi/vcmd.h"
+#include "excmd.h"
+#include "svi_screen.h"
+
+/*
+ * 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. */
+ u_char value; /* Special value (for lookup). */
+} TKLIST;
+static TKLIST const c_tklist[] = { /* Command mappings. */
+#ifdef SYSV_CURSES
+ {"kil1", "O", "insert line"},
+ {"kdch1", "x", "delete character"},
+ {"kcud1", "j", "cursor down"},
+ {"kel", "D", "delete to eol"},
+ {"kind", "\004", "scroll down"},
+ {"kll", "$", "go to eol"},
+ {"khome", "^", "go to sol"},
+ {"kich1", "i", "insert at cursor"},
+ {"kdl1", "dd", "delete line"},
+ {"kcub1", "h", "cursor left"},
+ {"knp", "\006", "page down"},
+ {"kpp", "\002", "page up"},
+ {"kri", "\025", "scroll up"},
+ {"ked", "dG", "delete to end of screen"},
+ {"kcuf1", "l", "cursor right"},
+ {"kcuu1", "k", "cursor up"},
+#else
+ {"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"},
+#endif
+ {NULL},
+};
+static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */
+ {NULL},
+};
+static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */
+#ifdef SYSV_CURSES
+ {"kcud1", "\033ja", "cursor down"},
+ {"kcub1", "\033ha", "cursor left"},
+ {"kcuu1", "\033ka", "cursor up"},
+ {"kcuf1", "\033la", "cursor right"},
+#else
+ {"kd", "\033ja", "cursor down"},
+ {"kl", "\033ha", "cursor left"},
+ {"ku", "\033ka", "cursor up"},
+ {"kr", "\033la", "cursor right"},
+#endif
+ {NULL},
+};
+
+/*
+ * svi_term_init --
+ * Initialize the special keys defined by the termcap/terminfo entry.
+ */
+int
+svi_term_init(sp)
+ SCR *sp;
+{
+ KEYLIST *kp;
+ SEQ *qp;
+ TKLIST const *tkp;
+ size_t len;
+ char *sbp, *s, *t, sbuf[1024];
+
+ /* Command mappings. */
+ for (tkp = c_tklist; tkp->name != NULL; ++tkp) {
+#ifdef SYSV_CURSES
+ if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
+ continue;
+#else
+ sbp = sbuf;
+ if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
+ continue;
+#endif
+ if (seq_set(sp, tkp->name, strlen(tkp->name), t, strlen(t),
+ tkp->output, strlen(tkp->output), SEQ_COMMAND, SEQ_SCREEN))
+ return (1);
+ }
+
+ /* Input mappings needing to be looked up. */
+ for (tkp = m1_tklist; tkp->name != NULL; ++tkp) {
+#ifdef SYSV_CURSES
+ if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
+ continue;
+#else
+ sbp = sbuf;
+ if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
+ continue;
+#endif
+ 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, SEQ_SCREEN))
+ return (1);
+ }
+
+ /* Input mappings that are already set or are text deletions. */
+ for (tkp = m2_tklist; tkp->name != NULL; ++tkp) {
+#ifdef SYSV_CURSES
+ if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
+ continue;
+#else
+ sbp = sbuf;
+ if ((t = tgetstr(tkp->ts, &sbp)) == NULL)
+ continue;
+#endif
+ /*
+ * !!!
+ * Some terminals' <cursor_left> keys send single <backspace>
+ * characters. This is okay in command mapping, but not okay
+ * in input mapping. That combination is the only one we'll
+ * ever see, hopefully, so kluge it here for now.
+ */
+ if (!strcmp(t, "\b"))
+ continue;
+ if (tkp->output == NULL) {
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), NULL, 0, SEQ_INPUT, SEQ_SCREEN))
+ return (1);
+ } else
+ if (seq_set(sp, tkp->name, strlen(tkp->name),
+ t, strlen(t), tkp->output, strlen(tkp->output),
+ SEQ_INPUT, SEQ_SCREEN))
+ return (1);
+ }
+
+ /* Rework any function key mappings. */
+ for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
+ if (!F_ISSET(qp, SEQ_FUNCMAP))
+ continue;
+ (void)svi_fmap(sp, qp->stype,
+ qp->input, qp->ilen, qp->output, qp->olen);
+ }
+
+ /* Set up the visual bell information. */
+ t = sbuf;
+ if (tgetstr("vb", &t) != NULL && (len = t - sbuf) != 0) {
+ MALLOC_RET(sp, s, char *, len);
+ memmove(s, sbuf, len);
+ if (SVP(sp)->VB != NULL)
+ free(SVP(sp)->VB);
+ SVP(sp)->VB = s;
+ return (0);
+ }
+
+ return (0);
+}
+
+/*
+ * svi_term_end --
+ * End the special keys defined by the termcap/terminfo entry.
+ */
+int
+svi_term_end(sp)
+ SCR *sp;
+{
+ SEQ *qp, *nqp;
+
+ /* Delete screen specific mappings. */
+ for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = nqp) {
+ nqp = qp->q.le_next;
+ if (!F_ISSET(qp, SEQ_SCREEN))
+ continue;
+ (void)seq_mdel(qp);
+ }
+ return (0);
+}
+
+/*
+ * svi_fmap --
+ * Map a function key.
+ */
+int
+svi_fmap(sp, stype, from, flen, to, tlen)
+ SCR *sp;
+ enum seqtype stype;
+ CHAR_T *from, *to;
+ size_t flen, tlen;
+{
+ char *t, keyname[64];
+ size_t nlen;
+
+ /* If the terminal isn't initialized, there's nothing to do. */
+ if (!F_ISSET(SVP(sp), SVI_CURSES_INIT))
+ return (0);
+
+#ifdef SYSV_CURSES
+ (void)snprintf(keyname, sizeof(keyname), "kf%d", atoi(from + 1));
+ if ((t = tigetstr(keyname)) == NULL || t == (char *)-1)
+ t = NULL;
+#else
+ /*
+ * !!!
+ * Historically, the 4BSD termcap code didn't support functions keys
+ * greater than 9. This was silently enforced -- asking for key k12
+ * returned the value for k1. We try and get around this by using
+ * the tables specified in the terminfo(TI_ENV) man page from the 3rd
+ * Edition SVID. This assumes that the implementors of any System V
+ * compatibility code or an extended termcap used those codes.
+ */
+ { int n; char *sbp, sbuf[1024];
+ static const char codes[] = {
+/* 0-10 */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';',
+/* 11-19 */ '1', '2', '3', '4', '5', '6', '7', '8', '9',
+/* 20-63 */ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ };
+ if ((n = atoi(from + 1)) > 63) {
+ msgq(sp, M_ERR,
+ "Termcap has no code for the %s function key",
+ from);
+ return (1);
+ }
+ (void)snprintf(keyname, sizeof(keyname),
+ "%c%c", n <= 10 ? 'k' : 'F', codes[n]);
+ sbp = sbuf;
+ t = tgetstr(keyname, &sbp);
+ }
+#endif
+ if (t == NULL) {
+ msgq(sp, M_ERR, "This terminal has no %s key", from);
+ return (1);
+ }
+ nlen = snprintf(keyname,
+ sizeof(keyname), "function key %d", atoi(from + 1));
+ return (seq_set(sp, keyname, nlen, t, strlen(t),
+ to, tlen, stype, SEQ_SCREEN | SEQ_USERDEF));
+}
diff --git a/usr.bin/vi/svi/svi_util.c b/usr.bin/vi/svi/svi_util.c
new file mode 100644
index 000000000000..5ba8b1e6e6a0
--- /dev/null
+++ b/usr.bin/vi/svi/svi_util.c
@@ -0,0 +1,347 @@
+/*-
+ * 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[] = "@(#)svi_util.c 8.53 (Berkeley) 8/12/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <curses.h>
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "../vi/vcmd.h"
+#include "excmd.h"
+#include "svi_screen.h"
+#include "../sex/sex_screen.h"
+
+/*
+ * svi_bell --
+ * Ring the bell.
+ */
+void
+svi_bell(sp)
+ SCR *sp;
+{
+#ifdef SYSV_CURSES
+ if (O_ISSET(sp, O_FLASH))
+ flash();
+ else
+ beep();
+#else
+ if (O_ISSET(sp, O_FLASH) && SVP(sp)->VB != NULL) {
+ (void)tputs(SVP(sp)->VB, 1, vi_putchar);
+ (void)fflush(stdout);
+ } else
+ (void)write(STDOUT_FILENO, "\007", 1); /* '\a' */
+#endif
+ F_CLR(sp, S_BELLSCHED);
+}
+
+/*
+ * svi_optchange --
+ * Screen specific "option changed" routine.
+ */
+int
+svi_optchange(sp, opt)
+ SCR *sp;
+ int opt;
+{
+ switch (opt) {
+ case O_TERM:
+ /* Toss any saved visual bell information. */
+ if (SVP(sp)->VB != NULL) {
+ FREE(SVP(sp)->VB, strlen(SVP(sp)->VB) + 1);
+ SVP(sp)->VB = NULL;
+ }
+
+ /* Reset the screen size. */
+ if (sp->s_window(sp, 0))
+ return (1);
+ F_SET(sp, S_RESIZE);
+ break;
+ case O_WINDOW:
+ if (svi_crel(sp, O_VAL(sp, O_WINDOW)))
+ return (1);
+ break;
+ }
+
+ (void)v_optchange(sp, opt);
+ (void)ex_optchange(sp, opt);
+
+ return (0);
+}
+
+/*
+ * svi_busy --
+ * Put the cursor somewhere so the user will think we're busy.
+ */
+int
+svi_busy(sp, msg)
+ SCR *sp;
+ char const *msg;
+{
+ /*
+ * 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 the terminal isn't initialized, there's nothing to do.
+ */
+ if (!F_ISSET(SVP(sp), SVI_CURSES_INIT))
+ return (0);
+
+ MOVE(sp, INFOLINE(sp), 0);
+ if (msg) {
+ ADDSTR(msg);
+ clrtoeol();
+ }
+ 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;
+{
+#ifdef SYSV_CURSES
+ keypad(stdscr, on ? TRUE : FALSE);
+#else
+ char *sbp, *t, sbuf[128];
+
+ sbp = sbuf;
+ if ((t = tgetstr(on ? "ks" : "ke", &sbp)) == NULL)
+ return;
+ (void)tputs(t, 0, vi_putchar);
+ (void)fflush(stdout);
+#endif
+}
+
+/*
+ * svi_clear --
+ * Clear from the row down to the end of the screen.
+ */
+int
+svi_clear(sp)
+ SCR *sp;
+{
+ size_t oldy, oldx, row;
+
+ getyx(stdscr, oldy, oldx);
+ for (row = SVP(sp)->srows - 1; row >= oldy; --row) {
+ MOVEA(sp, row, 0);
+ clrtoeol();
+ }
+ MOVEA(sp, oldy, oldx);
+ refresh();
+ return (0);
+}
+
+/*
+ * svi_suspend --
+ * Suspend an svi screen.
+ *
+ * See signal.c for a long discussion of what's going on here. Let
+ * me put it this way, it's NOT my fault.
+ */
+int
+svi_suspend(sp)
+ SCR *sp;
+{
+ struct termios sv_term;
+ sigset_t set;
+ int oldx, oldy, rval;
+ char *sbp, *t, sbuf[128];
+
+ rval = 0;
+
+ /*
+ * Block SIGALRM, because vi uses timers to decide when to paint
+ * busy messages on the screen.
+ */
+ (void)sigemptyset(&set);
+ (void)sigaddset(&set, SIGALRM);
+ if (sigprocmask(SIG_BLOCK, &set, NULL)) {
+ msgq(sp, M_SYSERR, "suspend: sigblock");
+ return (1);
+ }
+
+ /* Save the current cursor position. */
+ getyx(stdscr, oldy, oldx);
+
+ /*
+ * Move the cursor to the bottom of the screen.
+ *
+ * XXX
+ * Some curses implementations don't turn off inverse video when
+ * standend() is called, waiting to see what the next character is
+ * going to be, instead. Write a character to force inverse video
+ * off, and then clear the line.
+ */
+ MOVE(sp, INFOLINE(sp), 0);
+ ADDCH('.');
+ refresh();
+ MOVE(sp, INFOLINE(sp), 0);
+ clrtoeol();
+ refresh();
+
+ /* Restore the cursor keys to normal mode. */
+ svi_keypad(sp, 0);
+
+ /* Send VE/TE. */
+#ifdef SYSV_CURSES
+ if ((t = tigetstr("cnorm")) != NULL && t != (char *)-1)
+ (void)tputs(t, 0, vi_putchar);
+ if ((t = tigetstr("rmcup")) != NULL && t != (char *)-1)
+ (void)tputs(t, 0, vi_putchar);
+#else
+ sbp = sbuf;
+ if ((t = tgetstr("ve", &sbp)) != NULL)
+ (void)tputs(t, 0, vi_putchar);
+ sbp = sbuf;
+ if ((t = tgetstr("te", &sbp)) != NULL)
+ (void)tputs(t, 0, vi_putchar);
+#endif
+ (void)fflush(stdout);
+
+ /* Save current terminal settings, and restore the original ones. */
+ if (tcgetattr(STDIN_FILENO, &sv_term)) {
+ msgq(sp, M_SYSERR, "suspend: tcgetattr");
+ return (1);
+ }
+ if (tcsetattr(STDIN_FILENO,
+ TCSASOFT | TCSADRAIN, &sp->gp->original_termios)) {
+ msgq(sp, M_SYSERR, "suspend: tcsetattr original");
+ return (1);
+ }
+
+ /* Push out any waiting messages. */
+ (void)write(STDOUT_FILENO, "\n", 1);
+ (void)sex_refresh(sp, sp->ep);
+
+ /* Stop the process group. */
+ if (kill(0, SIGTSTP)) {
+ msgq(sp, M_SYSERR, "suspend: kill");
+ rval = 1;
+ }
+
+ /* Time passes ... */
+
+ /* Restore current terminal settings. */
+ if (tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &sv_term)) {
+ msgq(sp, M_SYSERR, "suspend: tcsetattr current");
+ rval = 1;
+ }
+
+ /* Send TI/VS. */
+#ifdef SYSV_CURSES
+ if ((t = tigetstr("smcup")) != NULL && t != (char *)-1)
+ (void)tputs(t, 0, vi_putchar);
+ if ((t = tigetstr("cvvis")) != NULL && t != (char *)-1)
+ (void)tputs(t, 0, vi_putchar);
+#else
+ sbp = sbuf;
+ if ((t = tgetstr("ti", &sbp)) != NULL)
+ (void)tputs(t, 0, vi_putchar);
+ sbp = sbuf;
+ if ((t = tgetstr("vs", &sbp)) != NULL)
+ (void)tputs(t, 0, vi_putchar);
+#endif
+ (void)fflush(stdout);
+
+ /* Put the cursor keys into application mode. */
+ svi_keypad(sp, 1);
+
+ /*
+ * If the screen changed size, do a full refresh. Otherwise,
+ * System V has curses repaint it. 4BSD curses will repaint
+ * it in the wrefresh() call below.
+ */
+ if (!sp->s_window(sp, 1))
+ (void)sp->s_refresh(sp, sp->ep);
+#ifdef SYSV_CURSES
+ else
+ redrawwin(stdscr);
+#endif
+
+ /*
+ * Restore the cursor.
+ *
+ * !!!
+ * Don't use MOVE/MOVEA, we don't want to return without resetting
+ * the signals, regardless.
+ */
+ (void)move(oldy, oldx);
+ (void)wrefresh(curscr);
+
+ /* Reset the signals. */
+ if (sigprocmask(SIG_UNBLOCK, &set, NULL)) {
+ msgq(sp, M_SYSERR, "suspend: sigblock");
+ rval = 1;
+ }
+ return (rval);
+}
+
+/*
+ * svi_gdbrefresh --
+ * Stub routine so can flush out screen changes using gdb.
+ */
+#ifdef DEBUG
+int
+svi_gdbrefresh()
+{
+ refresh();
+ return (0);
+}
+#endif
diff --git a/usr.bin/vi/vi/getc.c b/usr.bin/vi/vi/getc.c
new file mode 100644
index 000000000000..14c8423120c0
--- /dev/null
+++ b/usr.bin/vi/vi/getc.c
@@ -0,0 +1,268 @@
+/*-
+ * 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[] = "@(#)getc.c 8.9 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * Character stream routines --
+ * These routines return the file a character at a time. There are two
+ * special cases. First, the end of a line, end of a file, start of a
+ * file and empty lines are returned as special cases, and no character
+ * is returned. Second, empty lines include lines that have only white
+ * space in them, because the vi search functions don't care about white
+ * space, and this makes it easier for them to be consistent.
+ */
+
+/*
+ * cs_init --
+ * Initialize character stream routines.
+ */
+int
+cs_init(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ recno_t lno;
+
+ if ((csp->cs_bp =
+ file_gline(sp, ep, csp->cs_lno, &csp->cs_len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ msgq(sp, M_BERR, "Empty file");
+ else
+ GETLINE_ERR(sp, csp->cs_lno);
+ return (1);
+ }
+ if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
+ csp->cs_cno = 0;
+ csp->cs_flags = CS_EMP;
+ } else {
+ csp->cs_flags = 0;
+ csp->cs_ch = csp->cs_bp[csp->cs_cno];
+ }
+ return (0);
+}
+
+/*
+ * cs_next --
+ * Retrieve the next character.
+ */
+int
+cs_next(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ recno_t slno;
+
+ switch (csp->cs_flags) {
+ case CS_EMP: /* EMP; get next line. */
+ case CS_EOL: /* EOL; get next line. */
+ slno = csp->cs_lno; /* Save current line. */
+ if ((csp->cs_bp =
+ file_gline(sp, ep, ++csp->cs_lno, &csp->cs_len)) == NULL) {
+ csp->cs_lno = slno;
+ if (file_lline(sp, ep, &slno))
+ return (1);
+ if (slno > csp->cs_lno) {
+ GETLINE_ERR(sp, csp->cs_lno);
+ return (1);
+ }
+ csp->cs_flags = CS_EOF;
+ } else if (csp->cs_len == 0 ||
+ v_isempty(csp->cs_bp, csp->cs_len)) {
+ csp->cs_cno = 0;
+ csp->cs_flags = CS_EMP;
+ } else {
+ csp->cs_flags = 0;
+ csp->cs_ch = csp->cs_bp[csp->cs_cno = 0];
+ }
+ break;
+ case 0:
+ if (csp->cs_cno == csp->cs_len - 1)
+ csp->cs_flags = CS_EOL;
+ else
+ csp->cs_ch = csp->cs_bp[++csp->cs_cno];
+ break;
+ case CS_EOF: /* EOF. */
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ return (0);
+}
+
+/*
+ * cs_fspace --
+ * If on a space, eat forward until something other than a
+ * whitespace character.
+ *
+ * XXX
+ * Semantics of checking the current character were coded for the fword()
+ * function -- once the other word routines are converted, they may have
+ * to change.
+ */
+int
+cs_fspace(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
+ return (0);
+ for (;;) {
+ if (cs_next(sp, ep, csp))
+ return (1);
+ if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
+ break;
+ }
+ return (0);
+}
+
+/*
+ * cs_fblank --
+ * Eat forward to the next non-whitespace character.
+ */
+int
+cs_fblank(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ for (;;) {
+ if (cs_next(sp, ep, csp))
+ return (1);
+ if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
+ csp->cs_flags == 0 && isblank(csp->cs_ch))
+ continue;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * cs_prev --
+ * Retrieve the previous character.
+ */
+int
+cs_prev(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ recno_t slno;
+
+ switch (csp->cs_flags) {
+ case CS_EMP: /* EMP; get previous line. */
+ case CS_EOL: /* EOL; get previous line. */
+ if (csp->cs_lno == 1) { /* SOF. */
+ csp->cs_flags = CS_SOF;
+ break;
+ }
+ slno = csp->cs_lno; /* Save current line. */
+ if ((csp->cs_bp = /* Line should exist. */
+ file_gline(sp, ep, --csp->cs_lno, &csp->cs_len)) == NULL) {
+ GETLINE_ERR(sp, csp->cs_lno);
+ csp->cs_lno = slno;
+ return (1);
+ }
+ if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
+ csp->cs_cno = 0;
+ csp->cs_flags = CS_EMP;
+ } else {
+ csp->cs_flags = 0;
+ csp->cs_cno = csp->cs_len - 1;
+ csp->cs_ch = csp->cs_bp[csp->cs_cno];
+ }
+ break;
+ case 0:
+ if (csp->cs_cno == 0)
+ 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. */
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ return (0);
+}
+
+/*
+ * cs_bblank --
+ * Eat backward to the next non-whitespace character.
+ */
+int
+cs_bblank(sp, ep, csp)
+ SCR *sp;
+ EXF *ep;
+ VCS *csp;
+{
+ for (;;) {
+ if (cs_prev(sp, ep, csp))
+ return (1);
+ if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
+ csp->cs_flags == 0 && isblank(csp->cs_ch))
+ continue;
+ break;
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_ch.c b/usr.bin/vi/vi/v_ch.c
new file mode 100644
index 000000000000..1e59460ff7d9
--- /dev/null
+++ b/usr.bin/vi/vi/v_ch.c
@@ -0,0 +1,340 @@
+/*-
+ * 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_ch.c 8.13 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+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)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ vp->character = VIP(sp)->lastckey;
+
+ switch (VIP(sp)->csearchdir) {
+ case CNOTSET:
+ noprev(sp);
+ return (1);
+ case FSEARCH:
+ return (v_chF(sp, ep, vp));
+ case fSEARCH:
+ return (v_chf(sp, ep, vp));
+ case TSEARCH:
+ return (v_chT(sp, ep, vp));
+ case tSEARCH:
+ return (v_cht(sp, ep, vp));
+ default:
+ abort();
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * v_chrrepeat -- [count],
+ * Repeat the last F, f, T or t search in the reverse direction.
+ */
+int
+v_chrrepeat(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum cdirection savedir;
+ int rval;
+
+ vp->character = VIP(sp)->lastckey;
+ savedir = VIP(sp)->csearchdir;
+
+ switch (VIP(sp)->csearchdir) {
+ case CNOTSET:
+ noprev(sp);
+ return (1);
+ case FSEARCH:
+ rval = v_chf(sp, ep, vp);
+ break;
+ case fSEARCH:
+ rval = v_chF(sp, ep, vp);
+ break;
+ case TSEARCH:
+ rval = v_cht(sp, ep, vp);
+ break;
+ case tSEARCH:
+ rval = v_chT(sp, ep, vp);
+ break;
+ default:
+ abort();
+ }
+ VIP(sp)->csearchdir = savedir;
+ return (rval);
+}
+
+/*
+ * v_cht -- [count]tc
+ * Search forward in the line for the character before the next
+ * occurrence of the specified character.
+ */
+int
+v_cht(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (v_chf(sp, ep, vp))
+ return (1);
+
+ /*
+ * v_chf places the cursor on the character, where the 't'
+ * command wants it to its left. We know this is safe since
+ * we had to move right for v_chf() to have succeeded.
+ */
+ --vp->m_stop.cno;
+
+ /*
+ * Make any necessary correction to the motion decision made
+ * by the v_chf routine.
+ */
+ if (!ISMOTION(vp))
+ vp->m_final = vp->m_stop;
+
+ VIP(sp)->csearchdir = tSEARCH;
+ return (0);
+}
+
+/*
+ * v_chf -- [count]fc
+ * Search forward in the line for the next occurrence of the
+ * specified character.
+ */
+int
+v_chf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ size_t len;
+ recno_t lno;
+ u_long cnt;
+ int key;
+ char *endp, *p, *startp;
+
+ /*
+ * !!!
+ * 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))
+ VIP(sp)->lastckey = key;
+ VIP(sp)->csearchdir = fSEARCH;
+
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ if (len == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+
+ 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(sp, key);
+ return (1);
+ }
+ }
+
+ 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_DEF.
+ */
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_chT -- [count]Tc
+ * Search backward in the line for the character after the next
+ * occurrence of the specified character.
+ */
+int
+v_chT(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ if (v_chF(sp, ep, vp))
+ return (1);
+
+ /*
+ * v_chF places the cursor on the character, where the 'T'
+ * command wants it to its right. We know this is safe since
+ * we had to move left for v_chF() to have succeeded.
+ */
+ ++vp->m_stop.cno;
+
+ /*
+ * Make any necessary correction to the motion decision made
+ * by the v_chF routine.
+ *
+ * XXX
+ * If you change this, notice that v_chF changes vp->m_start
+ * AFTER setting vp->m_final.
+ */
+ if (!F_ISSET(vp, VC_Y))
+ vp->m_final = vp->m_stop;
+
+ VIP(sp)->csearchdir = TSEARCH;
+ return (0);
+}
+
+/*
+ * v_chF -- [count]Fc
+ * Search backward in the line for the next occurrence of the
+ * specified character.
+ */
+int
+v_chF(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+ u_long cnt;
+ int key;
+ char *endp, *p;
+
+ /*
+ * !!!
+ * 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))
+ VIP(sp)->lastckey = key;
+ VIP(sp)->csearchdir = FSEARCH;
+
+ if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+
+ if (len == 0) {
+ notfound(sp, key);
+ return (1);
+ }
+
+ endp = p - 1;
+ 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(sp, key);
+ return (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_DEF. 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", KEY_NAME(sp, ch));
+}
diff --git a/usr.bin/vi/vi/v_delete.c b/usr.bin/vi/vi/v_delete.c
new file mode 100644
index 000000000000..aa2af9814e95
--- /dev/null
+++ b/usr.bin/vi/vi/v_delete.c
@@ -0,0 +1,160 @@
+/*-
+ * 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_delete.c 8.14 (Berkeley) 7/28/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_Delete -- [buffer][count]D
+ * Delete line command.
+ */
+int
+v_Delete(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+
+ 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, vp->m_start.lno);
+ return (1);
+ }
+
+ if (len == 0)
+ return (0);
+
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno = len - 1;
+
+ /* Yank the lines. */
+ if (cut(sp, ep,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, CUT_NUMOPT))
+ return (1);
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, 0))
+ return (1);
+
+ vp->m_final.lno = vp->m_start.lno;
+ vp->m_final.cno = vp->m_start.cno ? vp->m_start.cno - 1 : 0;
+ return (0);
+}
+
+/*
+ * v_delete -- [buffer][count]d[count]motion
+ * Delete a range of text.
+ */
+int
+v_delete(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t nlines;
+ size_t len;
+ int lmode;
+
+ lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0;
+
+ /* Yank the lines. */
+ if (cut(sp, ep, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop,
+ lmode | (F_ISSET(vp, VM_CUTREQ) ? CUT_NUMREQ : CUT_NUMOPT)))
+ return (1);
+
+ /* Delete the lines. */
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, lmode))
+ return (1);
+
+ /*
+ * 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 (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);
+ }
+ }
+
+ /*
+ * 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 (vp->m_final.cno >= len)
+ vp->m_final.cno = len ? len - 1 : 0;
+
+ /*
+ * !!!
+ * The "dd" command moved to the first non-blank; "d<motion>" didn't.
+ */
+ if (F_ISSET(vp, VM_LDOUBLE)) {
+ F_CLR(vp, VM_RCM_MASK);
+ F_SET(vp, VM_RCM_SETFNB);
+ }
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_ex.c b/usr.bin/vi/vi/v_ex.c
new file mode 100644
index 000000000000..6481b407d002
--- /dev/null
+++ b/usr.bin/vi/vi/v_ex.c
@@ -0,0 +1,352 @@
+/*-
+ * 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_ex.c 8.10 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+static void excmd __P((EXCMDARG *,
+ int, int, recno_t, recno_t, int, ARGS *[], ARGS *, char *));
+
+/*
+ * v_again -- &
+ * Repeat the previous substitution.
+ */
+int
+v_again(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+
+ excmd(&cmd, C_SUBAGAIN,
+ 2, vp->m_start.lno, vp->m_start.lno, 1, ap, &a, "");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_at -- @
+ * Execute a buffer.
+ */
+int
+v_at(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+
+ excmd(&cmd, C_AT, 0, OOBLNO, OOBLNO, 0, ap, &a, NULL);
+ if (F_ISSET(vp, VC_BUFFER)) {
+ F_SET(&cmd, E_BUFFER);
+ cmd.buffer = vp->buffer;
+ }
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * 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)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* Save the current line/column number. */
+ sp->frp->lno = sp->lno;
+ sp->frp->cno = sp->cno;
+ F_SET(sp->frp, FR_CURSORSET);
+
+ /* Switch to ex mode. */
+ sp->saved_vi_mode = F_ISSET(sp, S_VI_CURSES | S_VI_XAW);
+ F_CLR(sp, S_SCREENS);
+ F_SET(sp, S_EX);
+ return (0);
+}
+
+/*
+ * v_filter -- [count]!motion command(s)
+ * Run range through shell commands, replacing text.
+ */
+int
+v_filter(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+ TEXT *tp;
+
+ /*
+ * !!!
+ * Historical vi permitted "!!" in an empty file, and it's handled
+ * as a special case in the ex_bang routine. Don't modify this setup
+ * without understanding that one. In particular, note that we're
+ * manipulating the ex argument structures behind ex's back.
+ *
+ * !!!
+ * Historical vi did not permit the '!' command to be associated with
+ * a non-line oriented motion command, in general, although it did
+ * with search commands. So, !f; and !w would fail, but !/;<CR>
+ * would succeed, even if they all moved to the same location in the
+ * current line. I don't see any reason to disallow '!' using any of
+ * the possible motion commands.
+ */
+ excmd(&cmd, C_BANG,
+ 2, vp->m_start.lno, vp->m_stop.lno, 0, ap, &a, NULL);
+ EXP(sp)->argsoff = 0; /* XXX */
+ if (F_ISSET(vp, VC_ISDOT)) {
+ if (argv_exp1(sp, ep, &cmd, "!", 1, 1))
+ return (1);
+ } else {
+ /* Get the command from the user. */
+ if (sp->s_get(sp, ep, sp->tiqp,
+ '!', TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK)
+ return (1);
+ /*
+ * Len is 0 if backspaced over the prompt,
+ * 1 if only CR entered.
+ */
+ tp = sp->tiqp->cqh_first;
+ if (tp->len <= 1)
+ return (0);
+
+ if (argv_exp1(sp, ep, &cmd, tp->lb + 1, tp->len - 1, 1))
+ return (1);
+ }
+ cmd.argc = EXP(sp)->argsoff; /* XXX */
+ cmd.argv = EXP(sp)->args; /* XXX */
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_join -- [count]J
+ * Join lines together.
+ */
+int
+v_join(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+ int lno;
+
+ /*
+ * YASC.
+ * The general rule is that '#J' joins # lines, counting the current
+ * line. However, 'J' and '1J' are the same as '2J', i.e. join the
+ * current and next lines. This doesn't map well into the ex command
+ * (which takes two line numbers), so we handle it here. Note that
+ * we never test for EOF -- historically going past the end of file
+ * worked just fine.
+ */
+ lno = vp->m_start.lno + 1;
+ if (F_ISSET(vp, VC_C1SET) && vp->count > 2)
+ lno = vp->m_start.lno + (vp->count - 1);
+
+ excmd(&cmd, C_JOIN, 2, vp->m_start.lno, lno, 0, ap, &a, NULL);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_shiftl -- [count]<motion
+ * Shift lines left.
+ */
+int
+v_shiftl(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+
+ excmd(&cmd, C_SHIFTL,
+ 2, vp->m_start.lno, vp->m_stop.lno, 0, ap, &a, "<");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_shiftr -- [count]>motion
+ * Shift lines right.
+ */
+int
+v_shiftr(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+
+ excmd(&cmd, C_SHIFTR,
+ 2, vp->m_start.lno, vp->m_stop.lno, 0, ap, &a, ">");
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_switch -- ^^
+ * Switch to the previous file.
+ */
+int
+v_switch(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+ char *name;
+
+ /*
+ * Try the alternate file name, then the previous file
+ * name. Use the real name, not the user's current name.
+ */
+ if ((name = sp->alt_name) == NULL) {
+ msgq(sp, M_ERR, "No previous file to edit");
+ return (1);
+ }
+
+ /* If autowrite is set, write out the file. */
+ if (file_m1(sp, ep, 0, FS_ALL))
+ return (1);
+
+ excmd(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, ap, &a, name);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_tagpush -- ^[
+ * Do a tag search on a the cursor keyword.
+ */
+int
+v_tagpush(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+
+ excmd(&cmd, C_TAG, 0, OOBLNO, 0, 0, ap, &a, vp->keyword);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * v_tagpop -- ^T
+ * Pop the tags stack.
+ */
+int
+v_tagpop(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ ARGS *ap[2], a;
+ EXCMDARG cmd;
+
+ excmd(&cmd, C_TAGPOP, 0, OOBLNO, 0, 0, ap, &a, NULL);
+ return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final));
+}
+
+/*
+ * excmd --
+ * Build an EX command structure.
+ */
+static void
+excmd(cmdp, cmd_id, naddr, lno1, lno2, force, ap, a, arg)
+ EXCMDARG *cmdp;
+ int cmd_id, force, naddr;
+ recno_t lno1, lno2;
+ ARGS *ap[2], *a;
+ char *arg;
+{
+ memset(cmdp, 0, sizeof(EXCMDARG));
+ cmdp->cmd = &cmds[cmd_id];
+ cmdp->addrcnt = naddr;
+ cmdp->addr1.lno = lno1;
+ cmdp->addr2.lno = lno2;
+ cmdp->addr1.cno = cmdp->addr2.cno = 1;
+ if (force)
+ cmdp->flags |= E_FORCE;
+ if ((a->bp = arg) == NULL) {
+ cmdp->argc = 0;
+ a->len = 0;
+ } else {
+ cmdp->argc = 1;
+ a->len = strlen(arg);
+ }
+ ap[0] = a;
+ ap[1] = NULL;
+ cmdp->argv = ap;
+}
diff --git a/usr.bin/vi/vi/v_increment.c b/usr.bin/vi/vi/v_increment.c
new file mode 100644
index 000000000000..6961953276dc
--- /dev/null
+++ b/usr.bin/vi/vi/v_increment.c
@@ -0,0 +1,163 @@
+/*-
+ * 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_increment.c 8.9 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static char * const fmt[] = {
+#define DEC 0
+ "%ld",
+#define SDEC 1
+ "%+ld",
+#define HEXC 2
+ "%#0.*lX",
+#define HEXL 3
+ "%#0.*lx",
+#define OCTAL 4
+ "%#0.*lo",
+};
+
+/*
+ * v_increment -- [count]#[#+-]
+ * Increment/decrement a keyword number.
+ */
+int
+v_increment(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ VI_PRIVATE *vip;
+ u_long ulval;
+ long lval;
+ size_t blen, len, nlen;
+ int rval;
+ char *bp, *ntype, *p, nbuf[100];
+
+ vip = VIP(sp);
+
+ /* Do repeat operations. */
+ if (vp->character == '#')
+ vp->character = vip->inc_lastch;
+
+ /* Get new value. */
+ if (F_ISSET(vp, VC_C1SET))
+ vip->inc_lastval = vp->count;
+
+ if (vp->character != '+' && vp->character != '-') {
+ msgq(sp, M_ERR, "usage: %s", vp->kp->usage);
+ return (1);
+ }
+ vip->inc_lastch = vp->character;
+
+ /* Figure out the resulting type and number. */
+ p = vp->keyword;
+ len = vp->klen;
+ if (len > 1 && p[0] == '0') {
+ if (vp->character == '+') {
+ ulval = strtoul(vp->keyword, NULL, 0);
+ if (ULONG_MAX - ulval < vip->inc_lastval)
+ goto overflow;
+ ulval += vip->inc_lastval;
+ } else {
+ ulval = strtoul(vp->keyword, NULL, 0);
+ if (ulval < vip->inc_lastval)
+ goto underflow;
+ ulval -= vip->inc_lastval;
+ }
+ ntype = fmt[OCTAL];
+ if (len > 2)
+ if (p[1] == 'X')
+ ntype = fmt[HEXC];
+ else if (p[1] == 'x')
+ ntype = fmt[HEXL];
+ nlen = snprintf(nbuf, sizeof(nbuf), ntype, len, ulval);
+ } else {
+ if (vp->character == '+') {
+ lval = strtol(vp->keyword, NULL, 0);
+ if (lval > 0 && LONG_MAX - lval < vip->inc_lastval) {
+overflow: msgq(sp, M_ERR, "Resulting number too large");
+ return (1);
+ }
+ lval += vip->inc_lastval;
+ } else {
+ lval = strtol(vp->keyword, NULL, 0);
+ if (lval < 0 && -(LONG_MIN - lval) < vip->inc_lastval) {
+underflow: msgq(sp, M_ERR, "Resulting number too small");
+ return (1);
+ }
+ lval -= vip->inc_lastval;
+ }
+ ntype = lval != 0 &&
+ (*vp->keyword == '+' || *vp->keyword == '-') ?
+ fmt[SDEC] : fmt[DEC];
+ nlen = snprintf(nbuf, sizeof(nbuf), ntype, lval);
+ }
+
+ 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, 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, vp->m_start.lno, bp, len);
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
diff --git a/usr.bin/vi/vi/v_init.c b/usr.bin/vi/vi/v_init.c
new file mode 100644
index 000000000000..069733ce1b23
--- /dev/null
+++ b/usr.bin/vi/vi/v_init.c
@@ -0,0 +1,256 @@
+/*-
+ * 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_init.c 8.26 (Berkeley) 8/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+#include "excmd.h"
+
+static int v_comment __P((SCR *, EXF *));
+
+/*
+ * v_screen_copy --
+ * Copy vi screen.
+ */
+int
+v_screen_copy(orig, sp)
+ SCR *orig, *sp;
+{
+ VI_PRIVATE *ovip, *nvip;
+
+ /* Create the private vi structure. */
+ CALLOC_RET(orig, nvip, VI_PRIVATE *, 1, sizeof(VI_PRIVATE));
+ sp->vi_private = nvip;
+
+ if (orig == NULL) {
+ nvip->inc_lastch = '+';
+ nvip->inc_lastval = 1;
+ nvip->csearchdir = CNOTSET;
+ } else {
+ ovip = VIP(orig);
+
+ /* User can replay the last input, but nothing else. */
+ if (ovip->rep_len != 0) {
+ MALLOC(orig, nvip->rep, char *, ovip->rep_len);
+ if (nvip->rep != NULL) {
+ memmove(nvip->rep, ovip->rep, ovip->rep_len);
+ nvip->rep_len = ovip->rep_len;
+ }
+ }
+
+ nvip->inc_lastch = ovip->inc_lastch;
+ nvip->inc_lastval = ovip->inc_lastval;
+
+ if (ovip->ps != NULL &&
+ (nvip->ps = strdup(ovip->ps)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ return (1);
+ }
+
+ nvip->lastckey = ovip->lastckey;
+ nvip->csearchdir = ovip->csearchdir;
+ }
+ return (0);
+}
+
+/*
+ * v_screen_end --
+ * End a vi screen.
+ */
+int
+v_screen_end(sp)
+ SCR *sp;
+{
+ VI_PRIVATE *vip;
+
+ vip = VIP(sp);
+
+ if (vip->rep != NULL)
+ free(vip->rep);
+
+ if (vip->ps != NULL)
+ free(vip->ps);
+
+ /* Free private memory. */
+ FREE(vip, sizeof(VI_PRIVATE));
+ sp->vi_private = NULL;
+
+ return (0);
+}
+
+/*
+ * v_init --
+ * Initialize vi.
+ */
+int
+v_init(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ size_t len;
+
+ /*
+ * The default address is line 1, column 0. If the address set
+ * bit is on for this file, load the address, ensuring that it
+ * exists.
+ */
+ if (F_ISSET(sp->frp, FR_CURSORSET)) {
+ sp->lno = sp->frp->lno;
+ sp->cno = sp->frp->cno;
+
+ if (file_gline(sp, ep, sp->lno, &len) == NULL) {
+ if (sp->lno != 1 || sp->cno != 0) {
+ if (file_lline(sp, ep, &sp->lno))
+ return (1);
+ if (sp->lno == 0)
+ sp->lno = 1;
+ sp->cno = 0;
+ }
+ } else if (sp->cno >= len)
+ sp->cno = 0;
+
+ if (F_ISSET(sp->frp, FR_FNONBLANK)) {
+ sp->cno = 0;
+ if (nonblank(sp, ep, sp->lno, &sp->cno))
+ return (1);
+
+ /* Reset strange attraction. */
+ sp->rcm = 0;
+ sp->rcm_last = 0;
+ }
+ } else {
+ sp->lno = 1;
+ sp->cno = 0;
+
+ if (O_ISSET(sp, O_COMMENT) && v_comment(sp, ep))
+ return (1);
+
+ /* Vi always starts up on the first non-<blank>. */
+ if (nonblank(sp, ep, sp->lno, &sp->cno))
+ return (1);
+
+ /* Reset strange attraction. */
+ sp->rcm = 0;
+ sp->rcm_last = 0;
+ }
+
+ /* Make ex display to a special function. */
+ if ((sp->stdfp = fwopen(sp, sp->s_ex_write)) == NULL) {
+ msgq(sp, M_SYSERR, "ex output");
+ return (1);
+ }
+#ifdef MAKE_EX_OUTPUT_LINE_BUFFERED
+ (void)setvbuf(sp->stdfp, NULL, _IOLBF, 0);
+#endif
+
+ /* Display the status line. */
+ return (msg_status(sp, ep, sp->lno, 0));
+}
+
+/*
+ * v_end --
+ * End vi session.
+ */
+int
+v_end(sp)
+ SCR *sp;
+{
+ /* Close down ex output file descriptor. */
+ (void)fclose(sp->stdfp);
+
+ return (0);
+}
+
+/*
+ * v_optchange --
+ * Handle change of options for vi.
+ */
+int
+v_optchange(sp, opt)
+ SCR *sp;
+ int opt;
+{
+ switch (opt) {
+ case O_PARAGRAPHS:
+ case O_SECTIONS:
+ return (v_buildps(sp));
+ }
+ return (0);
+}
+
+/*
+ * v_comment --
+ * Skip the first comment.
+ */
+static int
+v_comment(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ recno_t lno;
+ size_t len;
+ char *p;
+
+ for (lno = 1;
+ (p = file_gline(sp, ep, lno, &len)) != NULL && len == 0; ++lno);
+ if (p == NULL || len <= 1 || memcmp(p, "/*", 2))
+ return (0);
+ do {
+ for (; len; --len, ++p)
+ if (p[0] == '*' && len > 1 && p[1] == '/') {
+ sp->lno = lno;
+ return (0);
+ }
+ } while ((p = file_gline(sp, ep, ++lno, &len)) != NULL);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_left.c b/usr.bin/vi/vi/v_left.c
new file mode 100644
index 000000000000..ec57d9143091
--- /dev/null
+++ b/usr.bin/vi/vi/v_left.c
@@ -0,0 +1,287 @@
+/*-
+ * 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.9 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.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_DEF. 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_DEF.
+ */
+ 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_DEF. 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_DEF. 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_DEF. 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/vi/v_mark.c b/usr.bin/vi/vi/v_mark.c
new file mode 100644
index 000000000000..66dda1a7ff59
--- /dev/null
+++ b/usr.bin/vi/vi/v_mark.c
@@ -0,0 +1,210 @@
+/*-
+ * 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_mark.c 8.8 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.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)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (mark_set(sp, ep, vp->character, &vp->m_start, 1));
+}
+
+enum which {BMARK, FMARK};
+static int mark __P((SCR *, EXF *, VICMDARG *, enum which));
+
+
+/*
+ * v_bmark -- `['`a-z]
+ * Move to a mark.
+ *
+ * Moves to a mark, setting both row and column.
+ *
+ * !!!
+ * 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_bmark(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (mark(sp, ep, vp, BMARK));
+}
+
+/*
+ * v_fmark -- '['`a-z]
+ * Move to a mark.
+ *
+ * Move to the first nonblank character of the line containing the mark.
+ */
+int
+v_fmark(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (mark(sp, ep, vp, FMARK));
+}
+
+static int
+mark(sp, ep, vp, cmd)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ enum which cmd;
+{
+ MARK m;
+ size_t len;
+ enum direction dir;
+
+ if (mark_get(sp, ep, vp->character, &vp->m_stop))
+ return (1);
+
+ /* Forward marks move to the first non-blank. */
+ if (cmd == FMARK) {
+ 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 the motion is in the reverse direction, switch the start and
+ * stop MARK's so that it's in a forward direction. (There's no
+ * reason for this other than to make the tests below easier. The
+ * code in vi.c:vi() would have done the switch.) Both forward
+ * and backward motions can happen for either kind of mark command.
+ */
+ 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) {
+ dir = BACKWARD;
+ m = vp->m_start;
+ vp->m_start = vp->m_stop;
+ vp->m_stop = m;
+ } else
+ dir = FORWARD;
+
+ /*
+ * BACKWARD:
+ * 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_DEF.
+ *
+ * FORWARD:
+ * VC_D and VC_Y commands don't move. Ignore VC_C and VC_DEF.
+ */
+ if (dir == BACKWARD)
+ if (F_ISSET(vp, VC_D) ||
+ F_ISSET(vp, VC_Y) && vp->m_start.lno != vp->m_stop.lno)
+ vp->m_final = vp->m_start;
+ else
+ vp->m_final = vp->m_stop;
+ else
+ vp->m_final = vp->m_start;
+
+ if (cmd == FMARK)
+ return (0);
+
+ /*
+ * Forward marks are always line oriented, and it's set in the
+ * vcmd.c table. Backward marks that start and stop at column
+ * 0 of the line are also line mode commands.
+ */
+ if (vp->m_start.cno == 0 && vp->m_stop.cno == 0)
+ F_SET(vp, VM_LMODE);
+
+ /*
+ * BMARK'S that move backward and start at column 0, or move forward
+ * and end at column 0 are corrected to the last column of the previous
+ * line. Else, adjust the starting/ending point to the character
+ * before the current one (this is safe because we know the command had
+ * to move to succeed).
+ */
+ 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);
+ }
+ vp->m_stop.cno = len ? len - 1 : 0;
+ } else
+ --vp->m_stop.cno;
+
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_match.c b/usr.bin/vi/vi/v_match.c
new file mode 100644
index 000000000000..b047a4431747
--- /dev/null
+++ b/usr.bin/vi/vi/v_match.c
@@ -0,0 +1,198 @@
+/*-
+ * 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_match.c 8.14 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_match -- %
+ * Search to matching character.
+ */
+int
+v_match(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ VCS cs;
+ MARK *mp;
+ recno_t lno;
+ size_t cno, len, off;
+ int cnt, matchc, startc, (*gc)__P((SCR *, EXF *, VCS *));
+ char *p;
+
+ /*
+ * !!!
+ * Historic practice; ignore the count.
+ */
+ 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, vp->m_start.lno);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Historical practice was to search for the initial character
+ * in the forward direction only.
+ */
+ for (off = vp->m_start.cno;; ++off) {
+ if (off >= len) {
+nomatch: msgq(sp, M_BERR, "No match character on this line");
+ return (1);
+ }
+ switch (startc = p[off]) {
+ case '(':
+ matchc = ')';
+ gc = cs_next;
+ break;
+ case ')':
+ matchc = '(';
+ gc = cs_prev;
+ break;
+ case '[':
+ matchc = ']';
+ gc = cs_next;
+ break;
+ case ']':
+ matchc = '[';
+ gc = cs_prev;
+ break;
+ case '{':
+ matchc = '}';
+ gc = cs_next;
+ break;
+ case '}':
+ matchc = '{';
+ gc = cs_prev;
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ cs.cs_lno = vp->m_start.lno;
+ cs.cs_cno = off;
+ if (cs_init(sp, ep, &cs))
+ return (1);
+ for (cnt = 1;;) {
+ if (gc(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags != 0) {
+ if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF)
+ break;
+ continue;
+ }
+ if (cs.cs_ch == startc)
+ ++cnt;
+ else if (cs.cs_ch == matchc && --cnt == 0)
+ break;
+ }
+ if (cnt) {
+ msgq(sp, M_BERR, "Matching character not found");
+ return (1);
+ }
+
+ vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * 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_DEF.
+ *
+ * !!!
+ * Don't correct for leftward movement -- historic vi deleted the
+ * starting cursor position when deleting to a match.
+ */
+ 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 the line, i.e. the
+ * movement is cutting all of the line's text, and the later cursor
+ * position has nothing other than whitespace characters between it
+ * and the end of its line, the buffer is in line mode.
+ */
+ if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno)
+ return (0);
+ mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop;
+ if (mp->cno != 0) {
+ cno = 0;
+ if (nonblank(sp, ep, mp->lno, &cno))
+ return (1);
+ if (cno < mp->cno)
+ return (0);
+ }
+ mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start;
+ if ((p = file_gline(sp, ep, mp->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, mp->lno);
+ return (1);
+ }
+ for (p += mp->cno + 1, len -= mp->cno; --len; ++p)
+ if (!isblank(*p))
+ return (0);
+ F_SET(vp, VM_LMODE);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_ntext.c b/usr.bin/vi/vi/v_ntext.c
new file mode 100644
index 000000000000..5dcba3b2f967
--- /dev/null
+++ b/usr.bin/vi/vi/v_ntext.c
@@ -0,0 +1,1899 @@
+/*-
+ * 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[] = "@(#)v_ntext.c 8.120 (Berkeley) 8/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+#include "excmd.h"
+
+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 *));
+static int txt_indent __P((SCR *, TEXT *));
+static int txt_margin __P((SCR *,
+ TEXT *, CHAR_T *, TEXT *, u_int, int *));
+static int txt_outdent __P((SCR *, TEXT *));
+static void txt_Rcleanup __P((SCR *,
+ TEXTH *, TEXT *, const char *, const size_t));
+static int txt_resolve __P((SCR *, EXF *, TEXTH *, u_int));
+static void txt_showmatch __P((SCR *, EXF *));
+static void txt_unmap __P((SCR *, TEXT *, u_int *));
+
+/* Cursor character (space is hard to track on the screen). */
+#if defined(DEBUG) && 0
+#undef CH_CURSOR
+#define CH_CURSOR '+'
+#endif
+
+/*
+ * v_ntext --
+ * Read in text from the user.
+ *
+ * !!!
+ * 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
+ * the entire line on each keystroke, the "bcd" gets pushed to the right as
+ * we ignore that the user has "promised" to change the rest of the characters.
+ * Users have noticed, but this isn't worth fixing, and, the way that the
+ * historic vi did it results in an even worse bug. Given the keystrokes
+ * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears
+ * on the second <esc> key.
+ */
+int
+v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+ MARK *tm; /* To MARK. */
+ const char *lp; /* Input line. */
+ const size_t len; /* Input line length. */
+ MARK *rp; /* Return MARK. */
+ ARG_CHAR_T prompt; /* Prompt to display. */
+ recno_t ai_line; /* Line number to use for autoindent count. */
+ u_int flags; /* TXT_ flags. */
+{
+ /* State of abbreviation checks. */
+ 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. */
+ enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex;
+ /* State of quotation. */
+ enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;
+ enum input tval;
+ struct termios t; /* Terminal characteristics. */
+ CH ikey; /* Input character structure. */
+ CHAR_T ch; /* Input character. */
+ TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
+ TEXT wmt; /* Wrapmargin text structure. */
+ size_t owrite, insert; /* Temporary copies of TEXT fields. */
+ size_t rcol; /* 0-N: insert offset in the replay buffer. */
+ size_t col; /* Current column. */
+ u_long margin; /* Wrapmargin value. */
+ u_int iflags; /* Input flags. */
+ int ab_cnt, ab_turnoff; /* Abbreviation count, if turned off. */
+ int eval; /* Routine return value. */
+ int replay; /* If replaying a set of input. */
+ int showmatch; /* Showmatch set on this character. */
+ int sig_ix, sig_reset; /* Signal information. */
+ int testnr; /* Test first character for nul replay. */
+ int max, tmp;
+ int unmap_tst; /* Input map needs testing. */
+ int wmset, wmskip; /* Wrapmargin happened, blank skip flags. */
+ char *p;
+
+ /*
+ * Set the input flag, so tabs get displayed correctly
+ * and everyone knows that the text buffer is in use.
+ */
+ F_SET(sp, S_INPUT);
+
+ /* Local initialization. */
+ eval = 0;
+
+ /*
+ * Get one TEXT structure with some initial buffer space, reusing
+ * the last one if it's big enough. (All TEXT bookkeeping fields
+ * default to 0 -- text_init() handles this.) If changing a line,
+ * copy it into the TEXT buffer.
+ */
+ if (tiqh->cqh_first != (void *)tiqh) {
+ tp = tiqh->cqh_first;
+ if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
+ text_lfree(tiqh);
+ goto newtp;
+ }
+ tp->ai = tp->insert = tp->offset = tp->owrite = 0;
+ if (lp != NULL) {
+ tp->len = len;
+ memmove(tp->lb, lp, len);
+ } else
+ tp->len = 0;
+ } else {
+newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
+ return (1);
+ CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
+ }
+
+ /* Set the starting line number. */
+ tp->lno = sp->lno;
+
+ /*
+ * Set the insert and overwrite counts. If overwriting characters,
+ * do insertion afterward. If not overwriting characters, assume
+ * doing insertion. If change is to a mark, emphasize it with an
+ * CH_ENDMARK
+ */
+ if (len) {
+ if (LF_ISSET(TXT_OVERWRITE)) {
+ 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] = CH_ENDMARK;
+ }
+
+ /*
+ * 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 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
+ * and overwrite will be zero. If doing autoindent, figure out how
+ * much indentation we need and fill it in. Update input column and
+ * screen cursor as necessary.
+ */
+ if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
+ if (txt_auto(sp, ep, ai_line, NULL, 0, tp))
+ return (1);
+ sp->cno = tp->ai;
+ } else {
+ /*
+ * The cc and S commands have a special feature -- leading
+ * <blank> characters are handled as autoindent characters.
+ * Beauty!
+ */
+ if (LF_ISSET(TXT_AICHARS)) {
+ tp->offset = 0;
+ tp->ai = sp->cno;
+ } else
+ tp->offset = sp->cno;
+ }
+
+ /* If getting a command buffer from the user, there may be a prompt. */
+ if (LF_ISSET(TXT_PROMPT)) {
+ tp->lb[sp->cno++] = prompt;
+ ++tp->len;
+ ++tp->offset;
+ }
+
+ /*
+ * If appending after the end-of-line, add a space into the buffer
+ * and move the cursor right. This space is inserted, i.e. pushed
+ * along, and then deleted when the line is resolved. Assumes that
+ * the cursor is already positioned at the end of the line. This
+ * avoids the nastiness of having the cursor reside on a magical
+ * column, i.e. a column that doesn't really exist. The only down
+ * side is that we may wrap lines or scroll the screen before it's
+ * strictly necessary. Not a big deal.
+ */
+ if (LF_ISSET(TXT_APPENDEOL)) {
+ tp->lb[sp->cno] = CH_CURSOR;
+ ++tp->len;
+ ++tp->insert;
+ }
+
+ /*
+ * Historic practice is that the wrapmargin value was a distance
+ * from the RIGHT-HAND column, not the left. It's more useful to
+ * us as a distance from the left-hand column.
+ *
+ * !!!/XXX
+ * Replay commands were not affected by the wrapmargin option in the
+ * historic 4BSD vi. What I found surprising was that people depend
+ * on it, as in this gem of a macro which centers lines:
+ *
+ * map #c $mq81a ^V^[81^V|D`qld0:s/ / /g^V^M$p
+ *
+ * Other historic versions of vi, notably Sun's, applied wrapmargin
+ * to replay lines as well.
+ *
+ * XXX
+ * Setting margin causes a significant performance hit. Normally
+ * we don't update the screen if there are keys waiting, but we
+ * have to if margin is set, otherwise the screen routines don't
+ * know where the cursor is.
+ *
+ * !!!
+ * One more special case. If an inserted <blank> character causes
+ * wrapmargin to split the line, the next user entered character is
+ * discarded if it's a <space> character.
+ */
+ if (LF_ISSET(TXT_REPLAY) || !LF_ISSET(TXT_WRAPMARGIN))
+ margin = 0;
+ else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
+ margin = sp->cols - margin;
+ wmset = wmskip = 0;
+
+ /* Initialize abbreviations checks. */
+ if (F_ISSET(sp->gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {
+ abb = A_INWORD;
+ ab_cnt = ab_turnoff = 0;
+ } else
+ abb = A_NOTSET;
+
+ /*
+ * Set up the dot command. Dot commands are done by saving the
+ * actual characters and replaying the input. We have to push
+ * the characters onto the key stack and then handle them normally,
+ * otherwise things like wrapmargin will fail.
+ *
+ * XXX
+ * It would be nice if we could swallow backspaces and such, but
+ * it's not all that easy to do. Another possibility would be to
+ * recognize full line insertions, which could be performed quickly,
+ * without replay.
+ */
+nullreplay:
+ rcol = 0;
+ if (replay = LF_ISSET(TXT_REPLAY)) {
+ /*
+ * !!!
+ * Historically, it wasn't an error to replay non-existent
+ * input. This test is necessary, we get here by the user
+ * doing an input command followed by a nul.
+ *
+ * !!!
+ * Historically, vi did not remap or reabbreviate replayed
+ * input. It did, however, beep at you if you changed an
+ * abbreviation and then replayed the input. We're not that
+ * compatible.
+ */
+ if (VIP(sp)->rep == NULL)
+ return (0);
+ if (term_push(sp, VIP(sp)->rep, VIP(sp)->rep_cnt, CH_NOMAP))
+ return (1);
+ testnr = 0;
+ abb = A_NOTSET;
+ LF_CLR(TXT_RECORD);
+ } else
+ testnr = 1;
+
+ unmap_tst = LF_ISSET(TXT_MAPINPUT) && LF_ISSET(TXT_INFOLINE);
+ iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
+ for (showmatch = 0, sig_reset = 0,
+ carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) {
+ /*
+ * Reset the line and update the screen. (The txt_showmatch()
+ * code refreshes the screen for us.) Don't refresh unless
+ * we're about to wait on a character or we need to know where
+ * the cursor really is.
+ */
+ if (showmatch || margin || !KEYS_WAITING(sp)) {
+ if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
+ goto err;
+ if (showmatch) {
+ showmatch = 0;
+ txt_showmatch(sp, ep);
+ } else if (sp->s_refresh(sp, ep))
+ goto err;
+ }
+
+ /* Get the next character. */
+next_ch: tval = term_key(sp, &ikey, quoted == Q_THISCHAR ?
+ iflags & ~(TXT_MAPCOMMAND | TXT_MAPINPUT) : iflags);
+ ch = ikey.ch;
+
+ /* Restore the terminal state if it was modified. */
+ if (sig_reset && !tcgetattr(STDIN_FILENO, &t)) {
+ t.c_lflag |= ISIG;
+ t.c_iflag |= sig_ix;
+ sig_reset = 0;
+ (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
+ }
+
+ /*
+ * !!!
+ * Historically, <interrupt> exited the user from text input
+ * mode or cancelled a colon command, and returned to command
+ * mode. It also beeped the terminal, but that seems a bit
+ * excessive.
+ */
+ if (tval != INP_OK) {
+ if (tval == INP_INTR)
+ goto k_escape;
+ goto err;
+ }
+
+ /* Abbreviation check. See comment in txt_abbrev(). */
+#define MAX_ABBREVIATION_EXPANSION 256
+ if (ikey.flags & CH_ABBREVIATED) {
+ if (++ab_cnt > MAX_ABBREVIATION_EXPANSION) {
+ term_flush(sp,
+ "Abbreviation exceeded maximum number of characters",
+ CH_ABBREVIATED);
+ ab_cnt = 0;
+ continue;
+ }
+ } else
+ ab_cnt = 0;
+
+ /* Wrapmargin check. */
+ if (wmskip) {
+ wmskip = 0;
+ if (ch == ' ')
+ goto next_ch;
+ }
+
+ /*
+ * !!!
+ * Historic feature. If the first character of the input is
+ * a nul, replay the previous input. This isn't documented
+ * anywhere, and is a great test of vi clones.
+ */
+ if (ch == '\0' && testnr) {
+ LF_SET(TXT_REPLAY);
+ goto nullreplay;
+ }
+ testnr = 0;
+
+ /*
+ * Check to see if the character fits into the input (and
+ * replay, if necessary) buffers. It isn't necessary to
+ * have tp->len bytes, since it doesn't consider overwrite
+ * characters, but not worth fixing.
+ */
+ if (LF_ISSET(TXT_RECORD)) {
+ BINC_GOTO(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);
+ VIP(sp)->rep[rcol++] = ch;
+ }
+ BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
+
+ /*
+ * If the character was quoted, replace the last character
+ * (the literal mark) with the new character. If quoted
+ * by someone else, simply insert the character.
+ */
+ if (ikey.flags & CH_QUOTED)
+ goto insq_ch;
+ if (quoted == Q_THISCHAR) {
+ --sp->cno;
+ ++tp->owrite;
+ quoted = Q_NOTSET;
+ goto insq_ch;
+ }
+ /*
+ * !!!
+ * Extension. If the user enters "<CH_HEX>[isxdigit()]*" we
+ * will try to use the value as a character. Anything else
+ * inserts the <CH_HEX> character, and resets hex mode.
+ */
+ if (hex == H_INHEX && !isxdigit(ch)) {
+ if (txt_hex(sp, tp))
+ goto err;
+ hex = H_NOTSET;
+ }
+
+ switch (ikey.value) {
+ case K_CR: /* Carriage return. */
+ case K_NL: /* New line. */
+ /* Return in script windows and the command line. */
+k_cr: if (LF_ISSET(TXT_CR)) {
+ /*
+ * If this was a map, we may have not displayed
+ * the line. Display it, just in case.
+ *
+ * If a script window and not the colon line,
+ * push a <cr> so it gets executed.
+ */
+ if (LF_ISSET(TXT_INFOLINE)) {
+ if (sp->s_change(sp,
+ ep, tp->lno, LINE_RESET))
+ goto err;
+ } else if (F_ISSET(sp, S_SCRIPT))
+ (void)term_push(sp, "\r", 1, CH_NOMAP);
+ goto k_escape;
+ }
+
+#define LINE_RESOLVE { \
+ /* \
+ * Handle abbreviations. If there was one, \
+ * discard the replay characters. \
+ */ \
+ 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 (abb != A_NOTSET) \
+ abb = A_NOTWORD; \
+ if (unmap_tst) \
+ txt_unmap(sp, tp, &iflags); \
+ /* Delete any appended cursor. */ \
+ if (LF_ISSET(TXT_APPENDEOL)) { \
+ --tp->len; \
+ --tp->insert; \
+ } \
+}
+ LINE_RESOLVE;
+
+ /*
+ * Save the current line information for restoration
+ * in txt_backup(). Set the new line length.
+ */
+ tp->sv_len = tp->len;
+ tp->sv_cno = sp->cno;
+ tp->len = sp->cno;
+
+ /* Update the old line. */
+ if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
+ goto err;
+
+ /*
+ * Historic practice was to delete <blank> characters
+ * following the inserted newline. This affected the
+ * 'R', 'c', and 's' commands; 'c' and 's' retained
+ * the insert characters only, 'R' moved overwrite and
+ * insert characters into the next TEXT structure.
+ * All other commands simply deleted the overwrite
+ * characters. We have to keep track of the number of
+ * characters erased for the 'R' command so that we
+ * can get the final resolution of the line correct.
+ */
+ tp->R_erase = 0;
+ owrite = tp->owrite;
+ insert = tp->insert;
+ if (LF_ISSET(TXT_REPLACE) && owrite != 0) {
+ for (p = tp->lb + sp->cno;
+ owrite > 0 && isblank(*p);
+ ++p, --owrite, ++tp->R_erase);
+ if (owrite == 0)
+ for (; insert > 0 && isblank(*p);
+ ++p, ++tp->R_erase, --insert);
+ } else {
+ for (p = tp->lb + sp->cno + owrite;
+ insert > 0 && isblank(*p); ++p, --insert);
+ owrite = 0;
+ }
+
+ /* Set up bookkeeping for the new line. */
+ if ((ntp = text_init(sp, p,
+ insert + owrite, insert + owrite + 32)) == NULL)
+ goto err;
+ ntp->insert = insert;
+ ntp->owrite = owrite;
+ ntp->lno = tp->lno + 1;
+
+ /*
+ * Reset the autoindent line value. 0^D keeps the ai
+ * line from changing, ^D changes the level, even if
+ * there are no characters in the old line. Note,
+ * if using the current tp structure, use the cursor
+ * as the length, the user may have erased autoindent
+ * characters.
+ */
+ if (LF_ISSET(TXT_AUTOINDENT)) {
+ if (carat_st == C_NOCHANGE) {
+ if (txt_auto(sp, ep,
+ OOBLNO, &ait, ait.ai, ntp))
+ goto err;
+ FREE_SPACE(sp, ait.lb, ait.lb_len);
+ } else
+ if (txt_auto(sp, ep,
+ OOBLNO, tp, sp->cno, ntp))
+ goto err;
+ carat_st = C_NOTSET;
+ }
+
+ /* Reset the cursor. */
+ sp->lno = ntp->lno;
+ sp->cno = ntp->ai;
+
+ /*
+ * If we're here because wrapmargin was set and we've
+ * broken a line, there may be additional information
+ * (i.e. the start of a line) in the wmt structure.
+ */
+ if (wmset) {
+ if (wmt.len != 0 ||
+ wmt.insert != 0 || wmt.owrite != 0) {
+ BINC_GOTO(sp, ntp->lb, ntp->lb_len,
+ ntp->len + wmt.len + 32);
+ memmove(ntp->lb + sp->cno, wmt.lb,
+ wmt.len + wmt.insert + wmt.owrite);
+ ntp->len +=
+ wmt.len + wmt.insert + wmt.owrite;
+ ntp->insert = wmt.insert;
+ ntp->owrite = wmt.owrite;
+ sp->cno += wmt.len;
+ }
+ wmset = 0;
+ }
+
+ /* New lines are TXT_APPENDEOL. */
+ if (ntp->owrite == 0 && ntp->insert == 0) {
+ BINC_GOTO(sp,
+ ntp->lb, ntp->lb_len, ntp->len + 1);
+ LF_SET(TXT_APPENDEOL);
+ ntp->lb[sp->cno] = CH_CURSOR;
+ ++ntp->insert;
+ ++ntp->len;
+ }
+
+ /*
+ * Swap old and new TEXT's, and insert the new TEXT
+ * into the queue.
+ *
+ * !!!
+ * DON'T insert until the old line has been updated,
+ * or the inserted line count in line.c:file_gline()
+ * will be wrong.
+ */
+ tp = ntp;
+ CIRCLEQ_INSERT_TAIL(tiqh, tp, q);
+
+ /* Update the new line. */
+ if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
+ goto err;
+
+ /* Set the renumber bit. */
+ F_SET(sp, S_RENUMBER);
+
+ /* Refresh if nothing waiting. */
+ if (margin || !KEYS_WAITING(sp))
+ if (sp->s_refresh(sp, ep))
+ goto err;
+ goto next_ch;
+ case K_ESCAPE: /* Escape. */
+ if (!LF_ISSET(TXT_ESCAPE))
+ goto ins_ch;
+k_escape: LINE_RESOLVE;
+
+ /*
+ * Clean up for the 'R' command, restoring overwrite
+ * characters, and making them into insert characters.
+ */
+ if (LF_ISSET(TXT_REPLACE))
+ txt_Rcleanup(sp, tiqh, tp, lp, len);
+
+ /*
+ * If there are any overwrite characters, copy down
+ * any insert characters, and decrement the length.
+ */
+ if (tp->owrite) {
+ if (tp->insert)
+ memmove(tp->lb + sp->cno,
+ tp->lb + sp->cno + tp->owrite,
+ tp->insert);
+ tp->len -= tp->owrite;
+ }
+
+ /*
+ * Optionally resolve the lines into the file. Clear
+ * the input flag, the look-aside buffer is no longer
+ * valid. If not resolving the lines into the file,
+ * end it with a nul.
+ *
+ * XXX
+ * This is wrong, should pass back a length.
+ */
+ if (LF_ISSET(TXT_RESOLVE)) {
+ if (txt_resolve(sp, ep, tiqh, flags))
+ goto err;
+ F_CLR(sp, S_INPUT);
+ } else {
+ BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
+ tp->lb[tp->len] = '\0';
+ }
+
+ /*
+ * Set the return cursor position to rest on the last
+ * inserted character.
+ */
+ if (rp != NULL) {
+ rp->lno = tp->lno;
+ rp->cno = sp->cno ? sp->cno - 1 : 0;
+ if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
+ goto err;
+ }
+ goto ret;
+ case K_CARAT: /* Delete autoindent chars. */
+ if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
+ carat_st = C_CARATSET;
+ goto ins_ch;
+ case K_ZERO: /* Delete autoindent chars. */
+ if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
+ carat_st = C_ZEROSET;
+ goto ins_ch;
+ case K_CNTRLD: /* Delete autoindent char. */
+ /*
+ * If in the first column or no characters to erase,
+ * ignore the ^D (this matches historic practice). If
+ * not doing autoindent or already inserted non-ai
+ * characters, it's a literal. The latter test is done
+ * in the switch, as the CARAT forms are N + 1, not N.
+ */
+ if (!LF_ISSET(TXT_AUTOINDENT))
+ goto ins_ch;
+ if (sp->cno == 0)
+ break;
+ switch (carat_st) {
+ case C_CARATSET: /* ^^D */
+ if (sp->cno > tp->ai + tp->offset + 1)
+ goto ins_ch;
+ /* Save the ai string for later. */
+ ait.lb = NULL;
+ ait.lb_len = 0;
+ BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai);
+ memmove(ait.lb, tp->lb, tp->ai);
+ ait.ai = ait.len = tp->ai;
+
+ carat_st = C_NOCHANGE;
+ goto leftmargin;
+ case C_ZEROSET: /* 0^D */
+ if (sp->cno > tp->ai + tp->offset + 1)
+ goto ins_ch;
+ carat_st = C_NOTSET;
+leftmargin: tp->lb[sp->cno - 1] = ' ';
+ tp->owrite += sp->cno - tp->offset;
+ tp->ai = 0;
+ sp->cno = tp->offset;
+ break;
+ case C_NOTSET: /* ^D */
+ if (sp->cno > tp->ai + tp->offset)
+ goto ins_ch;
+ (void)txt_outdent(sp, tp);
+ break;
+ default:
+ abort();
+ }
+ break;
+ case K_VERASE: /* Erase the last character. */
+ /*
+ * If can erase over the prompt, return. Len is 0
+ * if backspaced over the prompt, 1 if only CR entered.
+ */
+ if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
+ tp->len = 0;
+ goto ret;
+ }
+
+ /*
+ * If at the beginning of the line, try and drop back
+ * to a previously inserted line.
+ */
+ if (sp->cno == 0) {
+ if ((ntp = txt_backup(sp,
+ ep, tiqh, tp, &flags)) == NULL)
+ goto err;
+ tp = ntp;
+ break;
+ }
+
+ /* If nothing to erase, bell the user. */
+ if (sp->cno <= tp->offset) {
+ msgq(sp, M_BERR,
+ "No more characters to erase");
+ break;
+ }
+
+ /* Drop back one character. */
+ --sp->cno;
+
+ /*
+ * Increment overwrite, decrement ai if deleted.
+ *
+ * !!!
+ * Historic vi did not permit users to use erase
+ * characters to delete autoindent characters.
+ */
+ ++tp->owrite;
+ if (sp->cno < tp->ai)
+ --tp->ai;
+ break;
+ case K_VWERASE: /* Skip back one word. */
+ /*
+ * If at the beginning of the line, try and drop back
+ * to a previously inserted line.
+ */
+ if (sp->cno == 0) {
+ if ((ntp = txt_backup(sp,
+ ep, tiqh, tp, &flags)) == NULL)
+ goto err;
+ tp = ntp;
+ }
+
+ /*
+ * If at offset, nothing to erase so bell the user.
+ */
+ if (sp->cno <= tp->offset) {
+ msgq(sp, M_BERR,
+ "No more characters to erase");
+ break;
+ }
+
+ /*
+ * First werase goes back to any autoindent
+ * and second werase goes back to the offset.
+ *
+ * !!!
+ * Historic vi did not permit users to use erase
+ * characters to delete autoindent characters.
+ */
+ if (tp->ai && sp->cno > tp->ai)
+ max = tp->ai;
+ else {
+ tp->ai = 0;
+ max = tp->offset;
+ }
+
+ /* Skip over trailing space characters. */
+ while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
+ --sp->cno;
+ ++tp->owrite;
+ }
+ if (sp->cno == max)
+ break;
+ /*
+ * There are three types of word erase found on UNIX
+ * systems. They can be identified by how the string
+ * /a/b/c is treated -- as 1, 3, or 6 words. Historic
+ * vi had two classes of characters, and strings were
+ * delimited by them and <blank>'s, so, 6 words. The
+ * historic tty interface used <blank>'s to delimit
+ * strings, so, 1 word. The algorithm offered in the
+ * 4.4BSD tty interface (as stty altwerase) treats it
+ * as 3 words -- there are two classes of characters,
+ * and strings are delimited by them and <blank>'s.
+ * The difference is that the type of the first erased
+ * character erased is ignored, which is exactly right
+ * when erasing pathname components. Here, the options
+ * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
+ * 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;
+ ++tp->owrite;
+ if (isblank(tp->lb[sp->cno - 1]))
+ break;
+ }
+ else {
+ if (LF_ISSET(TXT_ALTWERASE)) {
+ --sp->cno;
+ ++tp->owrite;
+ if (isblank(tp->lb[sp->cno - 1]))
+ break;
+ }
+ if (sp->cno > max)
+ tmp = inword(tp->lb[sp->cno - 1]);
+ while (sp->cno > max) {
+ --sp->cno;
+ ++tp->owrite;
+ if (tmp != inword(tp->lb[sp->cno - 1])
+ || isblank(tp->lb[sp->cno - 1]))
+ break;
+ }
+ }
+ break;
+ case K_VKILL: /* Restart this line. */
+ /*
+ * If at the beginning of the line, try and drop back
+ * to a previously inserted line.
+ */
+ if (sp->cno == 0) {
+ if ((ntp = txt_backup(sp,
+ ep, tiqh, tp, &flags)) == NULL)
+ goto err;
+ tp = ntp;
+ }
+
+ /* If at offset, nothing to erase so bell the user. */
+ if (sp->cno <= tp->offset) {
+ msgq(sp, M_BERR,
+ "No more characters to erase");
+ break;
+ }
+
+ /*
+ * First kill goes back to any autoindent
+ * and second kill goes back to the offset.
+ *
+ * !!!
+ * Historic vi did not permit users to use erase
+ * characters to delete autoindent characters.
+ */
+ if (tp->ai && sp->cno > tp->ai)
+ max = tp->ai;
+ else {
+ tp->ai = 0;
+ max = tp->offset;
+ }
+ tp->owrite += sp->cno - max;
+ sp->cno = max;
+ break;
+ case K_CNTRLT: /* Add autoindent char. */
+ if (!LF_ISSET(TXT_CNTRLT))
+ goto ins_ch;
+ if (txt_indent(sp, tp))
+ goto err;
+ goto ebuf_chk;
+#ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_SUSPEND
+ case K_CNTRLZ:
+ /*
+ * XXX
+ * Note, historically suspend triggered an autowrite.
+ * That needs to be done to make this work correctly.
+ */
+ (void)sp->s_suspend(sp);
+ break;
+#endif
+#ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
+ case K_FORMFEED:
+ F_SET(sp, S_REFRESH);
+ break;
+#endif
+ case K_RIGHTBRACE:
+ case K_RIGHTPAREN:
+ showmatch = LF_ISSET(TXT_SHOWMATCH);
+ goto ins_ch;
+ case K_VLNEXT: /* Quote the next character. */
+ ch = '^';
+ quoted = Q_NEXTCHAR;
+ /*
+ * If there are no keys in the queue, reset the tty
+ * so that the user can enter a ^C, ^Q, ^S. There's
+ * an obvious race here, if the user entered the ^C
+ * already. There's nothing that we can do to fix
+ * that problem.
+ */
+ if (!KEYS_WAITING(sp) && !tcgetattr(STDIN_FILENO, &t)) {
+ t.c_lflag &= ~ISIG;
+ sig_ix = t.c_iflag & (IXON | IXOFF);
+ t.c_iflag &= ~(IXON | IXOFF);
+ sig_reset = 1;
+ (void)tcsetattr(STDIN_FILENO,
+ TCSASOFT | TCSADRAIN, &t);
+ }
+ /*
+ * XXX
+ * Pass the tests for abbreviations, so ":ab xa XA",
+ * "ixa^V<space>" works. Historic vi did something
+ * weird here: ":ab x y", "ix\<space>" resulted in
+ * "<space>x\", for some unknown reason. Had to be
+ * a bug.
+ */
+ goto insl_ch;
+ case K_HEXCHAR:
+ hex = H_NEXTCHAR;
+ goto insq_ch;
+ default: /* Insert the character. */
+ins_ch: /*
+ * 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. If entering a blank character,
+ * check for unmap commands, as well.
+ */
+ 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 (abb != A_NOTSET)
+ abb = inword(ch) ? A_INWORD : A_NOTWORD;
+
+insl_ch: if (tp->owrite) /* Overwrite a character. */
+ --tp->owrite;
+ else if (tp->insert) { /* Insert a character. */
+ ++tp->len;
+ if (tp->insert == 1)
+ tp->lb[sp->cno + 1] = tp->lb[sp->cno];
+ else
+ memmove(tp->lb + sp->cno + 1,
+ tp->lb + sp->cno, tp->insert);
+ }
+
+ tp->lb[sp->cno++] = ch;
+
+ /* Check to see if we've crossed the margin. */
+ if (margin) {
+ if (sp->s_column(sp, ep, &col))
+ goto err;
+ if (col >= margin) {
+ if (txt_margin(sp,
+ tp, &ch, &wmt, flags, &tmp))
+ goto err;
+ if (tmp) {
+ if (isblank(ch))
+ wmskip = 1;
+ wmset = 1;
+ goto k_cr;
+ }
+ }
+ }
+
+ /*
+ * If we've reached the end of the buffer, then we
+ * need to switch into insert mode. This happens
+ * when there's a change to a mark and the user puts
+ * in more characters than the length of the motion.
+ */
+ebuf_chk: if (sp->cno >= tp->len) {
+ BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
+ LF_SET(TXT_APPENDEOL);
+ tp->lb[sp->cno] = CH_CURSOR;
+ ++tp->insert;
+ ++tp->len;
+ }
+
+ if (hex == H_NEXTCHAR)
+ hex = H_INHEX;
+ if (quoted == Q_NEXTCHAR)
+ quoted = Q_THISCHAR;
+ break;
+ }
+#if defined(DEBUG) && 1
+ if (sp->cno + tp->insert + tp->owrite != tp->len)
+ msgq(sp, M_ERR,
+ "len %u != cno: %u ai: %u insert %u overwrite %u",
+ tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
+ tp->len = sp->cno + tp->insert + tp->owrite;
+#endif
+ }
+
+ /* Clear input flag. */
+ret: F_CLR(sp, S_INPUT);
+
+ if (LF_ISSET(TXT_RECORD))
+ VIP(sp)->rep_cnt = rcol;
+ return (eval);
+
+err: /* Error jumps. */
+binc_err:
+ eval = 1;
+ txt_err(sp, ep, tiqh);
+ goto ret;
+}
+
+/*
+ * txt_abbrev --
+ * Handle abbreviations.
+ */
+static int
+txt_abbrev(sp, tp, pushcp, isinfoline, didsubp, turnoffp)
+ SCR *sp;
+ TEXT *tp;
+ CHAR_T *pushcp;
+ int isinfoline, *didsubp, *turnoffp;
+{
+ CHAR_T ch;
+ SEQ *qp;
+ size_t len, off;
+ char *p;
+
+ /*
+ * Find the start of the "word". Historically, abbreviations
+ * could be preceded by any non-word character or the beginning
+ * of the entry, .e.g inserting an abbreviated string in the
+ * middle of another string triggered the replacement.
+ */
+ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
+ if (!inword(*p)) {
+ ++p;
+ break;
+ }
+ ++len;
+ if (off == tp->ai || off == tp->offset)
+ break;
+ }
+
+ /*
+ * !!!
+ * Historic vi exploded abbreviations on the command line. This has
+ * obvious problems in that unabbreviating the string can be extremely
+ * tricky, particularly if the string has, say, an embedded escape
+ * character. Personally, I think it's a stunningly bad idea. Other
+ * examples of problems this caused in historic vi are:
+ * :ab foo bar
+ * :ab foo baz
+ * results in "bar" being abbreviated to "baz", which wasn't what the
+ * user had in mind at all. Also, the commands:
+ * :ab foo bar
+ * :unab foo<space>
+ * resulted in an error message that "bar" wasn't mapped. Finally,
+ * since the string was already exploded by the time the unabbreviate
+ * command got it, all it knew was that an abbreviation had occurred.
+ * Cleverly, it checked the replacement string for its unabbreviation
+ * match, which meant that the commands:
+ * :ab foo1 bar
+ * :ab foo2 bar
+ * :unab foo2
+ * unabbreviate "foo1", and the commands:
+ * :ab foo bar
+ * :ab bar baz
+ * unabbreviate "foo"!
+ *
+ * Anyway, people neglected to first ask my opinion before they wrote
+ * macros that depend on this stuff, so, we make this work as follows.
+ * When checking for an abbreviation on the command line, 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 abbreviate or unabbreviate
+ * commands. If it is, turn abbreviations off and return as if no
+ * abbreviation was found. Note also, minor trickiness, so that if
+ * the user erases the line and starts another command, we turn the
+ * abbreviations back on.
+ *
+ * This makes the layering look like a Nachos Supreme.
+ */
+ *didsubp = 0;
+ if (isinfoline)
+ if (off == tp->ai || off == tp->offset)
+ if (ex_is_abbrev(p, len)) {
+ *turnoffp = 1;
+ return (0);
+ } else
+ *turnoffp = 0;
+ else
+ if (*turnoffp)
+ return (0);
+
+ /* Check for any abbreviations. */
+ if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)
+ return (0);
+
+ /*
+ * Push the abbreviation onto the tty stack. Historically, characters
+ * resulting from an abbreviation expansion were themselves subject to
+ * map expansions, O_SHOWMATCH matching etc. This means the expanded
+ * characters will be re-tested for abbreviations. It's difficult to
+ * know what historic practice in this case was, since abbreviations
+ * were applied to :colon command lines, so entering abbreviations that
+ * looped was tricky, although possible. In addition, obvious loops
+ * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will
+ * silently only implement and/or display the last abbreviation.)
+ *
+ * This implementation doesn't recover well from such abbreviations.
+ * The main input loop counts abbreviated characters, and, when it
+ * reaches a limit, discards any abbreviated characters on the queue.
+ * It's difficult to back up to the original position, as the replay
+ * queue would have to be adjusted, and the line state when an initial
+ * abbreviated character was received would have to be saved.
+ */
+ ch = *pushcp;
+ if (term_push(sp, &ch, 1, CH_ABBREVIATED))
+ return (1);
+ if (term_push(sp, qp->output, qp->olen, CH_ABBREVIATED))
+ return (1);
+
+ /* Move to the start of the abbreviation, adjust the length. */
+ sp->cno -= len;
+ tp->len -= len;
+
+ /* Copy any insert characters back. */
+ if (tp->insert)
+ memmove(tp->lb + sp->cno + tp->owrite,
+ tp->lb + sp->cno + tp->owrite + len, tp->insert);
+
+ /*
+ * We return the length of the abbreviated characters. This is so
+ * the calling routine can replace the replay characters with the
+ * abbreviation. This means that subsequent '.' commands will produce
+ * the same text, regardless of intervening :[un]abbreviate commands.
+ * This is historic practice.
+ */
+ *didsubp = len;
+ 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;
+}
+
+/*
+ * txt_ai_resolve --
+ * When a line is resolved by <esc> or <cr>, review autoindent
+ * characters.
+ */
+static void
+txt_ai_resolve(sp, tp)
+ SCR *sp;
+ TEXT *tp;
+{
+ u_long ts;
+ int del;
+ size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
+ char *p;
+
+ /*
+ * If the line is empty, has an offset, or no autoindent
+ * characters, we're done.
+ */
+ if (!tp->len || tp->offset || !tp->ai)
+ return;
+
+ /*
+ * If the length is less than or equal to the autoindent
+ * characters, delete them.
+ */
+ if (tp->len <= tp->ai) {
+ tp->len = tp->ai = 0;
+ if (tp->lno == sp->lno)
+ sp->cno = 0;
+ return;
+ }
+
+ /*
+ * The autoindent characters plus any leading <blank> characters
+ * in the line are resolved into the minimum number of characters.
+ * Historic practice.
+ */
+ ts = O_VAL(sp, O_TABSTOP);
+
+ /* Figure out the last <blank> screen column. */
+ for (p = tp->lb, scno = 0, len = tp->len,
+ spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
+ if (*p == '\t') {
+ if (spaces)
+ tab_after_sp = 1;
+ scno += STOP_OFF(scno, ts);
+ } else {
+ ++spaces;
+ ++scno;
+ }
+
+ /*
+ * If there are no spaces, or no tabs after spaces and less than
+ * ts spaces, it's already minimal.
+ */
+ if (!spaces || !tab_after_sp && spaces < ts)
+ return;
+
+ /* Count up spaces/tabs needed to get to the target. */
+ for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
+ cno += STOP_OFF(cno, ts);
+ spaces = scno - cno;
+
+ /*
+ * Figure out how many characters we're dropping -- if we're not
+ * dropping any, it's already minimal, we're done.
+ */
+ old = p - tp->lb;
+ new = spaces + tabs;
+ if (old == new)
+ return;
+
+ /* Shift the rest of the characters down, adjust the counts. */
+ del = old - new;
+ memmove(p - del, p, tp->len - old);
+ tp->len -= del;
+
+ /* If the cursor was on this line, adjust it as well. */
+ if (sp->lno == tp->lno)
+ sp->cno -= del;
+
+ /* Fill in space/tab characters. */
+ for (p = tp->lb; tabs--;)
+ *p++ = '\t';
+ while (spaces--)
+ *p++ = ' ';
+}
+
+/*
+ * txt_auto --
+ * Handle autoindent. If aitp isn't NULL, use it, otherwise,
+ * retrieve the line.
+ */
+int
+txt_auto(sp, ep, lno, aitp, len, tp)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ size_t len;
+ TEXT *aitp, *tp;
+{
+ size_t nlen;
+ char *p, *t;
+
+ if (aitp == NULL) {
+ /*
+ * If the ex append command is executed with an address of 0,
+ * it's possible to get here with a line number of 0. Return
+ * an indent of 0.
+ */
+ if (lno == 0) {
+ tp->ai = 0;
+ return (0);
+ }
+ if ((t = file_gline(sp, ep, lno, &len)) == NULL)
+ return (1);
+ } else
+ t = aitp->lb;
+
+ /* Count whitespace characters. */
+ for (p = t; len > 0; ++p, --len)
+ if (!isblank(*p))
+ break;
+
+ /* Set count, check for no indentation. */
+ if ((nlen = (p - t)) == 0)
+ return (0);
+
+ /* 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, t, nlen);
+
+ /* Set the autoindent count. */
+ tp->ai = nlen;
+ return (0);
+}
+
+/*
+ * txt_backup --
+ * Back up to the previously edited line.
+ */
+static TEXT *
+txt_backup(sp, ep, tiqh, tp, flagsp)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+ TEXT *tp;
+ u_int *flagsp;
+{
+ TEXT *ntp;
+ u_int flags;
+
+ /* Get a handle on the previous TEXT structure. */
+ if ((ntp = tp->q.cqe_prev) == (void *)tiqh) {
+ msgq(sp, M_BERR, "Already at the beginning of the insert");
+ return (tp);
+ }
+
+ /* Reset the cursor, bookkeeping. */
+ sp->lno = ntp->lno;
+ sp->cno = ntp->sv_cno;
+ ntp->len = ntp->sv_len;
+
+ /* Handle appending to the line. */
+ flags = *flagsp;
+ if (ntp->owrite == 0 && ntp->insert == 0) {
+ ntp->lb[ntp->len] = CH_CURSOR;
+ ++ntp->insert;
+ ++ntp->len;
+ LF_SET(TXT_APPENDEOL);
+ } else
+ LF_CLR(TXT_APPENDEOL);
+ *flagsp = flags;
+
+ /* Release the current TEXT. */
+ CIRCLEQ_REMOVE(tiqh, tp, q);
+ text_free(tp);
+
+ /* Update the old line on the screen. */
+ if (sp->s_change(sp, ep, ntp->lno + 1, LINE_DELETE))
+ return (NULL);
+
+ /* Return the new/current TEXT. */
+ return (ntp);
+}
+
+/*
+ * txt_err --
+ * Handle an error during input processing.
+ */
+static void
+txt_err(sp, ep, tiqh)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+{
+ recno_t lno;
+ size_t len;
+
+ /*
+ * The problem with input processing is that the cursor is at an
+ * indeterminate position since some input may have been lost due
+ * to a malloc error. So, try to go back to the place from which
+ * the cursor started, knowing that it may no longer be available.
+ *
+ * We depend on at least one line number being set in the text
+ * chain.
+ */
+ for (lno = tiqh->cqh_first->lno;
+ file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
+
+ sp->lno = lno == 0 ? 1 : lno;
+ sp->cno = 0;
+
+ /* Redraw the screen, just in case. */
+ F_SET(sp, S_REDRAW);
+}
+
+/*
+ * txt_hex --
+ * Let the user insert any character value they want.
+ *
+ * !!!
+ * This is an extension. The pattern "^X[0-9a-fA-F]*" is a way
+ * for the user to specify a character value which their keyboard
+ * may not be able to enter.
+ */
+static int
+txt_hex(sp, tp)
+ SCR *sp;
+ TEXT *tp;
+{
+ CHAR_T savec;
+ size_t len, off;
+ u_long value;
+ char *p, *wp;
+
+ /*
+ * Null-terminate the string. Since nul isn't a legal hex value,
+ * this should be okay, and lets us use a local routine, which
+ * presumably understands the character set, to convert the value.
+ */
+ savec = tp->lb[sp->cno];
+ tp->lb[sp->cno] = 0;
+
+ /* Find the previous CH_HEX character. */
+ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off, ++len) {
+ if (*p == CH_HEX) {
+ wp = p + 1;
+ break;
+ }
+ /* Not on this line? Shouldn't happen. */
+ if (off == tp->ai || off == tp->offset)
+ goto nothex;
+ }
+
+ /* If length of 0, then it wasn't a hex value. */
+ if (len == 0)
+ goto nothex;
+
+ /* Get the value. */
+ errno = 0;
+ value = strtol(wp, NULL, 16);
+ if (errno || value > MAX_CHAR_T) {
+nothex: tp->lb[sp->cno] = savec;
+ return (0);
+ }
+
+ /* Restore the original character. */
+ tp->lb[sp->cno] = savec;
+
+ /* Adjust the bookkeeping. */
+ sp->cno -= len;
+ tp->len -= len;
+ tp->lb[sp->cno - 1] = value;
+
+ /* Copy down any overwrite characters. */
+ if (tp->owrite)
+ memmove(tp->lb + sp->cno,
+ tp->lb + sp->cno + len, tp->owrite);
+
+ /* Copy down any insert characters. */
+ if (tp->insert)
+ memmove(tp->lb + sp->cno + tp->owrite,
+ tp->lb + sp->cno + tp->owrite + len, tp->insert);
+
+ return (0);
+}
+
+/*
+ * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
+ * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
+ * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
+ * the 10th column, and ^D moves it back.
+ *
+ * !!!
+ * The ^T and ^D characters in historical vi only had special meaning when
+ * they were the first characters typed after entering text input mode.
+ * Since normal erase characters couldn't erase autoindent (in this case
+ * ^T) characters, this meant that inserting text into previously existing
+ * text was quite strange, ^T only worked if it was the first keystroke,
+ * and then it could only be erased by using ^D. This implementation treats
+ * ^T specially anywhere it occurs in the input, and permits the standard
+ * erase characters to erase characters inserted using it.
+ *
+ * XXX
+ * Technically, txt_indent, txt_outdent should part of the screen interface,
+ * as they require knowledge of the size of a space character on the screen.
+ * (Not the size of tabs, because tabs are logically composed of spaces.)
+ * They're left in the text code because they're complicated, not to mention
+ * the gruesome awareness that if spaces aren't a single column on the screen
+ * for any language, we're into some serious, ah, for lack of a better word,
+ * "issues".
+ */
+
+/*
+ * txt_indent --
+ * Handle ^T indents.
+ */
+static int
+txt_indent(sp, tp)
+ SCR *sp;
+ TEXT *tp;
+{
+ u_long sw, ts;
+ size_t cno, off, scno, spaces, tabs;
+
+ ts = O_VAL(sp, O_TABSTOP);
+ sw = O_VAL(sp, O_SHIFTWIDTH);
+
+ /* Get the current screen column. */
+ for (off = scno = 0; off < sp->cno; ++off)
+ if (tp->lb[off] == '\t')
+ scno += STOP_OFF(scno, ts);
+ else
+ ++scno;
+
+ /* Count up spaces/tabs needed to get to the target. */
+ for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
+ cno + STOP_OFF(cno, ts) <= scno; ++tabs)
+ cno += STOP_OFF(cno, ts);
+ spaces = scno - cno;
+
+ /* Put space/tab characters in place of any overwrite characters. */
+ for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
+ tp->lb[sp->cno++] = '\t';
+ for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
+ tp->lb[sp->cno++] = ' ';
+
+ if (!tabs && !spaces)
+ return (0);
+
+ /* Make sure there's enough room. */
+ BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
+
+ /* Move the insert characters out of the way. */
+ if (tp->insert)
+ memmove(tp->lb + sp->cno + spaces + tabs,
+ tp->lb + sp->cno, tp->insert);
+
+ /* Add new space/tab characters. */
+ for (; tabs--; ++tp->len, ++tp->ai)
+ tp->lb[sp->cno++] = '\t';
+ for (; spaces--; ++tp->len, ++tp->ai)
+ tp->lb[sp->cno++] = ' ';
+ return (0);
+}
+
+/*
+ * txt_outdent --
+ * Handle ^D outdents.
+ *
+ */
+static int
+txt_outdent(sp, tp)
+ SCR *sp;
+ TEXT *tp;
+{
+ u_long sw, ts;
+ size_t cno, off, scno, spaces;
+
+ ts = O_VAL(sp, O_TABSTOP);
+ sw = O_VAL(sp, O_SHIFTWIDTH);
+
+ /* Get the current screen column. */
+ for (off = scno = 0; off < sp->cno; ++off)
+ if (tp->lb[off] == '\t')
+ scno += STOP_OFF(scno, ts);
+ else
+ ++scno;
+
+ /* Get the previous shiftwidth column. */
+ for (cno = scno; --scno % sw != 0;);
+
+ /* Decrement characters until less than or equal to that slot. */
+ for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
+ if (tp->lb[--off] == '\t')
+ cno -= STOP_OFF(cno, ts);
+ else
+ --cno;
+
+ /* Spaces needed to get to the target. */
+ spaces = scno - cno;
+
+ /* Maybe just a delete. */
+ if (spaces == 0)
+ return (0);
+
+ /* Make sure there's enough room. */
+ BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);
+
+ /* Use up any overwrite characters. */
+ for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
+ tp->lb[sp->cno++] = ' ';
+
+ /* Maybe that was enough. */
+ if (spaces == 0)
+ return (0);
+
+ /* Move the insert characters out of the way. */
+ if (tp->insert)
+ memmove(tp->lb + sp->cno + spaces,
+ tp->lb + sp->cno, tp->insert);
+
+ /* Add new space characters. */
+ for (; spaces--; ++tp->len, ++tp->ai)
+ tp->lb[sp->cno++] = ' ';
+ return (0);
+}
+
+/*
+ * txt_resolve --
+ * Resolve the input text chain into the file.
+ */
+static int
+txt_resolve(sp, ep, tiqh, flags)
+ SCR *sp;
+ EXF *ep;
+ TEXTH *tiqh;
+ u_int flags;
+{
+ TEXT *tp;
+ recno_t lno;
+
+ /*
+ * The first line replaces a current line, and all subsequent lines
+ * are appended into the file. Resolve autoindented characters for
+ * each line before committing it.
+ */
+ tp = tiqh->cqh_first;
+ if (LF_ISSET(TXT_AUTOINDENT))
+ txt_ai_resolve(sp, tp);
+ if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
+ return (1);
+
+ for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)sp->tiqp; ++lno) {
+ if (LF_ISSET(TXT_AUTOINDENT))
+ txt_ai_resolve(sp, tp);
+ if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * txt_showmatch --
+ * Show a character match.
+ *
+ * !!!
+ * Historic vi tried to display matches even in the :colon command line.
+ * I think not.
+ */
+static void
+txt_showmatch(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct timeval second;
+ VCS cs;
+ MARK m;
+ fd_set zero;
+ int cnt, endc, startc;
+
+ /*
+ * Do a refresh first, in case the v_ntext() code hasn't done
+ * one in awhile, so the user can see what we're complaining
+ * about.
+ */
+ if (sp->s_refresh(sp, ep))
+ return;
+ /*
+ * We don't display the match if it's not on the screen. Find
+ * out what the first character on the screen is.
+ */
+ if (sp->s_position(sp, ep, &m, 0, P_TOP))
+ return;
+
+ /* Initialize the getc() interface. */
+ cs.cs_lno = sp->lno;
+ cs.cs_cno = sp->cno - 1;
+ if (cs_init(sp, ep, &cs))
+ return;
+ startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
+
+ /* Search for the match. */
+ for (cnt = 1;;) {
+ if (cs_prev(sp, ep, &cs))
+ return;
+ if (cs.cs_lno < m.lno ||
+ cs.cs_lno == m.lno && cs.cs_cno < m.cno)
+ return;
+ if (cs.cs_flags != 0) {
+ if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
+ (void)sp->s_bell(sp);
+ return;
+ }
+ continue;
+ }
+ if (cs.cs_ch == endc)
+ ++cnt;
+ else if (cs.cs_ch == startc && --cnt == 0)
+ break;
+ }
+
+ /* Move to the match. */
+ m.lno = sp->lno;
+ m.cno = sp->cno;
+ sp->lno = cs.cs_lno;
+ sp->cno = cs.cs_cno;
+ (void)sp->s_refresh(sp, ep);
+
+ /*
+ * Sleep(3) is eight system calls. Do it fast -- besides,
+ * I don't want to wait an entire second.
+ */
+ FD_ZERO(&zero);
+ second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
+ second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
+ (void)select(0, &zero, &zero, &zero, &second);
+
+ /* Return to the current location. */
+ sp->lno = m.lno;
+ sp->cno = m.cno;
+ (void)sp->s_refresh(sp, ep);
+}
+
+/*
+ * txt_margin --
+ * Handle margin wrap.
+ */
+static int
+txt_margin(sp, tp, chp, wmtp, flags, didbreak)
+ SCR *sp;
+ TEXT *tp, *wmtp;
+ CHAR_T *chp;
+ int *didbreak;
+ u_int flags;
+{
+ size_t len, off;
+ char *p, *wp;
+
+ /* Find the nearest previous blank. */
+ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --off, --p, ++len) {
+ if (isblank(*p)) {
+ wp = p + 1;
+ break;
+ }
+
+ /*
+ * If reach the start of the line, there's nowhere to break.
+ *
+ * !!!
+ * Historic vi belled each time a character was entered after
+ * crossing the margin until a space was entered which could
+ * be used to break the line. I don't as it tends to wake the
+ * cats.
+ */
+ if (off == tp->ai || off == tp->offset) {
+ *didbreak = 0;
+ return (0);
+ }
+ }
+
+ /*
+ * Store saved information about the rest of the line in the
+ * wrapmargin TEXT structure.
+ */
+ wmtp->lb = p + 1;
+ wmtp->len = len;
+ wmtp->insert = LF_ISSET(TXT_APPENDEOL) ? tp->insert - 1 : tp->insert;
+ wmtp->owrite = tp->owrite;
+
+ /* Correct current bookkeeping information. */
+ sp->cno -= len;
+ if (LF_ISSET(TXT_APPENDEOL)) {
+ tp->len -= len + tp->owrite + (tp->insert - 1);
+ tp->insert = 1;
+ } else {
+ tp->len -= len + tp->owrite + tp->insert;
+ tp->insert = 0;
+ }
+ tp->owrite = 0;
+
+ /*
+ * !!!
+ * Delete any trailing whitespace from the current line.
+ */
+ for (;; --p, --off) {
+ if (!isblank(*p))
+ break;
+ --sp->cno;
+ --tp->len;
+ if (off == tp->ai || off == tp->offset)
+ break;
+ }
+ *didbreak = 1;
+ return (0);
+}
+
+/*
+ * txt_Rcleanup --
+ * Resolve the input line for the 'R' command.
+ */
+static void
+txt_Rcleanup(sp, tiqh, tp, lp, olen)
+ SCR *sp;
+ TEXTH *tiqh;
+ TEXT *tp;
+ const char *lp;
+ const size_t olen;
+{
+ TEXT *ttp;
+ size_t ilen, tmp;
+
+ /*
+ * Check to make sure that the cursor hasn't moved beyond
+ * the end of the line.
+ */
+ if (tp->owrite == 0)
+ return;
+
+ /*
+ * Calculate how many characters the user has entered,
+ * plus the blanks erased by <carriage-return>/<newline>s.
+ */
+ for (ttp = tiqh->cqh_first, ilen = 0;;) {
+ ilen += ttp == tp ? sp->cno : ttp->len + ttp->R_erase;
+ if ((ttp = ttp->q.cqe_next) == (void *)sp->tiqp)
+ break;
+ }
+
+ /*
+ * If the user has entered less characters than the original line
+ * was long, restore any overwriteable characters to the original
+ * characters, and make them insert characters. We don't copy them
+ * anywhere, because the 'R' command doesn't have insert characters.
+ */
+ if (ilen < olen) {
+ tmp = MIN(tp->owrite, olen - ilen);
+ memmove(tp->lb + sp->cno, lp + ilen, tmp);
+ tp->owrite -= tmp;
+ tp->insert += tmp;
+ }
+}
diff --git a/usr.bin/vi/vi/v_paragraph.c b/usr.bin/vi/vi/v_paragraph.c
new file mode 100644
index 000000000000..590718dd7fdb
--- /dev/null
+++ b/usr.bin/vi/vi/v_paragraph.c
@@ -0,0 +1,370 @@
+/*-
+ * 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_paragraph.c 8.18 (Berkeley) 7/29/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+#define INTEXT_CHECK { \
+ if (len == 0 || v_isempty(p, len)) { \
+ if (!--cnt) \
+ goto found; \
+ pstate = P_INBLANK; \
+ } \
+ /* \
+ * !!! \
+ * Historic documentation (USD:15-11, 4.2) said that formfeed \
+ * characters (^L) in the first column delimited paragraphs. \
+ * The historic vi code mentions formfeed characters, but never \
+ * implements them. It seems reasonable, do it. \
+ */ \
+ if (p[0] == '\014') { \
+ if (!--cnt) \
+ goto found; \
+ continue; \
+ } \
+ if (p[0] != '.' || len < 2) \
+ continue; \
+ for (lp = VIP(sp)->ps; *lp != '\0'; lp += 2) \
+ if (lp[0] == p[1] && \
+ (lp[1] == ' ' && len == 2 || lp[1] == p[2]) && \
+ !--cnt) \
+ goto found; \
+}
+
+/*
+ * v_paragraphf -- [count]}
+ * Move forward count paragraphs.
+ *
+ * Paragraphs are empty lines after text, formfeed characters, or values
+ * from the paragraph or section options.
+ */
+int
+v_paragraphf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ 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 = 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.
+ */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cnt *= 2;
+ if (len == 0 || v_isempty(p, len))
+ pstate = P_INBLANK;
+ else {
+ --cnt;
+ pstate = P_INTEXT;
+ }
+
+ for (;;) {
+ lastlno = lno;
+ lastlen = len;
+ if ((p = file_gline(sp, ep, ++lno, &len)) == NULL)
+ goto eof;
+ switch (pstate) {
+ case P_INTEXT:
+ INTEXT_CHECK;
+ break;
+ case P_INBLANK:
+ if (len == 0 || v_isempty(p, len))
+ break;
+ if (--cnt) {
+ pstate = P_INTEXT;
+ break;
+ }
+ /*
+ * !!!
+ * Non-motion commands move to the end of the range,
+ * VC_D and VC_Y stay at the start. Ignore VC_C and
+ * VC_DEF. Adjust the 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 (ISMOTION(vp)) {
+ vp->m_stop.lno = lastlno;
+ vp->m_stop.cno = lastlen ? lastlen - 1 : 0;
+ vp->m_final = vp->m_start;
+ } else {
+ vp->m_stop.lno = lno;
+ vp->m_stop.cno = 0;
+ vp->m_final = vp->m_stop;
+ }
+ return (0);
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * !!!
+ * 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. It also historically worked on empty files, so we
+ * have to make it okay.
+ */
+eof: if (vp->m_start.lno == lno || vp->m_start.lno == lno - 1) {
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (vp->m_start.lno != 1 || lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ vp->m_start.cno = 0;
+ return (0);
+ }
+ if (vp->m_start.cno == (len ? len - 1 : 0)) {
+ v_eof(sp, ep, NULL);
+ return (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_DEF.
+ *
+ * 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);
+ }
+ 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 backward count paragraphs.
+ */
+int
+v_paragraphb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum { P_INTEXT, P_INBLANK } pstate;
+ size_t len;
+ recno_t cnt, lno;
+ 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.
+ *
+ * !!!
+ * 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.
+ */
+ 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. */
+ 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.
+ */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ cnt *= 2;
+ if (len == 0 || v_isempty(p, len))
+ pstate = P_INBLANK;
+ else {
+ --cnt;
+ pstate = P_INTEXT;
+
+ /*
+ * !!!
+ * If the starting cursor is past the first column,
+ * the current line is checked for a paragraph.
+ */
+ if (vp->m_start.cno > 0)
+ ++lno;
+ }
+
+ for (;;) {
+ if ((p = file_gline(sp, ep, --lno, &len)) == NULL)
+ goto sof;
+ switch (pstate) {
+ case P_INTEXT:
+ INTEXT_CHECK;
+ break;
+ case P_INBLANK:
+ if (len != 0 && !v_isempty(p, len)) {
+ if (!--cnt)
+ goto found;
+ pstate = P_INTEXT;
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /* SOF is a movement sink. */
+sof: lno = 1;
+
+found: vp->m_stop.lno = lno;
+ vp->m_stop.cno = 0;
+
+ /*
+ * All commands move to the end of the range. (We already
+ * adjusted the start of the range for motion commands).
+ */
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_buildps --
+ * Build the paragraph command search pattern.
+ */
+int
+v_buildps(sp)
+ SCR *sp;
+{
+ VI_PRIVATE *vip;
+ size_t p_len, s_len;
+ char *p, *p_p, *s_p;
+
+ /*
+ * The vi paragraph command searches for either a paragraph or
+ * section option macro.
+ */
+ p_len = (p_p = O_STR(sp, O_PARAGRAPHS)) == NULL ? 0 : strlen(p_p);
+ s_len = (s_p = O_STR(sp, O_SECTIONS)) == NULL ? 0 : strlen(s_p);
+
+ if (p_len == 0 && s_len == 0)
+ return (0);
+
+ MALLOC_RET(sp, p, char *, p_len + s_len + 1);
+
+ vip = VIP(sp);
+ if (vip->ps != NULL)
+ free(vip->ps);
+
+ if (p_p != NULL)
+ memmove(p, p_p, p_len + 1);
+ if (s_p != NULL)
+ memmove(p + p_len, s_p, s_len + 1);
+ vip->ps = p;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_put.c b/usr.bin/vi/vi/v_put.c
new file mode 100644
index 000000000000..8206d1621d35
--- /dev/null
+++ b/usr.bin/vi/vi/v_put.c
@@ -0,0 +1,168 @@
+/*-
+ * 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_put.c 8.9 (Berkeley) 5/2/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static void inc_buf __P((SCR *, VICMDARG *));
+
+/*
+ * v_Put -- [buffer]P
+ * Insert the contents of the buffer before the cursor.
+ */
+int
+v_Put(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ u_long cnt;
+
+ if (F_ISSET(vp, VC_ISDOT))
+ inc_buf(sp, vp);
+
+ /*
+ * !!!
+ * Historic vi did not support a count with the 'p' and 'P'
+ * commands. It's useful, so we do.
+ */
+ for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ if (put(sp, ep, NULL,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_final, 0))
+ return (1);
+ vp->m_start = vp->m_final;
+ }
+ return (0);
+}
+
+/*
+ * v_put -- [buffer]p
+ * Insert the contents of the buffer after the cursor.
+ */
+int
+v_put(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ u_long cnt;
+
+ if (F_ISSET(vp, VC_ISDOT))
+ inc_buf(sp, vp);
+
+ /*
+ * !!!
+ * Historic vi did not support a count with the 'p' and 'P'
+ * commands. It's useful, so we do.
+ */
+ for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ if (put(sp, ep, NULL,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_final, 1))
+ return (1);
+ vp->m_start = vp->m_final;
+ }
+ return (0);
+}
+
+/*
+ * !!!
+ * 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
+ * would be repeatedly output. This was not documented, and is a bit
+ * tricky to reconstruct. Historical versions of vi also dropped the
+ * contents of the default buffer after each put, so after `"4p' the
+ * default buffer would be empty. This makes no sense to me, so we
+ * don't bother. Don't assume sequential order of numeric characters.
+ *
+ * And, if that weren't exciting enough, failed commands don't normally
+ * set the dot command. Well, boys and girls, an exception is that
+ * the buffer increment gets done regardless of the success of the put.
+ */
+static void
+inc_buf(sp, vp)
+ SCR *sp;
+ VICMDARG *vp;
+{
+ CHAR_T v;
+
+ switch (vp->buffer) {
+ case '1':
+ v = '2';
+ break;
+ case '2':
+ v = '3';
+ break;
+ case '3':
+ v = '4';
+ break;
+ case '4':
+ v = '5';
+ break;
+ case '5':
+ v = '6';
+ break;
+ case '6':
+ v = '7';
+ break;
+ case '7':
+ v = '8';
+ break;
+ case '8':
+ v = '9';
+ break;
+ default:
+ return;
+ }
+ VIP(sp)->sdot.buffer = vp->buffer = v;
+}
diff --git a/usr.bin/vi/vi/v_redraw.c b/usr.bin/vi/vi/v_redraw.c
new file mode 100644
index 000000000000..8f7054ca9522
--- /dev/null
+++ b/usr.bin/vi/vi/v_redraw.c
@@ -0,0 +1,67 @@
+/*-
+ * 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_redraw.c 8.4 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_redraw -- ^R
+ * Redraw the screen.
+ */
+int
+v_redraw(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ F_SET(sp, S_REFRESH);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_replace.c b/usr.bin/vi/vi/v_replace.c
new file mode 100644
index 000000000000..92540242bd51
--- /dev/null
+++ b/usr.bin/vi/vi/v_replace.c
@@ -0,0 +1,194 @@
+/*-
+ * 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_replace.c 8.18 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.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.
+ */
+int
+v_replace(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ CH ikey;
+ TEXT *tp;
+ recno_t lno;
+ size_t blen, len;
+ u_long cnt;
+ int rval;
+ char *bp, *p;
+
+ /*
+ * If the line doesn't exist, or it's empty, replacement isn't
+ * allowed. It's not hard to implement, but:
+ *
+ * 1: It's historic practice.
+ * 2: For consistency, this change would require that the more
+ * general case, "Nr", when the user is < N characters from
+ * the end of the line, also work.
+ * 3: Replacing a newline has somewhat odd semantics.
+ */
+ 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, vp->m_start.lno);
+ return (1);
+ }
+ goto nochar;
+ }
+ if (len == 0) {
+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 append replacement characters
+ * to the line, but I see no compelling reason to do so.
+ */
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ 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 any character,
+ * single escapes return.
+ */
+ if (F_ISSET(vp, VC_ISDOT)) {
+ ikey.ch = VIP(sp)->rlast;
+ ikey.value = KEY_VAL(sp, ikey.ch);
+ } else {
+ sp->showmode = "Replace char";
+ (void)sp->s_refresh(sp, ep);
+
+ if (term_key(sp, &ikey, 0) != INP_OK)
+ return (1);
+ switch (ikey.value) {
+ case K_ESCAPE:
+ return (0);
+ case K_VLNEXT:
+ if (term_key(sp, &ikey, 0) != INP_OK)
+ return (1);
+ break;
+ }
+ VIP(sp)->rlast = ikey.ch;
+ }
+
+ /* Copy the line. */
+ GET_SPACE_RET(sp, bp, blen, len);
+ memmove(bp, p, len);
+ p = bp;
+
+ if (ikey.value == K_CR || ikey.value == K_NL) {
+ /* Set return line. */
+ 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, vp->m_start.lno, p, vp->m_start.cno))
+ goto err_ret;
+
+ /*
+ * The rest of the current line. And, of course, now it gets
+ * tricky. Any white space after the replaced character is
+ * stripped, and autoindent is applied. Put the cursor on the
+ * last indent character as did historic vi.
+ */
+ 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, vp->m_start.lno, NULL, 0, tp))
+ goto err_ret;
+ 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, vp->m_start.lno, "", 0)) {
+err_ret: rval = 1;
+ break;
+ }
+ } else {
+ 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/vi/v_right.c b/usr.bin/vi/vi/v_right.c
new file mode 100644
index 000000000000..df7c85ca9fc8
--- /dev/null
+++ b/usr.bin/vi/vi/v_right.c
@@ -0,0 +1,162 @@
+/*-
+ * 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_right.c 8.8 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_right -- [count]' ', [count]l
+ * Move right by columns.
+ */
+int
+v_right(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+
+ 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, vp->m_start.lno);
+ return (1);
+ }
+
+ /* It's always illegal to move right on empty lines. */
+ if (len == 0) {
+ v_eol(sp, ep, NULL);
+ return (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_DEF. 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 && !ISMOTION(vp)) {
+ v_eol(sp, ep, NULL);
+ return (1);
+ }
+ if (vp->m_stop.cno >= len) {
+ vp->m_stop.cno = len - 1;
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ } else if (ISMOTION(vp)) {
+ --vp->m_stop.cno;
+ vp->m_final = vp->m_start;
+ } else
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_dollar -- [count]$
+ * Move to the last column.
+ */
+int
+v_dollar(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+
+ /*
+ * !!!
+ * A count moves down count - 1 rows, so, "3$" is the same as "2j$".
+ */
+ 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);
+ 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 (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, vp->m_start.lno);
+ return (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_DEF.
+ */
+ 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/vi/v_screen.c b/usr.bin/vi/vi/v_screen.c
new file mode 100644
index 000000000000..20ca6ba67a30
--- /dev/null
+++ b/usr.bin/vi/vi/v_screen.c
@@ -0,0 +1,90 @@
+/*-
+ * 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[] = "@(#)v_screen.c 8.12 (Berkeley) 8/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_screen -- ^W
+ * Switch screens.
+ */
+int
+v_screen(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * Try for the next lower screen, or, go back to the first
+ * screen on the stack.
+ */
+ if (sp->q.cqe_next != (void *)&sp->gp->dq)
+ sp->nextdisp = sp->q.cqe_next;
+ else if (sp->gp->dq.cqh_first == sp) {
+ msgq(sp, M_ERR, "No other screen to switch to");
+ return (1);
+ } else
+ sp->nextdisp = sp->gp->dq.cqh_first;
+
+ /*
+ * Display the old screen's status line so the user can
+ * find the screen they want.
+ */
+ (void)msg_status(sp, ep, vp->m_start.lno, 0);
+
+ /* Save the old screen's cursor information. */
+ sp->frp->lno = sp->lno;
+ sp->frp->cno = sp->cno;
+ F_SET(sp->frp, FR_CURSORSET);
+
+ F_SET(sp, S_SSWITCH);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_scroll.c b/usr.bin/vi/vi/v_scroll.c
new file mode 100644
index 000000000000..b381dc550517
--- /dev/null
+++ b/usr.bin/vi/vi/v_scroll.c
@@ -0,0 +1,486 @@
+/*-
+ * 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_scroll.c 8.20 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.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
+ * is the right thing to do. For example, single line movements, such as
+ * 'j' or 'k', should probably work on physical lines. Commands like "dj",
+ * or "j.", where '.' is a change command, make more sense for physical lines
+ * than they do for logical lines.
+ *
+ * These arguments, however, don't apply to scrolling commands like ^D and
+ * ^F -- if the window is fairly small, using physical lines can result in
+ * a half-page scroll repainting the entire screen, which is not what the
+ * user wanted. Second, if the line is larger than the screen, using physical
+ * lines can make it impossible to display parts of the line -- there aren't
+ * any commands that don't display the beginning of the line in historic vi,
+ * and if both the beginning and end of the line can't be on the screen at
+ * the same time, you lose. This is even worse in the case of the H, L, and
+ * M commands -- for large lines, they may all refer to the same line and
+ * will result in no movement at all.
+ *
+ * Another issue is that page and half-page scrolling commands historically
+ * moved to the first non-blank character in the new line. If the line is
+ * approximately the same size as the screen, this loses because the cursor
+ * before and after a ^D, may refer to the same location on the screen. In
+ * this implementation, scrolling commands set the cursor to the first non-
+ * blank character if the line changes because of the scroll. Otherwise,
+ * the cursor is left alone.
+ *
+ * This implementation does the scrolling (^B, ^D, ^F, ^U, ^Y, ^E), and the
+ * cursor positioning commands (H, L, M) commands using logical lines, not
+ * physical.
+ */
+
+/*
+ * v_lgoto -- [count]G
+ * Go to first non-blank character of the line count, the last line
+ * of the file by default.
+ */
+int
+v_lgoto(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t nlines;
+
+ if (F_ISSET(vp, VC_C1SET)) {
+ if (file_gline(sp, ep, vp->count, NULL) == NULL) {
+ v_eof(sp, ep, &vp->m_start);
+ return (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 - 1 from the top of the screen, 0 by default.
+ */
+int
+v_home(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ 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);
+}
+
+/*
+ * v_middle -- M
+ * Move to the first non-blank character of the logical line
+ * in the middle of the screen.
+ */
+int
+v_middle(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.
+ */
+ 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 - 1 from the bottom of the screen, 0 by default.
+ */
+int
+v_bottom(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ 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;
+{
+ /* Guess that it's the end of the range. */
+ vp->m_final = vp->m_stop;
+
+ /*
+ * Non-motion commands move the cursor to the end of the range, and
+ * then to the NEXT nonblank of the line. Historic vi always moved
+ * to the first nonblank in the line; since the H, M, and L commands
+ * are logical motions in this implementation, we do the next nonblank
+ * so that it looks approximately the same to the user. To make this
+ * happen, the VM_RCM_SETNNB flag is set in the vcmd.c command table.
+ *
+ * If it's a motion, it's more complicated. The best possible solution
+ * is probably to display the first nonblank of the line the cursor
+ * will eventually rest on. This is tricky, particularly given that if
+ * the associated command is a delete, we don't yet know what line that
+ * will be. So, we clear the VM_RCM_SETNNB flag, and set the first
+ * nonblank flag (VM_RCM_SETFNB). Note, if the lines are sufficiently
+ * long, this can cause the cursor to warp out of the screen. It's too
+ * hard to fix.
+ *
+ * XXX
+ * The G command is always first nonblank, so it's okay to reset it.
+ */
+ if (ISMOTION(vp)) {
+ F_CLR(vp, VM_RCM_MASK);
+ F_SET(vp, VM_RCM_SETFNB);
+ } else
+ 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_DEF.
+ */
+ 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;
+}
+
+/*
+ * v_up -- [count]^P, [count]k, [count]-
+ * Move up by lines.
+ */
+int
+v_up(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+
+ lno = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ if (vp->m_start.lno <= lno) {
+ v_sof(sp, &vp->m_start);
+ return (1);
+ }
+ vp->m_stop.lno = vp->m_start.lno - lno;
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_cr -- [count]^M
+ * In a script window, send the line to the shell.
+ * In a regular window, move down by lines.
+ */
+int
+v_cr(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * 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, vp->m_start.lno) : v_down(sp, ep, vp));
+}
+
+/*
+ * v_down -- [count]^J, [count]^N, [count]j, [count]^M, [count]+
+ * Move down by lines.
+ */
+int
+v_down(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+
+ 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, &vp->m_start);
+ return (1);
+ }
+ vp->m_stop.lno = lno;
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_hpageup -- [count]^U
+ * Page up half screens.
+ */
+int
+v_hpageup(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * 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))
+ sp->defscroll = vp->count;
+ if (sp->s_scroll(sp, ep, &vp->m_stop, sp->defscroll, CNTRL_U))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_hpagedown -- [count]^D
+ * Page down half screens.
+ */
+int
+v_hpagedown(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * 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))
+ sp->defscroll = vp->count;
+ if (sp->s_scroll(sp, ep, &vp->m_stop, sp->defscroll, CNTRL_D))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_pagedown -- [count]^F
+ * Page down full screens.
+ * !!!
+ * Historic vi did not move to the EOF if the screen couldn't move, i.e.
+ * if EOF was already displayed on the screen. This implementation does
+ * move to EOF in that case, making ^F more like the the historic ^D.
+ */
+int
+v_pagedown(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t offset;
+
+ /*
+ * !!!
+ * The calculation in IEEE Std 1003.2-1992 (POSIX) is:
+ *
+ * top_line = top_line + count * (window - 2);
+ *
+ * which was historically wrong. The correct one is:
+ *
+ * top_line = top_line + count * window - 2;
+ *
+ * i.e. the two line "overlap" was only subtracted once. Which
+ * makes no sense, but then again, an overlap makes no sense for
+ * any screen but the "next" one anyway. We do it the historical
+ * was as there's no good reason to change it.
+ *
+ * If the screen has been split, use the smaller of the current
+ * window size and the window option value.
+ *
+ * Given a one-line screen with the cursor on line 1, it would be
+ * possible for this to fail, i.e. "1 + 1 * 1 - 2 = 0". Move at
+ * least one line.
+ */
+#define IS_SPLIT_SCREEN(sp) \
+ ((sp)->q.cqe_prev != (void *)&(sp)->gp->dq || \
+ (sp)->q.cqe_next != (void *)&(sp)->gp->dq)
+
+ offset = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) *
+ (IS_SPLIT_SCREEN(sp) ?
+ MIN(sp->t_maxrows, O_VAL(sp, O_WINDOW)) : O_VAL(sp, O_WINDOW)) - 2;
+ if (offset == 0)
+ offset = 1;
+ if (sp->s_scroll(sp, ep, &vp->m_stop, offset, CNTRL_F))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_pageup -- [count]^B
+ * Page up full screens.
+ *
+ * !!!
+ * Historic vi did not move to the SOF if the screen couldn't move, i.e.
+ * if SOF was already displayed on the screen. This implementation does
+ * move to SOF in that case, making ^B more like the the historic ^U.
+ */
+int
+v_pageup(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t offset;
+
+ /*
+ * !!!
+ * The calculation in IEEE Std 1003.2-1992 (POSIX) is:
+ *
+ * top_line = top_line - count * (window - 2);
+ *
+ * which was historically wrong. The correct one is:
+ *
+ * top_line = (top_line - count * window) + 2;
+ *
+ * A simpler expression is that, as with ^F, we scroll exactly:
+ *
+ * count * window - 2
+ *
+ * lines.
+ *
+ * Bizarre. As with ^F, an overlap makes no sense for anything
+ * but the first screen. We do it the historical way as there's
+ * no good reason to change it.
+ *
+ * If the screen has been split, use the smaller of the current
+ * window size and the window option value.
+ *
+ * Given a one-line screen with the cursor on line 1, it would be
+ * possible for this to fail, i.e. "1 + 1 * 1 - 2 = 0". Move at
+ * least one line.
+ */
+ offset = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) *
+ (IS_SPLIT_SCREEN(sp) ?
+ MIN(sp->t_maxrows, O_VAL(sp, O_WINDOW)) : O_VAL(sp, O_WINDOW)) - 2;
+ if (offset == 0)
+ offset = 1;
+ if (sp->s_scroll(sp, ep, &vp->m_stop, offset, CNTRL_B))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_lineup -- [count]^Y
+ * Page up by lines.
+ */
+int
+v_lineup(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * The cursor moves down, staying with its original line, unless it
+ * reaches the bottom of the screen.
+ */
+ if (sp->s_scroll(sp, ep,
+ &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, CNTRL_Y))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_linedown -- [count]^E
+ * Page down by lines.
+ */
+int
+v_linedown(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * The cursor moves up, staying with its original line, unless it
+ * reaches the top of the screen.
+ */
+ if (sp->s_scroll(sp, ep,
+ &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, CNTRL_E))
+ return (1);
+ vp->m_final = vp->m_stop;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_search.c b/usr.bin/vi/vi/v_search.c
new file mode 100644
index 000000000000..2ba013ae91f2
--- /dev/null
+++ b/usr.bin/vi/vi/v_search.c
@@ -0,0 +1,414 @@
+/*-
+ * 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_search.c 8.32 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static int correct __P((SCR *, EXF *, VICMDARG *, u_int));
+static int getptrn __P((SCR *, EXF *, ARG_CHAR_T, char **, size_t *));
+static int search __P((SCR *,
+ EXF *, VICMDARG *, char *, size_t, u_int, enum direction));
+
+/*
+ * v_searchn -- n
+ * Repeat last search.
+ */
+int
+v_searchn(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (search(sp, ep, vp, NULL, 0, SEARCH_MSG, sp->searchdir));
+}
+
+/*
+ * v_searchN -- N
+ * Reverse last search.
+ */
+int
+v_searchN(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum direction dir;
+
+ switch (sp->searchdir) {
+ case BACKWARD:
+ dir = FORWARD;
+ break;
+ case FORWARD:
+ dir = BACKWARD;
+ break;
+ default: /* NOTSET handled in search(). */
+ dir = sp->searchdir;
+ break;
+ }
+ return (search(sp, ep, vp, NULL, 0, SEARCH_MSG, dir));
+}
+
+/*
+ * v_searchb -- [count]?RE[? offset]
+ * Search backward.
+ */
+int
+v_searchb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ size_t len;
+ char *ptrn;
+
+ if (F_ISSET(vp, VC_ISDOT))
+ ptrn = NULL;
+ else {
+ if (getptrn(sp, ep, CH_BSEARCH, &ptrn, &len))
+ return (1);
+ if (len == 0) {
+ F_SET(vp, VM_NOMOTION);
+ return (0);
+ }
+ }
+ return (search(sp, ep, vp, ptrn, len,
+ SEARCH_MSG | SEARCH_PARSE | SEARCH_SET, BACKWARD));
+}
+
+/*
+ * v_searchf -- [count]/RE[/ offset]
+ * Search forward.
+ */
+int
+v_searchf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ size_t len;
+ char *ptrn;
+
+ if (F_ISSET(vp, VC_ISDOT))
+ ptrn = NULL;
+ else {
+ if (getptrn(sp, ep, CH_FSEARCH, &ptrn, &len))
+ return (1);
+ if (len == 0) {
+ F_SET(vp, VM_NOMOTION);
+ return (0);
+ }
+ }
+ return (search(sp, ep, vp, ptrn, len,
+ SEARCH_MSG | SEARCH_PARSE | SEARCH_SET, 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, 0, SEARCH_MSG | SEARCH_TERM, FORWARD);
+
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+static int
+search(sp, ep, vp, ptrn, len, flags, dir)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ u_int flags;
+ char *ptrn;
+ size_t len;
+ enum direction dir;
+{
+ char *eptrn;
+
+ if (ISMOTION(vp))
+ flags |= SEARCH_EOL;
+
+ for (;;) {
+ switch (dir) {
+ case BACKWARD:
+ if (b_search(sp, ep,
+ &vp->m_start, &vp->m_stop, ptrn, &eptrn, &flags))
+ return (1);
+ break;
+ case FORWARD:
+ if (f_search(sp, ep,
+ &vp->m_start, &vp->m_stop, ptrn, &eptrn, &flags))
+ return (1);
+ break;
+ case NOTSET:
+ msgq(sp, M_ERR, "No previous search pattern");
+ return (1);
+ default:
+ abort();
+ }
+
+ /*
+ * !!!
+ * Historically, vi permitted trailing <blank>'s, multiple
+ * search strings (separated by semi-colons) and full-blown
+ * z commands after / and ? search strings. In the case of
+ * multiple search strings, leading <blank>'s on the second
+ * and subsequent strings was eaten as well.
+ *
+ * !!!
+ * However, the command "/STRING/; " failed, apparently it
+ * confused the parser. We're not *that* compatible.
+ *
+ * The N, n, and ^A commands also get to here, but they've
+ * set ptrn to NULL, len to 0, or the SEARCH_TERM flag, or
+ * some combination thereof.
+ */
+ if (ptrn == NULL || len == 0)
+ break;
+ len -= eptrn - ptrn;
+ for (; len > 0 && isblank(*eptrn); ++eptrn, --len);
+ if (len == 0)
+ break;
+
+ switch (*eptrn) {
+ case ';':
+ for (++eptrn; --len > 0 && isblank(*eptrn); ++eptrn);
+ ptrn = eptrn;
+ switch (*eptrn) {
+ case '/':
+ dir = FORWARD;
+ break;
+ case '?':
+ dir = BACKWARD;
+ break;
+ default:
+ goto usage;
+ }
+ ptrn = eptrn;
+ vp->m_start = vp->m_stop;
+ continue;
+ case 'z':
+ if (term_push(sp, eptrn, len, CH_NOMAP | CH_QUOTED))
+ return (1);
+ goto ret;
+ default:
+usage: msgq(sp, M_ERR,
+ "Characters after search string and/or delta");
+ return (1);
+ }
+ }
+
+ /* Non-motion commands move to the end of the range. */
+ret: if (ISMOTION(vp)) {
+ if (correct(sp, ep, vp, flags))
+ return (1);
+ } else
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * getptrn --
+ * Get the search pattern.
+ */
+static int
+getptrn(sp, ep, prompt, ptrnp, lenp)
+ SCR *sp;
+ EXF *ep;
+ ARG_CHAR_T prompt;
+ char **ptrnp;
+ size_t *lenp;
+{
+ TEXT *tp;
+
+ if (sp->s_get(sp, ep, sp->tiqp, prompt,
+ TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK)
+ return (1);
+
+ /* Len is 0 if backspaced over the prompt, 1 if only CR entered. */
+ tp = sp->tiqp->cqh_first;
+ *ptrnp = tp->lb;
+ *lenp = tp->len;
+ return (0);
+}
+
+/*
+ * correct --
+ * Handle command with a search as the motion.
+ *
+ * !!!
+ * Historically, commands didn't affect the line searched to/from if the
+ * motion command was a search and the final position was the start/end
+ * of the line. There were some special cases and vi was not consistent;
+ * it was fairly easy to confuse it. For example, given the two lines:
+ *
+ * abcdefghi
+ * ABCDEFGHI
+ *
+ * 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 going to exactly match historic practice.
+ */
+static int
+correct(sp, ep, vp, flags)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ u_int flags;
+{
+ enum direction dir;
+ MARK m;
+ size_t len;
+
+ /*
+ * !!!
+ * We may have wrapped if wrapscan was set, and we may have returned
+ * to the position where the cursor started. Historic vi didn't cope
+ * with this well. Yank wouldn't beep, but the first put after the
+ * yank would move the cursor right one column (without adding any
+ * text) and the second would put a copy of the current line. The
+ * change and delete commands would beep, but would leave the cursor
+ * on the colon command line. I believe that there are macros that
+ * depend on delete, at least, failing. For now, commands that use
+ * search as a motion component fail when the search returns to the
+ * original cursor position.
+ */
+ if (vp->m_start.lno == vp->m_stop.lno &&
+ vp->m_start.cno == vp->m_stop.cno) {
+ msgq(sp, M_BERR, "Search wrapped to original position");
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Searches become line mode operations if there was a delta
+ * specified to the search pattern.
+ */
+ if (LF_ISSET(SEARCH_DELTA))
+ F_SET(vp, VM_LMODE);
+
+ /*
+ * If the motion is in the reverse direction, switch the start and
+ * stop MARK's so that it's in a forward direction. (There's no
+ * reason for this other than to make the tests below easier. The
+ * code in vi.c:vi() would have done the switch.) Both forward
+ * and backward motions can happen for any kind of search command
+ * because of the wrapscan option.
+ */
+ 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) {
+ dir = BACKWARD;
+ m = vp->m_start;
+ vp->m_start = vp->m_stop;
+ vp->m_stop = m;
+ } else
+ dir = FORWARD;
+
+ /*
+ * BACKWARD:
+ * 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_DEF.
+ *
+ * FORWARD:
+ * VC_D and VC_Y commands don't move. Ignore VC_C and VC_DEF.
+ */
+ if (dir == BACKWARD)
+ if (F_ISSET(vp, VC_D) ||
+ F_ISSET(vp, VC_Y) && vp->m_start.lno != vp->m_stop.lno)
+ vp->m_final = vp->m_start;
+ else
+ vp->m_final = vp->m_stop;
+ else
+ vp->m_final = vp->m_start;
+
+ /*
+ * !!!
+ * Backward searches starting at column 0, and forward searches ending
+ * at column 0 are corrected to the last column of the previous line.
+ * Otherwise, adjust the starting/ending point to the character before
+ * the current one (this is safe because we know the search had to move
+ * to succeed).
+ *
+ * Searches become line mode operations if they start at column 0 and
+ * end at column 0 of another line.
+ */
+ 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 (vp->m_start.cno == 0)
+ F_SET(vp, VM_LMODE);
+ vp->m_stop.cno = len ? len - 1 : 0;
+ } else
+ --vp->m_stop.cno;
+
+ 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..9bc06b678995
--- /dev/null
+++ b/usr.bin/vi/vi/v_section.c
@@ -0,0 +1,280 @@
+/*-
+ * 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.10 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.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 section was defined as the first character(s) of the
+ * line matching, 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.
+ */
+
+/*
+ * v_sectionf -- [count]]]
+ * Move forward count sections/functions.
+ *
+ * !!!
+ * 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. No clue why.
+ */
+int
+v_sectionf(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t cnt, lno;
+ size_t len;
+ char *p, *list, *lp;
+
+ /* Get the macro list. */
+ if ((list = O_STR(sp, O_SECTIONS)) == NULL)
+ return (1);
+
+ /*
+ * !!!
+ * 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.
+ */
+ 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);
+ }
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ for (lno = vp->m_start.lno;
+ (p = file_gline(sp, ep, ++lno, &len)) != NULL;) {
+ if (len == 0)
+ continue;
+ if (p[0] == '{' || ISMOTION(vp) && p[0] == '}') {
+ if (!--cnt) {
+ if (p[0] == '{')
+ goto adjust1;
+ goto adjust2;
+ }
+ continue;
+ }
+ /*
+ * !!!
+ * Historic documentation (USD:15-11, 4.2) said that formfeed
+ * characters (^L) in the first column delimited sections.
+ * The historic code mentions formfeed characters, but never
+ * implements them. Seems reasonable, do it.
+ */
+ if (p[0] == '\014') {
+ if (!--cnt)
+ goto adjust1;
+ continue;
+ }
+ if (p[0] != '.' || len < 2)
+ continue;
+ for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
+ if (lp[0] == p[1] &&
+ (lp[1] == ' ' && len == 2 || lp[1] == p[2]) &&
+ !--cnt) {
+ /*
+ * !!!
+ * If not cutting this line, adjust to the end
+ * of the previous one. Otherwise, position to
+ * column 0.
+ */
+adjust1: if (ISMOTION(vp))
+ goto ret1;
+
+adjust2: vp->m_stop.lno = lno;
+ vp->m_stop.cno = 0;
+ goto ret2;
+ }
+ }
+
+ /* If moving forward, reached EOF, check to see if we started there. */
+ if (vp->m_start.lno == lno - 1) {
+ v_eof(sp, ep, NULL);
+ return (1);
+ }
+
+ret1: if (file_gline(sp, ep, --lno, &len) == NULL)
+ return (1);
+ vp->m_stop.lno = lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+
+ /*
+ * Non-motion commands go to the end of the range. VC_D and
+ * VC_Y stay at the start of the range. Ignore VC_C and VC_DEF.
+ */
+ret2: if (ISMOTION(vp)) {
+ vp->m_final = vp->m_start;
+ if (F_ISSET(vp, VM_LMODE))
+ vp->m_final.cno = 0;
+ } else
+ vp->m_final = vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_sectionb -- [count][[
+ * Move backward count sections/functions.
+ */
+int
+v_sectionb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ size_t len;
+ recno_t cnt, lno;
+ char *p, *list, *lp;
+
+ /* An empty file or starting from line 1 is always illegal. */
+ if (vp->m_start.lno <= 1) {
+ v_sof(sp, NULL);
+ return (1);
+ }
+
+ /* Get the macro list. */
+ if ((list = O_STR(sp, O_SECTIONS)) == NULL)
+ return (1);
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ for (lno = vp->m_start.lno;
+ (p = file_gline(sp, ep, --lno, &len)) != NULL;) {
+ if (len == 0)
+ continue;
+ if (p[0] == '{') {
+ if (!--cnt)
+ goto adjust1;
+ continue;
+ }
+ /*
+ * !!!
+ * Historic documentation (USD:15-11, 4.2) said that formfeed
+ * characters (^L) in the first column delimited sections.
+ * The historic code mentions formfeed characters, but never
+ * implements them. Seems reasonable, do it.
+ */
+ if (p[0] == '\014') {
+ if (!--cnt)
+ goto adjust1;
+ continue;
+ }
+ if (p[0] != '.' || len < 2)
+ continue;
+ for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
+ if (lp[0] == p[1] &&
+ (lp[1] == ' ' && len == 2 || lp[1] == p[2]) &&
+ !--cnt) {
+adjust1: vp->m_stop.lno = lno;
+ vp->m_stop.cno = 0;
+ goto ret1;
+ }
+ }
+
+ /*
+ * If moving backward, reached SOF, which is a movement sink.
+ * We already checked for starting there.
+ */
+ vp->m_stop.lno = 1;
+ vp->m_stop.cno = 0;
+
+ /*
+ * All commands move to the end of the range.
+ *
+ * !!!
+ * Historic practice is the section cut was in line mode if it started
+ * from column 0 and was in the backward direction. Otherwise, left
+ * motion commands adjust the starting point to the character before
+ * the current one. What makes this worse is that if it cut to line
+ * mode it also went to the first non-<blank>.
+ */
+ret1: if (vp->m_start.cno == 0) {
+ F_CLR(vp, VM_RCM_MASK);
+ F_SET(vp, VM_RCM_SETFNB);
+
+ --vp->m_start.lno;
+ F_SET(vp, VM_LMODE);
+ } else
+ --vp->m_start.cno;
+
+ vp->m_final = vp->m_stop;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_sentence.c b/usr.bin/vi/vi/v_sentence.c
new file mode 100644
index 000000000000..87c6039ac3f5
--- /dev/null
+++ b/usr.bin/vi/vi/v_sentence.c
@@ -0,0 +1,386 @@
+/*-
+ * 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_sentence.c 8.15 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.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
+ * vi states that any number of ')', ']', '"' and '\'' characters can be
+ * between the delimiter character and the spaces or end of line, however,
+ * the historical implementation did not handle additional '"' characters.
+ * We follow the documentation here, not the implementation.
+ *
+ * Once again, historical vi didn't do sentence movements associated with
+ * counts consistently, mostly in the presence of lines containing only
+ * white-space characters.
+ *
+ * This implementation also permits a single tab to delimit sentences, and
+ * treats lines containing only white-space characters as empty lines.
+ * Finally, tabs are eaten (along with spaces) when skipping to the start
+ * of the text following a "sentence".
+ */
+
+/*
+ * v_sentencef -- [count])
+ * Move forward count sentences.
+ */
+int
+v_sentencef(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ enum { BLANK, NONE, PERIOD } state;
+ VCS cs;
+ size_t len;
+ u_long cnt;
+
+ 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.
+ */
+ if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (--cnt == 0) {
+ 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);
+ if (cs.cs_flags == CS_EOF)
+ break;
+ if (cs.cs_flags == CS_EOL) {
+ if ((state == PERIOD || state == BLANK) && --cnt == 0) {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == 0 &&
+ isblank(cs.cs_ch) && cs_fblank(sp, ep, &cs))
+ return (1);
+ goto okret;
+ }
+ state = NONE;
+ continue;
+ }
+ if (cs.cs_flags == CS_EMP) { /* An EMP is two sentences. */
+ if (--cnt == 0)
+ goto okret;
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ if (--cnt == 0)
+ goto okret;
+ state = NONE;
+ continue;
+ }
+ switch (cs.cs_ch) {
+ case '.':
+ case '?':
+ case '!':
+ state = PERIOD;
+ break;
+ case ')':
+ case ']':
+ case '"':
+ case '\'':
+ if (state != PERIOD)
+ state = NONE;
+ break;
+ case '\t':
+ if (state == PERIOD)
+ state = BLANK;
+ /* FALLTHROUGH */
+ case ' ':
+ if (state == PERIOD) {
+ state = BLANK;
+ break;
+ }
+ if (state == BLANK && --cnt == 0) {
+ if (cs_fblank(sp, ep, &cs))
+ return (1);
+ goto okret;
+ }
+ /* FALLTHROUGH */
+ default:
+ state = NONE;
+ break;
+ }
+ }
+
+ /* 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: 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 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_DEF. Adjust the
+ * end of the range for motion commands.
+ */
+ 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);
+}
+
+/*
+ * v_sentenceb -- [count](
+ * Move backward count sentences.
+ */
+int
+v_sentenceb(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ VCS cs;
+ recno_t slno;
+ size_t len, scno;
+ u_long cnt;
+ int last;
+
+ /*
+ * !!!
+ * 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 = 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;
+
+ /*
+ * !!!
+ * 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_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 (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) {
+ last = 1;
+ continue;
+ }
+ if (cs.cs_flags == CS_EMP) {
+ if (--cnt == 0)
+ goto ret;
+ if (cs_bblank(sp, ep, &cs))
+ return (1);
+ last = 0;
+ continue;
+ }
+ switch (cs.cs_ch) {
+ case '.':
+ case '?':
+ case '!':
+ if (!last || --cnt != 0) {
+ last = 0;
+ continue;
+ }
+
+ret: slno = cs.cs_lno;
+ scno = cs.cs_cno;
+
+ /*
+ * Move to the start of the sentence, skipping blanks
+ * and special characters.
+ */
+ do {
+ if (cs_next(sp, ep, &cs))
+ return (1);
+ } while (!cs.cs_flags &&
+ (cs.cs_ch == ')' || cs.cs_ch == ']' ||
+ cs.cs_ch == '"' || cs.cs_ch == '\''));
+ if ((cs.cs_flags || isblank(cs.cs_ch)) &&
+ cs_fblank(sp, ep, &cs))
+ return (1);
+
+ /*
+ * If it was ". xyz", with the cursor on the 'x', or
+ * "end. ", with the cursor in the spaces, or the
+ * beginning of a sentence preceded by an empty line,
+ * we can end up where we started. Fix it.
+ */
+ if (vp->m_start.lno != cs.cs_lno ||
+ vp->m_start.cno != cs.cs_cno)
+ goto okret;
+
+ /*
+ * Well, if an empty line preceded possible blanks
+ * and the sentence, it could be a real sentence.
+ */
+ for (;;) {
+ if (cs_prev(sp, ep, &cs))
+ return (1);
+ if (cs.cs_flags == CS_EOL)
+ continue;
+ if (cs.cs_flags == 0 && isblank(cs.cs_ch))
+ continue;
+ break;
+ }
+ if (cs.cs_flags == CS_EMP)
+ goto okret;
+
+ /* But it wasn't; try again. */
+ ++cnt;
+ cs.cs_lno = slno;
+ cs.cs_cno = scno;
+ last = 0;
+ break;
+ case '\t':
+ last = 1;
+ break;
+ default:
+ 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: vp->m_stop.lno = cs.cs_lno;
+ vp->m_stop.cno = cs.cs_cno;
+
+ /*
+ * !!!
+ * 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.
+ *
+ * All commands move to the end of the range. Adjust the start of
+ * the range for motion commands.
+ */
+ 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 = vp->m_stop;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_status.c b/usr.bin/vi/vi/v_status.c
new file mode 100644
index 000000000000..5ea544c7e2a8
--- /dev/null
+++ b/usr.bin/vi/vi/v_status.c
@@ -0,0 +1,73 @@
+/*-
+ * 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_status.c 8.16 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_status -- ^G
+ * Show the file status.
+ */
+int
+v_status(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+
+ /*
+ * ^G in historic vi reset the cursor column to the first
+ * non-blank character in the line. This doesn't seem of
+ * any usefulness whatsoever, so I don't bother.
+ */
+ return (msg_status(sp, ep, vp->m_start.lno, 1));
+}
diff --git a/usr.bin/vi/vi/v_stop.c b/usr.bin/vi/vi/v_stop.c
new file mode 100644
index 000000000000..1e865d97da4d
--- /dev/null
+++ b/usr.bin/vi/vi/v_stop.c
@@ -0,0 +1,75 @@
+/*-
+ * 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_stop.c 8.7 (Berkeley) 3/8/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_stop -- ^Z
+ * Suspend vi.
+ */
+int
+v_stop(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* If autowrite is set, write out the file. */
+ if (F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE)) {
+ if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
+ return (1);
+ if (sp->s_refresh(sp, ep))
+ return (1);
+ }
+ return (sp->s_suspend(sp));
+}
diff --git a/usr.bin/vi/vi/v_text.c b/usr.bin/vi/vi/v_text.c
new file mode 100644
index 000000000000..e6c940a7bf93
--- /dev/null
+++ b/usr.bin/vi/vi/v_text.c
@@ -0,0 +1,883 @@
+/*-
+ * 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_text.c 8.40 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * !!!
+ * Repeated input in the historic vi is mostly wrong and this isn't very
+ * backward compatible. For example, if the user entered "3Aab\ncd" in
+ * the historic vi, the "ab" was repeated 3 times, and the "\ncd" was then
+ * appended to the result. There was also a hack which I don't remember
+ * right now, where "3o" would open 3 lines and then let the user fill them
+ * in, to make screen movements on 300 baud modems more tolerable. I don't
+ * think it's going to be missed.
+ *
+ * !!!
+ * 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
+ * starting cursor position before the change command "moves" the cursor, the
+ * cursor position to which we return on undo will be where the user entered
+ * the change command, not the start of the change. Several of the following
+ * routines re-log the cursor to make this work correctly. Historic vi tried
+ * to do the same thing, and mostly got it right. (The only spectacular way
+ * 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.) 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 u_int set_txt_std __P((SCR *, VICMDARG *, 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)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ size_t len;
+ u_int flags;
+ int first;
+ char *p;
+
+ sp->showmode = "Append";
+ flags = set_txt_std(sp, vp, TXT_APPENDEOL);
+ 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) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ lno = 1;
+ len = 0;
+ } else {
+ /* Correct logging for implied cursor motion. */
+ if (first == 1) {
+ 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->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ flags = set_txt_std(sp, vp, TXT_APPENDEOL | TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_ia -- [count]a
+ * Append text to the cursor position.
+ */
+int
+v_ia(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ u_int flags;
+ size_t len;
+ char *p;
+
+ sp->showmode = "Append";
+ flags = set_txt_std(sp, vp, 0);
+ 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
+ * repaint the screen.
+ */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ lno = 1;
+ len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else if (len) {
+ if (len == sp->cno + 1) {
+ sp->cno = len;
+ LF_SET(TXT_APPENDEOL);
+ } else
+ ++sp->cno;
+ } else
+ LF_SET(TXT_APPENDEOL);
+
+ if (v_ntext(sp, ep,
+ sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ flags = set_txt_std(sp, vp, TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_iI -- [count]I
+ * Insert text at the first non-blank character in the line.
+ */
+int
+v_iI(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ size_t len;
+ u_int flags;
+ int first;
+ char *p;
+
+ sp->showmode = "Insert";
+ flags = set_txt_std(sp, vp, 0);
+ 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
+ * the screen.
+ */
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ lno = 1;
+ len = 0;
+ } else {
+ sp->cno = 0;
+ if (nonblank(sp, ep, lno, &sp->cno))
+ return (1);
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT_FIRST;
+ }
+ if (len == 0)
+ LF_SET(TXT_APPENDEOL);
+
+ if (v_ntext(sp, ep,
+ sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ flags = set_txt_std(sp, vp, TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_ii -- [count]i
+ * Insert text at the cursor position.
+ */
+int
+v_ii(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ size_t len;
+ u_int flags;
+ char *p;
+
+ sp->showmode = "Insert";
+ flags = set_txt_std(sp, vp, 0);
+ 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, vp->m_start.lno);
+ return (1);
+ }
+ lno = 1;
+ len = 0;
+ }
+ /* If len == sp->cno, it's a replay caused by a count. */
+ if (len == 0 || len == sp->cno)
+ LF_SET(TXT_APPENDEOL);
+
+ if (v_ntext(sp, ep,
+ sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ /*
+ * On replay, if the line isn't empty, advance the insert
+ * by one (make it an append).
+ */
+ flags = set_txt_std(sp, vp, TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ if ((sp->cno = vp->m_final.cno) != 0)
+ ++sp->cno;
+ }
+ return (0);
+}
+
+/*
+ * v_iO -- [count]O
+ * Insert text above this line.
+ */
+int
+v_iO(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t ai_line, lno;
+ size_t len;
+ u_long cnt;
+ u_int flags;
+ int first;
+ char *p;
+
+ sp->showmode = "Insert";
+ flags = set_txt_std(sp, vp, TXT_APPENDEOL);
+ for (first = 1, cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ if (sp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0)
+ goto insert;
+ p = NULL;
+ len = 0;
+ ai_line = OOBLNO;
+ } else {
+insert: p = "";
+ sp->cno = 0;
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT_FIRST;
+
+ if (file_iline(sp, ep, sp->lno, p, 0))
+ return (1);
+ if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, sp->lno);
+ return (1);
+ }
+ ai_line = sp->lno + 1;
+ }
+
+ if (v_ntext(sp, ep,
+ sp->tiqp, NULL, p, len, &vp->m_final, 0, ai_line, flags))
+ return (1);
+
+ flags = set_txt_std(sp, vp, TXT_APPENDEOL | TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_io -- [count]o
+ * Insert text after this line.
+ */
+int
+v_io(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t ai_line, lno;
+ size_t len;
+ u_long cnt;
+ u_int flags;
+ int first;
+ char *p;
+
+ sp->showmode = "Insert";
+ flags = set_txt_std(sp, vp, TXT_APPENDEOL);
+ for (first = 1,
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ if (sp->lno == 1) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0)
+ goto insert;
+ p = NULL;
+ len = 0;
+ ai_line = OOBLNO;
+ } else {
+insert: p = "";
+ sp->cno = 0;
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT_FIRST;
+
+ len = 0;
+ if (file_aline(sp, ep, 1, sp->lno, p, len))
+ return (1);
+ if ((p = file_gline(sp, ep, ++sp->lno, &len)) == NULL) {
+ GETLINE_ERR(sp, sp->lno);
+ return (1);
+ }
+ ai_line = sp->lno - 1;
+ }
+
+ if (v_ntext(sp, ep,
+ sp->tiqp, NULL, p, len, &vp->m_final, 0, ai_line, flags))
+ return (1);
+
+ flags = set_txt_std(sp, vp, TXT_APPENDEOL | TXT_REPLAY);
+ sp->lno = lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+ }
+ return (0);
+}
+
+/*
+ * v_Change -- [buffer][count]C
+ * Change line command.
+ */
+int
+v_Change(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ return (v_CS(sp, ep, vp, 0));
+}
+
+/*
+ * v_Subst -- [buffer][count]S
+ * Line substitute command.
+ */
+int
+v_Subst(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ u_int flags;
+
+ /*
+ * The S command is the same as a 'C' command from the beginning
+ * of the line. This is hard to do in the parser, so do it here.
+ *
+ * If autoindent is on, the change is from the first *non-blank*
+ * character of the line, not the first character. And, to make
+ * it just a bit more exciting, the initial space is handled as
+ * auto-indent characters.
+ */
+ LF_INIT(0);
+ if (O_ISSET(sp, O_AUTOINDENT)) {
+ vp->m_start.cno = 0;
+ if (nonblank(sp, ep, vp->m_start.lno, &vp->m_start.cno))
+ return (1);
+ LF_SET(TXT_AICHARS);
+ } else
+ vp->m_start.cno = 0;
+ sp->cno = vp->m_start.cno;
+ return (v_CS(sp, ep, vp, flags));
+}
+
+/*
+ * v_CS --
+ * C and S commands.
+ */
+static int
+v_CS(sp, ep, vp, iflags)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+ u_int iflags;
+{
+ MARK *tm;
+ recno_t lno;
+ size_t len;
+ char *p;
+ u_int flags;
+
+ sp->showmode = "Change";
+ flags = set_txt_std(sp, vp, iflags);
+
+ /*
+ * There are two cases -- if a count is supplied, we do a line
+ * mode change where we delete the lines and then insert text
+ * into a new line. Otherwise, we replace the current line.
+ */
+ 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,
+ 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.
+ *
+ * !!!
+ * Historic practice, C and S did not cut into the numeric
+ * buffers, only the unnamed one.
+ */
+ if (cut(sp, ep,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, CUT_LINEMODE))
+ return (1);
+
+ /* Insert a line while we still can... */
+ if (file_iline(sp, ep, vp->m_start.lno, "", 0))
+ return (1);
+ ++vp->m_start.lno;
+ ++vp->m_stop.lno;
+
+ /* Delete the lines. */
+ if (delete(sp, ep, &vp->m_start, &vp->m_stop, 1))
+ return (1);
+
+ /* Get the inserted line. */
+ 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 = vp->m_start.lno;
+ sp->cno = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ /* The line may be empty, but that's okay. */
+ 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, vp->m_start.lno);
+ return (1);
+ }
+ 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;
+ /*
+ * !!!
+ * Historic practice, C and S did not cut into the
+ * numeric buffers, only the unnamed one.
+ */
+ if (cut(sp, ep,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, CUT_LINEMODE))
+ return (1);
+ LF_SET(TXT_EMARK | TXT_OVERWRITE);
+ }
+ tm = &vp->m_stop;
+ }
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT;
+
+ return (v_ntext(sp, ep,
+ sp->tiqp, tm, p, len, &vp->m_final, 0, OOBLNO, flags));
+}
+
+/*
+ * v_change -- [buffer][count]c[count]motion
+ * Change command.
+ */
+int
+v_change(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t blen, len;
+ u_int flags;
+ int lmode, rval;
+ char *bp, *p;
+
+ sp->showmode = "Change";
+ flags = set_txt_std(sp, vp, 0);
+
+ /*
+ * Move the cursor to the start of the change. Note, if autoindent
+ * is turned on, the cc command in line mode changes from the first
+ * *non-blank* character of the line, not the first character. And,
+ * to make it just a bit more exciting, the initial space is handled
+ * as auto-indent characters.
+ */
+ lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0;
+ if (lmode) {
+ vp->m_start.cno = 0;
+ if (O_ISSET(sp, O_AUTOINDENT)) {
+ if (nonblank(sp, ep, vp->m_start.lno, &vp->m_start.cno))
+ return (1);
+ LF_SET(TXT_AICHARS);
+ }
+ }
+ sp->lno = vp->m_start.lno;
+ sp->cno = vp->m_start.cno;
+
+ /* Correct logging for implied cursor motion. */
+ LOG_CORRECT;
+
+ /*
+ * Turn off the VM_RCM flags, inserting text has its own rules for
+ * cursor positioning.
+ */
+ F_CLR(vp, VM_RCM_MASK);
+
+ /*
+ * If not in line mode and changing within a single line, the line
+ * either currently has text or it doesn't. If it doesn't, insert
+ * some. Otherwise, copy it and overwrite it.
+ */
+ if (!lmode && 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, vp->m_start.lno);
+ return (1);
+ }
+ }
+ vp->m_stop.cno = len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ /*
+ * !!!
+ * Historic practice, c cut into the numeric buffers,
+ * as well as the unnamed one.
+ */
+ if (cut(sp, ep,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode | CUT_NUMOPT))
+ return (1);
+ if (len == 0)
+ LF_SET(TXT_APPENDEOL);
+ LF_SET(TXT_EMARK | TXT_OVERWRITE);
+ }
+ return (v_ntext(sp, ep, sp->tiqp,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags));
+ }
+
+ /*
+ * It's trickier if changing over multiple lines. If we're in
+ * line mode we delete all of the lines and insert a replacement
+ * line which the user edits. If there was leading whitespace
+ * in the first line being changed, we copy it and use it as the
+ * replacement. If we're not in line mode, we just delete the
+ * text and start inserting.
+ *
+ * !!!
+ * Historic practice, c cut into the numeric buffers, as well as the
+ * unnamed one.
+ *
+ * Copy the text.
+ */
+ if (cut(sp, ep,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode | CUT_NUMOPT))
+ return (1);
+
+ /* If replacing entire lines and there's leading text. */
+ if (lmode && vp->m_start.cno) {
+ /* Get a copy of the first line changed. */
+ 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, vp->m_start.cno);
+ memmove(bp, p, vp->m_start.cno);
+ } else
+ bp = NULL;
+
+ /* Delete the text. */
+ 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, vp->m_start.lno, bp, vp->m_start.cno))
+ return (1);
+ 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, vp->m_start.lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno != 0) {
+ GETLINE_ERR(sp, vp->m_start.lno);
+ return (1);
+ }
+ len = 0;
+ }
+
+ /* Check to see if we're appending to the line. */
+ if (vp->m_start.cno >= len)
+ LF_SET(TXT_APPENDEOL);
+
+ rval = v_ntext(sp, ep,
+ sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags);
+
+ if (bp != NULL)
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
+
+/*
+ * v_Replace -- [count]R
+ * Overwrite multiple characters.
+ */
+int
+v_Replace(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ u_long cnt;
+ size_t len;
+ u_int flags;
+ char *p;
+
+ sp->showmode = "Replace";
+ flags = set_txt_std(sp, vp, 0);
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ 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, vp->m_start.lno);
+ return (1);
+ }
+ len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ if (len == 0)
+ LF_SET(TXT_APPENDEOL);
+ LF_SET(TXT_OVERWRITE | TXT_REPLACE);
+ }
+ vp->m_stop.lno = vp->m_start.lno;
+ vp->m_stop.cno = len ? len - 1 : 0;
+ if (v_ntext(sp, ep, sp->tiqp,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+
+ /*
+ * Special case. The historic vi handled [count]R badly, in that R
+ * would replace some number of characters, and then the count would
+ * append count-1 copies of the replacing chars to the replaced space.
+ * 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 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, vp->m_final.lno, &len)) == NULL)
+ GETLINE_ERR(sp, vp->m_final.lno);
+ flags = set_txt_std(sp, vp, TXT_REPLAY);
+
+ sp->lno = vp->m_final.lno;
+
+ if (len == 0 || vp->m_final.cno == len - 1) {
+ sp->cno = len;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ sp->cno = vp->m_final.cno;
+ if (vp->m_final.cno != 0)
+ ++sp->cno;
+ LF_SET(TXT_OVERWRITE | TXT_REPLACE);
+ }
+
+ vp->m_stop.lno = sp->lno;
+ vp->m_stop.cno = sp->cno;
+ if (v_ntext(sp, ep, sp->tiqp,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * v_subst -- [buffer][count]s
+ * Substitute characters.
+ */
+int
+v_subst(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+ u_int flags;
+ char *p;
+
+ sp->showmode = "Change";
+ flags = set_txt_std(sp, vp, 0);
+ 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, vp->m_start.lno);
+ return (1);
+ }
+ len = 0;
+ LF_SET(TXT_APPENDEOL);
+ } else {
+ if (len == 0)
+ LF_SET(TXT_APPENDEOL);
+ LF_SET(TXT_EMARK | TXT_OVERWRITE);
+ }
+
+ 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,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
+ return (1);
+
+ return (v_ntext(sp, ep, sp->tiqp,
+ &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags));
+}
+
+/*
+ * set_txt_std --
+ * Initialize text processing flags.
+ */
+static u_int
+set_txt_std(sp, vp, init)
+ SCR *sp;
+ VICMDARG *vp;
+ u_int init;
+{
+ u_int flags;
+
+ /* Text operations are all interruptible. */
+ F_SET(sp, S_INTERRUPTIBLE);
+
+ LF_INIT(init);
+ LF_SET(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))
+ LF_SET(TXT_WRAPMARGIN);
+ if (F_ISSET(sp, S_SCRIPT))
+ LF_SET(TXT_CR);
+ if (O_ISSET(sp, O_TTYWERASE))
+ LF_SET(TXT_TTYWERASE);
+ if (F_ISSET(vp, VC_ISDOT))
+ LF_SET(TXT_REPLAY);
+ return (flags);
+}
diff --git a/usr.bin/vi/vi/v_ulcase.c b/usr.bin/vi/vi/v_ulcase.c
new file mode 100644
index 000000000000..9bf150fd3cbd
--- /dev/null
+++ b/usr.bin/vi/vi/v_ulcase.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[] = "@(#)v_ulcase.c 8.8 (Berkeley) 7/15/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static int ulcase __P((SCR *, EXF *,
+ recno_t, CHAR_T *, size_t, size_t, size_t));
+
+/*
+ * v_ulcase -- [count]~
+ * Toggle upper & lower case letters.
+ *
+ * !!!
+ * 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.
+ *
+ * !!!
+ * In historic vi, the count was ignored. It would have been better
+ * if there had been an associated motion, but it's too late to make
+ * that the default now.
+ */
+int
+v_ulcase(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t cno, lcnt, len;
+ u_long cnt;
+ char *p;
+
+ lno = vp->m_start.lno;
+ cno = vp->m_start.cno;
+
+ /* EOF is an infinite count sink. */
+ for (cnt =
+ F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt > 0; cno = 0, ++lno) {
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL)
+ break;
+
+ /* Empty lines decrement the count by one. */
+ if (len == 0) {
+ --cnt;
+ vp->m_final.lno = lno + 1;
+ vp->m_final.cno = 0;
+ } else {
+ if (cno + cnt >= len) {
+ lcnt = len - 1;
+ cnt -= len - cno;
+
+ vp->m_final.lno = lno + 1;
+ vp->m_final.cno = 0;
+ } else {
+ lcnt = cno + cnt - 1;
+ cnt = 0;
+
+ vp->m_final.lno = lno;
+ vp->m_final.cno = lcnt + 1;
+ }
+
+ if (ulcase(sp, ep, lno, p, len, cno, lcnt))
+ return (1);
+ }
+ }
+
+ /* Check to see if we tried to move past EOF. */
+ if (file_gline(sp, ep, vp->m_final.lno, &len) == NULL) {
+ (void)file_gline(sp, ep, --vp->m_final.lno, &len);
+ vp->m_final.cno = len == 0 ? 0 : len - 1;
+ }
+ return (0);
+}
+
+/*
+ * v_mulcase -- [count]~[count]motion
+ * Toggle upper & lower case letters over a range.
+ */
+int
+v_mulcase(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ CHAR_T *p;
+ size_t len;
+ recno_t lno;
+
+ for (lno = vp->m_start.lno;;) {
+ if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
+ GETLINE_ERR(sp, lno);
+ return (1);
+ }
+ if (len != 0 &&
+ ulcase(sp, ep, lno, p, len,
+ lno == vp->m_start.lno ? vp->m_start.cno : 0,
+ !F_ISSET(vp, VM_LMODE) &&
+ lno == vp->m_stop.lno ? vp->m_stop.cno : len))
+ return (1);
+
+ if (++lno > vp->m_stop.lno)
+ break;
+ }
+
+ /*
+ * XXX
+ * I didn't create a new motion command when I added motion semantics
+ * for ~. While that's the correct way to do it, that choice would
+ * have required changes all over the vi directory for little gain.
+ * Instead, we pretend it's a yank command. Note, this means that we
+ * follow the cursor motion rules for yank commands, but that seems
+ * reasonable to me.
+ */
+ return (0);
+}
+
+/*
+ * ulcase --
+ * Change part of a line's case.
+ */
+static int
+ulcase(sp, ep, lno, lp, len, scno, ecno)
+ SCR *sp;
+ EXF *ep;
+ recno_t lno;
+ CHAR_T *lp;
+ size_t len, scno, ecno;
+{
+ size_t blen;
+ int change, rval;
+ CHAR_T ch, *p, *t;
+ char *bp;
+
+ GET_SPACE_RET(sp, bp, blen, len);
+ memmove(bp, lp, len);
+
+ change = rval = 0;
+ for (p = bp + scno, t = bp + ecno + 1; p < t; ++p) {
+ ch = *(u_char *)p;
+ if (islower(ch)) {
+ *p = toupper(ch);
+ change = 1;
+ } else if (isupper(ch)) {
+ *p = tolower(ch);
+ change = 1;
+ }
+ }
+
+ if (change && file_sline(sp, ep, lno, bp, len))
+ rval = 1;
+
+ FREE_SPACE(sp, bp, blen);
+ return (rval);
+}
diff --git a/usr.bin/vi/vi/v_undo.c b/usr.bin/vi/vi/v_undo.c
new file mode 100644
index 000000000000..65dc715e189a
--- /dev/null
+++ b/usr.bin/vi/vi/v_undo.c
@@ -0,0 +1,162 @@
+/*-
+ * 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_undo.c 8.10 (Berkeley) 5/7/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_Undo -- U
+ * Undo changes to this line.
+ */
+int
+v_Undo(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /*
+ * Historically, U reset the cursor to the first column in the line
+ * (not the first non-blank). This seems a bit non-intuitive, but,
+ * considering that we may have undone multiple changes, anything
+ * else (including the cursor position stored in the logging records)
+ * is going to appear random.
+ */
+ vp->m_final.cno = 0;
+
+ /*
+ * !!!
+ * Set up the flags so that an immediately subsequent 'u' will roll
+ * forward, instead of backward. In historic vi, a 'u' following a
+ * 'U' redid all of the changes to the line. Given that the user has
+ * explicitly discarded those changes by entering 'U', it seems likely
+ * that the user wants something between the original and end forms of
+ * the line, so starting to replay the changes seems the best way to
+ * get to there.
+ */
+ F_SET(ep, F_UNDO);
+ ep->lundo = BACKWARD;
+
+ return (log_setline(sp, ep));
+}
+
+/*
+ * v_undo -- u
+ * Undo the last change.
+ */
+int
+v_undo(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* Set the command count. */
+ VIP(sp)->u_ccnt = sp->ccnt;
+
+ /*
+ * !!!
+ * In historic vi, 'u' toggled between "undo" and "redo", i.e. 'u'
+ * undid the last undo. However, if there has been a change since
+ * the last undo/redo, we always do an undo. To make this work when
+ * the user can undo multiple operations, we leave the old semantic
+ * unchanged, but make '.' after a 'u' do another undo/redo operation.
+ * This has two problems.
+ *
+ * The first is that 'u' didn't set '.' in historic vi. So, if a
+ * user made a change, realized it was in the wrong place, does a
+ * 'u' to undo it, moves to the right place and then does '.', the
+ * change was reapplied. To make this work, we only apply the '.'
+ * to the undo command if it's the command immediately following an
+ * undo command. See vi/vi.c:getcmd() for the details.
+ *
+ * The second is that the traditional way to view the numbered cut
+ * buffers in vi was to enter the commands "1pu.u.u.u. which will
+ * no longer work because the '.' immediately follows the 'u' command.
+ * Since we provide a much better method of viewing buffers, and
+ * nobody can think of a better way of adding in multiple undo, this
+ * remains broken.
+ *
+ * !!!
+ * There is change to historic practice for the final cursor position
+ * in this implementation. In historic vi, if an undo was isolated to
+ * a single line, the cursor moved to the start of the change, and
+ * then, subsequent 'u' commands would not move it again. (It has been
+ * pointed out that users used multiple undo commands to get the cursor
+ * to the start of the changed text.) Nvi toggles between the cursor
+ * position before and after the change was made. One final issue is
+ * that historic vi only did this if the user had not moved off of the
+ * line before entering the undo command; otherwise, vi would move the
+ * cursor to the most attractive position on the changed line.
+ *
+ * It would be difficult to match historic practice in this area. You
+ * not only have to know that the changes were isolated to one line,
+ * but whether it was the first or second undo command as well. And,
+ * to completely match historic practice, we'd have to track users line
+ * changes, too. This isn't worth the effort.
+ */
+ if (!F_ISSET(ep, F_UNDO)) {
+ F_SET(ep, F_UNDO);
+ ep->lundo = BACKWARD;
+ } else if (!F_ISSET(vp, VC_ISDOT))
+ ep->lundo = ep->lundo == BACKWARD ? FORWARD : BACKWARD;
+
+ switch (ep->lundo) {
+ case BACKWARD:
+ return (log_backward(sp, ep, &vp->m_final));
+ case FORWARD:
+ return (log_forward(sp, ep, &vp->m_final));
+ default:
+ abort();
+ }
+ /* NOTREACHED */
+}
diff --git a/usr.bin/vi/vi/v_util.c b/usr.bin/vi/vi/v_util.c
new file mode 100644
index 000000000000..d7defa8c3db4
--- /dev/null
+++ b/usr.bin/vi/vi/v_util.c
@@ -0,0 +1,159 @@
+/*-
+ * 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_util.c 8.10 (Berkeley) 7/18/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_eof --
+ * Vi end-of-file error.
+ */
+void
+v_eof(sp, ep, mp)
+ SCR *sp;
+ EXF *ep;
+ MARK *mp;
+{
+ recno_t lno;
+
+ if (mp == NULL)
+ msgq(sp, M_BERR, "Already at end-of-file");
+ else {
+ if (file_lline(sp, ep, &lno))
+ return;
+ if (mp->lno >= lno)
+ msgq(sp, M_BERR, "Already at end-of-file");
+ else
+ msgq(sp, M_BERR, "Movement past the end-of-file");
+ }
+}
+
+/*
+ * v_eol --
+ * Vi end-of-line error.
+ */
+void
+v_eol(sp, ep, mp)
+ SCR *sp;
+ EXF *ep;
+ MARK *mp;
+{
+ size_t len;
+
+ if (mp == NULL)
+ msgq(sp, M_BERR, "Already at end-of-line");
+ else {
+ if (file_gline(sp, ep, mp->lno, &len) == NULL) {
+ GETLINE_ERR(sp, mp->lno);
+ return;
+ }
+ if (mp->cno == len - 1)
+ msgq(sp, M_BERR, "Already at end-of-line");
+ else
+ msgq(sp, M_BERR, "Movement past the end-of-line");
+ }
+}
+
+/*
+ * 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.
+ */
+void
+v_sof(sp, mp)
+ SCR *sp;
+ MARK *mp;
+{
+ if (mp == NULL || mp->lno == 1)
+ msgq(sp, M_BERR, "Already at the beginning of the file");
+ else
+ msgq(sp, M_BERR, "Movement past the beginning of the file");
+}
+
+/*
+ * 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
+v_isempty(p, len)
+ char *p;
+ size_t len;
+{
+ for (; len--; ++p)
+ if (!isblank(*p))
+ return (0);
+ return (1);
+}
diff --git a/usr.bin/vi/vi/v_word.c b/usr.bin/vi/vi/v_word.c
new file mode 100644
index 000000000000..7c53fe98fd67
--- /dev/null
+++ b/usr.bin/vi/vi/v_word.c
@@ -0,0 +1,570 @@
+/*-
+ * 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.21 (Berkeley) 7/27/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.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_DEF.
+ */
+ 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_DEF.
+ */
+ 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;
+
+ /*
+ * All commands move to the end of the range. Motion commands
+ * adjust the starting point to the character before the current
+ * one.
+ *
+ * !!!
+ * The historic vi didn't get this right -- the `yb' command yanked
+ * the right stuff and even updated the cursor value, but the cursor
+ * was not actually updated on the screen.
+ */
+ vp->m_final = vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_xchar.c b/usr.bin/vi/vi/v_xchar.c
new file mode 100644
index 000000000000..6bb317cd5f73
--- /dev/null
+++ b/usr.bin/vi/vi/v_xchar.c
@@ -0,0 +1,136 @@
+/*-
+ * 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_xchar.c 8.8 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_xchar -- [count]x
+ * Deletes the character(s) on which the cursor sits.
+ */
+int
+v_xchar(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t lno;
+ size_t len;
+
+ if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ 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);
+ }
+
+ /*
+ * 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.
+ */
+ 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,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
+ return (1);
+ return (delete(sp, ep, &vp->m_start, &vp->m_stop, 0));
+}
+
+/*
+ * v_Xchar -- [count]X
+ * Deletes the character(s) immediately before the current cursor
+ * position.
+ */
+int
+v_Xchar(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ u_long cnt;
+
+ if (vp->m_start.cno == 0) {
+ v_sol(sp);
+ return (1);
+ }
+
+ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
+ 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,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, 0))
+ return (1);
+ return (delete(sp, ep, &vp->m_start, &vp->m_stop, 0));
+}
diff --git a/usr.bin/vi/vi/v_yank.c b/usr.bin/vi/vi/v_yank.c
new file mode 100644
index 000000000000..14f99f57ce47
--- /dev/null
+++ b/usr.bin/vi/vi/v_yank.c
@@ -0,0 +1,94 @@
+/*-
+ * 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_yank.c 8.14 (Berkeley) 5/17/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_yank -- [buffer][count]Y
+ * [buffer][count]y[count][motion]
+ * Yank text (or lines of text) into a cut buffer.
+ *
+ * !!!
+ * 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_yank(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ int lmode;
+
+ /* 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,
+ F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
+ &vp->m_start, &vp->m_stop, lmode))
+ return (1);
+
+ sp->rptlines[L_YANKED] += (vp->m_stop.lno - vp->m_start.lno) + 1;
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_z.c b/usr.bin/vi/vi/v_z.c
new file mode 100644
index 000000000000..ca780f400055
--- /dev/null
+++ b/usr.bin/vi/vi/v_z.c
@@ -0,0 +1,159 @@
+/*-
+ * 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_z.c 8.16 (Berkeley) 7/17/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * v_z -- [count]z[count][-.+^<CR>]
+ * Move the screen.
+ */
+int
+v_z(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ recno_t last, lno;
+ u_int value;
+
+ /*
+ * The first count is the line to use. If the value doesn't
+ * exist, use the last line.
+ */
+ if (F_ISSET(vp, VC_C1SET)) {
+ lno = vp->count;
+ if (file_lline(sp, ep, &last))
+ return (1);
+ if (lno > last)
+ lno = last;
+ } else
+ lno = vp->m_start.lno;
+
+ /* 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'
+ * command is another way to get artificially small windows.
+ *
+ * !!!
+ * A window size of 0 was historically allowed, and simply ignored.
+ * Also, this could be much more simply done by modifying the value
+ * of the O_WINDOW option, but that's not how it worked historically.
+ */
+ if (F_ISSET(vp, VC_C2SET) &&
+ vp->count2 != 0 && sp->s_crel(sp, vp->count2))
+ return (1);
+
+ switch (vp->character) {
+ case '-': /* Put the line at the bottom. */
+ if (sp->s_fill(sp, ep, lno, P_BOTTOM))
+ return (1);
+ break;
+ case '.': /* Put the line in the middle. */
+ if (sp->s_fill(sp, ep, lno, P_MIDDLE))
+ return (1);
+ break;
+ case '+':
+ /*
+ * If the user specified a line number, put that line at the
+ * top and move the cursor to it. Otherwise, scroll forward
+ * a screen from the current screen.
+ */
+ if (F_ISSET(vp, VC_C1SET)) {
+ if (sp->s_fill(sp, ep, lno, P_TOP))
+ return (1);
+ if (sp->s_position(sp, ep, &vp->m_final, 0, P_TOP))
+ return (1);
+ } else
+ if (sp->s_scroll(sp, ep,
+ &vp->m_final, sp->t_rows, Z_PLUS))
+ return (1);
+ break;
+ case '^':
+ /*
+ * If the user specified a line number, put that line at the
+ * bottom, move the cursor to it, and then display the screen
+ * before that one. Otherwise, scroll backward a screen from
+ * the current screen.
+ *
+ * !!!
+ * Note, we match the off-by-one characteristics of historic
+ * vi, here.
+ */
+ if (F_ISSET(vp, VC_C1SET)) {
+ if (sp->s_fill(sp, ep, lno, P_BOTTOM))
+ return (1);
+ if (sp->s_position(sp, ep, &vp->m_final, 0, P_TOP))
+ return (1);
+ if (sp->s_fill(sp, ep, vp->m_final.lno, P_BOTTOM))
+ return (1);
+ } else
+ if (sp->s_scroll(sp, ep,
+ &vp->m_final, sp->t_rows, Z_CARAT))
+ return (1);
+ break;
+ default: /* Put the line at the top for <cr>. */
+ value = KEY_VAL(sp, vp->character);
+ if (value != K_CR && value != K_NL) {
+ msgq(sp, M_ERR, "usage: %s", vp->kp->usage);
+ return (1);
+ }
+ if (sp->s_fill(sp, ep, lno, P_TOP))
+ return (1);
+ break;
+ }
+
+
+ return (0);
+}
diff --git a/usr.bin/vi/vi/v_zexit.c b/usr.bin/vi/vi/v_zexit.c
new file mode 100644
index 000000000000..cd4aac715a35
--- /dev/null
+++ b/usr.bin/vi/vi/v_zexit.c
@@ -0,0 +1,82 @@
+/*-
+ * 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_zexit.c 8.11 (Berkeley) 8/4/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "excmd.h"
+#include "vcmd.h"
+
+/*
+ * v_zexit -- ZZ
+ * Save the file and exit.
+ */
+int
+v_zexit(sp, ep, vp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *vp;
+{
+ /* Write back any modifications. */
+ if (F_ISSET(ep, F_MODIFIED) &&
+ file_write(sp, ep, NULL, NULL, NULL, FS_ALL))
+ return (1);
+
+ /* Check to make sure it's not a temporary file. */
+ if (file_m3(sp, ep, 0))
+ return (1);
+
+ /* Check for more files to edit. */
+ if (ex_ncheck(sp, 0))
+ return (1);
+
+ F_SET(sp, S_EXIT);
+ return (0);
+}
diff --git a/usr.bin/vi/vi/vcmd.c b/usr.bin/vi/vi/vcmd.c
new file mode 100644
index 000000000000..59b6e8b34482
--- /dev/null
+++ b/usr.bin/vi/vi/vcmd.c
@@ -0,0 +1,533 @@
+/*-
+ * 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[] = "@(#)vcmd.c 8.39 (Berkeley) 7/28/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+/*
+ * This array maps keystrokes to vi command functions. It is known
+ * in ex/ex_usage.c that it takes four columns to name a vi character.
+ */
+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|VM_CUTREQ|VM_RCM_SET,
+ "[count]^A",
+ "^A search forward for cursor word"},
+/* 002 ^B */
+ {v_pageup, V_CNT|VM_RCM_SET,
+ "[count]^B",
+ "^B scroll up by screens"},
+/* 003 ^C */
+ {NULL, 0,
+ "^C",
+ "^C interrupt an operation (e.g. read, write, search)"},
+/* 004 ^D */
+ {v_hpagedown, V_CNT|VM_RCM_SET,
+ "[count]^D",
+ "^D scroll down by half screens (setting count)"},
+/* 005 ^E */
+ {v_linedown, V_CNT,
+ "[count]^E",
+ "^E scroll down by lines"},
+/* 006 ^F */
+ {v_pagedown, V_CNT|VM_RCM_SET,
+ "[count]^F",
+ "^F scroll down by screens"},
+/* 007 ^G */
+ {v_status, 0,
+ "^G",
+ "^G file status"},
+/* 010 ^H */
+ {v_left, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]^H",
+ "^H move left by characters"},
+/* 011 ^I */
+ {NULL},
+/* 012 ^J */
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
+ "[count]^J",
+ "^J move down by lines"},
+/* 013 ^K */
+ {NULL},
+/* 014 ^L */
+ {v_redraw, 0,
+ "^L",
+ "^L redraw screen"},
+/* 015 ^M */
+ {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_MOVE|VM_LMODE|VM_RCM,
+ "[count]^N",
+ "^N move down by lines"},
+/* 017 ^O */
+ {NULL},
+/* 020 ^P */
+ {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. */
+ {NULL},
+/* 022 ^R */
+ {v_redraw, 0,
+ "^R",
+ "^R redraw screen"},
+/* 023 ^S -- not available, used for hardware flow control. */
+ {NULL},
+/* 024 ^T */
+ {v_tagpop, V_ABS|VM_RCM_SET,
+ "^T",
+ "^T tag pop"},
+/* 025 ^U */
+ {v_hpageup, V_CNT|VM_RCM_SET,
+ "[count]^U",
+ "^U half page up (set count)"},
+/* 026 ^V */
+ {NULL, 0,
+ "^V",
+ "^V input a literal character"},
+/* 027 ^W */
+ {v_screen, 0,
+ "^W",
+ "^W move to next screen"},
+/* 030 ^X */
+ {NULL},
+/* 031 ^Y */
+ {v_lineup, V_CNT,
+ "[count]^Y",
+ "^Y page up by lines"},
+/* 032 ^Z */
+ {v_stop, 0,
+ "^Z",
+ "^Z suspend editor"},
+/* 033 ^[ */
+ {NULL, 0,
+ "^[ <escape>",
+ "^[ <escape> leave input mode, return to command mode"},
+/* 034 ^\ */
+ {v_exmode, 0,
+ "^\\",
+ " ^\\ switch to ex mode"},
+/* 035 ^] */
+ {v_tagpush, V_ABS|V_KEYW|VM_RCM_SET,
+ "^]",
+ "^] tag push cursor word"},
+/* 036 ^^ */
+ {v_switch, 0,
+ "^^",
+ "^^ switch to previous file"},
+/* 037 ^_ */
+ {NULL},
+/* 040 ' ' */
+ {v_right, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]' '",
+ " <space> move right by columns"},
+/* 041 ! */
+ {v_filter, V_CNT|V_DOT|V_MOTION|VC_DEF|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|VM_RCM_SET,
+ "[count]#[#+-]",
+ " # number increment/decrement"},
+/* 044 $ */
+ {v_dollar, V_CNT|V_MOVE|VM_RCM_SETLAST,
+ " [count]$",
+ " $ move to last column"},
+/* 045 % */
+ {v_match, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "%",
+ " % move to match"},
+/* 046 & */
+ {v_again, 0,
+ "&",
+ " & repeat substitution"},
+/* 047 ' */
+ {v_fmark, V_ABS_L|V_CHAR|V_MOVE|VM_LMODE,
+ "'['a-z]",
+ " ' move to mark (to first non-blank)"},
+/* 050 ( */
+ {v_sentenceb, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "[count](",
+ " ( move back sentence"},
+/* 051 ) */
+ {v_sentencef, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "[count])",
+ " ) move forward sentence"},
+/* 052 * */
+ {NULL},
+/* 053 + */
+ {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|VM_RCM_SET,
+ "[count],",
+ " , reverse last F, f, T or t search"},
+/* 055 - */
+ {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
+ "[count]-",
+ " - move up by lines (to first non-blank)"},
+/* 056 . */
+ {NULL, 0,
+ ".",
+ " . repeat the last command"},
+/* 057 / */
+ {v_searchf, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "/RE[/ offset]",
+ " / search forward"},
+/* 060 0 */
+ {v_zero, V_MOVE|VM_RCM_SET,
+ "0",
+ " 0 move to first character"},
+/* 061 1 */
+ {NULL},
+/* 062 2 */
+ {NULL},
+/* 063 3 */
+ {NULL},
+/* 064 4 */
+ {NULL},
+/* 065 5 */
+ {NULL},
+/* 066 6 */
+ {NULL},
+/* 067 7 */
+ {NULL},
+/* 070 8 */
+ {NULL},
+/* 071 9 */
+ {NULL},
+/* 072 : */
+ {v_ex, 0,
+ ":command [| command] ...",
+ " : ex command"},
+/* 073 ; */
+ {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|VC_DEF|VM_RCM_SET,
+ "[count]<[count]motion",
+ " < shift lines left to motion"},
+/* 075 = */
+ {NULL},
+/* 076 > */
+ {v_shiftr, V_CNT|V_DOT|V_MOTION|VC_DEF|VM_RCM_SET,
+ "[count]>[count]motion",
+ " > shift lines right to motion"},
+/* 077 ? */
+ {v_searchb, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "?RE[? offset]",
+ " ? search backward"},
+/* 100 @ */
+ {v_at, V_RBUF|VM_RCM_SET,
+ "@buffer",
+ " @ execute buffer"},
+/* 101 A */
+ {v_iA, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]A",
+ " A append to the line"},
+/* 102 B */
+ {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|VM_RCM_SET,
+ "[buffer][count]C",
+ " C change to end-of-line"},
+/* 104 D */
+ {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|VM_RCM_SET,
+ "[count]E",
+ " E move to end of bigword"},
+/* 106 F */
+ {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_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
+ "[count]G",
+ " G move to line"},
+/* 110 H */
+ {v_home, V_ABS_L|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|VM_RCM_SET,
+ "[count]I",
+ " I insert at line beginning"},
+/* 112 J */
+ {v_join, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]J",
+ " J join lines"},
+/* 113 K */
+ {NULL},
+/* 114 L */
+ {v_bottom, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
+ "[count]L",
+ " L move to screen bottom"},
+/* 115 M */
+ {v_middle, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
+ "M",
+ " M move to screen middle"},
+/* 116 N */
+ {v_searchN, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "n",
+ " N reverse last search"},
+/* 117 O */
+ {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|VM_RCM_SET,
+ "[buffer]P",
+ " P insert before cursor from buffer"},
+/* 121 Q */
+ {v_exmode, 0,
+ "Q",
+ " Q switch to ex mode"},
+/* 122 R */
+ {v_Replace, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]R",
+ " R replace characters"},
+/* 123 S */
+ {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|VM_RCM_SET,
+ "[count]T character",
+ " T before character in line backward search"},
+/* 125 U */
+ {v_Undo, VM_RCM_SET,
+ "U",
+ " U Restore the current line"},
+/* 126 V */
+ {NULL},
+/* 127 W */
+ {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|VM_RCM_SET,
+ "[buffer][count]X",
+ " X delete character before cursor"},
+/* 131 Y */
+ {v_yank, V_CNT|VM_LMODE|V_OBUF,
+ "[buffer][count]Y",
+ " Y copy line"},
+/* 132 Z */
+ {v_zexit, 0,
+ "ZZ",
+ "ZZ save file and exit"},
+/* 133 [ */
+ {v_sectionb, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
+ "[[",
+ "[[ move back section"},
+/* 134 \ */
+ {NULL},
+/* 135 ] */
+ {v_sectionf, V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
+ "]]",
+ "]] move forward section"},
+/* 136 ^ */
+ /*
+ * 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|VM_RCM_SET,
+ "^",
+ " ^ move to first non-blank"},
+/* 137 _ */
+ /*
+ * 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|VM_RCM_SETFNB,
+ "_",
+ " _ move to first non-blank"},
+/* 140 ` */
+ {v_bmark, V_ABS_C|V_CHAR|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "`[`a-z]",
+ " ` move to mark"},
+/* 141 a */
+ {v_ia, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]a",
+ " a append after cursor"},
+/* 142 b */
+ {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|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|VC_D|VM_RCM_SET,
+ "[buffer][count]d[count]motion",
+ " d delete to motion"},
+/* 145 e */
+ {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|VM_RCM_SET,
+ "[count]f character",
+ " f character in line forward search"},
+/* 147 g */
+ {NULL},
+/* 150 h */
+ {v_left, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]h",
+ " h move left by columns"},
+/* 151 i */
+ {v_ii, V_CNT|V_DOT|VM_RCM_SET,
+ "[count]i",
+ " i insert before cursor"},
+/* 152 j */
+ {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM,
+ "[count]j",
+ " j move down by lines"},
+/* 153 k */
+ {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|VM_RCM_SET,
+ "[count]l",
+ " l move right by columns"},
+/* 155 m */
+ {v_mark, V_CHAR,
+ "m[a-z]",
+ " m set mark"},
+/* 156 n */
+ {v_searchn, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "n",
+ " n repeat last search"},
+/* 157 o */
+ {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|VM_RCM_SET,
+ "[buffer]p",
+ " p insert after cursor from buffer"},
+/* 161 q */
+ {NULL},
+/* 162 r */
+ {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|VM_RCM_SET,
+ "[buffer][count]s",
+ " s substitute character"},
+/* 164 t */
+ {v_cht, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]t character",
+ " t before character in line forward search"},
+/* 165 u */
+ /*
+ * DON'T set the V_DOT flag, it' more complicated than that.
+ * See vi/vi.c for details.
+ */
+ {v_undo, VM_RCM_SET,
+ "u",
+ " u undo last change"},
+/* 166 v */
+ {NULL},
+/* 167 w */
+ {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|VM_RCM_SET,
+ "[buffer][count]x",
+ " x delete character"},
+/* 171 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 */
+ /*
+ * DON'T set the V_CHAR flag, the char isn't required,
+ * so it's handled specially in getcmd().
+ */
+ {v_z, V_ABS_L|V_CNT|VM_RCM_SET,
+ "[line]z[window_size][-|.|+|^|<CR>]",
+ " z redraw window"},
+/* 173 { */
+ {v_paragraphb, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "[count]{",
+ " { move back paragraph"},
+/* 174 | */
+ {v_ncol, V_CNT|V_MOVE|VM_RCM_SET,
+ "[count]|",
+ " | move to column"},
+/* 175 } */
+ {v_paragraphf, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
+ "[count]}",
+ " } move forward paragraph"},
+/* 176 ~ */
+ {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..4c13076b4e5d
--- /dev/null
+++ b/usr.bin/vi/vi/vcmd.h
@@ -0,0 +1,346 @@
+/*-
+ * 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.
+ *
+ * @(#)vcmd.h 8.40 (Berkeley) 8/5/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 command and
+ * 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_DEF 0x00000004 /* The '<', '>' and '!' commands. */
+#define VC_Y 0x00000008 /* The 'y' command. */
+#define VC_COMMASK 0x0000000f /* Mask for VC flags. */
+#define ISMOTION(vp) F_ISSET(vp, VC_COMMASK)
+
+#define VM_CUTREQ 0x00000010 /* Always cut into numeric buffers. */
+#define VM_LDOUBLE 0x00000020 /* Doubled command for line mode. */
+#define VM_LMODE 0x00000040 /* Motion is line oriented. */
+#define VM_NOMOTION 0x00000080 /* Motion command not entered. */
+#define VM_COMMASK 0x000000f0 /* Mask for VM flags. */
+
+ /*
+ * The VM_RCM_* flags are single usage, i.e. if you set one, you have
+ * to clear the others.
+ */
+#define VM_RCM 0x00000100 /* Use relative cursor movment (RCM). */
+#define VM_RCM_SET 0x00000200 /* RCM: set to current position. */
+#define VM_RCM_SETFNB 0x00000400 /* RCM: set to first non-blank (FNB). */
+#define VM_RCM_SETLAST 0x00000800 /* RCM: set to last character. */
+#define VM_RCM_SETNNB 0x00001000 /* RCM: set to next non-blank. */
+#define VM_RCM_MASK 0x00001f00 /* Mask for RCM flags. */
+
+ /* Flags for the underlying function. */
+#define VC_BUFFER 0x00002000 /* The buffer was set. */
+#define VC_C1RESET 0x00004000 /* Reset C1SET flag for dot commands. */
+#define VC_C1SET 0x00008000 /* Count 1 was set. */
+#define VC_C2SET 0x00010000 /* Count 2 was set. */
+#define VC_ISDOT 0x00020000 /* 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 them 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.
+ *
+ * The 'c', '<', '>', and '!' commands are special cases. We ignore
+ * the final cursor position for all of them: for 'c', the text input
+ * routines set the cursor to the last character inserted; for '<',
+ * '>' and '!', the underlying ex commands that do the operation will
+ * set the cursor for us. We still need a VC_C flag because there are
+ * special motion semantics that are associated with the 'c' command.
+ * We don't need VC_ flags for the others, because, as far as I know,
+ * there are no special semantics associated with their motions. So,
+ * we group them under a single VC_ flag so that the standard motion
+ * adjustments get done.
+ */
+ 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 0x00040000 /* Absolute movement, set '' mark. */
+#define V_ABS_C 0x00080000 /* V_ABS: if the line/column changed. */
+#define V_ABS_L 0x00100000 /* V_ABS: if the line changed. */
+#define V_CHAR 0x00200000 /* Character (required, trailing). */
+#define V_CNT 0x00400000 /* Count (optional, leading). */
+#define V_DOT 0x00800000 /* On success, sets dot command. */
+#define V_KEYNUM 0x01000000 /* Cursor referenced number. */
+#define V_KEYW 0x02000000 /* Cursor referenced word. */
+#define V_MOTION 0x04000000 /* Motion (required, trailing). */
+#define V_MOVE 0x08000000 /* Command defines movement. */
+#define V_OBUF 0x10000000 /* Buffer (optional, leading). */
+#define V_RBUF 0x20000000 /* 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];
+extern VIKEYS const tmotion; /* XXX Hacked ~ command. */
+
+/* Definition of a vi "word". */
+#define inword(ch) (isalnum(ch) || (ch) == '_')
+
+/* Offset to next column of stop size. */
+#define STOP_OFF(c, stop) (stop - (c) % stop)
+
+/* Character stream structure, prototypes. */
+typedef struct _vcs {
+ recno_t cs_lno; /* Line. */
+ size_t cs_cno; /* Column. */
+ CHAR_T *cs_bp; /* Buffer. */
+ size_t cs_len; /* Length. */
+ CHAR_T 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 *ps; /* Paragraph plus section list. */
+
+ 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_buildps __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 *, ARG_CHAR_T, 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_mulcase);
+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/vi/vi.c b/usr.bin/vi/vi/vi.c
new file mode 100644
index 000000000000..9e52eb1c8884
--- /dev/null
+++ b/usr.bin/vi/vi/vi.c
@@ -0,0 +1,937 @@
+/*-
+ * 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[] = "@(#)vi.c 8.89 (Berkeley) 8/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/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 "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+#include "vcmd.h"
+
+static int getcmd __P((SCR *, EXF *,
+ VICMDARG *, VICMDARG *, VICMDARG *, int *, int *));
+static __inline int
+ getcount __P((SCR *, ARG_CHAR_T, u_long *));
+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 *, int *));
+
+/*
+ * Side-effect:
+ * The dot structure can be set by the underlying vi functions,
+ * see v_Put() and v_put().
+ */
+#define DOT (&VIP(sp)->sdot)
+#define DOTMOTION (&VIP(sp)->sdotmotion)
+
+/*
+ * vi --
+ * Main vi command loop.
+ */
+int
+vi(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ MARK abs;
+ VICMDARG cmd, *vp;
+ u_int flags, saved_mode;
+ int comcount, eval, mapped;
+
+ /* Start vi and paint the screen. */
+ if (v_init(sp, ep))
+ return (1);
+
+ /* Command initialization. */
+ memset(&cmd, 0, sizeof(VICMDARG));
+
+ for (eval = 0, vp = &cmd;;) {
+ /* Refresh the screen. */
+ sp->showmode = "Command";
+ if (sp->s_refresh(sp, ep)) {
+ eval = 1;
+ break;
+ }
+
+ /* Set the new favorite position. */
+ if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) {
+ sp->rcm_last = 0;
+ (void)sp->s_column(sp, ep, &sp->rcm);
+ }
+
+ /*
+ * If not currently in a map, log the cursor position,
+ * and set a flag so that this command can become the
+ * DOT command.
+ */
+ if (MAPPED_KEYS_WAITING(sp))
+ mapped = 1;
+ else {
+ if (log_cursor(sp, ep))
+ goto err;
+ mapped = 0;
+ }
+
+ /*
+ * We get a command, which may or may not have an associated
+ * motion. If it does, we get it too, calling its underlying
+ * function to get the resulting mark. We then call the
+ * command setting the cursor to the resulting mark.
+ */
+ if (getcmd(sp, ep, DOT, vp, NULL, &comcount, &mapped))
+ goto err;
+
+ /*
+ * Historical practice: if a dot command gets a new count,
+ * any motion component goes away, i.e. "d3w2." deletes a
+ * total of 5 words.
+ */
+ 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. */
+ if (F_ISSET(vp, V_KEYNUM | V_KEYW) &&
+ getkeyword(sp, ep, vp, vp->flags))
+ goto err;
+
+ /* Prepare to set the previous context. */
+ if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) {
+ abs.lno = sp->lno;
+ abs.cno = sp->cno;
+ }
+
+ /*
+ * 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.
+ */
+ 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;
+
+ /*
+ * 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, &mapped))
+ 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;
+
+ /* Save the mode and call the function. */
+ saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
+ if ((vp->kp->func)(sp, ep, vp))
+ goto err;
+#ifdef DEBUG
+ /* Make sure no function left the temporary space locked. */
+ if (F_ISSET(sp->gp, G_TMP_INUSE)) {
+ msgq(sp, M_ERR,
+ "Error: vi: temporary buffer not released");
+ return (1);
+ }
+#endif
+ /*
+ * If that command took us out of vi or changed the screen,
+ * then exit the loop without further action.
+ */
+ if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))
+ break;
+
+ /*
+ * Set the dot command structure.
+ *
+ * !!!
+ * Historically, no command which used any mapped keys became
+ * the dot command.
+ */
+ if (F_ISSET(vp, V_DOT) && !mapped) {
+ *DOT = cmd;
+ F_SET(DOT, VC_ISDOT);
+
+ /*
+ * If a count was supplied for both the command and
+ * its motion, the count was used only for the motion.
+ * Turn the count back on for the dot structure.
+ */
+ if (F_ISSET(vp, VC_C1RESET))
+ F_SET(DOT, VC_C1SET);
+
+ /* VM flags aren't retained. */
+ F_CLR(DOT, VM_COMMASK | VM_RCM_MASK);
+ }
+
+ /*
+ * Some vi row movements are "attracted" to the last position
+ * 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 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
+ * have to modify the column because they are always line mode
+ * operations when used as motions, so the column number isn't
+ * of any interest.
+ *
+ * Does this totally violate the screen and editor layering?
+ * You betcha. As they say, if you think you understand it,
+ * you don't.
+ */
+ switch (F_ISSET(vp, VM_RCM_MASK)) {
+ case 0:
+ case VM_RCM_SET:
+ break;
+ case VM_RCM:
+ vp->m_final.cno = sp->s_rcm(sp, ep, vp->m_final.lno);
+ break;
+ case VM_RCM_SETLAST:
+ sp->rcm_last = 1;
+ break;
+ case VM_RCM_SETFNB:
+ vp->m_final.cno = 0;
+ /* FALLTHROUGH */
+ case VM_RCM_SETNNB:
+ if (nonblank(sp, ep, vp->m_final.lno, &vp->m_final.cno))
+ goto err;
+ break;
+ default:
+ abort();
+ }
+
+ /* Update the cursor. */
+ sp->lno = vp->m_final.lno;
+ sp->cno = vp->m_final.cno;
+
+ /*
+ * Set the absolute mark -- set even if a tags or similar
+ * command, since the tag may be moving to the same file.
+ */
+ if ((F_ISSET(vp, V_ABS) ||
+ F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno ||
+ F_ISSET(vp, V_ABS_C) &&
+ (sp->lno != abs.lno || sp->cno != abs.cno)) &&
+ mark_set(sp, ep, ABSMARK1, &abs, 1))
+ goto err;
+
+ if (!MAPPED_KEYS_WAITING(sp))
+ (void)msg_rpt(sp, 1);
+
+ /*
+ * Check and clear the interrupts. There's an obvious race,
+ * but it's not worth cleaning up. This is done after the
+ * err: lable, so that if the "error" was an interupt it gets
+ * cleaned up.
+ *
+ * !!!
+ * Previous versions of nvi cleared mapped characters on error,
+ * even if it wasn't an interrupt. This feature was removed as
+ * users complained that it wasn't historic practice and that
+ * they used leading (illegal) <escape> characters in the map
+ * to clean up vi state before the map was interpreted.
+ */
+err: if (INTERRUPTED(sp))
+ term_flush(sp, "Interrupted", CH_MAPPED);
+ CLR_INTERRUPT(sp);
+ }
+
+ /* Free allocated keyword memory. */
+ if (cmd.keyword != NULL)
+ free(cmd.keyword);
+
+ return (v_end(sp) || eval);
+}
+
+#define KEY(key, map) { \
+ if (getkey(sp, &ikey, map)) \
+ return (1); \
+ if (ikey.value == K_ESCAPE) \
+ goto esc; \
+ if (F_ISSET(&ikey, CH_MAPPED)) \
+ *mappedp = 1; \
+ key = ikey.ch; \
+}
+
+/*
+ * The O_TILDEOP option makes the ~ command take a motion instead
+ * of a straight count. This is the replacement structure we use
+ * instead of the one currently in the VIKEYS table.
+ *
+ * XXX
+ * Note, I used VC_Y instead of creating a new motion command, it's
+ * a lot easier.
+ */
+VIKEYS const tmotion = {
+ v_mulcase, V_CNT|V_DOT|V_MOTION|VC_Y|VM_RCM_SET,
+ "[count]~[count]motion",
+ " ~ change case to motion"
+};
+
+/*
+ * getcmd --
+ *
+ * The command structure for vi is less complex than ex (and don't think
+ * I'm not grateful!) The command syntax is:
+ *
+ * [count] [buffer] [count] key [[motion] | [buffer] [character]]
+ *
+ * and there are several special cases. The motion value is itself a vi
+ * command, with the syntax:
+ *
+ * [count] key [character]
+ */
+static int
+getcmd(sp, ep, dp, vp, ismotion, comcountp, mappedp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *dp, *vp;
+ VICMDARG *ismotion; /* Previous key if getting motion component. */
+ int *comcountp, *mappedp;
+{
+ enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart;
+ VIKEYS const *kp;
+ u_int flags;
+ CH ikey;
+ CHAR_T key;
+ char *s;
+
+ /* Refresh the command structure. */
+ memset(&vp->vp_startzero, 0,
+ (char *)&vp->vp_endzero - (char *)&vp->vp_startzero);
+
+ /*
+ * Get a key.
+ *
+ * <escape> cancels partial commands, i.e. a command where at least
+ * one non-numeric character has been entered. Otherwise, it beeps
+ * the terminal.
+ *
+ * !!!
+ * POSIX 1003.2-1992 explicitly disallows cancelling commands where
+ * all that's been entered is a number, requiring that the terminal
+ * be alerted.
+ */
+ cpart = ismotion == NULL ? COMMANDMODE : ISPARTIAL;
+ KEY(key, TXT_MAPCOMMAND);
+ if (ismotion == NULL)
+ cpart = NOTPARTIAL;
+
+ /* Pick up optional buffer. */
+ if (key == '"') {
+ cpart = ISPARTIAL;
+ if (ismotion != NULL) {
+ msgq(sp, M_BERR,
+ "Buffers should be specified before the command");
+ return (1);
+ }
+ KEY(vp->buffer, 0);
+ F_SET(vp, VC_BUFFER);
+
+ KEY(key, TXT_MAPCOMMAND);
+ }
+
+ /*
+ * Pick up optional count, where a leading 0 is not a count,
+ * it's a command.
+ */
+ if (isdigit(key) && key != '0') {
+ if (getcount(sp, key, &vp->count))
+ return (1);
+ F_SET(vp, VC_C1SET);
+ *comcountp = 1;
+
+ KEY(key, TXT_MAPCOMMAND);
+ } else
+ *comcountp = 0;
+
+ /* Pick up optional buffer. */
+ if (key == '"') {
+ cpart = ISPARTIAL;
+ if (F_ISSET(vp, VC_BUFFER)) {
+ msgq(sp, M_ERR, "Only one buffer can be specified");
+ return (1);
+ }
+ if (ismotion != NULL) {
+ msgq(sp, M_BERR,
+ "Buffers should be specified before the command");
+ return (1);
+ }
+ KEY(vp->buffer, 0);
+ F_SET(vp, VC_BUFFER);
+
+ KEY(key, TXT_MAPCOMMAND);
+ }
+
+ /* Check for an OOB command key. */
+ cpart = ISPARTIAL;
+ if (key > MAXVIKEY) {
+ msgq(sp, M_BERR, "%s isn't a vi command", KEY_NAME(sp, key));
+ return (1);
+ }
+ kp = &vikeys[vp->key = key];
+
+ /* The tildeop option makes the ~ command take a motion. */
+ if (key == '~' && O_ISSET(sp, O_TILDEOP))
+ kp = &tmotion;
+
+ vp->kp = kp;
+
+ /*
+ * Find the command. The only legal command with no underlying
+ * function is dot. It's historic practice that <escape> doesn't
+ * just erase the preceding number, it beeps the terminal as well.
+ * It's a common problem, so just beep the terminal unless verbose
+ * was set.
+ */
+ if (kp->func == NULL) {
+ if (key != '.') {
+ msgq(sp, ikey.value == K_ESCAPE ? M_BERR : M_ERR,
+ "%s isn't a vi command", KEY_NAME(sp, key));
+ return (1);
+ }
+
+ /* If called for a motion command, stop now. */
+ if (dp == NULL)
+ goto usage;
+
+ /* A repeatable command must have been executed. */
+ if (!F_ISSET(dp, VC_ISDOT)) {
+ msgq(sp, M_ERR, "No command to repeat");
+ return (1);
+ }
+
+ /*
+ * !!!
+ * If a '.' is immediately entered after an undo command, we
+ * replay the log instead of redoing the last command. This
+ * is necessary because 'u' can't set the dot command -- see
+ * vi/v_undo.c:v_undo for details.
+ */
+ if (VIP(sp)->u_ccnt == sp->ccnt) {
+ vp->kp = &vikeys['u'];
+ F_SET(vp, VC_ISDOT);
+ return (0);
+ }
+
+ /* Set new count/buffer, if any, and return. */
+ if (F_ISSET(vp, VC_C1SET)) {
+ F_SET(dp, VC_C1SET);
+ dp->count = vp->count;
+ }
+ if (F_ISSET(vp, VC_BUFFER))
+ dp->buffer = vp->buffer;
+ *vp = *dp;
+ return (0);
+ }
+
+ /* Set the flags based on the command flags. */
+ flags = kp->flags;
+
+ /* Check for illegal count. */
+ if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT))
+ goto usage;
+
+ /* Illegal motion command. */
+ if (ismotion == NULL) {
+ /* Illegal buffer. */
+ if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER))
+ goto usage;
+
+ /* Required buffer. */
+ if (LF_ISSET(V_RBUF)) {
+ KEY(vp->buffer, 0);
+ F_SET(vp, VC_BUFFER);
+ }
+ }
+
+ /*
+ * 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') {
+ /*
+ * Historically, half entered [[, ]] or Z commands weren't
+ * cancelled by <escape>, the terminal was beeped instead.
+ * POSIX.2-1992 probably didn't notice, and requires that
+ * they be cancelled instead of beeping. Seems fine to me.
+ */
+ KEY(key, TXT_MAPCOMMAND);
+
+ if (vp->key != key) {
+usage: if (ismotion == NULL)
+ s = kp->usage;
+ else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP))
+ s = tmotion.usage;
+ else
+ s = vikeys[ismotion->key].usage;
+ msgq(sp, M_ERR, "Usage: %s", s);
+ return (1);
+ }
+ }
+ /* 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);
+ }
+ }
+
+ /*
+ * Commands that have motion components can be doubled to
+ * imply the current line.
+ */
+ if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
+ msgq(sp, M_ERR, "%s may not be used as a motion command",
+ KEY_NAME(sp, key));
+ return (1);
+ }
+
+ /* Required character. */
+ if (LF_ISSET(V_CHAR))
+ KEY(vp->character, 0);
+
+ return (0);
+
+esc: switch (cpart) {
+ case COMMANDMODE:
+ msgq(sp, M_BERR, "Already in command mode");
+ break;
+ case ISPARTIAL:
+ break;
+ case NOTPARTIAL:
+ (void)sp->s_bell(sp);
+ break;
+ }
+ return (1);
+}
+
+/*
+ * getmotion --
+ *
+ * Get resulting motion mark.
+ */
+static int
+getmotion(sp, ep, dm, vp, mappedp)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *dm, *vp;
+ int *mappedp;
+{
+ MARK m;
+ VICMDARG motion;
+ size_t len;
+ u_long cnt;
+ int notused;
+
+ /*
+ * If '.' command, use the dot motion, else get the motion command.
+ * Clear any line motion flags, the subsequent motion isn't always
+ * the same, i.e. "/aaa" may or may not be a line motion.
+ */
+ if (F_ISSET(vp, VC_ISDOT)) {
+ motion = *dm;
+ F_SET(&motion, VC_ISDOT);
+ F_CLR(&motion, VM_COMMASK);
+ } else if (getcmd(sp, ep, NULL, &motion, vp, &notused, mappedp))
+ return (1);
+
+ /*
+ * 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.
+ */
+ cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
+ if (F_ISSET(vp, VC_C1SET)) {
+ motion.count *= vp->count;
+ F_SET(&motion, VC_C1SET);
+
+ /*
+ * Set flags to restore the original values of the command
+ * structure so dot commands can change the count values,
+ * e.g. "2dw" "3." deletes a total of five words.
+ */
+ F_CLR(vp, VC_C1SET);
+ F_SET(vp, VC_C1RESET);
+ }
+
+ /*
+ * Some commands can be repeated to indicate the current line. In
+ * this case, or if the command is a "line command", set the flags
+ * appropriately. If not a doubled command, run the function to get
+ * the resulting mark.
+ */
+ if (vp->key == motion.key) {
+ F_SET(vp, VM_LDOUBLE | 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.
+ *
+ * If the current line is missing, i.e. the file is empty,
+ * historic vi permitted a "cc" or "!!" command to insert
+ * text.
+ */
+ 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);
+ }
+ vp->m_stop.cno = 0;
+ } else
+ vp->m_stop.cno = len ? len - 1 : 0;
+ } else {
+ /*
+ * Motion commands change the underlying movement (*snarl*).
+ * For example, "l" is illegal at the end of a line, but "dl"
+ * is not. Set flags so the function knows the situation.
+ */
+ F_SET(&motion, vp->kp->flags & VC_COMMASK);
+
+ /*
+ * Copy the key flags into the local structure, except for
+ * the RCM flags, the motion command will set the RCM flags
+ * in the vp structure as necessary.
+ */
+ F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK);
+
+ /*
+ * 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.
+ */
+ 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);
+
+ /*
+ * Copy cut buffer, line mode and cursor position information
+ * from the motion command structure, i.e. anything that the
+ * motion command can set for us. The commands can flag the
+ * movement as a line motion (see v_sentence) as well as set
+ * the VM_RCM_* flags explicitly.
+ */
+ F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK));
+
+ /*
+ * 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 (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 (F_ISSET(vp->kp, V_DOT)) {
+ *dm = motion;
+ dm->count = cnt;
+ }
+ return (0);
+}
+
+#define innum(c) (isdigit(c) || strchr("abcdefABCDEF", c))
+
+/*
+ * getkeyword --
+ * Get the "word" the cursor is on.
+ */
+static int
+getkeyword(sp, ep, kp, flags)
+ SCR *sp;
+ EXF *ep;
+ VICMDARG *kp;
+ u_int flags;
+{
+ recno_t lno;
+ size_t beg, end, len;
+ char *p;
+
+ if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) {
+ if (file_lline(sp, ep, &lno))
+ return (1);
+ if (lno == 0)
+ v_eof(sp, ep, NULL);
+ else
+ GETLINE_ERR(sp, sp->lno);
+ return (1);
+ }
+
+ /*
+ * !!!
+ * Historically, tag commands skipped over any leading whitespace
+ * characters.
+ */
+ for (beg = sp->cno; beg < len && isspace(p[beg]); ++beg);
+
+ if (beg >= len ||
+ LF_ISSET(V_KEYW) && !inword(p[beg]) ||
+ LF_ISSET(V_KEYNUM) && !innum(p[beg]) &&
+ p[beg] != '-' && p[beg] != '+')
+ goto noword;
+
+ /*
+ * !!!
+ * Find the beginning/end of the keyword. Keywords (V_KEYW) are
+ * used for cursor-word searching and for tags. Historical vi
+ * only used the word in a tag search from the cursor to the end
+ * of the word, i.e. if the cursor was on the 'b' in " abc ", the
+ * tag was "bc". For no particular reason, we make the cursor
+ * word searches follow the same rule.
+ */
+ if (beg != 0)
+ if (LF_ISSET(V_KEYW)) {
+#ifdef MOVE_TO_KEYWORD_BEGINNING
+ for (;;) {
+ --beg;
+ if (!inword(p[beg])) {
+ ++beg;
+ break;
+ }
+ if (beg == 0)
+ break;
+ }
+#endif
+ } else {
+ for (;;) {
+ --beg;
+ if (!innum(p[beg])) {
+ if (beg > 0 && p[beg - 1] == '0' &&
+ (p[beg] == 'X' || p[beg] == 'x'))
+ --beg;
+ else
+ ++beg;
+ break;
+ }
+ if (beg == 0)
+ break;
+ }
+
+ /* Skip possible leading sign. */
+ if (beg != 0 && p[beg] != '0' &&
+ (p[beg - 1] == '+' || p[beg - 1] == '-'))
+ --beg;
+ }
+
+ if (LF_ISSET(V_KEYW)) {
+ for (end = beg; ++end < len && inword(p[end]););
+ --end;
+ } else {
+ for (end = beg; ++end < len;) {
+ if (p[end] == 'X' || p[end] == 'x') {
+ if (end != beg + 1 || p[beg] != '0')
+ break;
+ continue;
+ }
+ if (!innum(p[end]))
+ break;
+ }
+
+ /* Just a sign isn't a number. */
+ if (end == beg && (p[beg] == '+' || p[beg] == '-')) {
+noword: msgq(sp, M_BERR, "Cursor not in a %s",
+ LF_ISSET(V_KEYW) ? "word" : "number");
+ return (1);
+ }
+ --end;
+ }
+
+ /*
+ * Getting a keyword implies moving the cursor to its beginning.
+ * Refresh now.
+ */
+ if (beg != sp->cno) {
+ sp->cno = beg;
+ sp->s_refresh(sp, ep);
+ }
+
+ /*
+ * XXX
+ * 8-bit clean problem. Numeric keywords are handled using strtol(3)
+ * and friends. This would have to be fixed in v_increment and here
+ * to not depend on a trailing NULL.
+ */
+ len = (end - beg) + 2; /* XXX */
+ kp->klen = (end - beg) + 1;
+ BINC_RET(sp, kp->keyword, kp->kbuflen, len);
+ memmove(kp->keyword, p + beg, kp->klen);
+ kp->keyword[kp->klen] = '\0'; /* XXX */
+ return (0);
+}
+
+/*
+ * getcount --
+ * Return the next count.
+ */
+static __inline int
+getcount(sp, fkey, countp)
+ SCR *sp;
+ ARG_CHAR_T fkey;
+ u_long *countp;
+{
+ u_long count, tc;
+ CH ikey;
+
+ ikey.ch = fkey;
+ count = tc = 0;
+ do {
+ /* Assume that overflow results in a smaller number. */
+ tc = count * 10 + ikey.ch - '0';
+ if (count > tc) {
+ /* Toss to the next non-digit. */
+ do {
+ if (getkey(sp, &ikey,
+ TXT_MAPCOMMAND | TXT_MAPNODIGIT))
+ return (1);
+ } while (isdigit(ikey.ch));
+ msgq(sp, M_ERR, "Number larger than %lu", ULONG_MAX);
+ return (1);
+ }
+ count = tc;
+ if (getkey(sp, &ikey, TXT_MAPCOMMAND | TXT_MAPNODIGIT))
+ return (1);
+ } while (isdigit(ikey.ch));
+ *countp = count;
+ return (0);
+}
+
+/*
+ * getkey --
+ * Return the next key.
+ */
+static __inline int
+getkey(sp, ikeyp, map)
+ SCR *sp;
+ CH *ikeyp;
+ u_int map;
+{
+ switch (term_key(sp, ikeyp, map)) {
+ case INP_EOF:
+ case INP_ERR:
+ F_SET(sp, S_EXIT_FORCE);
+ return (1);
+ case INP_INTR:
+ /*
+ * !!!
+ * Historically, vi beeped on command level interrupts.
+ *
+ * Historically, vi exited to ex mode if no file was named
+ * on the command line, and two interrupts were generated
+ * in a row. (Just figured you might want to know that.)
+ */
+ (void)sp->s_bell(sp);
+ return (1);
+ case INP_OK:
+ return (0);
+ }
+ /* NOTREACHED */
+}
diff --git a/usr.bin/vi/xaw/xaw_screen.c b/usr.bin/vi/xaw/xaw_screen.c
new file mode 100644
index 000000000000..14a9674ffefe
--- /dev/null
+++ b/usr.bin/vi/xaw/xaw_screen.c
@@ -0,0 +1,98 @@
+/*-
+ * 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[] = "@(#)xaw_screen.c 8.6 (Berkeley) 5/21/94";
+#endif /* not lint */
+
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "compat.h"
+#include <db.h>
+#include <regex.h>
+
+#include "vi.h"
+
+/*
+ * xaw_init --
+ * Athena widget screen initialization.
+ */
+int
+xaw_screen_init(sp)
+ SCR *sp;
+{
+ msgq(sp, M_ERR, "The Athena widget screen not yet implemented");
+ return (1);
+}
+
+/*
+ * xaw_screen_copy --
+ * Copy to a new screen.
+ */
+int
+xaw_screen_copy(orig, sp)
+ SCR *orig, *sp;
+{
+ return (0);
+}
+
+/*
+ * xaw_screen_end --
+ * End a screen.
+ */
+int
+xaw_screen_end(sp)
+ SCR *sp;
+{
+ return (0);
+}
+
+/*
+ * xaw --
+ * Main vi Athena widget screen loop.
+ */
+int
+xaw(sp, ep, spp)
+ SCR *sp, **spp;
+ EXF *ep;
+{
+ *spp = NULL;
+ return (0);
+}