Remove the old nvi-1.34, it has served us well but it's time has come..

(It was tagged immediately prior to removal with the tag "nvi_1_34_final")
This commit is contained in:
Peter Wemm 1996-11-01 08:25:51 +00:00
parent 4f85133da7
commit 301b0bb501
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=19311
181 changed files with 0 additions and 67408 deletions

View File

@ -1,200 +0,0 @@
# @(#)README 8.86 (Berkeley) 8/17/94
This is the README for version 1.34 of nex/nvi, a freely redistributable
replacement for the Berkeley ex and vi text editors. The compressed or
gzip'd archives 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.

View File

@ -1,18 +0,0 @@
# @(#)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>

View File

@ -1,115 +0,0 @@
.\" 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

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
# @(#)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>

File diff suppressed because it is too large Load Diff

View File

@ -1,734 +0,0 @@
.\" 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

View File

@ -1,14 +0,0 @@
# @(#)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}

View File

@ -1,798 +0,0 @@
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
# @(#)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>

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +0,0 @@
# @(#)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"
}

View File

@ -1,127 +0,0 @@
.\" Copyright (c) 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)ref.so 8.6 (Berkeley) 7/15/94
.\"
.\"
.\" indented paragraph, with spaces between the items, bold font
.de IP
.\".tm arg 1 \\$1 arg 2 \\$2 arg 3 \\$3
.sp 1
.nr PS \\n(ps
.nr ps 0
.ip "\fB\\$1\fP" \\$2
.nr ps \\n(PS
.br
..
.\" indented paragraph, no spaces between the items, bold font
.de Ip
.\".tm arg 1 \\$1 arg 2 \\$2 arg 3 \\$3
.nr PS \\n(ps
.nr ps 0
.ns
.ip "\fB\\$1\fP" \\$2
.nr ps \\n(PS
.br
..
.\" start nested .IP
.de SS
.sp
.ba +5n
..
.\" end nested .IP
.de SE
.ba -5n
..
.\" nested .IP, no spaces, normal font
.de SP
.\".tm arg 1 \\$1 arg 2 \\$2 arg 3 \\$3
.nr PS \\n(ps
.nr ps 0
.ns
.ip "\\$1" 9n
.nr ps \\n(PS
..
.\" typewriter font
.de LI
\&\fC\\$1\fP\\$2
..
.\" ex/vi names in command font
.de EV
\&\fB\\$1\fP/\fB\\$2\fP\\$3
..
.\" command names
.de CO
\&\fB\\$1\fP\\$2
..
.\" key words for index
.de KY
.sy echo >>index '\\$1 \\n%'
..
.\" option names
.de OP
\&\fB\\$1\fP\\$2
..
.\" paren quoted (typewriter font)
.de PQ
(\*(lq\fC\\$1\fP\*(rq)\\$2
..
.\" quoted bold
.de QB
\*(lq\fB\\$1\fP\*(rq\\$2
..
.\" quoted command
.de QC
\*(lq\fB\\$1\fP\*(rq\\$2
..
.\" quoted option
.de QO
\*(lq\fB\\$1\fP\*(rq\\$2
..
.\" quoted (no font change)
.de QQ
\*(lq\\$1\*(rq\\$2
..
.\" quoted (typewriter font)
.de QT
\*(lq\fC\\$1\fP\*(rq\\$2
..
.\" section macro to build TOC
.de SH
.(x
\\$2
.)x
.sh \\$1 "\\$2"
..
.\" manual section
.de XR
\&\fI\\$1\fP(\\$2)\\$3
..

View File

@ -1,949 +0,0 @@
.\" Copyright (c) 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)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.

View File

@ -1,270 +0,0 @@
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
# @(#)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>

File diff suppressed because it is too large Load Diff

View File

@ -1,644 +0,0 @@
.\" 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
\&.

File diff suppressed because it is too large Load Diff

View File

@ -1,468 +0,0 @@
.\" 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

View File

@ -1,108 +0,0 @@
# @(#)Makefile 8.51 (Berkeley) 8/17/94
VI= nvi
EX= nex
VIEW= nview
PROG= nvi
LINKS= ${BINDIR}/${VI} ${BINDIR}/${EX} ${BINDIR}/${VI} ${BINDIR}/${VIEW}
LINKS+= ${BINDIR}/${VI} ${BINDIR}/vi ${BINDIR}/${EX} ${BINDIR}/ex
LINKS+= ${BINDIR}/${VI} ${BINDIR}/view
MAN1= ${.CURDIR}/../USD.doc/vi.man/vi.1
MLINKS+=vi.1 ex.1 vi.1 view.1
MLINKS+=vi.1 nex.1 vi.1 nview.1 vi.1 nvi.1
CFLAGS+=-I. -I${.CURDIR}
DPADD+= ${LIBCURSES} ${LIBTERMCAP} ${LIBUTIL}
LDADD+= -lcurses -ltermcap -lutil
.PATH: ${.CURDIR}/../common ${.CURDIR}/../ex ${.CURDIR}/../sex \
${.CURDIR}/../vi ${.CURDIR}/../svi ${.CURDIR}/../xaw
SPECHDR=compat.h excmd.h options.h
CLEANFILES+=${SPECHDR} ${EX}
# 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 ${SPECHDR}
# 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
all: ${VI} ${EX}
all: nvi nex
nex: nvi
rm -f nex
ln nvi nex
${EX}: ${VI}
rm -f ${EX}
ln ${VI} ${EX}
compat.h:
:> compat.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
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
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 -ltermcap 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
.include "../../Makefile.inc"
.include <bsd.prog.mk>
.depend: ${SPECHDR}

View File

@ -1,53 +0,0 @@
/*-
* 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;

View File

@ -1,366 +0,0 @@
/*-
* 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.34 (Berkeley) 8/17/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));
}

View File

@ -1,96 +0,0 @@
/*-
* 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 *));

View File

@ -1,195 +0,0 @@
/*-
* 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.12 (Berkeley) 8/17/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);
}
if (len != 0) {
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);
}

View File

@ -1,837 +0,0 @@
/*-
* 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.97 (Berkeley) 8/17/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...
*
* !!!
* Note, because the EXF structure is examine at interrupt time,
* the underlying DB structures have to be consistent as soon as
* it's assigned to an SCR structure.
*/
++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
}

View File

@ -1,128 +0,0 @@
/*-
* 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));

View File

@ -1,107 +0,0 @@
/*-
* 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. */

View File

@ -1,492 +0,0 @@
/*-
* 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.32 (Berkeley) 8/17/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));
}

View File

@ -1,698 +0,0 @@
/*-
* 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.18 (Berkeley) 8/17/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

View File

@ -1,53 +0,0 @@
/*-
* 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 *));

View File

@ -1,720 +0,0 @@
/*-
* 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.106 (Berkeley) 8/17/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.
*
* !!!
* Signals not on, no need to block them for queue manipulation.
*/
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) {
SIGBLOCK(__global_list);
CIRCLEQ_REMOVE(&sp->gp->hq, sp, q);
CIRCLEQ_INSERT_TAIL(&sp->gp->dq, sp, q);
SIGUNBLOCK(__global_list);
} 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);
/*
* !!!
* Signals not on, no need to block them for queue manipulation.
*/
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);
}

View File

@ -1,272 +0,0 @@
/*-
* 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.21 (Berkeley) 8/17/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 */
}

View File

@ -1,73 +0,0 @@
/*-
* 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));

View File

@ -1,194 +0,0 @@
/*-
* 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.8 (Berkeley) 8/16/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) { \
void *__bincp; \
if ((nlen) > llen) { \
if ((__bincp = binc(sp, lp, &(llen), nlen)) == NULL) \
goto binc_err; \
/* \
* !!! \
* Possible pointer conversion. \
*/ \
lp = __bincp; \
} \
}
#define BINC_RET(sp, lp, llen, nlen) { \
void *__bincp; \
if ((nlen) > llen) { \
if ((__bincp = binc(sp, lp, &(llen), nlen)) == NULL) \
return (1); \
/* \
* !!! \
* Possible pointer conversion. \
*/ \
lp = __bincp; \
} \
}
/*
* 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)))
void *binc __P((SCR *, void *, size_t *, size_t));

View File

@ -1,428 +0,0 @@
/*-
* 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.12 (Berkeley) 8/17/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 &&
(mp->mbuf = binc(sp, mp->mbuf, &mp->blen, len)) == NULL)
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

View File

@ -1,82 +0,0 @@
/*-
* 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 *, ...));

View File

@ -1,9 +0,0 @@
# @(#)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);
}

View File

@ -1,890 +0,0 @@
/*-
* 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.66 (Berkeley) 8/17/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);
}

View File

@ -1,108 +0,0 @@
/*-
* 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));

View File

@ -1,518 +0,0 @@
/*-
* 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.36 (Berkeley) 8/17/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);
}

View File

@ -1,45 +0,0 @@
/*-
* 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"

View File

@ -1,254 +0,0 @@
/*-
* 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.11 (Berkeley) 8/17/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);
}

View File

@ -1,869 +0,0 @@
/*-
* 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.74 (Berkeley) 8/17/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);
}
}

View File

@ -1,311 +0,0 @@
/*-
* 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.67 (Berkeley) 8/17/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. */
SIGBLOCK(sp->gp);
CIRCLEQ_REMOVE(&sp->gp->dq, sp, q);
SIGUNBLOCK(sp->gp);
/* Free the screen itself. */
FREE(sp, sizeof(SCR));
return (rval);
}

View File

@ -1,342 +0,0 @@
/*-
* 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 *));

View File

@ -1,833 +0,0 @@
/*-
* 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.48 (Berkeley) 8/17/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);
}

View File

@ -1,54 +0,0 @@
/*-
* 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 *));

View File

@ -1,351 +0,0 @@
/*-
* 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.33 (Berkeley) 8/17/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_T *name, *input, *output;
size_t nlen, ilen, olen;
enum seqtype stype;
int flags;
{
CHAR_T *p;
SEQ *lastqp, *qp;
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. */
if (qp->input[0] < MAX_BIT_SEQ)
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_T *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_T *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;
{
CHAR_T *p;
SEQ *qp;
int cnt, len, olen;
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;
{
CHAR_T *p;
SEQ *qp;
size_t olen;
int ch;
/* 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);
}

View File

@ -1,79 +0,0 @@
/*-
* 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.12 (Berkeley) 8/16/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_T *name; /* Sequence name (if any). */
size_t nlen; /* Name length. */
CHAR_T *input; /* Sequence input keys. */
size_t ilen; /* Input keys length. */
CHAR_T *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_T *, size_t, enum seqtype));
int seq_dump __P((SCR *, enum seqtype, int));
SEQ *seq_find __P((SCR *, SEQ **, CHAR_T *, 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_T *, size_t,
CHAR_T *, size_t, CHAR_T *, size_t, enum seqtype, int));

View File

@ -1,569 +0,0 @@
/*-
* 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.34 (Berkeley) 8/17/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);
}

View File

@ -1,732 +0,0 @@
/*-
* 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.81 (Berkeley) 8/17/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);
}

View File

@ -1,205 +0,0 @@
/*-
* 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));

View File

@ -1,84 +0,0 @@
/*-
* 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

View File

@ -1,213 +0,0 @@
/*-
* 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.74 (Berkeley) 8/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 <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.
*/
void *
binc(sp, bp, bsizep, min)
SCR *sp; /* sp MAY BE NULL!!! */
void *bp;
size_t *bsizep, min;
{
size_t csize;
/* If already larger than the minimum, just return. */
if (min && *bsizep >= min)
return (bp);
csize = *bsizep + MAX(min, 256);
REALLOC(sp, bp, void *, csize);
if (bp == 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 (NULL);
}
/*
* Memory is guaranteed to be zero-filled, various parts of
* nvi depend on this.
*/
memset((char *)bp + *bsizep, 0, csize - *bsizep);
*bsizep = csize;
return (bp);
}
/*
* 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);
}

View File

@ -1,124 +0,0 @@
/*-
* 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));

View File

@ -1,200 +0,0 @@
# @(#)README 8.86 (Berkeley) 8/17/94
This is the README for version 1.34 of nex/nvi, a freely redistributable
replacement for the Berkeley ex and vi text editors. The compressed or
gzip'd archives 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.

View File

@ -1,44 +0,0 @@
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.
+ 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.

View File

@ -1,528 +0,0 @@
1.33 -> 1.34 Wed Aug 17 14:37:32 1994 (PUBLICLY AVAILABLE VERSION)
+ Back out sccsid string fix, it won't work on SunOS 4.1.
1.32 -> 1.33 Wed Aug 17 09:31:41 1994 (PUBLICLY AVAILABLE VERSION)
+ Get back 5K of data space for the sccsid strings.
+ Fix bug where cG fix in version 1.31 broke cw cursor positioning
when the change command extended the line.
+ Fix core dump in map/seq code if character larger than 7 bits.
+ Block signals when manipulating the SCR chains.
+ Fix memory allocation for machines with multiple pointer sizes.
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.

View File

@ -1,55 +0,0 @@
# @(#)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.

View File

@ -1,87 +0,0 @@
List of things that should be added:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ X11 (Tk, Motif, Xaw) interface.
+ Interpreted language (Perl5, Scheme, Tcl)
+ Ports: Windows, Windows NT, MSDOS
+ Message catalogs.
+ Forms editing package; use RE's to verify field contents.
+ Internationalization, including wide character support.
+ Support for single line window editing, including full editing
capability on the vi colon command line.
+ Rob Pike's sam style RE's.
List of suggested features:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ 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.
+ 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.

View File

@ -1,88 +0,0 @@
# @(#)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.

View File

@ -1,32 +0,0 @@
# @(#)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.

View File

@ -1,77 +0,0 @@
# @(#)gdb.script 8.3 (Berkeley) 8/16/94
# 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 private structures
define vip
print *((VI_PRIVATE *)sp->vi_private)
end
define svp
print *((SVI_PRIVATE *)sp->svi_private)
end
define exp
print *((EX_PRIVATE *)sp->ex_private)
end
define sxp
print *((SEX_PRIVATE *)sp->sex_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

View File

@ -1,350 +0,0 @@
# @(#)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 ===
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

View File

@ -1,219 +0,0 @@
# @(#)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.

View File

@ -1,61 +0,0 @@
# @(#)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.)

File diff suppressed because it is too large Load Diff

View File

@ -1,741 +0,0 @@
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}.

View File

@ -1,24 +0,0 @@
#!/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

File diff suppressed because it is too large Load Diff

View File

@ -1,129 +0,0 @@
/*-
* 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.14 (Berkeley) 8/17/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));
}

View File

@ -1,220 +0,0 @@
/*-
* 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.24 (Berkeley) 8/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 <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);
}

View File

@ -1,263 +0,0 @@
/*-
* 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.29 (Berkeley) 8/17/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);
}

View File

@ -1,609 +0,0 @@
/*-
* 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.38 (Berkeley) 8/17/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);
}

View File

@ -1,118 +0,0 @@
/*-
* 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.27 (Berkeley) 8/17/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);
}

View File

@ -1,242 +0,0 @@
/*-
* 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.35 (Berkeley) 8/17/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);
}

View File

@ -1,223 +0,0 @@
/*-
* 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.18 (Berkeley) 8/17/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);
}

View File

@ -1,92 +0,0 @@
/*-
* 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.14 (Berkeley) 8/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_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);
}

View File

@ -1,324 +0,0 @@
/*-
* 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.8 (Berkeley) 8/17/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

View File

@ -1,169 +0,0 @@
/*-
* 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.23 (Berkeley) 8/17/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");
}
}

View File

@ -1,122 +0,0 @@
/*-
* 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.20 (Berkeley) 8/17/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);
}

View File

@ -1,86 +0,0 @@
/*-
* 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.8 (Berkeley) 8/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_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);
}

View File

@ -1,79 +0,0 @@
/*-
* 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.15 (Berkeley) 8/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_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);
}

View File

@ -1,103 +0,0 @@
/*-
* 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.12 (Berkeley) 8/17/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));
}

View File

@ -1,400 +0,0 @@
/*-
* 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.43 (Berkeley) 8/17/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;
}

View File

@ -1,202 +0,0 @@
/*-
* 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.18 (Berkeley) 8/17/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);
}

View File

@ -1,200 +0,0 @@
/*-
* 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.14 (Berkeley) 8/17/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);
}

View File

@ -1,160 +0,0 @@
/*-
* 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.19 (Berkeley) 8/17/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));
}

View File

@ -1,66 +0,0 @@
/*-
* 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.8 (Berkeley) 8/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"
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));
}

View File

@ -1,130 +0,0 @@
/*-
* 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.14 (Berkeley) 8/17/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);
}

View File

@ -1,222 +0,0 @@
/*-
* 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.19 (Berkeley) 8/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 <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);
}

View File

@ -1,75 +0,0 @@
/*-
* 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.6 (Berkeley) 8/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_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);
}

View File

@ -1,128 +0,0 @@
/*-
* 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.14 (Berkeley) 8/17/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);
}

View File

@ -1,212 +0,0 @@
/*-
* 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.16 (Berkeley) 8/17/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);
}

View File

@ -1,78 +0,0 @@
/*-
* 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.8 (Berkeley) 8/17/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);
}

Some files were not shown because too many files have changed in this diff Show More