diff options
author | sef <sef@FreeBSD.org> | 1994-08-16 23:36:45 +0000 |
---|---|---|
committer | sef <sef@FreeBSD.org> | 1994-08-16 23:36:45 +0000 |
commit | a6a4f07746b676691400c41fa4f116251050ba7f (patch) | |
tree | f7f1cc01b7d9f04f19bfc16853d3e1be207a8ffc /usr.bin/vi | |
download | FreeBSD-src-a6a4f07746b676691400c41fa4f116251050ba7f.zip FreeBSD-src-a6a4f07746b676691400c41fa4f116251050ba7f.tar.gz |
Latest public release of nvi, from Keith Bostic. I hope I got this
right ;).
Reviewed by: Sean Eric Fagan
Diffstat (limited to 'usr.bin/vi')
182 files changed, 103461 insertions, 0 deletions
diff --git a/usr.bin/vi/Makefile b/usr.bin/vi/Makefile new file mode 100644 index 0000000..9777077 --- /dev/null +++ b/usr.bin/vi/Makefile @@ -0,0 +1,3 @@ +SUBDIR= common + +.include <bsd.subdir.mk> diff --git a/usr.bin/vi/USD.doc/edit/Makefile b/usr.bin/vi/USD.doc/edit/Makefile new file mode 100644 index 0000000..3d30bc9 --- /dev/null +++ b/usr.bin/vi/USD.doc/edit/Makefile @@ -0,0 +1,18 @@ +# @(#)Makefile 8.1 (Berkeley) 6/8/93 + +DIR= usd/11.edit +SRCS= edittut.ms +MACROS= -msU + +paper.ps: ${SRCS} + ${TBL} ${SRCS} | ${ROFF} > ${.TARGET} + +# index for versatec is different from the one in edit.tut +# because the fonts are different and entries reference page +# rather than section numbers. if you have a typesetter +# you should just use the index in edit.tut, and ignore editvindex. + +editvindex: + ${TROFF} ${MACROS} -n22 edit.vindex + +.include <bsd.doc.mk> diff --git a/usr.bin/vi/USD.doc/edit/edit.vindex b/usr.bin/vi/USD.doc/edit/edit.vindex new file mode 100644 index 0000000..2098f14 --- /dev/null +++ b/usr.bin/vi/USD.doc/edit/edit.vindex @@ -0,0 +1,115 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)edit.vindex 8.1 (Berkeley) 6/8/93 +.\" +.bd I +.ND +.TL +Index +.sp 3 +.2C +.nf +addressing, \fIsee\fR line numbers +append mode, 4 +backslash (\\), 18 +buffer, 2 +command mode, 4 +context search, 8, 10, 13, 18 +control characters (``^'' notation), 8 +control-d, 6 +current filename, 19, 20 +current line (.), 9, 15 +diagnostic messages, 4 +disk, 2 +documentation, 21 +edit (to begin editing session), 3, 7 +editing commands: +.in +2 +append (a), 4, 7 +change (c), 16 +copy (co), 13 +delete (d), 13-14 +edit (e), 12 +file (f), 19 +global (g), 18-19 +move (m), 12-13 +number (nu), 9 +preserve (pre), 20-21 +print (p), 8 +quit (q), 5, 11 +quit! (q!), 11 +read (r), 20 +recover (rec), 20 +substitute (s), 9-10, 17, 18 +undo (u), 14, 17 +write (w), 5-6, 11, 19-20 +z, 11 +.sp 10i +! (shell escape), 19 +$= , 15 ++, 15 +\-, 15 +//, 8, 18 +??, 18 +\&\fB.\fR, 9, 15 +\&\fB.\fR=, 9, 15 +.in -2 +erasing +.ti +2 +characters (#), 8 +.ti +2 +lines (@), 8 +ex (text editor), 21 +\fIEx Reference Manual\fR, 21 +file, 1 +file recovery, 20 +filename, 2 +Interrupt (message), 7 +line numbers, \fIsee also\fR current line +.ti +2 +dollar sign ($), 8, 12-13, 15 +.ti +2 +dot (.), 9, 15 +.ti +2 +relative (+ and \-), 15, 16 +logging out, 6 +login procedure, 2 +``magic'' characters, 21 +non-printing characters, 8 +``not found'' (message), 3 +program, 1 +recovery \fIsee\fR file recovery +shell, 18 +shell escape (!), 19 +special characters (^, $, \e), 18 +text input mode, 4 +UNIX, 1 diff --git a/usr.bin/vi/USD.doc/edit/edittut.ms b/usr.bin/vi/USD.doc/edit/edittut.ms new file mode 100644 index 0000000..5f4c28c --- /dev/null +++ b/usr.bin/vi/USD.doc/edit/edittut.ms @@ -0,0 +1,2322 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)edittut.ms 8.1 (Berkeley) 6/8/93 +.\" +.EH 'USD:11-%''Edit: A Tutorial' +.OH 'Edit: A Tutorial''USD:11-%' +.LP +.ds u \s-2UNIX\s0 +.ll 5i +.nr LL 5i +.ND +.sp 4 +.ce +\f3\s+2Edit: A Tutorial\s0\f1 +.sp +.ce 3 +.I +Ricki Blau +.sp +James Joyce +.R +.sp +.ce 3 +Computing Services +University of California +Berkeley, California 94720 +.sp 3 +.ce +.I +ABSTRACT +.R +.sp +.LP +This narrative introduction to the use of the text editor +.I edit +assumes no prior familiarity with computers or with text editing. +Its aim is to lead the beginning \s-2UNIX\(dg\s+2 user through the +.FS +\(dgUNIX is a trademark of Bell Laboratories. +.FE +fundamental steps of writing and revising a file of text. +Edit, +a version of the text editor +.I ex, +was designed to provide an informative environment +for new and casual users. +.PP +We welcome comments and suggestions about this tutorial +and the \s-2UNIX\s+2 documentation in general. +.sp .5v +September 1981 +.bp +.ll 6.5i +.nr LL 6.5i +.nr LT 6.5i +.ds u \s-2UNIX\s0 +.ce +\s+2\f3Contents\f1\s0 +.LP +.nf +Introduction\ \ \ 3 +.sp +Session 1\ \ \4 +.in +.5i +Making contact with \s-2UNIX\s+2\ \ \ 4 +Logging in\ \ \4 +Asking for \fIedit\fR\ \ \ 4 +The ``Command not found'' message\ \ \ 5 +A summary\ \ \5 +Entering text\ \ \ 5 +Messages from \fIedit\fR\ \ \ 5 +Text input mode\ \ \ 6 +Making corrections\ \ \ 6 +Writing text to disk\ \ \ 7 +Signing off\ \ \7 +.in -.5i +.sp +Session 2\ \ \ 8 +.in +.5i +Adding more text to the file\ \ \ 8 +Interrupt\ \ \ 8 +Making corrections\ \ \ 8 +Listing what's in the buffer (p)\ \ \ 9 +Finding things in the buffer\ \ \ 9 +The current line\ \ \ 10 +Numbering lines (nu)\ \ \ 10 +Substitute command (s)\ \ \ 10 +Another way to list what's in the buffer (z)\ \ \ 11 +Saving the modified text\ \ \ 12 +.in -.5i +.sp +Session 3\ \ \ 13 +.in +.5i +Bringing text into the buffer (e)\ \ \ 13 +Moving text in the buffer (m)\ \ \ 13 +Copying lines (copy)\ \ \ 14 +Deleting lines (d)\ \ \ 14 +A word or two of caution\ \ \ 15 +Undo (u) to the rescue\ \ \ 15 +More about the dot (.) and buffer end ($)\ \ \ 16 +Moving around in the buffer (+ and \-)\ \ \ 16 +Changing lines (c)\ \ \ 17 +.in -.5i +.sp +Session 4\ \ \ 18 +.in +.5i +Making commands global (g)\ \ \ 18 +More about searching and substituting\ \ \ 19 +Special characters\ \ \ 19 +Issuing \s-2UNIX\s+2 commands from the editor\ \ \ 20 +Filenames and file manipulation\ \ \ 20 +The file (f) command\ \ \ 20 +Reading additional files (r)\ \ \ 21 +Writing parts of the buffer\ \ \ 21 +Recovering files\ \ \ 21 +Other recovery techniques\ \ \ 21 +Further reading and other information\ \ \ 22 +Using \fIex\fR\ \ \ 22 +.in -.5i +.sp +Index\ \ \ 23 +.bp +.SH +.ce +\s+2Introduction\s0 +.PP +Text editing using a terminal connected to a computer +allows you to create, modify, and print text +easily. +A +.I +text editor +.R +is a program +that assists you +as you create and modify text. +The text editor you will learn here is named +.I edit. +Creating text using edit is as easy as typing it +on an electric typewriter. +Modifying text involves telling the text editor +what you want to add, change, or delete. +You can review your text +by typing a command +to print the file contents +as they are currently. +Another program (which we do not discuss in this +document), a text formatter, +rearranges your text +for you into ``finished form.'' +.PP +These lessons assume no prior familiarity with computers +or with text editing. +They consist of a series of text editing sessions +which lead you through the fundamental steps +of creating and revising text. +After scanning each lesson and before beginning the next, +you should try the examples at a terminal to get a feeling +for the actual process of text editing. +If you set aside some time for experimentation, +you will soon become familiar with using the +computer to write and modify text. +In addition to the actual use of the text editor, +other features of \s-2UNIX\s0 will be very important to your work. +You can begin to +learn about these other features by +reading one of the other tutorials +that provide a general introduction to the system. +You will be ready to proceed with this lesson as soon as +you are familiar with (1) your terminal and its special keys, +(2) how to login, +(3) and the ways of correcting typing errors. +Let's first define some terms: +.sp .5 +.IP program 12 +A set of instructions, given to the computer, +describing the sequence of steps the computer performs +in order to accomplish a specific task. +The task must be specific, +such as balancing your checkbook +or editing your text. +A general task, +such as working for world peace, +is something we can all do, +but not something we can currently write programs to do. +.IP UNIX +\s-2UNIX\s0 is a special type of program, +called an operating system, that supervises the machinery +and all other programs comprising the total +computer system. +.IP edit +.I edit +is the name of the \s-2UNIX\s0 text editor you will be learning to use, +and is a program that aids you in writing or revising text. +Edit was designed for beginning users, +and is a simplified version of an editor named +.I ex. +.IP file +Each \s-2UNIX\s0 account is allotted +space for the permanent storage of information, +such as programs, data or text. +A file is a logical unit of data, +for example, an essay, a program, +or a chapter from a book, +which is stored on a computer system. +Once you create a file, +it is kept until you instruct the system to remove it. +You may create a file during one \s-2UNIX\s0 session, +end the session, +and return to use it at a later time. +Files contain anything you choose to write and store in them. +The sizes of files vary to suit your needs; +one file might hold only a single number, +yet another might contain +a very long document or program. +The only way to save +information from one session to the next is to store it in a file, +which you will learn in Session 1. +.IP filename +Filenames are used to distinguish one file from another, +serving the same purpose as the labels of manila +folders in a file cabinet. +In order to write or access information in a file, +you use the name of that file in a \s-2UNIX\s0 command, +and the system will automatically locate the file. +.IP disk +Files are stored on an input/output device called a disk, +which looks something like a stack of phonograph records. +Each surface is coated with a material similar to that +on magnetic recording tape, +and information is recorded on it. +.IP buffer +A temporary work space, made available to the user +for the duration of a session of text editing +and used for creating and modifying +the text file. +We can think of the buffer as a blackboard that is +erased after each class, where each session with the editor +is a class. +.bp +.SH +.ce 1 +\s+2Session 1\s0 +.sp 1 +.SH +Making contact with \s-1UNIX\s0 +.PP +To use the editor you must first make contact with the computer +by logging in to \s-2UNIX\s0. +We'll quickly review the standard \s-2UNIX\s0 login procedure +for the two ways you can make contact: +on a terminal that is directly linked to the computer, +or over a telephone line where the computer answers your call. +.SH +Directly-linked terminals +.PP +Turn on your terminal and press the \s-1RETURN\s0 key. +You are now ready to login. +.SH +Dial-up terminals +.PP +If your terminal connects with the computer over a telephone line, +turn on the terminal, dial the system access number, +and, when you hear a high-pitched tone, place the +telephone handset in the acoustic coupler, if you are using one. +You are now ready to login. +.SH +Logging in +.PP +The message inviting you to login is: +.DS I 1i +login: +.DE +.LP +Type your login name, which identifies you to \s-2UNIX\s0, +on the same line as the login message, +and press \s-2RETURN\s+2. +If the terminal you are using +has both upper and lower case, +.B +be sure you enter your login name in lower case; +.R +otherwise \s-2UNIX\s0 assumes your terminal +has only upper case and will not recognize lower case +letters you may type. +\s-2UNIX\s0 types ``login:'' and you reply +with your login name, for example ``susan'': +.DS I 1i +login: \fBsusan\fR \fI(and press the \s-2RETURN\s0 key)\fR +.DE +(In the examples, input you would type appears in +.B "bold face" +to distinguish it from the responses from \s-2UNIX\s0.) +.PP +\s-2UNIX\s0 will next respond with a request for a password +as an additional precaution to prevent +unauthorized people from using your account. +The password will not appear when you type it, +to prevent others from seeing it. +The message is: +.DS I 1i +Password: \fI(type your password and press \s-2RETURN\s+2)\fR +.DE +If any of the information you gave during the login +sequence was mistyped or incorrect, +\s-2UNIX\s0 will respond with +.DS I 1i +Login incorrect. +.if t .sp .2v +.if n .sp 1 +login: +.DE +in which case you should start the login process anew. +Assuming that you have successfully +logged in, \s-2UNIX\s0 +will print the message of the day and eventually will present +you with a % at the beginning of a fresh line. +The % is the \s-2UNIX\s0 prompt symbol +which tells you that \s-2UNIX\s0 is ready to accept a command. +.bd I 3 +.SH +Asking for \fIedit\fP +.fl +.bd I +.PP +You are ready to tell \s-2UNIX\s0 that you +want to work with edit, the text editor. +Now is a convenient time to choose +a name for the file of text you are about to create. +To begin your editing session, +type +.B edit +followed by a space and then the filename +you have selected; for example, ``text''. +After that, +press the \s-2RETURN\s0 key and wait for edit's response: +.DS I 1i +% \fBedit text\fP \fI(followed by a \s-2RETURN\s+2)\fR +"text" No such file or directory +: +.DE +If you typed the command correctly, +you will now be in communication with edit. +Edit has set aside a buffer for use as +a temporary working space during your current editing session. +Since ``text'' is a new file we are about to create +the editor was unable to find that file, which it +confirms by saying: +.DS I 1i +"text" No such file or directory +.DE +On the next line appears edit's prompt ``:'', +announcing that you are in \f2command mode\f1 and +edit expects a command from you. +You may now begin to create the new file. +.SH +The ``Command not found'' message +.PP +If you misspelled edit by typing, say, ``editor'', +this might appear: +.DS I 1i +% \fBeditor\fP +editor: Command not found +% +.DE +Your mistake in calling edit ``editor'' was +treated by \s-2UNIX\s0 as a request +for a program named ``editor''. +Since there is no program +named ``editor'', +\s-2UNIX\s0 reported that the program was ``not found''. +A new % indicates that \s-2UNIX\s0 is ready for another command, +and you may then enter the correct command. +.SH +A summary +.PP +Your exchange with \s-2UNIX\s0 as you logged in and made contact with edit +should look something like this: +.DS I 1i +login: \fBsusan\fP +Password: +\&... A Message of General Interest ... +% \fBedit text\fP +"text" No such file or directory +: +.DE +.SH +Entering text +.PP +You may now begin entering text into the buffer. +This is done by \fIappending\fP (or adding) text to whatever +is currently in the buffer. +Since there is nothing in the buffer at the moment, +you are appending text to nothing; +in effect, +since you are adding text to nothing +you are creating text. +Most edit commands have two equivalent forms: +a word that suggests what the command does, +and a shorter abbreviation of that word. +Many beginners find the full command names +easier to remember at first, +but once you are familiar with editing you may +prefer to type the shorter abbreviations. +The command to input text is ``append''. +(It may be abbreviated ``a''.) +Type +.B append +and press the \s-2RETURN\s0 key. +.DS I 1i +% \fBedit text +\fR:\|\fBappend +.R +.DE +.SH +.bd I 3 +Messages from +.I edit +.fl +.bd I +.PP +If you make a mistake in entering a command and +type something that edit does not recognize, +edit will respond with a message +intended to help you diagnose your error. +For example, if you misspell the command to input text by typing, +perhaps, ``add'' instead of ``append'' or ``a'', +you will receive this message: +.DS I 1i +:\|\fBadd\fR +add: Not an editor command +: +.DE +When you receive a diagnostic message, +check what you typed in order to determine what +part of your command confused edit. +The message above means that edit +was unable to recognize your mistyped command +and, therefore, did not execute it. +Instead, a new ``:'' +appeared to let you know that +edit is again ready to execute a command. +.SH +Text input mode +.PP +By giving the command ``append'' (or using the abbreviation ``a''), +you entered +.I +text input mode, +.R +also known as +.I +append mode. +.R +When you enter text input mode, +edit stops sending you a prompt. +You will not receive any prompts +or error messages +while in text input mode. +You can enter +pretty much anything you want on the lines. +The lines are transmitted one by one to the buffer +and held there during the editing session. +You may append as much text as you want, and +.I +when you wish to stop entering text lines you should +type a period as the only character on the line +and press the \s-2RETURN\s0 key. +.R +When you type the period and press \s-2RETURN\s0, +you signal that you want to stop appending text, +and edit responds by allowing +you to exit text input mode and reenter command mode. +Edit will again +prompt you for a command by printing ``:''. +.PP +Leaving append mode does not destroy the text in +the buffer. +You have to leave append +mode to do any of the other kinds of editing, +such as changing, adding, or printing text. +If you type a period as the first character and +type any other character on the same line, +edit will believe you want to remain in append mode +and will not let you out. +As this can be very frustrating, +be sure to type +.B only +the period and the \s-2RETURN\s0 key. +.PP +This is a good place to learn an important +lesson about computers and text: a blank space is +a character as far as a computer is concerned. +If you so much as type a period followed by a blank +(that is, type a period and then the space bar on the keyboard), +you will remain in append mode with the last line of text +being: +.DS I 1i +.B +.ps +2 +\&. +.ps -2 +.R +.DE +Let's say that you enter the lines +(try to type +.B exactly +what you see, including ``thiss''): +.DS I 1i +.B +This is some sample text. +And thiss is some more text. +Text editing is strange, but nice. +\&. +.R +.DE +The last line is the period followed by a \s-2RETURN\s0 +that gets you out of append mode. +.SH +Making corrections +.PP +If you have read a general introduction to \s-2UNIX\s0, +you will recall that it is possible to erase individual +letters that you have typed. +This is done by typing the designated erase character +as many times as there are characters +you want to erase. +.PP +The usual erase character varies from place to place and +user to user. Often it +is the backspace (control-H), +so you can correct typing errors +in the line you are typing +by holding down the \s-1CTRL\s+1 key +and typing the ``H'' key. (Sometimes it is the DEL key.) +If you type the erase character +you will notice +that the terminal backspaces in the line you are on. +You can backspace over your error, +and then type what you want to be the rest of the line. +.PP +If you make a bad start +in a line +and would like to begin again, +you can either backspace to the beginning of the line +or you can use the at-sign ``@'' to erase everything on the line: +.DS I 1i +.B +Text edtiing is strange, but@ +Text editing is strange, but nice. +.R +.fl +.bd S +.DE +When you type the at-sign (@), you erase +the entire line typed so far +and are given a fresh line to type on. +You may immediately begin to retype the line. +This, unfortunately, does not work after you type the +line and press \s-2RETURN\s+2. +To make corrections in lines that have been completed, +it is necessary to use the editing commands +covered in the next sessions. +.SH +Writing text to disk +.PP +You are now ready to edit the text. One common operation +is to write the text to disk as a file for safekeeping +after the session is over. +This is the only way to save information from one session to the next, +since the editor's buffer is temporary and will last only until the +end of the editing session. +Learning how to write a file to disk is second in +importance only to entering the text. +To write the contents of the buffer to a disk +file, use the command ``write'' +(or its abbreviation ``w''): +.DS I 1i +:\|\fBwrite +.R +.DE +Edit will copy the contents of the buffer to a disk file. +If the file does not yet exist, +a new file will be created automatically +and the presence of a ``[New file]'' will be noted. +The newly-created file will be given the name specified when +you entered the editor, in this case ``text''. +To confirm that the disk file has been successfully written, +edit will repeat the filename and give +the number of lines and the total +number of characters in the file. +The buffer remains unchanged by the ``write'' command. +All of the lines that were written to disk will still be +in the buffer, +should you want to modify or add to them. +.PP +Edit must have a name for the file to be written. +If you forgot to indicate the name of the file +when you began to edit, +edit will print in response to your write command: +.DS I 1i +No current filename +.DE +If this happens, you can specify the filename in a new write command: +.DS I 1i +:\|\fBwrite text +.R +.DE +After the ``write'' (or ``w''), type a space and then the name of the file. +.SH +Signing off +.PP +We have done enough for this first lesson on using the +\s-2UNIX\s0 text editor, and are ready to quit the session with edit. +To do this we type ``quit'' (or ``q'') and press \s-2RETURN\s+2: +.DS I 1i +:\|\fBwrite +.R +"text" [New file] 3 lines, 90 characters +:\|\fBquit\fR +% +.DE +The % is from \s-2UNIX\s0 to tell you that your session with edit is +over and you may command \s-2UNIX\s0 further. +Since we want +to end the entire session at the terminal, we also need to +exit from \s-2UNIX\s0. +In response to the \s-2UNIX\s0 prompt of ``\|%\|'' +type the command +.DS I 1i +%\|\fBlogout\fR +.DE +This will end your session with \s-2UNIX\s0, and will ready the +terminal for the next user. +It is always important to type \fBlogout\fR at the end of a session +to make absolutely sure no one +could accidentally stumble into your abandoned +session and thus gain access to your files, +tempting even the most honest of souls. +.sp 1 +.PP +This is the end of the first session on \s-2UNIX\s0 text editing. +.bp +.TL +Session 2 +.sp +.PP +Login with \s-2UNIX\s0 as in the first session: +.DS I 1i +login: \fBsusan\fP \fI(carriage return)\fR +Password: \fI(give password and carriage return)\fR +.if t .sp .2v +.if n .sp 1 +\&... A Message of General Interest ... +% +.DE +When you indicate you want to edit, +you can specify the name of the file you worked on last time. +This will +start edit working, and it will fetch the contents of the +file into the buffer, so that you can resume editing the same file. +When edit has copied the file into the buffer, it +will repeat its name and tell +you the number of lines and characters it contains. +Thus, +.DS I 1i +.B +% edit text +.R +"text" 3 lines, 90 characters +: +.DE +means you asked edit to fetch +the file named ``text'' for editing, +causing it to copy the +90 characters of text into the buffer. +Edit awaits +your further instructions, +and indicates this by its prompt character, the colon (:). +In this session, we will append more text to our file, +print the contents of the buffer, and learn to change the text of a line. +.SH +Adding more text to the file +.PP +If you want to add more to the end of your +text you may do so by using the append command to enter text input mode. +When ``append'' is the first command +of your editing session, +the lines you enter +are placed at the end of the buffer. +Here we'll use the abbreviation for the append command, ``a'': +.DS I 1i +:\|\fBa +This is text added in Session 2. +It doesn't mean much here, but +it does illustrate the editor. +\|\fB\s+2\&.\s-2 +.R +.DE +You may recall that once you enter append mode +using the ``a'' (or ``append'') command, +you need to type a line containing only a period (.) +to exit append mode. +.SH +Interrupt +.PP +Should you press the \s-2RUB\s+2 key (sometimes labelled \s-2DELETE\s+2) +while working with edit, +it will send this message to you: +.DS I 1i +Interrupt +: +.DE +Any command that edit might be executing +is terminated by rub or delete, +causing edit to prompt you for a new command. +If you are appending text at the time, +you will exit from append mode +and be expected to give another command. +The line of text you were typing +when the append command was interrupted +will not be entered into the buffer. +.SH +Making corrections +.PP +If while typing the line you hit an incorrect key, +recall that +you may delete the incorrect character +or cancel the entire line of input by erasing in the usual way. +Refer either +to the last few pages of Session 1 +if you need to review +the procedures for making a correction. +The most important idea to remember is that +erasing a character or cancelling a line must be done +before you press the \s-2RETURN\s+2 key. +.SH +Listing what's in the buffer (p) +.PP +Having appended text to what you wrote in Session 1, +you might want to see all the lines in the buffer. +To print the contents of the buffer, type the command: +.DS I 1i +:\|\fB1,$p +.R +.DE +The ``1''\(dg +.FS +\(dgThe numeral ``one'' is the top left-most key, +and should not be confused with the letter ``el''. +.FE +stands for line 1 of the buffer, +the ``$'' is a special symbol designating the last line +of the buffer, +and ``p'' (or \fBprint\fR) is the command to print from line 1 +to the end of the buffer. +The command ``1,$p'' gives you: +.DS I 1i +This is some sample text. +And thiss is some more text. +Text editing is strange, but nice. +This is text added in Session 2. +It doesn't mean much here, but +it does illustrate the editor. +.DE +Occasionally, you may accidentally +type a character that can't be printed, +which can be done by striking a key +while the \s-2CTRL\s0 key is pressed. +In printing lines, edit uses a special notation to +show the existence of non-printing characters. +Suppose you had introduced the non-printing character ``control-A'' +into the word ``illustrate'' +by accidently pressing the \s-2CTRL\s0 key while +typing ``a''. +This can happen on many terminals +because the \s-2CTRL\s+2 key and the ``A'' key +are beside each other. +If your finger presses between the two keys, +control-A results. +When asked to print the contents of the buffer, +edit would display +.DS I 1i +it does illustr^Ate the editor. +.DE +To represent the control-A, edit shows ``^A''. +The sequence ``^'' followed by a capital +letter stands for the one character +entered by holding down the \s-2CTRL\s0 key and typing the letter +which appears after the ``^''. +We'll soon discuss the commands that can be used +to correct this typing error. +.PP +In looking over the text we see that +``this'' is typed as ``thiss'' in the second line, +a deliberate error so we can learn to make corrections. +Let's correct the spelling. +.SH +Finding things in the buffer +.PP +In order to change something in the buffer we first need to +find it. +We can find ``thiss'' in the text we have +entered by looking at a listing +of the lines. +Physically speaking, we search the lines +of text looking for ``thiss'' and stop searching when +we have found it. +The way to tell edit to search for something +is to type it inside slash marks: +.DS I 1i +:\|\fB/thiss/ +.R +.DE +By typing +.B /thiss/ +and pressing \s-1RETURN\s0, +you instruct edit to search for ``thiss''. +If you ask edit to look for a pattern of characters +which it cannot find in the buffer, +it will respond ``Pattern not found''. +When edit finds +the characters ``thiss'', it will print the line of text +for your inspection: +.DS I 1i +And thiss is some more text. +.DE +Edit is now positioned in the buffer at the +line it just printed, +ready to make a change in the line. +.bp +.SH +The current line +.PP +Edit keeps track of the line in the buffer where it is located +at all times during an editing session. +In general, the line that has been most recently +printed, entered, or changed +is the current location in the buffer. +The editor is prepared to make changes +at the current location in the buffer, +unless you direct it to another location. +.PP +In particular, +when you bring a file into the buffer, +you will be located at the last line in the file, +where the editor left off copying the lines +from the file to the buffer. +If your first editing command is ``append'', +the lines you enter are added +to the end of the file, +after the current line \(em +the last line in the file. +.PP +You can refer to your current location in the buffer by the +symbol +period (.) usually known by the name ``dot''. +If you type ``.'' and carriage +return you will be instructing edit to print the current line: +.DS I 1i +:\|\fB\s+2\&.\s-2 +.R +And thiss is some more text. +.DE +.PP +If you want to know the number of the current line, +you can type +.B \&.= +and press \s-2RETURN\s+2, +and edit will respond with the line number: +.DS I 1i +:\|\fB\s+2.\s-2= +.R +2 +.DE +If you type the number of any line and press \s-2RETURN\s+2, +edit will position you at that line and +print its contents: +.DS I 1i +:\|\fB2 +.R +And thiss is some more text. +.DE +You should experiment with these commands +to gain experience in using them to make changes. +.SH +Numbering lines (nu) +.PP +The +.B +number (nu) +.R +command is similar to print, +giving both the number and the text of each printed line. +To see the number and the text of the current line type +.DS I 1i +:\|\fBnu +.R +\0\0\0\0\02\0\0And thiss is some more text. +.DE +Note that the shortest abbreviation for the number command is +``nu'' (and not ``n'', which is used for a different command). +You may specify a range of lines +to be listed by the number command in the same way that lines +are specified for print. +For example, \f31,$nu\f1 lists all lines in the buffer with their +corresponding line numbers. +.SH +Substitute command (s) +.PP +Now that you have found the misspelled word, +you can change it from ``thiss'' to ``this''. +As far as edit is concerned, +changing things is a matter of +substituting one thing for another. +As +.I a +stood for +.I append, +so +.I s +stands for +.I substitute. +We will use the abbreviation ``s'' to reduce the chance +of mistyping the substitute command. +This command will instruct edit to make the change: +.DS I 1i +\f32s/thiss/this/\f1 +.DE +We first indicate the line to be changed, line 2, +and then +type an ``s'' to indicate we want +edit to make a substitution. +Inside the first set of slashes +are the characters that we want to change, +followed by the characters to replace them, +and then a closing slash mark. +To summarize: +.DS I 1i +2s/ \fIwhat is to be changed\fR / \fIwhat to change it to \fR/ +.DE +If edit finds an exact match of the characters to be +changed it will make the change +.B only +in the first occurrence of the characters. +If it does not find the characters +to be changed, it will respond: +.DS I 1i +Substitute pattern match failed +.DE +indicating that your instructions could not be carried out. +When edit does find the characters that you want to change, +it will make the substitution and automatically print +the changed line, so that you can check that the correct substitution +was made. +In the example, +.DS I 1i +:\|\fB2s/thiss/this/ +.R +And this is some more text. +.DE +line 2 (and line 2 only) will be searched for the characters +``thiss'', and when the first exact match is found, ``thiss'' +will be changed to ``this''. +Strictly speaking, it was not necessary above to +specify the number of the line to be changed. +In +.DS I 1i +:\|\fBs/thiss/this/ +.R +.DE +edit will assume that we mean to change +the line where we are currently located (``.''). +In this case, +the command without a line number would have produced the same result +because we were already located +at the line we wished to change. +.PP +For another illustration of the substitute command, +let us choose the line: +.DS I 1i +Text editing is strange, but nice. +.DE +You can make this line a bit more positive +by taking out the characters ``strange, but\ '' so the line +reads: +.DS I 1i +Text editing is nice. +.DE +A command that will first position edit at the desired line +and then make the substitution is: +.DS I 1i +:\|\fB/strange/s/strange, but // +.R +.DE +.LP +What we have done here is combine our search with +our substitution. +Such combinations are perfectly legal, +and speed up editing quite a bit +once you get used to them. +That is, you do not necessarily have to use +line numbers to identify a line to edit. +Instead, you may identify the line you want to change +by asking edit to search for a specified pattern of letters +that occurs in that line. +The parts of the above command are: +.TS +.in +1i +.nr 35 \n(.u +.nf +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.nr 80 0 +.nr 38 \w\f3/strange/\fP +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \w\f3s\fP +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \w\f3/strange, but //\fP +.if \n(80<\n(38 .nr 80 \n(38 +.nr 81 0 +.nr 38 \wtells edit to find the characters ``strange'' in the text +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtells edit to make a substitution +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsubstitutes nothing at all for the characters ``strange, but '' +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(0*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.if t .if (\n(TW+\n(.o)>7.75i .tm Table at line 307 file ed2.tbl is too wide - \n(TW units +.fc +.nr #T 0 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.. +.ec +.ta \n(80u \n(81u +\&\h'|\n(40u'\f3/strange/\fP\h'|\n(41u'tells edit to find the characters ``strange'' in the text +.ta \n(80u \n(81u +\&\h'|\n(40u'\f3s\fP\h'|\n(41u'tells edit to make a substitution +.ta \n(80u \n(81u +\&\h'|\n(40u'\f3/strange, but //\fP\h'|\n(41u'substitutes nothing at all for the characters ``strange, but '' +.fc +.nr T. 1 +.T# 1 +.if \n(35>0 .fi +.in -1i +.TE +.PP +You should note the space after ``but'' in ``/strange, but /''. +If you do not indicate that the space is to be taken out, +your line will read: +.DS I 1i +.if t Text editing is nice. +.if n Text editing is nice. +.DE +which looks a little funny +because of the extra space between ``is'' and ``nice''. +Again, we realize from this that a blank space +is a real character to a computer, and in editing text +we need to be aware of spaces +within a line just as we would be aware of an ``a'' or +a ``4''. +.SH +Another way to list what's in the buffer (z) +.PP +Although the print command is useful for looking at specific lines +in the buffer, +other commands may be more convenient for +viewing large sections of text. +You can ask to see a screen full of text at a time +by using the command +.B z. +If you type +.DS I 1i +:\|\fB1z +.R +.DE +edit will start with line 1 and continue printing lines, +stopping either when the screen of +your terminal is full +or when the last line in the buffer has been printed. +If you want to read the next segment of text, type the command +.DS I 1i +:\|\fBz +.DE +If no starting line number is given for the z command, +printing will start at the ``current'' line, in this case the +last line printed. +Viewing lines in the buffer one screen full at a time +is known as \fIpaging\fR. +Paging can also be used to print +a section of text on a hard-copy terminal. +.SH +Saving the modified text +.PP +This seems to be a good place to pause in our work, +and so we should end the second session. +If you (in haste) type ``q'' to quit the session +your dialogue with edit will be: +.DS I 1i +:\|\fBq +.R +No write since last change (:quit! overrides) +: +.DE +This is edit's warning that you have not written +the modified contents of the buffer to disk. +You run the risk of losing the work you did +during the editing session since you typed the latest write +command. +Because in this lesson we have not written +to disk at all, everything we have done +would have been lost +if edit had obeyed the \fBq\fR command. +If you did not want to save the work done during +this editing session, you would have to type ``q!'' +or (``quit!'') +to confirm that you indeed wanted to end the session +immediately, +leaving the file as it was +after the most recent ``write'' command. +However, +since you want to save what +you have edited, you need to type: +.DS I 1i +:\|\fBw +.R +"text" 6 lines, 171 characters +.DE +and then follow with the commands to quit and logout: +.DS I 1i +:\|\fBq +% \fBlogout\fR +.DE +and hang up the phone or turn off the terminal when +\s-2UNIX\s0 asks for a name. +Terminals connected to the port selector +will stop after the logout command, +and pressing keys on the keyboard will do nothing. +.sp 1 +.PP +This is the end of the second session on \s-2UNIX\s0 text editing. +.bp +.TL +Session 3 +.SH +Bringing text into the buffer (e) +.PP +Login to \s-2UNIX\s0 and make contact with edit. +You should try to login without +looking at the notes, but if you must +then by all means do. +.PP +Did you remember to give the name of the file +you wanted to edit? +That is, did you type +.DS I 1i +% \fBedit text\fR +.DE +or simply +.DS I 1i +% \fBedit\fR +.DE +Both ways get you in contact with edit, but the first way +will bring a copy of the file named ``text'' into +the buffer. +If you did forget to tell edit the name of your file, +you can get it into the buffer by +typing: +.DS I 1i +:\|\fBe text +.R +"text" 6 lines, 171 characters +.DE +The command +.B edit, +which may be abbreviated \fBe\fR, +tells edit that you want +to erase anything that might already be in +the buffer and bring a copy of the file ``text'' into the buffer +for editing. +You may also use the edit (e) command to change files in +the middle of an editing session, +or to give edit the name of a new file that you want to create. +Because the edit command clears the buffer, +you will receive a warning if you try to edit a new file without +having saved a copy of the old file. +This gives you a chance to write the contents of the buffer to disk +before editing the next file. +.SH +Moving text in the buffer (m) +.PP +Edit allows you to move lines of text +from one location in the buffer to another +by means of the +.B move +(\fBm\fR) command. +The first two examples are for illustration only, +though after you have read this Session +you are welcome to return to them for practice. +The command +.DS I 1i +:\|\fB2,4m$ +.R +.DE +directs edit to move lines 2, 3, and 4 +to the end of the buffer ($). +The format for the move command is that you specify +the first line to be moved, the last line to be moved, +the move command ``m'', and the line after which +the moved text is to be placed. +So, +.DS I 1i +:\|\fB1,3m6 +.R +.DE +would instruct edit to move lines 1 through 3 (inclusive) +to a location after line 6 in the buffer. +To move only one line, say, line 4, +to a location in the buffer after line 5, +the command would be ``4m5''. +.PP +Let's move some text using the command: +.DS I 1i +:\|\fB5,$m1 +.R +2 lines moved +it does illustrate the editor. +.DE +After executing a command that moves more than one line of the buffer, +edit tells how many lines were affected by the move +and prints the last moved line for your inspection. +If you want to see more than just the last line, +you can then +use the print (p), z, or number (nu) command to view more text. +The buffer should now contain: +.DS I 1i +This is some sample text. +It doesn't mean much here, but +it does illustrate the editor. +And this is some more text. +Text editing is nice. +This is text added in Session 2. +.DE +You can restore the original order by typing: +.DS I 1i +:\|\fB4,$m1 +.R +.DE +or, combining context searching and the move command: +.DS I 1i +:\|\fB/And this is some/,/This is text/m/This is some sample/ +.R +.DE +(Do not type both examples here!) +The problem with combining context searching +with the move command +is that your chance of making a typing error +in such a long command is greater than +if you type line numbers. +.SH +Copying lines (copy) +.PP +The +.B copy +command +is used to make a second copy of specified lines, +leaving the original lines where they were. +Copy +has the same format as the move command, for example: +.DS I 1i +:\|\fB2,5copy $ +.R +.DE +makes a copy of lines 2 through 5, +placing the added lines after the buffer's end ($). +Experiment with the copy command +so that you can become familiar with how it works. +Note that the shortest abbreviation for copy is +\f3co\f1 (and +not the letter ``c'', which has another meaning). +.SH +Deleting lines (d) +.PP +Suppose you want to delete +the line +.DS I 1i +This is text added in Session 2. +.DE +from the buffer. +If you know the number of the line to be deleted, +you can type +that number followed by +\fBdelete\fR or \fBd\fR. +This example deletes line 4, +which is ``This is text added in Session 2.'' +if you typed the commands +suggested so far. +.DS I 1i +:\|\fB4d +.R +It doesn't mean much here, but +.DE +Here ``4'' is the number of the line to be deleted, +and ``delete'' or ``d'' is the command to delete the line. +After executing the delete command, +edit prints the line that has become the current line (``.''). +.PP +If you do not happen to know the line number +you can search for the line and then delete it using this +sequence of commands: +.DS I 1i +:\|\fB/added in Session 2./ +.R +This is text added in Session 2. +:\|\fBd +.R +It doesn't mean much here, but +.DE +The ``/added in Session 2./'' +asks edit to locate and print +the line containing the indicated text, +starting its search at the current line +and moving line by line +until it finds the text. +Once you are sure that you have correctly specified the line +you want to delete, +you can enter the delete (d) command. +In this case it is not necessary to +specify a line number before the ``d''. +If no line number is given, +edit deletes the current line (``.''), +that is, the line found by our search. +After the deletion, your buffer should contain: +.DS I 1i +This is some sample text. +And this is some more text. +Text editing is nice. +It doesn't mean much here, but +it does illustrate the editor. +And this is some more text. +Text editing is nice. +This is text added in Session 2. +It doesn't mean much here, but +.DE +To delete both lines 2 and 3: +.DS I 1i +And this is some more text. +Text editing is nice. +.DE +you type +.DS I 1i +:\|\f32,3d\f1 +2 lines deleted +.DE +which specifies the range of lines from 2 to 3, +and the operation on those lines \(em ``d'' for delete. +If you delete more than one line +you will receive a message +telling you the number of lines deleted, +as indicated in the example above. +.PP +The previous example assumes that you know the line numbers for +the lines to be deleted. +If you do not you might combine the search command +with the delete command: +.DS I 1i +:\|\fB/And this is some/,/Text editing is nice./d +.R +.DE +.SH +A word or two of caution +.PP +In using the search function to locate lines to +be deleted you should be +.B +absolutely sure +.R +the characters you give as the basis for the search +will take edit to the line you want deleted. +Edit will search for the first +occurrence of the characters starting from where +you last edited \- +that is, from the line you see printed if you type dot (.). +.PP +A search based on too few +characters may result in the wrong lines being deleted, +which edit will do as easily as if you had meant it. +For this reason, it is usually safer +to specify the search and then delete in two separate steps, +at least until you become familiar enough with using the editor +that you understand how best to specify searches. +For a beginner it is not a bad idea to double-check +each command before pressing \s-2RETURN\s+2 to send the command on its way. +.SH +Undo (u) to the rescue +.PP +The +.B +undo (u) +.R +command has the ability to +reverse the effects of the last command that changed the buffer. +To undo the previous command, type +``u'' or ``undo''. +Undo can rescue +the contents of the buffer from many an unfortunate mistake. +However, its powers are not unlimited, +so it is still wise to be reasonably +careful about the commands you give. +.PP +It is possible to undo only commands which +have the power to change the buffer \(em for example, +delete, append, move, copy, substitute, and even undo itself. +The commands write (w) and edit (e), which interact with disk files, +cannot be undone, nor can commands that do not change +the buffer, such as print. +Most importantly, +the +.B only +command that can be reversed by undo +is the +last ``undo-able'' command you typed. +You can use control-H and @ to change +commands while you are typing them, +and undo to reverse the effect of the commands +after you have typed them and pressed \s-2RETURN\s+2. +.PP +To illustrate, +let's issue an undo command. +Recall that the last buffer-changing command we gave deleted +the lines formerly numbered 2 and 3. +Typing undo at this moment will reverse the effects +of the deletion, causing those two lines to be +replaced in the buffer. +.DS I 1i +:\|\fBu +.R +2 more lines in file after undo +And this is some more text. +.DE +Here again, edit informs you if the command affects more +than one line, +and prints +the text of the line which is now ``dot'' (the current line). +.SH +More about the dot (.) and buffer end ($) +.PP +The function assumed by the symbol dot depends on its context. +It can be used: +.IP +1. to exit from append mode; we type dot (and only a dot) on +a line and press \s-2RETURN\s+2; +.IP +2. to refer to the line we are at in the buffer. +.LP +Dot can also be combined with the equal sign to get +the number of the line currently being edited: +.DS I 1i +:\|\fB\&.= +.R +.DE +If we type ``\fB.\fR='' we are asking for the number of the line, +and if we type ``\fB.\fR'' we are asking for the text of the line. +.PP +In this editing session and the last, we used the dollar +sign to indicate the end of the buffer +in commands such as print, copy, and move. +The dollar sign as a command asks edit to print the last +line in the buffer. +If the dollar sign is combined with the equal sign (\f3$=\f1) +edit will print the line number corresponding to the +last line in the buffer. +.PP +``\fB.\fR'' and ``$'', then, represent line numbers. +Whenever appropriate, these symbols can be used in +place of line numbers in commands. +For example +.DS I 1i +:\|\fB\s+2.\s-2,$d +.R +.DE +instructs edit to delete all lines from the current line (\fB.\fR) +to the end of the buffer. +.SH +Moving around in the buffer (+ and \-) +.PP +When you are editing +you often want +to go back and re-read a previous line. +You could specify a context search for a line you want to +read if you remember some of its text, +but if you simply want to see what was written a few, say 3, lines +ago, you can type +.DS I 1i +\-3p +.DE +This tells edit to move back to a position 3 lines +before the current line (.) +and print that line. +You can move forward in the buffer similarly: +.DS I 1i ++2p +.DE +instructs edit to print the line that is 2 +ahead of your current position. +.PP +You may use ``+'' and ``\-'' in any command where edit +accepts line numbers. +Line numbers specified with ``+'' or ``\-'' +can be combined to print a range of lines. +The command +.DS I 1i +:\|\fB\-1,+2copy$ +.R +.DE +makes a copy of 4 lines: the current line, the line before it, +and the two after it. +The copied lines will be placed after the last line +in the buffer ($), +and the original lines referred to by ``\-1'' and ``+2'' +remain where they are. +.PP +Try typing only ``\-''; you will move back one line just as +if you had typed ``\-1p''. +Typing the command ``+'' works similarly. +You might also try typing a few plus or minus signs in a row +(such as ``+++'') to see edit's response. +Typing \s-2RETURN\s+2 alone on a line is the equivalent +of typing ``+1p''; it will move you one line ahead in the buffer +and print that line. +.PP +If you are at the last line of the buffer and try +to move further ahead, perhaps by typing a ``+'' or +a carriage return alone on the line, +edit will remind you that you are at the end of the buffer: +.sp +.nf +.ti 1i +At end-of-file +.br +or +.ti 1i +Not that many lines in buffer +.fi +.LP +Similarly, if you try to move to a position before the first line, +edit will print one of these messages: +.sp +.nf +.ti 1i +Nonzero address required on this command +.br +or +.ti 1i +Negative address \- first buffer line is 1 +.fi +.LP +The number associated with a buffer line is the line's ``address'', +in that it can be used to locate the line. +.SH +Changing lines (c) +.PP +You can also delete certain lines and +insert new text in their place. +This can be accomplished easily with the +.B "change (c)" +command. +The change command instructs edit to delete specified lines +and then switch to text input mode to +accept the text that will replace them. +Let's say you want to change the first two lines in the buffer: +.DS I 1i +This is some sample text. +And this is some more text. +.DE +to read +.DS I 1i +This text was created with the \s-2UNIX\s0 text editor. +.DE +To do so, you type: +.DS I 1i +:\|\fB1,2c +.R +2 lines changed +.B +This text was created with the \s-2UNIX\s0 text editor. +\s+2\&.\s-2 +.R +: +.DE +In the command +.B 1,2c +we specify that we want to change +the range of lines beginning with 1 and ending with 2 +by giving line numbers as with the print command. +These lines will be deleted. +After you type \s-2RETURN\s+2 to end the change command, +edit notifies you if more than one line will be changed +and places you in text input mode. +Any text typed on the following lines will be inserted into +the position where lines were deleted by the change command. +.B +You will remain in text input mode until you exit in the usual way, +by typing a period alone on a line. +.R +Note that the number of lines added to the buffer need not be +the same as the number of lines deleted. +.sp 1 +.PP +This is the end of the third session on text editing with \s-2UNIX\s0. +.bp +.SH +.ce 1 +\s+2Session 4\s0 +.sp +.PP +This lesson covers several topics, starting with +commands that apply throughout the buffer, +characters with special meanings, +and how to issue \s-2UNIX\s0 commands while in the editor. +The next topics deal with files: +more on reading and writing, +and methods of recovering files lost in a crash. +The final section suggests sources of further information. +.SH +Making commands global (g) +.PP +One disadvantage to the commands we have used for +searching or substituting is that if you +have a number of instances of a word to change +it appears that you have to type the command +repeatedly, once for +each time the change needs to be made. +Edit, however, provides a way to make commands +apply to the entire contents of the buffer \- +the +.B +global (g) +.R +command. +.PP +To print all lines +containing a certain sequence of characters +(say, ``text'') +the command is: +.DS I 1i +:\|\fBg/text/p +.R +.DE +The ``g'' instructs edit to +make a global search for all lines +in the buffer containing the characters ``text''. +The ``p'' prints the lines found. +.PP +To issue a global command, start by typing a ``g'' and then a search +pattern identifying +the lines to be affected. +Then, on the same line, type the command to be +executed for the identified lines. +Global substitutions are frequently useful. +For example, +to change all instances of the word ``text'' to the word ``material'' +the command would be a combination of the global search and the +substitute command: +.DS I 1i +:\|\fBg/text/s/text/material/g +.R +.DE +Note the ``g'' at the end of the global command, +which instructs edit to change +each and every instance of ``text'' to ``material''. +If you do not type the ``g'' at the end of the command +only the +.I first +instance of ``text'' \fIin each line\fR will be changed +(the normal result of the substitute command). +The ``g'' at the end of the command is independent of the ``g'' +at the beginning. +You may give a command such as: +.DS I 1i +:\|\fB5s/text/material/g +.R +.DE +to change every instance of ``text'' in line 5 alone. +Further, neither command will change ``text'' to ``material'' +if ``Text'' begins with a capital rather than a lower-case +.I t. +.PP +Edit does not automatically print the lines modified by a +global command. +If you want the lines to be printed, type a ``p'' +at the end of the global command: +.DS I 1i +:\|\fBg/text/s/text/material/gp +.R +.DE +You should be careful +about using the global command in combination with any other \- +in essence, be sure of what you are telling edit to do +to the entire buffer. +For example, +.DS I 1i +:\|\fBg/ /d +.R +72 less lines in file after global +.DE +will delete every line containing a blank anywhere in it. +This could adversely affect +your document, since most lines have spaces between words +and thus would be deleted. +After executing the global command, +edit will print a warning if the command added or deleted more than one line. +Fortunately, the undo command can reverse +the effects of a global command. +You should experiment with the global command +on a small file of text to see what it can do for you. +.SH +More about searching and substituting +.PP +In using slashes to identify a character string +that we want to search for or change, +we have always specified the exact characters. +There is a less tedious way to +repeat the same string of characters. +To change ``text'' to ``texts'' we may type either +.DS I 1i +:\|\fB/text/s/text/texts/ +.R +.DE +as we have done in the past, +or a somewhat abbreviated command: +.DS I 1i +:\|\fB/text/s//texts/ +.R +.DE +In this example, the characters to be changed +are not specified \- +there are no characters, not even a space, +between the two slash marks +that indicate what is to be changed. +This lack of characters between the slashes +is taken by the editor to mean +``use the characters we last searched for as the characters to be changed.'' +.PP +Similarly, the last context search may be repeated +by typing a pair of slashes with nothing between them: +.DS I 1i +:\|\fB/does/ +.R +It doesn't mean much here, but +:\|\fB// +.R +it does illustrate the editor. +.DE +(You should note that the search command found the characters ``does'' +in the word ``doesn't'' in the first search request.) +Because no characters are specified for the second search, +the editor scans the buffer for the next occurrence of the +characters ``does''. +.PP +Edit normally searches forward through the buffer, +wrapping around from the end of the buffer to the beginning, +until the specified character string is found. +If you want to search in the reverse direction, +use question marks (?) instead of slashes +to surround the characters you are searching for. +.PP +It is also possible +to repeat the last substitution +without having to retype the entire command. +An ampersand (&) used as a command +repeats the most recent substitute command, +using the same search and replacement patterns. +After altering the current line by typing +.DS I 1i +:\|\fBs/text/texts/ +.R +.DE +you type +.DS I 1i +:\|\fB/text/& +.R +.DE +or simply +.DS I 1i +:\|\fB//& +.R +.DE +to make the same change on the next line in the buffer +containing the characters ``text''. +.SH +Special characters +.PP +Two characters have special meanings when +used in specifying searches: ``$'' and ``^''. +``$'' is taken by the editor to mean ``end of the line'' +and is used to identify strings +that occur at the end of a line. +.DS I 1i +:\|\fBg/text.$/s//material./p +.R +.DE +tells the editor to search for all lines ending in ``text.'' +(and nothing else, not even a blank space), +to change each final ``text.'' to ``material.'', +and print the changed lines. +.PP +The symbol ``^'' indicates the beginning of a line. +Thus, +.DS I 1i +:\|\fBs/^/1. / +.R +.DE +instructs the editor to insert ``1.'' and a space at the beginning +of the current line. +.PP +The characters ``$'' and ``^'' have special meanings only in the context +of searching. +At other times, they are ordinary characters. +If you ever need to search for a character that has a special meaning, +you must indicate that the +character is to lose temporarily +its special significance by typing another special character, +the backslash (\\), before it. +.DS I 1i +:\|\fBs/\\\\\&$/dollar/ +.R +.DE +looks for the character ``$'' in the current +line and replaces it by the word ``dollar''. +Were it not for the backslash, the ``$'' would have represented +``the end of the line'' in your search +rather than the character ``$''. +The backslash retains its special significance +unless it is preceded by another backslash. +.SH +Issuing \s-2UNIX\s0 commands from the editor +.PP +After creating several files with the editor, +you may want to delete files +no longer useful to you or ask for a list of your files. +Removing and listing files are not functions of the editor, +and so they require the use of \s-2UNIX\s0 system commands +(also referred to as ``shell'' commands, as +``shell'' is the name of the program that processes \s-2UNIX\s0 commands). +You do not need to quit the editor to execute a \s-2UNIX\s0 command +as long as you indicate that it +is to be sent to the shell for execution. +To use the \s-2UNIX\s0 command +.B rm +to remove the file named ``junk'' type: +.DS I 1i +:\|\fB!rm junk +.R +! +: +.DE +The exclamation mark (!) +indicates that the rest of the line is to be processed as a shell command. +If the buffer contents have not been written since the last change, +a warning will be printed before the command is executed: +.DS I 1i +[No write since last change] +.DE +The editor prints a ``!'' when the command is completed. +Other tutorials describe useful features of the system, +of which an editor is only one part. +.SH +Filenames and file manipulation +.PP +Throughout each editing session, +edit keeps track of the name of the file being edited as the +.I "current filename." +Edit remembers as the current filename the name given +when you entered the editor. +The current filename changes whenever the edit (e) command +is used to specify a new file. +Once edit has recorded a current filename, +it inserts that name into any command where a filename has been omitted. +If a write command does not specify a file, +edit, as we have seen, supplies the current filename. +If you are editing a file named ``draft3'' having 283 lines in it, +you can have the editor write onto a different file +by including its name in the write command: +.DS I 1i +:\fB\|w chapter3 +.R +"chapter3" [new file] 283 lines, 8698 characters +.DE +The current filename remembered by the editor +.I +will not be changed as a result of the write command. +.R +Thus, if the next write command +does not specify a name, +edit will write onto the current file (``draft3'') +and not onto the file ``chapter3''. +.SH +The file (f) command +.PP +To ask for the current filename, type +.B file +(or +.B f ). +In response, the editor provides current information about the buffer, +including the filename, your current position, the number of +lines in the buffer, +and the percent of the distance through the file +your current location is. +.DS I 1i +:\|\fBf +.R +"text" [Modified] line 3 of 4 --75%-- +.DE +.\"The expression ``[Edited]'' indicates that the buffer contains +.\"either the editor's copy of the existing file ``text'' +.\"or a file which you are just now creating. +If the contents of the buffer have changed +since the last time the file was written, +the editor will tell you that the file has been ``[Modified]''. +After you save the changes by writing onto a disk file, +the buffer will no longer be considered modified: +.DS I 1i +:\|\fBw +.R +"text" 4 lines, 88 characters +:\|\fBf +.R +"text" line 3 of 4 --75%-- +.DE +.SH +Reading additional files (r) +.PP +The +\f3read (r)\f1 command allows you to add the contents of a file +to the buffer +at a specified location, +essentially copying new lines +between two existing lines. +To use it, specify the line after which the new text will be placed, +the \f3read (r)\f1 command, +and then the name of the file. +If you have a file named ``example'', the command +.DS I 1i +:\|\fB$r example +.R +"example" 18 lines, 473 characters +.DE +reads the file ``example'' +and adds it to the buffer after the last line. +The current filename is not changed by the read command. +.SH +Writing parts of the buffer +.PP +The +.B +write (w) +.R +command can write all or part of the buffer +to a file you specify. +We are already familiar with +writing the entire contents of the +buffer to a disk file. +To write only part of the buffer onto a file, +indicate the beginning and ending lines before the write command, +for example +.DS I 1i +:\|\fB45,$w ending +.R +.DE +Here all lines from 45 through the end of the buffer +are written onto the file named +.I ending. +The lines remain in the buffer +as part of the document you are editing, +and you may continue to edit the entire buffer. +Your original file is unaffected +by your command to write part of the buffer +to another file. +Edit still remembers whether you have saved changes to the buffer +in your original file or not. +.SH +Recovering files +.PP +Although it does not happen very often, +there are times \s-2UNIX\s+2 stops working +because of some malfunction. +This situation is known as a \fIcrash\fR. +Under most circumstances, +edit's crash recovery feature +is able to save work to within a few lines of changes +before a crash (or an accidental phone hang up). +If you lose the contents of an editing buffer in a system crash, +you will normally receive mail when you login that gives +the name of the recovered file. +To recover the file, +enter the editor and type the command +.B recover +(\fBrec\fR), +followed by the name of the lost file. +For example, +to recover the buffer for an edit session +involving the file ``chap6'', the command is: +.DS I 1i +.R +:\|\fBrecover chap6 +.R +.DE +Recover is sometimes unable to save the entire buffer successfully, +so always check the contents of the saved buffer carefully +before writing it back onto the original file. +For best results, +write the buffer to a new file temporarily +so you can examine it without risk to the original file. +Unfortunately, +you cannot use the recover command +to retrieve a file you removed +using the shell command \f3rm\f1. +.SH +Other recovery techniques +.PP +If something goes wrong when you are using the editor, +it may be possible to save your work by using the command +.B preserve +(\fBpre\fR), +which saves the buffer as if the system had crashed. +If you are writing a file and you get the message +``Quota exceeded'', you have tried to use more disk storage +than is allotted to your account. +.I +Proceed with caution +.R +because it is likely that only a part +of the editor's buffer is now present in the file you tried to write. +In this case you should use the shell escape from the editor (!) +to remove some files you don't need and try to write +the file again. +If this is not possible and you cannot find someone to help you, +enter the command +.DS I 1i +:\|\fBpreserve +.R +.DE +and wait for the reply, +.DS I 1i +File preserved. +.DE +If you do not receive this reply, +seek help immediately. +Do not simply leave the editor. +If you do, the buffer will be lost, +and you may not be able to save your file. +If the reply is ``File preserved.'' +you can leave the editor +(or logout) +to remedy the situation. +After a preserve, you can use the recover command +once the problem has been corrected, +or the \fB\-r\fR option of the edit command +if you leave the editor and want to return. +.PP +If you make an undesirable change to the buffer +and type a write command before discovering your mistake, +the modified version will replace any previous version of the file. +Should you ever lose a good version of a document in this way, +do not panic and leave the editor. +As long as you stay in the editor, +the contents of the buffer remain accessible. +Depending on the nature of the problem, +it may be possible +to restore the buffer to a more complete +state with the undo command. +After fixing the damaged buffer, you can again write the file +to disk. +.SH +Further reading and other information +.PP +Edit is an editor designed for beginning and casual users. +It is actually a version of a more powerful editor called +.I ex. +These lessons are intended to introduce you to the editor +and its more commonly-used commands. +We have not covered all of the editor's commands, +but a selection of commands +that should be sufficient to accomplish most of your editing tasks. +You can find out more about the editor in the +.I +Ex Reference Manual, +.R +which is applicable to both +.I ex +and +.I edit. +One way to become familiar with the manual is to begin by reading +the description of commands that you already know. +.bd I 3 +.SH +Using +.I ex +.fl +.bd I +.PP +As you become more experienced with using the editor, +you may still find that edit continues to meet your needs. +However, should you become interested in using +.I ex, +it is easy to switch. +To begin an editing session with +.I ex, +use the name +.B ex +in your command instead of +.B edit. +.PP +Edit commands also work in +.I ex, +but the editing environment is somewhat different. +You should be aware of a few differences +between +.I ex +and +.I edit. +In edit, only the characters ``^'', ``$'', and ``\\'' have +special meanings in searching the buffer +or indicating characters to be changed by a substitute command. +Several additional characters have special +meanings in ex, as described in the +.I +Ex Reference Manual. +.R +Another feature of the edit environment prevents users from +accidently entering two alternative modes of editing, +.I open +and +.I visual, +in which +the editor behaves quite differently from normal command mode. +If you are using ex and you encounter strange behavior, +you may have accidently entered open mode by typing ``o''. +Type the \s-2ESC\s0 key and then a ``Q'' +to get out of open or visual mode and back into +the regular editor command mode. +The document +.I +An Introduction to Display Editing with Vi\|\| +.R +provide full details of visual mode. +.bp +.SH +.ce 1 +\s+2Index\s0 +.LP +.sp 2 +.2C +.nf +addressing, \fIsee\fR line numbers +ampersand, 20 +append mode, 6-7 +append (a) command, 6, 7, 9 +``At end of file'' (message), 18 +backslash (\\), 21 +buffer, 3 +caret (^), 10, 20 +change (c) command, 18 +command mode, 5-6 +``Command not found'' (message), 6 +context search, 10-12, 19-21 +control characters (``^'' notation), 10 +control-H, 7 +copy (co) command, 15 +corrections, 7, 16 +current filename, 21 +current line (\|.\|), 11, 17 +delete (d) command, 15-16 +dial-up, 5 +disk, 3 +documentation, 3, 23 +dollar ($), 10, 11, 17, 20-21 +dot (\f3\|.\|\f1) 11, 17 +edit (text editor), 3, 5, 23 +edit (e) command, 5, 9, 14 +editing commands: +.in +.25i +append (a), 6, 7, 9 +change (c), 18 +copy (co), 15 +delete (d), 15-16 +edit (text editor), 3, 5, 23 +edit (e), 5, 9, 14 +file (f), 21-22 +global (g), 19 +move (m), 14-15 +number (nu), 11 +preserve (pre), 22-23 +print (p), 10 +quit (q), 8, 13 +read (r), 22 +recover (rec), 22, 23 +substitute (s), 11-12, 19, 20 +undo (u), 16-17, 23 +write (w), 8, 13, 21, 22 +z, 12-13 +! (shell escape), 21 +$=, 17 ++, 17 +\-, 17 +//, 12, 20 +??, 20 +\&., 11, 17 +\&.=, 11, 17 +.in -.25i +entering text, 3, 6-7 +erasing +.in +.25i +characters (^H), 7 +lines (@), 7 +.in -.25i +error corrections, 7, 16 +ex (text editor), 23 +\fIEx Reference Manual\fR, 23 +exclamation (!), 21 +file, 3 +file (f) command, 21-22 +file recovery, 22-23 +filename, 3, 21 +global (g) command, 19 +input mode, 6-7 +Interrupt (message), 9 +line numbers, \fIsee also\fR current line +.in +.25i +dollar sign ($), 10, 11, 17 +dot (\|.\|), 11, 17 +relative (+ and \-), 17 +.in -.25i +list, 10 +logging in, 4-6 +logging out, 8 +``Login incorrect'' (message), 5 +minus (\-), 17 +move (m) command, 14-15 +``Negative address\(emfirst buffer line is 1'' (message), 18 +``No current filename'' (message), 8 +``No such file or directory'' (message), 5, 6 +``No write since last change'' (message), 21 +non-printing characters, 10 +``Nonzero address required'' (message), 18 +``Not an editor command'' (message), 6 +``Not that many lines in buffer'' (message), 18 +number (nu) command, 11 +password, 5 +period (\|.\|), 11, 17 +plus (+), 17 +preserve (pre) command, 22-23 +print (p) command, 10 +program, 3 +prompts +.in .25i +% (\s-2UNIX\s0), 5 +: (edit), 5, 6, 7 +\0 (append), 7 +.in -.25i +question (?), 20 +quit (q) command, 8, 13 +read (r) command, 22 +recover (rec) command, 22, 23 +recovery, \fIsee\fR\| file recovery +references, 3, 23 +remove (rm) command, 21, 22 +reverse command effects (undo), 16-17, 23 +searching, 10-12, 19-21 +shell, 21 +shell escape (!), 21 +slash (/), 11-12, 20 +special characters (^, $, \\), 10, 11, 17, 20-21 +substitute (s) command, 11-12, 19, 20 +terminals, 4-5 +text input mode, 7 +undo (u) command, 16-17, 23 +\s-1UNIX\s0, 3 +write (w) command, 8, 13, 21, 22 +z command, 12-13 + diff --git a/usr.bin/vi/USD.doc/exref/Makefile b/usr.bin/vi/USD.doc/exref/Makefile new file mode 100644 index 0000000..11f4e66 --- /dev/null +++ b/usr.bin/vi/USD.doc/exref/Makefile @@ -0,0 +1,14 @@ +# @(#)Makefile 8.1 (Berkeley) 6/8/93 + +DIR= usd/13.ex +SRCS= ex.rm +MACROS= -msU +CLEANFILES=summary.* + +paper.ps: ${SRCS} summary.ps + ${ROFF} ${SRCS} > ${.TARGET} + +summary.ps: ex.summary + ${TBL} ex.summary | ${ROFF} > ${.TARGET} + +.include <bsd.doc.mk> diff --git a/usr.bin/vi/USD.doc/exref/ex.rm b/usr.bin/vi/USD.doc/exref/ex.rm new file mode 100644 index 0000000..79670c2 --- /dev/null +++ b/usr.bin/vi/USD.doc/exref/ex.rm @@ -0,0 +1,2230 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ex.rm 8.1 (Berkeley) 6/8/93 +.\" +.EH 'USD:13-%''Ex Reference Manual' +.OH 'Ex Reference Manual''USD:13-%' +.de ZP +.nr pd \\n()P +.nr )P 0 +.if \\n(.$=0 .IP +.if \\n(.$=1 .IP "\\$1" +.if \\n(.$>=2 .IP "\\$1" "\\$2" +.nr )P \\n(pd +.rm pd +.. +.de LC +.br +.sp .1i +.ne 4 +.LP +.ta 4.0i +.. +.bd S B 3 +.\".RP +.TL +Ex Reference Manual +.br +Version 3.7 +.AU +William Joy +.AU +Mark Horton +.AI +Computer Science Division +Department of Electrical Engineering and Computer Science +University of California, Berkeley +Berkeley, Ca. 94720 +.AB +.I Ex +a line oriented text editor, which supports both command and display +oriented editing. +This reference manual describes the command oriented part of +.I ex; +the display editing features of +.I ex +are described in +.I "An Introduction to Display Editing with Vi." +Other documents about the editor include the introduction +.I "Edit: A tutorial", +the +.I "Ex/edit Command Summary", +and a +.I "Vi Quick Reference" +card. +.AE +.NH 1 +Starting ex +.PP +.FS +The financial support of an \s-2IBM\s0 Graduate Fellowship and the National +Science Foundation under grants MCS74-07644-A03 and MCS78-07291 is gratefully +acknowledged. +.FE +Each instance of the editor has a set of options, +which can be set to tailor it to your liking. +The command +.I edit +invokes a version of +.I ex +designed for more casual or beginning +users by changing the default settings of some of these options. +To simplify the description which follows we +assume the default settings of the options. +.PP +When invoked, +.I ex +determines the terminal type from the \s-2TERM\s0 variable in the environment. +It there is a \s-2TERMCAP\s0 variable in the environment, and the type +of the terminal described there matches the \s-2TERM\s0 variable, +then that description +is used. Also if the \s-2TERMCAP\s0 variable contains a pathname (beginning +with a \fB/\fR) then the editor will seek the description of the terminal +in that file (rather than the default /etc/termcap). +If there is a variable \s-2EXINIT\s0 in the environment, then the editor +will execute the commands in that variable, +otherwise if there is a file +.I \&.exrc +in your \s-2HOME\s0 directory +.I ex +reads commands from that file, simulating a +.I source +command. +Option setting commands placed in +\s-2EXINIT\s0 or +.I \&.exrc +will be executed before each editor session. +.PP +A command to enter +.I ex +has the following prototype:\(dg +.FS +\(dg Brackets `[' `]' surround optional parameters here. +.FE +.DS +\fBex\fP [ \fB\-\fP ] [ \fB\-v\fP ] [ \fB\-t\fP \fItag\fP ] [ \fB\-r\fP ] [ \fB\-l\fP ] [ \fB\-w\fP\fIn\fP ] [ \fB\-x\fP ] [ \fB\-R\fP ] [ \fB+\fP\fIcommand\fP ] name ... +.DE +The most common case edits a single file with no options, i.e.: +.DS +\fBex\fR name +.DE +The +.B \- +command line option +option suppresses all interactive-user feedback +and is useful in processing editor scripts in command files. +The +.B \-v +option is equivalent to using +.I vi +rather than +.I ex. +The +.B \-t +option is equivalent to an initial +.I tag +command, editing the file containing the +.I tag +and positioning the editor at its definition. +The +.B \-r +option is used in recovering after an editor or system crash, +retrieving the last saved version of the named file or, +if no file is specified, +typing a list of saved files. +The +.B \-l +option sets up for editing \s-2LISP\s0, setting the +.I showmatch +and +.I lisp +options. +The +.B \-w +option sets the default window size to +.I n, +and is useful on dialups to start in small windows. +The +.B \-x +option causes +.I ex +to prompt for a +.I key , +which is used to encrypt and decrypt the contents of the file, +which should already be encrypted using the same key, +see +.I crypt (1). +The +.B \-R +option sets the +.I readonly +option at the start. +.I Name +arguments indicate files to be edited. +An argument of the form +\fB+\fIcommand\fR +indicates that the editor should begin by executing the specified command. +If +.I command +is omitted, then it defaults to ``$'', positioning the editor at the last +line of the first file initially. Other useful commands here are scanning +patterns of the form ``/pat'' or line numbers, e.g. ``+100'' starting +at line 100. +.NH 1 +File manipulation +.NH 2 +Current file +.PP +.I Ex +is normally editing the contents of a single file, +whose name is recorded in the +.I current +file name. +.I Ex +performs all editing actions in a buffer +(actually a temporary file) +into which the text of the file is initially read. +Changes made to the buffer have no effect on the file being +edited unless and until the buffer contents are written out to the +file with a +.I write +command. +After the buffer contents are written, +the previous contents of the written file are no longer accessible. +When a file is edited, +its name becomes the current file name, +and its contents are read into the buffer. +.PP +The current file is almost always considered to be +.I edited. +This means that the contents of the buffer are logically +connected with the current file name, +so that writing the current buffer contents onto that file, +even if it exists, +is a reasonable action. +If the current file is not +.I edited +then +.I ex +will not normally write on it if it already exists.* +.FS +* The +.I file +command will say ``[Not edited]'' if the current file is not considered +edited. +.FE +.NH 2 +Alternate file +.PP +Each time a new value is given to the current file name, +the previous current file name is saved as the +.I alternate +file name. +Similarly if a file is mentioned but does not become the current file, +it is saved as the alternate file name. +.NH 2 +Filename expansion +.PP +Filenames within the editor may be specified using the normal +shell expansion conventions. +In addition, +the character `%' in filenames is replaced by the +.I current +file name and the character +`#' by the +.I alternate +file name.\(dg +.FS +\(dg This makes it easy to deal alternately with +two files and eliminates the need for retyping the +name supplied on an +.I edit +command after a +.I "No write since last change" +diagnostic is received. +.FE +.NH 2 +Multiple files and named buffers +.PP +If more than one file is given on the command line, +then the first file is edited as described above. +The remaining arguments are placed with the first file in the +.I "argument list." +The current argument list may be displayed with the +.I args +command. +The next file in the argument list may be edited with the +.I next +command. +The argument list may also be respecified by specifying +a list of names to the +.I next +command. +These names are expanded, +the resulting list of names becomes the new argument list, +and +.I ex +edits the first file on the list. +.PP +For saving blocks of text while editing, and especially when editing +more than one file, +.I ex +has a group of named buffers. +These are similar to the normal buffer, except that only a limited number +of operations are available on them. +The buffers have names +.I a +through +.I z.\(dd +.FS +\(dd It is also possible to refer to +.I A +through +.I Z; +the upper case buffers are the same as the lower but commands +append to named buffers rather than replacing +if upper case names are used. +.FE +.NH 2 +Read only +.PP +It is possible to use +.I ex +in +.I "read only" +mode to look at files that you have no intention of modifying. +This mode protects you from accidently overwriting the file. +Read only mode is on when the +.I readonly +option is set. +It can be turned on with the +.B \-R +command line option, +by the +.I view +command line invocation, +or by setting the +.I readonly +option. +It can be cleared by setting +.I noreadonly . +It is possible to write, even while in read only mode, by indicating +that you really know what you are doing. +You can write to a different file, or can use the ! form of write, +even while in read only mode. +.NH 1 +Exceptional Conditions +.NH 2 +Errors and interrupts +.PP +When errors occur +.I ex +(optionally) rings the terminal bell and, in any case, prints an error +diagnostic. If the primary input is from a file, editor processing +will terminate. If an interrupt signal is received, +.I ex +prints ``Interrupt'' and returns to its command level. If the primary +input is a file, then +.I ex +will exit when this occurs. +.NH 2 +Recovering from hangups and crashes +.PP +If a hangup signal is received and the buffer has been modified since +it was last written out, or if the system crashes, either the editor +(in the first case) or the system (after it reboots in the second) will +attempt to preserve the buffer. The next time you log in you should be +able to recover the work you were doing, losing at most a few lines of +changes from the last point before the hangup or editor crash. To +recover a file you can use the +.B \-r +option. If you were editing the file +.I resume, +then you should change +to the directory where you were when the crash occurred, giving the command +.DS +\fBex \-r\fP\fI resume\fP +.DE +After checking that the retrieved file is indeed ok, you can +.I write +it over the previous contents of that file. +.PP +You will normally get mail from the system telling you when a file has +been saved after a crash. The command +.DS +\fBex\fP \-\fBr\fP +.DE +will print a list of the files which have been saved for you. +(In the case of a hangup, +the file will not appear in the list, +although it can be recovered.) +.NH 1 +Editing modes +.PP +.I Ex +has five distinct modes. The primary mode is +.I command +mode. Commands are entered in command mode when a `:' prompt is +present, and are executed each time a complete line is sent. In +.I "text input" +mode +.I ex +gathers input lines and places them in the file. The +.I append, +.I insert, +and +.I change +commands use text input mode. +No prompt is printed when you are in text input mode. +This mode is left by typing a `.' alone at the beginning of a line, and +.I command +mode resumes. +.PP +The last three modes are +.I open +and +.I visual +modes, entered by the commands of the same name, and, within open and +visual modes +.I "text insertion" +mode. +.I Open +and +.I visual +modes allow local editing operations to be performed on the text in the +file. The +.I open +command displays one line at a time on any terminal while +.I visual +works on \s-2CRT\s0 terminals with random positioning cursors, using the +screen as a (single) window for file editing changes. +These modes are described (only) in +.I "An Introduction to Display Editing with Vi." +.NH +Command structure +.PP +Most command names are English words, +and initial prefixes of the words are acceptable abbreviations. +The ambiguity of abbreviations is resolved in favor of the more commonly +used commands.* +.FS +* As an example, the command +.I substitute +can be abbreviated `s' +while the shortest available abbreviation for the +.I set +command is `se'. +.FE +.NH 2 +Command parameters +.PP +Most commands accept prefix addresses specifying the lines in the file +upon which they are to have effect. +The forms of these addresses will be discussed below. +A number of commands also may take a trailing +.I count +specifying the number of lines to be involved in the command.\(dg +.FS +\(dg Counts are rounded down if necessary. +.FE +Thus the command ``10p'' will print the tenth line in the buffer while +``delete 5'' will delete five lines from the buffer, +starting with the current line. +.PP +Some commands take other information or parameters, +this information always being given after the command name.\(dd +.FS +\(dd Examples would be option names in a +.I set +command i.e. ``set number'', +a file name in an +.I edit +command, +a regular expression in a +.I substitute +command, +or a target address for a +.I copy +command, i.e. ``1,5 copy 25''. +.FE +.NH 2 +Command variants +.PP +A number of commands have two distinct variants. +The variant form of the command is invoked by placing an +`!' immediately after the command name. +Some of the default variants may be controlled by options; +in this case, the `!' serves to toggle the default. +.NH 2 +Flags after commands +.PP +The characters `#', `p' and `l' may be placed after many commands.** +.FS +** +A `p' or `l' must be preceded by a blank or tab +except in the single special case `dp'. +.FE +In this case, the command abbreviated by these characters +is executed after the command completes. +Since +.I ex +normally prints the new current line after each change, `p' is rarely necessary. +Any number of `+' or `\-' characters may also be given with these flags. +If they appear, the specified offset is applied to the current line +value before the printing command is executed. +.NH 2 +Comments +.PP +It is possible to give editor commands which are ignored. +This is useful when making complex editor scripts +for which comments are desired. +The comment character is the double quote: ". +Any command line beginning with " is ignored. +Comments beginning with " may also be placed at the ends +of commands, except in cases where they could be confused as part +of text (shell escapes and the substitute and map commands). +.NH 2 +Multiple commands per line +.PP +More than one command may be placed on a line by separating each pair +of commands by a `|' character. +However the +.I global +commands, +comments, +and the shell escape `!' +must be the last command on a line, as they are not terminated by a `|'. +.NH 2 +Reporting large changes +.PP +Most commands which change the contents of the editor buffer give +feedback if the scope of the change exceeds a threshold given by the +.I report +option. +This feedback helps to detect undesirably large changes so that they may +be quickly and easily reversed with an +.I undo. +After commands with more global effect such as +.I global +or +.I visual, +you will be informed if the net change in the number of lines +in the buffer during this command exceeds this threshold. +.NH 1 +Command addressing +.NH 2 +Addressing primitives +.IP \fB.\fR 20 +The current line. +Most commands leave the current line as the last line which they affect. +The default address for most commands is the current line, +thus `\fB.\fR' is rarely used alone as an address. +.IP \fIn\fR 20 +The \fIn\fRth line in the editor's buffer, lines being numbered +sequentially from 1. +.IP \fB$\fR 20 +The last line in the buffer. +.IP \fB%\fR 20 +An abbreviation for ``1,$'', the entire buffer. +.IP \fI+n\fR\ \fI\-n\fR 20 +An offset relative to the current buffer line.\(dg +.FS +\(dg +The forms `.+3' `+3' and `+++' are all equivalent; +if the current line is line 100 they all address line 103. +.FE +.IP \fB/\fIpat\fR\fB/\fR\ \fB?\fIpat\fR\fB?\fR 20 +Scan forward and backward respectively for a line containing \fIpat\fR, a +regular expression (as defined below). The scans normally wrap around the end +of the buffer. +If all that is desired is to print the next line containing \fIpat\fR, then +the trailing \fB/\fR or \fB?\fR may be omitted. +If \fIpat\fP is omitted or explicitly empty, then the last +regular expression specified is located.\(dd +.FS +\(dd The forms \fB\e/\fP and \fB\e?\fP scan +using the last regular expression used in a scan; after a substitute +\fB//\fP and \fB??\fP would scan using the substitute's regular expression. +.FE +.IP \fB\(aa\(aa\fP\ \fB\(aa\fP\fIx\fP 20 +Before each non-relative motion of the current line `\fB.\fP', +the previous current line is marked with a tag, subsequently referred to as +`\(aa\(aa'. +This makes it easy to refer or return to this previous context. +Marks may also be established by the +.I mark +command, using single lower case letters +.I x +and the marked lines referred to as +`\(aa\fIx\fR'. +.NH 2 +Combining addressing primitives +.PP +Addresses to commands consist of a series of addressing primitives, +separated by `,' or `;'. +Such address lists are evaluated left-to-right. +When addresses are separated by `;' the current line `\fB.\fR' +is set to the value of the previous addressing expression +before the next address is interpreted. +If more addresses are given than the command requires, +then all but the last one or two are ignored. +If the command takes two addresses, the first addressed line must +precede the second in the buffer.\(dg +.FS +\(dg Null address specifications are permitted in a list of addresses, +the default in this case is the current line `.'; +thus `,100' is equivalent to `\fB.\fR,100'. +It is an error to give a prefix address to a command which expects none. +.FE +.NH 1 +Command descriptions +.PP +The following form is a prototype for all +.I ex +commands: +.DS +\fIaddress\fR \fBcommand\fR \fI! parameters count flags\fR +.DE +All parts are optional; the degenerate case is the empty command which prints +the next line in the file. For sanity with use from within +.I visual +mode, +.I ex +ignores a ``:'' preceding any command. +.PP +In the following command descriptions, the +default addresses are shown in parentheses, +which are +.I not, +however, +part of the command. +.LC +\fBabbreviate\fR \fIword rhs\fP abbr: \fBab\fP +.ZP +Add the named abbreviation to the current list. +When in input mode in visual, if +.I word +is typed as a complete word, it will be changed to +.I rhs . +.LC +( \fB.\fR ) \fBappend\fR abbr: \fBa\fR +.br +\fItext\fR +.br +\&\fB.\fR +.ZP +Reads the input text and places it after the specified line. +After the command, `\fB.\fR' +addresses the last line input or the +specified line if no lines were input. +If address `0' is given, +text is placed at the beginning of the buffer. +.LC +\fBa!\fR +.br +\fItext\fR +.br +\&\fB.\fR +.ZP +The variant flag to +.I append +toggles the setting for the +.I autoindent +option during the input of +.I text. +.LC +\fBargs\fR +.ZP +The members of the argument list are printed, with the current argument +delimited by `[' and `]'. +.ig +.PP +\fBcd\fR \fIdirectory\fR +.ZP +The +.I cd +command is a synonym for +.I chdir. +.. +.LC +( \fB.\fP , \fB.\fP ) \fBchange\fP \fIcount\fP abbr: \fBc\fP +.br +\fItext\fP +.br +\&\fB.\fP +.ZP +Replaces the specified lines with the input \fItext\fP. +The current line becomes the last line input; +if no lines were input it is left as for a +\fIdelete\fP. +.LC +\fBc!\fP +.br +\fItext\fP +.br +\&\fB.\fP +.ZP +The variant toggles +.I autoindent +during the +.I change. +.ig +.LC +\fBchdir\fR \fIdirectory\fR +.ZP +The specified \fIdirectory\fR becomes the current directory. +If no directory is specified, the current value of the +.I home +option is used as the target directory. +After a +.I chdir +the current file is not considered to have been +edited so that write restrictions on pre-existing files apply. +.. +.LC +( \fB.\fP , \fB.\fP )\|\fBcopy\fP \fIaddr\fP \fIflags\fP abbr: \fBco\fP +.ZP +A +.I copy +of the specified lines is placed after +.I addr, +which may be `0'. +The current line +`\fB.\fR' +addresses the last line of the copy. +The command +.I t +is a synonym for +.I copy. +.LC +( \fB.\fR , \fB.\fR )\|\fBdelete\fR \fIbuffer\fR \fIcount\fR \fIflags\fR abbr: \fBd\fR +.ZP +Removes the specified lines from the buffer. +The line after the last line deleted becomes the current line; +if the lines deleted were originally at the end, +the new last line becomes the current line. +If a named +.I buffer +is specified by giving a letter, +then the specified lines are saved in that buffer, +or appended to it if an upper case letter is used. +.LC +\fBedit\fR \fIfile\fR abbr: \fBe\fR +.br +\fBex\fR \fIfile\fR +.ZP +Used to begin an editing session on a new file. +The editor +first checks to see if the buffer has been modified since the last +.I write +command was issued. +If it has been, +a warning is issued and the +command is aborted. +The +command otherwise deletes the entire contents of the editor buffer, +makes the named file the current file and prints the new filename. +After insuring that this file is sensible\(dg +.FS +\(dg I.e., that it is not a binary file such as a directory, +a block or character special file other than +.I /dev/tty, +a terminal, +or a binary or executable file +(as indicated by the first word). +.FE +the editor reads the file into its buffer. +.IP +If the read of the file completes without error, +the number of lines and characters read is typed. +If there were any non-\s-2ASCII\s0 characters +in the file they are stripped of their non-\s-2ASCII\s0 +high bits, +and any null characters in the file are discarded. +If none of these errors occurred, the file is considered +.I edited. +If the last line of the input file is missing the trailing +newline character, it will be supplied and a complaint will be issued. +This command leaves the current line `\fB.\fR' at the last line read.\(dd +.FS +\(dd If executed from within +.I open +or +.I visual, +the current line is initially the first line of the file. +.FE +.LC +\fBe!\fR \fIfile\fR +.ZP +The variant form suppresses the complaint about modifications having +been made and not written from the editor buffer, thus +discarding all changes which have been made before editing the new file. +.LC +\fBe\fR \fB+\fIn\fR \fIfile\fR +.ZP +Causes the editor to begin at line +.I n +rather than at the last line; +\fIn\fR may also be an editor command containing no spaces, e.g.: ``+/pat''. +.LC +\fBfile\fR abbr: \fBf\fR +.ZP +Prints the current file name, +whether it has been `[Modified]' since the last +.I write +command, +whether it is +.I "read only" , +the current line, +the number of lines in the buffer, +and the percentage of the way through the buffer of the current line.* +.FS +* In the rare case that the current file is `[Not edited]' this is +noted also; in this case you have to use the form \fBw!\fR to write to +the file, since the editor is not sure that a \fBwrite\fR will not +destroy a file unrelated to the current contents of the buffer. +.FE +.LC +\fBfile\fR \fIfile\fR +.ZP +The current file name is changed to +.I file +which is considered +`[Not edited]'. +.LC +( 1 , $ ) \fBglobal\fR /\fIpat\|\fR/ \fIcmds\fR abbr: \fBg\fR +.ZP +First marks each line among those specified which matches +the given regular expression. +Then the given command list is executed with `\fB.\fR' initially +set to each marked line. +.IP +The command list consists of the remaining commands on the current +input line and may continue to multiple lines by ending all but the +last such line with a `\e'. +If +.I cmds +(and possibly the trailing \fB/\fR delimiter) is omitted, each line matching +.I pat +is printed. +.I Append, +.I insert, +and +.I change +commands and associated input are permitted; +the `\fB.\fR' terminating input may be omitted if it would be on the +last line of the command list. +.I Open +and +.I visual +commands are permitted in the command list and take input from the terminal. +.IP +The +.I global +command itself may not appear in +.I cmds. +The +.I undo +command is also not permitted there, +as +.I undo +instead can be used to reverse the entire +.I global +command. +The options +.I autoprint +and +.I autoindent +are inhibited during a +.I global, +(and possibly the trailing \fB/\fR delimiter) and the value of the +.I report +option is temporarily infinite, +in deference to a \fIreport\fR for the entire global. +Finally, the context mark `\'\'' is set to the value of +`.' before the global command begins and is not changed during a global +command, +except perhaps by an +.I open +or +.I visual +within the +.I global. +.LC +\fBg!\fR \fB/\fIpat\fB/\fR \fIcmds\fR abbr: \fBv\fR +.IP +The variant form of \fIglobal\fR runs \fIcmds\fR at each line not matching +\fIpat\fR. +.LC +( \fB.\fR )\|\fBinsert\fR abbr: \fBi\fR +.br +\fItext\fR +.br +\&\fB.\fR +.ZP +Places the given text before the specified line. +The current line is left at the last line input; +if there were none input it is left at the line before the addressed line. +This command differs from +.I append +only in the placement of text. +.KS +.LC +\fBi!\fR +.br +\fItext\fR +.br +\&\fB.\fR +.ZP +The variant toggles +.I autoindent +during the +.I insert. +.KE +.LC +( \fB.\fR , \fB.\fR+1 ) \fBjoin\fR \fIcount\fR \fIflags\fR abbr: \fBj\fR +.ZP +Places the text from a specified range of lines +together on one line. +White space is adjusted at each junction to provide at least +one blank character, two if there was a `\fB.\fR' at the end of the line, +or none if the first following character is a `)'. +If there is already white space at the end of the line, +then the white space at the start of the next line will be discarded. +.LC +\fBj!\fR +.ZP +The variant causes a simpler +.I join +with no white space processing; the characters in the lines are simply +concatenated. +.LC +( \fB.\fR ) \fBk\fR \fIx\fR +.ZP +The +.I k +command is a synonym for +.I mark. +It does not require a blank or tab before the following letter. +.LC +( \fB.\fR , \fB.\fR ) \fBlist\fR \fIcount\fR \fIflags\fR +.ZP +Prints the specified lines in a more unambiguous way: +tabs are printed as `^I' +and the end of each line is marked with a trailing `$'. +The current line is left at the last line printed. +.LC +\fBmap\fR \fIlhs\fR \fIrhs\fR +.ZP +The +.I map +command is used to define macros for use in +.I visual +mode. +.I Lhs +should be a single character, or the sequence ``#n'', for n a digit, +referring to function key \fIn\fR. When this character or function key +is typed in +.I visual +mode, it will be as though the corresponding \fIrhs\fR had been typed. +On terminals without function keys, you can type ``#n''. +See section 6.9 of the ``Introduction to Display Editing with Vi'' +for more details. +.LC +( \fB.\fR ) \fBmark\fR \fIx\fR +.ZP +Gives the specified line mark +.I x, +a single lower case letter. +The +.I x +must be preceded by a blank or a tab. +The addressing form `\'x' then addresses this line. +The current line is not affected by this command. +.LC +( \fB.\fR , \fB.\fR ) \fBmove\fR \fIaddr\fR abbr: \fBm\fR +.ZP +The +.I move +command repositions the specified lines to be after +.I addr . +The first of the moved lines becomes the current line. +.LC +\fBnext\fR abbr: \fBn\fR +.ZP +The next file from the command line argument list is edited. +.LC +\fBn!\fR +.ZP +The variant suppresses warnings about the modifications to the buffer not +having been written out, discarding (irretrievably) any changes which may +have been made. +.LC +\fBn\fR \fIfilelist\fR +.br +\fBn\fR \fB+\fIcommand\fR \fIfilelist\fR +.ZP +The specified +.I filelist +is expanded and the resulting list replaces the +current argument list; +the first file in the new list is then edited. +If +.I command +is given (it must contain no spaces), then it is executed after editing the first such file. +.LC +( \fB.\fR , \fB.\fR ) \fBnumber\fR \fIcount\fR \fIflags\fR abbr: \fB#\fR or \fBnu\fR +.ZP +Prints each specified line preceded by its buffer line +number. +The current line is left at the last line printed. +.KS +.LC +( \fB.\fR ) \fBopen\fR \fIflags\fR abbr: \fBo\fR +.br +( \fB.\fR ) \fBopen\fR /\fIpat\|\fR/ \fIflags\fR +.ZP +Enters intraline editing \fIopen\fR mode at each addressed line. +If +.I pat +is given, +then the cursor will be placed initially at the beginning of the +string matched by the pattern. +To exit this mode use Q. +See +.I "An Introduction to Display Editing with Vi" +for more details. +.KE +.LC +\fBpreserve\fR +.ZP +The current editor buffer is saved as though the system had just crashed. +This command is for use only in emergencies when a +.I write +command has resulted in an error and you don't know how to save your work. +After a +.I preserve +you should seek help. +.LC +( \fB.\fR , \fB.\fR )\|\fBprint\fR \fIcount\fR abbr: \fBp\fR or \fBP\fR +.ZP +Prints the specified lines +with non-printing characters printed as control characters `^\fIx\fR\|'; +delete (octal 177) is represented as `^?'. +The current line is left at the last line printed. +.LC +( \fB.\fR )\|\fBput\fR \fIbuffer\fR abbr: \fBpu\fR +.ZP +Puts back +previously +.I deleted +or +.I yanked +lines. +Normally used with +.I delete +to effect movement of lines, +or with +.I yank +to effect duplication of lines. +If no +.I buffer +is specified, then the last +.I deleted +or +.I yanked +text is restored.* +.FS +* But no modifying commands may intervene between the +.I delete +or +.I yank +and the +.I put, +nor may lines be moved between files without using a named buffer. +.FE +By using a named buffer, text may be restored that was saved there at any +previous time. +.LC +\fBquit\fR abbr: \fBq\fR +.ZP +Causes +.I ex +to terminate. +No automatic write of the editor buffer to a file is performed. +However, +.I ex +issues a warning message if the file has changed +since the last +.I write +command was issued, and does not +.I quit.\(dg +.FS +\(dg \fIEx\fR +will also issue a diagnostic if there are more files in the argument +list. +.FE +Normally, you will wish to save your changes, and you +should give a \fIwrite\fR command; +if you wish to discard them, use the \fBq!\fR command variant. +.LC +\fBq!\fR +.ZP +Quits from the editor, discarding changes to the buffer without complaint. +.LC +( \fB.\fR ) \fBread\fR \fIfile\fR abbr: \fBr\fR +.ZP +Places a copy of the text of the given file in the +editing buffer after the specified line. +If no +.I file +is given the current file name is used. +The current file name is not changed unless there is none in which +case +.I file +becomes the current name. +The sensibility restrictions for the +.I edit +command apply here also. +If the file buffer is empty and there is no current name then +.I ex +treats this as an +.I edit +command. +.IP +Address `0' is legal for this command and causes the file to be read at +the beginning of the buffer. +Statistics are given as for the +.I edit +command when the +.I read +successfully terminates. +After a +.I read +the current line is the last line read.\(dd +.FS +\(dd Within +.I open +and +.I visual +the current line is set to the first line read rather than the last. +.FE +.LC +( \fB.\fR ) \fBread\fR \fB!\fR\fIcommand\fR +.ZP +Reads the output of the command +.I command +into the buffer after the specified line. +This is not a variant form of the command, rather a read +specifying a +.I command +rather than a +.I filename; +a blank or tab before the \fB!\fR is mandatory. +.LC +\fBrecover \fIfile\fR +.ZP +Recovers +.I file +from the system save area. +Used after a accidental hangup of the phone** +.FS +** The system saves a copy of the file you were editing only if you +have made changes to the file. +.FE +or a system crash** or +.I preserve +command. +Except when you use +.I preserve +you will be notified by mail when a file is saved. +.LC +\fBrewind\fR abbr: \fBrew\fR +.ZP +The argument list is rewound, and the first file in the list is edited. +.LC +\fBrew!\fR +.ZP +Rewinds the argument list discarding any changes made to the current buffer. +.LC +\fBset\fR \fIparameter\fR +.ZP +With no arguments, prints those options whose values have been +changed from their defaults; +with parameter +.I all +it prints all of the option values. +.IP +Giving an option name followed by a `?' +causes the current value of that option to be printed. +The `?' is unnecessary unless the option is Boolean valued. +Boolean options are given values either by the form +`set \fIoption\fR' to turn them on or +`set no\fIoption\fR' to turn them off; +string and numeric options are assigned via the form +`set \fIoption\fR=value'. +.IP +More than one parameter may be given to +.I set \|; +they are interpreted left-to-right. +.LC +\fBshell\fR abbr: \fBsh\fR +.IP +A new shell is created. +When it terminates, editing resumes. +.LC +\fBsource\fR \fIfile\fR abbr: \fBso\fR +.IP +Reads and executes commands from the specified file. +.I Source +commands may be nested. +.LC +( \fB.\fR , \fB.\fR ) \fBsubstitute\fR /\fIpat\fR\|/\fIrepl\fR\|/ \fIoptions\fR \fIcount\fR \fIflags\fR abbr: \fBs\fR +.IP +On each specified line, the first instance of pattern +.I pat +is replaced by replacement pattern +.I repl. +If the +.I global +indicator option character `g' +appears, then all instances are substituted; +if the +.I confirm +indication character `c' appears, +then before each substitution the line to be substituted +is typed with the string to be substituted marked +with `\(ua' characters. +By typing an `y' one can cause the substitution to be performed, +any other input causes no change to take place. +After a +.I substitute +the current line is the last line substituted. +.IP +Lines may be split by substituting +new-line characters into them. +The newline in +.I repl +must be escaped by preceding it with a `\e'. +Other metacharacters available in +.I pat +and +.I repl +are described below. +.LC +.B stop +.ZP +Suspends the editor, returning control to the top level shell. +If +.I autowrite +is set and there are unsaved changes, +a write is done first unless the form +.B stop ! +is used. +This commands is only available where supported by the teletype driver +and operating system. +.LC +( \fB.\fR , \fB.\fR ) \fBsubstitute\fR \fIoptions\fR \fIcount\fR \fIflags\fR abbr: \fBs\fR +.ZP +If +.I pat +and +.I repl +are omitted, then the last substitution is repeated. +This is a synonym for the +.B & +command. +.LC +( \fB.\fR , \fB.\fR ) \fBt\fR \fIaddr\fR \fIflags\fR +.ZP +The +.I t +command is a synonym for +.I copy . +.LC +\fBta\fR \fItag\fR +.ZP +The focus of editing switches to the location of +.I tag, +switching to a different line in the current file where it is defined, +or if necessary to another file.\(dd +.FS +\(dd If you have modified the current file before giving a +.I tag +command, you must write it out; giving another +.I tag +command, specifying no +.I tag +will reuse the previous tag. +.FE +.IP +The tags file is normally created by a program such as +.I ctags, +and consists of a number of lines with three fields separated by blanks +or tabs. The first field gives the name of the tag, +the second the name of the file where the tag resides, and the third +gives an addressing form which can be used by the editor to find the tag; +this field is usually a contextual scan using `/\fIpat\fR/' to be immune +to minor changes in the file. Such scans are always performed as if +.I nomagic +was set. +.PP +The tag names in the tags file must be sorted alphabetically. +.LC +\fBunabbreviate\fR \fIword\fP abbr: \fBuna\fP +.ZP +Delete +.I word +from the list of abbreviations. +.LC +\fBundo\fR abbr: \fBu\fR +.ZP +Reverses the changes made in the buffer by the last +buffer editing command. +Note that +.I global +commands are considered a single command for the purpose of +.I undo +(as are +.I open +and +.I visual.) +Also, the commands +.I write +and +.I edit +which interact with the +file system cannot be undone. +.I Undo +is its own inverse. +.IP +.I Undo +always marks the previous value of the current line `\fB.\fR' +as `\'\''. +After an +.I undo +the current line is the first line restored +or the line before the first line deleted if no lines were restored. +For commands with more global effect +such as +.I global +and +.I visual +the current line regains it's pre-command value after an +.I undo. +.LC +\fBunmap\fR \fIlhs\fR +.ZP +The macro expansion associated by +.I map +for +.I lhs +is removed. +.LC +( 1 , $ ) \fBv\fR /\fIpat\fR\|/ \fIcmds\fR +.ZP +A synonym for the +.I global +command variant \fBg!\fR, running the specified \fIcmds\fR on each +line which does not match \fIpat\fR. +.LC +\fBversion\fR abbr: \fBve\fR +.ZP +Prints the current version number of the editor +as well as the date the editor was last changed. +.LC +( \fB.\fR ) \fBvisual\fR \fItype\fR \fIcount\fR \fIflags\fR abbr: \fBvi\fR +.ZP +Enters visual mode at the specified line. +.I Type +is optional and may be `\-' , `\(ua' or `\fB.\fR' +as in the +.I z +command to specify the placement of the specified line on the screen. +By default, if +.I type +is omitted, the specified line is placed as the first on the screen. +A +.I count +specifies an initial window size; the default is the value of the option +.I window. +See the document +.I "An Introduction to Display Editing with Vi" +for more details. +To exit this mode, type Q. +.LC +\fBvisual\fP file +.br +\fBvisual\fP +\fIn\fP file +.ZP +From visual mode, +this command is the same as edit. +.LC +( 1 , $ ) \fBwrite\fR \fIfile\fR abbr: \fBw\fR +.ZP +Writes changes made back to \fIfile\fR, printing the number of lines and +characters written. +Normally \fIfile\fR is omitted and the text goes back where it came from. +If a \fIfile\fR is specified, then text will be written to that file.* +.FS +* The editor writes to a file only if it is +the current file and is +.I edited , +if the file does not exist, +or if the file is actually a teletype, +.I /dev/tty, +.I /dev/null. +Otherwise, you must give the variant form \fBw!\fR to force the write. +.FE +If the file does not exist it is created. +The current file name is changed only if there is no current file +name; the current line is never changed. +.IP +If an error occurs while writing the current and +.I edited +file, the editor +considers that there has been ``No write since last change'' +even if the buffer had not previously been modified. +.LC +( 1 , $ ) \fBwrite>>\fR \fIfile\fR abbr: \fBw>>\fR +.ZP +Writes the buffer contents at the end of +an existing file. +.IP +.LC +\fBw!\fR \fIname\fR +.ZP +Overrides the checking of the normal \fIwrite\fR command, +and will write to any file which the system permits. +.LC +( 1 , $ ) \fBw\fR \fB!\fR\fIcommand\fR +.ZP +Writes the specified lines into +.I command. +Note the difference between \fBw!\fR which overrides checks and +\fBw\ \ !\fR which writes to a command. +.LC +\fBwq\fR \fIname\fR +.ZP +Like a \fIwrite\fR and then a \fIquit\fR command. +.LC +\fBwq!\fR \fIname\fR +.ZP +The variant overrides checking on the sensibility of the +.I write +command, as \fBw!\fR does. +.LC +\fBxit\fP \fIname\fR +.ZP +If any changes have been made and not written, writes the buffer out. +Then, in any case, quits. +.LC +( \fB.\fR , \fB.\fR )\|\fByank\fR \fIbuffer\fR \fIcount\fR abbr: \fBya\fR +.ZP +Places the specified lines in the named +.I buffer, +for later retrieval via +.I put. +If no buffer name is specified, the lines go to a more volatile place; +see the \fIput\fR command description. +.LC +( \fB.+1\fR ) \fBz\fR \fIcount\fR +.ZP +Print the next \fIcount\fR lines, default \fIwindow\fR. +.LC +( \fB.\fR ) \fBz\fR \fItype\fR \fIcount\fR +.ZP +Prints a window of text with the specified line at the top. +If \fItype\fR is `\-' the line is placed at the bottom; a `\fB.\fR' causes +the line to be placed in the center.* +A count gives the number of lines to be displayed rather than +double the number specified by the \fIscroll\fR option. +On a \s-2CRT\s0 the screen is cleared before display begins unless a +count which is less than the screen size is given. +The current line is left at the last line printed. +.FS +* Forms `z=' and `z\(ua' also exist; `z=' places the current line in the +center, surrounds it with lines of `\-' characters and leaves the current +line at this line. The form `z\(ua' prints the window before `z\-' +would. The characters `+', `\(ua' and `\-' may be repeated for cumulative +effect. +On some v2 editors, no +.I type +may be given. +.FE +.LC +\fB!\fR \fIcommand\fR\fR +.ZP +The remainder of the line after the `!' character is sent to a shell +to be executed. +Within the text of +.I command +the characters +`%' and `#' are expanded as in filenames and the character +`!' is replaced with the text of the previous command. +Thus, in particular, +`!!' repeats the last such shell escape. +If any such expansion is performed, the expanded line will be echoed. +The current line is unchanged by this command. +.IP +If there has been ``[No\ write]'' of the buffer contents since the last +change to the editing buffer, then a diagnostic will be printed +before the command is executed as a warning. +A single `!' is printed when the command completes. +.LC +( \fIaddr\fR , \fIaddr\fR ) \fB!\fR \fIcommand\fR\fR +.ZP +Takes the specified address range and supplies it as +standard input to +.I command; +the resulting output then replaces the input lines. +.LC +( $ ) \fB=\fR +.ZP +Prints the line number of the +addressed line. +The current line is unchanged. +.KS +.LC +( \fB.\fR , \fB.\fR ) \fB>\fR \fIcount\fR \fIflags\fR +.br +( \fB.\fR , \fB.\fR ) \fB<\fR \fIcount\fR \fIflags\fR +.IP +Perform intelligent shifting on the specified lines; +\fB<\fR shifts left and \fB>\fR shift right. +The quantity of shift is determined by the +.I shiftwidth +option and the repetition of the specification character. +Only white space (blanks and tabs) is shifted; +no non-white characters are discarded in a left-shift. +The current line becomes the last line which changed due to the +shifting. +.KE +.LC +\fB^D\fR +.ZP +An end-of-file from a terminal input scrolls through the file. +The +.I scroll +option specifies the size of the scroll, normally a half screen of text. +.LC +( \fB.\fR+1 , \fB.\fR+1 ) +.br +( \fB.\fR+1 , \fB.\fR+1 ) | +.ZP +An address alone causes the addressed lines to be printed. +A blank line prints the next line in the file. +.LC +( \fB.\fR , \fB.\fR ) \fB&\fR \fIoptions\fR \fIcount\fR \fIflags\fR +.ZP +Repeats the previous +.I substitute +command. +.LC +( \fB.\fR , \fB.\fR ) \fB\s+2~\s0\fR \fIoptions\fR \fIcount\fR \fIflags\fR +.ZP +Replaces the previous regular expression with the previous +replacement pattern from a substitution. +.NH 1 +Regular expressions and substitute replacement patterns +.NH 2 +Regular expressions +.PP +A regular expression specifies a set of strings of characters. +A member of this set of strings is said to be +.I matched +by the regular expression. +.I Ex +remembers two previous regular expressions: +the previous regular expression used in a +.I substitute +command +and the previous regular expression used elsewhere +(referred to as the previous \fIscanning\fR regular expression.) +The previous regular expression +can always be referred to by a null \fIre\fR, e.g. `//' or `??'. +.NH 2 +Magic and nomagic +.PP +The regular expressions allowed by +.I ex +are constructed in one of two ways depending on the setting of +the +.I magic +option. +The +.I ex +and +.I vi +default setting of +.I magic +gives quick access to a powerful set of regular expression +metacharacters. +The disadvantage of +.I magic +is that the user must remember that these metacharacters are +.I magic +and precede them with the character `\e' +to use them as ``ordinary'' characters. +With +.I nomagic, +the default for +.I edit, +regular expressions are much simpler, +there being only two metacharacters. +The power of the other metacharacters is still available by preceding +the (now) ordinary character with a `\e'. +Note that `\e' is thus always a metacharacter. +.PP +The remainder of the discussion of regular expressions assumes +that +that the setting of this option is +.I magic.\(dg +.FS +\(dg To discern what is true with +.I nomagic +it suffices to remember that the only +special characters in this case will be `\(ua' at the beginning +of a regular expression, +`$' at the end of a regular expression, +and `\e'. +With +.I nomagic +the characters `\s+2~\s0' and `&' also lose their special meanings +related to the replacement pattern of a substitute. +.FE +.NH 2 +Basic regular expression summary +.PP +The following basic constructs are used to construct +.I magic +mode regular expressions. +.IP \fIchar\fR 15 +An ordinary character matches itself. +The characters `\(ua' at the beginning of a line, +`$' at the end of line, +`*' as any character other than the first, +`.', `\e', `[', and `\s+2~\s0' are not ordinary characters and +must be escaped (preceded) by `\e' to be treated as such. +.IP \fB\(ua\fR +At the beginning of a pattern +forces the match to succeed only at the beginning of a line. +.IP \fB$\fR +At the end of a regular expression forces the match to +succeed only at the end of the line. +.IP \&\fB.\fR +Matches any single character except +the new-line character. +.IP \fB\e<\fR +Forces the match +to occur only at the beginning of a ``variable'' or ``word''; +that is, either at the beginning of a line, or just before +a letter, digit, or underline and after a character not one of +these. +.IP \fB\e>\fR +Similar to `\e<', but matching the end of a ``variable'' +or ``word'', i.e. either the end of the line or before character +which is neither a letter, nor a digit, nor the underline character. +.IP \fB[\fIstring\fR]\fR +Matches any (single) character in the class defined by +.I string. +Most characters in +.I string +define themselves. +A pair of characters separated by `\-' in +.I string +defines the set of characters collating between the specified lower and upper +bounds, thus `[a\-z]' as a regular expression matches +any (single) lower-case letter. +If the first character of +.I string +is an `\(ua' then the construct +matches those characters which it otherwise would not; +thus `[\(uaa\-z]' matches anything but a lower-case letter (and of course a +newline). +To place any of the characters +`\(ua', `[', or `\-' in +.I string +you must escape them with a preceding `\e'. +.NH 2 +Combining regular expression primitives +.PP +The concatenation of two regular expressions matches the leftmost and +then longest string +which can be divided with the first piece matching the first regular +expression and the second piece matching the second. +Any of the (single character matching) regular expressions mentioned +above may be followed by the character `*' to form a regular expression +which matches any number of adjacent occurrences (including 0) of characters +matched by the regular expression it follows. +.PP +The character `\s+2~\s0' may be used in a regular expression, +and matches the text which defined the replacement part +of the last +.I substitute +command. +A regular expression may be enclosed between the sequences +`\e(' and `\e)' with side effects in the +.I substitute +replacement patterns. +.NH 2 +Substitute replacement patterns +.PP +The basic metacharacters for the replacement pattern are +`&' and `~'; these are +given as `\e&' and `\e~' when +.I nomagic +is set. +Each instance of `&' is replaced by the characters +which the regular expression matched. +The metacharacter `~' stands, in the replacement pattern, +for the defining text of the previous replacement pattern. +.PP +Other metasequences possible in the replacement pattern +are always introduced by the escaping character `\e'. +The sequence `\e\fIn\fR' is replaced by the text matched +by the \fIn\fR-th regular subexpression enclosed between +`\e(' and `\e)'.\(dg +.FS +\(dg When nested, parenthesized subexpressions are present, +\fIn\fR is determined by counting occurrences of `\e(' starting from the left. +.FE +The sequences `\eu' and `\el' cause the immediately following character in +the replacement to be converted to upper- or lower-case respectively +if this character is a letter. +The sequences `\eU' and `\eL' turn such conversion on, either until +`\eE' or `\ee' is encountered, or until the end of the replacement pattern. +.de LC +.br +.sp .1i +.ne 4 +.LP +.ta 3i +.. +.NH 1 +Option descriptions +.PP +.LC +\fBautoindent\fR, \fBai\fR default: noai +.ZP +Can be used to ease the preparation of structured program text. +At the beginning of each +.I append , +.I change +or +.I insert +command +or when a new line is +.I opened +or created by an +.I append , +.I change , +.I insert , +or +.I substitute +operation within +.I open +or +.I visual +mode, +.I ex +looks at the line being appended after, +the first line changed +or the line inserted before and calculates the amount of white space +at the start of the line. +It then aligns the cursor at the level of indentation so determined. +.IP +If the user then types lines of text in, +they will continue to be justified at the displayed indenting level. +If more white space is typed at the beginning of a line, +the following line will start aligned with the first non-white character +of the previous line. +To back the cursor up to the preceding tab stop one can hit +\fB^D\fR. +The tab stops going backwards are defined at multiples of the +.I shiftwidth +option. +You +.I cannot +backspace over the indent, +except by sending an end-of-file with a \fB^D\fR. +.IP +Specially processed in this mode is a line with no characters added +to it, which turns into a completely blank line (the white +space provided for the +.I autoindent +is discarded.) +Also specially processed in this mode are lines beginning with +an `\(ua' and immediately followed by a \fB^D\fR. +This causes the input to be repositioned at the beginning of the line, +but retaining the previous indent for the next line. +Similarly, a `0' followed by a \fB^D\fR +repositions at the beginning but without +retaining the previous indent. +.IP +.I Autoindent +doesn't happen in +.I global +commands or when the input is not a terminal. +.LC +\fBautoprint\fR, \fBap\fR default: ap +.ZP +Causes the current line to be printed after each +.I delete , +.I copy , +.I join , +.I move , +.I substitute , +.I t , +.I undo +or +shift command. +This has the same effect as supplying a trailing `p' +to each such command. +.I Autoprint +is suppressed in globals, +and only applies to the last of many commands on a line. +.LC +\fBautowrite\fR, \fBaw\fR default: noaw +.ZP +Causes the contents of the buffer to be written to the current file +if you have modified it and give a +.I next, +.I rewind, +.I stop, +.I tag, +or +.I ! +command, or a \fB^\(ua\fR (switch files) or \fB^]\fR (tag goto) command +in +.I visual. +Note, that the +.I edit +and +.I ex +commands do +.B not +autowrite. +In each case, there is an equivalent way of switching when autowrite +is set to avoid the +.I autowrite +(\fIedit\fR +for +.I next , +.I rewind! +for .I rewind , +.I stop! +for +.I stop , +.I tag! +for +.I tag , +.I shell +for +.I ! , +and +\fB:e\ #\fR and a \fB:ta!\fR command from within +.I visual). +.LC +\fBbeautify\fR, \fBbf\fR default: nobeautify +.ZP +Causes all control characters except tab, newline and form-feed +to be discarded from the input. +A complaint is registered the first time a +backspace character is discarded. +.I Beautify +does not apply to command input. +.LC +\fBdirectory\fR, \fBdir\fR default: dir=/tmp +.ZP +Specifies the directory in which +.I ex +places its buffer file. +If this directory in not +writable, then the editor will exit abruptly when it fails to be +able to create its buffer there. +.LC +\fBedcompatible\fR default: noedcompatible +.ZP +Causes the presence of absence of +.B g +and +.B c +suffixes on substitute commands to be remembered, and to be toggled +by repeating the suffices. The suffix +.B r +makes the substitution be as in the +.I ~ +command, instead of like +.I &. +.LC +\fBerrorbells\fR, \fBeb\fR default: noeb +.ZP +Error messages are preceded by a bell.* +.FS +* Bell ringing in +.I open +and +.I visual +on errors is not suppressed by setting +.I noeb. +.FE +If possible the editor always places the error message in a standout mode of the +terminal (such as inverse video) instead of ringing the bell. +.LC +\fBhardtabs\fR, \fBht\fR default: ht=8 +.ZP +Gives the boundaries on which terminal hardware tabs are set (or +on which the system expands tabs). +.LC +\fBignorecase\fR, \fBic\fR default: noic +.ZP +All upper case characters in the text are mapped to lower case in regular +expression matching. +In addition, all upper case characters in regular expressions are mapped +to lower case except in character class specifications. +.LC +\fBlisp\fR default: nolisp +.ZP +\fIAutoindent\fR indents appropriately for +.I lisp +code, and the \fB( ) { } [[\fR and \fB]]\fR commands in +.I open +and +.I visual +are modified to have meaning for \fIlisp\fR. +.LC +\fBlist\fR default: nolist +.ZP +All printed lines will be displayed (more) unambiguously, +showing tabs and end-of-lines as in the +.I list +command. +.LC +\fBmagic\fR default: magic for \fIex\fR and \fIvi\fR\(dg +.FS +\(dg \fINomagic\fR for \fIedit\fR. +.FE +.ZP +If +.I nomagic +is set, the number of regular expression metacharacters is greatly reduced, +with only `\(ua' and `$' having special effects. +In addition the metacharacters +`~' +and +`&' +of the replacement pattern are treated as normal characters. +All the normal metacharacters may be made +.I magic +when +.I nomagic +is set by preceding them with a `\e'. +.LC +\fBmesg\fR default: mesg +.ZP +Causes write permission to be turned off to the terminal +while you are in visual mode, if +.I nomesg +is set. +.LC +\fBmodeline\fR default: nomodeline +.ZP +If +.I modeline +is set, then the first 5 lines and the last five lines of the file +will be checked for ex command lines and the comands issued. +To be recognized as a command line, the line must have the string +.B ex: +or +.B vi: +preceeded by a tab or a space. This string may be anywhere in the +line and anything after the +.I : +is interpeted as editor commands. This option defaults to off because +of unexpected behavior when editting files such as +.I /etc/passwd. +.LC +\fBnumber, nu\fR default: nonumber +.ZP +Causes all output lines to be printed with their +line numbers. +In addition each input line will be prompted for by supplying the line number +it will have. +.LC +\fBopen\fR default: open +.ZP +If \fInoopen\fR, the commands +.I open +and +.I visual +are not permitted. +This is set for +.I edit +to prevent confusion resulting from accidental entry to +open or visual mode. +.LC +\fBoptimize, opt\fR default: optimize +.ZP +Throughput of text is expedited by setting the terminal +to not do automatic carriage returns +when printing more than one (logical) line of output, +greatly speeding output on terminals without addressable +cursors when text with leading white space is printed. +.LC +\fBparagraphs,\ para\fR default: para=IPLPPPQPP\0LIbp +.ZP +Specifies the paragraphs for the \fB{\fR and \fB}\fR operations in +.I open +and +.I visual. +The pairs of characters in the option's value are the names +of the macros which start paragraphs. +.LC +\fBprompt\fR default: prompt +.ZP +Command mode input is prompted for with a `:'. +.LC +\fBredraw\fR default: noredraw +.ZP +The editor simulates (using great amounts of output), an intelligent +terminal on a dumb terminal (e.g. during insertions in +.I visual +the characters to the right of the cursor position are refreshed +as each input character is typed.) +Useful only at very high speed. +.LC +\fBremap\fP default: remap +.ZP +If on, macros are repeatedly tried until they are unchanged. +For example, if +.B o +is mapped to +.B O , +and +.B O +is mapped to +.B I , +then if +.I remap +is set, +.B o +will map to +.B I , +but if +.I noremap +is set, it will map to +.B O . +.LC +\fBreport\fR default: report=5\(dg +.FS +\(dg 2 for \fIedit\fR. +.FE +.ZP +Specifies a threshold for feedback from commands. +Any command which modifies more than the specified number of lines +will provide feedback as to the scope of its changes. +For commands such as +.I global , +.I open , +.I undo , +and +.I visual +which have potentially more far reaching scope, +the net change in the number of lines in the buffer is +presented at the end of the command, subject to this same threshold. +Thus notification is suppressed during a +.I global +command on the individual commands performed. +.LC +\fBscroll\fR default: scroll=\(12 window +.ZP +Determines the number of logical lines scrolled when an end-of-file +is received from a terminal input in command mode, +and the number of lines printed by a command mode +.I z +command (double the value of +.I scroll ). +.LC +\fBsections\fR default: sections=SHNHH\0HU +.ZP +Specifies the section macros for the \fB[[\fR and \fB]]\fR operations +in +.I open +and +.I visual. +The pairs of characters in the options's value are the names +of the macros which start paragraphs. +.LC +\fBshell\fR, \fBsh\fR default: sh=/bin/sh +.ZP +Gives the path name of the shell forked for +the shell escape command `!', and by the +.I shell +command. +The default is taken from SHELL in the environment, if present. +.LC +\fBshiftwidth\fR, \fBsw\fR default: sw=8 +.ZP +Gives the width a software tab stop, +used in reverse tabbing with \fB^D\fR when using +.I autoindent +to append text, +and by the shift commands. +.LC +\fBshowmatch, sm\fR default: nosm +.ZP +In +.I open +and +.I visual +mode, when a \fB)\fR or \fB}\fR is typed, move the cursor to the matching +\fB(\fR or \fB{\fR for one second if this matching character is on the +screen. Extremely useful with +.I lisp. +.LC +\fBslowopen, slow\fR terminal dependent +.ZP +Affects the display algorithm used in +.I visual +mode, holding off display updating during input of new text to improve +throughput when the terminal in use is both slow and unintelligent. +See +.I "An Introduction to Display Editing with Vi" +for more details. +.LC +\fBtabstop,\ ts\fR default: ts=8 +.ZP +The editor expands tabs in the input file to be on +.I tabstop +boundaries for the purposes of display. +.LC +\fBtaglength,\ tl\fR default: tl=0 +.ZP +Tags are not significant beyond this many characters. +A value of zero (the default) means that all characters are significant. +.LC +\fBtags\fR default: tags=tags /usr/lib/tags +.ZP +A path of files to be used as tag files for the +.I tag +command. +A requested tag is searched for in the specified files, sequentially. +By default, files called +.B tags +are searched for in the current directory and in /usr/lib +(a master file for the entire system). +.LC +\fBterm\fR from environment TERM +.ZP +The terminal type of the output device. +.LC +\fBterse\fR default: noterse +.ZP +Shorter error diagnostics are produced for the experienced user. +.LC +\fBwarn\fR default: warn +.ZP +Warn if there has been `[No write since last change]' before a `!' +command escape. +.LC +\fBwindow\fR default: window=speed dependent +.ZP +The number of lines in a text window in the +.I visual +command. +The default is 8 at slow speeds (600 baud or less), +16 at medium speed (1200 baud), +and the full screen (minus one line) at higher speeds. +.LC +\fBw300,\ w1200\, w9600\fR +.ZP +These are not true options but set +.B window +only if the speed is slow (300), medium (1200), or high (9600), +respectively. +They are suitable for an EXINIT +and make it easy to change the 8/16/full screen rule. +.LC +\fBwrapscan\fR, \fBws\fR default: ws +.ZP +Searches using the regular expressions in addressing +will wrap around past the end of the file. +.LC +\fBwrapmargin\fR, \fBwm\fR default: wm=0 +.ZP +Defines a margin for automatic wrapover of text during input in +.I open +and +.I visual +modes. See +.I "An Introduction to Text Editing with Vi" +for details. +.LC +\fBwriteany\fR, \fBwa\fR default: nowa +.IP +Inhibit the checks normally made before +.I write +commands, allowing a write to any file which the system protection +mechanism will allow. +.NH 1 +Limitations +.PP +Editor limits that the user is likely to encounter are as follows: +1024 characters per line, +256 characters per global command list, +128 characters per file name, +128 characters in the previous inserted and deleted text in +.I open +or +.I visual, +100 characters in a shell escape command, +63 characters in a string valued option, +and 30 characters in a tag name, and +a limit of 250000 lines in the file is silently enforced. +.PP +The +.I visual +implementation limits the number of macros defined with map to +32, and the total number of characters in macros to be less than 512. +.LP +.LP +.I Acknowledgments. +Chuck Haley contributed greatly to the early development of +.I ex. +Bruce Englar encouraged the redesign which led to +.I ex +version 1. +Bill Joy wrote versions 1 and 2.0 through 2.7, +and created the framework that users see in the present editor. +Mark Horton added macros and other features and made the +editor work on a large number of terminals and Unix systems. diff --git a/usr.bin/vi/USD.doc/exref/ex.summary b/usr.bin/vi/USD.doc/exref/ex.summary new file mode 100644 index 0000000..618da07 --- /dev/null +++ b/usr.bin/vi/USD.doc/exref/ex.summary @@ -0,0 +1,734 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ex.summary 8.1 (Berkeley) 6/8/93 +.\" +.ds p \v'-0.2'.\v'+0.2' +.ds U \s-2UNIX\s+2 +.ds c \v'-0.2':\v'+0.2' +.nr PO .25i +.nr LL 6.75i +.lt 6.75i +.ll 6.75i +.ds CH +.ds LF Computing Services, U.C. Berkeley +.ds RF April 3, 1979 +.de SP +.sp 1v +.. +.nr PI 3n +.nr PD 0 +.ND +.ps 12 +.ft B +.ce 1 +Ex/Edit Command Summary (Version 2.0) +.ft R +.nr VS 11 +.nr PS 9 +.nr HM 0.5i +.nr CW +.2C +.PP +.I Ex +and +.I edit +are text editors, used for creating +and modifying files of text on the \*U +computer system. +.I Edit +is a variant of +.I ex +with features designed to +make it less complicated +to learn and use. +In terms of command syntax and effect +the editors are essentially identical, +and this command summary applies to both. +.PP +The summary is meant as a quick reference +for users already acquainted +with +.I edit +or \fIex\fP. +Fuller explanations of the editors are available +in the documents +.I +Edit: A Tutorial +.R +(a self-teaching introduction) and the +.I +Ex Reference Manual +.R +(the comprehensive reference source for +both \fIedit\fP and \fIex\fP). +Both of these writeups are available in the +Computing Services Library. +.PP +In the examples included with the +summary, commands and text entered by +the user are printed in \fBboldface\fR to +distinguish them from responses printed +by the computer. +.sp 0.45v +.LP +.B +The Editor Buffer +.PP +In order to perform its tasks +the editor sets aside a temporary +work space, +called a \fIbuffer\fR, +separate from the user's permanent +file. +Before starting to work on an existing +file the editor makes a copy of it in the +buffer, leaving the original untouched. +All editing changes are made to the +buffer copy, which must then +be written back to the permanent +file in order to update the +old version. +The buffer disappears +at the end of the editing session. +.sp 0.45v +.LP +.B +Editing: Command and Text Input Modes +.PP +.R +During an editing session there are +two usual modes of operation: +\fIcommand\fP mode and \fItext input\fP +mode. +(This disregards, for the moment, +.I open +and +.I visual +modes, discussed below.) +In command mode, the editor issues a +colon prompt (:) +to show that it is ready to +accept and execute a command. +In text input mode, on the other hand, there is +no prompt and the editor merely accepts text to +be added to the buffer. +Text input mode is initiated by the commands +\fIappend\fP, \fIinsert\fP, and \fIchange\fP, +and is terminated by typing a period as the +first and only character on a line. +.sp 0.45v +.LP +.B +Line Numbers and Command Syntax +.PP +.R +The editor keeps track of lines of text +in the buffer by numbering them consecutively +starting with 1 and renumbering +as lines are added or deleted. +At any given time the editor is positioned +at one of these lines; this position is +called the \fIcurrent line\fP. +Generally, commands that change the +contents of the buffer print the +new current line at the end of their +execution. +.PP +Most commands can be preceded by one or two +line-number addresses which indicate the lines +to be affected. +If one number is given the command operates on +that line only; if two, on an inclusive range +of lines. +Commands that can take line-number prefixes also +assume default prefixes if none are given. +The default assumed by each command is designed +to make it convenient to use in many instances +without any line-number prefix. +For the most part, a command used without a +prefix operates on the current line, +though exceptions to this rule should be noted. +The \fIprint\fP command +by itself, for instance, causes +one line, the current line, to be +printed at the terminal. +.PP +The summary shows the number of line addresses +that can be +prefixed to each command as well as +the defaults assumed if they are omitted. +For example, +.I (.,.) +means that up to 2 line-numbers may be given, +and that if none is given the +command operates on the current line. +(In the address prefix notation, ``.'' stands +for the current line and ``$'' stands for +the last line of the buffer.) +If no such notation appears, no +line-number prefix may be used. +.PP +Some commands take trailing +information; +only +the more important instances of this +are mentioned in the summary. +.sp 0.25v +.LP +.B +Open and Visual Modes +.PP +.R +Besides command and text input modes, +.I ex +and +.I edit +provide on some CRT terminals other modes of editing, +.I open +and +.I visual . +In these modes the cursor can +be moved to individual words +or characters in a line. +The commands then given are very different +from the standard editor commands; most do not appear on the screen when +typed. +.I +An Introduction to Display Editing with Vi +.R +provides a full discussion. +.sp 0.25v +.LP +.B +Special Characters +.PP +.R +.fi +Some characters take on special meanings +when used in context searches +and in patterns given to the \fIsubstitute\fP command. +For \fIedit\fR, these are ``^'' and ``$'', +meaning the beginning and end of a line, +respectively. +.I Ex +has the following additional special characters: +.B +.ce 1 +\&. & * [ ] ~ +.R +To use one of the special characters as its +simple graphic representation +rather than with its special meaning, +precede it by a backslash (\\). +The backslash always has a special meaning. +.1C +.rm LF +.rm RF +.rm CF +.nr FM 0.4 +.TS +cp10 cp10 cp10 cp10 +ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i). +Name Abbr Description Examples +.sp 1.75 +(.)\fBappend a T{ +Begins text input mode, +adding lines to the buffer after +the line specified. Appending continues +until ``.'' is typed alone at the +beginning of a new line, followed by +a carriage return. \fI0a\fR places +lines at the beginning of the buffer. +T} T{ +.nf +\fR:\fBa +Three lines of text +are added to the buffer +after the current line. +\*p +.R +\*c +.fi +T} +.SP +\fR(.,.)\fBchange c T{ +Deletes indicated line(s) and +initiates text input mode to +replace them with new text which follows. +New text is terminated the same way +as with \fIappend\fR. +T} T{ +.nf +:\fB5,6c +Lines 5 and 6 are +deleted and replaced by +these three lines. +\*p +.R +\*c +.fi +T} +.SP +\fR(.,.)\fBcopy \fIaddr co T{ +Places a copy of the specified lines +after the line indicated by \fIaddr\fR. +The example places a copy of lines 8 through +12, inclusive, after line 25. +T} T{ +.nf +\fR:\fB8,12co 25 +\fRLast line copied is printed +\fR\*c +.fi +T} +.SP +\fR(.,.)\fBdelete d T{ +Removes lines from the buffer +and prints the current line after the deletion. +T} T{ +.nf +\fR:\fB13,15d +\fRNew current line is printed +\*c +.fi +T} +.TE +.sp 0.5v +.TS +ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i). +T{ +\fBedit \fIfile\fP +.br +\fBedit! \fIfile\fP +T} T{ +e +.br +e! +T} T{ +.fi +\fRClears the editor buffer and then +copies into it the named \fIfile\fR, +which becomes the current file. +This is a way of shifting to a different +file +without leaving the editor. +The editor issues a warning +message if this command is used before +saving changes +made to the file already in the buffer; +using the form \fBe!\fR overrides this protective mechanism. +T} T{ +.nf +\fR:\fBe ch10\fR +No write since last change +:\fBe! ch10\fR +"ch10" 3 lines, 62 characters +\*c +.fi +T} +.SP +\fBfile \fIname\fR f T{ +\fRIf followed by a \fIname\fR, renames +the current file to \fIname\fR. +If used without \fIname\fR, prints +the name of the current file. +T} T{ +.nf +\fR:\fBf ch9 +\fR"ch9" [Modified] 3 lines ... +:\fBf +\fR"ch9" [Modified] 3 lines ... +\*c +.fi +T} +.SP +(1,$)\fBglobal g \fBglobal/\fIpattern\fB/\fIcommands T{ +.nf +:\fBg/nonsense/d +\fR\*c +.fi +T} +\fR(1,$)\fBglobal! g!\fR or \fBv T{ +Searches the entire buffer (unless a smaller +range is specified by line-number prefixes) and +executes \fIcommands\fR on every line with +an expression matching \fIpattern\fR. +The second form, abbreviated +either \fBg!\fR or \fBv\fR, +executes \fIcommands\fR on lines that \fIdo +not\fR contain the expression \fIpattern\fR. +T} \^ +.SP +\fR(.)\fBinsert i T{ +Inserts new lines of text immediately before the specified line. +Differs from +.I append +only in that text is placed before, rather than after, the indicated line. +In other words, \fB1i\fR has the same effect as \fB0a\fR. +T} T{ +.nf +:\fB1i +These lines of text will +be added prior to line 1. +\&. +\fR: +.fi +T} \^ +.SP +\fR(.,.+1)\fBjoin j T{ +Join lines together, adjusting white space (spaces +and tabs) as necessary. +T} T{ +.nf +:\fB2,5j\fR +Resulting line is printed +: +.fi +T} \^ +.TE +.bp +.TS +cp10 cp10 cp10 cp10 +ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i). +Name Abbr Description Examples +.sp 1.75 +\fR(.,.)\fBlist l T{ +\fRPrints lines in a more +unambiguous way than the \fIprint\fR +command does. The end of a line, +for example, is marked with a ``$'', +and tabs printed as ``^I''. +T} T{ +.nf +:\fB9l +\fRThis is line 9$ +\*c +.fi +T} +.TE +.sp 0.5v +.TS +ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i). +\fR(.,.)\fBmove \fIaddr\fB m T{ +\fRMoves the specified lines +to a position after the line +indicated by \fIaddr\fR. +T} T{ +.nf +\fR:\fB12,15m 25\fR +New current line is printed +\*c +.fi +T} +.SP +\fR(.,.)\fBnumber nu T{ +Prints each line preceded +by its buffer line number. +T} T{ +.nf +\fR:\fBnu +\0\0\fR10\0 This is line 10 +\*c +.fi +T} +.SP +\fR(.)\fBopen o T{ +Too involved to discuss here, +but if you enter open mode +accidentally, press +the \s-2ESC\s0 key followed by +\fBq\fR to +get back into normal editor +command mode. +\fIEdit\fP is designed to +prevent accidental use of +the open command. +T} +.SP +\fBpreserve pre T{ +Saves a copy of the current buffer contents as though the system had +just crashed. This is for use in an emergency when a +.I write +command has failed and you don't know how else to save your work.\(dg +T} T{ +.nf +:\fBpreserve\fR +File preserved. +: +.fi +T} +.SP +\fR(.,.)\fBprint p Prints the text of line(s). T{ +.nf +:\fB+2,+3p\fR +The second and third lines +after the current line +: +.fi +T} +.TE +.FS +\(dg Seek assistance from a consultant as soon as possible +after saving a file with the +.I preserve +command, because the file is saved on system storage space for only one week. +.FE +.SP +.nf +.TS +ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i). +T{ +.nf +\fBquit +quit! +.fi +T} T{ +.nf +q +q! +T} T{ +.fi +\fREnds the editing session. +You will receive a +warning if you have changed the buffer +since last writing its contents +to the file. In this event you +must either type \fBw\fR to write, +or type \fBq!\fR to exit from +the editor without saving your changes. +T} T{ +.nf +\fR:\fBq +\fRNo write since last change +:\fBq! +\fR% +.fi +T} +.SP +\fR(.)\fBread \fIfile\fP r T{ +.fi +\fRPlaces a copy of \fIfile\fR in the +buffer after the specified line. +Address 0 is permissible and causes +the copy of \fIfile\fR to be placed +at the beginning of the buffer. +The \fIread\fP command does not +erase any text already in the buffer. +If no line number is specified, +\fIfile\fR is placed after the +current line. +T} T{ +.nf +\fR:\fB0r newfile +\fR"newfile" 5 lines, 86 characters +\*c +.fi +T} +.SP +\fBrecover \fIfile\fP rec T{ +.fi +Retrieves a copy of the editor buffer +after a system crash, editor crash, +phone line disconnection, or +\fIpreserve\fR command. +T} +.SP +\fR(.,.)\fBsubstitute s T{ +.nf +\fBsubstitute/\fIpattern\fB/\fIreplacement\fB/ +substitute/\fIpattern\fB/\fIreplacement\fB/gc +.fi +\fRReplaces the first occurrence of \fIpattern\fR +on a line +with \fIreplacement\fP. +Including a \fBg\fR after the command +changes all occurrences of \fIpattern\fP +on the line. +The \fBc\fR option allows the user to +confirm each substitution before it is +made; see the manual for details. +T} T{ +.nf +:\fB3p +\fRLine 3 contains a misstake +:\fBs/misstake/mistake/ +\fRLine 3 contains a mistake +\*c +.fi +T} +.TE +.bp +.TS +cp10 cp10 cp10 cp10 +ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i). +Name Abbr Description Examples +.sp 1.75 +\fBundo u T{ +.fi +\fRReverses the changes made in +the buffer by the last buffer-editing +command. +Note that this example contains +a notification about the number of +lines affected. +T} T{ +.nf +\fR:\fB1,15d +\fR15 lines deleted +new line number 1 is printed +:\fBu +\fR15 more lines in file ... +old line number 1 is printed +\*c +.fi +T} +.SP +\fR(1,$)\fBwrite \fIfile\fR w T{ +.fi +\fRCopies data from the buffer onto +a permanent file. If no \fIfile\fR +is named, the current filename +is used. +The file is automatically created +if it does not yet exist. +A response containing the number of +lines and characters in the file +indicates that the write +has been completed successfully. +The editor's built-in protections +against overwriting existing files +will in some circumstances +inhibit a write. +The form \fBw!\fR forces the +write, confirming that +an existing file is to be overwritten. +T} T{ +.nf +\fR:\fBw +\fR"file7" 64 lines, 1122 characters +:\fBw file8 +\fR"file8" File exists ... +:\fBw! file8 +\fR"file8" 64 lines, 1122 characters +\*c +.fi +T} +\fR(1,$)\fBwrite! \fIfile\fP w! \^ \^ +.TE +.sp 0.5v +.TS +ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i). +\fR(.)\fBz \fIcount\fP z T{ +.fi +\fRPrints a screen full of text starting +with the line indicated; +or, if \fIcount\fR is specified, +prints that number of lines. +Variants of the \fIz\fR command +are described in the manual. +T} +.SP +\fB!\fIcommand T{ +.fi +Executes the remainder of the line +after \fB!\fR as a \*U command. +The buffer is unchanged by this, and +control is returned to the editor when +the execution of \fIcommand\fR is complete. +T} T{ +.nf +\fR:\fB!date +\fRFri Jun 9 12:15:11 PDT 1978 +! +\*c +.fi +T} +.SP +\fRcontrol-d T{ +.fi +Prints the next \fIscroll\fR of text, +normally half of a screen. See the +manual for details of the \fIscroll\fR +option. +T} +.SP +\fR(.+1)<cr> T{ +.fi +An address alone followed by a carriage +return causes the line to be printed. +A carriage return by itself prints the +line following the current line. +T} T{ +.nf +:\fR<cr> +the line after the current line +\*c +.fi +T} +.TE +.sp 0.5v +.TS +ltw(1.0i) lt2w(0.40i)fB ltw(3.0i) ltw(1.8i). +\fB/\fIpattern\fB/ T{ +.fi +\fRSearches for the next line in which +\fIpattern\fR occurs and prints it. +T} T{ +.nf +\fR:\fB/This pattern/ +\fRThis pattern next occurs here. +\*c +.fi +T} +.SP +\fB// T{ +Repeats the most recent search. +T} T{ +.nf +\fR:\fB// +\fRThis pattern also occurs here. +\*c +.fi +T} +.SP +\fB?\fIpattern\fB? T{ +Searches in the reverse direction +for \fIpattern\fP. +T} +.SP +\fB?? T{ +Repeats the most recent search, +moving in the reverse direction +through the buffer. +T} +.TE + diff --git a/usr.bin/vi/USD.doc/vi.man/Makefile b/usr.bin/vi/USD.doc/vi.man/Makefile new file mode 100644 index 0000000..fd89b8e --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.man/Makefile @@ -0,0 +1,14 @@ +# @(#)Makefile 8.5 (Berkeley) 7/16/94 + +SRCS= vi.1 +DOCS= vi.0 vi.0.ps + +all: ${DOCS} + +vi.0: vi.1 + groff -man -Tascii < vi.1 > $@ +vi.0.ps: vi.1 + groff -man < vi.1 > $@ + +clean: + rm -f ${DOCS} diff --git a/usr.bin/vi/USD.doc/vi.man/vi.0 b/usr.bin/vi/USD.doc/vi.man/vi.0 new file mode 100644 index 0000000..e6d9972 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.man/vi.0 @@ -0,0 +1,798 @@ +EX/VI(1) BSD Reference Manual EX/VI(1) + +NNAAMMEE + eexx,, vvii,, vviieeww - text editors + +SSYYNNOOPPSSIISS + eexx [--eeFFRRrrssvv] [--cc _c_m_d] [--tt _t_a_g] [--ww _s_i_z_e] [_f_i_l_e _._._.] + vvii [--eeFFRRrrvv] [--cc _c_m_d] [--tt _t_a_g] [--ww _s_i_z_e] [_f_i_l_e _._._.] + vviieeww [--eeFFRRrrvv] [--cc _c_m_d] [--tt _t_a_g] [--ww _s_i_z_e] [_f_i_l_e _._._.] + +DDEESSCCRRIIPPTTIIOONN + VVii is a screen oriented text editor. EExx is a line-oriented text editor. + EExx and vvii are different interfaces to the same program, and it is possi- + ble to switch back and forth during an edit session. VViieeww is the equiva- + lent of using the --RR (read-only) option of vvii. + + This manual page is the one provided with the nneexx//nnvvii versions of the + eexx//vvii text editors. NNeexx//nnvvii are intended as bug-for-bug compatible re- + placements for the original Fourth Berkeley Software Distribution (4BSD) + eexx and vvii programs. For the rest of this manual page, nneexx//nnvvii is used + only when it's necessary to distinguish it from the historic implementa- + tions of eexx//vvii. + + This manual page is intended for users already familiar with eexx//vvii. Any- + one else should almost certainly read a good tutorial on the editor be- + fore this manual page. If you're in an unfamiliar environment, and you + absolutely have to get work done immediately, read the section after the + options description, entitled ``Fast Startup''. It's probably enough to + get you going. + + The following options are available: + + --cc Execute _c_m_d immediately after starting the edit session. Partic- + ularly useful for initial positioning in the file, however _c_m_d is + not limited to positioning commands. This is the POSIX 1003.2 + interface for the historic ``+cmd'' syntax. NNeexx//nnvvii supports + both the old and new syntax. + + --ee Start editing in ex mode, as if the command name were eexx. + + --FF Don't copy the entire file when first starting to edit. (The de- + fault is to make a copy in case someone else modifies the file + during your edit session.) + + --RR Start editing in read-only mode, as if the command name was vviieeww, + or the readonly option was set. + + --rr Recover the specified files, or, if no files are specified, list + the files that could be recovered. If no recoverable files by + the specified name exist, the file is edited as if the --rr option + had not been specified. + + --ss Enter batch mode; applicable only to eexx edit sessions. Batch + mode is useful when running eexx scripts. Prompts, informative + messages and other user oriented message are turned off, and no + startup files or environmental variables are read. This is the + POSIX 1003.2 interface for the historic ``-'' argument. NNeexx//nnvvii + supports both the old and new syntax. + + --tt Start editing at the specified tag. (See ctags(1)). + + --ww Set the initial window size to the specified number of lines. + + + + --vv Start editing in vi mode, as if the command name was vvii or vviieeww. + + --XX Reserved for X11 interfaces. _N_o _X_1_1 _s_u_p_p_o_r_t _i_s _c_u_r_r_e_n_t_l_y + _i_m_p_l_e_m_e_n_t_e_d_. + + Command input for eexx//vvii is read from the standard input. In the vvii in- + terface, it is an error if standard input is not a terminal. In the eexx + interface, if standard input is not a terminal, eexx will read commands + from it regardless, however, the session will be a batch mode session, + exactly as if the --ss option had been specified. + + EExx//vvii exits 0 on success, and greater than 0 if an error occurs. + +FFAASSTT SSTTAARRTTUUPP + This section will tell you the minimum amount that you need to do simple + editing tasks using vvii. If you've never used any screen editor before, + you're likely to have problems even with this simple introduction. In + that case you should find someone that already knows vvii and have them + walk you through this section. + + VVii is a screen editor. This means that it takes up almost the entire + screen, displaying part of the file on each screen line, except for the + last line of the screen. The last line of the screen is used for you to + give commands to vvii, and for vvii to give information to you. + + The other fact that you need to understand is that vvii is a modeful edi- + tor, i.e. you are either entering text or you are executing commands, and + you have to be in the right mode to do one or the other. You will be in + command mode when you first start editing a file. There are commands + that switch you into input mode. There is only one key that takes you + out of input mode, and that is the <escape> key. (Key names are written + using less-than and greater-than signs, e.g. <escape> means the + ``escape'' key, usually labeled ``esc'' on your terminal's keyboard.) If + you're ever confused as to which mode you're in, keep entering the <es- + cape> key until vvii beeps at you. (Generally, vvii will beep at you if you + try and do something that's not allowed. It will also display error mes- + sages.) + + To start editing a file, enter the command ``vi file_name<carriage- + return>''. The command you should enter as soon as you start editing is + ``:set verbose showmode<carriage-return>''. This will make the editor + give you verbose error messages and display the current mode at the bot- + tom of the screen. + + The commands to move around the file are: + hh Move the cursor left one character. + jj Move the cursor down one line. + kk Move the cursor up one line. + ll Move the cursor right one character. + <<ccuurrssoorr--aarrrroowwss>> + The cursor arrow keys should work, too. + //tteexxtt<<ccaarrrriiaaggee--rreettuurrnn>> + Search for the string ``text'' in the file, and move the cursor to + its first character. + + The commands to enter new text are: + aa Append new text, _a_f_t_e_r the cursor. + ii Insert new text, _b_e_f_o_r_e the cursor. + oo Open a new line below the line the cursor is on, and start entering + text. + OO Open a new line above the line the cursor is on, and start entering + text. + <<eessccaappee>> + Once you've entered input mode using the one of the aa, ii, OO, or oo + commands, use <<eessccaappee>> to quit entering text and return to command + mode. + + The commands to copy text are: + yyyy Copy the line the cursor is on. + pp Append the copied line after the line the cursor is on. + + The commands to delete text are: + dddd Delete the line the cursor is on. + xx Delete the character the cursor is on. + + The commands to write the file are: + ::ww<<ccaarrrriiaaggee--rreettuurrnn>> + Write the file back to the file with the name that you originally + used as an argument on the vvii command line. + ::ww ffiillee__nnaammee<<ccaarrrriiaaggee--rreettuurrnn>> + Write the file back to the file with the name ``file_name''. + + The commands to quit editing and exit the editor are: + ::qq<<ccaarrrriiaaggee--rreettuurrnn>> + Quit editing and leave vi (if you've modified the file, but not + saved your changes, vvii will refuse to quit). + ::qq!!<<ccaarrrriiaaggee--rreettuurrnn>> + Quit, discarding any modifications that you may have made. + + One final caution. Unusual characters can take up more than one column + on the screen, and long lines can take up more than a single screen line. + The above commands work on ``physical'' characters and lines, i.e. they + affect the entire line no matter how many screen lines it takes up and + the entire character no matter how many screen columns it takes up. + +VVII CCOOMMMMAANNDDSS + The following section describes the commands available in the command + mode of the vvii editor. In each entry below, the tag line is a usage syn- + opsis for the command character. + + [[ccoouunntt]] <<ccoonnttrrooll--AA>> + Search forward count times for the current word. + [[ccoouunntt]] <<ccoonnttrrooll--BB>> + Page backwards count screens. + [[ccoouunntt]] <<ccoonnttrrooll--DD>> + Scroll forward count lines. + [[ccoouunntt]] <<ccoonnttrrooll--EE>> + Scroll forward count lines, leaving the current line and column as + is, if possible. + [[ccoouunntt]] <<ccoonnttrrooll--FF>> + Page forward count screens. + <<ccoonnttrrooll--GG>> + Display the file information. + <<ccoonnttrrooll--HH>> + [[ccoouunntt]] hh + Move the cursor back count characters in the current line. + [[ccoouunntt]] <<ccoonnttrrooll--JJ>> + [[ccoouunntt]] <<ccoonnttrrooll--NN>> + [[ccoouunntt]] jj + Move the cursor down count lines without changing the current col- + umn. + <<ccoonnttrrooll--LL>> + <<ccoonnttrrooll--RR>> + Repaint the screen. + [[ccoouunntt]] <<ccoonnttrrooll--MM>> + [[ccoouunntt]] ++ + Move the cursor down count lines to the first nonblank character of + that line. + [[ccoouunntt]] <<ccoonnttrrooll--PP>> + [[ccoouunntt]] kk + Move the cursor up count lines, without changing the current col- + + umn. + <<ccoonnttrrooll--TT>> + Return to the most recent tag context. + <<ccoonnttrrooll--UU>> + Scroll backwards count lines. + <<ccoonnttrrooll--WW>> + Switch to the next lower screen in the window, or, to the first + screen if there are no lower screens in the window. + <<ccoonnttrrooll--YY>> + Scroll backwards count lines, leaving the current line and column + as is, if possible. + <<ccoonnttrrooll--ZZ>> + Suspend the current editor session. + <<eessccaappee>> + Execute eexx commands or cancel partial commands. + <<ccoonnttrrooll--]]>> + Push a tag reference onto the tag stack. + <<ccoonnttrrooll--^^>> + Switch to the most recently edited file. + [[ccoouunntt]] <<ssppaaccee>> + [[ccoouunntt]] ll + Move the cursor forward count characters without changing the cur- + rent line. + [[ccoouunntt]] !! mmoottiioonn sshheellll--aarrgguummeenntt((ss)) + Replace text with results from a shell command. + [[ccoouunntt]] ## ++||--||## + Increment or decrement the cursor number. + [[ccoouunntt]] $$ + Move the cursor to the end of a line. + %% Move to the matching character. + && Repeat the previous substitution command on the current line. + ''<<cchhaarraacctteerr>> + ``<<cchhaarraacctteerr>> + Return to a context marked by the character <character>. + [[ccoouunntt]] (( + Back up count sentences. + [[ccoouunntt]] )) + Move forward count sentences. + [[ccoouunntt]] ,, + Reverse find character count times. + [[ccoouunntt]] -- + Move to first nonblank of the previous line, count times. + [[ccoouunntt]] .. + Repeat the last vvii command that modified text. + //RREE<<ccaarrrriiaaggee--rreettuurrnn>> + //RREE// [[ooffffsseett]]<<ccaarrrriiaaggee--rreettuurrnn>> + ??RREE<<ccaarrrriiaaggee--rreettuurrnn>> + ??RREE?? [[ooffffsseett]]<<ccaarrrriiaaggee--rreettuurrnn>> + NN + nn Search forward or backward for a regular expression. + 00 Move to the first character in the current line. + : Execute an ex command. + [[ccoouunntt]] ;; + Repeat the last character find count times. + [[ccoouunntt]] << mmoottiioonn + [[ccoouunntt]] >> mmoottiioonn + Shift lines left or right. + @@ bbuuffffeerr + Execute a named buffer. + [[ccoouunntt]] AA + Enter input mode, appending the text after the end of the line. + [[ccoouunntt]] BB + Move backwards count bigwords. + [[bbuuffffeerr]] [[ccoouunntt]] CC + + + Change text from the current position to the end-of-line. + [[bbuuffffeerr]] DD + Delete text from the current position to the end-of-line. + [[ccoouunntt]] EE + Move forward count end-of-bigwords. + [[ccoouunntt]] FF <<cchhaarraacctteerr>> + Search count times backward through the current line for + <character>. + [[ccoouunntt]] GG + Move to line count, or the last line of the file if count not spec- + ified. + [[ccoouunntt]] HH + Move to the screen line count - 1 lines below the top of the + screen. + [[ccoouunntt]] II + Enter input mode, inserting the text at the beginning of the line. + [[ccoouunntt]] JJ + Join lines. + [[ccoouunntt]] LL + Move to the screen line count - 1 lines above the bottom of the + screen. + MM Move to the screen line in the middle of the screen. + [[ccoouunntt]] OO + Enter input mode, appending text in a new line above the current + line. + [[bbuuffffeerr]] PP + Insert text from a buffer. + QQ Exit vvii (or visual) mode and switch to eexx mode. + [[ccoouunntt]] RR + Enter input mode, replacing the characters in the current line. + [[bbuuffffeerr]] [[ccoouunntt]] SS + Substitute count lines. + [[ccoouunntt]] TT <<cchhaarraacctteerr>> + Search backwards, count times, through the current line for the + character _a_f_t_e_r the specified <character>. + UU Restore the current line to its state before the cursor last moved + to it. + [[ccoouunntt]] WW + Move forward count bigwords. + [[bbuuffffeerr]] [[ccoouunntt]] XX + Delete count characters before the cursor. + [[bbuuffffeerr]] [[ccoouunntt]] YY + Copy (or ``yank'') count lines into the specified buffer. + ZZZZ Write the file and exit vvii. + [[ccoouunntt]] [[[[ + Back up count section boundaries. + [[ccoouunntt]] ]]]] + Move forward count section boundaries. + ^^ Move to first nonblank character on the current line. + [[ccoouunntt]] __ + Move down count - 1 lines, to the first nonblank character. + [[ccoouunntt]] aa + Enter input mode, appending the text after the cursor. + [[ccoouunntt]] bb + Move backwards count words. + [[bbuuffffeerr]] [[ccoouunntt]] cc mmoottiioonn + Change a region of text. + [[bbuuffffeerr]] [[ccoouunntt]] dd mmoottiioonn + Delete a region of text. + [[ccoouunntt]] ee + Move forward count end-of-words. + [[ccoouunntt]] ff<<cchhaarraacctteerr>> + Search forward, count times, through the rest of the current line + for <character>. + [[ccoouunntt]] ii + + Enter input mode, inserting the text before the cursor. + mm <<cchhaarraacctteerr>> + Save the current context (line and column) as <character>. + [[ccoouunntt]] oo + Enter input mode, appending text in a new line under the current + line. + [[bbuuffffeerr]] pp + Append text from a buffer. + [[ccoouunntt]] rr <<cchhaarraacctteerr>> + Replace count characters. + [[bbuuffffeerr]] [[ccoouunntt]] ss + Substitute count characters in the current line starting with the + current character. + [[ccoouunntt]] tt <<cchhaarraacctteerr>> + Search forward, count times, through the current line for the char- + acter immediately _b_e_f_o_r_e <character>. + uu Undo the last change made to the file. + [[ccoouunntt]] ww + Move forward count words. + [[bbuuffffeerr]] [[ccoouunntt]] xx + Delete count characters. + [[bbuuffffeerr]] [[ccoouunntt]] yy mmoottiioonn + Copy (or ``yank'') a text region specified by the count and motion + into a buffer. + [[ccoouunntt11]] zz [[ccoouunntt22]] --||..||++||^^||<<ccaarrrriiaaggee--rreettuurrnn>> + Redraw, optionally repositioning and resizing the screen. + [[ccoouunntt]] {{ + Move backward count paragraphs. + [[ccoouunntt]] || + Move to a specific _c_o_l_u_m_n position on the current line. + [[ccoouunntt]] }} + Move forward count paragraphs. + [[ccoouunntt]] ~~ + Reverse the case of the next count character(s). + [[ccoouunntt]] ~~ mmoottiioonn + Reverse the case of the characters in a text region specified by + the count and motion. + <<iinntteerrrruupptt>> + Interrupt the current operation. + +VVII TTEEXXTT IINNPPUUTT CCOOMMMMAANNDDSS + The following section describes the commands available in the text input + mode of the vvii editor. + + <<nnuull>> + Replay the previous input. + <<ccoonnttrrooll--DD>> + Erase the previous autoindent character. + ^^<<ccoonnttrrooll--DD>> + Erase all of the autoindent characters, and reset the autoindent + level. + 00<<ccoonnttrrooll--DD>> + Erase all of the autoindent characters. + <<ccoonnttrrooll--TT>> + Insert sufficient <tab> and <space> characters to move the cursor + forward to a column immediately after the next column which is an + even multiple of the sshhiiffttwwiiddtthh option. + <<eerraassee>> + <<ccoonnttrrooll--HH>> + Erase the last character. + <<lliitteerraall nneexxtt>> + Quote the next character. + <<eessccaappee>> + Resolve all text input into the file, and return to command mode. + <<lliinnee eerraassee>> + + Erase the current line. + <<ccoonnttrrooll--WW>> + <<wwoorrdd eerraassee>> + Erase the last word. The definition of word is dependent on the + aallttwweerraassee and ttttyywweerraassee options. + <<ccoonnttrrooll--XX>>[[00--99AA--FFaa--ff]]** + Insert a character with the specified hexadecimal value into the + text. + <<iinntteerrrruupptt>> + Interrupt text input mode, returning to command mode. + +EEXX CCOOMMMMAANNDDSS + The following section describes the commands available in the eexx editor. + In each entry below, the tag line is a usage synopsis for the command. + + <<eenndd--ooff--ffiillee>> + Scroll the screen. + !! aarrgguummeenntt((ss)) + [[rraannggee]]!! aarrgguummeenntt((ss)) + Execute a shell command, or filter lines through a shell command. + "" A comment. + [[rraannggee]] nnuu[[mmbbeerr]] [[ccoouunntt]] [[ffllaaggss]] + [[rraannggee]] ## [[ccoouunntt]] [[ffllaaggss]] + Display the selected lines, each preceded with its line number. + @@ bbuuffffeerr + ** bbuuffffeerr + Execute a buffer. + [[rraannggee]] dd[[eelleettee]] [[bbuuffffeerr]] [[ccoouunntt]] [[ffllaaggss]] + Delete the lines from the file. + ddii[[ssppllaayy]] bb[[uuffffeerrss]] || ss[[ccrreeeennss]] || tt[[aaggss]] + Display buffers, screens or tags. + ee[[ddiitt]][[!!]] [[++ccmmdd]] [[ffiillee]] + eexx[[!!]] [[++ccmmdd]] [[ffiillee]] + Edit a different file. + eexxuu[[ssaaggee]] [[ccoommmmaanndd]] + Display usage for an eexx command. + ff[[iillee]] [[ffiillee]] + Display and optionally change the file name. + ffgg [[nnaammee]] + VVii mode only. Foreground the specified screen. + [[rraannggee]] gg[[lloobbaall]] //ppaatttteerrnn// [[ccoommmmaannddss]] + [[rraannggee]] vv //ppaatttteerrnn// [[ccoommmmaannddss]] + Apply commands to lines matching (or not matching) a pattern. + hhee[[llpp]] + Display a help message. + [[lliinnee]] ii[[nnsseerrtt]][[!!]] + The input text is inserted before the specified line. + [[rraannggee]] jj[[ooiinn]][[!!]] [[ccoouunntt]] [[ffllaaggss]] + Join lines of text together. + [[rraannggee]] ll[[iisstt]] [[ccoouunntt]] [[ffllaaggss]] + Display the lines unambiguously. + mmaapp[[!!]] [[llhhss rrhhss]] + Define or display maps (for vvii only). + [[lliinnee]] mmaa[[rrkk]] <<cchhaarraacctteerr>> + [[lliinnee]] kk <<cchhaarraacctteerr>> + Mark the line with the mark <character>. + [[rraannggee]] mm[[oovvee]] lliinnee + Move the specified lines after the target line. + mmkk[[eexxrrcc]][[!!]] ffiillee + Write the abbreviations, editor options and maps to the specified + file. + nn[[eexxtt]][[!!]] [[ffiillee ......]] + Edit the next file from the argument list. + [[lliinnee]] oo[[ppeenn]] //ppaatttteerrnn// [[ffllaaggss]] + + + Enter open mode. + pprree[[sseerrvvee]] + Save the file in a form that can later be recovered using the eexx --rr + option. + pprreevv[[iioouuss]][[!!]] + Edit the previous file from the argument list. + [[rraannggee]] pp[[rriinntt]] [[ccoouunntt]] [[ffllaaggss]] + Display the specified lines. + [[lliinnee]] ppuu[[tt]] [[bbuuffffeerr]] + Append buffer contents to the current line. + qq[[uuiitt]][[!!]] + End the editing session. + [[lliinnee]] rr[[eeaadd]][[!!]] [[ffiillee]] + Read a file. + rreecc[[oovveerr]] ffiillee + Recover file if it was previously saved. + rreess[[iizzee]] [[++||--]]ssiizzee + VVii mode only. Grow or shrink the current screen. + rreeww[[iinndd]][[!!]] + Rewind the argument list. + ssee[[tt]] [[ooppttiioonn[[==[[vvaalluuee]]]] ......]] [[nnooooppttiioonn ......]] [[ooppttiioonn?? ......]] [[aallll]] + Display or set editor options. + sshh[[eellll]] + Run a shell program. + ssoo[[uurrccee]] ffiillee + Read and execute eexx commands from a file. + sspp[[lliitt]] [[ffiillee ......]] + VVii mode only. Split the screen. + [[rraannggee]] ss[[uubbssttiittuuttee]] [[//ppaatttteerrnn//rreeppllaaccee//]] [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]] + [[rraannggee]] && [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]] + [[rraannggee]] ~~ [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]] + Make substitutions. + ssuu[[ssppeenndd]][[!!]] + sstt[[oopp]][[!!]] + <<ssuussppeenndd>> + Suspend the edit session. + ttaa[[gg]][[!!]] ttaaggssttrriinngg + Edit the file containing the specified tag. + ttaaggpp[[oopp]][[!!]] [[ffiillee || nnuummbbeerr]] + Pop to the specified tag in the tags stack. + uunnmm[[aapp]][[!!]] llhhss + Unmap a mapped string. + vvee[[rrssiioonn]] + Display the version of the eexx//vvii editor. + [[lliinnee]] vvii[[ssuuaall]] [[ttyyppee]] [[ccoouunntt]] [[ffllaaggss]] + EExx mode only. Enter vvii. + vvii[[ssuuaall]][[!!]] [[++ccmmdd]] [[ffiillee]] + VVii mode only. Edit a new file. + vviiuu[[ssaaggee]] [[ccoommmmaanndd]] + Display usage for a vvii command. + [[rraannggee]] ww[[rriittee]][[!!]] [[>>>>]] [[ffiillee]] + [[rraannggee]] ww[[rriittee]] [[!!]] [[ffiillee]] + [[rraannggee]] wwnn[[!!]] [[>>>>]] [[ffiillee]] + [[rraannggee]] wwqq[[!!]] [[>>>>]] [[ffiillee]] + Write the file. + [[rraannggee]] xx[[iitt]][[!!]] [[ffiillee]] + Write the file if it has been modified. + [[rraannggee]] yyaa[[nnkk]] [[bbuuffffeerr]] [[ccoouunntt]] + Copy the specified lines to a buffer. + [[lliinnee]] zz [[ttyyppee]] [[ccoouunntt]] [[ffllaaggss]] + Adjust the window. + +SSEETT OOPPTTIIOONNSS + There are a large number of options that may be set (or unset) to change + the editor's behavior. This section describes the options, their abbre- + viations and their default values. + + In each entry below, the first part of the tag line is the full name of + the option, followed by any equivalent abbreviations. The part in square + brackets is the default value of the option. Most of the options are + boolean, i.e. they are either on or off, and do not have an associated + value. + + Options apply to both eexx and vvii modes, unless otherwise specified. + + aallttwweerraassee [[ooffff]] + VVii only. Select an alternate word erase algorithm. + aauuttooiinnddeenntt,, aaii [[ooffff]] + Automatically indent new lines. + aauuttoopprriinntt,, aapp [[ooffff]] + EExx only. Display the current line automatically. + aauuttoowwrriittee,, aaww [[ooffff]] + Write modified files automatically when changing files. + bbeeaauuttiiffyy,, bbff [[ooffff]] + Discard control characters. + ccddppaatthh [[eennvviirroonnmmeenntt vvaarriiaabbllee CCDDPPAATTHH,, oorr ccuurrrreenntt ddiirreeccttoorryy]] + The directory paths used as path prefixes for the ccdd command. + ccoolluummnnss,, ccoo [[8800]] + Set the number of columns in the screen. + ccoommmmeenntt [[ooffff]] + VVii only. Skip leading comments in files. + ddiirreeccttoorryy,, ddiirr [[eennvviirroonnmmeenntt vvaarriiaabbllee TTMMPPDDIIRR,, oorr //ttmmpp]] + The directory where temporary files are created. + eeddccoommppaattiibbllee,, eedd [[ooffff]] + Remember the values of the ``c'' and ``g'' suffices to the + ssuubbssttiittuuttee commands, instead of initializing them as unset for each + new command. + eerrrroorrbbeellllss,, eebb [[ooffff]] + EExx only. Announce error messages with a bell. + eexxrrcc,, eexx [[ooffff]] + Never read startup files in the local directory. + eexxtteennddeedd [[ooffff]] + Regular expressions are extended (i.e. egrep(1) style) expres- + sions. + ffllaasshh [[oonn]] + Flash the screen instead of beeping the keyboard on error. + hhaarrddttaabbss,, hhtt [[88]] + Set the spacing between hardware tab settings. + iiggnnoorreeccaassee,, iicc [[ooffff]] + Ignore case differences in regular expressions. + kkeeyyttiimmee [[66]] + The 10th's of a second eexx//vvii waits for a subsequent key to complete + a key mapping. + lleeffttrriigghhtt [[ooffff]] + VVii only. Do left-right scrolling. + lliinneess,, llii [[2244]] + VVii only. Set the number of lines in the screen. + lliisspp [[ooffff]] + VVii only. Modify various search commands and options to work with + Lisp. + + _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + lliisstt [[ooffff]] + Display lines in an unambiguous fashion. + mmaaggiicc [[oonn]] + Treat certain characters specially in regular expressions. + mmaattcchhttiimmee [[77]] + VVii only. The 10th's of a second eexx//vvii pauses on the matching char- + acter when the sshhoowwmmaattcchh option is set. + mmeessgg [[oonn]] + + + Permit messages from other users. + mmooddeelliinneess,, mmooddeelliinnee [[ooffff]] + Read the first and last few lines of each file for eexx commands. + + _T_h_i_s _o_p_t_i_o_n _w_i_l_l _n_e_v_e_r _b_e _i_m_p_l_e_m_e_n_t_e_d_. + nnuummbbeerr,, nnuu [[ooffff]] + Precede each line displayed with its current line number. + ooccttaall [[ooffff]] + Display unknown characters as octal numbers, instead of the default + hexadecimal. + ooppeenn [[oonn]] + EExx only. If this option is not set, the ooppeenn and vviissuuaall commands + are disallowed. + ooppttiimmiizzee,, oopptt [[oonn]] + VVii only. Optimize text throughput to dumb terminals. + + _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + ppaarraaggrraapphhss,, ppaarraa [[IIPPLLPPPPPPQQPPPP LLIIppppllppiippbbpp]] + VVii only. Define additional paragraph boundaries for the {{ and }} + commands. + pprroommpptt [[oonn]] + EExx only. Display a command prompt. + rreeaaddoonnllyy,, rroo [[ooffff]] + Mark the file as read-only. + rreeccddiirr [[//vvaarr//ttmmpp//vvii..rreeccoovveerr]] + The directory where recovery files are stored. + rreeddrraaww,, rree [[ooffff]] + VVii only. Simulate an intelligent terminal on a dumb one. + + _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + rreemmaapp [[oonn]] + Remap keys until resolved. + rreeppoorrtt [[55]] + Set the number of lines about which the editor reports changes or + yanks. + rruulleerr [[ooffff]] + VVii only. Display a row/column ruler on the colon command line. + ssccrroollll,, ssccrr [[wwiinnddooww // 22]] + Set the number of lines scrolled. + sseeccttiioonnss,, sseecctt [[NNHHSSHHHH HHUUnnhhsshh]] + VVii only. Define additional section boundaries for the [[[[ and ]]]] + commands. + sshheellll,, sshh [[eennvviirroonnmmeenntt vvaarriiaabbllee SSHHEELLLL,, oorr //bbiinn//sshh]] + Select the shell used by the editor. + sshhiiffttwwiiddtthh,, ssww [[88]] + Set the autoindent and shift command indentation width. + sshhoowwddiirrttyy [[ooffff]] + VVii only. Display an asterisk on the colon command line if the file + has been modified. + sshhoowwmmaattcchh,, ssmm [[ooffff]] + VVii only. Note matching ``{'' and ``('' for ``}'' and ``)'' charac- + ters. + sshhoowwmmooddee [[ooffff]] + VVii only. Display the current editor mode (command or input). + ssiiddeessccrroollll [[1166]] + VVii only. Set the amount a left-right scroll will shift. + sslloowwooppeenn,, ssllooww [[ooffff]] + Delay display updating during text input. + + _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + ssoouurrcceeaannyy [[ooffff]] + Read startup files not owned by the current user. + + _T_h_i_s _o_p_t_i_o_n _w_i_l_l _n_e_v_e_r _b_e _i_m_p_l_e_m_e_n_t_e_d_. + ttaabbssttoopp,, ttss [[88]] + + This option sets tab widths for the editor display. + ttaagglleennggtthh,, ttll [[00]] + Set the number of significant characters in tag names. + ttaaggss,, ttaagg [[ttaaggss //vvaarr//ddbb//lliibbcc..ttaaggss //ssyyss//kkeerrnn//ttaaggss]] + Set the list of tags files. + tteerrmm,, ttttyyttyyppee,, ttttyy [[eennvviirroonnmmeenntt vvaarriiaabbllee TTEERRMM]] + Set the terminal type. + tteerrssee [[ooffff]] + This option has historically made editor messages less verbose. It + has no effect in this implementation. + ttiillddeeoopp + Modify the ~~ command to take an associated motion. + ttiimmeeoouutt,, ttoo [[oonn]] + Time out on keys which may be mapped. + ttttyywweerraassee [[ooffff]] + VVii only. Select an alternate erase algorithm. + vveerrbboossee [[ooffff]] + only. Display an error message for every error. + ww330000 [[nnoo ddeeffaauulltt]] + VVii only. Set the window size if the baud rate is less than 1200 + baud. + ww11220000 [[nnoo ddeeffaauulltt]] + VVii only. Set the window size if the baud rate is equal to 1200 + baud. + ww99660000 [[nnoo ddeeffaauulltt]] + VVii only. Set the window size if the baud rate is greater than 1200 + baud. + wwaarrnn [[oonn]] + EExx only. This option causes a warning message to the terminal if + the file has been modified, since it was last written, before a !! + command. + wwiinnddooww,, ww,, wwii [[eennvviirroonnmmeenntt vvaarriiaabbllee LLIINNEESS]] + Set the window size for the screen. + wwrraappmmaarrggiinn,, wwmm [[00]] + VVii only. Break lines automatically when they reach the right-hand + margin. + wwrraappssccaann,, wwss [[oonn]] + Set searches to wrap around the end or beginning of the file. + wwrriitteeaannyy,, wwaa [[ooffff]] + Turn off file-overwriting checks. + +EENNVVIIRROONNMMEENNTTAALL VVAARRIIAABBLLEESS + COLUMNS The number of columns on the screen. This value overrides any + system or terminal specific values. If the COLUMNS environ- + mental variable is not set when eexx//vvii runs, or the ccoolluummnnss op- + tion is explicitly reset by the user, eexx//vvii enters the value + into the environment. + EXINIT A list of eexx startup commands, read if the variable NEXINIT is + not set. + HOME The user's home directory, used as the initial directory path + for the startup _$_H_O_M_E_/_._n_e_x_r_c and _$_H_O_M_E_/_._e_x_r_c files. This val- + ue is also used as the default directory for the vvii ccdd com- + mand. + LINES The number of rows on the screen. This value overrides any + system or terminal specific values. If the LINES environmen- + tal variable is not set when eexx//vvii runs, or the lliinneess option + is explicitly reset by the user, eexx//vvii enters the value into + the environment. + NEXINIT A list of eexx startup commands. + SHELL The user's shell of choice (see also the sshheellll option). + TERM The user's terminal type. The default is the type + ``unknown''. If the TERM environmental variable is not set + when eexx//vvii runs, or the tteerrmm option is explicitly reset by the + user, eexx//vvii enters the value into the environment. + TMPDIR The location used to stored temporary files (see also the + ddiirreeccttoorryy option). + +AASSYYNNCCHHRROONNOOUUSS EEVVEENNTTSS + SIGALRM VVii//eexx uses this signal for periodic backups of file modifica- + tions and to display ``busy'' messages when operations are + likely to take a long time. + SIGHUP + SIGTERM If the current buffer has changed since it was last written + in its entirety, the editor attempts to save the modified + file so it can be later recovered. See the vvii//eexx Reference + manual section entitled ``Recovery'' for more information. + SIGINT When an interrupt occurs, the current operation is halted, + and the editor returns to the command level. If interrupted + during text input, the text already input is resolved into + the file as if the text input had been normally terminated. + SIGWINCH The screen is resized. See the vvii//eexx Reference manual sec- + tion entitled ``Sizing the Screen'' for more information. + SIGCONT + SIGQUIT + SIGTSTP VVii//eexx ignores these signals. + +BBUUGGSS + See the file _n_v_i_/_d_o_c_s_/_b_u_g_s_._c_u_r_r_e_n_t for a list of the known bugs in this + version. + +FFIILLEESS + /bin/sh The default user shell. + /etc/vi.exrc System-wide vi startup file. + /tmp Temporary file directory. + /var/tmp/vi.recover The default recovery file directory. + $HOME/.nexrc 1st choice for user's home directory startup file. + $HOME/.exrc 2nd choice for user's home directory startup file. + .nexrc 1st choice for local directory startup file. + .exrc 2nd choice for local directory startup file. + +SSEEEE AALLSSOO + ctags(1), more(1), curses(3), dbopen(3) + + The ``Vi Quick Reference'' card. + + ``An Introduction to Display Editing with Vi'', found in the ``UNIX + User's Manual Supplementary Documents'' section of both the 4.3BSD and + 4.4BSD manual sets. This document is the closest thing available to an + introduction to the vvii screen editor. + + ``Ex Reference Manual (Version 3.7)'', found in the ``UNIX User's Manual + Supplementary Documents'' section of both the 4.3BSD and 4.4BSD manual + sets. This document is the final reference for the eexx editor, as dis- + tributed in most historic 4BSD and System V systems. + + ``Edit: A tutorial'', found in the ``UNIX User's Manual Supplementary + Documents'' section of the 4.3BSD manual set. This document is an intro- + duction to a simple version of the eexx screen editor. + + ``Ex/Vi Reference Manual'', found in the ``UNIX User's Manual + Supplementary Documents'' section of the 4.4BSD manual set. This docu- + ment is the final reference for the nneexx//nnvvii text editors, as distributed + in 4.4BSD and 4.4BSD-Lite. + + RRooffff source for all of these documents is distributed with nneexx//nnvvii in the + _n_v_i_/_U_S_D_._d_o_c directory of the nneexx//nnvvii source code. + + The files ``autowrite'', ``input'', ``quoting'', and ``structures'', + found in the _n_v_i_/_d_o_c_s_/_i_n_t_e_r_n_a_l_s directory of the nneexx//nnvvii source code. + +HHIISSTTOORRYY + The nneexx//nnvvii replacements for the eexx//vvii editor first appeared in 4.4BSD. + +SSTTAANNDDAARRDDSS + NNeexx//nnvvii is close to IEEE Std1003.2 (``POSIX''). That document differs + from historical eexx//vvii practice in several places; there are changes to be + made on both sides. + +4.4BSD July 15, 1994 13 diff --git a/usr.bin/vi/USD.doc/vi.man/vi.0.ps b/usr.bin/vi/USD.doc/vi.man/vi.0.ps new file mode 100644 index 0000000..f6cfc03 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.man/vi.0.ps @@ -0,0 +1,1063 @@ +%!PS-Adobe-3.0 +%%Creator: groff version 1.08 +%%DocumentNeededResources: font Times-Roman +%%+ font Times-Bold +%%+ font Courier-Bold +%%+ font Courier-Oblique +%%+ font Courier +%%+ font Times-Italic +%%+ font Symbol +%%DocumentSuppliedResources: procset grops 1.08 0 +%%Pages: 14 +%%PageOrder: Ascend +%%Orientation: Portrait +%%EndComments +%%BeginProlog +%%BeginResource: procset grops 1.08 0 +/setpacking where{ +pop +currentpacking +true setpacking +}if +/grops 120 dict dup begin +/SC 32 def +/A/show load def +/B{0 SC 3 -1 roll widthshow}bind def +/C{0 exch ashow}bind def +/D{0 exch 0 SC 5 2 roll awidthshow}bind def +/E{0 rmoveto show}bind def +/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def +/G{0 rmoveto 0 exch ashow}bind def +/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/I{0 exch rmoveto show}bind def +/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def +/K{0 exch rmoveto 0 exch ashow}bind def +/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/M{rmoveto show}bind def +/N{rmoveto 0 SC 3 -1 roll widthshow}bind def +/O{rmoveto 0 exch ashow}bind def +/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/Q{moveto show}bind def +/R{moveto 0 SC 3 -1 roll widthshow}bind def +/S{moveto 0 exch ashow}bind def +/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/SF{ +findfont exch +[exch dup 0 exch 0 exch neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/MF{ +findfont +[5 2 roll +0 3 1 roll +neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/level0 0 def +/RES 0 def +/PL 0 def +/LS 0 def +/PLG{ +gsave newpath clippath pathbbox grestore +exch pop add exch pop +}bind def +/BP{ +/level0 save def +1 setlinecap +1 setlinejoin +72 RES div dup scale +LS{ +90 rotate +}{ +0 PL translate +}ifelse +1 -1 scale +}bind def +/EP{ +level0 restore +showpage +}bind def +/DA{ +newpath arcn stroke +}bind def +/SN{ +transform +.25 sub exch .25 sub exch +round .25 add exch round .25 add exch +itransform +}bind def +/DL{ +SN +moveto +SN +lineto stroke +}bind def +/DC{ +newpath 0 360 arc closepath +}bind def +/TM matrix def +/DE{ +TM currentmatrix pop +translate scale newpath 0 0 .5 0 360 arc closepath +TM setmatrix +}bind def +/RC/rcurveto load def +/RL/rlineto load def +/ST/stroke load def +/MT/moveto load def +/CL/closepath load def +/FL{ +currentgray exch setgray fill setgray +}bind def +/BL/fill load def +/LW/setlinewidth load def +/RE{ +findfont +dup maxlength 1 index/FontName known not{1 add}if dict begin +{ +1 index/FID ne{def}{pop pop}ifelse +}forall +/Encoding exch def +dup/FontName exch def +currentdict end definefont pop +}bind def +/DEFS 0 def +/EBEGIN{ +moveto +DEFS begin +}bind def +/EEND/end load def +/CNT 0 def +/level1 0 def +/PBEGIN{ +/level1 save def +translate +div 3 1 roll div exch scale +neg exch neg exch translate +0 setgray +0 setlinecap +1 setlinewidth +0 setlinejoin +10 setmiterlimit +[]0 setdash +/setstrokeadjust where{ +pop +false setstrokeadjust +}if +/setoverprint where{ +pop +false setoverprint +}if +newpath +/CNT countdictstack def +userdict begin +/showpage{}def +}bind def +/PEND{ +clear +countdictstack CNT sub{end}repeat +level1 restore +}bind def +end def +/setpacking where{ +pop +setpacking +}if +%%EndResource +%%IncludeResource: font Times-Roman +%%IncludeResource: font Times-Bold +%%IncludeResource: font Courier-Bold +%%IncludeResource: font Courier-Oblique +%%IncludeResource: font Courier +%%IncludeResource: font Times-Italic +%%IncludeResource: font Symbol +grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL +792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron +/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space +/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft +/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four +/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C +/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash +/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q +/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase +/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger +/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut +/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash +/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar +/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus +/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu +/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright +/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde +/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute +/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls +/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute +/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve +/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex +/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE +/Courier@0 ENC0/Courier RE/Courier-Oblique@0 ENC0/Courier-Oblique RE +/Courier-Bold@0 ENC0/Courier-Bold RE/Times-Bold@0 ENC0/Times-Bold RE +/Times-Roman@0 ENC0/Times-Roman RE +%%EndProlog +%%Page: 1 1 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Bold@0 SF -.2(NA)72 +108 S(ME).2 E/F2 10/Courier-Bold@0 SF(ex, vi, view)102 120 Q F0 2.5<ad74>2.5 G +-.15(ex)187.42 120 S 2.5(te).15 G(ditors)206.43 120 Q F1(SYNOPSIS)72 144 Q F2 +(ex)102 156 Q F0([)3.333 E F2(\255eFRrsv)2.499 E F0 3.333(][).833 G F2<ad63> +-.834 E/F3 10/Courier-Oblique@0 SF(cmd)6 E F0 3.333(][).833 G F2<ad74>-.834 E +F3(tag)6 E F0 3.333(][).833 G F2<ad77>-.834 E F3(size)6 E F0 3.333(][).833 G F3 +(file ...)330.796 156 Q F0(]).833 E F2(vi)102 168 Q F0([)3.333 E F2(\255eFRrv) +2.499 E F0 3.333(][).833 G F2<ad63>-.834 E F3(cmd)6 E F0 3.333(][).833 G F2 +<ad74>-.834 E F3(tag)6 E F0 3.333(][).833 G F2<ad77>-.834 E F3(size)6 E F0 +3.333(][).833 G F3(file ...)324.796 168 Q F0(]).833 E F2(view)102 180 Q F0([) +3.333 E F2(\255eFRrv)2.499 E F0 3.333(][).833 G F2<ad63>-.834 E F3(cmd)6 E F0 +3.333(][).833 G F2<ad74>-.834 E F3(tag)6 E F0 3.333(][).833 G F2<ad77>-.834 E +F3(size)6 E F0 3.333(][).833 G F3(file ...)336.796 180 Q F0(]).833 E F1 +(DESCRIPTION)72 204 Q F2(Vi)102 216 Q F0 .176(is a screen oriented te)2.676 F +.176(xt editor)-.15 F(.)-.55 E F2(Ex)5.176 E F0 .176(is a line-oriented te) +2.676 F .175(xt editor)-.15 F(.)-.55 E F2(Ex)5.175 E F0(and)2.675 E F2(vi)2.675 +E F0 .175(are dif)2.675 F .175(ferent interf)-.25 F .175(aces to the)-.1 F .56 +(same program, and it is possible to switch back and forth during an edit sess\ +ion.)102 228 R F2(View)5.561 E F0 .561(is the equi)3.061 F -.25(va)-.25 G .561 +(lent of).25 F(using the)102 240 Q F2<ad52>4.166 E F0(\(read-only\) option of) +2.5 E F2(vi)2.5 E F0(.)A .216(This manual page is the one pro)102 258 R .215 +(vided with the)-.15 F F2(nex/nvi)2.715 E F0 -.15(ve)2.715 G .215 +(rsions of the).15 F F2(ex/vi)2.715 E F0(te)2.715 E .215(xt editors.)-.15 F F2 +(Nex/nvi)5.215 E F0(are)2.715 E 1.937(intended as b)102 270 R(ug-for)-.2 E(-b) +-.2 E 1.937(ug compatible replacements for the original F)-.2 F 1.938 +(ourth Berk)-.15 F(ele)-.1 E 4.438(yS)-.15 G(oftw)456.982 270 Q 1.938 +(are Distrib)-.1 F(ution)-.2 E(\(4BSD\))102 282 Q F2(ex)3.008 E F0(and)3.008 E +F2(vi)3.008 E F0 3.008(programs. F)3.008 F .508 +(or the rest of this manual page,)-.15 F F2(nex/nvi)3.008 E F0 .507 +(is used only when it')3.008 F 3.007(sn)-.55 G(ecessary)506.13 282 Q +(to distinguish it from the historic implementations of)102 294 Q F2(ex/vi)2.5 +E F0(.)A .961(This manual page is intended for users already f)102 312 R .961 +(amiliar with)-.1 F F2(ex/vi)3.461 E F0 3.462(.A)C -.15(ny)397.982 312 S .962 +(one else should almost certainly).15 F .582 +(read a good tutorial on the editor before this manual page.)102 324 R .582 +(If you')5.582 F .581(re in an unf)-.5 F .581(amiliar en)-.1 F .581 +(vironment, and you)-.4 F .799(absolutely ha)102 336 R 1.099 -.15(ve t)-.2 H +3.299(og).15 G .799(et w)184.317 336 R .799(ork done immediately)-.1 F 3.299 +(,r)-.65 G .8(ead the section after the options description, entitled `)299.803 +336 R(`F)-.74 E(ast)-.15 E(Startup')102 348 Q('. It')-.74 E 2.5(sp)-.55 G +(robably enough to get you going.)162.09 348 Q(The follo)102 366 Q +(wing options are a)-.25 E -.25(va)-.2 G(ilable:).25 E F2<ad63>103.666 384 Q F0 +(Ex)137 384 Q(ecute)-.15 E F3(cmd)2.675 E F0 .175 +(immediately after starting the edit session.)2.675 F -.15(Pa)5.175 G .174 +(rticularly useful for initial positioning in).15 F .624(the \214le, ho)137 396 +R(we)-.25 E -.15(ve)-.25 G(r).15 E F3(cmd)3.124 E F0 .625 +(is not limited to positioning commands.)3.124 F .625 +(This is the POSIX 1003.2 interf)5.625 F(ace)-.1 E(for the historic `)137 408 Q +(`+cmd')-.74 E 2.5('s)-.74 G(yntax.)239.47 408 Q F2(Nex/nvi)5 E F0 +(supports both the old and ne)2.5 E 2.5(ws)-.25 G(yntax.)440.1 408 Q F2<ad65> +103.666 426 Q F0(Start editing in e)137 426 Q 2.5(xm)-.15 G +(ode, as if the command name were)218.52 426 Q F2(ex)2.5 E F0(.)A F2<ad46> +103.666 444 Q F0(Don')137 444 Q 2.677(tc)-.18 G(op)167.267 444 Q 2.677(yt)-.1 G +.177(he entire \214le when \214rst starting to edit.)187.624 444 R .177 +(\(The def)5.177 F .177(ault is to mak)-.1 F 2.677(eac)-.1 G(op)456.532 444 Q +2.676(yi)-.1 G 2.676(nc)476.888 444 S .176(ase someone)489.004 444 R +(else modi\214es the \214le during your edit session.\))137 456 Q F2<ad52> +103.666 474 Q F0 .184 +(Start editing in read-only mode, as if the command name w)137 474 R(as)-.1 E +F2(view)2.685 E F0 2.685(,o)C 2.685(rt)421.415 474 S .185(he readonly option w) +430.21 474 R .185(as set.)-.1 F F2<ad72>103.666 492 Q F0(Reco)137 492 Q -.15 +(ve)-.15 G 2.627(rt).15 G .127(he speci\214ed \214les, or)175.427 492 R 2.627 +(,i)-.4 G 2.627(fn)263.305 492 S 2.627<6f8c>274.262 492 S .127 +(les are speci\214ed, list the \214les that could be reco)287.449 492 R -.15 +(ve)-.15 G 2.626(red. If).15 F .126(no re-)2.626 F(co)137 504 Q -.15(ve)-.15 G +.4(rable \214les by the speci\214ed name e).15 F .401 +(xist, the \214le is edited as if the)-.15 F F2<ad72>4.567 E F0 .401 +(option had not been speci-)2.901 F(\214ed.)137 516 Q F2<ad73>103.666 534 Q F0 +1.621(Enter batch mode; applicable only to)137 534 R F2(ex)4.121 E F0 1.621 +(edit sessions.)4.121 F 1.62(Batch mode is useful when running)6.621 F F2(ex) +4.12 E F0 2.647(scripts. Prompts,)137 546 R(informati)2.647 E .447 -.15(ve m) +-.25 H .147(essages and other user oriented message are turned of).15 F .148 +(f, and no start-)-.25 F .067(up \214les or en)137 558 R .067(vironmental v)-.4 +F .066(ariables are read.)-.25 F .066(This is the POSIX 1003.2 interf)5.066 F +.066(ace for the historic `)-.1 F(`\255')-.74 E(')-.74 E(ar)137 570 Q(gument.) +-.18 E F2(Nex/nvi)5 E F0(supports both the old and ne)2.5 E 2.5(ws)-.25 G +(yntax.)353 570 Q F2<ad74>103.666 588 Q F0 +(Start editing at the speci\214ed tag.)137 588 Q(\(See)5 E/F4 10/Courier@0 SF +(ctags)2.5 E F0(\(1\)\).)A F2<ad77>103.666 606 Q F0(Set the initial windo)137 +606 Q 2.5(ws)-.25 G(ize to the speci\214ed number of lines.)231.2 606 Q F2 +<ad76>103.666 624 Q F0(Start editing in vi mode, as if the command name w)137 +624 Q(as)-.1 E F2(vi)2.5 E F0(or)2.5 E F2(view)2.5 E F0(.)A F2<ad58>103.666 642 +Q F0(Reserv)137 642 Q(ed for X11 interf)-.15 E(aces.)-.1 E/F5 10/Times-Italic@0 +SF(No X11 support is curr)5 E(ently implemented.)-.37 E F0 .35 +(Command input for)102 660 R F2(ex/vi)2.85 E F0 .35 +(is read from the standard input.)2.85 F .35(In the)5.35 F F2(vi)2.85 E F0 +(interf)2.85 E .35(ace, it is an error if standard in-)-.1 F .343 +(put is not a terminal.)102 672 R .343(In the)5.343 F F2(ex)2.843 E F0(interf) +2.843 E .343(ace, if standard input is not a terminal,)-.1 F F2(ex)2.843 E F0 +.342(will read commands from it)2.843 F(re)102 684 Q -.05(ga)-.15 G .137 +(rdless, ho).05 F(we)-.25 E -.15(ve)-.25 G .937 -.4(r, t).15 H .137 +(he session will be a batch mode session, e).4 F .138(xactly as if the)-.15 F +F2<ad73>4.304 E F0 .138(option had been speci\214ed.)2.638 F 172.465 +(4.4BSD July)72 750 R(15, 1994)2.5 E(1)535 750 Q EP +%%Page: 2 2 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Courier-Bold@0 SF(Ex/vi)102 +96 Q F0 -.15(ex)2.5 G(its 0 on success, and greater than 0 if an error occurs.) +.15 E/F2 10/Times-Bold@0 SF -.9(FA)72 120 S 1.666(ST ST).9 F(AR)-.9 E(TUP)-.4 E +F0 .467(This section will tell you the minimum amount that you need to do simp\ +le editing tasks using)102 132 R F1(vi)2.966 E F0 2.966(.I)C 2.966(fy)506.584 +132 S(ou')517.88 132 Q -.15(ve)-.5 G(ne)102 144 Q -.15(ve)-.25 G 3.453(ru).15 G +.953(sed an)132.263 144 R 3.453(ys)-.15 G .953(creen editor before, you') +170.679 144 R .953(re lik)-.5 F .953(ely to ha)-.1 F 1.253 -.15(ve p)-.2 H .953 +(roblems e).15 F -.15(ve)-.25 G 3.453(nw).15 G .953 +(ith this simple introduction.)412.286 144 R(In)5.954 E +(that case you should \214nd someone that already kno)102 156 Q(ws)-.25 E F1 +(vi)2.5 E F0(and ha)2.5 E .3 -.15(ve t)-.2 H(hem w).15 E +(alk you through this section.)-.1 E F1(Vi)102 174 Q F0 .294 +(is a screen editor)2.794 F 5.294(.T)-.55 G .294(his means that it tak)198.51 +174 R .293 +(es up almost the entire screen, displaying part of the \214le on each)-.1 F +.001(screen line, e)102 186 R .001(xcept for the last line of the screen.)-.15 +F .002(The last line of the screen is used for you to gi)5.001 F .302 -.15 +(ve c)-.25 H(ommands).15 E(to)102 198 Q F1(vi)2.5 E F0 2.5(,a)C(nd for)133.72 +198 Q F1(vi)2.5 E F0(to gi)2.5 E .3 -.15(ve i)-.25 H(nformation to you.).15 E +.585(The other f)102 216 R .585(act that you need to understand is that)-.1 F +F1(vi)3.085 E F0 .585(is a modeful editor)3.085 F 3.085(,i)-.4 G .584 +(.e. you are either entering te)406.125 216 R .584(xt or)-.15 F .836(you are e) +102 228 R -.15(xe)-.15 G .836(cuting commands, and you ha).15 F 1.137 -.15 +(ve t)-.2 H 3.337(ob).15 G 3.337(ei)301.062 228 S 3.337(nt)311.619 228 S .837 +(he right mode to do one or the other)322.736 228 R 5.837(.Y)-.55 G .837 +(ou will be in)487.209 228 R 1.094 +(command mode when you \214rst start editing a \214le.)102 240 R 1.093 +(There are commands that switch you into input mode.)6.094 F .084 +(There is only one k)102 252 R .384 -.15(ey t)-.1 H .085(hat tak).15 F .085 +(es you out of input mode, and that is the <escape> k)-.1 F -.15(ey)-.1 G 5.085 +(.\()-.5 G -2.15 -.25(Ke y)449.895 252 T .085(names are written)2.835 F 1.473 +(using less-than and greater)102 264 R 1.473(-than signs, e.g.)-.2 F 1.473 +(<escape> means the `)6.473 F(`escape')-.74 E 3.973('k)-.74 G -.15(ey)420.59 +264 S 3.973(,u)-.5 G 1.473(sually labeled `)440.703 264 R(`esc')-.74 E 3.972 +('o)-.74 G(n)535 264 Q .553(your terminal')102 276 R 3.053(sk)-.55 G -.15(ey) +171.336 276 S 3.053(board.\) If).15 F(you')3.053 E .554(re e)-.5 F -.15(ve)-.25 +G 3.054(rc).15 G .554(onfused as to which mode you')277.45 276 R .554(re in, k) +-.5 F .554(eep entering the <escape>)-.1 F -.1(ke)102 288 S 2.615(yu)-.05 G +(ntil)123.805 288 Q F1(vi)2.615 E F0 .115(beeps at you.)2.615 F(\(Generally) +5.115 E(,)-.65 E F1(vi)2.615 E F0 .115 +(will beep at you if you try and do something that')2.615 F 2.614(sn)-.55 G +.114(ot allo)484.472 288 R 2.614(wed. It)-.25 F +(will also display error messages.\))102 300 Q 2.057 -.8(To s)102 318 T .457 +(tart editing a \214le, enter the command `).8 F(`)-.74 E/F3 10/Courier@0 SF +.458(vi file_name<carriage-return>)B F0 -.74('')C 2.958(.T).74 G .458 +(he command you)470.204 318 R .333 +(should enter as soon as you start editing is `)102 330 R(`)-.74 E F3 .333 +(:set verbose showmode<carriage-return>)B F0 -.74('')C 2.833(.T).74 G(his) +528.33 330 Q 1.441(will mak)102 342 R 3.941(et)-.1 G 1.441(he editor gi)149.782 +342 R 1.741 -.15(ve y)-.25 H 1.441(ou v).15 F 1.441 +(erbose error messages and display the current mode at the bottom of the)-.15 F +(screen.)102 354 Q(The commands to mo)102 372 Q .3 -.15(ve a)-.15 H +(round the \214le are:).15 E F2(h)102 384 Q F0(Mo)131 384 Q .3 -.15(ve t)-.15 H +(he cursor left one character).15 E(.)-.55 E F2(j)102 396 Q F0(Mo)131 396 Q .3 +-.15(ve t)-.15 H(he cursor do).15 E(wn one line.)-.25 E F2(k)102 408 Q F0(Mo) +131 408 Q .3 -.15(ve t)-.15 H(he cursor up one line.).15 E F2(l)102 420 Q F0 +(Mo)131 420 Q .3 -.15(ve t)-.15 H(he cursor right one character).15 E(.)-.55 E +F2(<cursor)102 432 Q(-arr)-.37 E -.1(ow)-.18 G(s>).1 E F0(The cursor arro)131 +444 Q 2.5(wk)-.25 G -.15(ey)207.01 444 S 2.5(ss).15 G(hould w)226.58 444 Q +(ork, too.)-.1 E F2(/text<carriage-r)102 456 Q(etur)-.18 E(n>)-.15 E F0 +(Search for the string `)131 468 Q(`te)-.74 E(xt')-.15 E 2.5('i)-.74 G 2.5(nt) +246.84 468 S(he \214le, and mo)257.12 468 Q .3 -.15(ve t)-.15 H +(he cursor to its \214rst character).15 E(.)-.55 E(The commands to enter ne)102 +486 Q 2.5(wt)-.25 G -.15(ex)220.34 486 S 2.5(ta).15 G(re:)239.35 486 Q F2(a)102 +498 Q F0(Append ne)131 498 Q 2.5(wt)-.25 G -.15(ex)186.85 498 S(t,).15 E/F4 10 +/Times-Italic@0 SF(after)2.5 E F0(the cursor)2.5 E(.)-.55 E F2(i)102 510 Q F0 +(Insert ne)131 510 Q 2.5(wt)-.25 G -.15(ex)177.96 510 S(t,).15 E F4(befor)2.5 E +(e)-.37 E F0(the cursor)2.5 E(.)-.55 E F2(o)102 522 Q F0(Open a ne)131 522 Q +2.5(wl)-.25 G(ine belo)183.79 522 Q 2.5(wt)-.25 G +(he line the cursor is on, and start entering te)227.98 522 Q(xt.)-.15 E F2(O) +102 534 Q F0(Open a ne)131 534 Q 2.5(wl)-.25 G(ine abo)183.79 534 Q .3 -.15 +(ve t)-.15 H(he line the cursor is on, and start entering te).15 E(xt.)-.15 E +F2(<escape>)102 546 Q F0 .744(Once you')131 558 R 1.044 -.15(ve e)-.5 H .744 +(ntered input mode using the one of the).15 F F2(a)3.244 E F0(,)A F2(i)3.244 E +F0(,)A F2(O)3.244 E F0 3.244(,o)C(r)390.542 558 Q F2(o)3.243 E F0 .743 +(commands, use)3.243 F F2(<escape>)3.243 E F0 .743(to quit)3.243 F(entering te) +131 570 Q(xt and return to command mode.)-.15 E(The commands to cop)102 588 Q +2.5(yt)-.1 G -.15(ex)200.78 588 S 2.5(ta).15 G(re:)219.79 588 Q F2(yy)102 600 Q +F0(Cop)131 600 Q 2.5(yt)-.1 G(he line the cursor is on.)157.85 600 Q F2(p)102 +612 Q F0(Append the copied line after the line the cursor is on.)131 612 Q +(The commands to delete te)102 630 Q(xt are:)-.15 E F2(dd)102 642 Q F0 +(Delete the line the cursor is on.)131 642 Q F2(x)102 654 Q F0 +(Delete the character the cursor is on.)131 654 Q +(The commands to write the \214le are:)102 672 Q F2(:w<carriage-r)102 684 Q +(etur)-.18 E(n>)-.15 E F0 .528(Write the \214le back to the \214le with the na\ +me that you originally used as an ar)131 696 R .528(gument on the)-.18 F F1(vi) +3.028 E F0(com-)3.028 E 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(2)535 750 Q +EP +%%Page: 3 3 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(mand line.)131 96 Q/F1 10 +/Times-Bold@0 SF(:w \214le_name<carriage-r)102 108 Q(etur)-.18 E(n>)-.15 E F0 +(Write the \214le back to the \214le with the name `)131 120 Q(`\214le_name') +-.74 E('.)-.74 E(The commands to quit editing and e)102 138 Q +(xit the editor are:)-.15 E F1(:q<carriage-r)102 150 Q(etur)-.18 E(n>)-.15 E F0 +.848(Quit editing and lea)131 162 R 1.148 -.15(ve v)-.2 H 3.348(i\().15 G .848 +(if you')239.6 162 R 1.148 -.15(ve m)-.5 H .848(odi\214ed the \214le, b).15 F +.848(ut not sa)-.2 F -.15(ve)-.2 G 3.348(dy).15 G .848(our changes,)415.454 162 +R/F2 10/Courier-Bold@0 SF(vi)3.347 E F0 .847(will refuse to)3.347 F(quit\).)131 +174 Q F1(:q!<carriage-r)102 186 Q(etur)-.18 E(n>)-.15 E F0(Quit, discarding an) +131 198 Q 2.5(ym)-.15 G(odi\214cations that you may ha)222.51 198 Q .3 -.15 +(ve m)-.2 H(ade.).15 E .686(One \214nal caution.)102 216 R .686 +(Unusual characters can tak)5.686 F 3.187(eu)-.1 G 3.187(pm)302.483 216 S .687 +(ore than one column on the screen, and long lines can)318.45 216 R(tak)102 228 +Q 3.129(eu)-.1 G 3.129(pm)126.689 228 S .629(ore than a single screen line.) +142.598 228 R .629(The abo)5.629 F .929 -.15(ve c)-.15 H .629(ommands w).15 F +.629(ork on `)-.1 F(`ph)-.74 E(ysical')-.05 E 3.129('c)-.74 G .628 +(haracters and lines, i.e.)446.476 228 R(the)102 240 Q 2.74(ya)-.15 G -.25(ff) +126.25 240 S .24(ect the entire line no matter ho).25 F 2.74(wm)-.25 G(an) +273.79 240 Q 2.74(ys)-.15 G .241(creen lines it tak)294.71 240 R .241 +(es up and the entire character no matter ho)-.1 F(w)-.25 E(man)102 252 Q 2.5 +(ys)-.15 G(creen columns it tak)130.46 252 Q(es up.)-.1 E F1 1.666(VI COMMANDS) +72 276 R F0 .186(The follo)102 288 R .186 +(wing section describes the commands a)-.25 F -.25(va)-.2 G .186 +(ilable in the command mode of the).25 F F2(vi)2.686 E F0(editor)2.686 E 5.186 +(.I)-.55 G 2.685(ne)498.54 288 S .185(ach en-)510.665 288 R(try belo)102 300 Q +1.3 -.65(w, t)-.25 H(he tag line is a usage synopsis for the command character) +.65 E(.)-.55 E F1([count] <contr)102 324 Q(ol-A>)-.18 E F0(Search forw)131 336 +Q(ard)-.1 E/F3 10/Courier@0 SF(count)2.5 E F0(times for the current w)2.5 E +(ord.)-.1 E F1([count] <contr)102 348 Q(ol-B>)-.18 E F0 -.15(Pa)131 360 S +(ge backw).15 E(ards)-.1 E F3(count)2.5 E F0(screens.)2.5 E F1([count] <contr) +102 372 Q(ol-D>)-.18 E F0(Scroll forw)131 384 Q(ard)-.1 E F3(count)2.5 E F0 +(lines.)2.5 E F1([count] <contr)102 396 Q(ol-E>)-.18 E F0(Scroll forw)131 408 Q +(ard)-.1 E F3(count)2.5 E F0(lines, lea)2.5 E +(ving the current line and column as is, if possible.)-.2 E F1([count] <contr) +102 420 Q(ol-F>)-.18 E F0 -.15(Pa)131 432 S(ge forw).15 E(ard)-.1 E F3(count) +2.5 E F0(screens.)2.5 E F1(<contr)102 444 Q(ol-G>)-.18 E F0 +(Display the \214le information.)131 456 Q F1(<contr)102 468 Q(ol-H>)-.18 E +([count] h)102 480 Q F0(Mo)131 492 Q .3 -.15(ve t)-.15 H(he cursor back).15 E +F3(count)2.5 E F0(characters in the current line.)2.5 E F1([count] <contr)102 +504 Q(ol-J>)-.18 E([count] <contr)102 516 Q(ol-N>)-.18 E([count] j)102 528 Q F0 +(Mo)131 540 Q .3 -.15(ve t)-.15 H(he cursor do).15 E(wn)-.25 E F3(count)2.5 E +F0(lines without changing the current column.)2.5 E F1(<contr)102 552 Q(ol-L>) +-.18 E(<contr)102 564 Q(ol-R>)-.18 E F0(Repaint the screen.)131 576 Q F1 +([count] <contr)102 588 Q(ol-M>)-.18 E([count] +)102 600 Q F0(Mo)131 612 Q .3 +-.15(ve t)-.15 H(he cursor do).15 E(wn)-.25 E F3(count)2.5 E F0 +(lines to the \214rst nonblank character of that line.)2.5 E F1([count] <contr) +102 624 Q(ol-P>)-.18 E([count] k)102 636 Q F0(Mo)131 648 Q .3 -.15(ve t)-.15 H +(he cursor up).15 E F3(count)2.5 E F0 +(lines, without changing the current column.)2.5 E F1(<contr)102 660 Q(ol-T>) +-.18 E F0(Return to the most recent tag conte)131 672 Q(xt.)-.15 E F1(<contr) +102 684 Q(ol-U>)-.18 E F0 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(3)535 750 +Q EP +%%Page: 4 4 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Scroll backw)131 96 Q(ards)-.1 E +/F1 10/Courier@0 SF(count)2.5 E F0(lines.)2.5 E/F2 10/Times-Bold@0 SF(<contr) +102 108 Q(ol-W>)-.18 E F0 .635(Switch to the ne)131 120 R .635(xt lo)-.15 F +.635(wer screen in the windo)-.25 F 1.935 -.65(w, o)-.25 H 1.435 -.4(r, t).65 H +3.135(ot).4 G .635(he \214rst screen if there are no lo)353.205 120 R .635 +(wer screens in)-.25 F(the windo)131 132 Q -.65(w.)-.25 G F2(<contr)102 144 Q +(ol-Y>)-.18 E F0(Scroll backw)131 156 Q(ards)-.1 E F1(count)2.5 E F0 +(lines, lea)2.5 E(ving the current line and column as is, if possible.)-.2 E F2 +(<contr)102 168 Q(ol-Z>)-.18 E F0(Suspend the current editor session.)131 180 Q +F2(<escape>)102 192 Q F0(Ex)131 204 Q(ecute)-.15 E/F3 10/Courier-Bold@0 SF(ex) +2.5 E F0(commands or cancel partial commands.)2.5 E F2(<contr)102 216 Q(ol-]>) +-.18 E F0(Push a tag reference onto the tag stack.)131 228 Q F2(<contr)102 240 +Q(ol-^>)-.18 E F0(Switch to the most recently edited \214le.)131 252 Q F2 +([count] <space>)102 264 Q([count] l)102 276 Q F0(Mo)131 288 Q .3 -.15(ve t) +-.15 H(he cursor forw).15 E(ard)-.1 E F1(count)2.5 E F0 +(characters without changing the current line.)2.5 E F2 +([count] ! motion shell-ar)102 300 Q(gument\(s\))-.1 E F0(Replace te)131 312 Q +(xt with results from a shell command.)-.15 E F2([count] # +|-|#)102 324 Q F0 +(Increment or decrement the cursor number)131 336 Q(.)-.55 E F2([count] $)102 +348 Q F0(Mo)131 360 Q .3 -.15(ve t)-.15 H(he cursor to the end of a line.).15 E +F2(%)102 372 Q F0(Mo)131 372 Q .3 -.15(ve t)-.15 H 2.5(ot).15 G +(he matching character)169.59 372 Q(.)-.55 E F2(&)102 384 Q F0(Repeat the pre) +131 384 Q(vious substitution command on the current line.)-.25 E F2 +('<character>)102 396 Q(`<character>)102 408 Q F0(Return to a conte)131 420 Q +(xt mark)-.15 E(ed by the character)-.1 E F1(<character>)2.5 E F0(.)A F2 +([count] \()102 432 Q F0(Back up)131 444 Q F1(count)2.5 E F0(sentences.)2.5 E +F2([count] \))102 456 Q F0(Mo)131 468 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E +F1(count)2.5 E F0(sentences.)2.5 E F2([count] ,)102 480 Q F0(Re)131 492 Q -.15 +(ve)-.25 G(rse \214nd character).15 E F1(count)2.5 E F0(times.)2.5 E F2 +([count] -)102 504 Q F0(Mo)131 516 Q .3 -.15(ve t)-.15 H 2.5<6f8c>.15 G +(rst nonblank of the pre)172.37 516 Q(vious line,)-.25 E F1(count)2.5 E F0 +(times.)2.5 E F2([count] .)102 528 Q F0(Repeat the last)131 540 Q F3(vi)2.5 E +F0(command that modi\214ed te)2.5 E(xt.)-.15 E F2(/RE<carriage-r)102 552 Q +(etur)-.18 E(n>)-.15 E(/RE/ [offset]<carriage-r)102 564 Q(etur)-.18 E(n>)-.15 E +(?RE<carriage-r)102 576 Q(etur)-.18 E(n>)-.15 E(?RE? [offset]<carriage-r)102 +588 Q(etur)-.18 E(n>)-.15 E(N)102 600 Q(n)102 612 Q F0(Search forw)131 612 Q +(ard or backw)-.1 E(ard for a re)-.1 E(gular e)-.15 E(xpression.)-.15 E F2(0) +102 624 Q F0(Mo)131 624 Q .3 -.15(ve t)-.15 H 2.5(ot).15 G +(he \214rst character in the current line.)169.59 624 Q 26.22(:E)102 636 S -.15 +(xe)137.11 636 S(cute an e).15 E 2.5(xc)-.15 G(ommand.)193.73 636 Q F2 +([count] ;)102 648 Q F0(Repeat the last character \214nd)131 660 Q F1(count)2.5 +E F0(times.)2.5 E F2([count] < motion)102 672 Q F0 172.465(4.4BSD July)72 750 R +(15, 1994)2.5 E(4)535 750 Q EP +%%Page: 5 5 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Bold@0 SF +([count] > motion)102 96 Q F0(Shift lines left or right.)131 108 Q F1 2.5(@b) +102 120 S(uffer)119.16 120 Q F0(Ex)131 132 Q(ecute a named b)-.15 E(uf)-.2 E +(fer)-.25 E(.)-.55 E F1([count] A)102 144 Q F0 +(Enter input mode, appending the te)131 156 Q(xt after the end of the line.) +-.15 E F1([count] B)102 168 Q F0(Mo)131 180 Q .3 -.15(ve b)-.15 H(ackw).15 E +(ards)-.1 E/F2 10/Courier@0 SF(count)2.5 E F0(bigw)2.5 E(ords.)-.1 E F1([b)102 +192 Q(uffer] [count] C)-.2 E F0(Change te)131 204 Q +(xt from the current position to the end-of-line.)-.15 E F1([b)102 216 Q +(uffer] D)-.2 E F0(Delete te)131 228 Q +(xt from the current position to the end-of-line.)-.15 E F1([count] E)102 240 Q +F0(Mo)131 252 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E F2(count)2.5 E F0 +(end-of-bigw)2.5 E(ords.)-.1 E F1([count] F <character>)102 264 Q F0(Search)131 +276 Q F2(count)2.5 E F0(times backw)2.5 E(ard through the current line for)-.1 +E F2(<character>)2.5 E F0(.)A F1([count] G)102 288 Q F0(Mo)131 300 Q .3 -.15 +(ve t)-.15 H 2.5(ol).15 G(ine)169.59 300 Q F2(count)2.5 E F0 2.5(,o)C 2.5(rt) +224.31 300 S(he last line of the \214le if)232.92 300 Q F2(count)2.5 E F0 +(not speci\214ed.)2.5 E F1([count] H)102 312 Q F0(Mo)131 324 Q .3 -.15(ve t) +-.15 H 2.5(ot).15 G(he screen line)169.59 324 Q F2(count - 1)2.5 E F0 +(lines belo)2.5 E 2.5(wt)-.25 G(he top of the screen.)334.43 324 Q F1 +([count] I)102 336 Q F0(Enter input mode, inserting the te)131 348 Q +(xt at the be)-.15 E(ginning of the line.)-.15 E F1([count] J)102 360 Q F0 +(Join lines.)131 372 Q F1([count] L)102 384 Q F0(Mo)131 396 Q .3 -.15(ve t)-.15 +H 2.5(ot).15 G(he screen line)169.59 396 Q F2(count - 1)2.5 E F0(lines abo)2.5 +E .3 -.15(ve t)-.15 H(he bottom of the screen.).15 E F1(M)102 408 Q F0(Mo)131 +408 Q .3 -.15(ve t)-.15 H 2.5(ot).15 G +(he screen line in the middle of the screen.)169.59 408 Q F1([count] O)102 420 +Q F0(Enter input mode, appending te)131 432 Q(xt in a ne)-.15 E 2.5(wl)-.25 G +(ine abo)305.86 432 Q .3 -.15(ve t)-.15 H(he current line.).15 E F1([b)102 444 +Q(uffer] P)-.2 E F0(Insert te)131 456 Q(xt from a b)-.15 E(uf)-.2 E(fer)-.25 E +(.)-.55 E F1(Q)102 468 Q F0(Exit)131 468 Q/F3 10/Courier-Bold@0 SF(vi)2.5 E F0 +(\(or visual\) mode and switch to)2.5 E F3(ex)2.5 E F0(mode.)2.5 E F1 +([count] R)102 480 Q F0 +(Enter input mode, replacing the characters in the current line.)131 492 Q F1 +([b)102 504 Q(uffer] [count] S)-.2 E F0(Substitute)131 516 Q F2(count)2.5 E F0 +(lines.)2.5 E F1([count] T <character>)102 528 Q F0 2.78(Search backw)131 540 R +(ards,)-.1 E F2(count)5.28 E F0 2.779 +(times, through the current line for the character)5.28 F/F4 10/Times-Italic@0 +SF(after)5.279 E F0 2.779(the speci\214ed)5.279 F F2(<character>)131 552 Q F0 +(.)A F1(U)102 564 Q F0 +(Restore the current line to its state before the cursor last mo)131 564 Q -.15 +(ve)-.15 G 2.5(dt).15 G 2.5(oi)388.99 564 S(t.)399.27 564 Q F1([count] W)102 +576 Q F0(Mo)131 588 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E F2(count)2.5 E F0 +(bigw)2.5 E(ords.)-.1 E F1([b)102 600 Q(uffer] [count] X)-.2 E F0(Delete)131 +612 Q F2(count)2.5 E F0(characters before the cursor)2.5 E(.)-.55 E F1([b)102 +624 Q(uffer] [count] Y)-.2 E F0(Cop)131 636 Q 2.5(y\()-.1 G(or `)158.4 636 Q +(`yank')-.74 E('\))-.74 E F2(count)2.5 E F0(lines into the speci\214ed b)2.5 E +(uf)-.2 E(fer)-.25 E(.)-.55 E F1(ZZ)102 648 Q F0(Write the \214le and e)131 648 +Q(xit)-.15 E F3(vi)2.5 E F0(.)A F1([count] [[)102 660 Q F0(Back up)131 672 Q F2 +(count)2.5 E F0(section boundaries.)2.5 E F1([count] ]])102 684 Q F0 172.465 +(4.4BSD July)72 750 R(15, 1994)2.5 E(5)535 750 Q EP +%%Page: 6 6 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Mo)131 96 Q .3 -.15(ve f)-.15 H +(orw).15 E(ard)-.1 E/F1 10/Courier@0 SF(count)2.5 E F0(section boundaries.)2.5 +E/F2 10/Times-Bold@0 SF(^)102 108 Q F0(Mo)131 108 Q .3 -.15(ve t)-.15 H 2.5 +<6f8c>.15 G(rst nonblank character on the current line.)172.37 108 Q F2 +([count] _)102 120 Q F0(Mo)131 132 Q .3 -.15(ve d)-.15 H -.25(ow).15 G(n).25 E +F1(count - 1)2.5 E F0(lines, to the \214rst nonblank character)2.5 E(.)-.55 E +F2([count] a)102 144 Q F0(Enter input mode, appending the te)131 156 Q +(xt after the cursor)-.15 E(.)-.55 E F2([count] b)102 168 Q F0(Mo)131 180 Q .3 +-.15(ve b)-.15 H(ackw).15 E(ards)-.1 E F1(count)2.5 E F0 -.1(wo)2.5 G(rds.).1 E +F2([b)102 192 Q(uffer] [count] c motion)-.2 E F0(Change a re)131 204 Q +(gion of te)-.15 E(xt.)-.15 E F2([b)102 216 Q(uffer] [count] d motion)-.2 E F0 +(Delete a re)131 228 Q(gion of te)-.15 E(xt.)-.15 E F2([count] e)102 240 Q F0 +(Mo)131 252 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E F1(count)2.5 E F0 +(end-of-w)2.5 E(ords.)-.1 E F2([count] f<character>)102 264 Q F0(Search forw) +131 276 Q(ard,)-.1 E F1(count)2.5 E F0 +(times, through the rest of the current line for)2.5 E F1(<character>)2.5 E F0 +(.)A F2([count] i)102 288 Q F0(Enter input mode, inserting the te)131 300 Q +(xt before the cursor)-.15 E(.)-.55 E F2 2.5(m<)102 312 S(character>)118.53 312 +Q F0(Sa)131 324 Q .3 -.15(ve t)-.2 H(he current conte).15 E +(xt \(line and column\) as)-.15 E F1(<character>)2.5 E F0(.)A F2([count] o)102 +336 Q F0(Enter input mode, appending te)131 348 Q(xt in a ne)-.15 E 2.5(wl)-.25 +G(ine under the current line.)305.86 348 Q F2([b)102 360 Q(uffer] p)-.2 E F0 +(Append te)131 372 Q(xt from a b)-.15 E(uf)-.2 E(fer)-.25 E(.)-.55 E F2 +([count] r <character>)102 384 Q F0(Replace)131 396 Q F1(count)2.5 E F0 +(characters.)2.5 E F2([b)102 408 Q(uffer] [count] s)-.2 E F0(Substitute)131 420 +Q F1(count)2.5 E F0 +(characters in the current line starting with the current character)2.5 E(.) +-.55 E F2([count] t <character>)102 432 Q F0 3.435(Search forw)131 444 R(ard,) +-.1 E F1(count)5.935 E F0 3.435 +(times, through the current line for the character immediately)5.935 F/F3 10 +/Times-Italic@0 SF(befor)5.935 E(e)-.37 E F1(<character>)131 456 Q F0(.)A F2(u) +102 468 Q F0(Undo the last change made to the \214le.)131 468 Q F2([count] w) +102 480 Q F0(Mo)131 492 Q .3 -.15(ve f)-.15 H(orw).15 E(ard)-.1 E F1(count)2.5 +E F0 -.1(wo)2.5 G(rds.).1 E F2([b)102 504 Q(uffer] [count] x)-.2 E F0(Delete) +131 516 Q F1(count)2.5 E F0(characters.)2.5 E F2([b)102 528 Q +(uffer] [count] y motion)-.2 E F0(Cop)131 540 Q 2.5(y\()-.1 G(or `)158.4 540 Q +(`yank')-.74 E('\) a te)-.74 E(xt re)-.15 E(gion speci\214ed by the)-.15 E F1 +(count)2.5 E F0(and motion into a b)2.5 E(uf)-.2 E(fer)-.25 E(.)-.55 E F2 +([count1] z [count2] -|.|+|^|<carriage-r)102 552 Q(etur)-.18 E(n>)-.15 E F0 +(Redra)131 564 Q 1.3 -.65(w, o)-.15 H +(ptionally repositioning and resizing the screen.).65 E F2([count] {)102 576 Q +F0(Mo)131 588 Q .3 -.15(ve b)-.15 H(ackw).15 E(ard)-.1 E F1(count)2.5 E F0 +(paragraphs.)2.5 E F2([count] |)102 600 Q F0(Mo)131 612 Q .3 -.15(ve t)-.15 H +2.5(oas).15 G(peci\214c)177.64 612 Q F3(column)2.5 E F0 +(position on the current line.)2.5 E F2([count] })102 624 Q F0(Mo)131 636 Q .3 +-.15(ve f)-.15 H(orw).15 E(ard)-.1 E F1(count)2.5 E F0(paragraphs.)2.5 E F2 +([count] ~)102 648 Q F0(Re)131 660 Q -.15(ve)-.25 G(rse the case of the ne).15 +E(xt)-.15 E F1(count)2.5 E F0(character\(s\).)2.5 E F2([count] ~ motion)102 672 +Q F0 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(6)535 750 Q EP +%%Page: 7 7 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Re)131 96 Q -.15(ve)-.25 G +(rse the case of the characters in a te).15 E(xt re)-.15 E +(gion speci\214ed by the)-.15 E/F1 10/Courier@0 SF(count)2.5 E F0(and)2.5 E F1 +(motion)2.5 E F0(.)A/F2 10/Times-Bold@0 SF(<interrupt>)102 108 Q F0 +(Interrupt the current operation.)131 120 Q F2 1.666(VI TEXT INPUT COMMANDS)72 +144 R F0(The follo)102 156 Q(wing section describes the commands a)-.25 E -.25 +(va)-.2 G(ilable in the te).25 E(xt input mode of the)-.15 E/F3 10 +/Courier-Bold@0 SF(vi)2.5 E F0(editor)2.5 E(.)-.55 E F2(<nul>)102 174 Q F0 +(Replay the pre)131 186 Q(vious input.)-.25 E F2(<contr)102 198 Q(ol-D>)-.18 E +F0(Erase the pre)131 210 Q(vious autoindent character)-.25 E(.)-.55 E F2 +(^<contr)102 222 Q(ol-D>)-.18 E F0 +(Erase all of the autoindent characters, and reset the autoindent le)131 234 Q +-.15(ve)-.25 G(l.).15 E F2(0<contr)102 246 Q(ol-D>)-.18 E F0 +(Erase all of the autoindent characters.)131 258 Q F2(<contr)102 270 Q(ol-T>) +-.18 E F0 .076(Insert suf)131 282 R(\214cient)-.25 E F1(<tab>)2.576 E F0(and) +2.576 E F1(<space>)2.576 E F0 .076(characters to mo)2.576 F .376 -.15(ve t)-.15 +H .076(he cursor forw).15 F .075(ard to a column immediate-)-.1 F +(ly after the ne)131 294 Q(xt column which is an e)-.15 E -.15(ve)-.25 G 2.5 +(nm).15 G(ultiple of the)305.7 294 Q F2(shiftwidth)2.5 E F0(option.)2.5 E F2 +(<erase>)102 306 Q(<contr)102 318 Q(ol-H>)-.18 E F0(Erase the last character) +131 330 Q(.)-.55 E F2(<literal next>)102 342 Q F0(Quote the ne)131 354 Q +(xt character)-.15 E(.)-.55 E F2(<escape>)102 366 Q F0(Resolv)131 378 Q 2.5(ea) +-.15 G(ll te)170.01 378 Q +(xt input into the \214le, and return to command mode.)-.15 E F2(<line erase>) +102 390 Q F0(Erase the current line.)131 402 Q F2(<contr)102 414 Q(ol-W>)-.18 E +(<w)102 426 Q(ord erase>)-.1 E F0(Erase the last w)131 438 Q 2.5(ord. The)-.1 F +(de\214nition of w)2.5 E(ord is dependent on the)-.1 E F2(altwerase)2.5 E F0 +(and)2.5 E F2(ttywerase)2.5 E F0(options.)2.5 E F2(<contr)102 450 Q +(ol-X>[0-9A-F)-.18 E(a-f])-.25 E/F4 10/Symbol SF(*)A F0 +(Insert a character with the speci\214ed he)131 462 Q(xadecimal v)-.15 E +(alue into the te)-.25 E(xt.)-.15 E F2(<interrupt>)102 474 Q F0(Interrupt te) +131 486 Q(xt input mode, returning to command mode.)-.15 E F2 1.666 +(EX COMMANDS)72 510 R F0 .163(The follo)102 522 R .163 +(wing section describes the commands a)-.25 F -.25(va)-.2 G .163(ilable in the) +.25 F F3(ex)2.663 E F0(editor)2.663 E 5.163(.I)-.55 G 2.663(ne)405.333 522 S +.164(ach entry belo)417.436 522 R 1.464 -.65(w, t)-.25 H .164(he tag line is) +.65 F 2.5(au)102 534 S(sage synopsis for the command.)113.94 534 Q F2 +(<end-of-\214le>)102 558 Q F0(Scroll the screen.)131 570 Q F2 2.5(!a)102 582 S +-.1(rg)112.83 582 S(ument\(s\)).1 E([range]! ar)102 594 Q(gument\(s\))-.1 E F0 +(Ex)131 606 Q +(ecute a shell command, or \214lter lines through a shell command.)-.15 E F2(") +102 618 Q F0 2.5(Ac)131 618 S(omment.)145.16 618 Q F2 +([range] nu[mber] [count] [\215ags])102 630 Q([range] # [count] [\215ags])102 +642 Q F0(Display the selected lines, each preceded with its line number)131 654 +Q(.)-.55 E F2 2.5(@b)102 666 S(uffer)119.16 666 Q F4(*)102 678 Q F2 -.2(bu)2.5 +G(ffer).2 E F0 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(7)535 750 Q EP +%%Page: 8 8 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Ex)131 96 Q(ecute a b)-.15 E(uf) +-.2 E(fer)-.25 E(.)-.55 E/F1 10/Times-Bold@0 SF([range] d[elete] [b)102 108 Q +(uffer] [count] [\215ags])-.2 E F0(Delete the lines from the \214le.)131 120 Q +F1(di[splay] b[uffers] | s[cr)102 132 Q(eens] | t[ags])-.18 E F0(Display b)131 +144 Q(uf)-.2 E(fers, screens or tags.)-.25 E F1(e[dit][!] [+cmd] [\214le])102 +156 Q(ex[!] [+cmd] [\214le])102 168 Q F0(Edit a dif)131 180 Q(ferent \214le.) +-.25 E F1(exu[sage] [command])102 192 Q F0(Display usage for an)131 204 Q/F2 10 +/Courier-Bold@0 SF(ex)2.5 E F0(command.)2.5 E F1(f[ile] [\214le])102 216 Q F0 +(Display and optionally change the \214le name.)131 228 Q F1(fg [name])102 240 +Q F2(Vi)131 252 Q F0(mode only)2.5 E 5(.F)-.65 G(ore)200.26 252 Q +(ground the speci\214ed screen.)-.15 E F1([range] g[lobal] /patter)102 264 Q +(n/ [commands])-.15 E([range] v /patter)102 276 Q(n/ [commands])-.15 E F0 +(Apply commands to lines matching \(or not matching\) a pattern.)131 288 Q F1 +(he[lp])102 300 Q F0(Display a help message.)131 312 Q F1([line] i[nsert][!]) +102 324 Q F0(The input te)131 336 Q +(xt is inserted before the speci\214ed line.)-.15 E F1 +([range] j[oin][!] [count] [\215ags])102 348 Q F0(Join lines of te)131 360 Q +(xt together)-.15 E(.)-.55 E F1([range] l[ist] [count] [\215ags])102 372 Q F0 +(Display the lines unambiguously)131 384 Q(.)-.65 E F1(map[!] [lhs rhs])102 396 +Q F0(De\214ne or display maps \(for)131 408 Q F2(vi)2.5 E F0(only\).)2.5 E F1 +([line] ma[rk] <character>)102 420 Q([line] k <character>)102 432 Q F0 +(Mark the line with the mark)131 444 Q/F3 10/Courier@0 SF(<character>)2.5 E F0 +(.)A F1([range] m[o)102 456 Q -.1(ve)-.1 G 2.5(]l).1 G(ine)170.11 456 Q F0(Mo) +131 468 Q .3 -.15(ve t)-.15 H(he speci\214ed lines after the tar).15 E +(get line.)-.18 E F1(mk[exr)102 480 Q(c][!] \214le)-.18 E F0(Write the abbre) +131 492 Q(viations, editor options and maps to the speci\214ed \214le.)-.25 E +F1(n[ext][!] [\214le ...])102 504 Q F0(Edit the ne)131 516 Q +(xt \214le from the ar)-.15 E(gument list.)-.18 E F1([line] o[pen] /patter)102 +528 Q(n/ [\215ags])-.15 E F0(Enter open mode.)131 540 Q F1(pr)102 552 Q(e[ser) +-.18 E -.1(ve)-.1 G(]).1 E F0(Sa)131 564 Q .3 -.15(ve t)-.2 H +(he \214le in a form that can later be reco).15 E -.15(ve)-.15 G(red using the) +.15 E F2 -1.834(ex \255r)2.5 F F0(option.)2.5 E F1(pr)102 576 Q -.15(ev)-.18 G +([ious][!]).15 E F0(Edit the pre)131 588 Q(vious \214le from the ar)-.25 E +(gument list.)-.18 E F1([range] p[rint] [count] [\215ags])102 600 Q F0 +(Display the speci\214ed lines.)131 612 Q F1([line] pu[t] [b)102 624 Q(uffer]) +-.2 E F0(Append b)131 636 Q(uf)-.2 E(fer contents to the current line.)-.25 E +F1(q[uit][!])102 648 Q F0(End the editing session.)131 660 Q F1 +([line] r[ead][!] [\214le])102 672 Q F0 172.465(4.4BSD July)72 750 R(15, 1994) +2.5 E(8)535 750 Q EP +%%Page: 9 9 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R(Read a \214le.)131 96 Q/F1 10 +/Times-Bold@0 SF -.18(re)102 108 S(c[o).18 E -.1(ve)-.1 G(r] \214le).1 E F0 +(Reco)131 120 Q -.15(ve)-.15 G(r).15 E/F2 10/Courier@0 SF(file)2.5 E F0 +(if it w)2.5 E(as pre)-.1 E(viously sa)-.25 E -.15(ve)-.2 G(d.).15 E F1 -.18 +(re)102 132 S(s[ize] [+|-]size).18 E/F3 10/Courier-Bold@0 SF(Vi)131 144 Q F0 +(mode only)2.5 E 5(.G)-.65 G(ro)202.07 144 Q 2.5(wo)-.25 G 2.5(rs)224.87 144 S +(hrink the current screen.)234.59 144 Q F1 -.18(re)102 156 S(w[ind][!]).18 E F0 +(Re)131 168 Q(wind the ar)-.25 E(gument list.)-.18 E F1(se[t] [option[=[v)102 +180 Q(alue]] ...] [nooption ...] [option? ...] [all])-.1 E F0 +(Display or set editor options.)131 192 Q F1(sh[ell])102 204 Q F0 +(Run a shell program.)131 216 Q F1(so[ur)102 228 Q(ce] \214le)-.18 E F0 +(Read and e)131 240 Q -.15(xe)-.15 G(cute).15 E F3(ex)2.5 E F0 +(commands from a \214le.)2.5 E F1(sp[lit] [\214le ...])102 252 Q F3(Vi)131 264 +Q F0(mode only)2.5 E 5(.S)-.65 G(plit the screen.)200.41 264 Q F1 +([range] s[ubstitute] [/patter)102 276 Q(n/r)-.15 E +(eplace/] [options] [count] [\215ags])-.18 E +([range] & [options] [count] [\215ags])102 288 Q +([range] ~ [options] [count] [\215ags])102 300 Q F0(Mak)131 312 Q 2.5(es)-.1 G +(ubstitutions.)160.06 312 Q F1(su[spend][!])102 324 Q(st[op][!])102 336 Q +(<suspend>)102 348 Q F0(Suspend the edit session.)131 360 Q F1 +(ta[g][!] tagstring)102 372 Q F0 +(Edit the \214le containing the speci\214ed tag.)131 384 Q F1 +(tagp[op][!] [\214le | number])102 396 Q F0 +(Pop to the speci\214ed tag in the tags stack.)131 408 Q F1(unm[ap][!] lhs)102 +420 Q F0(Unmap a mapped string.)131 432 Q F1 -.1(ve)102 444 S([rsion]).1 E F0 +(Display the v)131 456 Q(ersion of the)-.15 E F3(ex/vi)2.5 E F0(editor)2.5 E(.) +-.55 E F1([line] vi[sual] [type] [count] [\215ags])102 468 Q F3(Ex)131 480 Q F0 +(mode only)2.5 E 5(.E)-.65 G(nter)200.96 480 Q F3(vi)2.5 E F0(.)A F1 +(vi[sual][!] [+cmd] [\214le])102 492 Q F3(Vi)131 504 Q F0(mode only)2.5 E 5(.E) +-.65 G(dit a ne)200.96 504 Q 2.5<778c>-.25 G(le.)245.43 504 Q F1 +(viu[sage] [command])102 516 Q F0(Display usage for a)131 528 Q F3(vi)2.5 E F0 +(command.)2.5 E F1([range] w[rite][!] [>>] [\214le])102 540 Q +([range] w[rite] [!] [\214le])102 552 Q([range] wn[!] [>>] [\214le])102 564 Q +([range] wq[!] [>>] [\214le])102 576 Q F0(Write the \214le.)131 588 Q F1 +([range] x[it][!] [\214le])102 600 Q F0 +(Write the \214le if it has been modi\214ed.)131 612 Q F1([range] ya[nk] [b)102 +624 Q(uffer] [count])-.2 E F0(Cop)131 636 Q 2.5(yt)-.1 G +(he speci\214ed lines to a b)157.85 636 Q(uf)-.2 E(fer)-.25 E(.)-.55 E F1 +([line] z [type] [count] [\215ags])102 648 Q F0(Adjust the windo)131 660 Q -.65 +(w.)-.25 G 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(9)535 750 Q EP +%%Page: 10 10 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Bold@0 SF 1.666 +(SET OPTIONS)72 96 R F0 .519(There are a lar)102 108 R .518 +(ge number of options that may be set \(or unset\) to change the editor')-.18 F +3.018(sb)-.55 G(eha)453.614 108 Q(vior)-.2 E 5.518(.T)-.55 G .518(his section) +496.982 108 R(describes the options, their abbre)102 120 Q +(viations and their def)-.25 E(ault v)-.1 E(alues.)-.25 E .095 +(In each entry belo)102 138 R 1.395 -.65(w, t)-.25 H .095 +(he \214rst part of the tag line is the full name of the option, follo).65 F +.095(wed by an)-.25 F 2.595(ye)-.15 G(qui)487.915 138 Q -.25(va)-.25 G .095 +(lent ab-).25 F(bre)102 150 Q 3.034(viations. The)-.25 F .534 +(part in square brack)3.034 F .533(ets is the def)-.1 F .533(ault v)-.1 F .533 +(alue of the option.)-.25 F .533(Most of the options are boolean,)5.533 F +(i.e. the)102 162 Q 2.5(ya)-.15 G(re either on or of)140.73 162 Q +(f, and do not ha)-.25 E .3 -.15(ve a)-.2 H 2.5(na).15 G(ssociated v)298.14 162 +Q(alue.)-.25 E(Options apply to both)102 180 Q/F2 10/Courier-Bold@0 SF(ex)2.5 E +F0(and)2.5 E F2(vi)2.5 E F0(modes, unless otherwise speci\214ed.)2.5 E F1 +(altwerase [off])102 204 Q F2(Vi)131 216 Q F0(only)2.5 E 5(.S)-.65 G +(elect an alternate w)175.69 216 Q(ord erase algorithm.)-.1 E F1 +(autoindent, ai [off])102 228 Q F0(Automatically indent ne)131 240 Q 2.5(wl) +-.25 G(ines.)239.91 240 Q F1(autoprint, ap [off])102 252 Q F2(Ex)131 264 Q F0 +(only)2.5 E 5(.D)-.65 G(isplay the current line automatically)177.35 264 Q(.) +-.65 E F1(auto)102 276 Q(write, aw [off])-.1 E F0 +(Write modi\214ed \214les automatically when changing \214les.)131 288 Q F1 +(beautify)102 300 Q 2.5(,b)-.55 G 2.5(f[)147.01 300 S(off])156.17 300 Q F0 +(Discard control characters.)131 312 Q F1(cdpath [en)102 324 Q(vir)-.4 E +(onment v)-.18 E(ariable CDP)-.1 E -.95(AT)-.74 G(H, or curr).95 E(ent dir)-.18 +E(ectory])-.18 E F0(The directory paths used as path pre\214x)131 336 Q +(es for the)-.15 E F1(cd)2.5 E F0(command.)2.5 E F1(columns, co [80])102 348 Q +F0(Set the number of columns in the screen.)131 360 Q F1(comment [off])102 372 +Q F2(Vi)131 384 Q F0(only)2.5 E 5(.S)-.65 G(kip leading comments in \214les.) +175.69 384 Q F1(dir)102 396 Q(ectory)-.18 E 2.5(,d)-.55 G(ir [en)151.26 396 Q +(vir)-.4 E(onment v)-.18 E(ariable TMPDIR, or /tmp])-.1 E F0 +(The directory where temporary \214les are created.)131 408 Q F1 +(edcompatible, ed [off])102 420 Q F0 .279(Remember the v)131 432 R .279 +(alues of the `)-.25 F(`c')-.74 E 2.779('a)-.74 G .279(nd `)270.344 432 R(`g') +-.74 E 2.779('s)-.74 G(uf)306.632 432 Q .279(\214ces to the)-.25 F F1 +(substitute)2.78 E F0 .28(commands, instead of initializing)2.78 F +(them as unset for each ne)131 444 Q 2.5(wc)-.25 G(ommand.)246.27 444 Q F1(err) +102 456 Q(orbells, eb [off])-.18 E F2(Ex)131 468 Q F0(only)2.5 E 5(.A)-.65 G +(nnounce error messages with a bell.)177.35 468 Q F1(exr)102 480 Q(c, ex [off]) +-.18 E F0(Ne)131 492 Q -.15(ve)-.25 G 2.5(rr).15 G +(ead startup \214les in the local directory)160.86 492 Q(.)-.65 E F1 +(extended [off])102 504 Q F0(Re)131 516 Q(gular e)-.15 E(xpressions are e)-.15 +E(xtended \(i.e.)-.15 E/F3 10/Courier@0 SF(egrep)5 E F0(\(1\) style\) e)A +(xpressions.)-.15 E F1(\215ash [on])102 528 Q F0 +(Flash the screen instead of beeping the k)131 540 Q -.15(ey)-.1 G +(board on error).15 E(.)-.55 E F1(hardtabs, ht [8])102 552 Q F0 +(Set the spacing between hardw)131 564 Q(are tab settings.)-.1 E F1(ignor)102 +576 Q(ecase, ic [off])-.18 E F0(Ignore case dif)131 588 Q(ferences in re)-.25 E +(gular e)-.15 E(xpressions.)-.15 E F1 -.1(ke)102 600 S(ytime [6]).1 E F0 +(The 10th')131 612 Q 2.5(so)-.55 G 2.5(fas)181 612 S(econd)197.66 612 Q F2 +(ex/vi)2.5 E F0 -.1(wa)2.5 G(its for a subsequent k).1 E .3 -.15(ey t)-.1 H 2.5 +(oc).15 G(omplete a k)379.5 612 Q .3 -.15(ey m)-.1 H(apping.).15 E F1 +(leftright [off])102 624 Q F2(Vi)131 636 Q F0(only)2.5 E 5(.D)-.65 G 2.5(ol) +177.35 636 S(eft-right scrolling.)187.63 636 Q F1(lines, li [24])102 648 Q F2 +(Vi)131 660 Q F0(only)2.5 E 5(.S)-.65 G(et the number of lines in the screen.) +175.69 660 Q F1(lisp [off])102 672 Q F2(Vi)131 684 Q F0(only)2.5 E 5(.M)-.65 G +(odify v)179.02 684 Q(arious search commands and options to w)-.25 E +(ork with Lisp.)-.1 E 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(10)530 750 Q +EP +%%Page: 11 11 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Italic@0 SF +(This option is not yet implemented.)131 96 Q/F2 10/Times-Bold@0 SF(list [off]) +102 108 Q F0(Display lines in an unambiguous f)131 120 Q(ashion.)-.1 E F2 +(magic [on])102 132 Q F0 -.35(Tr)131 144 S +(eat certain characters specially in re).35 E(gular e)-.15 E(xpressions.)-.15 E +F2(matchtime [7])102 156 Q/F3 10/Courier-Bold@0 SF(Vi)131 168 Q F0(only)2.885 E +5.385(.T)-.65 G .385(he 10th')177.01 168 R 2.885(so)-.55 G 2.885(fas)221.67 168 +S(econd)239.1 168 Q F3(ex/vi)2.884 E F0 .384 +(pauses on the matching character when the)2.884 F F2(sho)2.884 E(wmatch)-.1 E +F0(op-)2.884 E(tion is set.)131 180 Q F2(mesg [on])102 192 Q F0 +(Permit messages from other users.)131 204 Q F2(modelines, modeline [off])102 +216 Q F0(Read the \214rst and last fe)131 228 Q 2.5(wl)-.25 G +(ines of each \214le for)240.18 228 Q F3(ex)2.5 E F0(commands.)2.5 E F1 +(This option will ne)131 246 Q(ver be implemented.)-.15 E F2(number)102 258 Q +2.5(,n)-.92 G 2.5(u[)145.53 258 S(off])156.92 258 Q F0 +(Precede each line displayed with its current line number)131 270 Q(.)-.55 E F2 +(octal [off])102 282 Q F0(Display unkno)131 294 Q +(wn characters as octal numbers, instead of the def)-.25 E(ault he)-.1 E +(xadecimal.)-.15 E F2(open [on])102 306 Q F3(Ex)131 318 Q F0(only)2.5 E 5(.I) +-.65 G 2.5(ft)173.46 318 S(his option is not set, the)182.07 318 Q F2(open)2.5 +E F0(and)2.5 E F2(visual)2.5 E F0(commands are disallo)2.5 E(wed.)-.25 E F2 +(optimize, opt [on])102 330 Q F3(Vi)131 342 Q F0(only)2.5 E 5(.O)-.65 G +(ptimize te)177.35 342 Q(xt throughput to dumb terminals.)-.15 E F1 +(This option is not yet implemented.)131 360 Q F2 +(paragraphs, para [IPLPPPQPP LIpplpipbp])102 372 Q F3(Vi)131 384 Q F0(only)2.5 +E 5(.D)-.65 G(e\214ne additional paragraph boundaries for the)177.35 384 Q F2 +({)2.5 E F0(and)2.5 E F2(})2.5 E F0(commands.)2.5 E F2(pr)102 396 Q(ompt [on]) +-.18 E F3(Ex)131 408 Q F0(only)2.5 E 5(.D)-.65 G(isplay a command prompt.) +177.35 408 Q F2 -.18(re)102 420 S(adonly).18 E 2.5(,r)-.55 G 2.5(o[)148.31 420 +S(off])159.14 420 Q F0(Mark the \214le as read-only)131 432 Q(.)-.65 E F2 -.18 +(re)102 444 S(cdir [/v).18 E(ar/tmp/vi.r)-.1 E(eco)-.18 E -.1(ve)-.1 G(r]).1 E +F0(The directory where reco)131 456 Q -.15(ve)-.15 G(ry \214les are stored.).15 +E F2 -.18(re)102 468 S(draw).18 E 2.5(,r)-.55 G 2.5(e[)141.63 468 S(off])151.9 +468 Q F3(Vi)131 480 Q F0(only)2.5 E 5(.S)-.65 G +(imulate an intelligent terminal on a dumb one.)175.69 480 Q F1 +(This option is not yet implemented.)131 498 Q F2 -.18(re)102 510 S(map [on]) +.18 E F0(Remap k)131 522 Q -.15(ey)-.1 G 2.5(su).15 G(ntil resolv)187.41 522 Q +(ed.)-.15 E F2 -.18(re)102 534 S(port [5]).18 E F0 +(Set the number of lines about which the editor reports changes or yanks.)131 +546 Q F2(ruler [off])102 558 Q F3(Vi)131 570 Q F0(only)2.5 E 5(.D)-.65 G +(isplay a ro)177.35 570 Q(w/column ruler on the colon command line.)-.25 E F2 +(scr)102 582 Q(oll, scr [windo)-.18 E 2.5(w/2)-.1 G(])194.77 582 Q F0 +(Set the number of lines scrolled.)131 594 Q F2(sections, sect [NHSHH HUnhsh]) +102 606 Q F3(Vi)131 618 Q F0(only)2.5 E 5(.D)-.65 G +(e\214ne additional section boundaries for the)177.35 618 Q F2([[)2.5 E F0(and) +2.5 E F2(]])2.5 E F0(commands.)2.5 E F2(shell, sh [en)102 630 Q(vir)-.4 E +(onment v)-.18 E(ariable SHELL, or /bin/sh])-.1 E F0 +(Select the shell used by the editor)131 642 Q(.)-.55 E F2(shiftwidth, sw [8]) +102 654 Q F0(Set the autoindent and shift command indentation width.)131 666 Q +F2(sho)102 678 Q(wdirty [off])-.1 E F0 172.465(4.4BSD July)72 750 R(15, 1994) +2.5 E(11)530 750 Q EP +%%Page: 12 12 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Courier-Bold@0 SF(Vi)131 96 +Q F0(only)2.5 E 5(.D)-.65 G(isplay an asterisk on the colon command line if th\ +e \214le has been modi\214ed.)177.35 96 Q/F2 10/Times-Bold@0 SF(sho)102 108 Q +(wmatch, sm [off])-.1 E F1(Vi)131 120 Q F0(only)2.5 E 5(.N)-.65 G +(ote matching `)177.35 120 Q(`{')-.74 E 2.5('a)-.74 G(nd `)255.37 120 Q(`\(') +-.74 E 2.5('f)-.74 G(or `)288.87 120 Q(`}')-.74 E 2.5('a)-.74 G(nd `)323.28 120 +Q(`\)')-.74 E 2.5('c)-.74 G(haracters.)357.89 120 Q F2(sho)102 132 Q +(wmode [off])-.1 E F1(Vi)131 144 Q F0(only)2.5 E 5(.D)-.65 G +(isplay the current editor mode \(command or input\).)177.35 144 Q F2(sidescr) +102 156 Q(oll [16])-.18 E F1(Vi)131 168 Q F0(only)2.5 E 5(.S)-.65 G +(et the amount a left-right scroll will shift.)175.69 168 Q F2(slo)102 180 Q +-.1(wo)-.1 G(pen, slo).1 E 2.5(w[)-.1 G(off])170.87 180 Q F0 +(Delay display updating during te)131 192 Q(xt input.)-.15 E/F3 10 +/Times-Italic@0 SF(This option is not yet implemented.)131 210 Q F2(sour)102 +222 Q(ceany [off])-.18 E F0(Read startup \214les not o)131 234 Q +(wned by the current user)-.25 E(.)-.55 E F3(This option will ne)131 252 Q +(ver be implemented.)-.15 E F2(tabstop, ts [8])102 264 Q F0 +(This option sets tab widths for the editor display)131 276 Q(.)-.65 E F2 +(taglength, tl [0])102 288 Q F0 +(Set the number of signi\214cant characters in tag names.)131 300 Q F2 +(tags, tag [tags /v)102 312 Q(ar/db/libc.tags /sys/k)-.1 E(er)-.1 E(n/tags]) +-.15 E F0(Set the list of tags \214les.)131 324 Q F2(term, ttytype, tty [en)102 +336 Q(vir)-.4 E(onment v)-.18 E(ariable TERM])-.1 E F0(Set the terminal type.) +131 348 Q F2(terse [off])102 360 Q F0 .759 +(This option has historically made editor messages less v)131 372 R 3.259 +(erbose. It)-.15 F .76(has no ef)3.259 F .76(fect in this implementa-)-.25 F +(tion.)131 384 Q F2(tildeop)102 396 Q F0(Modify the)131 408 Q F2(~)2.5 E F0 +(command to tak)2.5 E 2.5(ea)-.1 G 2.5(na)259.77 408 S(ssociated motion.)271.71 +408 Q F2(timeout, to [on])102 420 Q F0 -.35(Ti)131 432 S(me out on k).35 E -.15 +(ey)-.1 G 2.5(sw).15 G(hich may be mapped.)209.84 432 Q F2(ttywerase [off])102 +444 Q F1(Vi)131 456 Q F0(only)2.5 E 5(.S)-.65 G +(elect an alternate erase algorithm.)175.69 456 Q F2 -.1(ve)102 468 S +(rbose [off]).1 E F0(only)131 480 Q 5(.D)-.65 G(isplay an error message for e) +162.85 480 Q -.15(ve)-.25 G(ry error).15 E(.)-.55 E F2(w300 [no default])102 +492 Q F1(Vi)131 504 Q F0(only)2.5 E 5(.S)-.65 G(et the windo)175.69 504 Q 2.5 +(ws)-.25 G(ize if the baud rate is less than 1200 baud.)238.49 504 Q F2 +(w1200 [no default])102 516 Q F1(Vi)131 528 Q F0(only)2.5 E 5(.S)-.65 G +(et the windo)175.69 528 Q 2.5(ws)-.25 G +(ize if the baud rate is equal to 1200 baud.)238.49 528 Q F2 +(w9600 [no default])102 540 Q F1(Vi)131 552 Q F0(only)2.5 E 5(.S)-.65 G +(et the windo)175.69 552 Q 2.5(ws)-.25 G +(ize if the baud rate is greater than 1200 baud.)238.49 552 Q F2(war)102 564 Q +2.5(n[)-.15 G(on])129.9 564 Q F1(Ex)131 576 Q F0(only)2.979 E 5.479(.T)-.65 G +.479(his option causes a w)177.198 576 R .479 +(arning message to the terminal if the \214le has been modi\214ed, since it)-.1 +F -.1(wa)131 588 S 2.5(sl).1 G(ast written, before a)151.73 588 Q F2(!)2.5 E F0 +(command.)2.5 E F2(windo)102 600 Q 1.1 -.55(w, w, w)-.1 H 2.5(i[).55 G(en) +167.19 600 Q(vir)-.4 E(onment v)-.18 E(ariable LINES])-.1 E F0(Set the windo) +131 612 Q 2.5(ws)-.25 G(ize for the screen.)199.36 612 Q F2(wrapmar)102 624 Q +(gin, wm [0])-.1 E F1(Vi)131 636 Q F0(only)2.5 E 5(.B)-.65 G +(reak lines automatically when the)176.8 636 Q 2.5(yr)-.15 G +(each the right-hand mar)321.9 636 Q(gin.)-.18 E F2(wrapscan, ws [on])102 648 Q +F0(Set searches to wrap around the end or be)131 660 Q(ginning of the \214le.) +-.15 E F2(writeany)102 672 Q 2.5(,w)-.55 G 2.5(a[)151.44 672 S(off])162.27 672 +Q F0 -.45(Tu)131 684 S(rn of).45 E 2.5<668c>-.25 G(le-o)171.96 684 Q -.15(ve) +-.15 G(rwriting checks.).15 E 172.465(4.4BSD July)72 750 R(15, 1994)2.5 E(12) +530 750 Q EP +%%Page: 13 13 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R/F1 10/Times-Bold@0 SF(ENVIR)72 96 +Q(ONMENT)-.3 E 1.666(AL V)-.9 F(ARIABLES)-1.35 E/F2 10/Courier@0 SF(COLUMNS)102 +108 Q F0 .895(The number of columns on the screen.)161 108 R .896(This v)5.896 +F .896(alue o)-.25 F -.15(ve)-.15 G .896(rrides an).15 F 3.396(ys)-.15 G .896 +(ystem or terminal speci\214c)433.712 108 R -.25(va)161 120 S 5.317(lues. If) +.25 F 2.816(the COLUMNS en)5.317 F 2.816(vironmental v)-.4 F 2.816 +(ariable is not set when)-.25 F/F3 10/Courier-Bold@0 SF(ex/vi)5.316 E F0 2.816 +(runs, or the)5.316 F F1(columns)161 132 Q F0(option is e)2.5 E +(xplicitly reset by the user)-.15 E(,)-.4 E F3(ex/vi)2.5 E F0(enters the v)2.5 +E(alue into the en)-.25 E(vironment.)-.4 E F2(EXINIT)102 144 Q F0 2.5(Al)161 +144 S(ist of)173.5 144 Q F3(ex)2.5 E F0(startup commands, read if the v)2.5 E +(ariable)-.25 E F2(NEXINIT)2.5 E F0(is not set.)2.5 E F2(HOME)102 156 Q F0 .677 +(The user')161 156 R 3.177(sh)-.55 G .677(ome directory)211.234 156 R 3.177(,u) +-.65 G .678(sed as the initial directory path for the startup)277.758 156 R F2 +($HOME/.nexrc)3.178 E F0(and)161 168 Q F2($HOME/.exrc)2.865 E F0 2.865 +(\214les. This)2.865 F -.25(va)2.865 G .365(lue is also used as the def).25 F +.365(ault directory for the)-.1 F F3(vi)2.865 E F1(cd)2.865 E F0(com-)2.865 E +(mand.)161 180 Q F2(LINES)102 192 Q F0 .629(The number of ro)161 192 R .629 +(ws on the screen.)-.25 F .629(This v)5.629 F .629(alue o)-.25 F -.15(ve)-.15 G +.629(rrides an).15 F 3.13(ys)-.15 G .63(ystem or terminal speci\214c v)416.08 +192 R(al-)-.25 E 3.123(ues. If)161 204 R .623(the LINES en)3.123 F .623 +(vironmental v)-.4 F .623(ariable is not set when)-.25 F F3(ex/vi)3.122 E F0 +.622(runs, or the)3.122 F F1(lines)3.122 E F0 .622(option is)3.122 F -.15(ex) +161 216 S(plicitly reset by the user).15 E(,)-.4 E F3(ex/vi)2.5 E F0 +(enters the v)2.5 E(alue into the en)-.25 E(vironment.)-.4 E F2(NEXINIT)102 228 +Q F0 2.5(Al)161 228 S(ist of)173.5 228 Q F3(ex)2.5 E F0(startup commands.)2.5 E +F2(SHELL)102 240 Q F0(The user')161 240 Q 2.5(ss)-.55 G +(hell of choice \(see also the)208.77 240 Q F1(shell)2.5 E F0(option\).)2.5 E +F2(TERM)102 252 Q F0 1.338(The user')161 252 R 3.838(st)-.55 G 1.338 +(erminal type.)210.336 252 R 1.338(The def)6.338 F 1.338(ault is the type `)-.1 +F(`unkno)-.74 E(wn')-.25 E 1.339('. If the TERM en)-.74 F(vironmental)-.4 E +-.25(va)161 264 S .106(riable is not set when).25 F F3(ex/vi)2.606 E F0 .105 +(runs, or the)2.605 F F1(term)2.605 E F0 .105(option is e)2.605 F .105 +(xplicitly reset by the user)-.15 F(,)-.4 E F3(ex/vi)2.605 E F0(enters the v) +161 276 Q(alue into the en)-.25 E(vironment.)-.4 E F2(TMPDIR)102 288 Q F0 +(The location used to stored temporary \214les \(see also the)161 288 Q F1(dir) +2.5 E(ectory)-.18 E F0(option\).)2.5 E F1(ASYNCHR)72 312 Q 1.666(ONOUS EVENTS) +-.3 F F0(SIGALRM)102 324 Q F3(Vi/ex)167 324 Q F0 1.58(uses this signal for per\ +iodic backups of \214le modi\214cations and to display `)4.08 F(`b)-.74 E(usy') +-.2 E(')-.74 E(messages when operations are lik)167 336 Q(ely to tak)-.1 E 2.5 +(eal)-.1 G(ong time.)354.54 336 Q(SIGHUP)102 348 Q 18.61(SIGTERM If)102 360 R +.12(the current b)2.62 F(uf)-.2 E .12(fer has changed since it w)-.25 F .12 +(as last written in its entirety)-.1 F 2.62(,t)-.65 G .12 +(he editor attempts to)457.7 360 R(sa)167 372 Q .493 -.15(ve t)-.2 H .193 +(he modi\214ed \214le so it can be later reco).15 F -.15(ve)-.15 G 2.693 +(red. See).15 F(the)2.694 E F3(vi/ex)2.694 E F0 .194(Reference manual section) +2.694 F(entitled `)167 384 Q(`Reco)-.74 E -.15(ve)-.15 G(ry').15 E 2.5('f)-.74 +G(or more information.)255.19 384 Q 29.73(SIGINT When)102 396 R .594(an interr\ +upt occurs, the current operation is halted, and the editor returns to the com\ +-)3.094 F .364(mand le)167 408 R -.15(ve)-.25 G 2.864(l. If).15 F .364 +(interrupted during te)2.864 F .364(xt input, the te)-.15 F .364 +(xt already input is resolv)-.15 F .365(ed into the \214le as)-.15 F(if the te) +167 420 Q(xt input had been normally terminated.)-.15 E 12.51(SIGWINCH The)102 +432 R 2.772(screen is resized.)5.272 F 2.772(See the)7.772 F F3(vi/ex)5.272 E +F0 2.771(Reference manual section entitled `)5.272 F 2.771(`Sizing the)-.74 F +(Screen')167 444 Q 2.5('f)-.74 G(or more information.)205.96 444 Q(SIGCONT)102 +456 Q(SIGQ)102 468 Q(UIT)-.1 E(SIGTSTP)102 480 Q F3(Vi/ex)167 480 Q F0 +(ignores these signals.)2.5 E F1 -.1(BU)72 504 S(GS).1 E F0(See the \214le)102 +516 Q F2(nvi/docs/bugs.current)2.5 E F0(for a list of the kno)2.5 E(wn b)-.25 E +(ugs in this v)-.2 E(ersion.)-.15 E F1(FILES)72 540 Q F2(/bin/sh)102 552 Q F0 +(The def)221 552 Q(ault user shell.)-.1 E F2(/etc/vi.exrc)102 564 Q F0 +(System-wide vi startup \214le.)221 564 Q F2(/tmp)102 576 Q F0 -.7(Te)221 576 S +(mporary \214le directory).7 E(.)-.65 E F2(/var/tmp/vi.recover)102 588 Q F0 +(The def)5 E(ault reco)-.1 E -.15(ve)-.15 G(ry \214le directory).15 E(.)-.65 E +F2($HOME/.nexrc)102 600 Q F0(1st choice for user')221 600 Q 2.5(sh)-.55 G +(ome directory startup \214le.)308.76 600 Q F2($HOME/.exrc)102 612 Q F0 +(2nd choice for user')221 612 Q 2.5(sh)-.55 G(ome directory startup \214le.) +312.09 612 Q F2(.nexrc)102 624 Q F0 +(1st choice for local directory startup \214le.)221 624 Q F2(.exrc)102 636 Q F0 +(2nd choice for local directory startup \214le.)221 636 Q F1 1.666(SEE ALSO)72 +660 R F2(ctags)102 672 Q F0(\(1\),)A F2(more)5 E F0(\(1\),)A F2(curses)5 E F0 +(\(3\),)A F2(dbopen)5 E F0(\(3\))A(The `)102 696 Q(`V)-.74 E 2.5(iQ)-.6 G +(uick Reference')145.09 696 Q 2.5('c)-.74 G(ard.)218.2 696 Q 172.465 +(4.4BSD July)72 750 R(15, 1994)2.5 E(13)530 750 Q EP +%%Page: 14 14 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.834(EX/VI \( 1 \))72 48 R(BSD Reference Manual) +258.235 48 Q -.834(EX/VI \( 1 \))496.682 48 R -.74(``)102 96 S +(An Introduction to Display Editing with V).74 E(i')-.6 E(', found in the `) +-.74 E(`UNIX User')-.74 E 2.5(sM)-.55 G(anual Supplementary)412.2 96 Q +(Documents')102 108 Q 2.5('s)-.74 G +(ection of both the 4.3BSD and 4.4BSD manual sets.)159.86 108 Q +(This document is the closest thing a)5 E -.25(va)-.2 G(il-).25 E +(able to an introduction to the)102 120 Q/F1 10/Courier-Bold@0 SF(vi)2.5 E F0 +(screen editor)2.5 E(.)-.55 E -.74(``)102 144 S(Ex Reference Manual \(V).74 E +(ersion 3.7\)')-1.11 E(', found in the `)-.74 E(`UNIX User')-.74 E 2.5(sM)-.55 +G(anual Supplementary Documents')381.92 144 Q 2.5('s)-.74 G(ec-)526.99 144 Q +(tion of both the 4.3BSD and 4.4BSD manual sets.)102 156 Q +(This document is the \214nal reference for the)5 E F1(ex)2.5 E F0(editor)2.5 E +2.5(,a)-.4 G(s)528 156 Q(distrib)102 168 Q +(uted in most historic 4BSD and System V systems.)-.2 E -.74(``)102 192 S +(Edit: A tutorial').74 E(', found in the `)-.74 E(`UNIX User')-.74 E 2.5(sM) +-.55 G(anual Supplementary Documents')300.58 192 Q 2.5('s)-.74 G +(ection of the 4.3BSD)445.65 192 Q(manual set.)102 204 Q +(This document is an introduction to a simple v)5 E(ersion of the)-.15 E F1(ex) +2.5 E F0(screen editor)2.5 E(.)-.55 E -.74(``)102 228 S(Ex/V).74 E 2.5(iR)-.6 G +(eference Manual')140.38 228 Q(', found in the `)-.74 E(`UNIX User')-.74 E 2.5 +(sM)-.55 G(anual Supplementary Documents')339.39 228 Q 2.5('s)-.74 G +(ection of the)484.46 228 Q(4.4BSD manual set.)102 240 Q +(This document is the \214nal reference for the)5 E F1(nex/nvi)2.5 E F0(te)2.5 +E(xt editors, as distrib)-.15 E(uted in)-.2 E(4.4BSD and 4.4BSD-Lite.)102 252 Q +F1(Roff)102 270 Q F0(source for all of these documents is distrib)2.5 E +(uted with)-.2 E F1(nex/nvi)2.5 E F0(in the)2.5 E/F2 10/Courier@0 SF +(nvi/USD.doc)2.5 E F0(directory of the)2.5 E F1(nex/nvi)102 282 Q F0 +(source code.)2.5 E(The \214les `)102 306 Q(`auto)-.74 E(write')-.25 E(', `) +-.74 E(`input')-.74 E(', `)-.74 E(`quoting')-.74 E(', and `)-.74 E +(`structures')-.74 E(', found in the)-.74 E F2(nvi/docs/internals)2.5 E F0 +(direc-)2.5 E(tory of the)102 318 Q F1(nex/nvi)2.5 E F0(source code.)2.5 E/F3 +10/Times-Bold@0 SF(HIST)72 342 Q(OR)-.18 E(Y)-.35 E F0(The)102 354 Q F1 +(nex/nvi)2.5 E F0(replacements for the)2.5 E F1(ex/vi)2.5 E F0 +(editor \214rst appeared in 4.4BSD.)2.5 E F3(ST)72 378 Q(AND)-.9 E(ARDS)-.35 E +F1(Nex/nvi)102 390 Q F0 .1(is close to IEEE Std1003.2 \(`)2.6 F(`POSIX')-.74 E +2.6('\). That)-.74 F .1(document dif)2.6 F .1(fers from historical)-.25 F F1 +(ex/vi)2.6 E F0 .1(practice in)2.6 F(se)102 402 Q -.15(ve)-.25 G +(ral places; there are changes to be made on both sides.).15 E 172.465 +(4.4BSD July)72 750 R(15, 1994)2.5 E(14)530 750 Q EP +%%Trailer +end +%%EOF diff --git a/usr.bin/vi/USD.doc/vi.man/vi.1 b/usr.bin/vi/USD.doc/vi.man/vi.1 new file mode 100644 index 0000000..25f2a2c --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.man/vi.1 @@ -0,0 +1,1294 @@ +.\" Copyright (c) 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vi.1 8.12 (Berkeley) 7/15/94 +.\" +.Dd "July 15, 1994" +.Dt EX/VI 1 +.Os +.Sh NAME +.Nm ex, vi, view +.Nd text editors +.Sh SYNOPSIS +.Nm \&ex +.Op Fl eFRrsv +.Op Fl c Ar cmd +.Op Fl t Ar tag +.Op Fl w Ar size +.\".Op Fl X Ar \&aw +.Op Ar "file ..." +.Nm \&vi +.Op Fl eFRrv +.Op Fl c Ar cmd +.Op Fl t Ar tag +.Op Fl w Ar size +.\".Op Fl X Ar \&aw +.Op Ar "file ..." +.Nm view +.Op Fl eFRrv +.Op Fl c Ar cmd +.Op Fl t Ar tag +.Op Fl w Ar size +.\".Op Fl X Ar \&aw +.Op Ar "file ..." +.Sh DESCRIPTION +.Nm \&Vi +is a screen oriented text editor. +.Nm \&Ex +is a line-oriented text editor. +.Nm \&Ex +and +.Nm \&vi +are different interfaces to the same program, +and it is possible to switch back and forth during an edit session. +.Nm View +is the equivalent of using the +.Fl R +(read-only) option of +.Nm \&vi . +.Pp +This manual page is the one provided with the +.Nm nex/nvi +versions of the +.Nm ex/vi +text editors. +.Nm Nex/nvi +are intended as bug-for-bug compatible replacements for the original +Fourth Berkeley Software Distribution (4BSD) +.Nm \&ex +and +.Nm \&vi +programs. +For the rest of this manual page, +.Nm nex/nvi +is used only when it's necessary to distinguish it from the historic +implementations of +.Nm ex/vi . +.Pp +This manual page is intended for users already familiar with +.Nm ex/vi . +Anyone else should almost certainly read a good tutorial on the +editor before this manual page. +If you're in an unfamiliar environment, and you absolutely have to +get work done immediately, read the section after the options +description, entitled +.Dq "Fast Startup" . +It's probably enough to get you going. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl c +Execute +.Ar cmd +immediately after starting the edit session. +Particularly useful for initial positioning in the file, however +.Ar cmd +is not limited to positioning commands. +This is the POSIX 1003.2 interface for the historic +.Dq "+cmd" +syntax. +.Nm Nex/nvi +supports both the old and new syntax. +.It Fl e +Start editing in ex mode, as if the command name were +.Nm \&ex . +.It Fl F +Don't copy the entire file when first starting to edit. +(The default is to make a copy in case someone else modifies +the file during your edit session.) +.It Fl R +Start editing in read-only mode, as if the command name was +.Nm view , +or the readonly option was set. +.It Fl r +Recover the specified files, or, if no files are specified, +list the files that could be recovered. +If no recoverable files by the specified name exist, +the file is edited as if the +.Fl r +option had not been specified. +.It Fl s +Enter batch mode; applicable only to +.Nm \&ex +edit sessions. +Batch mode is useful when running +.Nm \&ex +scripts. +Prompts, informative messages and other user oriented message +are turned off, +and no startup files or environmental variables are read. +This is the POSIX 1003.2 interface for the historic +.Dq \&\- +argument. +.Nm \&Nex/nvi +supports both the old and new syntax. +.It Fl t +Start editing at the specified tag. +(See +.Xr ctags 1 ). +.It Fl w +Set the initial window size to the specified number of lines. +.It Fl v +Start editing in vi mode, as if the command name was +.Nm \&vi +or +.Nm view . +.It Fl X +Reserved for X11 interfaces. +.Em "No X11 support is currently implemented." +.El +.Pp +Command input for +.Nm ex/vi +is read from the standard input. +In the +.Nm \&vi +interface, it is an error if standard input is not a terminal. +In the +.Nm \&ex +interface, if standard input is not a terminal, +.Nm \&ex +will read commands from it regardless, however, the session will be a +batch mode session, exactly as if the +.Fl s +option had been specified. +.Pp +.Nm Ex/vi +exits 0 on success, and greater than 0 if an error occurs. +.Sh FAST STARTUP +This section will tell you the minimum amount that you need to +do simple editing tasks using +.Nm \&vi . +If you've never used any screen editor before, you're likely to have +problems even with this simple introduction. +In that case you should find someone that already knows +.Nm \&vi +and have them walk you through this section. +.Pp +.Nm \&Vi +is a screen editor. +This means that it takes up almost the entire screen, displaying part +of the file on each screen line, except for the last line of the screen. +The last line of the screen is used for you to give commands to +.Nm \&vi , +and for +.Nm \&vi +to give information to you. +.Pp +The other fact that you need to understand is that +.Nm \&vi +is a modeful editor, i.e. you are either entering text or you +are executing commands, and you have to be in the right mode +to do one or the other. +You will be in command mode when you first start editing a file. +There are commands that switch you into input mode. +There is only one key that takes you out of input mode, +and that is the <escape> key. +(Key names are written using less-than and greater-than signs, e.g. +<escape> means the +.Dq escape +key, usually labeled +.Dq esc +on your terminal's keyboard.) +If you're ever confused as to which mode you're in, +keep entering the <escape> key until +.Nm \&vi +beeps at you. +(Generally, +.Nm \&vi +will beep at you if you try and do something that's not allowed. +It will also display error messages.) +.Pp +To start editing a file, enter the command +.Dq Li "vi file_name<carriage-return>" . +The command you should enter as soon as you start editing is +.Dq Li ":set verbose showmode<carriage-return>" . +This will make the editor give you verbose error messages and display +the current mode at the bottom of the screen. +.Pp +The commands to move around the file are: +.Bl -tag -width XXXX -compact +.It Sy h +Move the cursor left one character. +.It Sy j +Move the cursor down one line. +.It Sy k +Move the cursor up one line. +.It Sy l +Move the cursor right one character. +.It Sy <cursor-arrows> +The cursor arrow keys should work, too. +.It Sy /text<carriage-return> +Search for the string +.Dq text +in the file, and move the cursor to its first character. +.El +.Pp +The commands to enter new text are: +.Bl -tag -width XXXX -compact +.It Sy a +Append new text, +.Em after +the cursor. +.It Sy i +Insert new text, +.Em before +the cursor. +.It Sy o +Open a new line below the line the cursor is on, and start +entering text. +.It Sy O +Open a new line above the line the cursor is on, and start +entering text. +.It Sy <escape> +Once you've entered input mode using the one of the +.Sy \&a , +.Sy \&i , +.Sy \&O , +or +.Sy \&o +commands, use +.Sy <escape> +to quit entering text and return to command mode. +.El +.Pp +The commands to copy text are: +.Bl -tag -width XXXX -compact +.It Sy yy +Copy the line the cursor is on. +.It Sy p +Append the copied line after the line the cursor is on. +.El +.Pp +The commands to delete text are: +.Bl -tag -width XXXX -compact +.It Sy dd +Delete the line the cursor is on. +.It Sy x +Delete the character the cursor is on. +.El +.Pp +The commands to write the file are: +.Bl -tag -width XXXX -compact +.It Sy :w<carriage-return> +Write the file back to the file with the name that you originally used +as an argument on the +.Nm \&vi +command line. +.It Sy :w file_name<carriage-return> +Write the file back to the file with the name +.Dq file_name . +.El +.Pp +The commands to quit editing and exit the editor are: +.Bl -tag -width XXXX -compact +.It Sy :q<carriage-return> +Quit editing and leave vi (if you've modified the file, but not +saved your changes, +.Nm \&vi +will refuse to quit). +.It Sy :q!<carriage-return> +Quit, discarding any modifications that you may have made. +.El +.Pp +One final caution. +Unusual characters can take up more than one column on the screen, +and long lines can take up more than a single screen line. +The above commands work on +.Dq physical +characters and lines, i.e. they affect the entire line no matter +how many screen lines it takes up and the entire character no matter +how many screen columns it takes up. +.Sh VI COMMANDS +The following section describes the commands available in the command +mode of the +.Nm \&vi +editor. +In each entry below, the tag line is a usage synopsis for the command +character. +.sp +.Bl -tag -width "XXXX" -compact +.It Sy "[count] <control-A>" +Search forward +.Li count +times for the current word. +.It Sy "[count] <control-B>" +Page backwards +.Li count +screens. +.It Sy "[count] <control-D>" +Scroll forward +.Li count +lines. +.It Sy "[count] <control-E>" +Scroll forward +.Li count +lines, leaving the current line and column as is, if possible. +.It Sy "[count] <control-F>" +Page forward +.Li count +screens. +.It Sy "<control-G>" +Display the file information. +.It Sy "<control-H>" +.It Sy "[count] h" +Move the cursor back +.Li count +characters in the current line. +.It Sy "[count] <control-J>" +.It Sy "[count] <control-N>" +.It Sy "[count] j" +Move the cursor down +.Li count +lines without changing the current column. +.It Sy "<control-L>" +.It Sy "<control-R>" +Repaint the screen. +.It Sy "[count] <control-M>" +.It Sy "[count] +" +Move the cursor down +.Li count +lines to the first nonblank character of that line. +.It Sy "[count] <control-P>" +.It Sy "[count] k" +Move the cursor up +.Li count +lines, without changing the current column. +.It Sy "<control-T>" +Return to the most recent tag context. +.It Sy "<control-U>" +Scroll backwards +.Li count +lines. +.It Sy "<control-W>" +Switch to the next lower screen in the window, or, to the first +screen if there are no lower screens in the window. +.It Sy "<control-Y>" +Scroll backwards +.Li count +lines, leaving the current line and column as is, if possible. +.It Sy "<control-Z>" +Suspend the current editor session. +.It Sy "<escape>" +Execute +.Nm \&ex +commands or cancel partial commands. +.It Sy "<control-]>" +Push a tag reference onto the tag stack. +.It Sy "<control-^>" +Switch to the most recently edited file. +.It Sy "[count] <space>" +.It Sy "[count] l" +Move the cursor forward +.Li count +characters without changing the current line. +.It Sy "[count] ! motion shell-argument(s)" +Replace text with results from a shell command. +.It Sy "[count] # +|-|#" +Increment or decrement the cursor number. +.It Sy "[count] $" +Move the cursor to the end of a line. +.It Sy "%" +Move to the matching character. +.It Sy "&" +Repeat the previous substitution command on the current line. +.It Sy "'<character>" +.It Sy "`<character>" +Return to a context marked by the character +.Li <character> . +.It Sy "[count] (" +Back up +.Li count +sentences. +.It Sy "[count] )" +Move forward +.Li count +sentences. +.It Sy "[count] ," +Reverse find character +.Li count +times. +.It Sy "[count] -" +Move to first nonblank of the previous line, +.Li count +times. +.It Sy "[count] ." +Repeat the last +.Nm \&vi +command that modified text. +.It Sy "/RE<carriage-return>" +.It Sy "/RE/ [offset]<carriage-return>" +.It Sy "?RE<carriage-return>" +.It Sy "?RE? [offset]<carriage-return>" +.It Sy "N" +.It Sy "n" +Search forward or backward for a regular expression. +.It Sy "0" +Move to the first character in the current line. +.It Sy ":" +Execute an ex command. +.It Sy "[count] ;" +Repeat the last character find +.Li count +times. +.It Sy "[count] < motion" +.It Sy "[count] > motion" +Shift lines left or right. +.It Sy "@ buffer" +Execute a named buffer. +.It Sy "[count] A" +Enter input mode, appending the text after the end of the line. +.It Sy "[count] B" +Move backwards +.Li count +bigwords. +.It Sy "[buffer] [count] C" +Change text from the current position to the end-of-line. +.It Sy "[buffer] D" +Delete text from the current position to the end-of-line. +.It Sy "[count] E" +Move forward +.Li count +end-of-bigwords. +.It Sy "[count] F <character>" +Search +.Li count +times backward through the current line for +.Li <character> . +.It Sy "[count] G" +Move to line +.Li count , +or the last line of the file if +.Li count +not specified. +.It Sy "[count] H" +Move to the screen line +.Li "count - 1" +lines below the top of the screen. +.It Sy "[count] I" +Enter input mode, inserting the text at the beginning of the line. +.It Sy "[count] J" +Join lines. +.It Sy "[count] L" +Move to the screen line +.Li "count - 1" +lines above the bottom of the screen. +.It Sy " M" +Move to the screen line in the middle of the screen. +.It Sy "[count] O" +Enter input mode, appending text in a new line above the current line. +.It Sy "[buffer] P" +Insert text from a buffer. +.It Sy "Q" +Exit +.Nm \&vi +(or visual) mode and switch to +.Nm \&ex +mode. +.It Sy "[count] R" +Enter input mode, replacing the characters in the current line. +.It Sy "[buffer] [count] S" +Substitute +.Li count +lines. +.It Sy "[count] T <character>" +Search backwards, +.Li count +times, +through the current line for the character +.Em after +the specified +.Li <character> . +.It Sy "U" +Restore the current line to its state before the cursor last +moved to it. +.It Sy "[count] W" +Move forward +.Li count +bigwords. +.It Sy "[buffer] [count] X" +Delete +.Li count +characters before the cursor. +.It Sy "[buffer] [count] Y" +Copy (or +.Dq yank ) +.Li count +lines into the specified buffer. +.It Sy "ZZ" +Write the file and exit +.Nm \&vi . +.It Sy "[count] [[" +Back up +.Li count +section boundaries. +.It Sy "[count] ]]" +Move forward +.Li count +section boundaries. +.It Sy "\&^" +Move to first nonblank character on the current line. +.It Sy "[count] _" +Move down +.Li "count - 1" +lines, to the first nonblank character. +.It Sy "[count] a" +Enter input mode, appending the text after the cursor. +.It Sy "[count] b" +Move backwards +.Li count +words. +.It Sy "[buffer] [count] c motion" +Change a region of text. +.It Sy "[buffer] [count] d motion" +Delete a region of text. +.It Sy "[count] e" +Move forward +.Li count +end-of-words. +.It Sy "[count] f<character>" +Search forward, +.Li count +times, through the rest of the current line for +.Li <character> . +.It Sy "[count] i" +Enter input mode, inserting the text before the cursor. +.It Sy "m <character>" +Save the current context (line and column) as +.Li <character> . +.It Sy "[count] o" +Enter input mode, appending text in a new line under the current line. +.It Sy "[buffer] p" +Append text from a buffer. +.It Sy "[count] r <character> +Replace +.Li count +characters. +.It Sy "[buffer] [count] s" +Substitute +.Li count +characters in the current line starting with the current character. +.It Sy "[count] t <character>" +Search forward, +.Li count +times, through the current line for the character immediately +.Em before +.Li <character> . +.It Sy "u" +Undo the last change made to the file. +.It Sy "[count] w" +Move forward +.Li count +words. +.It Sy "[buffer] [count] x" +Delete +.Li count +characters. +.It Sy "[buffer] [count] y motion" +Copy (or +.Dq yank ) +a text region specified by the +.Li count +and motion into a buffer. +.It Sy "[count1] z [count2] -|.|+|^|<carriage-return>" +Redraw, optionally repositioning and resizing the screen. +.It Sy "[count] {" +Move backward +.Li count +paragraphs. +.It Sy "[count] |" +Move to a specific +.Em column +position on the current line. +.It Sy "[count] }" +Move forward +.Li count +paragraphs. +.It Sy "[count] ~" +Reverse the case of the next +.Li count +character(s). +.It Sy "[count] ~ motion" +Reverse the case of the characters in a text region specified by the +.Li count +and +.Li motion . +.It Sy "<interrupt>" +Interrupt the current operation. +.El +.Sh VI TEXT INPUT COMMANDS +The following section describes the commands available in the text +input mode of the +.Nm \&vi +editor. +.Pp +.Bl -tag -width "XXXX" -compact +.It Sy "<nul>" +Replay the previous input. +.It Sy "<control-D>" +Erase the previous autoindent character. +.It Sy "^<control-D>" +Erase all of the autoindent characters, and reset the autoindent level. +.It Sy "0<control-D>" +Erase all of the autoindent characters. +.It Sy "<control-T>" +Insert sufficient +.Li <tab> +and +.Li <space> +characters to move the cursor forward to a column immediately +after the next column which is an even multiple of the +.Sy shiftwidth +option. +.It Sy "<erase> +.It Sy "<control-H>" +Erase the last character. +.It Sy "<literal next>" +Quote the next character. +.It Sy "<escape> +Resolve all text input into the file, and return to command mode. +.It Sy "<line erase> +Erase the current line. +.It Sy "<control-W>" +.It Sy "<word erase> +Erase the last word. +The definition of word is dependent on the +.Sy altwerase +and +.Sy ttywerase +options. +.It Sy "<control-X>[0-9A-Fa-f]*" +Insert a character with the specified hexadecimal value into the text. +.It Sy "<interrupt>" +Interrupt text input mode, returning to command mode. +.El +.Sh EX COMMANDS +The following section describes the commands available in the +.Nm \&ex +editor. +In each entry below, the tag line is a usage synopsis for the command. +.sp +.Bl -tag -width "XXXX" -compact +.It Sy "<end-of-file>" +Scroll the screen. +.It Sy "! argument(s)" +.It Sy "[range]! argument(s)" +Execute a shell command, or filter lines through a shell command. +.It Sy \&" +A comment. +.It Sy "[range] nu[mber] [count] [flags]" +.It Sy "[range] # [count] [flags]" +Display the selected lines, each preceded with its line number. +.It Sy "@ buffer" +.It Sy "* buffer" +Execute a buffer. +.It Sy "[range] d[elete] [buffer] [count] [flags]" +Delete the lines from the file. +.It Sy "di[splay] b[uffers] | s[creens] | t[ags]" +Display buffers, screens or tags. +.It Sy "e[dit][!] [+cmd] [file]" +.It Sy "ex[!] [+cmd] [file]" +Edit a different file. +.It Sy "exu[sage] [command]" +Display usage for an +.Nm \&ex +command. +.It Sy "f[ile] [file]" +Display and optionally change the file name. +.It Sy "fg [name]" +.Nm \&Vi +mode only. +Foreground the specified screen. +.It Sy "[range] g[lobal] /pattern/ [commands]" +.It Sy "[range] v /pattern/ [commands] +Apply commands to lines matching (or not matching) a pattern. +.It Sy "he[lp]" +Display a help message. +.It Sy "[line] i[nsert][!]" +The input text is inserted before the specified line. +.It Sy "[range] j[oin][!] [count] [flags]" +Join lines of text together. +.It Sy "[range] l[ist] [count] [flags]" +Display the lines unambiguously. +.It Sy "map[!] [lhs rhs]" +Define or display maps (for +.Nm \&vi +only). +.It Sy "[line] ma[rk] <character>" +.It Sy "[line] k <character>" +Mark the line with the mark +.Li <character> . +.It Sy "[range] m[ove] line" +Move the specified lines after the target line. +.It Sy "mk[exrc][!] file" +Write the abbreviations, editor options and maps to the specified +file. +.It Sy "n[ext][!] [file ...]" +Edit the next file from the argument list. +.It Sy "[line] o[pen] /pattern/ [flags]" +Enter open mode. +.It Sy "pre[serve]" +Save the file in a form that can later be recovered using the +.Nm \&ex +.Fl r +option. +.It Sy "prev[ious][!]" +Edit the previous file from the argument list. +.It Sy "[range] p[rint] [count] [flags]" +Display the specified lines. +.It Sy "[line] pu[t] [buffer]" +Append buffer contents to the current line. +.It Sy "q[uit][!]" +End the editing session. +.It Sy "[line] r[ead][!] [file]" +Read a file. +.It Sy "rec[over] file" +Recover +.Li file +if it was previously saved. +.It Sy "res[ize] [+|-]size" +.Nm \&Vi +mode only. +Grow or shrink the current screen. +.It Sy "rew[ind][!]" +Rewind the argument list. +.It Sy "se[t] [option[=[value]] ...] [nooption ...] [option? ...] [all]" +Display or set editor options. +.It Sy "sh[ell]" +Run a shell program. +.It Sy "so[urce] file" +Read and execute +.Nm \&ex +commands from a file. +.It Sy "sp[lit] [file ...]" +.Nm \&Vi +mode only. +Split the screen. +.It Sy "[range] s[ubstitute] [/pattern/replace/] [options] [count] [flags]" +.It Sy "[range] & [options] [count] [flags]" +.It Sy "[range] ~ [options] [count] [flags]" +Make substitutions. +.It Sy "su[spend][!]" +.It Sy "st[op][!]" +.It Sy <suspend> +Suspend the edit session. +.It Sy "ta[g][!] tagstring" +Edit the file containing the specified tag. +.It Sy "tagp[op][!] [file | number]" +Pop to the specified tag in the tags stack. +.It Sy "unm[ap][!] lhs" +Unmap a mapped string. +.It Sy "ve[rsion]" +Display the version of the +.Nm \&ex/vi +editor. +.It Sy "[line] vi[sual] [type] [count] [flags]" +.Nm \&Ex +mode only. +Enter +.Nm \&vi . +.It Sy "vi[sual][!] [+cmd] [file]" +.Nm \&Vi +mode only. +Edit a new file. +.It Sy "viu[sage] [command]" +Display usage for a +.Nm \&vi +command. +.It Sy "[range] w[rite][!] [>>] [file]" +.It Sy "[range] w[rite] [!] [file]" +.It Sy "[range] wn[!] [>>] [file]" +.It Sy "[range] wq[!] [>>] [file]" +Write the file. +.It Sy "[range] x[it][!] [file]" +Write the file if it has been modified. +.It Sy "[range] ya[nk] [buffer] [count]" +Copy the specified lines to a buffer. +.It Sy "[line] z [type] [count] [flags]" +Adjust the window. +.El +.Sh SET OPTIONS +There are a large number of options that may be set (or unset) to +change the editor's behavior. +This section describes the options, their abbreviations and their +default values. +.Pp +In each entry below, the first part of the tag line is the full name +of the option, followed by any equivalent abbreviations. +The part in square brackets is the default value of the option. +Most of the options are boolean, i.e. they are either on or off, +and do not have an associated value. +.Pp +Options apply to both +.Nm \&ex +and +.Nm \&vi +modes, unless otherwise specified. +.sp +.Bl -tag -width "XXXX" -compact +.It Sy "altwerase [off]" +.Nm \&Vi +only. +Select an alternate word erase algorithm. +.It Sy "autoindent, ai [off]" +Automatically indent new lines. +.It Sy "autoprint, ap [off]" +.Nm \&Ex +only. +Display the current line automatically. +.It Sy "autowrite, aw [off]" +Write modified files automatically when changing files. +.It Sy "beautify, bf [off]" +Discard control characters. +.It Sy "cdpath [environment variable CDPATH, or current directory]" +The directory paths used as path prefixes for the +.Sy cd +command. +.It Sy "columns, co [80]" +Set the number of columns in the screen. +.It Sy "comment [off]" +.Nm \&Vi +only. +Skip leading comments in files. +.It Sy "directory, dir [environment variable TMPDIR, or /tmp]" +The directory where temporary files are created. +.It Sy "edcompatible, ed [off]" +Remember the values of the +.Dq \&c +and +.Dq \&g +suffices to the +.Sy substitute +commands, instead of initializing them as unset for each new +command. +.It Sy "errorbells, eb [off]" +.Nm \&Ex +only. +Announce error messages with a bell. +.It Sy "exrc, ex [off]" +Never read startup files in the local directory. +.It Sy "extended [off]" +Regular expressions are extended (i.e. +.Xr egrep 1 +style) expressions. +.It Sy "flash [on]" +Flash the screen instead of beeping the keyboard on error. +.It Sy "hardtabs, ht [8]" +Set the spacing between hardware tab settings. +.It Sy "ignorecase, ic [off]" +Ignore case differences in regular expressions. +.It Sy "keytime [6]" +The 10th's of a second +.Nm ex/vi +waits for a subsequent key to complete a key mapping. +.It Sy "leftright [off]" +.Nm \&Vi +only. +Do left-right scrolling. +.It Sy "lines, li [24]" +.Nm \&Vi +only. +Set the number of lines in the screen. +.It Sy "lisp [off]" +.Nm \&Vi +only. +Modify various search commands and options to work with Lisp. +.Pp +.Em "This option is not yet implemented." +.It Sy "list [off]" +Display lines in an unambiguous fashion. +.It Sy "magic [on]" +Treat certain characters specially in regular expressions. +.It Sy "matchtime [7]" +.Nm \&Vi +only. +The 10th's of a second +.Nm ex/vi +pauses on the matching character when the +.Sy showmatch +option is set. +.It Sy "mesg [on]" +Permit messages from other users. +.It Sy "modelines, modeline [off]" +Read the first and last few lines of each file for +.Nm ex +commands. +.Pp +.Em "This option will never be implemented." +.It Sy "number, nu [off]" +Precede each line displayed with its current line number. +.It Sy "octal [off]" +Display unknown characters as octal numbers, instead of the default +hexadecimal. +.It Sy "open [on]" +.Nm \&Ex +only. +If this option is not set, the +.Sy open +and +.Sy visual +commands are disallowed. +.It Sy "optimize, opt [on]" +.Nm \&Vi +only. +Optimize text throughput to dumb terminals. +.Pp +.Em "This option is not yet implemented." +.It Sy "paragraphs, para [IPLPPPQPP LIpplpipbp]" +.Nm \&Vi +only. +Define additional paragraph boundaries for the +.Sy \&{ +and +.Sy \&} +commands. +.It Sy "prompt [on]" +.Nm \&Ex +only. +Display a command prompt. +.It Sy "readonly, ro [off]" +Mark the file as read-only. +.It Sy "recdir [/var/tmp/vi.recover]" +The directory where recovery files are stored. +.It Sy "redraw, re [off]" +.Nm \&Vi +only. +Simulate an intelligent terminal on a dumb one. +.Pp +.Em "This option is not yet implemented." +.It Sy "remap [on]" +Remap keys until resolved. +.It Sy "report [5]" +Set the number of lines about which the editor reports changes +or yanks. +.It Sy "ruler [off]" +.Nm \&Vi +only. +Display a row/column ruler on the colon command line. +.It Sy "scroll, scr [window / 2]" +Set the number of lines scrolled. +.It Sy "sections, sect [NHSHH HUnhsh]" +.Nm \&Vi +only. +Define additional section boundaries for the +.Sy \&[[ +and +.Sy \&]] +commands. +.It Sy "shell, sh [environment variable SHELL, or /bin/sh]" +Select the shell used by the editor. +.It Sy "shiftwidth, sw [8]" +Set the autoindent and shift command indentation width. +.It Sy "showdirty [off]" +.Nm \&Vi +only. +Display an asterisk on the colon command line if the file has been modified. +.It Sy "showmatch, sm [off]" +.Nm \&Vi +only. +Note matching +.Dq \&{ +and +.Dq \&( +for +.Dq \&} +and +.Dq \&) +characters. +.It Sy "showmode [off]" +.Nm \&Vi +only. +Display the current editor mode (command or input). +.It Sy "sidescroll [16]" +.Nm \&Vi +only. +Set the amount a left-right scroll will shift. +.It Sy "slowopen, slow [off]" +Delay display updating during text input. +.Pp +.Em "This option is not yet implemented." +.It Sy "sourceany [off]" +Read startup files not owned by the current user. +.Pp +.Em "This option will never be implemented." +.It Sy "tabstop, ts [8]" +This option sets tab widths for the editor display. +.It Sy "taglength, tl [0]" +Set the number of significant characters in tag names. +.It Sy "tags, tag [tags /var/db/libc.tags /sys/kern/tags]" +Set the list of tags files. +.It Sy "term, ttytype, tty [environment variable TERM]" +Set the terminal type. +.It Sy "terse [off]" +This option has historically made editor messages less verbose. +It has no effect in this implementation. +.It Sy "tildeop" +Modify the +.Sy \&~ +command to take an associated motion. +.It Sy "timeout, to [on]" +Time out on keys which may be mapped. +.It Sy "ttywerase [off]" +.Nm \&Vi +only. +Select an alternate erase algorithm. +.It Sy "verbose [off]" +.NM \&Vi +only. +Display an error message for every error. +.It Sy "w300 [no default]" +.Nm \&Vi +only. +Set the window size if the baud rate is less than 1200 baud. +.It Sy "w1200 [no default]" +.Nm \&Vi +only. +Set the window size if the baud rate is equal to 1200 baud. +.It Sy "w9600 [no default]" +.Nm \&Vi +only. +Set the window size if the baud rate is greater than 1200 baud. +.It Sy "warn [on]" +.Nm \&Ex +only. +This option causes a warning message to the terminal if the file has +been modified, since it was last written, before a +.Sy \&! +command. +.It Sy "window, w, wi [environment variable LINES]" +Set the window size for the screen. +.It Sy "wrapmargin, wm [0]" +.Nm \&Vi +only. +Break lines automatically when they reach the right-hand margin. +.It Sy "wrapscan, ws [on]" +Set searches to wrap around the end or beginning of the file. +.It Sy "writeany, wa [off]" +Turn off file-overwriting checks. +.El +.Sh ENVIRONMENTAL VARIABLES +.Bl -tag -width "COLUMNSXX" -compact +.It Ev COLUMNS +The number of columns on the screen. +This value overrides any system or terminal specific values. +If the COLUMNS environmental variable is not set when +.Nm ex/vi +runs, or the +.Sy columns +option is explicitly reset by the user, +.Nm ex/vi +enters the value into the environment. +.It Ev EXINIT +A list of +.Nm \&ex +startup commands, read if the variable +.Ev NEXINIT +is not set. +.It Ev HOME +The user's home directory, used as the initial directory path +for the startup +.Pa $HOME/.nexrc +and +.Pa $HOME/.exrc +files. +This value is also used as the default directory for the +.Nm \&vi +.Sy \&cd +command. +.It Ev LINES +The number of rows on the screen. +This value overrides any system or terminal specific values. +If the LINES environmental variable is not set when +.Nm ex/vi +runs, or the +.Sy lines +option is explicitly reset by the user, +.Nm ex/vi +enters the value into the environment. +.It Ev NEXINIT +A list of +.Nm \&ex +startup commands. +.It Ev SHELL +The user's shell of choice (see also the +.Sy shell +option). +.It Ev TERM +The user's terminal type. +The default is the type +.Dq unknown . +If the TERM environmental variable is not set when +.Nm ex/vi +runs, or the +.Sy term +option is explicitly reset by the user, +.Nm ex/vi +enters the value into the environment. +.It Ev TMPDIR +The location used to stored temporary files (see also the +.Sy directory +option). +.El +.Sh ASYNCHRONOUS EVENTS +.Bl -tag -width "SIGWINCHXX" -compact +.It SIGALRM +.Nm \&Vi/ex +uses this signal for periodic backups of file modifications +and to display +.Dq busy +messages when operations are likely to take a long time. +.It SIGHUP +.It SIGTERM +If the current buffer has changed since it was last written in its +entirety, the editor attempts to save the modified file so it can +be later recovered. +See the +.Nm \&vi/ex +Reference manual section entitled +.Dq Recovery +for more information. +.It SIGINT +When an interrupt occurs, +the current operation is halted, +and the editor returns to the command level. +If interrupted during text input, +the text already input is resolved into the file as if the text +input had been normally terminated. +.It SIGWINCH +The screen is resized. +See the +.Nm \&vi/ex +Reference manual section entitled +.Dq "Sizing the Screen" +for more information. +.It SIGCONT +.It SIGQUIT +.It SIGTSTP +.Nm \&Vi/ex +ignores these signals. +.El +.Sh BUGS +See the file +.Pa nvi/docs/bugs.current +for a list of the known bugs in this version. +.Sh FILES +.Bl -tag -width /var/tmp/vi.recover -compact +.It Pa /bin/sh +The default user shell. +.It Pa /etc/vi.exrc +System-wide vi startup file. +.It Pa /tmp +Temporary file directory. +.It Pa /var/tmp/vi.recover +The default recovery file directory. +.It Pa $HOME/.nexrc +1st choice for user's home directory startup file. +.It Pa $HOME/.exrc +2nd choice for user's home directory startup file. +.It Pa .nexrc +1st choice for local directory startup file. +.It Pa .exrc +2nd choice for local directory startup file. +.El +.Sh SEE ALSO +.Xr ctags 1 , +.Xr more 1 , +.Xr curses 3 , +.Xr dbopen 3 +.sp +The +.Dq "Vi Quick Reference" +card. +.sp +.Dq "\&An Introduction to Display Editing with Vi" , +found in the +.Dq "UNIX User's Manual Supplementary Documents" +section of both the 4.3BSD and 4.4BSD manual sets. +This document is the closest thing available to an introduction to the +.Nm \&vi +screen editor. +.sp +.Dq "\&Ex Reference Manual (Version 3.7)" , +found in the +.Dq "UNIX User's Manual Supplementary Documents" +section of both the 4.3BSD and 4.4BSD manual sets. +This document is the final reference for the +.Nm \&ex +editor, as distributed in most historic 4BSD and System V systems. +.sp +.Dq "Edit: A tutorial" , +found in the +.Dq "UNIX User's Manual Supplementary Documents" +section of the 4.3BSD manual set. +This document is an introduction to a simple version of the +.Nm \&ex +screen editor. +.sp +.Dq "\&Ex/Vi Reference Manual" , +found in the +.Dq "UNIX User's Manual Supplementary Documents" +section of the 4.4BSD manual set. +This document is the final reference for the +.Nm \&nex/nvi +text editors, as distributed in 4.4BSD and 4.4BSD-Lite. +.Pp +.Nm Roff +source for all of these documents is distributed with +.Nm nex/nvi +in the +.Pa nvi/USD.doc +directory of the +.Nm nex/nvi +source code. +.sp +The files +.Dq autowrite , +.Dq input , +.Dq quoting , +and +.Dq structures , +found in the +.Pa nvi/docs/internals +directory of the +.Nm nex/nvi +source code. +.Sh HISTORY +The +.Nm nex/nvi +replacements for the +.Nm ex/vi +editor first appeared in 4.4BSD. +.Sh STANDARDS +.Nm \&Nex/nvi +is close to IEEE Std1003.2 (``POSIX''). +That document differs from historical +.Nm ex/vi +practice in several places; there are changes to be made on both sides. diff --git a/usr.bin/vi/USD.doc/vi.ref/Makefile b/usr.bin/vi/USD.doc/vi.ref/Makefile new file mode 100644 index 0000000..2690f86 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/Makefile @@ -0,0 +1,25 @@ +# @(#)Makefile 8.16 (Berkeley) 8/15/94 + +DIR= usd/13.viref +SRCS= vi.ref ex.cmd.roff set.opt.roff vi.cmd.roff ref.so +MACROS= -me +CLEANFILES+=vi.ref.txt index index.so + +paper.ps: vi.ref index.so + soelim vi.ref | ${TBL} | ${ROFF} > ${.TARGET} + +vi.ref.txt: vi.ref index.so + soelim vi.ref | ${TBL} | groff ${MACROS} -Tascii > $@ + +index.so: vi.ref + # Build index.so, side-effect of building the paper. + soelim vi.ref | ${TBL} | ${ROFF} > /dev/null + sed -e 's/MINUSSIGN/\\-/' \ + -e 's/DOUBLEQUOTE/""/' \ + -e "s/SQUOTE/'/" \ + -e 's/ /__SPACE/g' < index | \ + sort -u '-t ' +0 -1 +1n | awk -f merge.awk | \ + sed -e 's/__SPACE/ /g' > index.so + rm -f index + +.include <bsd.doc.mk> diff --git a/usr.bin/vi/USD.doc/vi.ref/ex.cmd.roff b/usr.bin/vi/USD.doc/vi.ref/ex.cmd.roff new file mode 100644 index 0000000..a9cba6ae3 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/ex.cmd.roff @@ -0,0 +1,1776 @@ +.\" Copyright (c) 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ex.cmd.roff 8.24 (Berkeley) 7/17/94 +.\" +.SH 1 "Ex Description" +.pp +The following words have special meanings for +.CO ex +commands. +.KY "<eof>" +.IP "<eof>" +The end-of-file character is used to scroll the screen in the +.CO ex +editor. +This character is normally +.LI <control-D> , +however, whatever character is set for the current terminal is used. +.KY "line" +.IP "line" +A single-line address, given in any of the forms described in the +section entitled +.QB "Ex Addressing" . +The default for +.LI line +is the current line. +.KY "range" +.IP "range" +A line, or a pair of line addresses, separated by a comma or semicolon. +(See the section entitled +.QB "Ex Addressing" +for more information.) +The default for range is the current line +.i only , +i.e. +.QT \&.,. . +A percent sign +.PQ % +stands for the range +.QT 1,$ . +The starting address must be less than, or equal to, the ending address. +.KY "count" +.IP "count" +A positive integer, specifying the number of lines to be affected by +the command; the default is 1. +Generally, a count past the end-of-file may be specified, e.g. the +command +.QT "p 3000" +in a 10 line file is acceptable, and will print from the current line +through the last line in the file. +.KY "flags" +.IP "flags" +One or more of the characters +.QQ # , +.QQ p , +and +.QQ l . +When a command that accepts these flags completes, the addressed line(s) +are written out as if by the corresponding +.CO # , +.CO l +or +.CO p +commands. +In addition, any number of +.QT + +or +.QT \- +characters can be specified before, after, or during the flags, in which +case the line written is not necessarily the one affected by the command, +but rather the line addressed by the offset address specified. +The default for +.LI flags +is none. +.KY "file" +.IP "file" +A pattern used to derive a pathname; the default is the current file. +File names are subjected to normal +.XR sh 1 +word expansions. +.pp +Anywhere a file name is specified, it is also possible to use +the special string +.QT /tmp . +This will be replaced with a temporary file name which can be used +for temporary work, e.g. +.QT ":e /tmp" +creates and edits a new file. +.pp +If both a count and a range are specified for commands that use either, +the starting line for the command is the +.i last +line addressed by the range, and +.LI count - 1 +subsequent lines are affected by the command, e.g. the command +.QT 2,3p4 +prints out lines 3, 4, 5 and 6. +.pp +When only a line or range is specified, with no command, the implied +command is either a +.CO list , +.CO number +or +.CO print +command. +The command used is the most recent of the three commands to have been +used (including any use as a flag). +If none of these commands have been used before, the +.CO print +command is the implied command. +When no range or count is specified and the command line is a blank line, +the current line is incremented by 1 and then the current line is displayed. +.pp +Zero or more whitespace characters may precede or follow the addresses, +count, flags, or command name. +Any object following a command name (such as buffer, file, etc.), +that begins with an alphabetic character, +should be separated from the command name by at least one whitespace +character. +.pp +Any character, including +.LI <carriage-return> , +.QT % +and +.QT # +retain their literal value when preceded by a backslash. +.SH 1 "Ex Commands" +.pp +The following section describes the commands available in the +.CO ex +editor. +In each entry below, the tag line is a usage synopsis for the command. +.pp +Each command can be entered as the abbreviation +(those characters in the synopsis command word preceding the +.QQ [ +character), +the full command (all characters shown for the command word, +omitting the +.QQ [ +and +.QQ ] +characters), +or any leading subset of the full command down to the abbreviation. +For example, the args command (shown as +.QT ar[gs] +in the synopsis) +can be entered as +.QT ar , +.QT arg +or +.QT args . +.pp +Each +.CO ex +command described below notes the new current line after it +is executed, as well as any options that affect the command. +.KY DOUBLEQUOTE +.IP """" +A comment. +Command lines beginning with the double-quote character +.PQ """" +are ignored. +This permits comments in editor scripts and startup files. +.KY "<end-of-file>" +.IP "<end-of-file>" +Scroll the screen. +Write the next N lines, where N is the value of the +.OP scroll +option. +The command is the end-of-file terminal character, which may be +different on different terminals. +Traditionally, it is the +.LI <control-D> +key. +.sp +Historically, the +.CO eof +command ignored any preceding count, and the +.LI <end-of-file> +character was ignored unless it was entered as the first character +of the command. +This implementation treats it as a command +.i only +if entered as the first character of the command line, and otherwise +treats it as any other character. +.SS +.SP Line: +Set to the last line written. +.SP Options: +None. +.SE +.KY "!" +.IP "! argument(s)" +.Ip "[range]! argument(s)" +Execute a shell command, or filter lines through a shell command. +In the first synopsis, the remainder of the line after the +.QT ! +character is passed to the program named by the +.OP shell +option, as a single argument. +.sp +Within the rest of the line, +.QT % +and +.QT # +are expanded into the current and alternate pathnames, respectively. +The character +.QT ! +is expanded with the command text of the previous +.CO ! +command. +(Therefore, the command +.CO !! +repeats the previous +.CO ! +command.) +The special meanings of +.QT % , +.QT # , +and +.QT ! +can be overridden by escaping them with a backslash. +If no +.CO ! +or +.CO :! +command has yet been executed, it is an error to use an unescaped +.QT ! +character. +The +.CO ! +command does +.i not +do shell expansion on the strings provided as arguments. +If any of the above expansions change the command the user entered, +the command is redisplayed at the bottom of the screen. +.sp +.CO Ex +then executes the program named by the +.OP shell +option, with a +.b \-c +flag followed by the arguments (which are bundled into a single argument). +.sp +The +.CO ! +command is permitted in an empty file. +.sp +If the file has been modified since it was last completely written, +the +.Co ! +command will warn you. +.sp +A single +.QT ! +character is displayed when the command completes. +.sp +In the second form of the +.CO ! +command, the remainder of the line after the +.QT ! +is passed to the program named by the +.OP shell +option, as described above. +The specified lines are passed to the program as standard input, +and the standard and standard error output of the program replace +the original lines. +.SS +.SP Line: +Unchanged if no range was specified, otherwise set to the first +line of the range. +.SP Options: +Affected by the +.OP autowrite +and +.OP writeany +options. +.SE +.KY "number" +.IP "[range] nu[mber] [count] [flags]" +.KY "#" +.Ip "[range] # [count] [flags]" +Display the selected lines, each preceded with its line number. +.sp +The line number format is +.QQ %6d , +followed by two spaces. +.SS +.SP Line: +Set to the last line displayed. +.SP Options: +None. +.SE +.KY "@" +.IP "@ buffer" +.KY "*" +.Ip "* buffer" +Execute a buffer. +Each line in the named buffer is executed as an +.CO ex +command. +If no buffer is specified, or if the specified buffer is +.QT @ +or +.QT * , +the last buffer executed is used. +.KY < +.IP "[range] <[< ...] [count] [flags]" +Shift lines left or right. +The specified lines are shifted to the left (for the +.CO < +command) or right (for the +.CO > +command), by the number of columns specified by the +.OP shiftwidth +option. +Only leading whitespace characters are deleted when shifting left; +once the first column of the line contains a nonblank character, +the +.CO shift +command will succeed, but the line will not be modified. +.sp +If the command character +.CO < +or +.CO > +is repeated more than once, the command is repeated once for each +additional command character. +.SS +.SP Line: +If the current line is set to one of the lines that are affected +by the command, it is unchanged. +Otherwise, it is set to the first nonblank character of the lowest +numbered line shifted. +.SP Options: +Affected by the +.OP shiftwidth +option. +.SE +.KY = +.IP "[line] = [flags]" +Display the line number. +Display the line number of +.LI line +(which defaults to the last line in the file). +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY > +.IP "[range] >[> ...] [count] [flags]" +Shift right. +The specified lines are shifted to the right by the number of columns +specified by the +.OP shiftwidth +option, by inserting tab and space characters. +Empty lines are not changed. +.sp +If the command character +.QT > +is repeated more than once, the command is repeated once for each +additional command character. +.SS +.SP Line: +Set to the last line modified by the command. +.SP Options: +None. +.SE +.KY abbrev +.IP "ab[brev] lhs rhs" +Add an abbreviation to the current abbreviation list. +In +.CO vi , +if +.LI lhs +is entered such that it is preceded and followed by characters +that cannot be part of a word, it is replaced by the string +.LI rhs . +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY append +.IP "[line] a[ppend][!]" +The input text is appended to the specified line. +If line 0 is specified, the text is inserted at the beginning of the file. +Set to the last line input. +If no lines are input, then set to +.LI line , +or to the first line of the file if a +.LI line +of 0 was specified. +Following the command name with a +.QT ! +character causes the +.OP autoindent +option to be toggled for the duration of the command. +.SS +.SP Line: +Unchanged. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY args +.IP "ar[gs]" +Display the argument list. +The current argument is displayed inside of +.QT [ +and +.QT ] +characters. +The argument list is the list of operands specified on startup, +which can be replaced using the +.CO next +command. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY bg +.IP bg +.CO Vi +mode only. +Background the current screen. +.SS +.SP Line: +Set to the current line when the screen was last edited. +.SP Options: +None. +.SE +.KY change +.IP "[range] c[hange][!] [count]" +Replace the lines with input text. +Following the command name with a +.QT ! +character causes the +.OP autoindent +option to be toggled for the duration of the command. +.SS +.SP Line: +Set to the last line input, or, if no lines were input, +set to the line before the target line, or to the first +line of the file if there are no lines preceding the target line. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY cd +.KY chdir +.IP "chd[ir][!] [directory]" +.Ip "cd[!] [directory]" +Change the current working directory. +The +.LI directory +argument is subjected to +.XR sh 1 +word expansions. +When invoked with no directory argument and the +.LI HOME +environment variable is set, the directory named by the +.LI HOME +environment variable becomes the new current directory. +Otherwise, the new current directory becomes the directory returned +by the +.XR getpwent 3 +routine. +.sp +The +.CO chdir +command will fail if the file has been modified since the last complete +write of the file. +You can override this check by appending a +.QT ! +character to the command. +.SS +.SP Line: +Unchanged. +.SP Options: +Affected by the +.OP cdpath +option. +.SE +.KY copy +.KY t +.IP "[range] co[py] line [flags]" +.Ip "[range] t line [flags]" +Copy the specified lines (range) after the destination line. +Line 0 may be specified to insert the lines at the beginning of +the file. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY delete +.IP "[range] d[elete] [buffer] [count] [flags]" +Delete the lines from the file. +The deleted text is saved in the specified buffer, or, if no buffer +is specified, in the unnamed buffer. +If the command name is followed by a letter that could be interpreted +as either a buffer name or a flag value (because neither a +.LI count +or +.LI flags +values were given), +.CO ex +treats the letter as a +.LI flags +value if the letter immediately follows the command name, +without any whitespace separation. +If the letter is preceded by whitespace characters, +it treats it as a buffer name. +.SS +.SP Line: +Set to the line following the deleted lines, +or to the last line if the deleted lines were at the end. +.SP Options: +None. +.SE +.KY display +.IP "di[splay] b[uffers] | s[creens] | t[ags]" +Display buffers, screens or tags. +The +.CO display +command takes one of three additional arguments, which are as follows: +.SS +.SP b[uffers] +Display all buffers (including named, unnamed, and numeric) +that contain text. +.SP s[creens] +Display the file names of all background screens. +.SP t[ags] +Display the tags stack. +.SE +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY edit +.IP "e[dit][!] [+cmd] [file]" +.Ip "ex[!] [+cmd] [file]" +Edit a different file. +If the current buffer has been modified since the last complete write, +the command will fail. +You can override this by appending a +.QT ! +character to the command name. +.sp +If the +.QT +cmd +option is specified, that +.CO ex +command will be executed in the new file. +Any +.CO ex +command may be used, although the most common use of this feature is +to specify a line number or search pattern to set the initial location +in the new file. +.SS +.SP Line: +If you have previously edited the file, the current line will be set +to your last position in the file. +If that position does not exist, or you have not previously edited the +file, the current line will be set to the first line of the file if +you are in +.CO vi +mode, and the last line of the file if you are in +.CO ex . +.SP Options: +Affected by the +.OP autowrite +and +.OP writeany +options. +.SE +.KY exusage +.IP "exu[sage] [command]" +Display usage for an +.CO ex +command. +If +.LI command +is specified, a usage statement for that command is displayed. +Otherwise, usage statements for all +.CO ex +commands are displayed. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY file +.IP "f[ile] [file]" +Display and optionally change the file name. +If a file name is specified, the current pathname is changed to the +specified name. +The current pathname, the number of lines, and the current position +in the file are displayed. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY fg +.IP "fg [name]" +.CO Vi +mode only. +Foreground the specified screen. +Swap the current screen with the specified backgrounded screen. +If no screen is specified, the first background screen is foregrounded. +.SS +.SP Line: +Set to the current line when the screen was last edited. +.SP Options: +None. +.SE +.KY global +.IP "[range] g[lobal] /pattern/ [commands]" +.KY v +.Ip "[range] v /pattern/ [commands]" +Apply commands to lines matching (or not matching) a pattern. +The lines within the given range that match +.PQ g[lobal] , +or do not match +.PQ v +the given pattern are selected. +Then, the specified +.CO ex +command(s) are executed with the current line +.PQ \&. +set to each selected line. +If no range is specified, the entire file is searched for matching, +or not matching, lines. +.sp +Multiple commands can be specified, one per line, by escaping each +.LI <newline> +character with a backslash, or by separating commands with a +.QT | +character. +If no commands are specified, the command defaults to the +.CO print +command. +.sp +For the +.CO append , +.CO change +and +.CO insert +commands, the input text must be part of the global command line. +In this case, the terminating period can be omitted if it ends the commands. +.sp +The +.CO visual +command may also be specified as one of the +.CO ex +commands. +In this mode, input is taken from the terminal. +Entering a +.CO Q +command in +.CO vi +mode causes the next line matching the pattern to be selected and +.CO vi +to be reentered, until the list is exhausted. +.sp +The +.CO global , +.CO v +and +.CO undo +commands cannot be used as part of these commands. +.sp +The editor options +.OP autoprint , +.OP autoindent , +and +.OP report +are turned off for the duration of the +.CO global +and +.CO v +commands. +.SS +.SP Line: +The last line modified. +.SP Options: +None. +.SE +.KY help +.IP "he[lp]" +Display a help message. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY insert +.IP "[line] i[nsert][!]" +The input text is inserted before the specified line. +Following the command name with a +.QT ! +character causes the +.OP autoindent +option setting to be toggled for the duration of this command. +.SS +.SP Line: +Set to the last line input; if no lines were input, +set to the line before the target line, or to the first line +of the file if there are no lines preceding the target line. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY join +.IP "[range] j[oin][!] [count] [flags]" +Join lines of text together. +.sp +A +.LI count +specified to the +.Sy join +command specifies that the last line of the +.LI range +plus +.LI count +subsequent lines will be joined. +(Note, this differs by one from the general rule where only +.LI count - 1 +subsequent lines are affected.) +.sp +If the current line ends with a whitespace character, all whitespace +is stripped from the next line. +Otherwise, if the next line starts with a open parenthesis +.PQ ( , +do nothing. +Otherwise, if the current line ends with a question mark +.PQ ? , +period +.PQ \&. +or exclamation point +.PQ ! , +insert two spaces. +Otherwise, insert a single space. +.sp +Appending a +.QT ! +character to the command name causes a simpler join with no +white-space processing. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY list +.IP "[range] l[ist] [count] [flags]" +Display the lines unambiguously. +Tabs are displayed as +.QT ^I , +and the end of the line is marked with a +.QT $ +character. +.SS +.SP Line: +Set to the last line displayed. +.SP Options: +None. +.SE +.KY map +.IP "map[!] [lhs rhs]" +Define or display maps (for +.CO vi +only). +.sp +If +.QT lhs +and +.QT rhs +are not specified, the current set of command mode maps are displayed. +If a +.QT ! +character is appended to to the command, +the text input mode maps are displayed. +.sp +Otherwise, when the +.QT lhs +character sequence is entered in +.CO vi , +the action is as if the corresponding +.QT rhs +had been entered. +If a +.QT ! +character is appended to the command name, +the mapping is effective during text input mode, +otherwise, it is effective during command mode. +This allows +.QT lhs +to have two different macro definitions at the same time: one for command +mode and one for input mode. +.sp +Whitespace characters require escaping with a +.LI <literal next> +character to be entered in the +.LI lhs +string in visual mode. +.sp +Normally, keys in the +.LI rhs +string are remapped (see the +.OP remap +option), +and it is possible to create infinite loops. +However, keys which map to themselves are not further remapped, +regardless of the setting of the +.OP remap +option. +For example, the command +.QT ":map n nz." +maps the +.QT n +key to the +.CO n +and +.CO z +commands. +.sp +To exit an infinitely looping map, use the terminal +.LI <interrupt> +character. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY mark +.KY k +.IP "[line] ma[rk] <character>" +.Ip "[line] k <character>" +Mark the line with the mark +.LI <character> . +The expressions +.QT '<character> +and +.QT `<character> +can then be used as an address in any command that uses one. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY move +.IP "[range] m[ove] line" +Move the specified lines after the target line. +A target line of 0 places the lines at the beginning of the file. +.SS +.SP Line: +Set to the first of the moved lines. +.SP Options: +None. +.SE +.KY mkexrc +.IP "mk[exrc][!] file" +Write the abbreviations, editor options and maps to the specified +file. +Information is written in a form which can later be read back in +using the +.CO ex +.CO source +command. +If +.LI file +already exists, the +.CO mkexrc +command will fail. +This check can be overridden by appending a +.QT ! +character to the command. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY next +.IP "n[ext][!] [file ...]" +Edit the next file from the argument list. +The +.CO next +command will fail if the file has been modified since the last complete +write. +This check can be overridden by appending the +.QT ! +character to the command name. +The argument list can optionally be replaced by specifying a new one +as arguments to this command. +In this case, editing starts with the first file on the new list. +.SS +.SP Line: +Set as described for the +.CO edit +command. +.SP Options: +Affected by the options +.OP autowrite +and +.OP writeany . +.SE +.KY open +.IP "[line] o[pen] /pattern/ [flags]" +Enter open mode. +Open mode is the same as being in +.CO vi , +but with a one-line window. +All the standard +.CO vi +commands are available. +If a match is found for the optional RE argument, +the cursor is set to the start of the matching pattern. +.sp +.i "This command is not yet implemented." +.SS +.SP Line: +Unchanged, unless the optional RE is specified, in which case it is +set to the line where the matching pattern is found. +.SP Options: +Affected by the +.OP open +option. +.SE +.KY preserve +.IP "pre[serve]" +Save the file in a form that can later be recovered using the +.CO ex +.b \-r +option. +When the file is preserved, an email message is sent to the user. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY previous +.IP "prev[ious][!]" +Edit the previous file from the argument list. +The +.CO previous +command will fail if the file has been modified since the last complete +write. +This check can be overridden by appending the +.QT ! +character to the command name. +.SS +.SP Line: +Set as described for the +.CO edit +command. +.SP Options: +Affected by the options +.OP autowrite +and +.OP writeany . +None. +.SE +.KY print +.IP "[range] p[rint] [count] [flags]" +Display the specified lines. +.SS +.SP Line: +Set to the last line displayed. +.SP Options: +None. +.SE +.KY put +.IP "[line] pu[t] [buffer]" +Append buffer contents to the current line. +If a buffer is specified, its contents are appended to the line, +otherwise, the contents of the unnamed buffer are used. +.SS +.SP Line: +Set to the line after the current line. +.SP Options: +None. +.SE +.KY quit +.IP "q[uit][!]" +End the editing session. +If the file has been modified since the last complete write, the +.CO quit +command will fail. +This check may be overridden by appending a +.QT ! +character to the command. +.sp +If there are more files to edit, the +.CO quit +command will fail. +Appending a +.QT ! +character to the command name or entering two +.CO quit +commands (i.e. +.CO wq , +.CO quit , +.CO xit +or +.CO ZZ ) +in a row) will override this check and the editor will exit. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY read +.IP "[line] r[ead][!] [file]" +Read a file. +A copy of the specified file is appended to the line. +If +.LI line +is 0, the copy is inserted at the beginning of the file. +If no file is specified, the current file is read; if there is no +current file, then +.LI file +becomes the current file. +If there is no current file and no +.LI file +is specified, then the +.CO read +command will fail. +.sp +If +.LI file +is preceded by a +.QT ! +character, +.LI file +is treated as if it were a shell command, and passed to the program +named by the +.LI SHELL +environment variable. +The standard and standard error outputs of that command are read into +the file after the specified line. +The special meaning of the +.QT ! +character can be overridden by escaping it with a backslash +.PQ \e +character. +.SS +.SP Line: +When executed from +.CO ex , +the current line is set to the last line read. +When executed from +.CO vi , +the current line is set to the first line read. +.SP Options: +None. +.SE +.KY recover +.IP "rec[over] file" +Recover +.LI file +if it was previously saved. +If no saved file by that name exists, the +.CO recover +command behaves similarly to the +.CO edit +command. +.SS +.SP Line: +Set as described for the +.CO edit +command. +.SP Options: +None. +.SE +.KY resize +.IP "res[ize] [+|-]size" +.CO Vi +mode only. +Grow or shrink the current screen. +If +.LI size +is a positive, signed number, the current screen is grown by that many lines. +If +.LI size +is a negative, signed number, the current screen is shrunk by that many lines. +If +.LI size +is not signed, the current screen is set to the specified +.LI size . +Applicable only to split screens. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY rewind +.IP "rew[ind][!]" +Rewind the argument list. +If the current file has been modified since the last complete write, +the +.CO rewind +command will fail. +This check may be overridden by appending the +.QT ! +character to the command. +.sp +Otherwise, the current file is set to the first file in the argument +list. +.SS +.SP Line: +Set as described for the +.CO edit +command. +.SP Options: +Affected by the +.OP autowrite +and +.OP writeany +options. +.SE +.KY set +.IP "se[t] [option[=[value]] ...] [nooption ...] [option? ...] [all]" +Display or set editor options. +When no arguments are specified, the editor option +.OP term , +and any editor options whose values have been changed from the +default settings are displayed. +If the argument +.LI all +is specified, the values of all of editor options are displayed. +.sp +Specifying an option name followed by the character +.QT ? +causes the current value of that option to be displayed. +The +.QT ? +can be separated from the option name by whitespace characters. +The +.QT ? +is necessary only for Boolean valued options. +Boolean options can be given values by the form +.QT "set option" +to turn them on, or +.QT "set nooption" +to turn them off. +String and numeric options can be assigned by the form +.QT "set option=value" . +Any whitespace characters in strings can be included literally by preceding +each with a backslash. +More than one option can be set or listed by a single set command, +by specifying multiple arguments, each separated from the next by +whitespace characters. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY shell +.IP "sh[ell]" +Run a shell program. +The program named by the +.OP shell +option is run with a +.b \-i +(for interactive) flag. +Editing is resumed when that program exits. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY source +.IP "so[urce] file" +Read and execute +.CO ex +commands from a file. +.CO Source +commands may be nested. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY split +.IP "sp[lit] [file ...]" +.CO Vi +mode only. +Split the screen. +The current screen is split into two screens, of approximately equal size. +If the cursor is in the lower half of the screen, the screen will split +up, i.e. the new screen will be above the old one. +If the cursor is in the upper half of the screen, the new screen will be +below the old one. +.sp +If +.LI file +is specified, the new screen is editing that file, otherwise, both +screens are editing the same file, and changes in each will be +be reflected in the other. +The argument list for the new screen consists of the list of files +specified as arguments to this command, or, the current pathname if +no files are specified. +.SS +.SP Line: +If +.LI file +is specified, set as for the +.CO edit +command, otherwise unchanged. +.SP Options: +None. +.SE +.KY substitute +.IP "[range] s[ubstitute] [/pattern/replace/] [options] [count] [flags]" +.KY & +.Ip "[range] & [options] [count] [flags]" +.KY ~ +.Ip "[range] ~ [options] [count] [flags]" +Make substitutions. +Replace the first instance of +.LI pattern +with the string +.LI replace +on the specified line(s). +If the +.QT /pattern/repl/ +argument is not specified, the +.QT /pattern/repl/ +from the previous +.CO substitute +command is used. +.sp +If +.LI options +includes the letter +.QT c +(confirm), you will be prompted for confirmation before each replacement +is done. +An affirmative response (in English, a +.QT y +character) causes the replacement to be made. +A quit response (in English, a +.QT q +character) causes the +.CO substitute +command to be terminated. +Any other response causes the replacement not to be made, and the +.CO substitute +command continues. +If +.LI options +includes the letter +.QT g +(global), all nonoverlapping instances of +.LI pattern +in the line are replaced. +.sp +The +.CO & +version of the command is the same as not specifying a pattern +or replacement string to the +.CO substitute +command, and the +.QT & +is replaced by the pattern and replacement information from the +previous substitute command. +.sp +The +.CO ~ +version of the command is the same as +.CO & +and +.CO s , +except that the search pattern used is the last RE used in +.i any +command, not necessarily the one used in the last +.CO substitute +command. +.sp +For example, in the sequence +.ft C +.(b +s/red/blue/ +/green +~ +.)b +.ft R +the +.QT ~ +is equivalent to +.QT s/green/blue/ . +.sp +The +.CO substitute +command may be interrupted, using the terminal interrupt character. +All substitutions completed before the interrupt are retained. +.SS +.SP Line: +Set to the last line upon which a substitution was made. +.SP Options: +None. +.SE +.KY suspend +.IP "su[spend][!]" +.KY stop +.Ip "st[op][!]" +.KY <control-Z> +.Ip <control-Z> +Suspend the edit session. +Appending a +.QT ! +character to these commands turns off the +.OP autowrite +option for the command. +.SS +.SP Line: +Unchanged. +.SP Options: +Affected by the +.OP autowrite +option. +.SE +.KY tag +.IP "ta[g][!] tagstring" +Edit the file containing the specified tag. +Search for the tagstring, which can be in a different file. +If the tag is in a different file, then the new file is edited. +If the current file has been modified since the last complete write, +the +.CO tag +command will fail. +This check can be overridden by appending the +.QT ! +character to the command name. +.sp +The +.CO tag +command searches for +.LI tagstring +in the tags file(s) specified by the +.Op tags +option. +(See +.XR ctags 1 +for more information on tags files.) +.SS +.SP Line: +Set to the line indicated by the tag. +.SP Options: +Affected by the +.OP autowrite , +.OP taglength , +.OP tags +and +.OP writeany +options. +.SE +.KY tagpop +.IP "tagp[op][!] [file | number]" +Pop to the specified tag in the tags stack. +If neither +.LI file +or +.LI number +is specified, the +.CO tagpop +command pops to the most recent entry on the tags stack. +If +.LI file +or +.LI number +is specified, the +.CO tagpop +command pops to the most recent entry in the tags stack for that file, +or numbered entry in the tags stack, respectively. +(See the +.CO display +command for information on displaying the tags stack.) +.sp +If the file has been modified since the last complete write, the +.CO tagpop +command will fail. +This check may be overridden by appending a +.QT ! +character to the command name. +.SS +.SP Line: +Set to the line indicated by the tag. +.SP Options: +Affected by the +.OP autowrite , +and +.OP writeany +options. +.SE +.KY tagtop +.IP "tagt[op][!]" +Pop to the least recent tag on the tags stack, clearing the tags stack. +.sp +If the file has been modified since the last complete write, the +.CO tagpop +command will fail. +This check may be overridden by appending a +.QT ! +character to the command name. +.SS +.SP Line: +Set to the line indicated by the tag. +.SP Options: +Affected by the +.OP autowrite , +and +.OP writeany +options. +.SE +.KY unabbrev +.IP "una[bbrev] lhs" +Delete an abbreviation. +Delete +.LI lhs +from the current list of abbreviations. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY undo +.IP "u[ndo]" +Undo the last change made to the file. +Changes made by +.CO global , +.CO v , +.CO visual +and map sequences are considered a single command. +If repeated, the +.CO u +command alternates between these two states, and is its own inverse. +.SS +.SP Line: +Set to the last line modified by the command. +.SP Options: +None. +.SE +.KY unmap +.IP "unm[ap][!] lhs" +Unmap a mapped string. +Delete the command mode map definition for +.LI lhs . +If a +.QT ! +character is appended to the command name, delete the text input mode +map definition instead. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY version +.IP "ve[rsion]" +Display the version of the +.CO ex/vi +editor. +.KY visual +.IP "[line] vi[sual] [type] [count] [flags]" +.CO Ex +mode only. +Enter +.CO vi . +The +.LI type +is optional, and can be +.QT \- , +.QT + +or +.QT ^ , +as in the +.CO ex +.CO z +command, to specify the the position of the specified line in the screen +window. +(The default is to place the line at the top of the screen window.) +A +.LI count +specifies the number of lines that will initially be displayed. +(The default is the value of the +.OP window +editor option.) +.SS +.SP Line: +Unchanged unless +.LI line +is specified, in which case it is set to that line. +.SP Options: +None. +.SE +.KY visual +.IP "vi[sual][!] [+cmd] [file]" +.CO Vi +mode only. +Edit a new file. +Identical to the +.QT "edit[!] [+cmd] [file]" +command. +.KY viusage +.IP "viu[sage] [command]" +Display usage for a +.CO vi +command. +If +.LI command +is specified, a usage statement for that command is displayed. +Otherwise, usage statements for all +.CO vi +commands are displayed. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY write +.IP "[range] w[rite][!] [>>] [file]" +.Ip "[range] w[rite] [!] [file]" +.KY wn +.Ip "[range] wn[!] [>>] [file]" +.KY wq +.Ip "[range] wq[!] [>>] [file]" +Write the file. +The specified lines (the entire file, if no range is given) is written +to +.LI file . +If +.LI file +is not specified, the current pathname is used. +If +.LI file +is specified, and it exists, or if the current pathname was set using the +.CO file +command, and the file already exists, these commands will fail. +Appending a +.QT ! +character to the command name will override this check and the write +will be attempted, regardless. +.sp +Specifying the optional +.QT >> +string will cause the write to be appended to the file, in which case +no tests are made for the file already existing. +.sp +If the file is preceded by a +.QT ! +character, the program named in the SHELL environment variable is +invoked with file as its second argument, and the specified lines +are passed as standard input to that command. +The +.QT ! +in this usage must be separated from command name by at least one +whitespace character. +The special meaning of the +.QT ! +may be overridden by escaping it with a backslash +.PQ \e +character. +.sp +The +.CO wq +version of the write command will exit the editor after writing the file, +if there are no further files to edit. +Appending a +.QT ! +character to the command name or entering two +.QQ quit +commands (i.e. +.CO wq , +.CO quit , +.CO xit +or +.CO ZZ ) +in a row) will override this check and the editor will exit, +ignoring any files that have not yet been edited. +.sp +The +.CO wn +version of the write command will move to the next file after writing +the file, unless the write fails. +.SS +.SP Line: +Unchanged. +.SP Options: +Affected by the +.OP readonly +and +.OP writeany +options. +.SE +.KY xit +.IP "[range] x[it][!] [file]" +Write the file if it has been modified. +The specified lines are written to +.LI file , +if the file has been modified since the last complete write to any +file. +If no +.LI range +is specified, the entire file is written. +.sp +The +.CO xit +command will exit the editor after writing the file, +if there are no further files to edit. +Appending a +.QT ! +character to the command name or entering two +.QQ quit +commands (i.e. +.CO wq , +.CO quit , +.CO xit +or +.CO ZZ ) +in a row) will override this check and the editor will exit, +ignoring any files that have not yet been edited. +.SS +.SP Line: +Unchanged. +.SP Options: +Affected by the +.OP readonly +and +.OP writeany +options. +.SE +.KY yank +.IP "[range] ya[nk] [buffer] [count]" +Copy the specified lines to a buffer. +If no buffer is specified, the unnamed buffer is used. +.SS +.SP Line: +Unchanged. +.SP Options: +None. +.SE +.KY z +.IP "[line] z [type] [count] [flags]" +Adjust the window. +If no +.LI type +is specified, then +.LI count +lines following the specified line are displayed. +The default +.LI count +is the value of the +.OP window +option. +The +.LI type +argument changes the position at which +.LI line +is displayed on the screen by changing the number of lines +displayed before and after +.LI line . +The following +.LI type +characters may be used: +.SS +.SP \- +Place the line at the bottom of the screen. +.SP + +Place the line at the top of the screen. +.SP \&. +Place the line in the middle of the screen. +.SP ^ +Write out count lines starting +.LI "count * 2" +lines before +.LI line ; +the net effect of this is that a +.QT z^ +command following a +.CO z +command writes the previous page. +.SP = +Center +.LI line +on the screen with a line of hyphens displayed immediately before and +after it. +The number of preceding and following lines of text displayed are +reduced to account for those lines. +.SE +.SS +.SP Line: +Set to the last line displayed, with the exception of the +.Dq Li \&= +.LI type , +where the current line is set to the line specified by the command. +.SP Options: +Affected by the +.Sy window +option. +.SE diff --git a/usr.bin/vi/USD.doc/vi.ref/merge.awk b/usr.bin/vi/USD.doc/vi.ref/merge.awk new file mode 100644 index 0000000..16b5152 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/merge.awk @@ -0,0 +1,16 @@ +# @(#)merge.awk 8.3 (Berkeley) 5/26/94 +# +# merge index entries into one line per label +$1 == prev { + printf ", %s", $2; + next; +} +{ + if (NR != 1) + printf "\n"; + printf "%s \t%s", $1, $2; + prev = $1; +} +END { + printf "\n" +} diff --git a/usr.bin/vi/USD.doc/vi.ref/paper.ps b/usr.bin/vi/USD.doc/vi.ref/paper.ps new file mode 100644 index 0000000..e429d56b --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/paper.ps @@ -0,0 +1,30924 @@ +%!PS-Adobe-1.0 +%%Creator: python.bostic.com:root (Charlie,458E,7750) +%%Title: stdin (ditroff) +%%CreationDate: Mon Aug 15 14:24:12 1994 +%%EndComments +% @(#)psdit.pro 1.6 11/6/90 +% lib/psdit.pro -- prolog for psdit (ditroff) files +% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved. +% last edit: shore Sat Nov 23 20:28:03 1985 +% RCSID: $Header: psdit.pro,v 2.1 85/11/24 12:19:43 shore Rel $ + +% Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics, +% 17 Feb, 87. + +/$DITroff 140 dict def $DITroff begin +/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def +/xi{0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto + /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F}def +/PB{save /psv exch def currentpoint translate + resolution 72 div dup neg scale 0 0 moveto}def +/PE{psv restore}def +/arctoobig 90 def /arctoosmall .05 def +/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def +/tan{dup sin exch cos div}def +/point{resolution 72 div mul}def +/dround {transform round exch round exch itransform}def +/xT{/devname exch def}def +/xr{/mh exch def /my exch def /resolution exch def}def +/xp{}def +/xs{docsave restore end}def +/xt{}def +/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not + {fonts slotno fontname findfont put fontnames slotno fontname put}if}def +/xH{/fontheight exch def F}def +/xS{/fontslant exch def F}def +/s{/fontsize exch def /fontheight fontsize def F}def +/f{/fontnum exch def F}def +/F{fontheight 0 le{/fontheight fontsize def}if + fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore + fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if + makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def +/X{exch currentpoint exch pop moveto show}def +/N{3 1 roll moveto show}def +/Y{exch currentpoint pop exch moveto show}def +/S{show}def +/ditpush{}def/ditpop{}def +/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def +/AN{4 2 roll moveto 0 exch ashow}def +/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def +/AS{0 exch ashow}def +/MX{currentpoint exch pop moveto}def +/MY{currentpoint pop exch moveto}def +/MXY{moveto}def +/cb{pop}def % action on unknown char -- nothing for now +/n{}def/w{}def +/p{pop showpage xi}def +/Dt{/Dlinewidth exch def}def 1 Dt +/Ds{/Ddash exch def}def -1 Ds +/i{/Dstipple exch def}def 1 i +/Dsetlinewidth{2 Dlinewidth mul setlinewidth}def +/Dsetdash{Ddash 4 eq{[8 12]}{Ddash 16 eq{[32 36]} + {Ddash 20 eq{[32 12 8 12]}{[]}ifelse}ifelse}ifelse 0 setdash}def +/Dstroke{gsave Dsetlinewidth Dsetdash 1 setlinecap stroke grestore + currentpoint newpath moveto}def +/Dl{rlineto Dstroke}def +/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop + currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def + currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def +/Dc{dup arcellipse Dstroke}def +/De{arcellipse Dstroke}def +/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def + /cradius centerv centerv mul centerh centerh mul add sqrt def + /eradius endv endv mul endh endh mul add sqrt def + /endang endv endh atan def + /startang centerv neg centerh neg atan def + /sweep startang endang sub dup 0 lt{360 add}if def + sweep arctoobig gt + {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def + /midh midang cos midrad mul def /midv midang sin midrad mul def + midh neg midv neg endh endv centerh centerv midh midv Da + Da} + {sweep arctoosmall ge + {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def + centerv neg controldelt mul centerh controldelt mul + endv neg controldelt mul centerh add endh add + endh controldelt mul centerv add endv add + centerh endh add centerv endv add rcurveto Dstroke} + {centerh endh add centerv endv add rlineto Dstroke} + ifelse} + ifelse}def +/Dpatterns[ +[%cf[widthbits] +[8<0000000000000010>] +[8<0411040040114000>] +[8<0204081020408001>] +[8<0000103810000000>] +[8<6699996666999966>] +[8<0000800100001008>] +[8<81c36666c3810000>] +[8<0f0e0c0800000000>] +[8<0000000000000010>] +[8<0411040040114000>] +[8<0204081020408001>] +[8<0000001038100000>] +[8<6699996666999966>] +[8<0000800100001008>] +[8<81c36666c3810000>] +[8<0f0e0c0800000000>] +[8<0042660000246600>] +[8<0000990000990000>] +[8<0804020180402010>] +[8<2418814242811824>] +[8<6699996666999966>] +[8<8000000008000000>] +[8<00001c3e363e1c00>] +[8<0000000000000000>] +[32<00000040000000c00000004000000040000000e0000000000000000000000000>] +[32<00000000000060000000900000002000000040000000f0000000000000000000>] +[32<000000000000000000e0000000100000006000000010000000e0000000000000>] +[32<00000000000000002000000060000000a0000000f00000002000000000000000>] +[32<0000000e0000000000000000000000000000000f000000080000000e00000001>] +[32<0000090000000600000000000000000000000000000007000000080000000e00>] +[32<00010000000200000004000000040000000000000000000000000000000f0000>] +[32<0900000006000000090000000600000000000000000000000000000006000000>]] +[%ug +[8<0000020000000000>] +[8<0000020000002000>] +[8<0004020000002000>] +[8<0004020000402000>] +[8<0004060000402000>] +[8<0004060000406000>] +[8<0006060000406000>] +[8<0006060000606000>] +[8<00060e0000606000>] +[8<00060e000060e000>] +[8<00070e000060e000>] +[8<00070e000070e000>] +[8<00070e020070e000>] +[8<00070e020070e020>] +[8<04070e020070e020>] +[8<04070e024070e020>] +[8<04070e064070e020>] +[8<04070e064070e060>] +[8<06070e064070e060>] +[8<06070e066070e060>] +[8<06070f066070e060>] +[8<06070f066070f060>] +[8<060f0f066070f060>] +[8<060f0f0660f0f060>] +[8<060f0f0760f0f060>] +[8<060f0f0760f0f070>] +[8<0e0f0f0760f0f070>] +[8<0e0f0f07e0f0f070>] +[8<0e0f0f0fe0f0f070>] +[8<0e0f0f0fe0f0f0f0>] +[8<0f0f0f0fe0f0f0f0>] +[8<0f0f0f0ff0f0f0f0>] +[8<1f0f0f0ff0f0f0f0>] +[8<1f0f0f0ff1f0f0f0>] +[8<1f0f0f8ff1f0f0f0>] +[8<1f0f0f8ff1f0f0f8>] +[8<9f0f0f8ff1f0f0f8>] +[8<9f0f0f8ff9f0f0f8>] +[8<9f0f0f9ff9f0f0f8>] +[8<9f0f0f9ff9f0f0f9>] +[8<9f8f0f9ff9f0f0f9>] +[8<9f8f0f9ff9f8f0f9>] +[8<9f8f1f9ff9f8f0f9>] +[8<9f8f1f9ff9f8f1f9>] +[8<bf8f1f9ff9f8f1f9>] +[8<bf8f1f9ffbf8f1f9>] +[8<bf8f1fdffbf8f1f9>] +[8<bf8f1fdffbf8f1fd>] +[8<ff8f1fdffbf8f1fd>] +[8<ff8f1fdffff8f1fd>] +[8<ff8f1ffffff8f1fd>] +[8<ff8f1ffffff8f1ff>] +[8<ff9f1ffffff8f1ff>] +[8<ff9f1ffffff9f1ff>] +[8<ff9f9ffffff9f1ff>] +[8<ff9f9ffffff9f9ff>] +[8<ffbf9ffffff9f9ff>] +[8<ffbf9ffffffbf9ff>] +[8<ffbfdffffffbf9ff>] +[8<ffbfdffffffbfdff>] +[8<ffffdffffffbfdff>] +[8<ffffdffffffffdff>] +[8<fffffffffffffdff>] +[8<ffffffffffffffff>]] +[%mg +[8<8000000000000000>] +[8<0822080080228000>] +[8<0204081020408001>] +[8<40e0400000000000>] +[8<66999966>] +[8<8001000010080000>] +[8<81c36666c3810000>] +[8<f0e0c08000000000>] +[16<07c00f801f003e007c00f800f001e003c007800f001f003e007c00f801f003e0>] +[16<1f000f8007c003e001f000f8007c003e001f800fc007e003f001f8007c003e00>] +[8<c3c300000000c3c3>] +[16<0040008001000200040008001000200040008000000100020004000800100020>] +[16<0040002000100008000400020001800040002000100008000400020001000080>] +[16<1fc03fe07df0f8f8f07de03fc01f800fc01fe03ff07df8f87df03fe01fc00f80>] +[8<80>] +[8<8040201000000000>] +[8<84cc000048cc0000>] +[8<9900009900000000>] +[8<08040201804020100800020180002010>] +[8<2418814242811824>] +[8<66999966>] +[8<8000000008000000>] +[8<70f8d8f870000000>] +[8<0814224180402010>] +[8<aa00440a11a04400>] +[8<018245aa45820100>] +[8<221c224180808041>] +[8<88000000>] +[8<0855800080550800>] +[8<2844004482440044>] +[8<0810204080412214>] +[8<00>]]]def +/Dfill{ + save 6 1 roll + transform /maxy exch def /maxx exch def + transform /miny exch def /minx exch def + minx maxx gt{/minx maxx /maxx minx def def}if + miny maxy gt{/miny maxy /maxy miny def def}if + Dpatterns Dstipple 1 sub get exch 1 sub get + aload pop /stip exch def /stipw exch def /stiph 128 def + /imatrix[stipw 0 0 stiph 0 0]def + /tmatrix[stipw 0 0 stiph 0 0]def + /minx minx cvi stiph idiv stiph mul def + /miny miny cvi stipw idiv stipw mul def + eoclip 0 setgray + miny stiph maxy{ + tmatrix exch 5 exch put + minx stipw maxx{ + tmatrix exch 4 exch put tmatrix setmatrix + stipw stiph true imatrix {stip} imagemask + }for + }for + restore +}def +/Dp{Dfill Dstroke}def +/DP{Dfill currentpoint newpath moveto}def +end + +/ditstart{$DITroff begin + /nfonts 60 def % NFONTS makedev/ditroff dependent! + /fonts[nfonts{0}repeat]def + /fontnames[nfonts{()}repeat]def +/docsave save def +}def + +% character outcalls +/oc{ + /pswid exch def /cc exch def /name exch def + /ditwid pswid fontsize mul resolution mul 72000 div def + /ditsiz fontsize resolution mul 72 div def + ocprocs name known{ocprocs name get exec}{name cb}ifelse +}def +/fractm [.65 0 0 .6 0 0] def +/fraction{ + /fden exch def /fnum exch def gsave /cf currentfont def + cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto + fnum show rmoveto currentfont cf setfont(\244)show setfont fden show + grestore ditwid 0 rmoveto +}def +/oce{grestore ditwid 0 rmoveto}def +/dm{ditsiz mul}def +/ocprocs 50 dict def ocprocs begin +(14){(1)(4)fraction}def +(12){(1)(2)fraction}def +(34){(3)(4)fraction}def +(13){(1)(3)fraction}def +(23){(2)(3)fraction}def +(18){(1)(8)fraction}def +(38){(3)(8)fraction}def +(58){(5)(8)fraction}def +(78){(7)(8)fraction}def +(sr){gsave 0 .06 dm rmoveto(\326)show oce}def +(is){gsave 0 .15 dm rmoveto(\362)show oce}def +(->){gsave 0 .02 dm rmoveto(\256)show oce}def +(<-){gsave 0 .02 dm rmoveto(\254)show oce}def +(==){gsave 0 .05 dm rmoveto(\272)show oce}def +(uc){gsave currentpoint 400 .009 dm mul add translate + 8 -8 scale ucseal oce}def +end + +% an attempt at a PostScript FONT to implement ditroff special chars +% this will enable us to +% cache the little buggers +% generate faster, more compact PS out of psdit +% confuse everyone (including myself)! +50 dict dup begin +/FontType 3 def +/FontName /DIThacks def +/FontMatrix [.001 0 0 .001 0 0] def +/FontBBox [-260 -260 900 900] def% a lie but ... +/Encoding 256 array def +0 1 255{Encoding exch /.notdef put}for +Encoding + dup 8#040/space put %space + dup 8#110/rc put %right ceil + dup 8#111/lt put %left top curl + dup 8#112/bv put %bold vert + dup 8#113/lk put %left mid curl + dup 8#114/lb put %left bot curl + dup 8#115/rt put %right top curl + dup 8#116/rk put %right mid curl + dup 8#117/rb put %right bot curl + dup 8#120/rf put %right floor + dup 8#121/lf put %left floor + dup 8#122/lc put %left ceil + dup 8#140/sq put %square + dup 8#141/bx put %box + dup 8#142/ci put %circle + dup 8#143/br put %box rule + dup 8#144/rn put %root extender + dup 8#145/vr put %vertical rule + dup 8#146/ob put %outline bullet + dup 8#147/bu put %bullet + dup 8#150/ru put %rule + dup 8#151/ul put %underline + pop +/DITfd 100 dict def +/BuildChar{0 begin + /cc exch def /fd exch def + /charname fd /Encoding get cc get def + /charwid fd /Metrics get charname get def + /charproc fd /CharProcs get charname get def + charwid 0 fd /FontBBox get aload pop setcachedevice + 2 setlinejoin 40 setlinewidth + newpath 0 0 moveto gsave charproc grestore + end}def +/BuildChar load 0 DITfd put +/CharProcs 50 dict def +CharProcs begin +/space{}def +/.notdef{}def +/ru{500 0 rls}def +/rn{0 840 moveto 500 0 rls}def +/vr{0 800 moveto 0 -770 rls}def +/bv{0 800 moveto 0 -1000 rls}def +/br{0 840 moveto 0 -1000 rls}def +/ul{0 -140 moveto 500 0 rls}def +/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def +/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def +/sq{80 0 rmoveto currentpoint dround newpath moveto + 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def +/bx{80 0 rmoveto currentpoint dround newpath moveto + 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def +/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc + 50 setlinewidth stroke}def + +/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def +/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def +/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def +/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def +/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub + 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub + 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def +/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def +/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def +/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def +end + +/Metrics 50 dict def Metrics begin +/.notdef 0 def +/space 500 def +/ru 500 def +/br 0 def +/lt 416 def +/lb 416 def +/rt 416 def +/rb 416 def +/lk 416 def +/rk 416 def +/rc 416 def +/lc 416 def +/rf 416 def +/lf 416 def +/bv 416 def +/ob 350 def +/bu 350 def +/ci 750 def +/bx 750 def +/sq 750 def +/rn 500 def +/ul 500 def +/vr 0 def +end + +DITfd begin +/s2 500 def /s4 250 def /s3 333 def +/a4p{arcto pop pop pop pop}def +/2cx{2 copy exch}def +/rls{rlineto stroke}def +/currx{currentpoint pop}def +/dround{transform round exch round exch itransform} def +end +end +/DIThacks exch definefont pop +ditstart +(psc)xT +576 1 1 xr +1(Times-Roman)xf 1 f +2(Times-Italic)xf 2 f +3(Times-Bold)xf 3 f +4(Times-BoldItalic)xf 4 f +5(Helvetica)xf 5 f +6(Helvetica-Bold)xf 6 f +7(Courier)xf 7 f +8(Courier-Bold)xf 8 f +9(Symbol)xf 9 f +10(DIThacks)xf 10 f +10 s +1 f +xi +%%EndProlog + +%%Page: 1 1 +10 s 10 xH 0 xS 1 f 1 i +3 f +12 s +1796 795(Ex/Vi)N +2055(Reference)X +2491(Manual)X +2 f +10 s +2107 975(Keith)N +2300(Bostic)X +1 f +1861 1155(Computer)N +2201(Science)X +2471(Division)X +1328 1245(Department)N +1727(of)X +1814(Electrical)X +2142(Engineering)X +2554(and)X +2690(Computer)X +3030(Science)X +1754 1335(University)N +2112(of)X +2199(California,)X +2564(Berkeley)X +1856 1425(Berkeley,)N +2186(California)X +2551(94720)X +2038 1605(August)N +2289(15,)X +2409(1994)X +2 f +2168 1965(Abstract)N +1 f +776 2244(This)N +948(document)X +1294(is)X +1377(the)X +1505 0.4531(reference)AX +1836(guide)X +2045(for)X +2170(the)X +2299(4.4BSD)X +2585(implementations)X +3149(of)X +3 f +3247(nex)X +1 f +(/)S +3 f +3389(nvi)X +1 f +3495(,)X +3546(which)X +3773(are)X +576 2334(reimplementations)N +1192(of)X +1279(the)X +1397(historic)X +1657(Berkeley)X +3 f +1967(ex)X +1 f +2043(/)X +3 f +2065(vi)X +1 f +2147(editors.)X +2 f +1996 2778(Acknowledgements)N +1 f +776 3063(Bruce)N +1005(Englar)X +1256(encouraged)X +1664(the)X +1799(early)X +1997(development)X +2448(of)X +2552(the)X +2687(historic)X +3 f +2965(ex)X +1 f +3041(/)X +3 f +3063(vi)X +1 f +3163(editor.)X +3428(Peter)X +3631(Kessler)X +576 3153(helped)N +811(bring)X +1001(sanity)X +1213(to)X +1296(version)X +1553(2's)X +1672(command)X +2009(layout.)X +2270(Bill)X +2410(Joy)X +2541(wrote)X +2744(versions)X +3031(1)X +3091(and)X +3227(2.0)X +3347(through)X +3616(2.7,)X +3756(and)X +576 3243(created)N +842(the)X +973(framework)X +1359(that)X +1512(users)X +1710(see)X +1846(in)X +1941(the)X +2072(present)X +2337(editor.)X +2597(Mark)X +2804(Horton)X +3065(added)X +3291(macros)X +3557(and)X +3707(other)X +576 3333(features)N +851(and)X +987(made)X +3 f +1181(ex)X +1 f +1257(/)X +3 f +1279(vi)X +1 f +1361(work)X +1546(on)X +1646(a)X +1702(large)X +1883(number)X +2148(of)X +2235(terminals)X +2553(and)X +2689(Unix)X +2869(systems.)X +3 f +776 3456(Nvi)N +1 f +918(is)X +993(originally)X +1326(derived)X +1589(from)X +1767(software)X +2066(contributed)X +2454(to)X +2539(the)X +2660(University)X +3021(of)X +3111(California,)X +3479(Berkeley)X +3792(by)X +576 3546(Steve)N +774(Kirkendall,)X +1157(the)X +1275(author)X +1500(of)X +1587(the)X +3 f +1705(vi)X +1 f +1787(clone)X +3 f +1981(elvis)X +1 f +2132(.)X +776 3669(IEEE)N +992(Standard)X +1319(Portable)X +1628(Operating)X +1991(System)X +2268(Interface)X +2597(for)X +2733(Computer)X +3095(Environments)X +3587(\(POSIX\))X +576 3759(1003.2)N +816(style)X +987(Regular)X +1261(Expression)X +1637(support)X +1897(was)X +2042(done)X +2218(by)X +2318(Henry)X +2539(Spencer.)X +776 3882(The)N +930(curses)X +1161(library)X +1405(was)X +1560(originally)X +1901(done)X +2087(by)X +2197(Ken)X +2361(Arnold.)X +2658(Scrolling)X +2981(and)X +3127(reworking)X +3487(for)X +3 f +3611(nvi)X +1 f +3747(was)X +576 3972(done)N +752(by)X +852(Elan)X +1019(Amir.)X +776 4095(The)N +923(Institute)X +1207(of)X +1296(Electrical)X +1626(and)X +1764(Electronics)X +2147(Engineers)X +2490(has)X +2619(given)X +2820(us)X +2914(permission)X +3288(to)X +3373(reprint)X +3610(portions)X +576 4185(of)N +682(their)X +868(documentation.)X +1423(Portions)X +1728(of)X +1834(this)X +1987(document)X +2341(are)X +2478(reprinted)X +2806(and)X +2960(reproduced)X +3360(from)X +3554(IEEE)X +3766(Std)X +576 4275(1003.2-1992,)N +1031(IEEE)X +1233(Standard)X +1546(Portable)X +1841(Operating)X +2190(System)X +2453(Interface)X +2768(for)X +2890(Computer)X +3238(Environments)X +3716(\(PO-)X +576 4365(SIX\),)N +772(copyright)X +1099(1992)X +1279(by)X +1379(the)X +1497(Institute)X +1779(of)X +1866(Electrical)X +2194(and)X +2330(Electronics)X +2711(Engineers,)X +3072(Inc.)X +776 4488(The)N +921(\256nancial)X +1217(support)X +1477(of)X +1564(UUNET)X +1856(Communications)X +2422(Services)X +2714(is)X +2787(gratefully)X +3119(acknowledged.)X + +3 p +%%Page: 3 2 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3698(USD:13-3)X +576 762(1.)N +676(Description)X +1 f +3 f +776 885(Vi)N +1 f +876(is)X +949(a)X +1005(screen)X +1231(oriented)X +1514(text)X +1654(editor.)X +3 f +1902(Ex)X +1 f +2016(is)X +2090(a)X +2147(line-oriented)X +2578(text)X +2719(editor.)X +3 f +2967(Ex)X +1 f +3081(and)X +3 f +3218(vi)X +1 f +3301(are)X +3421(different)X +3719(interfaces)X +576 975(to)N +674(the)X +808(same)X +1009(program,)X +1336(and)X +1487(it)X +1566(is)X +1654(possible)X +1951(to)X +2048(switch)X +2292(back)X +2479(and)X +2630(forth)X +2821(during)X +3065(an)X +3176(edit)X +3331(session.)X +3 f +3637(View)X +1 f +3846(is)X +3934(the)X +576 1065(equivalent)N +930(of)X +1017(using)X +1210(the)X +3 f +9 f +1328(-)X +1330(-)X +3 f +1374(R)X +1 f +1452(\(read-only\))X +1834(option)X +2058(of)X +3 f +2145(vi)X +1 f +2207(.)X +776 1188(This)N +957 0.4531(reference)AX +1297(manual)X +1572(is)X +1664(the)X +1801(one)X +1956(provided)X +2280(with)X +2461(the)X +3 f +2598(nex)X +1 f +(/)S +3 f +2740(nvi)X +1 f +2885(versions)X +3191(of)X +3297(the)X +3 f +3434(ex)X +1 f +3510(/)X +3 f +3532(vi)X +1 f +3634(text)X +3794(editors.)X +3 f +576 1278(Nex)N +1 f +710(/)X +3 f +732(nvi)X +1 f +868(are)X +997(intended)X +1302(as)X +1398(bug-for-bug)X +1815(compatible)X +2200(replacements)X +2653(for)X +2776(the)X +2903(original)X +3181(Fourth)X +3423(Berkeley)X +3742(Software)X +576 1368(Distribution)N +987(\(4BSD\))X +3 f +1261(ex)X +1 f +1337(/)X +3 f +1359(vi)X +1 f +1446(programs.)X +1814(This)X +1981 0.4531(reference)AX +2307(manual)X +2568(is)X +2646(accompanied)X +3095(by)X +3201(a)X +3263(traditional-style)X +3796(manual)X +576 1458(page.)N +798(That)X +975(manual)X +1241(page)X +1423(describes)X +1752(the)X +1880(functionality)X +2319(found)X +2536(in)X +3 f +2627(ex)X +1 f +2703(/)X +3 f +2725(vi)X +1 f +2816(in)X +2907(far)X +3026(less)X +3175(detail)X +3382(than)X +3549(the)X +3676(description)X +576 1548(here.)N +781(In)X +874(addition,)X +1182(it)X +1252(describes)X +1578(the)X +1703(system)X +1952(interface)X +2261(to)X +3 f +2350(ex)X +1 f +2426(/)X +3 f +2448(vi)X +1 f +2510(,)X +2557(e.g.)X +2700(command)X +3043(line)X +3190(options,)X +3472(session)X +3730(recovery,)X +576 1638(signals,)N +838(environmental)X +1321(variables,)X +1651(and)X +1787(similar)X +2029(things.)X +776 1761(This)N +939 0.4531(reference)AX +1261(is)X +1336(intended)X +1634(for)X +1750(users)X +1937(already)X +2196(familiar)X +2472(with)X +3 f +2636(ex)X +1 f +2712(/)X +3 f +2734(vi)X +1 f +2796(.)X +2858(Anyone)X +3134(else)X +3281(should)X +3516(almost)X +3751(certainly)X +576 1851(read)N +737(a)X +795(good)X +977(tutorial)X +1230(on)X +1332(the)X +1452(editor)X +1661(\256rst.)X +1847(If)X +1923(you)X +2065(are)X +2186(in)X +2270(an)X +2368(unfamiliar)X +2723(environment,)X +3169(and)X +3306(you)X +3447(absolutely)X +3797(have)X +3970(to)X +576 1941(get)N +702(work)X +895(done)X +1079(immediately,)X +1527(see)X +1658(the)X +1784(section)X +2039(entitled)X +2308(``)X +3 f +2362(Fast)X +2538(Startup)X +1 f +2800('')X +2883(in)X +2974(the)X +3101(manual)X +3366(page.)X +3587(It)X +3665(is)X +3747(probably)X +576 2031(enough)N +832(to)X +914(get)X +1032(you)X +1172(started.)X +776 2154(There)N +984(are)X +1103(a)X +1159(few)X +1300(features)X +1575(in)X +3 f +1657(nex)X +1 f +(/)S +3 f +1799(nvi)X +1 f +1925(that)X +2065(are)X +2185(not)X +2308(found)X +2516(in)X +2599(historic)X +2860(versions)X +3148(of)X +3 f +3236(ex)X +1 f +3312(/)X +3 f +3334(vi)X +1 f +3396(.)X +3457(Some)X +3660(of)X +3748(the)X +3867(more)X +576 2244(interesting)N +941(of)X +1035(those)X +1231(features)X +1513(are)X +1639(brie\257y)X +1875(described)X +2210(in)X +2299(the)X +2424(section)X +2678(entitled)X +2945(``)X +3 f +2999(Additional)X +3389(Features)X +1 f +3688('')X +3769(near)X +3934(the)X +576 2334(end)N +719(of)X +813(this)X +955(document.)X +1338(For)X +1476(the)X +1601(rest)X +1744(of)X +1838(this)X +1980(document,)X +3 f +2343(nex)X +1 f +(/)S +3 f +2485(nvi)X +1 f +2618(is)X +2698(used)X +2872(only)X +3042(when)X +3244(it)X +3316(is)X +3397(necessary)X +3738(to)X +3828(distin-)X +576 2424(guish)N +769(it)X +833(from)X +1009(the)X +1127(historic)X +1387(implementations)X +1940(of)X +3 f +2027(ex)X +1 f +2103(/)X +3 f +2125(vi)X +1 f +2187(.)X +776 2547(Future)N +1012(versions)X +1306(of)X +1400(this)X +1542(software)X +1846(will)X +1997(be)X +2100(periodically)X +2510(made)X +2712(available)X +3030(by)X +3138(anonymous)X +3535(ftp,)X +3672(and)X +3816(can)X +3956(be)X +576 2637(retrieved)N +882(from)X +7 f +1058(ftp.cs.berkeley.edu)X +1 f +(,)S +2010(in)X +2092(the)X +2210(directory)X +7 f +2520(ucb/4bsd)X +1 f +(.)S +3 f +576 2823(2.)N +676(Startup)X +958(Information)X +1 f +3 f +776 2946(Ex)N +1 f +869(/)X +3 f +891(vi)X +1 f +981(interprets)X +1312(one)X +1456(of)X +1551(two)X +1699(possible)X +1989(environmental)X +2480(variables)X +2798(and)X +2942(reads)X +3140(up)X +3248(to)X +3338(three)X +3527(of)X +3622(\256ve)X +3770(possible)X +576 3036(\256les)N +737(during)X +974(startup.)X +1260(The)X +1413(variables)X +1731(and)X +1875(\256les)X +2036(are)X +2163(expected)X +2477(to)X +2567(contain)X +3 f +2831(ex)X +1 f +2935(commands,)X +3330(not)X +3 f +3460(vi)X +1 f +3550(commands.)X +3965(In)X +576 3126(addition,)N +879(they)X +1038(are)X +1158(interpreted)X +2 f +1527(before)X +1 f +1753(the)X +1872(\256le)X +1996(to)X +2080(be)X +2178(edited)X +2396(is)X +2471(read,)X +2652(and)X +2790(therefore)X +3103(many)X +3 f +3303(ex)X +1 f +3401(commands)X +3770(may)X +3930(not)X +576 3216(be)N +683(used.)X +901(Generally,)X +1269(any)X +1416(command)X +1763(that)X +1914(requires)X +2204(output)X +2439(to)X +2532(the)X +2660(screen)X +2896(or)X +2993(that)X +3143(needs)X +3356(a)X +3422(\256le)X +3554(upon)X +3744(which)X +3970(to)X +576 3306(operate,)N +853(will)X +997(cause)X +1196(an)X +1292(error)X +1469(if)X +1538(included)X +1834(in)X +1916(a)X +1972(startup)X +2210(\256le)X +2332(or)X +2419(environmental)X +2902(variable.)X +776 3429(Because)N +1071(the)X +3 f +1197(ex)X +1 f +1301(command)X +1645(set)X +1762(supported)X +2106(by)X +3 f +2214(nex)X +1 f +(/)S +3 f +2356(nvi)X +1 f +2490(is)X +2571(a)X +2635(superset)X +2926(of)X +3021(the)X +3147(command)X +3491(set)X +3608(supported)X +3952(by)X +576 3519(most)N +753(historical)X +1073(implementations)X +1628(of)X +3 f +1717(ex)X +1 f +1793(,)X +3 f +1835(nex)X +1 f +(/)S +3 f +1977(nvi)X +1 f +2105(can)X +2238(use)X +2366(the)X +2485(startup)X +2724(\256les)X +2878(created)X +3132(for)X +3247(the)X +3366(historical)X +3685(implemen-)X +576 3609(tations,)N +829(but)X +951(the)X +1069(converse)X +1375(may)X +1533(not)X +1655(be)X +1751(true.)X +776 3732(If)N +852(the)X +3 f +9 f +973(-)X +975(-)X +3 f +1019(s)X +1 f +1073(\(the)X +1221(historic)X +9 f +1484(-)X +1 f +1551(option\))X +1805(is)X +1881(speci\256ed,)X +2209(or)X +2299(if)X +2371(standard)X +2666(input)X +2853(is)X +2929(redirected)X +3274(from)X +3453(a)X +3512(\256le,)X +3657(all)X +3760(environ-)X +576 3822(mental)N +814(variables)X +1124(and)X +1260(startup)X +1498(\256les)X +1651(are)X +1770(ignored.)X +776 3945(Otherwise,)N +1146(startup)X +1384(\256les)X +1537(and)X +1673(environmental)X +2156(variables)X +2466(are)X +2585(handled)X +2859(in)X +2941(the)X +3059(following)X +3390(order:)X +616 4068(\(1\))N +830(The)X +975(\256le)X +7 f +1097(/etc/vi.exrc)X +1 f +1693(is)X +1766(read,)X +1945(as)X +2032(long)X +2194(as)X +2281(it)X +2345(is)X +2418(owned)X +2652(by)X +2752(root)X +2901(or)X +2988(the)X +3106(effective)X +3408(user)X +3562(ID)X +3667(of)X +3754(the)X +3872(user.)X +616 4191(\(2\))N +830(The)X +981(environmental)X +1471(variable)X +7 f +1757(NEXINIT)X +1 f +2120(\(or)X +2241(the)X +2366(variable)X +7 f +2652(EXINIT)X +1 f +(,)S +2987(if)X +7 f +3063(NEXINIT)X +1 f +3426(is)X +3506(not)X +3635(set\))X +3778(is)X +3858(inter-)X +830 4281(preted.)N +616 4404(\(3\))N +830(If)X +918(neither)X +7 f +1175(NEXINIT)X +1 f +1545(or)X +7 f +1646(EXINIT)X +1 f +1968(was)X +2127(set,)X +2270(and)X +2420(the)X +7 f +2552(HOME)X +1 f +2778(environmental)X +3275(variable)X +3568(is)X +3655(set,)X +3798(the)X +3930(\256le)X +7 f +830 4494($HOME/.nexrc)N +1 f +1430(\(or)X +1548(the)X +1670(\256le)X +7 f +1796($HOME/.exrc)X +1 f +(,)S +2368(if)X +7 f +2441($HOME/.nexrc)X +1 f +3041(does)X +3212(not)X +3338(exist\))X +3540(is)X +3617(read,)X +3800(as)X +3890(long)X +830 4584(as)N +917(the)X +1035(effective)X +1337(user)X +1491(ID)X +1596(of)X +1683(the)X +1801(user)X +1955(is)X +2028(root)X +2177(or)X +2264(is)X +2337(the)X +2455(same)X +2640(as)X +2727(the)X +2845(owner)X +3066(of)X +3153(the)X +3271(\256le.)X +616 4707(\(4\))N +830(If)X +921(the)X +3 f +1056(exrc)X +1 f +1241(option)X +1482(was)X +1644(turned)X +1886(on)X +2003(by)X +2120(one)X +2273(of)X +2377(the)X +2512(previous)X +2825(startup)X +3080(information)X +3495(sources,)X +3794(the)X +3930(\256le)X +7 f +830 4797(.nexrc)N +1 f +1142(\(or)X +1260(the)X +1382(\256le)X +7 f +1508(.exrc)X +1 f +(,)S +1792(if)X +7 f +1864(.nexrc)X +1 f +2175(does)X +2345(not)X +2470(exist\))X +2671(is)X +2747(read,)X +2929(as)X +3019(long)X +3184(as)X +3274(the)X +3395(effective)X +3700(user)X +3857(ID)X +3965(of)X +830 4887(the)N +948(user)X +1102(is)X +1175(the)X +1293(same)X +1478(as)X +1565(the)X +1683(owner)X +1904(of)X +1991(the)X +2109(\256le.)X +776 5010(No)N +894(startup)X +1132(\256le)X +1254(is)X +1327(read)X +1486(if)X +1555(it)X +1619(is)X +1692(writable)X +1975(by)X +2075(anyone)X +2327(other)X +2512(than)X +2670(its)X +2765(owner.)X +776 5133(It)N +845(is)X +918(not)X +1040(an)X +1136(error)X +1313(for)X +1427(any)X +1563(of)X +1650(the)X +1768(startup)X +2006(environmental)X +2489(variables)X +2799(or)X +2886(\256les)X +3039(not)X +3161(to)X +3243(exist.)X +776 5256(Once)N +978(all)X +1090(environmental)X +1585(variables)X +1907(are)X +2038(interpreted,)X +2438(and)X +2586(all)X +2698(startup)X +2948(\256les)X +3114(are)X +3246(read,)X +3438(the)X +3569(\256rst)X +3726(\256le)X +3861(to)X +3956(be)X +576 5346(edited)N +800(is)X +881(read)X +1048(in)X +1138(\(or)X +1260(a)X +1324(temporary)X +1682(\256le)X +1812(is)X +1893(created\).)X +2221(Then,)X +2434(any)X +2578(commands)X +2953(speci\256ed)X +3266(using)X +3467(the)X +3 f +9 f +3593(-)X +3595(-)X +3 f +3639(c)X +1 f +3702(option)X +3933(are)X +576 5436(executed,)N +902(in)X +984(the)X +1102(context)X +1358(of)X +1445(that)X +1585(\256le.)X + +4 p +%%Page: 4 3 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-4)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +576 762(3.)N +676(Recovery)X +1 f +776 885(There)N +991(is)X +1071(no)X +1178(recovery)X +1487(program)X +1786(for)X +3 f +1907(nex)X +1 f +(/)S +3 f +2049(nvi)X +1 f +2155(,)X +2202(nor)X +2336(does)X +3 f +2510(nex)X +1 f +(/)S +3 f +2652(nvi)X +1 f +2785(run)X +2919(setuid.)X +3177(Recovery)X +3512(\256les)X +3672(are)X +3799(created)X +576 975(readable)N +887(and)X +1041(writable)X +1342(by)X +1460(the)X +1596(owner)X +1835(only.)X +2055(Users)X +2276(may)X +2452(recover)X +2732(any)X +2886(\256le)X +3026(which)X +3260(they)X +3436(can)X +3585(read,)X +3781(and)X +3934(the)X +576 1065(superuser)N +904(may)X +1062(recover)X +1324(any)X +1460(edit)X +1600(session.)X +776 1188(Edit)N +952(sessions)X +1257(are)X +1399(backed)X +1670(by)X +1793(\256les)X +1969(in)X +2074(the)X +2215(directory)X +2548(named)X +2805(by)X +2929(the)X +3 f +3071(recdir)X +1 f +3325(option)X +3573(\(the)X +3742(directory)X +7 f +576 1278(/var/tmp/vi.recover)N +1 f +1508(by)X +1608(default\),)X +1898(and)X +2034(are)X +2153(named)X +2387(``)X +3 f +2441(vi.XXXXXX)X +1 f +2871('',)X +2965(where)X +3182(``)X +3 f +3236(XXXXXX)X +1 f +3584('')X +3658(is)X +3731(a)X +3787(number)X +576 1368(related)N +816(to)X +899(the)X +1018(process)X +1281(ID.)X +1428(When)X +1642(a)X +1700(\256le)X +1824(is)X +1899(\256rst)X +2045(modi\256ed,)X +2371(a)X +2429(second)X +2674(recovery)X +2978(\256le)X +3102(containing)X +3462(an)X +3560(email)X +3760(message)X +576 1458(for)N +691(the)X +810(user)X +965(is)X +1039(created,)X +1313(and)X +1450(is)X +1524(named)X +1759(``)X +3 f +1813 0.3077(recover.XXXXXX)AX +1 f +2441('',)X +2536(where,)X +2774(again,)X +2989(``)X +3 f +3043(XXXXXX)X +1 f +3391('')X +3466(is)X +3540(associated)X +3890(with)X +576 1548(the)N +698(process)X +963(ID.)X +1112(Both)X +1291(\256les)X +1448(are)X +1571(removed)X +1876(at)X +1958(the)X +2080(end)X +2220(of)X +2311(a)X +2371(normal)X +2622(edit)X +2766(session,)X +3041(but)X +3168(will)X +3317(remain)X +3565(if)X +3639(the)X +3762(edit)X +3907(ses-)X +576 1638(sion)N +729(is)X +802(abnormally)X +1187(terminated)X +1550(or)X +1637(the)X +1755(user)X +1909(runs)X +2067(the)X +3 f +2185(ex)X +2281(preserve)X +1 f +2596(command.)X +776 1761(The)N +3 f +935(recdir)X +1 f +1180(option)X +1419(may)X +1592(be)X +1703(set)X +1827(in)X +1924(either)X +2142(the)X +2275(user's)X +2502(or)X +2604(system's)X +2919(startup)X +3172(information,)X +3605(changing)X +3934(the)X +576 1851(recovery)N +887(directory.)X +1246(\(Note,)X +1478(however,)X +1804(that)X +1953(if)X +2031(a)X +2096(memory)X +2392(based)X +2604(\256le)X +2735(system)X +2985(is)X +3066(used)X +3241(as)X +3336(the)X +3462(backup)X +3722(directory,)X +576 1941(each)N +752(system)X +1002(reboot)X +1235(will)X +1388(delete)X +1609(all)X +1718(of)X +1814(the)X +1941(recovery)X +2252(\256les!)X +2461(The)X +2615(same)X +2809(caution)X +3074(applies)X +3330(to)X +3421(directories)X +3789(such)X +3965(as)X +7 f +576 2031(/tmp)N +1 f +792(which)X +1012(are)X +1135(cleared)X +1392(of)X +1483(their)X +1654(contents)X +1945(by)X +2049(a)X +2108(system)X +2353(reboot,)X +2601(or)X +7 f +2691(/usr/tmp)X +1 f +3098(which)X +3317(is)X +3393(periodically)X +3799(cleared)X +576 2121(of)N +663(old)X +785(\256les)X +938(on)X +1038(many)X +1236(systems.\))X +776 2244(The)N +926(recovery)X +1233(directory)X +1548(should)X +1786(be)X +1887(owned)X +2126(by)X +2231(root,)X +2405(or)X +2497(at)X +2580(least)X +2752(by)X +2857(a)X +2918(pseudo-user.)X +3371(In)X +3463(addition,)X +3770(if)X +3844(direc-)X +576 2334(tory)N +727(``sticky-bit'')X +1159(semantics)X +1497(are)X +1618(available,)X +1950(the)X +2070(directory)X +2382(should)X +2617(have)X +2791(the)X +2911(sticky-bit)X +3234(set)X +3344(so)X +3436(that)X +3577(\256les)X +3731(may)X +3890(only)X +576 2424(be)N +676(removed)X +981(by)X +1085(their)X +1256(owners.)X +1552(The)X +1702(recovery)X +2009(directory)X +2324(must)X +2504(be)X +2605(read,)X +2789(write,)X +2999(and)X +3140(executable)X +3509(by)X +3614(any)X +3755(user,)X +3934(i.e.)X +576 2514(mode)N +774(1777.)X +776 2637(If)N +850(the)X +968(recovery)X +1270(directory)X +1581(does)X +1749(not)X +1872(exist,)X +3 f +2064(ex)X +1 f +2140(/)X +3 f +2162(vi)X +1 f +2245(will)X +2390(attempt)X +2651(to)X +2734(create)X +2948(it.)X +3053(This)X +3216(can)X +3349(result)X +3548(in)X +3631(the)X +3750(recovery)X +576 2727(directory)N +895(being)X +1102(owned)X +1345(by)X +1454(a)X +1518(normal)X +1773(user,)X +1955(which)X +2179(means)X +2412(that)X +2560(that)X +2708(user)X +2870(will)X +3022(be)X +3126(able)X +3288(to)X +3378(remove)X +3647(other)X +3840(user's)X +576 2817(recovery)N +880(and)X +1018(backup)X +1272(\256les.)X +1467(This)X +1631(is)X +1706(annoying,)X +2046(but)X +2170(is)X +2245(not)X +2369(a)X +2427(security)X +2703(issue)X +2886(as)X +2976(the)X +3097(user)X +3254(cannot)X +3491(otherwise)X +3826(access)X +576 2907(or)N +663(modify)X +914(the)X +1032(\256les.)X +776 3030(The)N +924(recovery)X +1229(\256le)X +1354(has)X +1484(all)X +1587(of)X +1677(the)X +1798(necessary)X +2134(information)X +2535(in)X +2621(it)X +2689(to)X +2775(enable)X +3009(the)X +3131(user)X +3289(to)X +3375(recover)X +3641(the)X +3763(edit)X +3907(ses-)X +576 3120(sion.)N +774(In)X +866(addition,)X +1173(it)X +1242(has)X +1374(all)X +1479(of)X +1571(the)X +1694(necessary)X +2032(email)X +2235(headers)X +2505(for)X +2 f +2623(sendmail)X +1 f +2912(\(8\).)X +3070(When)X +3286(the)X +3408(system)X +3654(is)X +3731(rebooted,)X +576 3210(all)N +677(of)X +765(the)X +884(\256les)X +1038(in)X +7 f +1121(/var/tmp/vi.recover)X +1 f +2054(named)X +2289(``)X +3 f +2343 0.3077(recover.XXXXXX)AX +1 f +2971('')X +3046(should)X +3280(be)X +3377(sent)X +3527(to)X +3611(their)X +3780(owners,)X +576 3300(by)N +684(email,)X +910(using)X +1111(the)X +3 f +9 f +1237(-)X +1239(-)X +3 f +1283(t)X +1 f +1338(option)X +1570(of)X +3 f +1665(sendmail)X +1 f +1999(\(or)X +2121(a)X +2185(similar)X +2434(mechanism)X +2826(in)X +2915(other)X +3107(mailers\).)X +3437(If)X +3 f +3518(ex)X +1 f +3594(/)X +3 f +3616(vi)X +1 f +3705(receives)X +3996(a)X +576 3390(hangup)N +839(\(SIGHUP\))X +1209(signal,)X +1447(or)X +1541(the)X +1666(user)X +1828(executes)X +2133(the)X +3 f +2259(ex)X +2363(preserve)X +1 f +2686(command,)X +3 f +3050(ex)X +1 f +3126(/)X +3 f +3148(vi)X +1 f +3238(will)X +3390(automatically)X +3854(email)X +576 3480(the)N +694(recovery)X +996(information)X +1394(to)X +1476(the)X +1594(user.)X +776 3603(If)N +853(your)X +1023(system)X +1268(does)X +1438(not)X +1564(have)X +1740(the)X +3 f +1862(sendmail)X +1 f +2192(utility)X +2406(\(or)X +2524(a)X +2584(mailer)X +2813(program)X +3109(which)X +3329(supports)X +3624(its)X +3723(interface\))X +576 3693(the)N +700(source)X +936(\256le)X +7 f +1063(nvi/common/recover.c)X +1 f +2048(will)X +2197(have)X +2374(to)X +2461(be)X +2562(modi\256ed)X +2871(to)X +2958(use)X +3090(your)X +3262(local)X +3443(mail)X +3610(delivery)X +3898(pro-)X +576 3783(grams.)N +833(Note,)X +1030(if)X +3 f +1100(nex)X +1 f +(/)S +3 f +1242(nvi)X +1 f +1369(is)X +1443(changed)X +1732(to)X +1815(use)X +1944(another)X +2207(mailer,)X +2454(it)X +2520(is)X +2595(important)X +2928(to)X +3012(remember)X +3360(that)X +3502(the)X +3622(owner)X +3845(of)X +3934(the)X +576 3873(\256le)N +708(given)X +916(to)X +1008(the)X +1136(mailer)X +1371(is)X +1454(the)X +3 f +1582(nex)X +1 f +(/)S +3 f +1724(nvi)X +1 f +1860(user,)X +2044(so)X +2145(nothing)X +2419(in)X +2511(the)X +2638(\256le)X +2769(should)X +3011(be)X +3116(trusted)X +3363(as)X +3459(it)X +3532(may)X +3699(have)X +3880(been)X +576 3963(modi\256ed)N +880(in)X +962(an)X +1058(effort)X +1257(to)X +1339(compromise)X +1755(the)X +1873(system.)X +776 4086(Finally,)N +1046(the)X +1168(owner)X +1393(execute)X +1663(bit)X +1771(is)X +1848(set)X +1961(on)X +2065(backup)X +2321(\256les)X +2478(when)X +2676(they)X +2838(are)X +2961(created,)X +3238(and)X +3378(unset)X +3571(when)X +3770(they)X +3933(are)X +576 4176(\256rst)N +724(modi\256ed,)X +1052(e.g.)X +1192(backup)X +1448(\256les)X +1605(that)X +1749(have)X +1925(no)X +2029(associated)X +2383(email)X +2585(recovery)X +2891(\256le)X +3017(will)X +3165(have)X +3341(this)X +3480(bit)X +3588(set.)X +3741(\(There)X +3979(is)X +576 4266(also)N +735(a)X +801(small)X +1004(window)X +1292(where)X +1519(empty)X +1749(\256les)X +1912(can)X +2054(be)X +2160(created)X +2424(and)X +2571(not)X +2704(yet)X +2833(have)X +3016(this)X +3162(bit)X +3277(set.)X +3437(This)X +3610(is)X +3694(due)X +3841(to)X +3934(the)X +576 4356(method)N +836(in)X +918(which)X +1134(the)X +1252(\256les)X +1405(are)X +1524(created.\))X +1844(Such)X +2024(\256les)X +2177(should)X +2410(be)X +2506(deleted)X +2758(when)X +2952(the)X +3070(system)X +3312(reboots.)X +776 4479(A)N +884(simple)X +1147(way)X +1331(to)X +1443(do)X +1573(this)X +1738(cleanup)X +2038(is)X +2141(to)X +2253(insert)X +2481(the)X +2630(following)X +2992(Bourne)X +3279(shell)X +3481(script)X +3710(into)X +3885(your)X +7 f +576 4569(/etc/rc.local)N +1 f +1224(\(or)X +1342(other)X +1531(startup\))X +1800(\256le.)X +1966(The)X +2115(script)X +2316(should)X +2552(work)X +2740(with)X +2905(the)X +3026(historic)X +3289(Bourne)X +3548(shell,)X +3742(a)X +3801(POSIX)X +576 4659(1003.2)N +818(shell)X +991(or)X +1080(the)X +1201(Korn)X +1389(shell.)X +1603(\(A)X +1711(copy)X +1890(of)X +1980(this)X +2118(script)X +2319(is)X +2395(included)X +2694(as)X +7 f +2784(nvi/install/recover.script)X +1 f +576 4749(in)N +658(the)X +3 f +776(nex)X +1 f +(/)S +3 f +918(nvi)X +1 f +1044(distribution.\))X + +5 p +%%Page: 5 4 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3698(USD:13-5)X +7 f +896 762(#)N +1184(@\(#\)recover.script)X +2336(8.4)X +2528(\(Berkeley\))X +3056(8/13/94)X +896 852(#)N +896 942(#)N +992(Recover)X +1376(nvi)X +1568(editor)X +1904(files:)X +896 1032(RECDIR=/var/tmp/vi.recover)N +896 1122(SENDMAIL=/usr/lib/sendmail)N +896 1212(echo)N +1136('Recovering)X +1712(nvi)X +1904(editor)X +2240(sessions.')X +896 1392(#)N +992(Unmodified)X +1520(nvi)X +1712(editor)X +2048(backup)X +2384(files)X +2672(are)X +2864(either)X +3200(zero)X +3440(length)X +3776(or)X +896 1482(#)N +992(have)X +1232(the)X +1424(execute)X +1808(bit)X +2000(set.)X +2288(Delete)X +2624(both)X +2864(cases.)X +896 1572(vibackup=`echo)N +1616($RECDIR/vi.*`)X +896 1662(if)N +1040([)X +1136("$vibackup")X +1712(!=)X +1856("$RECDIR/vi.*")X +2576(];)X +2720(then)X +1184 1752(for)N +1376(i)X +1472(in)X +1616($vibackup;)X +2144(do)X +1472 1842(if)N +1616(test)X +1856(-x)X +2000($i)X +2144(-o)X +2288(!)X +2384(-s)X +2528($i;)X +2720(then)X +1760 1932(rm)N +1904($i)X +1472 2022(fi)N +1184 2112(done)N +896 2202(fi)N +896 2382(#)N +992(It)X +1136(is)X +1280(possible)X +1712(to)X +1856(get)X +2048(incomplete)X +2576(recovery)X +3008(files,)X +3344(if)X +3488(the)X +3680(editor)X +896 2472(#)N +992(crashes)X +1376(at)X +1520(the)X +1712(right)X +2000(time.)X +2336(Delete)X +2672(any)X +2864(recovery)X +3296(files)X +3584(without)X +896 2562(#)N +992(corresponding)X +1664(backup)X +2000(files,)X +2336(otherwise)X +2816(send)X +3056(mail)X +3296(to)X +3440(the)X +3632(user.)X +896 2652(virecovery=`echo)N +1712($RECDIR/recover.*`)X +896 2742(if)N +1040([)X +1136("$virecovery")X +1808(!=)X +1952("$RECDIR/recover.*")X +2912(];)X +3056(then)X +1184 2832(for)N +1376(i)X +1472(in)X +1616($virecovery;)X +2240(do)X +1472 2922(recfile=`awk)N +2096('/\303X-vi-recover-path:/{print)X +3488($2}')X +3728(<)X +3824($i`)X +1472 3012(if)N +1616(test)X +1856(!)X +1952(-n)X +2096($recfile)X +2528(-a)X +2672(-s)X +2816($recfile;)X +3296(then)X +1760 3102($SENDMAIL)N +2240(-t)X +2384(<)X +2480($i)X +1472 3192(else)N +1760 3282(rm)N +1904($i)X +1472 3372(fi)N +1184 3462(done)N +896 3552(fi)N +1 f +776 3798(If)N +859(you)X +1008(are)X +1136(not)X +1267(using)X +1469(the)X +1596(default)X +1848(value)X +2051(for)X +2174(the)X +3 f +2301(recdir)X +1 f +2540(option,)X +2793(be)X +2898(sure)X +3062(to)X +3154(substitute)X +3490(the)X +3618(value)X +3822(you're)X +576 3888(using)N +769(for)X +883(the)X +7 f +1001(RECDIR)X +1 f +1309(value)X +1503(in)X +1585(the)X +1703(recovery)X +2005(script.)X +776 4011(If)N +882(the)X +1032(path)X +1222(of)X +1341(your)X +1540(system's)X +3 f +1872(sendmail)X +1 f +2230(program)X +2555(\(or)X +2702(whatever)X +3050(mailer)X +3308(you're)X +3571(using\))X +3824(is)X +3930(not)X +7 f +576 4101(/usr/lib/sendmail)N +1 f +(,)S +1451(be)X +1566(sure)X +1739(to)X +1840(substitute)X +2184(the)X +2320(correct)X +2582(pathname)X +2932(for)X +3064(the)X +7 f +3200(SENDMAIL)X +1 f +3622(value)X +3834(in)X +3934(the)X +576 4191(recovery)N +878(script.)X +1116(Consult)X +1384(the)X +1502(manual)X +1758(page)X +1930(for)X +2044(details)X +2273(on)X +2373(recovering)X +2737(preserved)X +3070(or)X +3157(aborted)X +3418(editing)X +3660(sessions.)X +3 f +576 4377(4.)N +676(Sizing)X +904(the)X +1031(Screen)X +1 f +776 4500(The)N +926(size)X +1076(of)X +1168(the)X +1291(screen)X +1522(can)X +1659(be)X +1760(set)X +1874(in)X +1961(a)X +2022(number)X +2292(of)X +2384(ways.)X +3 f +2614(Ex)X +1 f +2707(/)X +3 f +2729(vi)X +1 f +2817(takes)X +3008(the)X +3132(following)X +3469(steps)X +3655(until)X +3827(values)X +576 4590(are)N +695(obtained)X +991(for)X +1105(both)X +1267(the)X +1385(number)X +1650(of)X +1737(rows)X +1913(and)X +2049(number)X +2314(of)X +2401(columns)X +2692(in)X +2774(the)X +2892(screen.)X +616 4713(\(1\))N +830(If)X +904(the)X +1022(environmental)X +1505(variable)X +7 f +1784(LINES)X +1 f +2044(exists,)X +2266(it)X +2330(is)X +2403(used)X +2570(to)X +2652(specify)X +2904(the)X +3022(number)X +3287(of)X +3374(rows)X +3550(in)X +3632(the)X +3750(screen.)X +616 4836(\(2\))N +830(If)X +909(the)X +1032(environmental)X +1520(variable)X +7 f +1804(COLUMNS)X +1 f +2165(exists,)X +2393(it)X +2463(is)X +2542(used)X +2715(to)X +2803(specify)X +3061(the)X +3185(number)X +3456(of)X +3549(columns)X +3846(in)X +3934(the)X +830 4926(screen.)N +616 5049(\(3\))N +830(The)X +975(TIOCGWINSZ)X +2 f +1494(ioctl)X +1 f +1636(\(2\))X +1750(is)X +1823(attempted)X +2159(on)X +2259(the)X +2377(standard)X +2669(error)X +2846(\256le)X +2968(descriptor.)X +616 5172(\(4\))N +830(The)X +978(termcap)X +1260(entry)X +1448(\(or)X +1565(terminfo)X +1864(entry)X +2053(on)X +2157(System)X +2416(V)X +2498(machines\))X +2852(is)X +2929(checked)X +3217(for)X +3335(the)X +3457(``li'')X +3633(entry)X +3822(\(rows\))X +830 5262(and)N +966(the)X +1084(``co'')X +1288(entry)X +1473(\(columns\).)X +616 5385(\(5\))N +830(The)X +975(number)X +1240(of)X +1327(rows)X +1503(is)X +1576(set)X +1685(to)X +1767(24,)X +1887(and)X +2023(the)X +2141(number)X +2406(of)X +2493(columns)X +2784(is)X +2857(set)X +2966(to)X +3048(80.)X +776 5508(If)N +851(a)X +908(window)X +1187(change)X +1436(size)X +1582(signal)X +1794(\(SIGWINCH\))X +2270(is)X +2344(received,)X +2658(the)X +2777(new)X +2932(window)X +3211(size)X +3357(is)X +3431(retrieved)X +3739(using)X +3934(the)X +576 5598(TIOCGWINSZ)N +2 f +1095(ioctl)X +1 f +1237(\(2\))X +1351(call,)X +1507(and)X +1643(all)X +1743(other)X +1928(information)X +2326(is)X +2399(ignored.)X + +6 p +%%Page: 6 5 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-6)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +576 762(5.)N +676(Character)X +1049(Display)X +1 f +776 885(In)N +865(both)X +3 f +1030(ex)X +1 f +1129(and)X +3 f +1268(vi)X +1 f +1353(printable)X +1661(characters)X +2011(as)X +2101(de\256ned)X +2360(by)X +2 f +2463(isprint)X +1 f +2671(\(3\))X +2788(are)X +2910(displayed)X +3240(using)X +3436(the)X +3557(local)X +3736(character)X +576 975(set.)N +776 1098(Non-printable)N +1255(characters,)X +1631(for)X +1754(which)X +2 f +1980(iscntrl)X +1 f +2184(\(3\))X +2308(returns)X +2561(true,)X +2736(and)X +2882(which)X +3108(are)X +3237(less)X +3387(than)X +3555(octal)X +3741(\\076,)X +3933(are)X +576 1188(displayed)N +915(as)X +1014(the)X +1144(string)X +1357(``)X +7 f +1411(\303<character>)X +1 f +('',)S +2092(where)X +7 f +2320(<character>)X +1 f +2879(is)X +2963(the)X +3092(character)X +3419(that)X +3570(is)X +3654(the)X +3783(original)X +576 1278 0.3250(character's)AN +961(value)X +1166(offset)X +1380(from)X +1568(the)X +1698(``)X +7 f +1752(@)X +1 f +('')S +1886(character.)X +2254(For)X +2397(example,)X +2721(the)X +2851(octal)X +3039(character)X +3367(\\001)X +3541(is)X +3626(displayed)X +3965(as)X +576 1368(``)N +7 f +630(\303A)X +1 f +(''.)S +845(If)X +2 f +924(iscntrl)X +1 f +1128(\(3\))X +1247(returns)X +1495(true)X +1645(for)X +1764(the)X +1887(octal)X +2068(character)X +2389(\\177,)X +2576(it)X +2645(is)X +2723(displayed)X +3054(as)X +3145(the)X +3267(string)X +3473(``)X +7 f +3527(\303?)X +1 f +(''.)S +3741(All)X +3867(other)X +576 1458(characters)N +947(are)X +1090(displayed)X +1441(as)X +1552(either)X +1779(hexadecimal)X +2229(values,)X +2498(in)X +2604(the)X +2746(form)X +2946(``)X +7 f +3000(0x<high-halfbyte>)X +3888(...)X +576 1548(0x<low-halfbyte>)N +1 f +('',)S +1469(or)X +1587(as)X +1705(octal)X +1911(values,)X +2186(in)X +2298(the)X +2446(form)X +2652(``)X +7 f +2706(\\<high-one-or-two-bits>)X +3888(...)X +576 1638(\\<low-three-bits>)N +1 f +(''.)S +1506(The)X +1651(display)X +1902(of)X +1989(unknown)X +2307(characters)X +2654(is)X +2727(based)X +2930(on)X +3030(the)X +3148(value)X +3342(of)X +3429(the)X +3 f +3547(octal)X +1 f +3732(option.)X +776 1761(In)N +3 f +864(vi)X +1 f +947(command)X +1285(mode,)X +1505(the)X +1625(cursor)X +1848(is)X +1923(always)X +2168(positioned)X +2523(on)X +2625(the)X +2745(last)X +2878(column)X +3140(of)X +3229(characters)X +3578(which)X +3796(take)X +3952(up)X +576 1851(more)N +765(than)X +927(one)X +1067(column)X +1331(on)X +1435(the)X +1557(screen.)X +1827(In)X +3 f +1918(vi)X +1 f +2003(text)X +2146(input)X +2333(mode,)X +2554(the)X +2675(cursor)X +2899(is)X +2975(positioned)X +3331(on)X +3434(the)X +3555(\256rst)X +3702(column)X +3965(of)X +576 1941(characters)N +923(which)X +1139(take)X +1293(up)X +1393(more)X +1578(than)X +1736(one)X +1872(column)X +2132(on)X +2232(the)X +2350(screen.)X +3 f +576 2127(6.)N +676(Multiple)X +989(Screens)X +1 f +3 f +776 2250(Nvi)N +1 f +916(supports)X +1207(multiple)X +1493(screens)X +1750(by)X +1851(dividing)X +2138(the)X +2257(window)X +2536(into)X +2681(regions.)X +2978(It)X +3048(also)X +3198(supports)X +3490(stacks)X +3707(of)X +3795(screens)X +576 2340(by)N +676(permitting)X +1029(the)X +1147(user)X +1301(to)X +1383(change)X +1631(the)X +1749(set)X +1858(of)X +1945(screens)X +2202(that)X +2342(are)X +2461(currently)X +2771(displayed.)X +776 2463(The)N +924(command)X +3 f +1263(split)X +1 f +1432(divides)X +1686(the)X +1807(current)X +2058(screen)X +2287(into)X +2434(two)X +2577(regions)X +2836(of)X +2926(approximately)X +3412(equal)X +3609(size.)X +3797(If)X +3875(a)X +3935(list)X +576 2553(of)N +668(\256les)X +826(are)X +950(speci\256ed)X +1260(as)X +1352(arguments)X +1711(to)X +1798(the)X +3 f +1921(split)X +1 f +2092(command,)X +2452(the)X +2574(list)X +2695(of)X +2786(\256les)X +2943(to)X +3029(be)X +3129(edited)X +3349(is)X +3426(initialized)X +3770(as)X +3861(if)X +3934(the)X +3 f +576 2643(next)N +1 f +747(command)X +1087(had)X +1227(been)X +1403(used.)X +1614(If)X +1692(no)X +1796(\256les)X +1953(are)X +2076(speci\256ed,)X +2405(the)X +2527(new)X +2685(screen)X +2915(will)X +3063(begin)X +3265(by)X +3370(editing)X +3617(the)X +3740(same)X +3930(\256le)X +576 2733(as)N +663(the)X +781(previous)X +1077(screen.)X +776 2856(When)N +992(more)X +1181(than)X +1343(one)X +1483(screen)X +1713(is)X +1790(editing)X +2036(a)X +2097(\256le,)X +2244(changes)X +2528(in)X +2615(any)X +2756(screen)X +2987(are)X +3111(re\257ected)X +3413(in)X +3500(all)X +3605(other)X +3795(screens)X +576 2946(editing)N +820(the)X +940(same)X +1127(\256le.)X +1291(Exiting)X +1548(any)X +1686(screen)X +1914(without)X +2180(saving)X +2410(any)X +2547(changes)X +2827(\(or)X +2942(explicitly)X +3265(discarding)X +3620(them\))X +3828(is)X +3902(per-)X +576 3036(mitted)N +800(until)X +966(the)X +1084(last)X +1215(screen)X +1441(editing)X +1683(the)X +1801(\256le)X +1923(is)X +1996(exited.)X +776 3159(The)N +3 f +923(resize)X +1 f +1142(command)X +1480(permits)X +1742(resizing)X +2018(of)X +2107(individual)X +2453(screens.)X +2752(Screens)X +3024(may)X +3184(be)X +3282(grown,)X +3529(shrunk)X +3769(or)X +3858(set)X +3970(to)X +576 3249(an)N +672(absolute)X +959(number)X +1224(of)X +1311(rows.)X +776 3372(The)N +3 f +921(\303W)X +1 f +1048(command)X +1384(is)X +1457(used)X +1624(to)X +1706(switch)X +1935(between)X +2223(screens.)X +2520(Each)X +3 f +2701(\303W)X +1 f +2829(moves)X +3059(to)X +3142(the)X +3261(next)X +3420(lower)X +3624(screen)X +3851(in)X +3934(the)X +576 3462(window,)N +874(or)X +961(to)X +1043(the)X +1161(\256rst)X +1305(screen)X +1531(in)X +1613(the)X +1731(window)X +2009(if)X +2078(there)X +2259(are)X +2378(no)X +2478(lower)X +2681(screens.)X +776 3585(The)N +3 f +925(bg)X +1 f +1033(command)X +1374(``backgrounds'')X +1917(the)X +2040(current)X +2293(screen.)X +2564(The)X +2714(screen)X +2945(disappears)X +3309(from)X +3490(the)X +3613(window,)X +3916(and)X +576 3675(the)N +702(rows)X +886(it)X +958(occupied)X +1276(are)X +1403(taken)X +1605(over)X +1776(by)X +1884(a)X +1948(neighboring)X +2363(screen.)X +2637(It)X +2714(is)X +2795(an)X +2899(error)X +3083(to)X +3172(attempt)X +3439(to)X +3528(background)X +3934(the)X +576 3765(only)N +738(screen)X +964(in)X +1046(the)X +1164(window.)X +776 3888(The)N +3 f +935(display)X +1212(screens)X +1 f +1496(command)X +1846(displays)X +2142(the)X +2274(names)X +2513(of)X +2614(the)X +2747(\256les)X +2915(associated)X +3280(with)X +3457(the)X +3590(current)X +3853(back-)X +576 3978(grounded)N +899(screens)X +1156(in)X +1238(the)X +1356(window.)X +776 4101(The)N +3 f +932(fg)X +1031([\256le])X +1 f +1219(command)X +1567(``foregrounds'')X +2095(the)X +2225(\256rst)X +2381(screen)X +2619(in)X +2713(the)X +2843(list)X +2972(of)X +3071(backgrounded)X +3558(screens)X +3827(that)X +3979(is)X +576 4191(associated)N +934(with)X +1103(its)X +1205(argument.)X +1575(If)X +1656(no)X +1763(\256le)X +1892(argument)X +2222(is)X +2302(speci\256ed,)X +2634(the)X +2759(\256rst)X +2910(screen)X +3143(on)X +3250(the)X +3375(list)X +3499(is)X +3579(foregrounded.)X +576 4281(Foregrounding)N +1072(consists)X +1345(of)X +1432(backgrounding)X +1933(the)X +2051(current)X +2299(screen,)X +2545(and)X +2681(replacing)X +3000(its)X +3095(space)X +3294(in)X +3376(the)X +3494(window)X +3772(with)X +3934(the)X +576 4371(foregrounded)N +1029(screen.)X +776 4494(If)N +852(the)X +972(last)X +1105(screen)X +1333(in)X +1417(the)X +1537(window)X +1817(is)X +1892(exited,)X +2131(and)X +2270(there)X +2454(are)X +2576(backgrounded)X +3054(screens,)X +3334(the)X +3455(\256rst)X +3602(screen)X +3831(on)X +3934(the)X +576 4584(list)N +693(of)X +780(backgrounded)X +1255(screens)X +1512(takes)X +1697(over)X +1860(the)X +1978(window.)X +3 f +576 4770(7.)N +676(Regular)X +972(Expressions)X +1400(and)X +1548(Replacement)X +2014(Strings)X +1 f +776 4893(Regular)N +1050(expressions)X +1444(are)X +1563(used)X +1730(in)X +1812(line)X +1952(addresses,)X +2301(as)X +2389(the)X +2508(\256rst)X +2653(part)X +2799(of)X +2887(the)X +3 f +3006(ex)X +3103(substitute)X +1 f +3436(,)X +3 f +3477(global)X +1 f +3685(,)X +3726(and)X +3 f +3863(vglo-)X +576 4983(bal)N +1 f +702(commands,)X +1089(and)X +1225(in)X +1307(search)X +1533(patterns.)X +776 5106(The)N +927(regular)X +1181(expressions)X +1581(supported)X +1923(by)X +3 f +2030(ex)X +1 f +2106(/)X +3 f +2128(vi)X +1 f +2217(are,)X +2363(by)X +2470(default,)X +2740(the)X +2865(Basic)X +3070(Regular)X +3351(Expressions)X +3765(\(BRE's\))X +576 5196(described)N +909(in)X +996(the)X +1119(IEEE)X +1318(POSIX)X +1574(Standard)X +1884(1003.2.)X +2169(The)X +3 f +2319(extended)X +1 f +2651(option)X +2880(causes)X +3115(all)X +3220(regular)X +3472(expressions)X +3870(to)X +3956(be)X +576 5286(interpreted)N +976(as)X +1095(the)X +1245(Extended)X +1600(Regular)X +1906(Expressions)X +2345(\(ERE's\))X +2661(described)X +3022(by)X +3155(the)X +3306(same)X +3524(standard.)X +3889(\(See)X +2 f +576 5376(re_format)N +1 f +(\(7\))S +1025(for)X +1154(more)X +1354(information.\))X +1834(Generally)X +2186(speaking,)X +2526(BRE's)X +2774(are)X +2908(the)X +3040(Regular)X +3328(Expressions)X +3749(found)X +3970(in)X +2 f +576 5466(ed)N +1 f +652(\(1\))X +766(and)X +2 f +902(grep)X +1 f +1049(\(1\),)X +1183(and)X +1319(ERE's)X +1548(are)X +1667(the)X +1785(Regular)X +2059(Expressions)X +2466(found)X +2673(in)X +2 f +2755(egrep)X +1 f +2938(\(1\).)X +776 5589(The)N +922(following)X +1254(is)X +1328(not)X +1451(intended)X +1748(to)X +1831(provide)X +2097(a)X +2154(description)X +2532(of)X +2621(Regular)X +2897(Expressions.)X +3346(The)X +3493(information)X +3893(here)X +576 5679(only)N +742(describes)X +1065(strings)X +1302(and)X +1442(characters)X +1793(which)X +2013(have)X +2189(special)X +2436(meanings)X +2766(in)X +2851(the)X +3 f +2972(ex)X +1 f +3048(/)X +3 f +3070(vi)X +1 f +3155(version)X +3414(of)X +3504(RE's,)X +3707(or)X +3797(options)X +576 5769(which)N +792(change)X +1040(the)X +1158(meanings)X +1485(of)X +1572(characters)X +1919(that)X +2059(normally)X +2368(have)X +2540(special)X +2783(meanings)X +3110(in)X +3192(RE's.)X + +7 p +%%Page: 7 6 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3698(USD:13-7)X +1 f +616 762(\(1\))N +830(An)X +948(empty)X +1168(RE)X +1290(\(e.g.)X +1473(``)X +7 f +1527(//)X +1 f +('')S +1697(or)X +1784(``)X +7 f +1838(??)X +1 f +('')S +2028(is)X +2101(equivalent)X +2455(to)X +2537(the)X +2655(last)X +2786(RE)X +2908(used.)X +616 885(\(2\))N +830(The)X +975(construct)X +1289(``)X +7 f +1343(\\<)X +1 f +('')S +1513(matches)X +1796(the)X +1914(beginning)X +2254(of)X +2341(a)X +2397(word.)X +616 1008(\(3\))N +830(The)X +975(construct)X +1289(``)X +7 f +1343(\\>)X +1 f +('')S +1513(matches)X +1796(the)X +1914(end)X +2050(of)X +2137(a)X +2193(word.)X +616 1131(\(4\))N +830(The)X +975(character)X +1291(``)X +7 f +1345(\304)X +1 f +('')S +1467(matches)X +1750(the)X +1868(replacement)X +2281(part)X +2426(of)X +2513(the)X +2631(last)X +3 f +2762(substitute)X +1 f +3115(command.)X +776 1254(When)N +992(the)X +3 f +1114(magic)X +1 f +1343(option)X +1571(is)X +2 f +1648(not)X +1 f +1774(set,)X +1907(the)X +2029(only)X +2195(characters)X +2546(with)X +2712(special)X +2959(meanings)X +3290(are)X +3413(a)X +3473(``)X +7 f +3527(\303)X +1 f +('')S +3653(character)X +3974(at)X +576 1344(the)N +698(beginning)X +1042(of)X +1133(an)X +1233(RE,)X +1379(a)X +1439(``)X +7 f +1493($)X +1 f +('')S +1619(character)X +1939(at)X +2021(the)X +2143(end)X +2282(of)X +2372(an)X +2471(RE,)X +2616(and)X +2755(the)X +2876(escaping)X +3180(character)X +3499(``)X +7 f +3553(\\)X +1 f +(''.)S +3718(The)X +3866(char-)X +576 1434(acters)N +788(``)X +7 f +842(.)X +1 f +('',)S +988(``)X +7 f +1042(*)X +1 f +('',)S +1188(``)X +7 f +1242([)X +1 f +('')S +1368(and)X +1508(``)X +7 f +1562(\304)X +1 f +('')S +1688(are)X +1811(treated)X +2054(as)X +2145(ordinary)X +2441(characters)X +2793(unless)X +3018(preceded)X +3334(by)X +3439(a)X +3500(``)X +7 f +3554(\\)X +1 f +('';)S +3703(when)X +3902(pre-)X +576 1524(ceded)N +784(by)X +884(a)X +940(``)X +7 f +994(\\)X +1 f +('')S +1116(they)X +1274(regain)X +1495(their)X +1662(special)X +1905(meaning.)X +776 1647(Replacement)N +1215(strings)X +1448(are)X +1567(the)X +1685(second)X +1928(part)X +2073(of)X +2160(a)X +3 f +2216(substitute)X +1 f +2569(command.)X +776 1770(The)N +924(character)X +1243(``)X +7 f +1297(&)X +1 f +('')S +1422(\(or)X +1539(``)X +7 f +1593(\\&)X +1 f +('')S +1766(if)X +1839(the)X +3 f +1961(magic)X +1 f +2190(option)X +2418(is)X +2 f +2495(not)X +1 f +2621(set\))X +2761(in)X +2847(the)X +2969(replacement)X +3386(string)X +3592(stands)X +3816(for)X +3934(the)X +576 1860(text)N +717(matched)X +1010(by)X +1111(the)X +1230(RE)X +1353(that)X +1494(is)X +1568(being)X +1767(replaced.)X +2101(The)X +2247(character)X +2564(``)X +7 f +2618(\304)X +1 f +('')S +2741(\(or)X +2856(``)X +7 f +2910(\\\304)X +1 f +('')S +3081(if)X +3151(the)X +3 f +3270(magic)X +1 f +3496(option)X +3721(is)X +2 f +3794(not)X +1 f +3916(set\))X +576 1950(stands)N +806(for)X +931(the)X +1060(replacement)X +1484(part)X +1640(of)X +1738(the)X +1867(previous)X +3 f +2174(substitute)X +1 f +2538(command.)X +2925(It)X +3005(is)X +3089(only)X +3262(valid)X +3453(after)X +3632(a)X +3 f +3699(substitute)X +1 f +576 2040(command)N +912(has)X +1039(been)X +1211(performed.)X +776 2163(The)N +922(string)X +1125(``)X +7 f +1179(\\#)X +1 f +('',)S +1370(where)X +1588(``)X +7 f +1642(#)X +1 f +('')S +1765(is)X +1839(an)X +1936(integer)X +2180(value)X +2376(from)X +2554(1)X +2616(to)X +2700(9,)X +2782(stands)X +3004(for)X +3120(the)X +3240(text)X +3382(matched)X +3676(by)X +3778(the)X +3898(por-)X +576 2253(tion)N +728(of)X +823(the)X +949(RE)X +1079(enclosed)X +1388(in)X +1478(the)X +1604(``)X +7 f +1658(#)X +1 f +('''th)S +1877(set)X +1994(of)X +2089(escaped)X +2372(parentheses,)X +2794(e.g.)X +2957(``)X +7 f +3011(\\\()X +1 f +('')S +3188(and)X +3331(``)X +7 f +3385(\\\))X +1 f +(''.)S +3602(For)X +3740(example,)X +576 2343(``)N +7 f +630(s/abc\\\(.*\\\)def/\\1/)X +1 f +('')S +1568(deletes)X +1811(the)X +1929(strings)X +2162(``)X +7 f +2216(abc)X +1 f +('')S +2434(and)X +2570(``)X +7 f +2624(def)X +1 f +('')S +2842(from)X +3018(the)X +3136(matched)X +3428(pattern.)X +776 2466(The)N +934(strings)X +1180(``)X +7 f +1234(\\l)X +1 f +('',)S +1437(``)X +7 f +1491(\\u)X +1 f +('',)S +1694(``)X +7 f +1748(\\L)X +1 f +('')S +1931(and)X +2080(``)X +7 f +2134(\\U)X +1 f +('')S +2317(can)X +2462(be)X +2571(used)X +2752(to)X +2848(modify)X +3113(the)X +3245(case)X +3418(of)X +3519(elements)X +3838(in)X +3934(the)X +576 2556(replacement)N +999(string.)X +1251(The)X +1406(string)X +1618(``)X +7 f +1672(\\l)X +1 f +('')S +1852(causes)X +2092(the)X +2220(next)X +2388(character)X +2714(to)X +2806(be)X +2912(converted)X +3259(to)X +3350(lowercase;)X +3723(the)X +3850(string)X +576 2646(``)N +7 f +630(\\u)X +1 f +('')S +815(behaves)X +1109(similarly,)X +1448(but)X +1585(converts)X +1892(to)X +1989(uppercase)X +2346(\(e.g.)X +7 f +2544(s/abc/\\U&/)X +1 f +3059(replaces)X +3358(the)X +3492(string)X +7 f +3710(abc)X +1 f +3890(with)X +7 f +576 2736(ABC)N +1 f +(\).)S +810(The)X +958(strings)X +1194(``)X +7 f +1248(\\L)X +1 f +('')S +1421(causes)X +1654(characters)X +2004(up)X +2107(to)X +2192(the)X +2313(end)X +2452(of)X +2541(the)X +2661(string)X +2865(or)X +2954(the)X +3074(next)X +3234 0.3611(occurrence)AX +3610(of)X +3699(the)X +3819(strings)X +576 2826(``)N +7 f +630(\\e)X +1 f +('')S +806(or)X +899(``)X +7 f +953(\\E)X +1 f +('')S +1129(to)X +1217(be)X +1319(converted)X +1663(to)X +1752(lowercase;)X +2123(the)X +2248(string)X +2457(``)X +7 f +2511(\\U)X +1 f +('')S +2688(behaves)X +2974(similarly,)X +3305(but)X +3434(converts)X +3733(to)X +3822(upper-)X +576 2916(case.)N +776 3039(If)N +850(the)X +968(entire)X +1171(replacement)X +1584(pattern)X +1827(is)X +1900(``)X +7 f +1954(%)X +1 f +('',)S +2096(then)X +2254(the)X +2372(last)X +2503(replacement)X +2916(pattern)X +3159(is)X +3232(used)X +3399(again.)X +776 3162(In)N +3 f +867(vi)X +1 f +929(,)X +973(inserting)X +1278(a)X +7 f +1339(<control-M>)X +1 f +1892(into)X +2041(the)X +2164(replacement)X +2582(string)X +2789(will)X +2938(cause)X +3142(the)X +3265(matched)X +3562(line)X +3707(to)X +3794(be)X +3895(split)X +576 3252(into)N +720(two)X +860(lines)X +1031(at)X +1109(that)X +1249(point.)X +1473(\(The)X +7 f +1645(<control-M>)X +1 f +2193(will)X +2337(be)X +2433(discarded.\))X +3 f +576 3438(8.)N +676(General)X +972(Editor)X +1214(Description)X +1 f +776 3561(When)N +3 f +989(ex)X +1 f +1086(or)X +3 f +1174(vi)X +1 f +1257(are)X +1377(executed,)X +1704(the)X +1823(text)X +1964(of)X +2052(a)X +2109(\256le)X +2232(is)X +2306(read)X +2466(\(or)X +2581(a)X +2638(temporary)X +2989(\256le)X +3112(is)X +3186(created\),)X +3487(and)X +3624(then)X +3783(all)X +3885(edit-)X +576 3651(ing)N +700(changes)X +981(happen)X +1235(within)X +1461(the)X +1581(context)X +1838(of)X +1926(the)X +2045(copy)X +2222(of)X +2310(the)X +2429(\256le.)X +2 f +2592(No)X +2706(changes)X +2990(affect)X +3189(the)X +3308(actual)X +3529(\256le)X +3648(until)X +3815(the)X +3934(\256le)X +576 3741(is)N +662(written)X +921(out)X +1 f +1023(,)X +1076(either)X +1293(using)X +1500(a)X +1570(write)X +1769(command)X +2119(or)X +2220(another)X +2495(command)X +2845(which)X +3075(is)X +3162(affected)X +3456(by)X +3570(the)X +3 f +3702(autowrite)X +1 f +576 3831(option.)N +776 3954(All)N +898(\256les)X +1052(are)X +1172(locked)X +1407(\(using)X +1628(the)X +2 f +1747(\257ock)X +1 f +1899(\(2\))X +2014(or)X +2 f +2102(fcntl)X +1 f +2244(\(2\))X +2359(interfaces\))X +2720(during)X +2950(the)X +3069(edit)X +3210(session,)X +3482(to)X +3565(avoid)X +3764(inadver-)X +576 4044(tently)N +781(making)X +1044(modi\256cations)X +1502(to)X +1587(multiple)X +1876(copies)X +2104(of)X +2194(the)X +2315(\256le.)X +2480(If)X +2557(a)X +2616(lock)X +2777(cannot)X +3014(be)X +3113(obtained)X +3412(for)X +3529(a)X +3587(\256le)X +3711(because)X +3988(it)X +576 4134(is)N +657(locked)X +899(by)X +1007(another)X +1276(process,)X +1565(the)X +1691(edit)X +1840(session)X +2100(is)X +2182(read-only)X +2519(\(as)X +2642(if)X +2720(the)X +3 f +2847(readonly)X +1 f +3178(option)X +3411(or)X +3507(the)X +3 f +9 f +3634(-)X +3636(-)X +3 f +3680(R)X +1 f +3767(\257ag)X +3916(had)X +576 4224(been)N +754(speci\256ed\).)X +1132(If)X +1212(a)X +1274(lock)X +1438(cannot)X +1678(be)X +1780(obtained)X +2082(for)X +2202(other)X +2393(reasons,)X +2680(the)X +2804(edit)X +2950(session)X +3207(will)X +3357(continue,)X +3679(but)X +3807(the)X +3930(\256le)X +576 4314(status)N +778(information)X +1176(\(see)X +1326(the)X +3 f +1444(<control-G>)X +1 f +1890(command\))X +2253(will)X +2397(re\257ect)X +2618(this)X +2753(fact.)X +776 4437(Both)N +3 f +955(ex)X +1 f +1055(and)X +3 f +1195(vi)X +1 f +1281(are)X +1405(modeful)X +1697(editors,)X +1960(i.e.)X +2083(they)X +2246(have)X +2423(two)X +2568(modes,)X +2822(``command'')X +3271(mode)X +3474(and)X +3615(``text)X +3814(input'')X +576 4527(mode.)N +817(The)X +965(former)X +1207(is)X +1283(intended)X +1582(to)X +1667(permit)X +1898(you)X +2040(to)X +2124(enter)X +2307(commands)X +2676(which)X +2894(modi\256es)X +3191(already)X +3450(existing)X +3725(text.)X +3907(The)X +576 4617(latter)N +762(is)X +836(intended)X +1133(to)X +1216(permit)X +1446(you)X +1588(to)X +1672(enter)X +1855(new)X +2011(text.)X +2193(When)X +3 f +2407(ex)X +1 f +2505(\256rst)X +2651(starts)X +2842(running,)X +3133(it)X +3199(is)X +3274(in)X +3358(command)X +3696(mode,)X +3916(and)X +576 4707(usually)N +838(displays)X +1131(a)X +1198(prompt)X +1460(\(see)X +1621(the)X +3 f +1750(prompt)X +1 f +2039(option)X +2274(for)X +2398(more)X +2593(information\).)X +3068(The)X +3223(prompt)X +3484(is)X +3567(a)X +3633(single)X +3854(colon)X +576 4797(\(``)N +7 f +657(:)X +1 f +(''\))S +817(character.)X +1184(There)X +1403(are)X +1533(three)X +1725(commands)X +2103(that)X +2255(switch)X +3 f +2496(ex)X +1 f +2604(into)X +2760(text)X +2912(input)X +3108(mode:)X +3 f +3340(append)X +1 f +3592(,)X +3 f +3644(change)X +1 f +3916(and)X +3 f +576 4887(insert)N +1 f +772(.)X +840(Once)X +1038(in)X +1128(input)X +1320(mode,)X +1546(entering)X +1837(a)X +1901(line)X +2049(containing)X +2415(only)X +2585(a)X +2649(single)X +2868(period)X +3101(\(``)X +7 f +3182(.)X +1 f +(''\))S +3359(terminates)X +3721(text)X +3868(input)X +576 4977(mode)N +774(and)X +910(returns)X +1153(to)X +1235(command)X +1571(mode,)X +1789(where)X +2006(the)X +2124(prompt)X +2375(is)X +2448(redisplayed.)X +776 5100(When)N +3 f +989(vi)X +1 f +1072(\256rst)X +1217(starts)X +1407(running,)X +1697(it)X +1763(is)X +1838(in)X +1922(command)X +2260(mode)X +2460(as)X +2549(well.)X +2749(There)X +2959(are)X +3080(eleven)X +3312(commands)X +3681(that)X +3823(switch)X +3 f +576 5190(vi)N +1 f +659(into)X +804(text)X +945(input)X +1130(mode:)X +3 f +1351(A)X +1 f +1409(,)X +3 f +1450(a)X +1 f +(,)S +3 f +1531(C)X +1 f +1589(,)X +3 f +1629(c)X +1 f +1665(,)X +3 f +1705(I)X +1 f +1736(,)X +3 f +1776(i)X +1 f +1798(,)X +3 f +1838(O)X +1 f +1900(,)X +3 f +1940(o)X +1 f +(,)S +3 f +2020(R)X +1 f +2078(,)X +3 f +2118(S)X +1 f +2182(and)X +3 f +2318(s)X +1 f +2349(.)X +2409(Once)X +2599(in)X +2681(input)X +2865(mode,)X +3083(entering)X +3366(an)X +7 f +3462(<escape>)X +1 f +3866(char-)X +576 5280(acter)N +753(terminates)X +1107(text)X +1247(input)X +1431(mode)X +1629(and)X +1765(returns)X +2008(to)X +2090(command)X +2426(mode.)X +776 5403(The)N +921(following)X +1252(words)X +1468(have)X +1640(special)X +1883(meanings)X +2210(in)X +2292(both)X +2454(the)X +3 f +2572(ex)X +1 f +2668(and)X +3 f +2804(vi)X +1 f +2886(command)X +3222(descriptions:)X +3 f +576 5583(<interrupt>)N +1 f +776 5673(The)N +927(interrupt)X +1229(character)X +1551(is)X +1630(used)X +1803(to)X +1891(interrupt)X +2193(the)X +2317(current)X +2571(operation.)X +2940(Normally)X +7 f +3274(<control-C>)X +1 f +(,)S +3849(what-)X +776 5763(ever)N +935(character)X +1251(is)X +1324(set)X +1433(for)X +1547(the)X +1665(current)X +1913(terminal)X +2200(is)X +2273(used.)X + +8 p +%%Page: 8 7 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-8)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +576 762(<literal)N +847(next>)X +1 f +776 852(The)N +923(literal)X +1132(next)X +1292(character)X +1610(is)X +1685(used)X +1854(to)X +1938(escape)X +2175(the)X +2295(subsequent)X +2673(character)X +2991(from)X +3169(any)X +3307(special)X +3552(meaning.)X +3890(This)X +776 942(character)N +1102(is)X +1185(always)X +7 f +1438(<control-V>)X +1 f +(.)S +2036(If)X +2120(the)X +2248(terminal)X +2545(is)X +2627(not)X +2758(set)X +2876(up)X +2985(to)X +3076(do)X +3185(XON/XOFF)X +3614(\257ow)X +3785(control,)X +776 1032(then)N +7 f +934(<control-Q>)X +1 f +1482(is)X +1555(used)X +1722(to)X +1804(mean)X +1998(literal)X +2205(next)X +2363(as)X +2450(well.)X +3 f +576 1212(current)N +855(pathname)X +1 f +776 1302(The)N +923(pathname)X +1257(of)X +1346(the)X +1467(\256le)X +1592(currently)X +1905(being)X +2106(edited)X +2325(by)X +2428(vi.)X +2553(When)X +2768(the)X +2889(percent)X +3149(character)X +3468(\(``)X +7 f +3549(%)X +1 f +(''\))S +3701(appears)X +3970(in)X +776 1392(a)N +833(\256le)X +956(name)X +1151(entered)X +1409(as)X +1497(part)X +1643(of)X +1731(an)X +3 f +1828(ex)X +1 f +1925(command)X +2262(argument,)X +2606(it)X +2671(is)X +2745(replaced)X +3039(by)X +3140(the)X +3259(current)X +3508(pathname.)X +3880(\(The)X +776 1482(``)N +7 f +830(%)X +1 f +('')S +952(character)X +1268(can)X +1400(be)X +1496(escaped)X +1771(by)X +1871(preceding)X +2208(it)X +2272(with)X +2434(a)X +2490(backslash.\))X +3 f +576 1662(alternate)N +904(pathname)X +1 f +776 1752(The)N +921(name)X +1115(of)X +1202(the)X +1320(last)X +1451(\256le)X +1573(name)X +1767(mentioned)X +2125(in)X +2207(an)X +3 f +2304(ex)X +1 f +2401(command,)X +2758(or,)X +2866(the)X +2985(previous)X +3282(current)X +3531(pathname)X +3864(if)X +3934(the)X +776 1842(last)N +913(\256le)X +1041(mentioned)X +1404(becomes)X +1710(the)X +1833(current)X +2086(\256le.)X +2253(When)X +2470(the)X +2593(hash)X +2765(mark)X +2955(character)X +3276(\(``)X +7 f +3357(#)X +1 f +(''\))S +3511(appears)X +3782(in)X +3869(a)X +3930(\256le)X +776 1932(name)N +979(entered)X +1245(as)X +1341(part)X +1495(of)X +1591(an)X +3 f +1696(ex)X +1 f +1801(command)X +2146(argument,)X +2498(it)X +2571(is)X +2653(replaced)X +2955(by)X +3064(the)X +3191(alternate)X +3498(pathname.)X +3880(\(The)X +776 2022(``)N +7 f +830(#)X +1 f +('')S +952(character)X +1268(can)X +1400(be)X +1496(escaped)X +1771(by)X +1871(preceding)X +2208(it)X +2272(with)X +2434(a)X +2490(backslash.\))X +3 f +576 2202(buffer)N +1 f +776 2292(One)N +931(of)X +1019(a)X +1076(number)X +1342(of)X +1430(named)X +1665(areas)X +1852(for)X +1968(saving)X +2199(copies)X +2426(of)X +2515(text.)X +2697(Commands)X +3083(that)X +3225(change)X +3475(or)X +3564(delete)X +3778(text)X +3920(can)X +776 2382(save)N +941(the)X +1061(changed)X +1351(or)X +1440(deleted)X +1693(text)X +1834(into)X +1979(a)X +2036(speci\256c)X +2302(buffer,)X +2540(for)X +2655(later)X +2819(use,)X +2967(if)X +3037(the)X +3156(command)X +3493(allows)X +3723(it)X +3788(\(i.e.)X +3934(the)X +3 f +776 2472(ex)N +872(change)X +1 f +1132(command)X +1468(cannot)X +1702(save)X +1866(the)X +1985(changed)X +2274(text)X +2415(in)X +2498(a)X +2555(named)X +2790(buffer\).)X +3075(Buffers)X +3337(are)X +3457(named)X +3692(with)X +3855(a)X +3912(sin-)X +776 2562(gle)N +895(character,)X +1232(preceded)X +1544(by)X +1645(a)X +1702(double)X +1941(quote,)X +2160(e.g.)X +7 f +2317("<character>)X +1 f +(.)S +2954(Historic)X +3232(implementations)X +3785(of)X +3 f +3872(ex)X +1 f +3948(/)X +3 f +3970(vi)X +1 f +776 2652(limited)N +7 f +1022(<character>)X +1 f +1570(to)X +1652(the)X +1770(alphanumeric)X +2227(characters;)X +3 f +2596(nex)X +1 f +(/)S +3 f +2738(nvi)X +1 f +2864(permits)X +3124(the)X +3242(use)X +3369(of)X +3456(any)X +3592(character.)X +776 2832(Buffers)N +1041(named)X +1279(by)X +1383(uppercase)X +1729(characters)X +2080(are)X +2203(the)X +2325(same)X +2514(as)X +2605(buffers)X +2857(named)X +3095(by)X +3199(lowercase)X +3545(characters,)X +3916(e.g.)X +776 2922(the)N +904(buffer)X +1131(named)X +1375(by)X +1485(the)X +1613(English)X +1887(character)X +2213(``)X +7 f +2267(A)X +1 f +('')S +2399(is)X +2482(the)X +2610(same)X +2805(as)X +2902(the)X +3030(buffer)X +3257(named)X +3500(by)X +3609(the)X +3736(character)X +776 3012(``)N +7 f +830(a)X +1 f +('',)S +977(with)X +1144(the)X +1267(exception)X +1604(that,)X +1769(if)X +1843(the)X +1966(buffer)X +2188(contents)X +2480(are)X +2604(being)X +2807(changed)X +3100(\(as)X +3219(with)X +3386(a)X +3447(text)X +3593(deletion)X +3877(or)X +3 f +3970(vi)X +776 3102(change)N +1 f +1036(command\),)X +1419(the)X +1537(text)X +1677(is)X +2 f +1750(appended)X +1 f +2082(to)X +2164(the)X +2282(buffer,)X +2519(instead)X +2766(of)X +2853(replacing)X +3172(the)X +3290(current)X +3538(contents.)X +776 3282(The)N +925(buffers)X +1177(named)X +1415(by)X +1519(the)X +1641(numeric)X +1928(characters)X +2279(\(in)X +2392(English,)X +2680(``)X +7 f +2734(1)X +1 f +('')S +2860(through)X +3133(``)X +7 f +3187(9)X +1 f +(''\),)S +3360(are)X +3483(special,)X +3751(in)X +3838(that)X +3983(if)X +776 3372(at)N +864(least)X +1041(one)X +1187(line)X +1337(is)X +1420(changed)X +1718(or)X +1814(deleted)X +2075(in)X +2166(the)X +2293(\256le,)X +2444(\(or)X +2567(a)X +2632(command)X +2977(changes)X +3265(or)X +3361(deletes)X +3613(a)X +3678(region)X +3912(that)X +776 3462(crosses)N +1032(a)X +1093(line)X +1238(boundary\))X +1593(a)X +1654(copy)X +1835(of)X +1927(the)X +2050(text)X +2195(is)X +2273(placed)X +2508(into)X +2657(the)X +2780(numeric)X +3068(buffer)X +3290(``)X +7 f +3344(1)X +1 f +('',)S +3491(regardless)X +3842(of)X +3934(the)X +776 3552(user)N +933(specifying)X +1290(another)X +1553(buffer)X +1772(in)X +1856(which)X +2074(to)X +2158(save)X +2323(it.)X +2429(Before)X +2670(this)X +2807(copy)X +2985(is)X +3060(done,)X +3258(the)X +3378(previous)X +3676(contents)X +3965(of)X +776 3642(buffer)N +1000(``)X +7 f +1054(1)X +1 f +('')S +1183(are)X +1309(moved)X +1555(into)X +1707(buffer)X +1932(``)X +7 f +1986(2)X +1 f +('',)S +2136(``)X +7 f +2190(2)X +1 f +('')S +2320(into)X +2472(buffer)X +2697(``)X +7 f +2751(3)X +1 f +('',)S +2901(and)X +3045(so)X +3144(on.)X +3292(The)X +3445(contents)X +3740(of)X +3835(buffer)X +776 3732(``)N +7 f +830(9)X +1 f +('')S +961(are)X +1089(discarded.)X +1466(In)X +3 f +1562(vi)X +1 f +1624(,)X +1672(text)X +1820(may)X +1986(be)X +2090(explicitly)X +2420(stored)X +2644(into)X +2796(the)X +2922(numeric)X +3213(buffers.)X +3509(In)X +3604(this)X +3747(case,)X +3934(the)X +776 3822(buffer)N +995(rotation)X +1266(described)X +1596(above)X +1810(occurs)X +2042(before)X +2270(the)X +2390(replacement)X +2805(of)X +2894(the)X +3014(buffer's)X +3291(contents.)X +3621(\(Text)X +3818(cannot)X +776 3912(be)N +874(explicitly)X +1198(stored)X +1416(into)X +1562(the)X +1682(numeric)X +1966(buffers)X +2215(in)X +3 f +2298(ex)X +1 f +2395(because)X +2671(of)X +2759(ambiguities)X +3153(that)X +3294(this)X +3430(would)X +3651(cause)X +3851(in)X +3934(the)X +3 f +776 4002(ex)N +1 f +872(command)X +1208(syntax.\))X +776 4182(When)N +991(a)X +3 f +1051(vi)X +1 f +1137(command)X +1477(synopsis)X +1776(shows)X +2000(both)X +2166(a)X +7 f +2226([buffer])X +1 f +2634(and)X +2774(a)X +7 f +2834([count])X +1 f +(,)S +3214(they)X +3376(may)X +3538(be)X +3638(presented)X +3970(in)X +776 4272(any)N +912(order.)X +776 4452(Finally,)N +1052(all)X +1162(buffers)X +1420(are)X +1549(either)X +1762(``line'')X +2020(or)X +2117 0.3750(``character'')AX +2551(oriented.)X +2884(All)X +3 f +3016(ex)X +1 f +3122(commands)X +3499(which)X +3725(store)X +3912(text)X +776 4542(into)N +922(buffers)X +1172(are)X +1293(line)X +1435(oriented.)X +1760(Some)X +3 f +1964(vi)X +1 f +2048(commands)X +2417(which)X +2635(store)X +2813(text)X +2955(into)X +3101(buffers)X +3351(are)X +3471(line)X +3612(oriented,)X +3916(and)X +776 4632(some)N +980(are)X +1114(character)X +1445(oriented;)X +1765(the)X +1898(description)X +2289(for)X +2418(each)X +2601(applicable)X +3 f +2966(vi)X +1 f +3063(command)X +3414(notes)X +3618(whether)X +3912(text)X +776 4722(copied)N +1020(into)X +1174(buffers)X +1432(using)X +1635(the)X +1762(command)X +2107(is)X +2189(line)X +2338(or)X +2434(character)X +2759(oriented.)X +3091(In)X +3187(addition,)X +3498(the)X +3 f +3625(vi)X +1 f +3716(command)X +3 f +776 4812(display)N +1053(buffers)X +1 f +1332(displays)X +1628(the)X +1760(current)X +2023(orientation)X +2405(for)X +2534(each)X +2717(buffer.)X +2989(Generally,)X +3361(the)X +3494(only)X +3671(importance)X +776 4902(attached)N +1074(to)X +1166(this)X +1311(orientation)X +1688(is)X +1771(that)X +1921(if)X +2000(the)X +2128(buffer)X +2355(is)X +2438(subsequently)X +2886(inserted)X +3170(into)X +3324(the)X +3451(text,)X +3620(line)X +3769(oriented)X +776 4992(buffers)N +1027(create)X +1243(new)X +1400(lines)X +1574(for)X +1691(each)X +1862(of)X +1952(the)X +2073(lines)X +2247(they)X +2408(contain,)X +2687(and)X +2826(character)X +3145(oriented)X +3431(buffers)X +3682(create)X +3898(new)X +776 5082(lines)N +951(for)X +1069(any)X +1209(lines)X +2 f +1384(other)X +1 f +1577(than)X +1739(the)X +1860(\256rst)X +2007(and)X +2146(last)X +2280(lines)X +2454(they)X +2615(contain.)X +2914(The)X +3062(\256rst)X +3209(and)X +3348(last)X +3482(lines)X +3656(are)X +3778(inserted)X +776 5172(into)N +927(the)X +1052(text)X +1199(at)X +1284(the)X +1409(current)X +1664(cursor)X +1892(position,)X +2196(becoming)X +2539(part)X +2691(of)X +2785(the)X +2910(current)X +3165(line.)X +3352(If)X +3433(there)X +3621(is)X +3701(more)X +3894(than)X +776 5262(one)N +912(line)X +1052(in)X +1134(the)X +1252(buffer,)X +1489(however,)X +1806(the)X +1924(current)X +2172(line)X +2312(itself)X +2492(will)X +2636(be)X +2732(split.)X +3 f +576 5442(unnamed)N +915(buffer)X +1 f +776 5532(The)N +924(unnamed)X +1241(buffer)X +1461(is)X +1537(a)X +1596(text)X +1739(storage)X +1994(area)X +2152(which)X +2371(is)X +2447(used)X +2617(by)X +2720(commands)X +3090(that)X +3233(take)X +3390(a)X +3450(buffer)X +3671(as)X +3762(an)X +3862(argu-)X +776 5622(ment,)N +976(when)X +1170(no)X +1270(buffer)X +1487(is)X +1560(speci\256ed)X +1865(by)X +1965(the)X +2083(user.)X +2277(There)X +2485(is)X +2558(no)X +2658(way)X +2812(to)X +2894(explicitly)X +3216 0.4531(reference)AX +3537(this)X +3672(buffer.)X + +9 p +%%Page: 9 8 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3698(USD:13-9)X +576 762(9.)N +676(Vi)X +776(Description)X +1 f +3 f +776 885(Vi)N +1 f +879(takes)X +1067(up)X +1170(the)X +1291(entire)X +1497(screen)X +1727(to)X +1813(display)X +2068(the)X +2190(edited)X +2410(\256le,)X +2556(except)X +2790(for)X +2908(the)X +3030(bottom)X +3280(line)X +3424(of)X +3515(the)X +3637(screen.)X +3907(The)X +576 975(bottom)N +824(line)X +966(of)X +1055(the)X +1175(screen)X +1403(is)X +1478(used)X +1647(to)X +1731(enter)X +3 f +1914(ex)X +1 f +2012(commands,)X +2401(and)X +2539(for)X +3 f +2655(vi)X +1 f +2739(error)X +2918(and)X +3056(informational)X +3513(messages.)X +3877(If)X +3952(no)X +576 1065(other)N +777(information)X +1191(is)X +1281(being)X +1496(displayed,)X +1860(the)X +1995(default)X +2255(display)X +2523(can)X +2672(show)X +2878(the)X +3013(current)X +3278(cursor)X +3516(row)X +3678(and)X +3831(cursor)X +576 1155(column,)N +863(an)X +966(indication)X +1313(of)X +1407(whether)X +1693(the)X +1818(\256le)X +1947(has)X +2081(been)X +2260(modi\256ed,)X +2591(and)X +2734(the)X +2859(current)X +3114(mode)X +3319(of)X +3413(the)X +3538(editor.)X +3792(See)X +3934(the)X +3 f +576 1245(ruler)N +1 f +750(,)X +3 f +790(showdirty)X +1 f +1152(and)X +3 f +1288(showmode)X +1 f +1668(options)X +1923(for)X +2037(more)X +2222(information.)X +776 1368(Empty)N +1012(lines)X +1186(do)X +1289(not)X +1414(have)X +1589(any)X +1729(special)X +1976(representation)X +2455(on)X +2559(the)X +2681(screen,)X +2931(but)X +3057(lines)X +3232(on)X +3336(the)X +3458(screen)X +3688(that)X +3832(would)X +576 1458(logically)N +886(come)X +1090(after)X +1268(the)X +1396(end)X +1542(of)X +1639(the)X +1767(\256le)X +1899(are)X +2028(displayed)X +2365(as)X +2461(a)X +2526(single)X +2746(tilde)X +2917(\(``)X +7 f +2998(\304)X +1 f +(''\))S +3156(character.)X +3521(To)X +3639(differentiate)X +576 1548(between)N +871(empty)X +1098(lines)X +1276(and)X +1419(lines)X +1597(consisting)X +1948(of)X +2042(only)X +2211(whitespace)X +2596(characters,)X +2971(use)X +3106(the)X +3 f +3232(list)X +1 f +3362(option.)X +3634(Historically,)X +576 1638(implementations)N +1130(of)X +3 f +1218(vi)X +1 f +1301(have)X +1474(also)X +1624(displayed)X +1952(some)X +2141(lines)X +2312(as)X +2399(single)X +2610(asterisk)X +2875(\(``)X +7 f +2956(@)X +1 f +(''\))S +3105(characters.)X +3492(These)X +3704(were)X +3881(lines)X +576 1728(that)N +717(were)X +895(not)X +1018(correctly)X +1326(displayed,)X +1675(i.e.)X +1795(lines)X +1968(on)X +2070(the)X +2190(screen)X +2418(that)X +2560(did)X +2684(not)X +2808(correspond)X +3187(to)X +3271(lines)X +3444(in)X +3528(the)X +3648(\256le,)X +3792(or)X +3881(lines)X +576 1818(that)N +716(did)X +838(not)X +960(\256t)X +1046(on)X +1146(the)X +1264(current)X +1512(screen.)X +3 f +1778(Nvi)X +1 f +1918(never)X +2117(displays)X +2399(lines)X +2570(in)X +2652(this)X +2787(fashion.)X +3 f +776 1941(Vi)N +1 f +881(is)X +959(a)X +1020(modeful)X +1312(editor,)X +1544(i.e.)X +1667(it)X +1736(has)X +1868(two)X +2013(modes,)X +2268(``command'')X +2718(mode)X +2922(and)X +3064(``text)X +3264(input'')X +3508(mode.)X +3752(When)X +3 f +3970(vi)X +1 f +576 2031(\256rst)N +724(starts,)X +937(it)X +1005(is)X +1082(in)X +1168(command)X +1508(mode.)X +1750(There)X +1962(are)X +2085(several)X +2337(commands)X +2708(that)X +2852(change)X +3 f +3104(vi)X +1 f +3189(into)X +3336(text)X +3479(input)X +3666(mode.)X +3907(The)X +7 f +576 2121(<escape>)N +1 f +980(character)X +1296(is)X +1369(used)X +1536(to)X +1618(resolve)X +1870(the)X +1988(text)X +2128(input)X +2312(into)X +2456(the)X +2574(\256le,)X +2716(and)X +2852(exit)X +2992(back)X +3164(into)X +3308(command)X +3644(mode.)X +3882(In)X +3 f +3970(vi)X +1 f +576 2211(command)N +916(mode,)X +1138(the)X +1260(cursor)X +1485(is)X +1562(always)X +1809(positioned)X +2166(on)X +2269(the)X +2390(last)X +2524(column)X +2787(of)X +2877(characters)X +3227(which)X +3446(take)X +3603(up)X +3706(more)X +3894(than)X +576 2301(one)N +714(column)X +976(on)X +1078(the)X +1198(screen.)X +1466(In)X +3 f +1555(vi)X +1 f +1639(text)X +1782(insert)X +1983(mode,)X +2204(the)X +2325(cursor)X +2549(is)X +2625(positioned)X +2981(on)X +3084(the)X +3205(\256rst)X +3352(column)X +3615(of)X +3705(characters)X +576 2391(which)N +792(take)X +946(up)X +1046(more)X +1231(than)X +1389(one)X +1525(column)X +1785(on)X +1885(the)X +2003(screen.)X +776 2514(Generally,)N +1138(if)X +1212(the)X +1335(cursor)X +1561(line)X +1707(and)X +1849(cursor)X +2076(column)X +2342(are)X +2467(not)X +2595(on)X +2701(the)X +2825(screen,)X +3077(then)X +3241(the)X +3365(screen)X +3597(is)X +3676(scrolled)X +3956(\(if)X +576 2604(the)N +695(target)X +899(cursor)X +1121(is)X +1195(close\))X +1407(or)X +1494(repainted)X +1813(\(if)X +1909(the)X +2027(target)X +2230(cursor)X +2451(is)X +2524(far)X +2634(away\))X +2851(so)X +2942(that)X +3082(the)X +3200(cursor)X +3421(is)X +3494(on)X +3594(the)X +3712(screen.)X +3978(If)X +576 2694(the)N +699(screen)X +930(is)X +1009(scrolled,)X +1309(it)X +1379(is)X +1458(moved)X +1702(a)X +1764(minimal)X +2056(amount,)X +2342(and)X +2484(the)X +2608(cursor)X +2835(line)X +2981(will)X +3131(usually)X +3388(appear)X +3629(at)X +3713(the)X +3837(top)X +3965(or)X +576 2784(bottom)N +832(of)X +929(the)X +1057(screen.)X +1333(In)X +1430(the)X +1558(screen)X +1794(is)X +1877(repainted,)X +2226(the)X +2354(cursor)X +2585(line)X +2735(will)X +2889(appear)X +3134(in)X +3226(the)X +3354(center)X +3581(of)X +3678(the)X +3806(screen,)X +576 2874(unless)N +799(the)X +920(cursor)X +1144(is)X +1220(suf\256ciently)X +1603(close)X +1791(to)X +1876(the)X +1997(beginning)X +2340(or)X +2430(end)X +2569(of)X +2660(the)X +2782(\256le)X +2908(that)X +3052(this)X +3191(is)X +3268(not)X +3394(possible.)X +3720(If)X +3798(the)X +3 f +3920(lef-)X +576 2964(tright)N +1 f +794(option)X +1020(is)X +1095(set,)X +1226(the)X +1346(screen)X +1574(may)X +1734(be)X +1832(scrolled)X +2108(or)X +2197(repainted)X +2518(in)X +2602(a)X +2660(horizontal)X +3007(direction)X +3314(as)X +3403(well)X +3563(as)X +3651(in)X +3734(a)X +3791(vertical)X +576 3054(one.)N +776 3177(A)N +869(major)X +1091(difference)X +1453(between)X +1756(the)X +1889(historical)X +3 f +2222(vi)X +1 f +2319(presentation)X +2746(and)X +3 f +2897(nvi)X +1 f +3038(is)X +3126(in)X +3224(the)X +3358(scrolling)X +3674(and)X +3826(screen)X +576 3267(oriented)N +893(position)X +1204(commands,)X +3 f +1625(<control-B>)X +1 f +2042(,)X +3 f +2116(<control-D>)X +1 f +2538(,)X +3 f +2612(<control-E>)X +1 f +3029(,)X +3 f +3103(<control-F>)X +1 f +3516(,)X +3 f +3590(<control-U>)X +1 f +4012(,)X +3 f +576 3357(<control-Y>)N +1 f +998(,)X +3 f +1049(H)X +1 f +1111(,)X +3 f +1162(L)X +1 f +1246(and)X +3 f +1394(M)X +1 f +1470(.)X +1542(In)X +1641(historical)X +1971(implementations)X +2536(of)X +3 f +2635(vi)X +1 f +2697(,)X +2749(these)X +2946(commands)X +3325(acted)X +3527(on)X +3639(physical)X +3938(\(as)X +576 3447(opposed)N +877(to)X +973(logical,)X +1245(or)X +1346(screen\))X +1613(lines.)X +1838(For)X +1982(lines)X +2166(that)X +2319(were)X +2509(suf\256ciently)X +2902(long)X +3077(in)X +3172(relation)X +3450(to)X +3545(the)X +3676(size)X +3834(of)X +3934(the)X +576 3537(screen,)N +822(this)X +957(meant)X +1174(that)X +1315(single)X +1527(line)X +1668(scroll)X +1867(commands)X +2235(might)X +2442(repaint)X +2686(the)X +2805(entire)X +3009(screen,)X +3256(scrolling)X +3557(or)X +3645(screen)X +3872(posi-)X +576 3627(tioning)N +823(command)X +1160(might)X +1367(not)X +1489(change)X +1737(the)X +1855(screen)X +2081(or)X +2168(move)X +2366(the)X +2484(cursor)X +2705(at)X +2783(all,)X +2903(and)X +3039(some)X +3228(lines)X +3399(simply)X +3636(could)X +3834(not)X +3956(be)X +576 3717(displayed,)N +927(even)X +1104(though)X +3 f +1351(vi)X +1 f +1438(would)X +1663(edit)X +1808(the)X +1931(\256le)X +2058(that)X +2203(contained)X +2540(them.)X +2765(In)X +3 f +2857(nvi)X +1 f +2963(,)X +3008(these)X +3198(commands)X +3570(act)X +3689(on)X +3794(logical,)X +576 3807(i.e.)N +718(screen)X +968(lines.)X +1203(You)X +1385(are)X +1528(unlikely)X +1834(to)X +1939(notice)X +2178(any)X +2337(difference)X +2707(unless)X +2950(you)X +3113(are)X +3255(editing)X +3520(\256les)X +3696(with)X +3881(lines)X +576 3897(signi\256cantly)N +991(longer)X +1216(than)X +1374(a)X +1430(screen)X +1656(width.)X +3 f +776 4020(Vi)N +1 f +883(keeps)X +1094(track)X +1283(of)X +1378(the)X +1504(currently)X +1822(``most)X +2059(attractive'')X +2440(cursor)X +2669(position.)X +2994(Each)X +3183(command)X +3527(description)X +3911(\(for)X +576 4110(commands)N +945(that)X +1087(can)X +1221(change)X +1471(the)X +1591(current)X +1841(cursor)X +2064(position\),)X +2390(speci\256es)X +2688(if)X +2759(the)X +2879(cursor)X +3101(is)X +3175(set)X +3285(to)X +3368(a)X +3425(speci\256c)X +3691(location)X +3970(in)X +576 4200(the)N +705(line,)X +876(or)X +974(if)X +1054(it)X +1129(is)X +1213(moved)X +1462(to)X +1555(the)X +1685(``most)X +1926(attractive)X +2257(cursor)X +2490(position''.)X +2873(The)X +3030(latter)X +3227(means)X +3464(that)X +3616(the)X +3746(cursor)X +3979(is)X +576 4290(moved)N +825(to)X +918(the)X +1047(cursor)X +1279(position)X +1567(that)X +1717(is)X +1800(vertically)X +2133(as)X +2230(close)X +2425(as)X +2522(possible)X +2814(to)X +2906(the)X +3034(current)X +3292(cursor)X +3523(position.)X +3850(If)X +3934(the)X +576 4380(current)N +826(line)X +968(is)X +1043(shorter)X +1288(than)X +1448(the)X +1568(cursor)X +1791(position)X +3 f +2070(vi)X +1 f +2154(would)X +2376(select,)X +2601(the)X +2722(cursor)X +2946(is)X +3022(positioned)X +3378(on)X +3481(the)X +3602(last)X +3736(character)X +576 4470(in)N +666(the)X +792(line.)X +980(\(If)X +1089(the)X +1215(line)X +1363(is)X +1444(empty,)X +1692(the)X +1818(cursor)X +2047(is)X +2128(positioned)X +2489(on)X +2596(the)X +2721(\256rst)X +2872(column)X +3139(of)X +3233(the)X +3358(line.\))X +3572(If)X +3653(a)X +3716(command)X +576 4560(moves)N +810(the)X +933(cursor)X +1159(to)X +1246(the)X +1369(most)X +1549(attractive)X +1873(position,)X +2175(it)X +2245(does)X +2418(not)X +2546(alter)X +2715(the)X +2839(current)X +3093(cursor)X +3320(position,)X +3623(and)X +3765(a)X +3827(subse-)X +576 4650(quent)N +775(movement)X +1134(will)X +1279(again)X +1474(attempt)X +1735(to)X +1818(move)X +2017(the)X +2136(cursor)X +2358(to)X +2441(that)X +2581(position.)X +2898(Therefore,)X +3256(although)X +3556(a)X +3612(movement)X +3970(to)X +576 4740(a)N +640(line)X +788(shorter)X +1039(than)X +1205(the)X +1331(currently)X +1649(most)X +1832(attractive)X +2159(position)X +2444(will)X +2596(cause)X +2803(the)X +2929(cursor)X +3158(to)X +3248(move)X +3454(to)X +3544(the)X +3671(end)X +3816(of)X +3912(that)X +576 4830(line,)N +737(a)X +794(subsequent)X +1171(movement)X +1530(to)X +1613(a)X +1670(longer)X +1896(line)X +2037(will)X +2182(cause)X +2382(the)X +2501(cursor)X +2723(to)X +2806(move)X +3005(back)X +3178(to)X +3260(the)X +3378(most)X +3553(attractive)X +3872(posi-)X +576 4920(tion.)N +776 5043(In)N +864(addition,)X +1167(the)X +3 f +1286($)X +1 f +1347(command)X +1684(makes)X +1910(the)X +2029(end)X +2166(of)X +2254(each)X +2423(line)X +2564(the)X +2684(most)X +2861(attractive)X +3182(cursor)X +3405(position)X +3684(rather)X +3894(than)X +576 5133(a)N +632(speci\256c)X +897(column.)X +776 5256(Each)N +3 f +958(vi)X +1 f +1042(command)X +1380(described)X +1710(below)X +1928(notes)X +2119(where)X +2338(the)X +2458(cursor)X +2681(ends)X +2850(up)X +2952(after)X +3122(it)X +3188(is)X +3263(executed.)X +3611(This)X +3775(position)X +576 5346(is)N +653(described)X +985(in)X +1071(terms)X +1273(of)X +1364(characters)X +1715(on)X +1819(the)X +1940(line,)X +2103(i.e.)X +2244(``the)X +2419(previous)X +2718 0.3409(character'',)AX +3111(or,)X +3221(``the)X +3396(last)X +3530(character)X +3849(in)X +3934(the)X +576 5436(line''.)N +810(This)X +972(is)X +1045(to)X +1127(avoid)X +1325(needing)X +1599(to)X +1681(continually)X +2061(refer)X +2234(to)X +2316(on)X +2416(what)X +2592(part)X +2737(of)X +2824(the)X +2942(character)X +3258(the)X +3376(cursor)X +3597(rests.)X +776 5559(The)N +921(following)X +1252(words)X +1468(have)X +1640(special)X +1883(meaning)X +2179(for)X +3 f +2293(vi)X +1 f +2375(commands.)X + +10 p +%%Page: 10 9 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-10)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +576 762(previous)N +889(context)X +1 f +776 852(The)N +927(position)X +1210(of)X +1303(the)X +1427(cursor)X +1654(before)X +1886(the)X +2010(command)X +2352(which)X +2574(caused)X +2819(the)X +2944(last)X +3082(absolute)X +3376(movement)X +3741(was)X +3893(exe-)X +776 942(cuted.)N +1012(Each)X +3 f +1195(vi)X +1 f +1279(command)X +1617(described)X +1947(in)X +2031(the)X +2151(next)X +2311(section)X +2559(that)X +2700(is)X +2774(considered)X +3143(an)X +3240(absolute)X +3528(movement)X +3887(is)X +3961(so)X +776 1032(noted.)N +1014(In)X +1101(addition,)X +1403(specifying)X +2 f +1757(any)X +1 f +1893(address)X +2154(to)X +2236(an)X +3 f +2332(ex)X +1 f +2428(command)X +2764(is)X +2837(considered)X +3205(an)X +3301(absolute)X +3588(movement.)X +3 f +576 1212(motion)N +1 f +776 1302(A)N +863(second)X +3 f +1115(vi)X +1 f +1206(command)X +1551(can)X +1693(be)X +1799(used)X +1976(as)X +2073(an)X +2179(optional)X +2471(trailing)X +2732(argument)X +3065(to)X +3157(the)X +3 f +3285(vi)X +3377(!)X +1 f +3404(,)X +3 f +3454(<)X +1 f +3500(,)X +3 f +3550(>)X +1 f +3596(,)X +3 f +3646(c)X +1 f +3682(,)X +3 f +3732(d)X +1 f +3776(,)X +3 f +3826(y)X +1 f +(,)S +3916(and)X +776 1392(\(depending)N +1158(on)X +1259(the)X +3 f +1378(tildeop)X +1 f +1633(option\))X +3 f +1884(\304)X +1 f +1931(commands.)X +2338(This)X +2500(command)X +2836(indicates)X +3141(the)X +3259(end)X +3395(of)X +3482(the)X +3600(region)X +3825(of)X +3912(text)X +776 1482(that's)N +993(affected)X +1292(by)X +1411(the)X +1548(command.)X +1943(The)X +2107(motion)X +2372(command)X +2727(may)X +2904(be)X +3019(either)X +3242(the)X +3380(command)X +3736(character)X +776 1572(repeated)N +1070(\(in)X +1180(which)X +1397(case)X +1557(it)X +1622(means)X +1848(the)X +1967(current)X +2216(line\))X +2384(or)X +2472(a)X +2528(cursor)X +2749(movement)X +3107(command.)X +3483(In)X +3570(the)X +3688(latter)X +3873(case,)X +776 1662(the)N +894(region)X +1119(affected)X +1399(by)X +1499(the)X +1617(command)X +1953(is)X +2026(from)X +2202(the)X +2320(starting)X +2581(or)X +2669(stopping)X +2965(cursor)X +3187(position)X +3465(which)X +3682(comes)X +3908(\256rst)X +776 1752(in)N +859(the)X +978(\256le,)X +1120(to)X +1202(immediately)X +1622(before)X +1848(the)X +1966(starting)X +2226(or)X +2313(stopping)X +2608(cursor)X +2829(position)X +3106(which)X +3322(comes)X +3547(later)X +3710(in)X +3792(the)X +3910(\256le.)X +776 1842(Commands)N +1166(that)X +1313(operate)X +1577(on)X +1684(lines)X +1862(instead)X +2116(of)X +2210(using)X +2410(beginning)X +2757(and)X +2900(ending)X +3145(cursor)X +3373(positions)X +3688(operate)X +3952(on)X +776 1932(all)N +880(of)X +971(the)X +1093(lines)X +1268(that)X +1412(are)X +1535(wholly)X +1781(or)X +1872(partially)X +2163(in)X +2248(the)X +2369(region.)X +2637(In)X +2727(addition,)X +3032(some)X +3224(other)X +3412(commands)X +3782(become)X +776 2022(line)N +922(oriented)X +1211(depending)X +1571(on)X +1677(where)X +1900(in)X +1988(the)X +2112(text)X +2258(they)X +2422(are)X +2548(used.)X +2762(The)X +2914(command)X +3257(descriptions)X +3671(below)X +3894(note)X +776 2112(these)N +961(special)X +1204(cases.)X +776 2292(The)N +921(following)X +1252(commands)X +1619(may)X +1777(all)X +1877(be)X +1973(used)X +2140(as)X +2227(motion)X +2473(components)X +2880(for)X +3 f +2994(vi)X +1 f +3076(commands:)X +7 f +776 2505(<control-A>)N +1472(<control-H>)X +2120(<control-J>)X +2768(<control-M>)X +776 2595(<control-N>)N +1472(<control-P>)X +2312(<space>)X +3248($)X +1256 2685(%)N +1424('<character>)X +2600(\()X +3248(\))X +1256 2775(+)N +1952(,)X +2600(-)X +3248(/)X +1256 2865(0)N +1952(;)X +2600(?)X +3248(B)X +1256 2955(E)N +1952(F)X +2600(G)X +3248(H)X +1256 3045(L)N +1952(M)X +2600(N)X +3248(T)X +1256 3135(W)N +1904([[)X +2552(]])X +3248(\303)X +1256 3225(_)N +1424(`<character>)X +2600(b)X +3248(e)X +1256 3315(f)N +1952(h)X +2600(j)X +3248(k)X +1256 3405(l)N +1952(n)X +2600(t)X +3248(w)X +1256 3495({)N +1952(|)X +2600(})X +1 f +776 3708(The)N +923(optional)X +1207(count)X +1407(pre\256x)X +1617(available)X +1930(for)X +2047(some)X +2239(of)X +2329(the)X +3 f +2450(vi)X +1 f +2535(commands)X +2905(that)X +3048(take)X +3205(motion)X +3454(commands,)X +3844(or)X +3934(the)X +776 3798(count)N +975(pre\256x)X +1183(available)X +1494(for)X +1609(the)X +3 f +1728(vi)X +1 f +1811(commands)X +2179(that)X +2320(are)X +2439(used)X +2606(as)X +2693(motion)X +2939(components,)X +3366(may)X +3524(be)X +3620(included)X +3916(and)X +776 3888(is)N +2 f +850(always)X +1 f +1093(considered)X +1463(part)X +1610(of)X +1699(the)X +1819(motion)X +2067(argument.)X +2432(For)X +2565(example,)X +2879(the)X +2999(commands)X +3368(``)X +7 f +3422(c2w)X +1 f +('')S +3642(and)X +3780(``)X +7 f +3834(2cw)X +1 f +('')S +776 3978(are)N +903(equivalent,)X +1285(and)X +1429(the)X +1555(region)X +1788(affected)X +2076(by)X +2184(the)X +3 f +2310(c)X +1 f +2374(command)X +2718(is)X +2799(two)X +2947(words)X +3171(of)X +3266(text.)X +3454(In)X +3549(addition,)X +3858(if)X +3934(the)X +776 4068(optional)N +1066(count)X +1272(pre\256x)X +1487(is)X +1568(speci\256ed)X +1881(for)X +2003(both)X +2173(the)X +3 f +2299(vi)X +1 f +2389(command)X +2733(and)X +2877(its)X +2980(motion)X +3234(component,)X +3639(the)X +3766(effect)X +3979(is)X +776 4158(multiplicative)N +1246(and)X +1388(is)X +1467(considered)X +1841(part)X +1992(of)X +2085(the)X +2209(motion)X +2461(argument.)X +2830(For)X +2967(example,)X +3285(the)X +3408(commands)X +3780(``)X +7 f +3834(4cw)X +1 f +('')S +776 4248(and)N +912(``)X +7 f +966(2c2w)X +1 f +('')S +1232(are)X +1351(equivalent,)X +1725(and)X +1861(the)X +1979(region)X +2204(affected)X +2484(by)X +2584(the)X +3 f +2702(c)X +1 f +2758(command)X +3094(is)X +3167(four)X +3321(words)X +3537(of)X +3624(text.)X +3 f +576 4428(count)N +1 f +776 4518(A)N +859(positive)X +1137(number)X +1407(used)X +1579(as)X +1671(an)X +1772(optional)X +2059(argument)X +2387(to)X +2474(most)X +2654(commands,)X +3046(either)X +3254(to)X +3341(give)X +3504(a)X +3566(size)X +3717(or)X +3810(a)X +3872(posi-)X +776 4608(tion)N +930(\(for)X +1081(display)X +1342(or)X +1439(movement)X +1807(commands\),)X +2231(or)X +2328(as)X +2425(a)X +2491(repeat)X +2718(count)X +2926(\(for)X +3077(commands)X +3454(that)X +3604(modify)X +3865(text\).)X +776 4698(The)N +932(count)X +1141(argument)X +1475(is)X +1559(always)X +1813(optional)X +2106(and)X +2254(defaults)X +2540(to)X +2634(1)X +2706(unless)X +2938(otherwise)X +3282(noted)X +3492(in)X +3586(the)X +3716(command)X +776 4788(description.)N +776 4968(When)N +995(a)X +3 f +1059(vi)X +1 f +1149(command)X +1493(synopsis)X +1796(shows)X +2024(both)X +2194(a)X +7 f +2258([buffer])X +1 f +2670(and)X +7 f +2814([count])X +1 f +(,)S +3198(they)X +3364(may)X +3530(be)X +3634(presented)X +3970(in)X +776 5058(any)N +912(order.)X +3 f +576 5238(bigword)N +1 f +776 5328(A)N +854(set)X +963(of)X +1050(non-whitespace)X +1575(characters)X +1923(preceded)X +2235(and)X +2372(followed)X +2678(by)X +2779(whitespace)X +3157(characters)X +3505(or)X +3593(the)X +3712(beginning)X +776 5418(or)N +863(end)X +999(of)X +1086(the)X +1204(\256le)X +1326(or)X +1413(line.)X +776 5598(Groups)N +1040(of)X +1135(empty)X +1363(lines)X +1542(\(or)X +1664(lines)X +1843(containing)X +2209(only)X +2379(whitespace)X +2764 0.3250(characters\))AX +3146(are)X +3274(treated)X +3522(as)X +3618(a)X +3683(single)X +3903(big-)X +776 5688(word.)N + +11 p +%%Page: 11 10 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-11)X +576 762(word)N +1 f +776 852(Generally,)N +1133(in)X +1215(languages)X +1556(where)X +1773(it)X +1837(is)X +1910(applicable,)X +3 f +2280(vi)X +1 f +2362(recognizes)X +2726(two)X +2866(kinds)X +3060(of)X +3148(words.)X +3405(First,)X +3592(a)X +3649(sequence)X +3965(of)X +776 942(letters,)N +1027(digits)X +1239(and)X +1390(underscores,)X +1829(delimited)X +2166(at)X +2259(both)X +2435(ends)X +2616(by:)X +2752(characters)X +3113(other)X +3312(than)X +3484(letters,)X +3734(digits,)X +3965(or)X +776 1032(underscores;)N +1206(the)X +1328(beginning)X +1672(or)X +1763(end)X +1903(of)X +1994(a)X +2054(line;)X +2220(the)X +2343(beginning)X +2688(or)X +2780(end)X +2921(of)X +3013(the)X +3136(\256le.)X +3303(Second,)X +3584(a)X +3645(sequence)X +3965(of)X +776 1122(characters)N +1126(other)X +1313(than)X +1473(letters,)X +1711(digits,)X +1930(underscores,)X +2356(or)X +2445(whitespace)X +2824(characters,)X +3193(delimited)X +3517(at)X +3597(both)X +3761(ends)X +3930(by:)X +776 1212(a)N +838(letter,)X +1049(digit,)X +1241(underscore,)X +1640(or)X +1733(whitespace)X +2116(character;)X +2460(the)X +2584(beginning)X +2930(or)X +3024(end)X +3167(of)X +3261(a)X +3324(line;)X +3493(the)X +3618(beginning)X +3965(or)X +776 1302(end)N +912(of)X +999(the)X +1117(\256le.)X +776 1482(Groups)N +1032(of)X +1119(empty)X +1339(lines)X +1510(\(or)X +1624(lines)X +1795(containing)X +2153(only)X +2315(whitespace)X +2692 0.3250(characters\))AX +3066(are)X +3185(treated)X +3424(as)X +3511(a)X +3567(single)X +3778(word.)X +3 f +576 1662(paragraph)N +1 f +776 1752(An)N +898(area)X +1057(of)X +1148(text)X +1292(that)X +1436(begins)X +1670(with)X +1837(either)X +2045(the)X +2168(beginning)X +2513(of)X +2605(a)X +2666(\256le,)X +2813(an)X +2914(empty)X +3139(line,)X +3304(or)X +3396(a)X +3457(section)X +3709(boundary,)X +776 1842(and)N +912(continues)X +1239(until)X +1405(either)X +1608(an)X +1704(empty)X +1924(line,)X +2084(section)X +2331(boundary,)X +2674(or)X +2761(the)X +2879(end)X +3015(of)X +3102(the)X +3220(\256le.)X +776 2022(Groups)N +1037(of)X +1129(empty)X +1355(lines)X +1532(\(or)X +1652(lines)X +1829(containing)X +2193(only)X +2361(whitespace)X +2744 0.3250(characters\))AX +3124(are)X +3249(treated)X +3494(as)X +3587(a)X +3649(single)X +3866(para-)X +776 2112(graph.)N +776 2292(Additional)N +1138(paragraph)X +1480(boundaries)X +1852(can)X +1984(be)X +2080(de\256ned)X +2336(using)X +2529(the)X +3 f +2647(paragraph)X +1 f +3031(option.)X +3 f +576 2472(section)N +1 f +776 2562(An)N +903(area)X +1067(of)X +1163(text)X +1312(that)X +1461(starts)X +1659(with)X +1830(the)X +1957(beginning)X +2306(of)X +2402(the)X +2529(\256le)X +2660(or)X +2756(a)X +2822(line)X +2972(whose)X +3207(\256rst)X +3361(character)X +3687(is)X +3770(an)X +3876(open)X +776 2652(brace)N +971(\(``)X +7 f +1052({)X +1 f +(''\))S +1201(and)X +1337(continues)X +1664(until)X +1830(the)X +1948(next)X +2106(section)X +2353(or)X +2440(the)X +2558(end)X +2694(of)X +2781(the)X +2899(\256le.)X +776 2832(Additional)N +1138(section)X +1385(boundaries)X +1757(can)X +1889(be)X +1985(de\256ned)X +2241(using)X +2434(the)X +3 f +2552(sections)X +1 f +2839(option.)X +3 f +576 3012(sentence)N +1 f +776 3102(An)N +895(area)X +1051(of)X +1139(text)X +1280(that)X +1421(begins)X +1651(with)X +1814(either)X +2018(the)X +2137(beginning)X +2478(of)X +2566(the)X +2685(\256le)X +2808(or)X +2896(the)X +3015(\256rst)X +3160(nonblank)X +3479(character)X +3796(follow-)X +776 3192(ing)N +901(the)X +1022(previous)X +1321(sentence,)X +1641(paragraph,)X +2006(or)X +2096(section)X +2346(boundary)X +2672(and)X +2811(continues)X +3141(until)X +3310(the)X +3431(end)X +3570(of)X +3660(the)X +3781(\256le)X +3906(or)X +3996(a)X +776 3282(or)N +866(a)X +926(period)X +1155(\(``)X +7 f +1236(.)X +1 f +(''\))S +1409(exclamation)X +1825(point)X +2013(\(``)X +7 f +2094(!)X +1 f +(''\))S +2267(or)X +2358(question)X +2653(mark)X +2842(\(``)X +7 f +2923(?)X +1 f +(''\))S +3096(character,)X +3436(followed)X +3745(by)X +3849(either)X +776 3372(an)N +882(end-of-line)X +1269(or)X +1366(two)X +1516(whitespace)X +1903(characters.)X +2300(Any)X +2468(number)X +2743(of)X +2840(closing)X +3101(parentheses)X +3505(\(``)X +7 f +3586(\))X +1 f +(''\),)S +3764(brackets)X +776 3462(\(``)N +7 f +857(])X +1 f +(''\))S +1007(or)X +1095(double-quote)X +1540(\(``)X +7 f +1621(")X +1 f +(''\))S +1772(characters)X +2121(can)X +2255(appear)X +2492(between)X +2782(the)X +2902(period,)X +3149(exclamation)X +3563(point,)X +3769(or)X +3858(ques-)X +776 3552(tion)N +920(mark)X +1105(and)X +1241(the)X +1359(whitespace)X +1736(characters)X +2083(or)X +2170(end-of-line.)X +776 3732(Groups)N +1040(of)X +1135(empty)X +1363(lines)X +1542(\(or)X +1664(lines)X +1843(containing)X +2209(only)X +2379(whitespace)X +2764 0.3250(characters\))AX +3146(are)X +3273(treated)X +3520(as)X +3615(a)X +3679(single)X +3898(sen-)X +776 3822(tence.)N +3 f +576 4008(10.)N +716(Vi)X +816(Commands)X +1 f +776 4131(The)N +926(following)X +1262(section)X +1514(describes)X +1838(the)X +1961(commands)X +2333(available)X +2649(in)X +2737(the)X +2861(command)X +3203(mode)X +3407(of)X +3500(the)X +3 f +3624(vi)X +1 f +3712(editor.)X +3965(In)X +576 4221(each)N +745(entry)X +931(below,)X +1168(the)X +1287(tag)X +1406(line)X +1547(is)X +1621(a)X +1678(usage)X +1882(synopsis)X +2178(for)X +2293(the)X +2412(command)X +2749(character.)X +3106(In)X +3194(addition,)X +3496(the)X +3614(\256nal)X +3776(line)X +3916(and)X +576 4311(column)N +836(the)X +954(cursor)X +1175(rests)X +1342(upon,)X +1542(and)X +1678(any)X +1814(options)X +2069(which)X +2285(affect)X +2489(the)X +2607(command)X +2943(are)X +3062(noted.)X +3 f +576 4491([count])N +841(<control-A>)X +1 f +776 4581(Search)N +1034(forward)X +7 f +1328(count)X +1 f +1607(times)X +1819(for)X +1952(the)X +2089(current)X +2356(word.)X +2600(The)X +2764(current)X +3031(word)X +3236(begins)X +3485(at)X +3583(the)X +3721(\256rst)X +3885(non-)X +776 4671(whitespace)N +1164(character)X +1491(on)X +1602(or)X +1699(after)X +1877(the)X +2005(current)X +2263(cursor)X +2494(position,)X +2801(and)X +2947(extends)X +3222(up)X +3332(to)X +3424(the)X +3552(next)X +3720(non-word)X +776 4761(character)N +1095(or)X +1185(the)X +1306(end)X +1445(of)X +1535(the)X +1656(line.)X +1839(The)X +1987(search)X +2216(is)X +2292(literal,)X +2522(i.e.)X +2643(no)X +2746(characters)X +3096(in)X +3182(the)X +3304(word)X +3493(have)X +3669(any)X +3809(special)X +776 4851(meaning)N +1076(in)X +1162(terms)X +1364(of)X +1455(Regular)X +1733(Expressions.)X +2184(It)X +2257(is)X +2334(an)X +2434(error)X +2615(if)X +2687(no)X +2790(matching)X +3111(pattern)X +3357(is)X +3433(found)X +3643(between)X +3934(the)X +776 4941(starting)N +1036(position)X +1313(and)X +1449(the)X +1567(end)X +1703(of)X +1790(the)X +1908(\256le.)X +776 5121(The)N +3 f +926(<control-A>)X +1 f +1373(command)X +1714(is)X +1792(an)X +1893(absolute)X +2185(movement.)X +2588(The)X +3 f +2738(<control-A>)X +1 f +3185(command)X +3526(may)X +3690(be)X +3792(used)X +3965(as)X +776 5211(the)N +896(motion)X +1144(component)X +1522(of)X +1611(other)X +3 f +1798(vi)X +1 f +1881(commands,)X +2269(in)X +2352(which)X +2569(case)X +2729(any)X +2866(text)X +3007(copied)X +3242(into)X +3387(a)X +3444(buffer)X +3662(is)X +3736(character)X +776 5301(oriented.)N +776 5481(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(where)X +1815(the)X +1933(word)X +2118(is)X +2191(found.)X +776 5571(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(character)X +1918(of)X +2005(the)X +2123(word.)X +776 5661(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(extended)X +1 f +1963(,)X +3 f +2003(ignorecase)X +1 f +2384(and)X +3 f +2520(wrapscan)X +1 f +2869(options.)X + +12 p +%%Page: 12 11 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-12)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +576 762([count])N +841(<control-B>)X +1 f +776 852(Page)N +965(backward)X +7 f +1311(count)X +1 f +1585(screens.)X +1896(Two)X +2077(lines)X +2262(of)X +2363(overlap)X +2638(are)X +2771(maintained)X +3161(by)X +3275(displaying)X +3642(the)X +3774(window)X +776 942(starting)N +1042(at)X +1126(line)X +7 f +1272(\(top_line)X +1758(-)X +1860(count)X +2154(*)X +2256(window_size\))X +2886(+)X +2988(2)X +1 f +(,)S +3081(where)X +7 f +3303(window_size)X +1 f +3856(is)X +3934(the)X +776 1032(value)N +973(of)X +1063(the)X +3 f +1184(window)X +1 f +1473(option.)X +1741(\(In)X +1859(the)X +1981(case)X +2144(of)X +2235(split)X +2396(screens,)X +2677(this)X +2816(size)X +2965(is)X +3042(corrected)X +3366(to)X +3452(the)X +3574(current)X +3826(screen)X +776 1122(size.\))N +988(This)X +1150(is)X +1223(an)X +1319(error)X +1496(if)X +1565(the)X +1683(movement)X +2041(is)X +2114(past)X +2263(the)X +2381(beginning)X +2721(of)X +2808(the)X +2926(\256le.)X +776 1302(The)N +3 f +921(<control-B>)X +1 f +1358(command)X +1694(is)X +1767(an)X +1863(absolute)X +2150(movement.)X +776 1482(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(of)X +1816(text)X +1956(displayed)X +2283(on)X +2383(the)X +2501(screen.)X +776 1572(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2441(line.)X +776 1662(Options:)N +1136(None.)X +3 f +576 1842([count])N +841(<control-D>)X +1 f +776 1932(Scroll)N +990(forward)X +7 f +1268(count)X +1 f +1531(lines.)X +1745(If)X +7 f +1822(count)X +1 f +2085(is)X +2161(not)X +2286(speci\256ed,)X +2614(scroll)X +2815(forward)X +3093(the)X +3214(number)X +3482(of)X +3572(lines)X +3747(speci\256ed)X +776 2022(by)N +881(the)X +1004(last)X +3 f +1140(<control-D>)X +1 f +1587(or)X +3 f +1679(<control-U>)X +1 f +2126(command.)X +2507(If)X +2586(this)X +2726(is)X +2803(the)X +2925(\256rst)X +3 f +3073(<control-D>)X +1 f +3519(or)X +3 f +3610(<control-U>)X +1 f +776 2112(command,)N +1141(scroll)X +1348(forward)X +1632(half)X +1786(the)X +1913(number)X +2188(of)X +2285(lines)X +2466(in)X +2558(the)X +2686(screen.)X +2962(\(In)X +3086(the)X +3214(case)X +3383(of)X +3480(split)X +3647(screens,)X +3934(the)X +776 2202(default)N +1026(scrolling)X +1333(distance)X +1623(is)X +1703(corrected)X +2029(to)X +2117(half)X +2268(the)X +2392(current)X +2646(screen)X +2878(size.\))X +3096(This)X +3264(is)X +3343(an)X +3445(error)X +3628(if)X +3703(the)X +3827(move-)X +776 2292(ment)N +956(is)X +1029(past)X +1178(the)X +1296(end)X +1432(of)X +1519(the)X +1637(\256le.)X +776 2472(The)N +3 f +921(<control-D>)X +1 f +1363(command)X +1699(is)X +1772(an)X +1868(absolute)X +2155(movement.)X +776 2652(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(current)X +1706(line)X +1846(plus)X +1999(the)X +2117(number)X +2382(of)X +2469(lines)X +2640(scrolled.)X +776 2742(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2441(line.)X +776 2832(Options:)N +1136(None.)X +3 f +576 3012([count])N +841(<control-E>)X +1 f +776 3102(Scroll)N +987(forward)X +7 f +1262(count)X +1 f +1522(lines,)X +1713(leaving)X +1969(the)X +2087(cursor)X +2308(on)X +2408(the)X +2526(current)X +2774(line)X +2914(and)X +3050(column,)X +3330(if)X +3399(possible.)X +3721(This)X +3883(is)X +3956(an)X +776 3192(error)N +953(if)X +1022(the)X +1140(movement)X +1498(is)X +1571(past)X +1720(the)X +1838(end)X +1974(of)X +2061(the)X +2179(\256le.)X +776 3372(Line:)N +1136(Unchanged)X +1524(unless)X +1747(the)X +1868(current)X +2119(line)X +2262(scrolls)X +2494(off)X +2611(the)X +2732(screen,)X +2981(in)X +3066(which)X +3285(case)X +3447(it)X +3514(is)X +3590(set)X +3702(to)X +3787(the)X +3908(\256rst)X +1136 3462(line)N +1276(on)X +1376(the)X +1494(screen.)X +776 3552(Column:)N +1136(Unchanged)X +1523(unless)X +1744(the)X +1863(current)X +2112(line)X +2253(scrolls)X +2483(off)X +2598(the)X +2717(screen,)X +2964(in)X +3047(which)X +3264(case)X +3424(it)X +3489(is)X +3563(set)X +3673(to)X +3757(the)X +3877(most)X +1136 3642(attractive)N +1455(cursor)X +1676(position.)X +776 3732(Options:)N +1136(None.)X +3 f +576 3912([count])N +841(<control-F>)X +1 f +776 4002(Page)N +955(forward)X +7 f +1233(count)X +1 f +1496(screens.)X +1797(Two)X +1968(lines)X +2143(of)X +2234(overlap)X +2499(are)X +2622(maintained)X +3002(by)X +3106(displaying)X +3463(the)X +3585(window)X +3867(start-)X +776 4092(ing)N +900(at)X +980(line)X +7 f +1122(top_line)X +1556(+)X +1654(count)X +1944(*)X +2042(window_size)X +2620(-)X +2718(2)X +1 f +(,)S +2808(where)X +7 f +3027(window_size)X +1 f +3577(is)X +3651(the)X +3770(value)X +3965(of)X +776 4182(the)N +3 f +903(window)X +1 f +1198(option.)X +1471(\(In)X +1594(the)X +1721(case)X +1889(of)X +1985(split)X +2151(screens,)X +2437(this)X +2581(size)X +2735(is)X +2817(corrected)X +3146(to)X +3238(the)X +3366(current)X +3624(screen)X +3860(size.\))X +776 4272(This)N +938(is)X +1011(an)X +1107(error)X +1284(if)X +1353(the)X +1471(movement)X +1829(is)X +1902(past)X +2051(the)X +2169(end)X +2305(of)X +2392(the)X +2510(\256le.)X +776 4452(The)N +3 f +921(<control-F>)X +1 f +1354(command)X +1690(is)X +1763(an)X +1859(absolute)X +2146(movement.)X +776 4632(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(line)X +1742(on)X +1842(the)X +1960(screen.)X +776 4722(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2441(current)X +2689(line.)X +776 4812(Options:)N +1136(None.)X +3 f +576 4992(<control-G>)N +1 f +776 5082(Display)N +1055(the)X +1183(\256le)X +1315(information.)X +1763(The)X +1918(information)X +2326(includes)X +2624(the)X +2753(current)X +3012(pathname,)X +3375(the)X +3504(current)X +3763(line,)X +3934(the)X +776 5172(number)N +1043(of)X +1132(total)X +1296(lines)X +1469(in)X +1553(the)X +1673(\256le,)X +1817(the)X +1937(current)X +2187(line)X +2329(as)X +2418(a)X +2476(percentage)X +2847(of)X +2936(the)X +3056(total)X +3220(lines)X +3393(in)X +3477(the)X +3597(\256le,)X +3741(if)X +3811(the)X +3930(\256le)X +776 5262(has)N +905(been)X +1079(modi\256ed,)X +1405(was)X +1552(able)X +1708(to)X +1792(be)X +1890(locked,)X +2146(if)X +2217(the)X +2337(\256le's)X +2519(name)X +2715(has)X +2844(been)X +3018(changed,)X +3328(and)X +3466(if)X +3537(the)X +3658(edit)X +3801(session)X +776 5352(is)N +849(read-only.)X +776 5532(Line:)N +1136(Unchanged.)X +776 5622(Column:)N +1136(Unchanged.)X +776 5712(Options:)N +1136(None.)X + +13 p +%%Page: 13 12 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-13)X +576 762(<control-H>)N +576 852([count])N +841(h)X +1 f +776 942(Move)N +989(the)X +1113(cursor)X +1340(back)X +7 f +1518(count)X +1 f +1784(characters)X +2137(in)X +2225(the)X +2349(current)X +2603(line.)X +2789(This)X +2957(is)X +3036(an)X +3138(error)X +3321(if)X +3396(the)X +3520(cursor)X +3747(is)X +3827(on)X +3934(the)X +776 1032(\256rst)N +920(character)X +1236(in)X +1318(the)X +1436(line.)X +776 1212(The)N +3 f +923(<control-H>)X +1 f +1372(and)X +3 f +1511(h)X +1 f +1578(commands)X +1948(may)X +2109(be)X +2208(used)X +2378(as)X +2468(the)X +2589(motion)X +2838(component)X +3217(of)X +3307(other)X +3 f +3495(vi)X +1 f +3580(commands,)X +3970(in)X +776 1302(which)N +992(case)X +1151(any)X +1287(text)X +1427(copied)X +1661(into)X +1805(a)X +1861(buffer)X +2078(is)X +2151(character)X +2467(oriented.)X +776 1482(Line:)N +1136(Unchanged.)X +776 1572(Column:)N +1136(Set)X +1263(to)X +1350(the)X +7 f +1473(current)X +1862(-)X +1963(count)X +1 f +2229(character,)X +2571(or,)X +2684(the)X +2808(\256rst)X +2958(character)X +3280(in)X +3368(the)X +3492(line)X +3638(if)X +7 f +3713(count)X +1 f +3979(is)X +1136 1662(greater)N +1380(than)X +1538(or)X +1625(equal)X +1819(to)X +1901(the)X +2019(number)X +2284(of)X +2371(characters)X +2718(in)X +2800(the)X +2918(line)X +3058(before)X +3284(the)X +3402(cursor.)X +776 1752(Options:)N +1136(None.)X +3 f +576 1932([count])N +841(<control-J>)X +576 2022([count])N +841(<control-N>)X +576 2112([count])N +841(j)X +1 f +776 2202(Move)N +993(the)X +1121(cursor)X +1352(down)X +7 f +1560(count)X +1 f +1830(lines)X +2011(without)X +2285(changing)X +2609(the)X +2737(current)X +2995(column.)X +3305(This)X +3477(is)X +3560(an)X +3666(error)X +3854(if)X +3934(the)X +776 2292(movement)N +1134(is)X +1207(past)X +1356(the)X +1474(end)X +1610(of)X +1697(the)X +1815(\256le.)X +776 2472(The)N +3 f +927(<control-J>)X +1 f +1331(,)X +3 f +1377(<control-N>)X +1 f +1825(and)X +3 f +1967(j)X +1 f +2020(commands)X +2393(may)X +2557(be)X +2659(used)X +2832(as)X +2925(the)X +3049(motion)X +3301(component)X +3684(of)X +3778(other)X +3 f +3970(vi)X +1 f +776 2562(commands,)N +1163(in)X +1245(which)X +1461(case)X +1620(any)X +1756(text)X +1896(copied)X +2130(into)X +2274(a)X +2330(buffer)X +2547(is)X +2620(line)X +2760(oriented.)X +776 2742(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(current)X +1706(line)X +1846(plus)X +7 f +1999(count)X +1 f +(.)S +776 2832(Column:)N +1136(The)X +1281(most)X +1456(attractive)X +1775(cursor)X +1996(position.)X +776 2922(Options:)N +1136(None.)X +3 f +576 3102(<control-L>)N +576 3192(<control-R>)N +1 f +776 3282(Repaint)N +1045(the)X +1163(screen.)X +776 3462(Line:)N +1136(Unchanged.)X +776 3552(Column:)N +1136(Unchanged.)X +776 3642(Options:)N +1136(None.)X +3 f +576 3822([count])N +841(<control-M>)X +576 3912([count])N +841(+)X +1 f +776 4002(Move)N +984(the)X +1103(cursor)X +1325(down)X +7 f +1524(count)X +1 f +1785(lines)X +1957(to)X +2040(the)X +2159(\256rst)X +2304(nonblank)X +2623(character)X +2940(of)X +3028(that)X +3169(line.)X +3350(This)X +3513(is)X +3587(an)X +3684(error)X +3863(if)X +3934(the)X +776 4092(movement)N +1134(is)X +1207(past)X +1356(the)X +1474(end)X +1610(of)X +1697(the)X +1815(\256le.)X +776 4272(The)N +3 f +922(<control-M>)X +1 f +1384(and)X +3 f +1522(+)X +1 f +1590(commands)X +1959(may)X +2119(be)X +2217(used)X +2386(as)X +2475(the)X +2595(motion)X +2843(component)X +3221(of)X +3310(other)X +3 f +3497(vi)X +1 f +3581(commands,)X +3970(in)X +776 4362(which)N +992(case)X +1151(any)X +1287(text)X +1427(copied)X +1661(into)X +1805(a)X +1861(buffer)X +2078(is)X +2151(line)X +2291(oriented.)X +776 4542(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(current)X +1706(line)X +1846(plus)X +7 f +1999(count)X +1 f +(.)S +776 4632(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 4722(Options:)N +1136(None.)X +3 f +576 4902([count])N +841(<control-P>)X +576 4992([count])N +841(k)X +1 f +776 5082(Move)N +983(the)X +1101(cursor)X +1323(up)X +7 f +1424(count)X +1 f +1685(lines,)X +1877(without)X +2142(changing)X +2457(the)X +2576(current)X +2825(column.)X +3126(This)X +3289(is)X +3363(an)X +3460(error)X +3638(if)X +3708(the)X +3827(move-)X +776 5172(ment)N +956(is)X +1029(past)X +1178(the)X +1296(beginning)X +1636(of)X +1723(the)X +1841(\256le.)X +776 5352(The)N +3 f +924(<control-P>)X +1 f +1360(and)X +3 f +1499(k)X +1 f +1566(commands)X +1937(may)X +2099(be)X +2199(used)X +2370(as)X +2461(the)X +2583(motion)X +2833(component)X +3213(of)X +3304(other)X +3 f +3493(vi)X +1 f +3579(commands,)X +3970(in)X +776 5442(which)N +992(case)X +1151(any)X +1287(text)X +1427(copied)X +1661(into)X +1805(a)X +1861(buffer)X +2078(is)X +2151(line)X +2291(oriented.)X +776 5622(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(current)X +1706(line)X +1846(minus)X +2061(count.)X +776 5712(Column:)N +1136(The)X +1281(most)X +1456(attractive)X +1775(cursor)X +1996(position.)X + +14 p +%%Page: 14 13 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-14)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +1 f +776 762(Options:)N +1136(None.)X +3 f +576 942(<control-T>)N +1 f +776 1032(Return)N +1014(to)X +1096(the)X +1214(most)X +1389(recent)X +1606(tag)X +1724(context.)X +2020(The)X +3 f +2165(<control-T>)X +1 f +2602(command)X +2938(is)X +3011(an)X +3107(absolute)X +3394(movement.)X +776 1212(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(context)X +1714(of)X +1801(the)X +1919(previous)X +2215(tag)X +2333(command.)X +776 1302(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(context)X +1714(of)X +1801(the)X +1919(previous)X +2215(tag)X +2333(command.)X +776 1392(Options:)N +1136(None.)X +3 f +576 1572(<control-U>)N +1 f +776 1662(Scroll)N +1003(backward)X +7 f +1352(count)X +1 f +1628(lines.)X +1856(If)X +7 f +1947(count)X +1 f +2224(is)X +2314(not)X +2453(speci\256ed,)X +2795(scroll)X +3010(backward)X +3360(the)X +3495(number)X +3777(of)X +3881(lines)X +776 1752(speci\256ed)N +1096(by)X +1211(the)X +1344(last)X +3 f +1490(<control-D>)X +1 f +1947(or)X +3 f +2049(<control-U>)X +1 f +2505(command.)X +2895(If)X +2983(this)X +3132(is)X +3219(the)X +3351(\256rst)X +3 f +3509(<control-D>)X +1 f +3965(or)X +3 f +776 1842(<control-U>)N +1 f +1221(command,)X +1580(scroll)X +1781(backward)X +2117(half)X +2266(the)X +2388(number)X +2657(of)X +2748(lines)X +2923(in)X +3009(the)X +3131(screen.)X +3401(\(In)X +3519(the)X +3641(case)X +3804(of)X +3895(split)X +776 1932(screens,)N +1057(the)X +1179(default)X +1426(scrolling)X +1729(distance)X +2015(is)X +2091(corrected)X +2414(to)X +2499(half)X +2647(the)X +2768(current)X +3019(screen)X +3248(size.\))X +3463(This)X +3628(is)X +3704(an)X +3803(error)X +3983(if)X +776 2022(the)N +894(movement)X +1252(is)X +1325(past)X +1474(the)X +1592(beginning)X +1932(of)X +2019(the)X +2137(\256le.)X +776 2202(The)N +3 f +921(<control-U>)X +1 f +1363(command)X +1699(is)X +1772(an)X +1868(absolute)X +2155(movement.)X +776 2382(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(current)X +1706(line)X +1846(minus)X +2061(the)X +2179(amount)X +2439(scrolled.)X +776 2472(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 2562(Options:)N +1136(None.)X +3 f +576 2742(<control-W>)N +1 f +776 2832(Switch)N +1021(to)X +1106(the)X +1227(next)X +1388(lower)X +1594(screen)X +1823(in)X +1908(the)X +2029(window,)X +2330(or,)X +2440(to)X +2525(the)X +2646(\256rst)X +2793(screen)X +3022(if)X +3094(there)X +3278(are)X +3400(no)X +3503(lower)X +3709(screens)X +3970(in)X +776 2922(the)N +894(window.)X +776 3102(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(previous)X +1754(cursor)X +1975(position)X +2252(in)X +2334(the)X +2452(window.)X +776 3192(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(previous)X +1754(cursor)X +1975(position)X +2252(in)X +2334(the)X +2452(window.)X +776 3282(Options:)N +1136(None.)X +3 f +576 3462(<control-Y>)N +1 f +776 3552(Scroll)N +989(backward)X +7 f +1324(count)X +1 f +1586(lines,)X +1779(leaving)X +2037(the)X +2157(current)X +2407(line)X +2550(and)X +2689(column)X +2952(as)X +3042(is,)X +3138(if)X +3210(possible.)X +3535(This)X +3700(is)X +3776(an)X +3875(error)X +776 3642(if)N +845(the)X +963(movement)X +1321(is)X +1394(past)X +1543(the)X +1661(beginning)X +2001(of)X +2088(the)X +2206(\256le.)X +776 3822(Line:)N +1136(Unchanged)X +1525(unless)X +1748(the)X +1869(current)X +2120(line)X +2263(scrolls)X +2496(off)X +2614(the)X +2736(screen,)X +2986(in)X +3072(which)X +3292(case)X +3455(it)X +3523(is)X +3600(set)X +3713(to)X +3799(the)X +3921(last)X +1136 3912(line)N +1276(of)X +1363(text)X +1503(displayed)X +1830(on)X +1930(the)X +2048(screen.)X +776 4002(Column:)N +1136(Unchanged)X +1536(unless)X +1770(the)X +1902(current)X +2164(line)X +2318(scrolls)X +2561(off)X +2689(the)X +2821(screen,)X +3081(in)X +3177(which)X +3407(case)X +3580(it)X +3658(is)X +3745(the)X +3877(most)X +1136 4092(attractive)N +1455(cursor)X +1676(position.)X +776 4182(Options:)N +1136(None.)X +3 f +576 4362(<control-Z>)N +1 f +776 4452(Suspend)N +1069(the)X +1189(current)X +1439(editor)X +1648(session.)X +1941(If)X +2017(the)X +2137(\256le)X +2261(has)X +2390(been)X +2564(modi\256ed)X +2870(since)X +3057(it)X +3124(was)X +3272(last)X +3406(completely)X +3785(written,)X +776 4542(and)N +914(the)X +3 f +1034(autowrite)X +1 f +1386(option)X +1612(is)X +1687(set,)X +1817(the)X +1936(\256le)X +2059(is)X +2133(written)X +2381(before)X +2608(the)X +2727(editor)X +2935(session)X +3187(is)X +3261(suspended.)X +3656(If)X +3731(this)X +3867(write)X +776 4632(fails,)N +954(the)X +1072(editor)X +1279(session)X +1530(is)X +1603(not)X +1725(suspended.)X +776 4812(Line:)N +1136(Unchanged.)X +776 4902(Column:)N +1136(Unchanged.)X +776 4992(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(autowrite)X +1 f +2006(option.)X +3 f +576 5172(<escape>)N +1 f +776 5262(Execute)N +3 f +1055(ex)X +1 f +1151(commands)X +1518(or)X +1605(cancel)X +1831(partial)X +2056(commands.)X +2463(If)X +2537(an)X +3 f +2633(ex)X +1 f +2729(command)X +3065(is)X +3138(being)X +3336(entered)X +3593(\(e.g.)X +3 f +3776(/)X +1 f +3798(,)X +3 f +3838(?)X +1 f +(,)S +3 f +3918(:)X +1 f +3965(or)X +3 f +776 5352(!)N +1 f +803(\),)X +877(the)X +1002(command)X +1345(is)X +1425(executed.)X +1778(If)X +1859(a)X +1922(partial)X +2154(command)X +2497(has)X +2631(been)X +2810(entered,)X +3093(e.g.)X +3255(or)X +3348(the)X +3472(command)X +3814(is)X +3893(can-)X +776 5442(celled.)N +1028(Otherwise,)X +1398(it)X +1462(is)X +1535(an)X +1631(error.)X +776 5622(Line:)N +1136(When)X +1350(an)X +3 f +1448(ex)X +1 f +1546(command)X +1884(is)X +1959(being)X +2159(executed,)X +2487(the)X +2607(current)X +2857(line)X +2999(is)X +3074(set)X +3186(as)X +3276(described)X +3607(for)X +3724(that)X +3867(com-)X +1136 5712(mand.)N +1374(Otherwise,)X +1744(unchanged.)X + +15 p +%%Page: 15 14 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-15)X +1 f +776 762(Column:)N +1136(When)X +1354(an)X +3 f +1456(ex)X +1 f +1558(command)X +1901(is)X +1981(being)X +2186(executed,)X +2519(the)X +2644(current)X +2899(column)X +3166(is)X +3246(set)X +3362(as)X +3456(described)X +3791(for)X +3912(that)X +1136 852(command.)N +1512(Otherwise,)X +1882(unchanged.)X +776 942(Options:)N +1136(None.)X +3 f +576 1122(<control-]>)N +1 f +776 1212(Push)N +953(a)X +1011(tag)X +1131 0.4531(reference)AX +1454(onto)X +1618(the)X +1738(tag)X +1858(stack.)X +2085(The)X +2232(tags)X +2383(\256les)X +2538(\(see)X +2691(the)X +3 f +2812(tags)X +1 f +2973(option)X +3200(for)X +3317(more)X +3505(information\))X +3933(are)X +776 1302(searched)N +1086(for)X +1207(a)X +1270(tag)X +1395(matching)X +1720(the)X +1845(current)X +2100(word.)X +2332(The)X +2484(current)X +2739(word)X +2931(begins)X +3167(at)X +3252(the)X +3377(\256rst)X +3528(non-whitespace)X +776 1392(character)N +1092(on)X +1192(or)X +1279(after)X +1447(the)X +1565(current)X +1813(cursor)X +2034(position,)X +2331(and)X +2468(extends)X +2734(up)X +2835(to)X +2918(the)X +3037(next)X +3196(non-word)X +3529(character)X +3846(or)X +3934(the)X +776 1482(end)N +914(of)X +1003(the)X +1123(line.)X +1305(If)X +1381(a)X +1439(matching)X +1759(tag)X +1879(is)X +1954(found,)X +2183(the)X +2302(current)X +2551(\256le)X +2674(is)X +2748(discarded)X +3077(and)X +3214(the)X +3333(\256le)X +3456(containing)X +3815(the)X +3934(tag)X +776 1572 0.4531(reference)AN +1097(is)X +1170(edited.)X +776 1752(If)N +851(the)X +971(current)X +1221(\256le)X +1345(has)X +1474(been)X +1648(modi\256ed)X +1954(since)X +2141(it)X +2207(was)X +2354(last)X +2487(completely)X +2865(written,)X +3134(the)X +3254(command)X +3592(will)X +3738(fail.)X +3907(The)X +3 f +776 1842(<control-]>)N +1 f +1187(command)X +1523(is)X +1596(an)X +1692(absolute)X +1979(movement.)X +776 2022(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(matching)X +2392(tag)X +2510(string.)X +776 2112(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(start)X +1616(of)X +1703(the)X +1821(matching)X +2139(tag)X +2257(string.)X +776 2202(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(tags)X +1 f +1814(and)X +3 f +1950(taglength)X +1 f +2290(options.)X +3 f +576 2382(<control-\303>)N +1 f +776 2472(Switch)N +1018(to)X +1100(the)X +1218(most)X +1393(recently)X +1672(edited)X +1888(\256le.)X +776 2652(If)N +852(the)X +972(\256le)X +1096(has)X +1225(been)X +1399(modi\256ed)X +1705(since)X +1892(it)X +1958(was)X +2105(last)X +2238(completely)X +2616(written,)X +2886(and)X +3025(the)X +3 f +3146(autowrite)X +1 f +3499(option)X +3726(is)X +3802(set,)X +3934(the)X +776 2742(\256le)N +905(is)X +984(written)X +1237(out.)X +1405(If)X +1485(this)X +1626(write)X +1817(fails,)X +2001(the)X +2125(command)X +2467(will)X +2617(fail.)X +2790(Otherwise,)X +3166(if)X +3241(the)X +3365(current)X +3619(\256le)X +3747(has)X +3880(been)X +776 2832(modi\256ed)N +1080(since)X +1265(it)X +1329(was)X +1474(last)X +1605(completely)X +1981(written,)X +2248(the)X +2366(command)X +2702(will)X +2846(fail.)X +776 3012(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(the)X +1716(cursor)X +1937(was)X +2082(on)X +2182(when)X +2376(the)X +2494(\256le)X +2616(was)X +2761(last)X +2892(edited.)X +776 3102(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(column)X +1718(the)X +1836(cursor)X +2057(was)X +2202(on)X +2302(when)X +2496(the)X +2614(\256le)X +2736(was)X +2881(last)X +3012(edited.)X +776 3192(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(autowrite)X +1 f +2006(option.)X +3 f +576 3372([count])N +841(<space>)X +576 3462([count])N +841(l)X +1 f +776 3552(Move)N +984(the)X +1103(cursor)X +1325(forward)X +7 f +1602(count)X +1 f +1864(characters)X +2213(without)X +2479(changing)X +2795(the)X +2915(current)X +3165(line.)X +3347(This)X +3511(is)X +3586(an)X +3684(error)X +3863(if)X +3934(the)X +776 3642(cursor)N +997(is)X +1070(on)X +1170(the)X +1288(last)X +1419(character)X +1735(in)X +1817(the)X +1935(line.)X +776 3822(The)N +3 f +921(<space>)X +1 f +1220(and)X +3 f +1356(l)X +1 f +1398(commands)X +1765(may)X +1923(be)X +2019(used)X +2186(as)X +2273(the)X +2391(motion)X +2637(component)X +3013(of)X +3100(other)X +3 f +3285(vi)X +1 f +3367(commands,)X +3754(in)X +3836(which)X +776 3912(case)N +937(any)X +1075(text)X +1217(copied)X +1453(into)X +1599(a)X +1657(buffer)X +1876(is)X +1951(character)X +2269(oriented.)X +2594(In)X +2683(addition,)X +2987(these)X +3173(commands)X +3541(may)X +3700(be)X +3797(used)X +3965(as)X +776 4002(the)N +908(motion)X +1168(components)X +1589(of)X +1690(other)X +1889(commands)X +2271(when)X +2480(the)X +2613(cursor)X +2849(is)X +2937(on)X +3052(the)X +3185(last)X +3331(character)X +3662(in)X +3759(the)X +3892(line,)X +776 4092(without)N +1040(error.)X +776 4272(Line:)N +1136(Unchanged.)X +776 4362(Column:)N +1136(Set)X +1259(to)X +1342(the)X +1461(current)X +1710(character)X +2027(plus)X +2181(the)X +2300(next)X +7 f +2459(count)X +1 f +2720(characters,)X +3088(or)X +3177(to)X +3261(the)X +3381(last)X +3514(character)X +3832(on)X +3934(the)X +1136 4452(line)N +1278(if)X +7 f +1349(count)X +1 f +1611(is)X +1686(greater)X +1932(than)X +2092(the)X +2212(number)X +2478(of)X +2566(characters)X +2914(in)X +2997(the)X +3116(line)X +3257(after)X +3426(the)X +3545(current)X +3794(charac-)X +1136 4542(ter.)N +776 4632(Options:)N +1136(None.)X +3 f +576 4812([count])N +841(!)X +888(motion)X +1148(shell-argument\(s\))X +1 f +776 4902(Replace)N +1055(text)X +1195(with)X +1357(results)X +1586(from)X +1762(a)X +1818(shell)X +1989(command.)X +2366(Pass)X +2529(the)X +2648(lines)X +2820(speci\256ed)X +3126(by)X +3227(the)X +7 f +3346(count)X +1 f +3607(and)X +7 f +3744(motion)X +1 f +776 4992(arguments)N +1136(as)X +1229(standard)X +1527(input)X +1717(to)X +1805(the)X +1928(program)X +2225(named)X +2464(by)X +2569(the)X +3 f +2692(shell)X +1 f +2872(option,)X +3121(and)X +3262(replace)X +3520(those)X +3714(lines)X +3890(with)X +776 5082(the)N +894(output)X +1118(\(both)X +1307(standard)X +1599(error)X +1776(and)X +1912(standard)X +2204(output\))X +2455(of)X +2542(that)X +2682(command.)X +776 5262(After)N +966(the)X +1084(motion)X +1330(is)X +1403(entered,)X +3 f +1680(vi)X +1 f +1762(prompts)X +2044(for)X +2158(arguments)X +2512(to)X +2594(the)X +2712(shell)X +2883(command.)X +776 5442(Within)N +1026(those)X +1223(arguments,)X +1605(``)X +7 f +1659(%)X +1 f +('')S +1790(and)X +1935(``)X +7 f +1989(#)X +1 f +('')S +2120(characters)X +2476(are)X +2604(expanded)X +2941(to)X +3032(the)X +3159(current)X +3416(and)X +3561(alternate)X +3867(path-)X +776 5532(names,)N +1024(respectively.)X +1475(The)X +1623(``)X +7 f +1677(!)X +1 f +('')S +1822(character)X +2141(is)X +2217(expanded)X +2548(with)X +2713(the)X +2833(command)X +3171(text)X +3313(of)X +3402(the)X +3522(previous)X +3 f +3820(!)X +1 f +3889(or)X +3 f +3978(:!)X +1 f +776 5622(commands.)N +1183 0.3125(\(Therefore,)AX +1568(the)X +1686(command)X +3 f +2022(!!)X +1 f +2116(repeats)X +2364(the)X +2482(previous)X +3 f +2778(!)X +1 f +2845(command.\))X +3248(The)X +3393(special)X +3637(meanings)X +3965(of)X +776 5712(``)N +7 f +830(%)X +1 f +('',)S +975(``)X +7 f +1029(#)X +1 f +('')S +1154(and)X +1293(``)X +7 f +1347(!)X +1 f +('')S +1492(can)X +1627(be)X +1726(overridden)X +2097(by)X +2200(escaping)X +2504(them)X +2687(with)X +2852(a)X +2910(backslash.)X +3284(If)X +3360(no)X +3 f +3462(!)X +1 f +3531(or)X +3 f +3620(:!)X +1 f +3716(command)X +776 5802(has)N +907(yet)X +1029(been)X +1205(executed,)X +1535(it)X +1603(is)X +1680(an)X +1780(error)X +1961(to)X +2047(use)X +2178(an)X +2278(unescaped)X +2637(``)X +7 f +2691(!)X +1 f +('')S +2837(character.)X +3197(The)X +3 f +3346(!)X +1 f +3417(command)X +3758(does)X +2 f +3930(not)X + +16 p +%%Page: 16 15 +10 s 10 xH 0 xS 2 f 1 i +3 f +576 474(USD:13-16)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +1 f +776 762(do)N +880(shell)X +1055(expansion)X +1404(on)X +1508(the)X +1630(strings)X +1867(provided)X +2175(as)X +2265(arguments.)X +2662(If)X +2739(any)X +2878(of)X +2968(the)X +3089(above)X +3304(expansions)X +3683(change)X +3934(the)X +776 852(arguments)N +1130(the)X +1248(user)X +1402(entered,)X +1679(the)X +1797(command)X +2133(is)X +2206(redisplayed)X +2596(at)X +2674(the)X +2792(bottom)X +3038(of)X +3125(the)X +3243(screen.)X +3 f +776 1032(Vi)N +1 f +882(then)X +1046(executes)X +1349(the)X +1473(program)X +1771(named)X +2011(by)X +2117(the)X +3 f +2241(shell)X +1 f +2422(option,)X +2672(with)X +2840(a)X +3 f +9 f +2902(-)X +2904(-)X +3 f +2948(c)X +1 f +3010(\257ag)X +3156(followed)X +3467(by)X +3573(the)X +3698(arguments)X +776 1122(\(which)N +1019(are)X +1138(bundled)X +1416(into)X +1560(a)X +1616(single)X +1827(argument\).)X +776 1302(The)N +3 f +921(!)X +1 f +988(command)X +1324(is)X +1397(permitted)X +1724(in)X +1806(an)X +1902(empty)X +2122(\256le.)X +776 1482(If)N +850(the)X +968(\256le)X +1090(has)X +1217(been)X +1389(modi\256ed)X +1693(since)X +1878(it)X +1942(was)X +2087(last)X +2218(completely)X +2594(written,)X +2861(the)X +3 f +2979(!)X +1 f +3046(command)X +3382(will)X +3526(warn)X +3707(you.)X +776 1662(Line:)N +1136(The)X +1281(\256rst)X +1425(line)X +1565(of)X +1652(the)X +1770(replaced)X +2063(text.)X +776 1752(Column:)N +1136(The)X +1281(\256rst)X +1425(column)X +1685(of)X +1772(the)X +1890(replaced)X +2183(text.)X +776 1842(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(shell)X +1 f +1831(option.)X +3 f +576 2022([count])N +841(#)X +901(+|-|#)X +1 f +776 2112(Increment)N +1135(or)X +1235(decrement)X +1603(the)X +1734(current)X +1996(number.)X +2315(The)X +2474(current)X +2736(number)X +3015(begins)X +3258(at)X +3350(the)X +3482(\256rst)X +3640(non-number)X +776 2202(character)N +1095(on)X +1198(or)X +1288(before)X +1517(the)X +1638(current)X +1889(cursor)X +2113(position,)X +2413(or)X +2503(the)X +2624(beginning)X +2967(of)X +3057(the)X +3178(line,)X +3341(and)X +3480(extends)X +3748(up)X +3850(to)X +3934(the)X +776 2292(\256rst)N +920(non-number)X +1332(character)X +1649(on)X +1750(or)X +1838(after)X +2007(the)X +2126(current)X +2375(cursor)X +2597(position)X +2875(or)X +2963(the)X +3082(end)X +3219(of)X +3307(the)X +3426(line.)X +3607(If)X +3682(the)X +3801(trailing)X +776 2382(character)N +1094(is)X +1169(a)X +7 f +1227(+)X +1 f +(,)S +1317(the)X +1437(number)X +1704(is)X +1779(incremented)X +2198(by)X +7 f +2300(count)X +1 f +(.)S +2602(If)X +2678(the)X +2798(trailing)X +3051(character)X +3369(is)X +3444(a)X +7 f +3502(-)X +1 f +(,)S +3592(the)X +3712(number)X +3979(is)X +776 2472(decremented)N +1220(by)X +7 f +1333(count)X +1 f +(.)S +1646(If)X +1733(the)X +1864(trailing)X +2128(character)X +2457(is)X +2543(a)X +7 f +2612(#)X +1 f +(,)S +2713(the)X +2844(previous)X +3154(increment)X +3509(or)X +3610(decrement)X +3979(is)X +776 2562(repeated.)N +776 2742(The)N +927(format)X +1167(of)X +1260(the)X +1384(number)X +1656(\(decimal,)X +1984(hexadecimal,)X +2437(and)X +2580(octal,)X +2783(and)X +2926(leading)X +3189(0's\))X +3341(is)X +3421(retained)X +3707(unless)X +3934(the)X +776 2832(new)N +930(value)X +1124(cannot)X +1358(be)X +1454(represented)X +1845(in)X +1927(the)X +2045(previous)X +2341(format.)X +776 3012(Line:)N +1136(Unchanged.)X +776 3102(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(character)X +1918(in)X +2000(the)X +2118(cursor)X +2339(word.)X +776 3192(Options:)N +1136(None.)X +3 f +576 3372([count])N +841($)X +1 f +776 3462(Move)N +989(the)X +1113(cursor)X +1340(to)X +1428(the)X +1552(end)X +1694(of)X +1787(a)X +1849(line.)X +2035(If)X +7 f +2115(count)X +1 f +2381(is)X +2460(speci\256ed,)X +2792(the)X +2917(cursor)X +3145(moves)X +3381(down)X +7 f +3586(count)X +3881(-)X +3984(1)X +1 f +776 3552(lines.)N +776 3732(It)N +845(is)X +918(not)X +1040(an)X +1136(error)X +1313(to)X +1395(use)X +1522(the)X +3 f +1640($)X +1 f +1700(command)X +2036(when)X +2230(the)X +2348(cursor)X +2569(is)X +2642(on)X +2742(the)X +2860(last)X +2991(character)X +3308(in)X +3391(the)X +3510(line)X +3651(or)X +3739(when)X +3934(the)X +776 3822(line)N +916(is)X +989(empty.)X +776 4002(The)N +3 f +921($)X +1 f +981(command)X +1317(may)X +1475(be)X +1571(used)X +1739(as)X +1827(the)X +1946(motion)X +2193(component)X +2570(of)X +2658(other)X +3 f +2844(vi)X +1 f +2927(commands,)X +3315(in)X +3398(which)X +3615(case)X +3775(any)X +3912(text)X +776 4092(copied)N +1014(into)X +1161(a)X +1220(buffer)X +1440(is)X +1516(character)X +1835(oriented,)X +2141(unless)X +2364(the)X +2485(cursor)X +2709(is)X +2785(at,)X +2886(or)X +2976(before)X +3205(the)X +3326(\256rst)X +3473(nonblank)X +3794(charac-)X +776 4182(ter)N +885(in)X +971(the)X +1093(line,)X +1257(in)X +1343(which)X +1563(case)X +1726(it)X +1794(is)X +1871(line)X +2015(oriented.)X +2343(It)X +2417(is)X +2495(not)X +2622(an)X +2723(error)X +2905(to)X +2992(use)X +3124(the)X +3 f +3247($)X +1 f +3312(command)X +3653(as)X +3745(a)X +3806(motion)X +776 4272(component)N +1154(when)X +1350(the)X +1470(cursor)X +1693(is)X +1768(on)X +1870(the)X +1990(last)X +2123(character)X +2441(in)X +2525(the)X +2645(line,)X +2807(although)X +3109(it)X +3175(is)X +3249(an)X +3346(error)X +3524(when)X +3719(the)X +3838(line)X +3979(is)X +776 4362(empty.)N +776 4542(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(current)X +1706(line)X +1846(plus)X +7 f +1999(count)X +1 f +2259(minus)X +2474(1.)X +776 4632(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(in)X +1987(the)X +2105(line.)X +776 4722(Options:)N +1136(None.)X +3 f +576 4902(%)N +1 f +776 4992(Move)N +986(to)X +1071(the)X +1192(matching)X +1513(character.)X +1872(The)X +2020(cursor)X +2244(moves)X +2477(to)X +2563(the)X +2685(parenthesis)X +3070(or)X +3161(curly)X +3350(brace)X +3549(which)X +2 f +3769(matches)X +1 f +776 5082(the)N +900(parenthesis)X +1287(or)X +1380(curly)X +1570(brace)X +1770(found)X +1982(at)X +2065(the)X +2188(current)X +2441(cursor)X +2667(position)X +2949(or)X +3041(which)X +3262(is)X +3340(the)X +3463(closest)X +3706(one)X +3847(to)X +3934(the)X +776 5172(right)N +964(of)X +1068(the)X +1203(cursor)X +1441(on)X +1558(the)X +1693(line.)X +1890(It)X +1976(is)X +2066(an)X +2179(error)X +2373(to)X +2472(execute)X +2756(the)X +3 f +2892(%)X +1 f +3010(command)X +3364(on)X +3482(a)X +3556(line)X +3714(without)X +3996(a)X +776 5262(parenthesis)N +1157(or)X +1244(curly)X +1429(brace.)X +1664(Historically,)X +2082(any)X +7 f +2218(count)X +1 f +2478(speci\256ed)X +2783(to)X +2865(the)X +3 f +2983(%)X +1 f +3083(command)X +3419(was)X +3564(ignored.)X +776 5442(The)N +3 f +921(%)X +1 f +1021(command)X +1357(is)X +1430(an)X +1527(absolute)X +1815(movement.)X +2214(The)X +3 f +2360(%)X +1 f +2461(command)X +2798(may)X +2957(be)X +3054(used)X +3222(as)X +3310(the)X +3429(motion)X +3676(component)X +776 5532(of)N +871(other)X +3 f +1064(vi)X +1 f +1153(commands,)X +1547(in)X +1636(which)X +1859(case)X +2025(any)X +2168(text)X +2315(copied)X +2556(into)X +2707(a)X +2770(buffer)X +2994(is)X +3074(character)X +3397(oriented,)X +3707(unless)X +3934(the)X +776 5622(starting)N +1036(point)X +1220(of)X +1307(the)X +1425(region)X +1650(is)X +1723(at)X +1801(or)X +1888(before)X +2115(the)X +2234(\256rst)X +2379(nonblank)X +2698(character)X +3015(on)X +3116(its)X +3212(line,)X +3373(and)X +3510(the)X +3629(ending)X +3868(point)X +776 5712(is)N +849(at)X +927(or)X +1014(after)X +1182(the)X +1300(last)X +1431(nonblank)X +1749(character)X +2065(on)X +2165(its)X +2260(line,)X +2420(in)X +2502(which)X +2718(case)X +2877(it)X +2941(is)X +3014(line)X +3154(oriented.)X + +17 p +%%Page: 17 16 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-17)X +1 f +776 762(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(matching)X +2392(character.)X +776 852(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(matching)X +1776(character.)X +776 942(Options:)N +1136(None.)X +3 f +576 1122(&)N +1 f +776 1212(Repeat)N +1019(the)X +1137(previous)X +1433(substitution)X +1825(command)X +2161(on)X +2261(the)X +2379(current)X +2627(line.)X +776 1392(Historically,)N +1194(any)X +7 f +1330(count)X +1 f +1590(speci\256ed)X +1895(to)X +1977(the)X +3 f +2095(&)X +1 f +2182(command)X +2518(was)X +2663(ignored.)X +776 1572(Line:)N +1136(Unchanged.)X +776 1662(Column:)N +1136(Unchanged)X +1531(if)X +1609(the)X +1736(cursor)X +1966(was)X +2120(on)X +2229(the)X +2356(last)X +2496(character)X +2821(in)X +2912(the)X +3039(line,)X +3208(otherwise,)X +3569(set)X +3688(to)X +3780(the)X +3908(\256rst)X +1136 1752(nonblank)N +1454(character)X +1770(in)X +1852(the)X +1970(line.)X +776 1842(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(edcompatible)X +1 f +2114(,)X +3 f +2154(extended)X +1 f +2461(,)X +3 f +2501(ignorecase)X +1 f +2882(and)X +3 f +3018(magic)X +1 f +3243(options.)X +3 f +576 2022 0.3182(\302<character>)AN +576 2112 0.3182(`<character>)AN +1 f +776 2202(Return)N +1014(to)X +1096(a)X +1152(context)X +1408(marked)X +1669(by)X +1769(the)X +1888(character)X +7 f +2205(<character>)X +1 f +(.)S +2794(If)X +7 f +2869(<character>)X +1 f +3418(is)X +3492(the)X +3611(``)X +7 f +3665(')X +1 f +('')S +3788(or)X +3876(``)X +7 f +3930(`)X +1 f +('')S +776 2292(character,)N +1113(return)X +1326(to)X +1409(the)X +1528(previous)X +1825(context.)X +2122(If)X +7 f +2197(<character>)X +1 f +2746(is)X +2820(any)X +2956(other)X +3141(character,)X +3477(return)X +3689(to)X +3771(the)X +3889(con-)X +776 2382(text)N +921(marked)X +1187(by)X +1292(that)X +1437(character)X +1759(\(see)X +1915(the)X +3 f +2039(m)X +1 f +2132(command)X +2474(for)X +2594(more)X +2785(information\).)X +3256(If)X +3336(the)X +3460(command)X +3802(is)X +3881(the)X +3 f +4005(\302)X +1 f +776 2472(command,)N +1137(only)X +1304(the)X +1427(line)X +1572(value)X +1771(is)X +1848(restored,)X +2151(and)X +2291(the)X +2413(cursor)X +2638(is)X +2715(placed)X +2949(on)X +3053(the)X +3175(\256rst)X +3323(nonblank)X +3645(character)X +3965(of)X +776 2562(that)N +916(line.)X +1096(If)X +1170(the)X +1288(command)X +1624(is)X +1697(the)X +3 f +1815(`)X +1 f +1862(command,)X +2218(both)X +2380(the)X +2498(line)X +2638(and)X +2774(column)X +3034(values)X +3259(are)X +3378(restored.)X +776 2742(It)N +849(is)X +926(an)X +1026(error)X +1207(if)X +1280(the)X +1402(context)X +1662(no)X +1766(longer)X +1995(exists)X +2202(because)X +2482(of)X +2574(line)X +2719(deletion.)X +3042(\(Contexts)X +3378(follow)X +3612(lines)X +3788(that)X +3933(are)X +776 2832(moved,)N +1034(or)X +1121(which)X +1337(are)X +1456(deleted)X +1708(and)X +1844(then)X +2002(restored.\))X +776 3012(The)N +3 f +924(\302)X +1 f +974(and)X +3 f +1113(`)X +1 f +1163(commands)X +1533(are)X +1655(both)X +1820(absolute)X +2110(movements.)X +2542(They)X +2730(may)X +2891(be)X +2990(used)X +3160(as)X +3250(a)X +3309(motion)X +3558(component)X +3938(for)X +776 3102(other)N +3 f +962(vi)X +1 f +1045(commands.)X +1453(For)X +1585(the)X +3 f +1704(\302)X +1 f +1752(command,)X +2108(any)X +2244(text)X +2384(copied)X +2618(into)X +2762(a)X +2818(buffer)X +3035(is)X +3108(line)X +3248(oriented.)X +3571(For)X +3702(the)X +3 f +3820(`)X +1 f +3867(com-)X +776 3192(mand,)N +1002(any)X +1146(text)X +1294(copied)X +1536(into)X +1688(a)X +1752(buffer)X +1977(is)X +2058(character)X +2382(oriented,)X +2693(unless)X +2921(it)X +2993(both)X +3163(starts)X +3360(and)X +3504(stops)X +3696(at)X +3782(the)X +3908(\256rst)X +776 3282(character)N +1099(in)X +1188(the)X +1313(line,)X +1480(in)X +1569(which)X +1792(case)X +1958(it)X +2029(is)X +2109(line)X +2255(oriented.)X +2584(In)X +2677(addition,)X +2985(when)X +3185(using)X +3384(the)X +3 f +3508(`)X +1 f +3561(command)X +3903(as)X +3996(a)X +776 3372(motion)N +1025(component,)X +1424(commands)X +1794(which)X +2013(move)X +2214(backward)X +2550(and)X +2689(started)X +2926(at)X +3007(the)X +3128(\256rst)X +3275(character)X +3594(in)X +3679(the)X +3801(line,)X +3965(or)X +776 3462(move)N +983(forward)X +1267(and)X +1412(ended)X +1633(at)X +1719(the)X +1845(\256rst)X +1997(character)X +2321(in)X +2411(the)X +2537(line,)X +2705(are)X +2832(corrected)X +3160(to)X +3250(the)X +3376(last)X +3515(character)X +3839(of)X +3934(the)X +776 3552(starting)N +1036(and)X +1172(ending)X +1410(lines,)X +1601(respectively.)X +776 3732(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(from)X +1774(the)X +1892(context.)X +776 3822(Column:)N +1136(Set)X +1261(to)X +1346(the)X +1467(\256rst)X +1614(nonblank)X +1935(character)X +2254(in)X +2340(the)X +2462(line,)X +2626(for)X +2744(the)X +3 f +2866(\302)X +1 f +2917(command,)X +3277(and)X +3417(set)X +3530(to)X +3616(the)X +3738(context's)X +1136 3912(column)N +1396(for)X +1510(the)X +3 f +1628(`)X +1 f +1675(command.)X +776 4002(Options:)N +1136(None.)X +3 f +576 4182([count])N +841(\()X +1 f +776 4272(Back)N +961(up)X +7 f +1061(count)X +1 f +1321(sentences.)X +776 4452(The)N +3 f +922(\()X +1 f +970(command)X +1307(is)X +1382(an)X +1480(absolute)X +1769(movement.)X +2169(The)X +3 f +2316(\()X +1 f +2365(command)X +2703(may)X +2863(be)X +2961(used)X +3130(as)X +3219(the)X +3339(motion)X +3587(component)X +3965(of)X +776 4542(other)N +3 f +963(vi)X +1 f +1047(commands,)X +1436(in)X +1520(which)X +1738(case)X +1899(any)X +2036(text)X +2177(copied)X +2412(into)X +2557(a)X +2614(buffer)X +2832(is)X +2906(character)X +3223(oriented,)X +3527(unless)X +3748(the)X +3867(start-)X +776 4632(ing)N +913(and)X +1064(stopping)X +1374(points)X +1604(of)X +1706(the)X +1839(region)X +2079(are)X +2213(the)X +2346(\256rst)X +2505(character)X +2836(in)X +2933(the)X +3066(line,)X +3241(in)X +3338(which)X +3569(case)X +3743(it)X +3823(is)X +3912(line)X +776 4722(oriented.)N +1111(In)X +1210(the)X +1340(latter)X +1537(case,)X +1728(the)X +1858(stopping)X +2165(point)X +2361(of)X +2460(the)X +2590(region)X +2827(is)X +2911(adjusted)X +3209(to)X +3302(be)X +3409(the)X +3538(end)X +3685(of)X +3783(the)X +3912(line)X +776 4812(immediately)N +1196(before)X +1422(it,)X +1506(and)X +1642(not)X +1764(the)X +1882(original)X +2151(cursor)X +2372(position.)X +776 4992(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(beginning)X +2414(of)X +2501(the)X +2619(sentence.)X +776 5082(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2441(sentence.)X +776 5172(Options:)N +1136(None.)X +3 f +576 5352([count])N +841(\))X +1 f +776 5442(Move)N +983(forward)X +7 f +1258(count)X +1 f +1518(sentences.)X +776 5622(The)N +3 f +922(\))X +1 f +970(command)X +1307(is)X +1382(an)X +1480(absolute)X +1769(movement.)X +2169(The)X +3 f +2316(\))X +1 f +2365(command)X +2703(may)X +2863(be)X +2961(used)X +3130(as)X +3219(the)X +3339(motion)X +3587(component)X +3965(of)X +776 5712(other)N +3 f +963(vi)X +1 f +1047(commands,)X +1436(in)X +1520(which)X +1738(case)X +1899(any)X +2036(text)X +2177(copied)X +2412(into)X +2557(a)X +2614(buffer)X +2832(is)X +2906(character)X +3223(oriented,)X +3527(unless)X +3748(the)X +3867(start-)X +776 5802(ing)N +901(point)X +1088(of)X +1179(the)X +1301(region)X +1530(is)X +1607(the)X +1729(\256rst)X +1877(character)X +2197(in)X +2283(the)X +2405(line,)X +2569(in)X +2655(which)X +2875(case)X +3038(it)X +3106(is)X +3183(line)X +3327(oriented.)X +3654(In)X +3745(the)X +3867(latter)X + +18 p +%%Page: 18 17 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-18)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +1 f +776 762(case,)N +961(if)X +1036(the)X +1160(stopping)X +1461(point)X +1651(of)X +1744(the)X +1868(region)X +2099(is)X +2178(also)X +2333(the)X +2457(\256rst)X +2607(character)X +2929(in)X +3017(the)X +3141(line,)X +3307(it)X +3376(is)X +3454(adjusted)X +3746(to)X +3833(be)X +3934(the)X +776 852(end)N +912(of)X +999(the)X +1117(line)X +1257(immediately)X +1677(before)X +1903(it.)X +776 1032(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(beginning)X +2414(of)X +2501(the)X +2619(sentence.)X +776 1122(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2441(sentence.)X +776 1212(Options:)N +1136(None.)X +3 f +576 1392([count])N +841(,)X +1 f +776 1482(Reverse)N +1055(\256nd)X +1199(character)X +7 f +1515(count)X +1 f +1775(times.)X +2008(Reverse)X +2288(the)X +2407(last)X +3 f +2539(F)X +1 f +2588(,)X +3 f +2629(f)X +1 f +2656(,)X +3 f +2697(T)X +1 f +2771(or)X +3 f +2859(t)X +1 f +2907(command,)X +3264(searching)X +3593(the)X +3712(other)X +3898(way)X +776 1572(in)N +858(the)X +976(line,)X +7 f +1136(count)X +1 f +1396(times.)X +776 1752(The)N +3 f +922(,)X +1 f +963(command)X +1300(may)X +1460(be)X +1558(used)X +1727(as)X +1816(the)X +1936(motion)X +2184(component)X +2562(of)X +2651(other)X +3 f +2838(vi)X +1 f +2922(commands,)X +3311(in)X +3395(which)X +3613(case)X +3774(any)X +3912(text)X +776 1842(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 2022(Line:)N +1136(Unchanged.)X +776 2112(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458 0.3068(searched-for)AX +1881(character.)X +776 2202(Options:)N +1136(None.)X +3 f +576 2382([count])N +9 f +841(-)X +843(-)X +1 f +776 2472(Move)N +983(to)X +1065(\256rst)X +1209(nonblank)X +1527(of)X +1614(the)X +1732(previous)X +2028(line,)X +7 f +2188(count)X +1 f +2448(times.)X +776 2652(This)N +938(is)X +1011(an)X +1107(error)X +1284(if)X +1353(the)X +1471(movement)X +1829(is)X +1902(past)X +2051(the)X +2169(beginning)X +2509(of)X +2596(the)X +2714(\256le.)X +776 2832(The)N +3 f +922(-)X +1 f +970(command)X +1307(may)X +1466(be)X +1563(used)X +1731(as)X +1819(the)X +1938(motion)X +2185(component)X +2562(of)X +2651(other)X +3 f +2838(vi)X +1 f +2922(commands,)X +3311(in)X +3395(which)X +3613(case)X +3774(any)X +3912(text)X +776 2922(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(line)X +1640(oriented.)X +776 3102(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(current)X +1706(line)X +1846(minus)X +7 f +2061(count)X +1 f +(.)S +776 3192(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 3282(Options:)N +1136(None.)X +3 f +576 3462([count])N +841(.)X +1 f +776 3552(Repeat)N +1031(the)X +1161(last)X +3 f +1304(vi)X +1 f +1398(command)X +1746(that)X +1898(modi\256ed)X +2214(text.)X +2406(The)X +2563(repeated)X +2869(command)X +3218(may)X +3389(be)X +3498(a)X +3567(command)X +3916(and)X +776 3642(motion)N +1030(component)X +1413(combination.)X +1880(If)X +7 f +1961(count)X +1 f +2228(is)X +2308(speci\256ed,)X +2640(it)X +2711(replaces)X +2 f +3002(both)X +1 f +3171(the)X +3296(count)X +3501(speci\256ed)X +3813(for)X +3934(the)X +776 3732(repeated)N +1093(command,)X +1473(and,)X +1653(if)X +1746(applicable,)X +2140(for)X +2278(the)X +2420(repeated)X +2737(motion)X +3007(component.)X +3448(If)X +7 f +3547(count)X +1 f +3832(is)X +3930(not)X +776 3822(speci\256ed,)N +1101(the)X +1219(counts)X +1448(originally)X +1779(speci\256ed)X +2084(to)X +2166(the)X +2284(command)X +2620(being)X +2818(repeated)X +3111(are)X +3230(used)X +3397(again.)X +776 4002(As)N +887(a)X +945(special)X +1190(case,)X +1371(if)X +1442(the)X +3 f +1562(.)X +1 f +1624(command)X +1962(is)X +2037(executed)X +2345(immediately)X +2767(after)X +2937(the)X +3 f +3057(u)X +1 f +3123(command,)X +3482(the)X +3603(change)X +3854(log)X +3979(is)X +776 4092(rolled)N +983(forward)X +1258(or)X +1345(backward,)X +1698(depending)X +2052(on)X +2152(the)X +2270(action)X +2486(of)X +2573(the)X +3 f +2691(u)X +1 f +2755(command.)X +776 4272(Line:)N +1136(Set)X +1258(as)X +1345(described)X +1673(for)X +1787(the)X +1905(repeated)X +2198(command.)X +776 4362(Column:)N +1136(Set)X +1258(as)X +1345(described)X +1673(for)X +1787(the)X +1905(repeated)X +2198(command.)X +776 4452(Options:)N +1136(None.)X +3 f +576 4632 0.1776(/RE<carriage-return>)AN +576 4722(/RE/)N +751 0.2500([offset]<carriage-return>)AX +576 4812 0.1908(?RE<carriage-return>)AN +576 4902(?RE?)N +787 0.2500([offset]<carriage-return>)AX +576 4992(N)N +576 5082(n)N +1 f +776 5172(Search)N +1017(forward)X +1295(or)X +1385(backward)X +1721(for)X +1838(a)X +1897(regular)X +2148(expression.)X +2554(The)X +2702(commands)X +3072(beginning)X +3415(with)X +3580(a)X +3639(slash)X +3822(\(``)X +7 f +3903(/)X +1 f +(''\))S +776 5262(character)N +1095(are)X +1217(forward)X +1495(searches,)X +1811(the)X +1932(commands)X +2302(beginning)X +2644(with)X +2808(a)X +2866(question)X +3159(mark)X +3346(\(``)X +7 f +3427(?)X +1 f +(''\))S +3598(are)X +3719(backward)X +776 5352(searches.)N +3 f +1117(Vi)X +1 f +1225(prompts)X +1515(with)X +1685(the)X +1811(leading)X +2075(character)X +2399(on)X +2507(the)X +2633(last)X +2772(line)X +2920(of)X +3015(the)X +3142(screen)X +3377(for)X +3500(a)X +3565(string.)X +3816(It)X +3894(then)X +776 5442(searches)N +1071(forward)X +1348(or)X +1437(backward)X +1772(in)X +1856(the)X +1976(\256le)X +2100(for)X +2216(the)X +2336(next)X +2496 0.3611(occurrence)AX +2872(of)X +2961(the)X +3081(string,)X +3305(which)X +3522(is)X +3596(interpreted)X +3965(as)X +776 5532(a)N +832(Basic)X +1030(Regular)X +1304(Expression.)X +776 5712(The)N +3 f +928(/)X +1 f +977(and)X +3 f +1120(?)X +1 f +1207(commands)X +1581(are)X +1707(absolute)X +2001(movements.)X +2437(They)X +2630(may)X +2796(be)X +2900(used)X +3075(as)X +3170(the)X +3296(motion)X +3550(components)X +3965(of)X +776 5802(other)N +3 f +974(vi)X +1 f +1069(commands,)X +1469(in)X +1564(which)X +1793(case)X +1965(any)X +2114(text)X +2267(copied)X +2514(into)X +2671(a)X +2740(buffer)X +2970(is)X +3056(character)X +3385(oriented,)X +3701(unless)X +3934(the)X + +19 p +%%Page: 19 18 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-19)X +1 f +776 762(search)N +1007(started)X +1246(and)X +1387(ended)X +1604(on)X +1709(the)X +1832(\256rst)X +1981(column)X +2246(of)X +2338(a)X +2399(line,)X +2564(in)X +2651(which)X +2872(case)X +3036(it)X +3105(is)X +3183(line)X +3328(oriented.)X +3657(In)X +3750(addition,)X +776 852(forward)N +1056(searches)X +1354(ending)X +1597(at)X +1680(the)X +1803(\256rst)X +1951(character)X +2271(of)X +2362(a)X +2422(line,)X +2586(and)X +2726(backward)X +3063(searches)X +3360(beginning)X +3704(at)X +3786(the)X +3908(\256rst)X +776 942(character)N +1098(in)X +1186(the)X +1310(line,)X +1476(are)X +1601(corrected)X +1927(to)X +2015(begin)X +2219(or)X +2312(end)X +2454(at)X +2538(the)X +2662(last)X +2799(character)X +3121(of)X +3214(the)X +3339(previous)X +3642(line.)X +3829(\(Note,)X +776 1032(forward)N +1061(and)X +1207(backward)X +1550(searches)X +1853(can)X +1995(occur)X +2204(for)X +2328(both)X +3 f +2500(/)X +1 f +2552(and)X +3 f +2698(?)X +1 f +2787(commands,)X +3183(if)X +3261(the)X +3 f +3388(wrapscan)X +1 f +3746(option)X +3979(is)X +776 1122(set.\))N +776 1302(If)N +852(an)X +950(offset)X +1155(from)X +1333(the)X +1453(matched)X +1747(line)X +1889(is)X +1964(speci\256ed)X +2271(\(i.e.)X +2418(a)X +2476(trailing)X +2729(``)X +7 f +2783(/)X +1 f +('')S +2907(or)X +2996(``)X +7 f +3050(?)X +1 f +('')S +3194(character)X +3512(is)X +3587(followed)X +3894(by)X +3996(a)X +776 1392(signed)N +1009(offset\),)X +1263(the)X +1385(buffer)X +1606(will)X +1754(always)X +2001(be)X +2100(line)X +2243(oriented)X +2529(\(e.g.)X +2715(``)X +7 f +2769(/string/+0)X +1 f +('')S +3326(will)X +3473(always)X +3719(guarantee)X +776 1482(a)N +832(line)X +972(orientation\).)X +776 1662(The)N +3 f +921(n)X +1 f +985(command)X +1321(repeats)X +1569(the)X +1687(previous)X +1983(search.)X +776 1842(The)N +3 f +921(N)X +1 f +999(command)X +1335(repeats)X +1583(the)X +1701(previous)X +1997(search,)X +2243(but)X +2365(in)X +2447(the)X +2565(reverse)X +2818(direction.)X +776 2022(Missing)N +1194(RE's)X +1515(\(e.g.)X +1839(``)X +7 f +1893(//<carriage-return>)X +1 f +('',)S +3040(``)X +7 f +3094(/<carriage-return>)X +1 f +('',)S +776 2112(``)N +7 f +830(??<carriage-return>)X +1 f +('',)S +1847(or)X +1945(``)X +7 f +1999(?<carriage-return>)X +1 f +('')S +2948(search)X +3185(for)X +3310(the)X +3439(last)X +3581(search)X +3818(RE,)X +3970(in)X +776 2202(the)N +894(indicated)X +1208(direction.)X +776 2382(Searches)N +1082(may)X +1240(be)X +1336(interrupted)X +1708(using)X +1901(the)X +7 f +2019(<interrupt>)X +1 f +2567(character.)X +776 2562(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(in)X +1680(which)X +1896(the)X +2014(match)X +2230(occurred.)X +776 2652(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(character)X +1918(of)X +2005(the)X +2123(matched)X +2415(string.)X +776 2742(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(edcompatible)X +1 f +2114(,)X +3 f +2154(extended)X +1 f +2461(,)X +3 f +2501(ignorecase)X +1 f +2862(,)X +3 f +2902(magic)X +1 f +3107(,)X +3147(and)X +3 f +3283(wrapscan)X +1 f +3632(options.)X +3 f +576 2922(0)N +1 f +776 3012(Move)N +985(to)X +1069(the)X +1189(\256rst)X +1335(character)X +1654(in)X +1739(the)X +1860(current)X +2111(line.)X +2294(It)X +2366(is)X +2442(not)X +2567(an)X +2666(error)X +2846(to)X +2931(use)X +3061(the)X +3 f +3182(0)X +1 f +3245(command)X +3584(when)X +3781(the)X +3902(cur-)X +776 3102(sor)N +894(is)X +967(on)X +1067(the)X +1185(\256rst)X +1329(character)X +1645(in)X +1727(the)X +1845(line,)X +776 3282(The)N +3 f +923(0)X +1 f +986(command)X +1325(may)X +1486(be)X +1585(used)X +1755(as)X +1845(the)X +1966(motion)X +2215(component)X +2594(of)X +2684(other)X +3 f +2872(vi)X +1 f +2957(commands,)X +3347(in)X +3432(which)X +3651(case)X +3813(it)X +3880(is)X +3956(an)X +776 3372(error)N +953(if)X +1022(the)X +1140(cursor)X +1361(is)X +1434(on)X +1534(the)X +1652(\256rst)X +1796(character)X +2112(in)X +2194(the)X +2312(line.)X +776 3552(Line:)N +1136(Unchanged.)X +776 3642(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(character)X +1918(in)X +2000(the)X +2118(line.)X +776 3732(Options:)N +1136(None.)X +3 f +576 3912(:)N +1 f +776 4002(Execute)N +1055(an)X +1152(ex)X +1249(command.)X +3 f +1626(Vi)X +1 f +1727(prompts)X +2010(for)X +2125(an)X +3 f +2222(ex)X +1 f +2319(command)X +2656(on)X +2757(the)X +2876(last)X +3008(line)X +3149(of)X +3237(the)X +3356(screen,)X +3603(using)X +3797(a)X +3854(colon)X +776 4092(\(``)N +7 f +857(:)X +1 f +(''\))S +1029(character.)X +1408(The)X +1575(command)X +1933(is)X +2028(terminated)X +2413(by)X +2535(a)X +7 f +2613(<carriage-return>)X +1 f +(,)S +7 f +3491(<newline>)X +1 f +3965(or)X +7 f +776 4182(<escape>)N +1 f +1184(character;)X +1526(all)X +1630(of)X +1721(these)X +1910(characters)X +2261(may)X +2423(be)X +2523(escaped)X +2802(by)X +2906(using)X +3103(a)X +7 f +3164(<literal)X +3601(next>)X +1 f +3866(char-)X +776 4272(acter.)N +993(The)X +1138(command)X +1474(is)X +1547(then)X +1705(executed.)X +776 4452(If)N +850(the)X +3 f +968(ex)X +1 f +1064(command)X +1400(writes)X +1616(to)X +1698(the)X +1816(screen,)X +3 f +2063(vi)X +1 f +2146(will)X +2291(prompt)X +2543(the)X +2662(user)X +2817(for)X +2932(a)X +7 f +2989(<carriage-return>)X +1 f +3826(before)X +776 4542(continuing)N +1144(when)X +1344(the)X +3 f +1468(ex)X +1 f +1570(command)X +1912(\256nishes.)X +2222(Large)X +2436(amounts)X +2733(of)X +2826(output)X +3056(from)X +3238(the)X +3 f +3362(ex)X +1 f +3464(command)X +3806(will)X +3956(be)X +776 4632(paged)N +994(for)X +1114(the)X +1238(user,)X +1418(and)X +1560(the)X +1684(user)X +1844(prompted)X +2177(for)X +2297(a)X +7 f +2359(<carriage-return>)X +1 f +3201(or)X +7 f +3294(<space>)X +1 f +3657(key)X +3800(to)X +3889(con-)X +776 4722(tinue.)N +999(In)X +1089(some)X +1281(cases,)X +1494(a)X +1553(quit)X +1700(\(normally)X +2039(a)X +2098(``q'')X +2269 0.3750(character\))AX +2615(or)X +7 f +2705(<interrupt>)X +1 f +3256(may)X +3417(be)X +3515(entered)X +3774(to)X +3858(inter-)X +776 4812(rupt)N +925(the)X +3 f +1043(ex)X +1 f +1139(command.)X +776 4992(When)N +988(the)X +3 f +1106(ex)X +1 f +1202(command)X +1538(\256nishes,)X +1822(and)X +1958(the)X +2076(user)X +2230(is)X +2303(prompted)X +2631(to)X +2714(resume)X +2967(visual)X +3179(mode,)X +3398(it)X +3463(is)X +3537(also)X +3687(possible)X +3970(to)X +776 5082(enter)N +957(another)X +1218(``)X +7 f +1272(:)X +1 f +('')S +1394(character)X +1710(followed)X +2015(by)X +2115(another)X +3 f +2376(ex)X +1 f +2472(command.)X +776 5262(Line:)N +1136(The)X +1281(current)X +1529(line)X +1669(is)X +1742(set)X +1851(as)X +1938(described)X +2266(for)X +2380(the)X +3 f +2498(ex)X +1 f +2594(command.)X +776 5352(Column:)N +1136(The)X +1281(current)X +1529(column)X +1789(is)X +1862(set)X +1971(as)X +2058(described)X +2386(for)X +2500(the)X +3 f +2618(ex)X +1 f +2714(command.)X +776 5442(Options:)N +1136(None.)X +3 f +576 5622([count])N +841(;)X +1 f +776 5712(Repeat)N +1025(the)X +1149(last)X +1286(character)X +1608(\256nd)X +7 f +1758(count)X +1 f +2024(times.)X +2263(The)X +2415(last)X +2553(character)X +2876(\256nd)X +3027(is)X +3107(one)X +3250(of)X +3344(the)X +3 f +3469(F)X +1 f +3518(,)X +3 f +3565(f)X +1 f +3592(,)X +3 f +3639(T)X +1 f +3719(or)X +3 f +3813(t)X +1 f +3867(com-)X +776 5802(mands.)N + +20 p +%%Page: 20 19 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-20)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +1 f +776 762(The)N +3 f +922(;)X +1 f +970(command)X +1307(may)X +1466(be)X +1563(used)X +1731(as)X +1819(the)X +1938(motion)X +2185(component)X +2562(of)X +2651(other)X +3 f +2838(vi)X +1 f +2922(commands,)X +3311(in)X +3395(which)X +3613(case)X +3774(any)X +3912(text)X +776 852(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 1032(Line:)N +1136(Unchanged.)X +776 1122(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458 0.3068(searched-for)AX +1881(character.)X +776 1212(Options:)N +1136(None.)X +3 f +576 1392([count])N +841(<)X +907(motion)X +576 1482([count])N +841(>)X +907(motion)X +1 f +776 1572(Shift)N +956(lines)X +1132(left)X +1264(or)X +1357(right.)X +1574(Shift)X +1755(the)X +1879(number)X +2150(of)X +2243(lines)X +2420(in)X +2508(the)X +2632(region)X +2863(speci\256ed)X +3174(by)X +3280(the)X +3404(motion)X +3656(component,)X +776 1662(times)N +7 f +980(count)X +1 f +(,)S +1271(left)X +1409(\(for)X +1561(the)X +3 f +1690(<)X +1 f +1767(command\))X +2141(or)X +2239(right)X +2421(\(for)X +2573(the)X +3 f +2702(>)X +1 f +2778(command\))X +3151(by)X +3261(the)X +3389(number)X +3664(of)X +3761(columns)X +776 1752(speci\256ed)N +1086(by)X +1191(the)X +3 f +1314(shiftwidth)X +1 f +1685(option.)X +1954(Only)X +2139(whitespace)X +2521(characters)X +2873(are)X +2997(deleted)X +3255(when)X +3455(shifting)X +3725(left;)X +3880(once)X +776 1842(the)N +901(\256rst)X +1052(character)X +1375(in)X +1464(the)X +1589(line)X +1736(contains)X +2030(a)X +2092(nonblank)X +2416(character,)X +2758(the)X +3 f +2882(shift)X +1 f +3059(will)X +3209(succeed,)X +3510(but)X +3638(the)X +3762(line)X +3908(will)X +776 1932(not)N +898(be)X +994(modi\256ed.)X +776 2112(Line:)N +1136(Unchanged.)X +776 2202(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 2292(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(shiftwidth)X +1 f +2022(option.)X +3 f +576 2472(@)N +670(buffer)X +1 f +776 2562(Execute)N +1065(a)X +1131(named)X +1375(buffer.)X +1642(Execute)X +1931(the)X +2059(named)X +2303(buffer)X +2530(as)X +3 f +2627(vi)X +1 f +2719(commands.)X +3136(The)X +3292(buffer)X +3520(may)X +3689(include)X +3 f +3956(ex)X +1 f +776 2652(commands,)N +1170(too,)X +1319(but)X +1448(they)X +1613(must)X +1795(be)X +1898(expressed)X +2241(as)X +2334(a)X +3 f +2396(:)X +1 f +2449(command.)X +2831(If)X +2911(the)X +3035(buffer)X +3258(is)X +3337(line)X +3483(oriented,)X +7 f +3792(<new-)X +776 2742(line>)N +1 f +1054(characters)X +1419(are)X +1556(logically)X +1874(appended)X +2220(to)X +2320(each)X +2506(line)X +2664(of)X +2769(the)X +2905(buffer.)X +3180(If)X +3272(the)X +3408(buffer)X +3644(is)X +3736(character)X +776 2832(oriented,)N +7 f +1079(<newline>)X +1 f +1531(characters)X +1878(are)X +1997(logically)X +2297(appended)X +2625(to)X +2707(all)X +2807(but)X +2929(the)X +3047(last)X +3178(line)X +3318(in)X +3400(the)X +3518(buffer.)X +776 3012(If)N +861(the)X +990(buffer)X +1218(name)X +1423(is)X +1507(``)X +7 f +1561(@)X +1 f +('',)S +1714(or)X +1812(``)X +7 f +1866(*)X +1 f +('',)S +2019(then)X +2188(the)X +2317(last)X +2459(buffer)X +2687(executed)X +3004(shall)X +3186(be)X +3293(used.)X +3511(It)X +3591(is)X +3675(an)X +3782(error)X +3970(to)X +776 3102(specify)N +1033(``)X +7 f +1087(@@)X +1 f +('')S +1262(or)X +1354(``)X +7 f +1408(**)X +1 f +('')S +1583(if)X +1657(there)X +1843(were)X +2025(no)X +2130(buffer)X +2351(previous)X +2651(executions.)X +3058(The)X +3207(text)X +3351(of)X +3442(a)X +3502(macro)X +3727(may)X +3889(con-)X +776 3192(tain)N +919(an)X +3 f +1019(@)X +1 f +1117(command,)X +1477(and)X +1617(it)X +1685(is)X +1762(possible)X +2048(to)X +2134(create)X +2351(in\256nite)X +2601(loops)X +2798(in)X +2884(this)X +3023(manner.)X +3328(\(The)X +7 f +3504(<interrupt>)X +1 f +776 3282(character)N +1092(may)X +1250(be)X +1346(used)X +1513(to)X +1595(interrupt)X +1891(the)X +2009(loop.\))X +776 3462(Line:)N +1136(The)X +1281(current)X +1529(line)X +1669(is)X +1742(set)X +1851(as)X +1938(described)X +2266(for)X +2380(the)X +2498(command\(s\).)X +776 3552(Column:)N +1136(The)X +1281(current)X +1529(column)X +1789(is)X +1862(set)X +1971(as)X +2058(described)X +2386(for)X +2500(the)X +2618(command\(s\).)X +776 3642(Options:)N +1136(None.)X +3 f +576 3822([count])N +841(A)X +1 f +776 3912(Enter)N +981(input)X +1176(mode,)X +1405(appending)X +1770(the)X +1899(text)X +2050(after)X +2229(the)X +2358(end)X +2505(of)X +2603(the)X +2732(line.)X +2923(If)X +7 f +3008(count)X +1 f +3279(is)X +3363(speci\256ed,)X +3699(the)X +3828(text)X +3979(is)X +776 4002(repeatedly)N +1131(input)X +7 f +1315(count)X +1603(-)X +1699(1)X +1 f +1767(more)X +1952(times)X +2145(after)X +2313(input)X +2497(mode)X +2695(is)X +2768(exited.)X +776 4182(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 4272(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 4362(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 4452(gin)N +1 f +1262(options.)X +3 f +576 4632([count])N +841(B)X +1 f +776 4722(Move)N +995(backward)X +7 f +1340(count)X +1 f +1612(bigwords.)X +1982(Move)X +2201(the)X +2331(cursor)X +2564(backward)X +2909(to)X +3003(the)X +3133(beginning)X +3485(of)X +3584(a)X +3652(bigword)X +3952(by)X +776 4812(repeating)N +1096(the)X +1215(following)X +1547(algorithm:)X +1901(if)X +1971(the)X +2090(current)X +2339(position)X +2617(is)X +2691(at)X +2770(the)X +2889(beginning)X +3230(of)X +3318(a)X +3374(bigword)X +3661(or)X +3748(the)X +3866(char-)X +776 4902(acter)N +955(at)X +1036(the)X +1157(current)X +1408(position)X +1688(cannot)X +1925(be)X +2024(part)X +2172(of)X +2262(a)X +2321(bigword,)X +2631(move)X +2832(to)X +2917(the)X +3038(\256rst)X +3185(character)X +3504(of)X +3594(the)X +3715(preceding)X +776 4992(bigword.)N +1105(Otherwise,)X +1477(move)X +1677(to)X +1761(the)X +1881(\256rst)X +2027(character)X +2345(of)X +2434(the)X +2554(bigword)X +2843(at)X +2923(the)X +3043(current)X +3293(position.)X +3612(If)X +3688(no)X +3790(preced-)X +776 5082(ing)N +908(bigword)X +1205(exists)X +1418(on)X +1529(the)X +1658(current)X +1917(line,)X +2088(move)X +2297(to)X +2390(the)X +2519(\256rst)X +2674(character)X +3001(of)X +3099(the)X +3228(last)X +3370(bigword)X +3668(on)X +3779(the)X +3908(\256rst)X +776 5172(preceding)N +1113(line)X +1253(that)X +1393(contains)X +1680(a)X +1736(bigword.)X +776 5352(The)N +3 f +921(B)X +1 f +994(command)X +1330(may)X +1488(be)X +1584(used)X +1751(as)X +1838(the)X +1956(motion)X +2202(component)X +2578(of)X +2665(other)X +3 f +2850(vi)X +1 f +2932(commands,)X +3319(in)X +3401(which)X +3617(case)X +3776(any)X +3912(text)X +776 5442(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 5622(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(word)X +2259(selected.)X +776 5712(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(character)X +1918(of)X +2005(the)X +2123(word)X +2308(selected.)X + +21 p +%%Page: 21 20 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-21)X +1 f +776 762(Options:)N +1136(None.)X +3 f +576 942([buffer])N +864([count])X +1129(C)X +1 f +776 1032(Change)N +1058(text)X +1215(from)X +1408(the)X +1543(current)X +1808(position)X +2102(to)X +2201(the)X +2336(end-of-line.)X +2770(If)X +7 f +2862(count)X +1 f +3140(is)X +3231(speci\256ed,)X +3574(the)X +3710(input)X +3912(text)X +776 1122(replaces)N +1060(from)X +1236(the)X +1354(current)X +1602(position)X +1879(to)X +1961(the)X +2079(end-of-line,)X +2476(plus)X +7 f +2629(count)X +2917(-)X +3013(1)X +1 f +3081(subsequent)X +3457(lines.)X +776 1302(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 1392(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 1482(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 1572(gin)N +1 f +1262(options.)X +3 f +576 1752([buffer])N +864(D)X +1 f +776 1842(Delete)N +1006(text)X +1146(from)X +1322(the)X +1440(current)X +1688(position)X +1965(to)X +2047(the)X +2165(end-of-line.)X +776 2022(It)N +845(is)X +918(not)X +1040(an)X +1136(error)X +1313(to)X +1395(execute)X +1661(the)X +3 f +1779(D)X +1 f +1857(command)X +2193(on)X +2293(an)X +2389(empty)X +2609(line.)X +776 2202(Line:)N +1136(Unchanged.)X +776 2292(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(character)X +1774(before)X +2000(the)X +2118(current)X +2367(character,)X +2704(or,)X +2812(column)X +3073(1)X +3134(if)X +3204(the)X +3323(cursor)X +3545(was)X +3691(on)X +3792(column)X +1136 2382(1.)N +776 2472(Options:)N +1136(None.)X +3 f +576 2652([count])N +841(E)X +1 f +776 2742(Move)N +983(forward)X +7 f +1258(count)X +1 f +1518(end-of-bigwords.)X +2113(Move)X +2320(the)X +2438(cursor)X +2659(forward)X +2935(to)X +3018(the)X +3137(end)X +3274(of)X +3362(a)X +3419(bigword)X +3707(by)X +3808(repeat-)X +776 2832(ing)N +906(the)X +1032(following)X +1371(algorithm:)X +1732(if)X +1809(the)X +1935(current)X +2191(position)X +2476(is)X +2557(the)X +2683(end)X +2827(of)X +2922(a)X +2986(bigword)X +3281(or)X +3376(the)X +3502(character)X +3826(at)X +3912(that)X +776 2922(position)N +1061(cannot)X +1303(be)X +1407(part)X +1560(of)X +1655(a)X +1719(bigword,)X +2034(move)X +2240(to)X +2331(the)X +2458(last)X +2598(character)X +2923(of)X +3019(the)X +3146(following)X +3486(bigword.)X +3822(Other-)X +776 3012(wise,)N +973(move)X +1181(to)X +1273(the)X +1401(last)X +1542(character)X +1868(of)X +1965(the)X +2093(bigword)X +2390(at)X +2477(the)X +2604(current)X +2861(position.)X +3187(If)X +3270(no)X +3379(succeeding)X +3765(bigword)X +776 3102(exists)N +984(on)X +1090(the)X +1214(current)X +1468(line,)X +1634(move)X +1838(to)X +1927(the)X +2052(last)X +2190(character)X +2513(of)X +2607(the)X +2732(\256rst)X +2883(bigword)X +3177(on)X +3284(the)X +3409(next)X +3574(following)X +3912(line)X +776 3192(that)N +916(contains)X +1203(a)X +1259(bigword.)X +776 3372(The)N +3 f +921(E)X +1 f +994(command)X +1330(may)X +1488(be)X +1584(used)X +1751(as)X +1838(the)X +1956(motion)X +2202(component)X +2578(of)X +2665(other)X +3 f +2850(vi)X +1 f +2932(commands,)X +3319(in)X +3401(which)X +3617(case)X +3776(any)X +3912(text)X +776 3462(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 3642(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(word)X +2259(selected.)X +776 3732(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(of)X +1992(the)X +2110(word)X +2295(selected.)X +776 3822(Options:)N +1136(None.)X +3 f +576 4002([count])N +841(F)X +910 0.3125(<character>)AX +1 f +776 4092(Search)N +7 f +1015(count)X +1 f +1275(times)X +1468(backward)X +1801(through)X +2070(the)X +2188(current)X +2436(line)X +2576(for)X +7 f +2690(<character>)X +1 f +(.)S +776 4272(The)N +3 f +921(F)X +1 f +990(command)X +1326(may)X +1484(be)X +1580(used)X +1747(as)X +1834(the)X +1952(motion)X +2198(component)X +2574(of)X +2661(other)X +3 f +2846(vi)X +1 f +2928(commands,)X +3315(in)X +3398(which)X +3615(case)X +3775(any)X +3912(text)X +776 4362(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 4542(Line:)N +1136(Unchanged.)X +776 4632(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458 0.3068(searched-for)AX +1881(character.)X +776 4722(Options:)N +1136(None.)X +3 f +576 4902([count])N +841(G)X +1 f +776 4992(Move)N +983(to)X +1065(line)X +7 f +1205(count)X +1 f +(,)S +1485(or)X +1572(the)X +1690(last)X +1821(line)X +1961(of)X +2048(the)X +2166(\256le)X +2288(if)X +7 f +2357(count)X +1 f +2617(not)X +2739(speci\256ed.)X +776 5172(The)N +3 f +924(G)X +1 f +1009(command)X +1348(is)X +1424(an)X +1523(absolute)X +1813(movement.)X +2214(The)X +3 f +2362(G)X +1 f +2447(command)X +2786(may)X +2947(be)X +3046(used)X +3216(as)X +3306(the)X +3427(motion)X +3676(component)X +776 5262(of)N +863(other)X +3 f +1048(vi)X +1 f +1130(commands,)X +1517(in)X +1599(which)X +1815(case)X +1974(any)X +2110(text)X +2250(copied)X +2484(into)X +2628(a)X +2684(buffer)X +2901(is)X +2974(line)X +3114(oriented.)X +776 5442(Line:)N +1136(Set)X +1258(to)X +7 f +1340(count)X +1 f +(,)S +1620(if)X +1689(speci\256ed,)X +2014(otherwise,)X +2366(the)X +2484(last)X +2615(line.)X +776 5532(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 5622(Options:)N +1136(None.)X + +22 p +%%Page: 22 21 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-22)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +576 762([count])N +841(H)X +1 f +776 852(Move)N +983(to)X +1065(the)X +1183(screen)X +1409(line)X +7 f +1549(count)X +1837(-)X +1933(1)X +1 f +2001(lines)X +2172(below)X +2388(the)X +2506(top)X +2628(of)X +2715(the)X +2833(screen.)X +776 1032(The)N +3 f +924(H)X +1 f +1009(command)X +1348(is)X +1424(an)X +1523(absolute)X +1813(movement.)X +2214(The)X +3 f +2362(H)X +1 f +2447(command)X +2786(may)X +2947(be)X +3046(used)X +3216(as)X +3306(the)X +3427(motion)X +3676(component)X +776 1122(of)N +863(other)X +3 f +1048(vi)X +1 f +1130(commands,)X +1517(in)X +1599(which)X +1815(case)X +1974(any)X +2110(text)X +2250(copied)X +2484(into)X +2628(a)X +2684(buffer)X +2901(is)X +2974(line)X +3114(oriented.)X +776 1302(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +7 f +1598(count)X +1886(-)X +1982(1)X +1 f +2050(lines)X +2221(below)X +2437(the)X +2555(top)X +2677(of)X +2764(the)X +2882(screen.)X +776 1392(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2 f +2441(screen)X +1 f +2671(line.)X +776 1482(Options:)N +1136(None.)X +3 f +576 1662([count])N +841(I)X +1 f +776 1752(Enter)N +971(input)X +1156(mode,)X +1375(inserting)X +1676(the)X +1795(text)X +1936(at)X +2015(the)X +2134(beginning)X +2475(of)X +2564(the)X +2684(line.)X +2866(If)X +7 f +2942(count)X +1 f +3204(is)X +3279(speci\256ed,)X +3606(the)X +3726(text)X +3868(input)X +776 1842(is)N +849(repeatedly)X +1204(input)X +7 f +1388(count)X +1676(-)X +1772(1)X +1 f +1840(more)X +2025(times.)X +776 2022(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 2112(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 2202(Options:)N +1136(None.)X +3 f +576 2382([count])N +841(J)X +1 f +776 2472(Join)N +929(lines.)X +1140(If)X +7 f +1214(count)X +1 f +1474(is)X +1547(speci\256ed,)X +7 f +1872(count)X +1 f +2132(lines)X +2303(are)X +2422(joined;)X +2664(a)X +2720(minimum)X +3050(of)X +3137(two)X +3277(lines)X +3448(are)X +3568(always)X +3812(joined,)X +776 2562(regardless)N +1122(of)X +1209(the)X +1327(value)X +1521(of)X +7 f +1608(count)X +1 f +(.)S +776 2742(If)N +859(the)X +986(current)X +1244(line)X +1394(ends)X +1571(with)X +1743(a)X +1809(whitespace)X +2196(character,)X +2542(all)X +2652(whitespace)X +3039(is)X +3122(stripped)X +3410(from)X +3596(the)X +3724(next)X +3892(line.)X +776 2832(Otherwise,)N +1148(if)X +1219(the)X +1338(next)X +1497(line)X +1638(starts)X +1828(with)X +1991(a)X +2048(open)X +2225(parenthesis)X +2607(\(``)X +7 f +2688(\()X +1 f +(''\))S +2838(do)X +2939(nothing.)X +3244(Otherwise,)X +3615(if)X +3685(the)X +3804(current)X +776 2922(line)N +917(ends)X +1086(with)X +1250(a)X +1308(question)X +1601(mark)X +1788(\(``)X +7 f +1869(?)X +1 f +(''\),)S +2040(period)X +2267(\(``)X +7 f +2348(.)X +1 f +(''\))S +2519(or)X +2608(exclamation)X +3022(point)X +3208(\(``)X +7 f +3289(!)X +1 f +(''\),)S +3460(insert)X +3660(two)X +3802(spaces.)X +776 3012(Otherwise,)N +1146(insert)X +1344(a)X +1400(single)X +1611(space.)X +776 3192(It)N +845(is)X +918(not)X +1040(an)X +1136(error)X +1313(to)X +1395(join)X +1539(lines)X +1710(past)X +1859(the)X +1977(end)X +2113(of)X +2200(the)X +2318(\256le,)X +2460(i.e.)X +2578(lines)X +2749(that)X +2889(do)X +2989(not)X +3111(exist.)X +776 3372(Line:)N +1136(Unchanged.)X +776 3462(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(character)X +1774(after)X +1942(the)X +2060(last)X +2191(character)X +2507(of)X +2594(the)X +2712(next-to-last)X +3097(joined)X +3317(line.)X +776 3552(Options:)N +1136(None.)X +3 f +576 3732([count])N +841(L)X +1 f +776 3822(Move)N +983(to)X +1065(the)X +1183(screen)X +1409(line)X +7 f +1549(count)X +1837(-)X +1933(1)X +1 f +2001(lines)X +2172(above)X +2384(the)X +2502(bottom)X +2748(of)X +2835(the)X +2953(screen.)X +776 4002(The)N +3 f +925(L)X +1 f +1002(command)X +1342(is)X +1419(an)X +1519(absolute)X +1810(movement.)X +2212(The)X +3 f +2361(L)X +1 f +2438(command)X +2778(may)X +2940(be)X +3040(used)X +3211(as)X +3302(the)X +3425(motion)X +3676(component)X +776 4092(of)N +863(other)X +3 f +1048(vi)X +1 f +1130(commands,)X +1517(in)X +1599(which)X +1815(case)X +1974(any)X +2110(text)X +2250(copied)X +2484(into)X +2628(a)X +2684(buffer)X +2901(is)X +2974(line)X +3114(oriented.)X +776 4272(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +7 f +1598(count)X +1886(-)X +1982(1)X +1 f +2050(lines)X +2221(above)X +2433(the)X +2551(bottom)X +2797(of)X +2884(the)X +3002(screen.)X +776 4362(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2 f +2441(screen)X +1 f +2671(line.)X +776 4452(Options:)N +1136(None.)X +3 f +596 4632(M)N +1 f +776 4722(Move)N +983(to)X +1065(the)X +1183(screen)X +1409(line)X +1549(in)X +1631(the)X +1749(middle)X +1991(of)X +2078(the)X +2196(screen.)X +776 4902(The)N +3 f +922(M)X +1 f +1019(command)X +1356(is)X +1430(an)X +1527(absolute)X +1815(movement.)X +2214(The)X +3 f +2360(M)X +1 f +2457(command)X +2794(may)X +2953(be)X +3050(used)X +3219(as)X +3308(the)X +3428(motion)X +3676(component)X +776 4992(of)N +863(other)X +3 f +1048(vi)X +1 f +1130(commands,)X +1517(in)X +1599(which)X +1815(case)X +1974(any)X +2110(text)X +2250(copied)X +2484(into)X +2628(a)X +2684(buffer)X +2901(is)X +2974(line)X +3114(oriented.)X +776 5172(Historically,)N +1194(any)X +7 f +1330(count)X +1 f +1590(speci\256ed)X +1895(to)X +1977(the)X +3 f +2095(M)X +1 f +2191(command)X +2527(was)X +2672(ignored.)X +776 5352(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(in)X +1680(the)X +1798(middle)X +2040(of)X +2127(the)X +2245(screen.)X +776 5442(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2 f +2441(screen)X +1 f +2671(line.)X +776 5532(Options:)N +1136(None.)X +3 f +576 5712([count])N +841(O)X +1 f +776 5802(Enter)N +970(input)X +1154(mode,)X +1372(appending)X +1726(text)X +1866(in)X +1948(a)X +2004(new)X +2158(line)X +2298(above)X +2510(the)X +2628(current)X +2876(line.)X +3057(If)X +7 f +3132(count)X +1 f +3393(is)X +3467(speci\256ed,)X +3793(the)X +3912(text)X + +23 p +%%Page: 23 22 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-23)X +1 f +776 762(input)N +960(is)X +1033(repeatedly)X +1388(input)X +7 f +1572(count)X +1860(-)X +1956(1)X +1 f +2024(more)X +2209(times.)X +776 942(Historically,)N +1194(any)X +7 f +1330(count)X +1 f +1590(speci\256ed)X +1895(to)X +1977(the)X +3 f +2095(O)X +1 f +2177(command)X +2513(was)X +2658(ignored.)X +776 1122(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 1212(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 1302(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 1392(gin)N +1 f +1262(options.)X +3 f +576 1572([buffer])N +864(P)X +1 f +776 1662(Insert)N +980(text)X +1121(from)X +1298(a)X +1355(buffer.)X +1613(Text)X +1782(from)X +1960(the)X +2080(buffer)X +2299(\(the)X +2446(unnamed)X +2762(buffer)X +2981(by)X +3083(default\))X +3355(is)X +3430(inserted)X +3706(before)X +3934(the)X +776 1752(current)N +1024(column)X +1284(or,)X +1391(if)X +1460(the)X +1578(buffer)X +1795(is)X +1868(line)X +2008(oriented,)X +2311(before)X +2537(the)X +2655(current)X +2903(line.)X +776 1932(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(lowest)X +1687(numbered)X +2028(line)X +2168(insert,)X +2386(if)X +2455(the)X +2573(buffer)X +2790(is)X +2863(line)X +3003(oriented,)X +3306(otherwise)X +3638(unchanged.)X +776 2022(Column:)N +1136(Set)X +1261(to)X +1346(the)X +1467(\256rst)X +1614(nonblank)X +1935(character)X +2254(of)X +2344(the)X +2465(appended)X +2796(text,)X +2959(if)X +3032(the)X +3154(buffer)X +3375(is)X +3452(line)X +3596(oriented,)X +3903(oth-)X +1136 2112(erwise,)N +1386(the)X +1504(last)X +1635(character)X +1951(of)X +2038(the)X +2156(appended)X +2484(text.)X +776 2202(Options:)N +1136(None.)X +3 f +576 2382(Q)N +1 f +776 2472(Exit)N +3 f +929(vi)X +1 f +1011(\(or)X +1125(visual\))X +1363(mode)X +1561(and)X +1697(switch)X +1926(to)X +3 f +2008(ex)X +1 f +2104(mode.)X +776 2652(Line:)N +1136(Unchanged.)X +776 2742(Column:)N +1136(No)X +1254(longer)X +1479(relevant.)X +776 2832(Options:)N +1136(None.)X +3 f +576 3012([count])N +841(R)X +1 f +776 3102(Enter)N +971(input)X +1156(mode,)X +1375(replacing)X +1695(the)X +1814(characters)X +2162(in)X +2245(the)X +2364(current)X +2613(line.)X +2794(If)X +7 f +2869(count)X +1 f +3130(is)X +3204(speci\256ed,)X +3531(the)X +3651(text)X +3793(input)X +3979(is)X +776 3192(repeatedly)N +1131(input)X +7 f +1315(count)X +1603(-)X +1699(1)X +1 f +1767(more)X +1952(times.)X +776 3372(If)N +855(the)X +978(end)X +1119(of)X +1211(the)X +1334(current)X +1587(line)X +1732(is)X +1810(reached,)X +2106(no)X +2211(more)X +2401(characters)X +2753(are)X +2877(replaced)X +3176(and)X +3318(any)X +3460(further)X +3705(characters)X +776 3462(input)N +960(are)X +1079(appended)X +1407(to)X +1489(the)X +1607(line.)X +776 3642(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 3732(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 3822(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 3912(gin)N +1 f +1262(options.)X +3 f +576 4092([buffer])N +864([count])X +1129(S)X +1 f +776 4182(Substitute)N +7 f +1115(count)X +1 f +1375(lines.)X +776 4362(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 4452(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 4542(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 4632(gin)N +1 f +1262(options.)X +3 f +576 4812([count])N +841(T)X +914 0.3125(<character>)AX +1 f +776 4902(Search)N +1014(backward,)X +7 f +1366(count)X +1 f +1625(times,)X +1837(through)X +2105(the)X +2222(current)X +2469(line)X +2608(for)X +2721(the)X +2838(character)X +2 f +3153(after)X +1 f +3323(the)X +3440(speci\256ed)X +7 f +3744(<char-)X +776 4992(acter>)N +1 f +(.)S +776 5172(The)N +3 f +921(T)X +1 f +994(command)X +1330(may)X +1488(be)X +1584(used)X +1751(as)X +1838(the)X +1956(motion)X +2202(component)X +2578(of)X +2665(other)X +3 f +2850(vi)X +1 f +2932(commands,)X +3319(in)X +3401(which)X +3617(case)X +3776(any)X +3912(text)X +776 5262(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 5442(Line:)N +1136(Unchanged.)X +776 5532(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(character)X +2 f +1774(after)X +1 f +1945(the)X +2063 0.3068(searched-for)AX +2486(character.)X +776 5622(Options:)N +1136(None.)X + +24 p +%%Page: 24 23 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-24)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +576 762(U)N +1 f +776 852(Restore)N +1041(the)X +1159(current)X +1407(line)X +1547(to)X +1629(its)X +1724(state)X +1891(before)X +2117(the)X +2235(cursor)X +2456(last)X +2587(moved)X +2825(to)X +2907(it.)X +776 1032(Line:)N +1136(Unchanged.)X +776 1122(Column:)N +1136(The)X +1281(\256rst)X +1425(character)X +1741(in)X +1823(the)X +1941(line.)X +776 1212(Options:)N +1136(None.)X +3 f +576 1392([count])N +841(W)X +1 f +776 1482(Move)N +985(forward)X +7 f +1262(count)X +1 f +1524(bigwords.)X +1884(Move)X +2094(the)X +2215(cursor)X +2439(forward)X +2717(to)X +2802(the)X +2923(beginning)X +3266(of)X +3356(a)X +3415(bigword)X +3705(by)X +3808(repeat-)X +776 1572(ing)N +903(the)X +1026(following)X +1362(algorithm:)X +1720(if)X +1794(the)X +1917(current)X +2170(position)X +2452(is)X +2530(within)X +2759(a)X +2820(bigword)X +3112(or)X +3204(the)X +3326(character)X +3646(at)X +3728(that)X +3872(posi-)X +776 1662(tion)N +926(cannot)X +1166(be)X +1268(part)X +1419(of)X +1512(a)X +1574(bigword,)X +1887(move)X +2091(to)X +2179(the)X +2303(\256rst)X +2453(character)X +2775(of)X +2868(the)X +2992(next)X +3156(bigword.)X +3489(If)X +3569(no)X +3676(subsequent)X +776 1752(bigword)N +1066(exists)X +1271(on)X +1374(the)X +1495(current)X +1746(line,)X +1909(move)X +2110(to)X +2195(the)X +2316(\256rst)X +2463(character)X +2782(of)X +2872(the)X +2993(\256rst)X +3139(bigword)X +3428(on)X +3530(the)X +3650(\256rst)X +3796(follow-)X +776 1842(ing)N +898(line)X +1038(that)X +1178(contains)X +1465(a)X +1521(bigword.)X +776 2022(The)N +3 f +927(W)X +1 f +1033(command)X +1375(may)X +1539(be)X +1641(used)X +1814(as)X +1908(the)X +2033(motion)X +2286(component)X +2669(of)X +2763(other)X +3 f +2955(vi)X +1 f +3044(commands,)X +3438(in)X +3527(which)X +3750(case)X +3916(any)X +776 2112(text)N +916(copied)X +1150(into)X +1294(a)X +1350(buffer)X +1567(is)X +1640(character)X +1956(oriented.)X +776 2292(Line:)N +1136(The)X +1281(line)X +1421(containing)X +1779(the)X +1897(word)X +2082(selected.)X +776 2382(Column:)N +1136(The)X +1281(\256rst)X +1425(character)X +1741(of)X +1828(the)X +1946(word)X +2131(selected.)X +776 2472(Options:)N +1136(None.)X +3 f +576 2652([buffer])N +864([count])X +1129(X)X +1 f +776 2742(Delete)N +7 f +1008(count)X +1 f +1270(characters)X +1619(before)X +1847(the)X +1967(cursor.)X +2230(If)X +2306(the)X +2426(number)X +2693(of)X +2782(characters)X +3132(to)X +3217(be)X +3316(deleted)X +3571(is)X +3647(greater)X +3894(than)X +776 2832(or)N +874(equal)X +1079(to)X +1172(the)X +1301(number)X +1577(of)X +1675(characters)X +2033(to)X +2126(the)X +2255(beginning)X +2606(of)X +2704(the)X +2833(line,)X +3004(all)X +3115(of)X +3213(the)X +3341(characters)X +3698(before)X +3934(the)X +776 2922(current)N +1024(cursor)X +1245(position,)X +1542(to)X +1624(the)X +1742(beginning)X +2082(of)X +2169(the)X +2287(line,)X +2447(are)X +2566(deleted.)X +776 3102(Line:)N +1136(Unchanged.)X +776 3192(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(current)X +1706(character)X +2022(minus)X +7 f +2237(count)X +1 f +(,)S +2518(or)X +2606(the)X +2725(\256rst)X +2870(character)X +3187(if)X +3257(count)X +3456(is)X +3530(greater)X +3775(than)X +3934(the)X +1136 3282(number)N +1401(of)X +1488(characters)X +1835(in)X +1917(the)X +2035(line)X +2175(before)X +2401(the)X +2519(cursor.)X +776 3372(Options:)N +1136(None.)X +3 f +576 3552([buffer])N +864([count])X +1129(Y)X +1 f +776 3642(Copy)N +969(\(or)X +1083(``yank''\))X +7 f +1394(count)X +1 f +1654(lines)X +1825(into)X +1969(the)X +2087(speci\256ed)X +2392(buffer.)X +776 3822(Line:)N +1136(Unchanged.)X +776 3912(Column:)N +1136(Unchanged.)X +776 4002(Options:)N +1136(None.)X +3 f +576 4182(ZZ)N +1 f +776 4272(Write)N +979(the)X +1097(\256le)X +1219(and)X +1356(exit)X +3 f +1497(vi)X +1 f +1559(.)X +1620(The)X +1766(\256le)X +1889(is)X +1963(only)X +2126(written)X +2374(if)X +2444(it)X +2509(has)X +2637(been)X +2810(modi\256ed)X +3115(since)X +3301(the)X +3420(last)X +3552(complete)X +3867(write)X +776 4362(of)N +863(the)X +981(\256le)X +1103(to)X +1185(any)X +1321(\256le.)X +776 4542(The)N +3 f +922(ZZ)X +1 f +1050(command)X +1388(will)X +1534(exit)X +1676(the)X +1796(editor)X +2005(after)X +2175(writing)X +2428(the)X +2548(\256le,)X +2692(if)X +2763(there)X +2946(are)X +3067(no)X +3169(further)X +3410(\256les)X +3565(to)X +3649(edit.)X +3831(Enter-)X +776 4632(ing)N +901(two)X +1044(``quit'')X +1299(commands)X +1669(\(i.e.)X +3 f +1837(wq)X +1 f +1939(,)X +3 f +1981(quit)X +1 f +2118(,)X +3 f +2160(xit)X +1 f +2271(or)X +3 f +2360(ZZ)X +1 f +2466(\))X +2515(in)X +2599(a)X +2657(row)X +2804(will)X +2950(override)X +3240(this)X +3377(check)X +3587(and)X +3725(the)X +3845(editor)X +776 4722(will)N +920(exit,)X +1080(ignoring)X +1371(any)X +1507(\256les)X +1660(that)X +1800(have)X +1972(not)X +2094(yet)X +2212(been)X +2384(edited.)X +776 4902(Line:)N +1136(Unchanged.)X +776 4992(Column:)N +1136(Unchanged.)X +776 5082(Options:)N +1136(None.)X +3 f +576 5262([count])N +841([[)X +1 f +776 5352(Back)N +961(up)X +7 f +1061(count)X +1 f +1321(section)X +1568(boundaries.)X +776 5532(The)N +3 f +925([[)X +1 f +1003(command)X +1343(is)X +1420(an)X +1520(absolute)X +1811(movement.)X +2213(The)X +3 f +2362([[)X +1 f +2440(command)X +2780(may)X +2942(be)X +3042(used)X +3213(as)X +3304(the)X +3426(motion)X +3676(component)X +776 5622(of)N +871(other)X +3 f +1064(vi)X +1 f +1153(commands,)X +1547(in)X +1636(which)X +1859(case)X +2025(any)X +2168(text)X +2315(copied)X +2556(into)X +2707(a)X +2770(buffer)X +2994(is)X +3074(character)X +3397(oriented,)X +3707(unless)X +3934(the)X +776 5712(starting)N +1036(position)X +1313(is)X +1386(column)X +1646(0,)X +1726(in)X +1808(which)X +2024(case)X +2183(it)X +2247(is)X +2320(line)X +2460(oriented.)X + +25 p +%%Page: 25 24 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-25)X +1 f +776 762(This)N +938(is)X +1011(an)X +1107(error)X +1284(if)X +1353(the)X +1471(movement)X +1829(is)X +1902(past)X +2051(the)X +2169(beginning)X +2509(of)X +2596(the)X +2714(\256le.)X +776 942(Line:)N +1136(Set)X +1261(to)X +1346(the)X +1467(previous)X +1766(line)X +1909(that)X +2052(is)X +7 f +2128(count)X +1 f +2391(section)X +2641(boundaries)X +3016(back,)X +3212(or)X +3303(the)X +3425(\256rst)X +3573(line)X +3717(of)X +3808(the)X +3930(\256le)X +1136 1032(if)N +1205(no)X +1305(more)X +1490(section)X +1737(boundaries)X +2109(exist)X +2280(preceding)X +2617(the)X +2735(current)X +2983(line.)X +776 1122(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 1212(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(sections)X +1 f +1943(option.)X +3 f +576 1392([count])N +841(]])X +1 f +776 1482(Move)N +983(forward)X +7 f +1258(count)X +1 f +1518(section)X +1765(boundaries.)X +776 1662(The)N +3 f +925(]])X +1 f +1003(command)X +1343(is)X +1420(an)X +1520(absolute)X +1811(movement.)X +2213(The)X +3 f +2362(]])X +1 f +2440(command)X +2780(may)X +2942(be)X +3042(used)X +3213(as)X +3304(the)X +3426(motion)X +3676(component)X +776 1752(of)N +871(other)X +3 f +1064(vi)X +1 f +1153(commands,)X +1547(in)X +1636(which)X +1859(case)X +2025(any)X +2168(text)X +2315(copied)X +2556(into)X +2707(a)X +2770(buffer)X +2994(is)X +3074(character)X +3397(oriented,)X +3707(unless)X +3934(the)X +776 1842(starting)N +1036(position)X +1313(is)X +1386(column)X +1646(0,)X +1726(in)X +1808(which)X +2024(case)X +2183(it)X +2247(is)X +2320(line)X +2460(oriented.)X +776 2022(This)N +938(is)X +1011(an)X +1107(error)X +1284(if)X +1353(the)X +1471(movement)X +1829(is)X +1902(past)X +2051(the)X +2169(end)X +2305(of)X +2392(the)X +2510(\256le.)X +776 2202(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(that)X +1738(is)X +7 f +1811(count)X +1 f +2072(section)X +2320(boundaries)X +2693(forward,)X +2989(or)X +3077(to)X +3160(the)X +3279(last)X +3411(line)X +3552(of)X +3640(the)X +3759(\256le)X +3882(if)X +3952(no)X +1136 2292(more)N +1321(section)X +1568(boundaries)X +1940(exist)X +2111(following)X +2442(the)X +2560(current)X +2808(line.)X +776 2382(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 2472(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(sections)X +1 f +1943(option.)X +3 f +576 2652(\303)N +1 f +776 2742(Move)N +983(to)X +1065(\256rst)X +1209(nonblank)X +1527(character)X +1843(on)X +1943(the)X +2061(current)X +2309(line.)X +776 2922(The)N +3 f +922(\303)X +1 f +970(command)X +1307(may)X +1466(be)X +1563(used)X +1731(as)X +1819(the)X +1938(motion)X +2185(component)X +2562(of)X +2651(other)X +3 f +2838(vi)X +1 f +2922(commands,)X +3311(in)X +3395(which)X +3613(case)X +3774(any)X +3912(text)X +776 3012(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 3192(Line:)N +1136(Unchanged.)X +776 3282(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(of)X +2323(the)X +2441(current)X +2689(line.)X +776 3372(Options:)N +1136(None.)X +3 f +576 3552([count])N +841(_)X +1 f +776 3642(Move)N +985(down)X +7 f +1185(count)X +1475(-)X +1573(1)X +1 f +1643(lines,)X +1836(to)X +1920(the)X +2040(\256rst)X +2186(nonblank)X +2506(character.)X +2864(The)X +3 f +3012(_)X +1 f +3075(command)X +3414(may)X +3575(be)X +3674(used)X +3844(as)X +3934(the)X +776 3732(motion)N +1022(component)X +1398(of)X +1485(other)X +3 f +1670(vi)X +1 f +1752(commands,)X +2139(in)X +2221(which)X +2437(case)X +2596(any)X +2732(text)X +2872(copied)X +3106(into)X +3250(a)X +3306(buffer)X +3523(is)X +3596(line)X +3736(oriented.)X +776 3912(It)N +845(is)X +918(not)X +1040(an)X +1136(error)X +1313(to)X +1395(execute)X +1661(the)X +3 f +1779(_)X +1 f +1839(command)X +2175(when)X +2369(the)X +2487(cursor)X +2708(is)X +2781(on)X +2881(the)X +2999(\256rst)X +3143(character)X +3459(in)X +3541(the)X +3659(line.)X +776 4092(Line:)N +1136(The)X +1281(current)X +1529(line)X +1669(plus)X +7 f +1822(count)X +2110(-)X +2206(1)X +1 f +(.)S +776 4182(Column:)N +1136(The)X +1281(\256rst)X +1425(nonblank)X +1743(character)X +2059(in)X +2141(the)X +2259(line.)X +776 4272(Options:)N +1136(None.)X +3 f +576 4452([count])N +841(a)X +1 f +776 4542(Enter)N +971(input)X +1156(mode,)X +1375(appending)X +1730(the)X +1850(text)X +1992(after)X +2162(the)X +2282(cursor.)X +2545(If)X +7 f +2621(count)X +1 f +2883(is)X +2958(speci\256ed,)X +3285(the)X +3405(text)X +3547(input)X +3733(is)X +3808(repeat-)X +776 4632(edly)N +934(input)X +7 f +1118(count)X +1406(-)X +1502(1)X +1 f +1570(more)X +1755(times.)X +776 4812(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 4902(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 4992(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 5082(gin)N +1 f +1262(options.)X +3 f +576 5262([count])N +841(b)X +1 f +776 5352(Move)N +986(backward)X +7 f +1322(count)X +1 f +1585(words.)X +1844(Move)X +2054(the)X +2175(cursor)X +2400(backward)X +2737(to)X +2823(the)X +2945(beginning)X +3289(of)X +3380(a)X +3440(word)X +3629(by)X +3733(repeating)X +776 5442(the)N +895(following)X +1227(algorithm:)X +1581(if)X +1651(the)X +1770(current)X +2018(position)X +2295(is)X +2368(at)X +2446(the)X +2564(beginning)X +2904(of)X +2991(a)X +3047(word,)X +3252(move)X +3450(to)X +3532(the)X +3650(\256rst)X +3794(charac-)X +776 5532(ter)N +883(of)X +972(the)X +1092(preceding)X +1431(word.)X +1658(Otherwise,)X +2030(the)X +2150(current)X +2400(position)X +2679(moves)X +2910(to)X +2994(the)X +3114(\256rst)X +3260(character)X +3578(of)X +3667(the)X +3787(word)X +3974(at)X +776 5622(the)N +895(current)X +1144(position.)X +1462(If)X +1537(no)X +1638(preceding)X +1976(word)X +2161(exists)X +2363(on)X +2463(the)X +2581(current)X +2829(line,)X +2989(move)X +3187(to)X +3269(the)X +3387(\256rst)X +3531(character)X +3847(of)X +3934(the)X +776 5712(last)N +907(word)X +1092(on)X +1192(the)X +1310(\256rst)X +1454(preceding)X +1791(line)X +1931(that)X +2071(contains)X +2358(a)X +2414(word.)X + +26 p +%%Page: 26 25 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-26)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +1 f +776 762(The)N +3 f +921(b)X +1 f +985(command)X +1321(may)X +1479(be)X +1575(used)X +1742(as)X +1829(the)X +1947(motion)X +2193(component)X +2570(of)X +2658(other)X +3 f +2844(vi)X +1 f +2927(commands,)X +3315(in)X +3398(which)X +3615(case)X +3775(any)X +3912(text)X +776 852(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 1032(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(word)X +2259(selected.)X +776 1122(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(character)X +1918(of)X +2005(the)X +2123(word)X +2308(selected.)X +776 1212(Options:)N +1136(None.)X +3 f +576 1392([buffer])N +864([count])X +1129(c)X +1185(motion)X +1 f +776 1482(Change)N +1041(a)X +1097(region)X +1322(of)X +1409(text.)X +1589(If)X +1663(only)X +1825(part)X +1970(of)X +2057(a)X +2113(single)X +2324(line)X +2464(is)X +2537(affected,)X +2838(then)X +2997(the)X +3116(last)X +3248(character)X +3565(being)X +3764(changed)X +776 1572(is)N +849(marked)X +1110(with)X +1272(a)X +1328(``)X +7 f +1382($)X +1 f +(''.)S +1544(Otherwise,)X +1914(the)X +2032(region)X +2257(of)X +2344(text)X +2484(is)X +2557(deleted,)X +2829(and)X +2965(input)X +3149(mode)X +3347(is)X +3420(entered.)X +776 1752(If)N +7 f +850(count)X +1 f +1110(is)X +1183(speci\256ed,)X +1508(it)X +1572(is)X +1645(applied)X +1901(to)X +1983(the)X +7 f +2101(motion)X +1 f +(.)S +776 1932(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 2022(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 2112(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 2202(gin)N +1 f +1262(options.)X +3 f +576 2382([buffer])N +864([count])X +1129(d)X +1193(motion)X +1 f +776 2472(Delete)N +1006(a)X +1062(region)X +1287(of)X +1374(text.)X +1554(If)X +7 f +1628(count)X +1 f +1888(is)X +1961(speci\256ed,)X +2286(it)X +2350(is)X +2423(applied)X +2679(to)X +2761(the)X +7 f +2879(motion)X +1 f +(.)S +776 2652(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(where)X +1815(the)X +1933(region)X +2158(starts.)X +776 2742(Column:)N +1136(Set)X +1261(to)X +1346(the)X +1467(\256rst)X +1615(character)X +1935(in)X +2021(the)X +2143(line)X +2287(after)X +2459(the)X +2581(last)X +2716(character)X +3036(in)X +3122(the)X +3244(region.)X +3513(If)X +3591(no)X +3695(such)X +3866(char-)X +1136 2832(acter)N +1313(exists,)X +1535(set)X +1644(to)X +1726(the)X +1844(last)X +1975(character)X +2291(before)X +2517(the)X +2635(region.)X +776 2922(Options:)N +1136(None.)X +3 f +576 3102([count])N +841(e)X +1 f +776 3192(Move)N +984(forward)X +7 f +1260(count)X +1 f +1521(end-of-words.)X +2015(Move)X +2223(the)X +2342(cursor)X +2564(forward)X +2840(to)X +2923(the)X +3042(end)X +3179(of)X +3267(a)X +3324(word)X +3511(by)X +3613(repeating)X +3934(the)X +776 3282(following)N +1108(algorithm:)X +1462(if)X +1532(the)X +1651(current)X +1900(position)X +2178(is)X +2252(the)X +2371(end)X +2508(of)X +2596(a)X +2653(word,)X +2859(move)X +3058(to)X +3141(the)X +3260(last)X +3392(character)X +3709(of)X +3797(the)X +3916(fol-)X +776 3372(lowing)N +1034(word.)X +1275(Otherwise,)X +1661(move)X +1876(to)X +1975(the)X +2110(last)X +2258(character)X +2591(of)X +2695(the)X +2830(word)X +3032(at)X +3127(the)X +3262(current)X +3527(position.)X +3861(If)X +3952(no)X +776 3462(succeeding)N +1161(word)X +1354(exists)X +1564(on)X +1672(the)X +1798(current)X +2053(line,)X +2220(move)X +2425(to)X +2514(the)X +2639(last)X +2777(character)X +3100(of)X +3194(the)X +3319(\256rst)X +3470(word)X +3662(on)X +3769(the)X +3894(next)X +776 3552(following)N +1107(line)X +1247(that)X +1387(contains)X +1674(a)X +1730(word.)X +776 3732(The)N +3 f +921(e)X +1 f +978(command)X +1315(may)X +1474(be)X +1571(used)X +1739(as)X +1827(the)X +1946(motion)X +2193(component)X +2570(of)X +2658(other)X +3 f +2844(vi)X +1 f +2927(commands,)X +3315(in)X +3398(which)X +3615(case)X +3775(any)X +3912(text)X +776 3822(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 4002(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(word)X +2259(selected.)X +776 4092(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(of)X +1992(the)X +2110(word)X +2295(selected.)X +776 4182(Options:)N +1136(None.)X +3 f +576 4362([count])N +841(f)X +888 0.3125(<character>)AX +1 f +776 4452(Search)N +1015(forward,)X +7 f +1310(count)X +1 f +1570(times,)X +1783(through)X +2052(the)X +2170(rest)X +2306(of)X +2393(the)X +2511(current)X +2759(line)X +2899(for)X +7 f +3013(<character>)X +1 f +(.)S +776 4632(The)N +3 f +922(f)X +1 f +970(command)X +1307(may)X +1466(be)X +1563(used)X +1731(as)X +1819(the)X +1938(motion)X +2185(component)X +2562(of)X +2651(other)X +3 f +2838(vi)X +1 f +2922(commands,)X +3311(in)X +3395(which)X +3613(case)X +3774(any)X +3912(text)X +776 4722(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 4902(Line:)N +1136(Unchanged.)X +776 4992(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458 0.3068(searched-for)AX +1881(character.)X +776 5082(Options:)N +1136(None.)X +3 f +576 5262([count])N +841(i)X +1 f +776 5352(Enter)N +971(input)X +1156(mode,)X +1375(inserting)X +1676(the)X +1795(text)X +1936(before)X +2163(the)X +2282(cursor.)X +2545(If)X +7 f +2621(count)X +1 f +2883(is)X +2958(speci\256ed,)X +3285(the)X +3405(text)X +3547(input)X +3733(is)X +3808(repeat-)X +776 5442(edly)N +934(input)X +7 f +1118(count)X +1406(-)X +1502(1)X +1 f +1570(more)X +1755(times.)X +776 5622(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 5712(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X + +27 p +%%Page: 27 26 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-27)X +1 f +776 762(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 852(gin)N +1 f +1262(options.)X +3 f +576 1032(m)N +663 0.3125(<character>)AX +1 f +776 1122(Save)N +956(the)X +1078(current)X +1330(context)X +1590(\(line)X +1761(and)X +1902(column\))X +2194(as)X +7 f +2286(<character>)X +1 f +(.)S +2879(The)X +3029(exact)X +3224(position)X +3506(is)X +3584(referred)X +3865(to)X +3952(by)X +776 1212(``)N +7 f +830(`<character>)X +1 f +(''.)S +1520(The)X +1665(line)X +1805(is)X +1878(referred)X +2154(to)X +2236(by)X +2336(``)X +7 f +2390('<character>)X +1 f +(''.)S +776 1392(Historically,)N +7 f +1205(<character>)X +1 f +1764(was)X +1920(restricted)X +2250(to)X +2343(lower-case)X +2723(letters)X +2950(only,)X +3 f +3143(nvi)X +1 f +3280(permits)X +3551(the)X +3680(use)X +3818(of)X +3916(any)X +776 1482(character.)N +776 1662(Line:)N +1136(Unchanged.)X +776 1752(Column:)N +1136(Unchanged.)X +776 1842(Options:)N +1136(None.)X +3 f +576 2022([count])N +841(o)X +1 f +776 2112(Enter)N +970(input)X +1154(mode,)X +1372(appending)X +1727(text)X +1868(in)X +1951(a)X +2008(new)X +2163(line)X +2304(under)X +2508(the)X +2627(current)X +2876(line.)X +3057(If)X +7 f +3132(count)X +1 f +3393(is)X +3467(speci\256ed,)X +3793(the)X +3912(text)X +776 2202(input)N +960(is)X +1033(repeatedly)X +1388(input)X +7 f +1572(count)X +1860(-)X +1956(1)X +1 f +2024(more)X +2209(times.)X +776 2382(Historically,)N +1194(any)X +7 f +1330(count)X +1 f +1590(speci\256ed)X +1895(to)X +1977(the)X +3 f +2095(o)X +1 f +2155(command)X +2491(was)X +2636(ignored.)X +776 2562(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 2652(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 2742(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 2832(gin)N +1 f +1262(options.)X +3 f +576 3012([buffer])N +864(p)X +1 f +776 3102(Append)N +1055(text)X +1200(from)X +1381(a)X +1442(buffer.)X +1704(Text)X +1876(from)X +2057(the)X +2180(buffer)X +2402(\(the)X +2552(unnamed)X +2871(buffer)X +3093(by)X +3198(default\))X +3473(is)X +3551(appended)X +3884(after)X +776 3192(the)N +894(current)X +1142(column)X +1402(or,)X +1509(if)X +1578(the)X +1696(buffer)X +1913(is)X +1986(line)X +2126(oriented,)X +2429(after)X +2597(the)X +2715(current)X +2963(line.)X +776 3372(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(line)X +1742(appended,)X +2090(if)X +2159(the)X +2277(buffer)X +2494(is)X +2567(line)X +2707(oriented,)X +3010(otherwise)X +3342(unchanged.)X +776 3462(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2237(of)X +2325(the)X +2444(appended)X +2773(text)X +2914(if)X +2984(the)X +3103(buffer)X +3321(is)X +3395(line)X +3536(oriented,)X +3840(other-)X +1136 3552(wise,)N +1323(the)X +1441(last)X +1572(character)X +1888(of)X +1975(the)X +2093(appended)X +2421(text.)X +776 3642(Options:)N +1136(None.)X +3 f +576 3822([count])N +841(r)X +897 0.3125(<character>)AX +1 f +776 3912(Replace)N +1073(characters.)X +1478(The)X +1641(next)X +7 f +1817(count)X +1 f +2095(characters)X +2460(in)X +2560(the)X +2696(line)X +2854(are)X +2991(replaced)X +3303(with)X +7 f +3484(<character>)X +1 f +(.)S +776 4002(Replacing)N +1121(characters)X +1468(with)X +7 f +1630(<newline>)X +1 f +2082(characters)X +2429(results)X +2658(in)X +2740(creating)X +3019(new,)X +3193(empty)X +3413(lines)X +3584(into)X +3728(the)X +3846(\256le.)X +776 4182(If)N +7 f +850(<character>)X +1 f +1398(is)X +7 f +1471(<escape>)X +1 f +(,)S +1895(the)X +2013(command)X +2349(is)X +2422(cancelled.)X +776 4362(Line:)N +1136(Unchanged)X +1527(unless)X +1752(the)X +1875(replacement)X +2293(character)X +2614(is)X +2692(a)X +7 f +2753(<newline>)X +1 f +(,)S +3231(in)X +3319(which)X +3541(case)X +3706(it)X +3776(is)X +3855(set)X +3970(to)X +1136 4452(the)N +1254(current)X +1502(line)X +1642(plus)X +7 f +1795(count)X +2083(-)X +2179(1)X +1 f +(.)S +776 4542(Column:)N +1136(Set)X +1264(to)X +1352(the)X +1476(last)X +1613(character)X +1935(replaced,)X +2254(unless)X +2480(the)X +2605(replacement)X +3025(character)X +3348(is)X +3428(a)X +7 f +3491(<newline>)X +1 f +(,)S +3970(in)X +1136 4632(which)N +1352(case)X +1511(the)X +1629(cursor)X +1850(is)X +1923(in)X +2005(column)X +2265(1)X +2325(of)X +2412(the)X +2530(last)X +2661(line)X +2801(inserted.)X +776 4722(Options:)N +1136(None.)X +3 f +576 4902([buffer])N +864([count])X +1129(s)X +1 f +776 4992(Substitute)N +7 f +1115(count)X +1 f +1375(characters)X +1722(in)X +1804(the)X +1922(current)X +2170(line)X +2310(starting)X +2570(with)X +2732(the)X +2850(current)X +3098(character.)X +776 5172(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(line)X +1729(upon)X +1909(which)X +2125(characters)X +2472(were)X +2649(entered.)X +776 5262(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(last)X +1589(character)X +1905(entered.)X +776 5352(Options:)N +1136(Affected)X +1440(by)X +1542(the)X +3 f +1662(altwerase)X +1 f +1988(,)X +3 f +2030(autoindent)X +1 f +2398(,)X +3 f +2440(beautify)X +1 f +(,)S +3 f +2762(showmatch)X +1 f +3149(,)X +3 f +3191(ttywerase)X +1 f +3545(and)X +3 f +3684(wrapmar-)X +1136 5442(gin)N +1 f +1262(options.)X +3 f +576 5622([count])N +841(t)X +888 0.3125(<character>)AX +1 f +776 5712(Search)N +1014(forward,)X +7 f +1308(count)X +1 f +1567(times,)X +1779(through)X +2047(the)X +2164(current)X +2411(line)X +2551(for)X +2665(the)X +2783(character)X +3099(immediately)X +2 f +3519(before)X +7 f +3744(<char-)X +776 5802(acter>)N +1 f +(.)S + +28 p +%%Page: 28 27 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-28)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +1 f +776 762(The)N +3 f +922(t)X +1 f +970(command)X +1307(may)X +1466(be)X +1563(used)X +1731(as)X +1819(the)X +1938(motion)X +2185(component)X +2562(of)X +2651(other)X +3 f +2838(vi)X +1 f +2922(commands,)X +3311(in)X +3395(which)X +3613(case)X +3774(any)X +3912(text)X +776 852(copied)N +1010(into)X +1154(a)X +1210(buffer)X +1427(is)X +1500(character)X +1816(oriented.)X +776 1032(Line:)N +1136(Unchanged.)X +776 1122(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(character)X +2 f +1774(before)X +1 f +1999(the)X +2117 0.3068(searched-for)AX +2540(character.)X +776 1212(Options:)N +1136(None.)X +3 f +576 1392(u)N +1 f +776 1482(Undo)N +985(the)X +1114(last)X +1256(change)X +1515(made)X +1720(to)X +1813(the)X +1942(\256le.)X +2115(If)X +2200(repeated,)X +2524(the)X +3 f +2653(u)X +1 f +2728(command)X +3075(alternates)X +3415(between)X +3715(these)X +3912(two)X +776 1572(states,)N +997(and)X +1136(is)X +1212(its)X +1310(own)X +1471(inverse.)X +1766(When)X +1981(used)X +2151(after)X +2322(an)X +2421(insert)X +2622(that)X +2765(inserted)X +3042(text)X +3185(on)X +3287(more)X +3474(than)X +3634(one)X +3772(line,)X +3934(the)X +776 1662(lines)N +947(are)X +1066(saved)X +1269(in)X +1351(the)X +1469(numeric)X +1752(buffers.)X +776 1842(The)N +3 f +928(.)X +1 f +995(command,)X +1358(when)X +1560(used)X +1735(immediately)X +2163(after)X +2339(the)X +3 f +2465(u)X +1 f +2537(command,)X +2901(causes)X +3139(the)X +3265(change)X +3521(log)X +3651(to)X +3741(be)X +3845(rolled)X +776 1932(forward)N +1051(or)X +1138(backward,)X +1491(depending)X +1845(on)X +1945(the)X +2063(action)X +2279(of)X +2366(the)X +3 f +2484(u)X +1 f +2548(command.)X +776 2112(Line:)N +1136(Set)X +1276(to)X +1376(the)X +1512(position)X +1807(of)X +1912(the)X +2048(\256rst)X +2211(line)X +2370(changed,)X +2697(if)X +2785(the)X +2922(reversal)X +3216(affects)X +3470(only)X +3651(one)X +3806(line)X +3965(or)X +1136 2202(represents)N +1482(an)X +1578(addition)X +1860(or)X +1947(change;)X +2217(otherwise,)X +2569(the)X +2687(line)X +2827(preceding)X +3164(the)X +3282(deleted)X +3534(text.)X +776 2292(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(cursor)X +1679(position)X +1956(before)X +2182(the)X +2300(change)X +2548(was)X +2693(made.)X +776 2382(Options:)N +1136(None.)X +3 f +576 2562([count])N +841(w)X +1 f +776 2652(Move)N +986(forward)X +7 f +1264(count)X +1 f +1527(words.)X +1786(Move)X +1996(the)X +2117(cursor)X +2341(forward)X +2619(to)X +2704(the)X +2825(beginning)X +3168(of)X +3258(a)X +3318(word)X +3507(by)X +3611(repeating)X +3934(the)X +776 2742(following)N +1111(algorithm:)X +1468(if)X +1541(the)X +1663(current)X +1915(position)X +2196(is)X +2273(at)X +2355(the)X +2477(beginning)X +2821(of)X +2912(a)X +2972(word,)X +3181(move)X +3383(to)X +3468(the)X +3589(\256rst)X +3736(character)X +776 2832(of)N +866(the)X +987(next)X +1148(word.)X +1376(If)X +1453(no)X +1556(subsequent)X +1935(word)X +2123(exists)X +2328(on)X +2431(the)X +2552(current)X +2803(line,)X +2966(move)X +3167(to)X +3253(the)X +3375(\256rst)X +3523(character)X +3843(of)X +3934(the)X +776 2922(\256rst)N +920(word)X +1105(on)X +1205(the)X +1323(\256rst)X +1467(following)X +1798(line)X +1938(that)X +2078(contains)X +2365(a)X +2421(word.)X +776 3102(The)N +3 f +928(w)X +1 f +1014(command)X +1358(may)X +1524(be)X +1628(used)X +1803(as)X +1898(the)X +2024(motion)X +2278(component)X +2662(of)X +2757(other)X +3 f +2950(vi)X +1 f +3040(commands,)X +3435(in)X +3525(which)X +3749(case)X +3916(any)X +776 3192(text)N +916(copied)X +1150(into)X +1294(a)X +1350(buffer)X +1567(is)X +1640(character)X +1956(oriented.)X +776 3372(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(word)X +2259(selected.)X +776 3462(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(character)X +1918(of)X +2005(the)X +2123(word)X +2308(selected.)X +776 3552(Options:)N +1136(None.)X +3 f +576 3732([buffer])N +864([count])X +1129(x)X +1 f +776 3822(Delete)N +7 f +1007(count)X +1 f +1268(characters.)X +1656(The)X +1802(deletion)X +2081(is)X +2155(at)X +2235(the)X +2355(current)X +2605(character)X +2923(position.)X +3242(If)X +3318(the)X +3438(number)X +3705(of)X +3794(charac-)X +776 3912(ters)N +915(to)X +1000(be)X +1099(deleted)X +1354(is)X +1430(greater)X +1676(than)X +1836(or)X +1925(equal)X +2121(to)X +2205(the)X +2325(number)X +2592(of)X +2681(characters)X +3030(to)X +3114(the)X +3234(end)X +3372(of)X +3461(the)X +3581(line,)X +3743(all)X +3845(of)X +3934(the)X +776 4002(characters)N +1123(from)X +1299(the)X +1417(current)X +1665(cursor)X +1886(position)X +2163(to)X +2245(the)X +2363(end)X +2499(of)X +2586(the)X +2704(line)X +2844(are)X +2963(deleted.)X +776 4182(Line:)N +1136(Unchanged.)X +776 4272(Column:)N +1136(Unchanged)X +1525(unless)X +1748(the)X +1869(last)X +2003(character)X +2322(in)X +2407(the)X +2528(line)X +2671(is)X +2747(deleted)X +3002(and)X +3141(the)X +3263(cursor)X +3488(is)X +3565(not)X +3691(already)X +3952(on)X +1136 4362(the)N +1254(\256rst)X +1398(character)X +1714(in)X +1796(the)X +1914(line,)X +2074(in)X +2156(which)X +2372(case)X +2531(it)X +2595(is)X +2668(set)X +2777(to)X +2859(the)X +2977(previous)X +3273(character.)X +776 4452(Options:)N +1136(None.)X +3 f +576 4632([buffer])N +864([count])X +1129(y)X +1189(motion)X +1 f +776 4722(Copy)N +981(\(or)X +1107(``yank''\))X +1430(a)X +1498(text)X +1650(region)X +1887(speci\256ed)X +2204(by)X +2316(the)X +7 f +2446(count)X +1 f +2718(and)X +2866(motion)X +3124(into)X +3280(a)X +3349(buffer.)X +3619(If)X +7 f +3706(count)X +1 f +3979(is)X +776 4812(speci\256ed,)N +1101(it)X +1165(is)X +1238(applied)X +1494(to)X +1576(the)X +7 f +1694(motion)X +1 f +(.)S +776 4992(Line:)N +1136(Unchanged,)X +1544(unless)X +1766(the)X +1886(region)X +2113(covers)X +2345(more)X +2532(than)X +2692(a)X +2751(single)X +2965(line,)X +3128(in)X +3213(which)X +3432(case)X +3594(it)X +3661(is)X +3737(set)X +3849(to)X +3934(the)X +1136 5082(line)N +1276(where)X +1493(the)X +1611(region)X +1836(starts.)X +776 5172(Column:)N +1136(Unchanged,)X +1544(unless)X +1766(the)X +1886(region)X +2113(covers)X +2345(more)X +2532(than)X +2692(a)X +2751(single)X +2965(line,)X +3128(in)X +3213(which)X +3432(case)X +3594(it)X +3661(is)X +3737(set)X +3849(to)X +3934(the)X +1136 5262(character)N +1452(were)X +1629(the)X +1747(region)X +1972(starts.)X +776 5352(Options:)N +1136(None.)X +3 f +576 5532([count1])N +881(z)X +937([count2])X +1242(type)X +1 f +776 5622(Redraw)N +1049(the)X +1170(screen)X +1399(with)X +1564(a)X +1623(window)X +7 f +1904(count2)X +1 f +2215(lines)X +2389(long,)X +2574(with)X +2740(line)X +7 f +2884(count1)X +1 f +3196(placed)X +3430(as)X +3521(speci\256ed)X +3830(by)X +3934(the)X +7 f +776 5712(type)N +1 f +1005(character.)X +1378(If)X +7 f +1469(count1)X +1 f +1794(is)X +1884(not)X +2023(speci\256ed,)X +2365(it)X +2445(defaults)X +2735(to)X +2833(the)X +2967(current)X +3231(line.)X +3427(If)X +7 f +3517(count2)X +1 f +3841(is)X +3930(not)X +776 5802(speci\256ed,)N +1101(it)X +1165(defaults)X +1439(to)X +1521(the)X +1639(current)X +1887(window)X +2165(size.)X + +29 p +%%Page: 29 28 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-29)X +1 f +776 762(The)N +921(following)X +7 f +1252(type)X +1 f +1464(characters)X +1811(may)X +1969(be)X +2065(used:)X +776 942(+)N +1136(If)X +7 f +1225(count1)X +1 f +1548(is)X +1636(speci\256ed,)X +1977(place)X +2183(the)X +2317(line)X +7 f +2473(count1)X +1 f +2797(at)X +2891(the)X +3025(top)X +3163(of)X +3266(the)X +3400(screen.)X +3682(Otherwise,)X +1136 1032(display)N +1387(the)X +1505(screen)X +1731(after)X +1899(the)X +2017(current)X +2265(screen,)X +2511(similarly)X +2815(to)X +2897(the)X +3 f +3015(<control-F>)X +1 f +3448(command.)X +776 1122 0.2266(<carriage-return>)AN +1136 1212(Place)N +1330(the)X +1448(line)X +7 f +1588(count1)X +1 f +1896(at)X +1974(the)X +2092(top)X +2214(of)X +2301(the)X +2419(screen.)X +776 1302(.)N +1136(Place)X +1330(the)X +1448(line)X +7 f +1588(count1)X +1 f +1896(in)X +1978(the)X +2096(center)X +2313(of)X +2400(the)X +2518(screen.)X +9 f +776 1392(-)N +1 f +1136(Place)X +1330(the)X +1448(line)X +7 f +1588(count1)X +1 f +1896(at)X +1974(the)X +2092(bottom)X +2338(of)X +2425(the)X +2543(screen.)X +776 1482(\303)N +1136(If)X +7 f +1214(count1)X +1 f +1526(is)X +1603(speci\256ed,)X +1932(place)X +2126(the)X +2248(line)X +2392(that)X +2536(is)X +2613(at)X +2695(the)X +2817(top)X +2943(of)X +3034(the)X +3156(screen)X +3386(when)X +7 f +3584(count1)X +1 f +3896(is)X +3974(at)X +1136 1572(the)N +1264(bottom)X +1520(of)X +1617(the)X +1745(screen,)X +2001(at)X +2089(the)X +2217(bottom)X +2472(of)X +2568(the)X +2695(screen,)X +2950(i.e.)X +3077(display)X +3337(the)X +3464(screen)X +3699(before)X +3934(the)X +1136 1662(screen)N +1362(before)X +7 f +1588(count1)X +1 f +(.)S +1937(Otherwise,)X +2308(display)X +2560(the)X +2679(screen)X +2906(before)X +3133(the)X +3252(current)X +3501(screen,)X +3748(similarly)X +1136 1752(to)N +1218(the)X +3 f +1336(<control-B>)X +1 f +1773(command.)X +776 1932(Line:)N +1136(Set)X +1263(to)X +7 f +1350(count1)X +1 f +1663(unless)X +7 f +1888(count1)X +1 f +2201(is)X +2279(not)X +2406(speci\256ed)X +2716(and)X +2857(the)X +7 f +2980(type)X +1 f +3197(character)X +3518(was)X +3668(either)X +3876(``)X +7 f +3930(\303)X +1 f +('')S +1136 2022(or)N +1224(``)X +7 f +1278(+)X +1 f +('',)S +1421(in)X +1504(which)X +1721(case)X +1881(it)X +1946(is)X +2020(set)X +2130(to)X +2213(the)X +2332(line)X +2473(before)X +2700(the)X +2819(\256rst)X +2964(line)X +3105(on)X +3206(the)X +3325(previous)X +3621(screen)X +3847(or)X +3934(the)X +1136 2112(line)N +1276(after)X +1444(the)X +1562(last)X +1693(line)X +1833(on)X +1933(the)X +2051(previous)X +2347(screen,)X +2593(respectively.)X +776 2202(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 2292(Options:)N +1136(None.)X +3 f +576 2472([count])N +841({)X +1 f +776 2562(Move)N +983(backward)X +7 f +1316(count)X +1 f +1576(paragraphs.)X +776 2742(The)N +3 f +922({)X +1 f +975(command)X +1312(is)X +1386(an)X +1483(absolute)X +1771(movement.)X +2170(The)X +3 f +2316({)X +1 f +2369(command)X +2706(may)X +2865(be)X +2962(used)X +3130(as)X +3219(the)X +3339(motion)X +3587(component)X +3965(of)X +776 2832(other)N +3 f +963(vi)X +1 f +1047(commands,)X +1436(in)X +1520(which)X +1738(case)X +1899(any)X +2036(text)X +2177(copied)X +2412(into)X +2557(a)X +2614(buffer)X +2832(is)X +2906(character)X +3223(oriented,)X +3527(unless)X +3748(the)X +3867(start-)X +776 2922(ing)N +898(character)X +1214(is)X +1287(the)X +1405(\256rst)X +1549(character)X +1865(on)X +1965(its)X +2060(line,)X +2220(in)X +2302(which)X +2518(case)X +2677(it)X +2741(is)X +2814(line)X +2954(oriented.)X +776 3102(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(beginning)X +2414(of)X +2501(the)X +2619(previous)X +2915(paragraph.)X +776 3192(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 3282(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(paragraph)X +1 f +2040(option.)X +3 f +576 3462([count])N +841(|)X +1 f +776 3552(Move)N +983(to)X +1065(a)X +1121(speci\256c)X +2 f +1386(column)X +1 f +1642(position)X +1919(on)X +2019(the)X +2137(current)X +2385(line.)X +776 3732(The)N +3 f +922(|)X +1 f +962(command)X +1300(may)X +1460(be)X +1558(used)X +1727(as)X +1816(the)X +1936(motion)X +2184(component)X +2562(of)X +2651(other)X +3 f +2838(vi)X +1 f +2922(commands,)X +3311(in)X +3395(which)X +3613(case)X +3774(any)X +3912(text)X +776 3822(copied)N +1012(into)X +1158(a)X +1216(buffer)X +1435(is)X +1510(character)X +1828(oriented.)X +2153(It)X +2224(is)X +2299(an)X +2397(error)X +2576(to)X +2660(use)X +2789(the)X +3 f +2908(|)X +1 f +2947(command)X +3284(as)X +3372(a)X +3429(motion)X +3676(component)X +776 3912(and)N +912(for)X +1026(the)X +1144(cursor)X +1365(not)X +1487(to)X +1569(move.)X +776 4092(Line:)N +1136(Unchanged.)X +776 4182(Column:)N +1136(Set)X +1265(to)X +1355(the)X +1481(character)X +1805(occupying)X +2167(the)X +2293(column)X +2561(position)X +2846(identi\256ed)X +3176(by)X +7 f +3284(count)X +1 f +(,)S +3572(if)X +3649(the)X +3775(position)X +1136 4272(exists)N +1339(in)X +1422(the)X +1541(line.)X +1722(If)X +1797(the)X +1916(column)X +2176(length)X +2396(of)X +2483(the)X +2601(current)X +2849(line)X +2989(is)X +3062(less)X +3202(than)X +7 f +3360(count)X +1 f +(,)S +3640(the)X +3758(cursor)X +3979(is)X +1136 4362(moved)N +1374(to)X +1456(the)X +1574(last)X +1705(character)X +2021(in)X +2103(the)X +2221(line.)X +776 4452(Options:)N +1136(None.)X +3 f +576 4632([count])N +841(})X +1 f +776 4722(Move)N +983(forward)X +7 f +1258(count)X +1 f +1518(paragraphs.)X +776 4902(The)N +3 f +922(})X +1 f +975(command)X +1312(is)X +1386(an)X +1483(absolute)X +1771(movement.)X +2170(The)X +3 f +2316(})X +1 f +2369(command)X +2706(may)X +2865(be)X +2962(used)X +3130(as)X +3219(the)X +3339(motion)X +3587(component)X +3965(of)X +776 4992(other)N +3 f +963(vi)X +1 f +1047(commands,)X +1436(in)X +1520(which)X +1738(case)X +1899(any)X +2036(text)X +2177(copied)X +2412(into)X +2557(a)X +2614(buffer)X +2832(is)X +2906(character)X +3223(oriented,)X +3527(unless)X +3748(the)X +3867(start-)X +776 5082(ing)N +898(character)X +1214(is)X +1287(at)X +1365(or)X +1452(before)X +1678(any)X +1814(nonblank)X +2132(characters)X +2479(in)X +2561(its)X +2656(line,)X +2816(in)X +2898(which)X +3114(case)X +3273(it)X +3337(is)X +3410(line)X +3550(oriented.)X +776 5262(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(containing)X +1956(the)X +2074(beginning)X +2414(of)X +2501(the)X +2619(next)X +2777(paragraph.)X +776 5352(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(\256rst)X +1602(nonblank)X +1920(character)X +2236(in)X +2318(the)X +2436(line.)X +776 5442(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(paragraph)X +1 f +2040(option.)X +3 f +576 5622([count])N +841(\304)X +1 f +776 5712(Reverse)N +1062(the)X +1187(case)X +1353(of)X +1447(the)X +1572(next)X +7 f +1738(count)X +1 f +2006 0.3021(character\(s\).)AX +2455(This)X +2625(is)X +2706(the)X +2832(historic)X +3100(semantic)X +3413(for)X +3535(the)X +3 f +3661(\304)X +1 f +3716(command)X +776 5802(and)N +912(it)X +976(is)X +1049(only)X +1211(in)X +1293(effect)X +1497(if)X +1566(the)X +3 f +1684(tildeop)X +1 f +1939(option)X +2163(is)X +2236(not)X +2358(set.)X + +30 p +%%Page: 30 29 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-30)N +2826(Nvi/Nex)X +3122 0.3906(Reference)AX +3487(\(Vi)X +3614(Commands\))X +1 f +776 762(Lowercase)N +1148(alphabetic)X +1501(characters)X +1851(are)X +1974(changed)X +2266(to)X +2352(uppercase,)X +2718(and)X +2858(uppercase)X +3204(characters)X +3555(are)X +3678(changed)X +3970(to)X +776 852(lowercase.)N +1158(No)X +1276(other)X +1461(characters)X +1808(are)X +1927(affected.)X +776 1032(Historically,)N +1203(the)X +3 f +1330(\304)X +1 f +1386(command)X +1731(did)X +1863(not)X +1995(take)X +2159(an)X +2265(associated)X +2625(count,)X +2853(nor)X +2990(did)X +3122(it)X +3196(move)X +3404(past)X +3563(the)X +3691(end)X +3837(of)X +3934(the)X +776 1122(current)N +1025(line.)X +1206(As)X +1316(it)X +1381(had)X +1518(no)X +1619(associated)X +1970(motion)X +2217(it)X +2282(was)X +2428(dif\256cult)X +2701(to)X +2783(change)X +3031(the)X +3149(case)X +3308(of)X +3395(large)X +3576(blocks)X +3805(of)X +3892(text.)X +776 1212(In)N +3 f +868(nvi)X +1 f +974(,)X +1019(if)X +1093(the)X +1216(cursor)X +1442(is)X +1520(on)X +1625(the)X +1748(last)X +1884(character)X +2205(of)X +2297(a)X +2359(line,)X +2525(and)X +2667(there)X +2854(are)X +2979(more)X +3170(lines)X +3347(in)X +3435(the)X +3559(\256le,)X +3707(the)X +3831(cursor)X +776 1302(moves)N +1005(to)X +1087(the)X +1205(next)X +1363(line.)X +776 1482(It)N +849(is)X +926(not)X +1052(an)X +1152(error)X +1333(to)X +1419(specify)X +1675(a)X +1735(count)X +1938(larger)X +2151(than)X +2314(the)X +2437(number)X +2707(of)X +2799(characters)X +3151(between)X +3444(the)X +3567(cursor)X +3793(and)X +3934(the)X +776 1572(end)N +912(of)X +999(the)X +1117(\256le.)X +776 1752(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(of)X +1685(the)X +1803(character)X +2119(after)X +7 f +2287(count)X +1 f +2547(characters,)X +2914(or,)X +3021(end)X +3157(of)X +3244(\256le.)X +776 1842(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(character)X +1774(after)X +7 f +1942(count)X +1 f +2202(characters,)X +2569(or,)X +2676(end-of-\256le.)X +776 1932(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(tildeop)X +1 f +1911(option.)X +3 f +576 2112([count])N +841(\304)X +888(motion)X +1 f +776 2202(Reverse)N +1063(the)X +1189(case)X +1356(of)X +1451(the)X +1577(characters)X +1932(in)X +2022(a)X +2086(text)X +2234(region)X +2467(speci\256ed)X +2780(by)X +2888(the)X +7 f +3014(count)X +1 f +3282(and)X +7 f +3426(motion)X +1 f +(.)S +3782(Only)X +3970(in)X +776 2292(effect)N +980(if)X +1049(the)X +3 f +1167(tildeop)X +1 f +1422(option)X +1646(is)X +1719(set.)X +776 2472(Lowercase)N +1147(characters)X +1496(are)X +1617(changed)X +1908(to)X +1993(uppercase,)X +2358(and)X +2497(uppercase)X +2842(characters)X +3192(are)X +3314(changed)X +3605(to)X +3690(lowercase.)X +776 2562(No)N +894(other)X +1079(characters)X +1426(are)X +1545(affected.)X +776 2742(Line:)N +1136(Set)X +1258(to)X +1340(the)X +1458(line)X +1598(of)X +1685(the)X +1803(character)X +2119(after)X +2287(the)X +2405(last)X +2536(character)X +2852(in)X +2934(the)X +3052(region.)X +776 2832(Column:)N +1136(Set)X +1258(to)X +1340(the)X +1458(character)X +1774(after)X +1942(the)X +2060(last)X +2191(character)X +2507(in)X +2589(the)X +2707(region.)X +776 2922(Options:)N +1136(Affected)X +1438(by)X +1538(the)X +3 f +1656(tildeop)X +1 f +1911(option.)X +3 f +576 3102(<interrupt>)N +1 f +776 3192(Interrupt)N +1087(the)X +1215(current)X +1473(operation.)X +1846(Many)X +2063(of)X +2160(the)X +2289(potentially)X +2662(long-running)X +3 f +3111(vi)X +1 f +3204(commands)X +3582(may)X +3751(be)X +3858(inter-)X +776 3282(rupted)N +1014(using)X +1220(the)X +1351(terminal)X +1650(interrupt)X +1958(character.)X +2326(These)X +2550(operations)X +2916(include)X +3184(searches,)X +3509(\256le)X +3643(reading)X +3916(and)X +776 3372(writing,)N +1059(\256lter)X +1242(operations)X +1608(and)X +1756(map)X +1927(character)X +2256(expansion.)X +2654(Interrupts)X +2999(are)X +3131(also)X +3293(enabled)X +3576(when)X +3783(running)X +776 3462(commands)N +1143(outside)X +1394(of)X +3 f +1481(vi)X +1 f +1543(.)X +776 3642(If)N +853(the)X +7 f +974(<interrupt>)X +1 f +1525(character)X +1844(is)X +1920(used)X +2090(to)X +2175(interrupt)X +2474(while)X +2675(entering)X +2961(an)X +3 f +3060(ex)X +1 f +3159(command,)X +3518(the)X +3639(command)X +3979(is)X +776 3732(aborted,)N +1057(the)X +1175(cursor)X +1396(returns)X +1639(to)X +1721(its)X +1816(previous)X +2112(position,)X +2409(and)X +3 f +2545(vi)X +1 f +2627(remains)X +2901(in)X +2983(command)X +3319(mode.)X +776 3912(Generally,)N +1145(if)X +1226(the)X +7 f +1356(<interrupt>)X +1 f +1916(character)X +2244(is)X +2329(used)X +2508(to)X +2603(interrupt)X +2912(any)X +3061(operation,)X +3417(any)X +3566(changes)X +3858(made)X +776 4002(before)N +1002(the)X +1120(interrupt)X +1416(are)X +1535(left)X +1662(in)X +1744(place.)X +776 4182(Line:)N +1136(Dependent)X +1504(on)X +1604(the)X +1722(operation)X +2045(being)X +2243(interrupted.)X +776 4272(Column:)N +1136(Dependent)X +1504(on)X +1604(the)X +1722(operation)X +2045(being)X +2243(interrupted.)X +776 4362(Options:)N +1136(None.)X +3 f +776 4548(11.)N +916(Vi)X +1016(Text)X +1192(Input)X +1402(Commands)X +1 f +976 4671(The)N +1121(following)X +1452(section)X +1699(describes)X +2018(the)X +2136(commands)X +2503(available)X +2813(in)X +2895(the)X +3013(text)X +3153(input)X +3337(mode)X +3535(of)X +3622(the)X +3 f +3740(vi)X +1 f +3822(editor.)X +976 4794(Historically,)N +3 f +1394(vi)X +1 f +1476(implementations)X +2030(only)X +2193(permitted)X +2521(the)X +2640(characters)X +2988(inserted)X +3263(on)X +3364(the)X +3483(current)X +3732(line)X +3873(to)X +3956(be)X +776 4884(erased.)N +1060(In)X +1165(addition,)X +1485(only)X +1665(the)X +7 f +1801(<control-D>)X +1 f +2367(erase)X +2571(character)X +2905(and)X +3059(the)X +3195(``)X +7 f +3249(0<control-D>)X +1 f +('')S +3916(and)X +776 4974(``)N +7 f +830(\303<control-D>)X +1 f +('')S +1488(erase)X +1683(strings)X +1925(could)X +2132(erase)X +2327(autoindent)X +2694(characters.)X +3090(This)X +3261(implementation)X +3792(permits)X +776 5064(erasure)N +1038(to)X +1129(continue)X +1434(past)X +1592(the)X +1719(beginning)X +2068(of)X +2164(the)X +2291(current)X +2548(line,)X +2717(and)X +2862(back)X +3043(to)X +3134(where)X +3360(text)X +3509(input)X +3701(mode)X +3907(was)X +776 5154(entered.)N +1080(In)X +1174(addition,)X +1483(autoindent)X +1848(characters)X +2202(may)X +2367(be)X +2471(erased)X +2705(using)X +2906(the)X +3032(standard)X +3332(erase)X +3526(characters.)X +3921(For)X +776 5244(the)N +908(line)X +1061(and)X +1210(word)X +1408(erase)X +1607(characters,)X +1987(reaching)X +2297(the)X +2428(autoindent)X +2799(characters)X +3159(forms)X +3379(a)X +3448(``soft'')X +3709(boundary,)X +776 5334(denoting)N +1081(the)X +1204(end)X +1345(of)X +1437(the)X +1561(current)X +1815(word)X +2006(or)X +2099(line)X +2245(erase.)X +2477(Repeating)X +2828(the)X +2952(word)X +3143(or)X +3236(line)X +3382(erase)X +3574(key)X +3716(will)X +3866(erase)X +776 5424(the)N +894(autoindent)X +1252(characters.)X +976 5547(Historically,)N +3 f +1396(vi)X +1 f +1480(always)X +1725(used)X +7 f +1894(<control-H>)X +1 f +2444(and)X +7 f +2582(<control-W>)X +1 f +3132(as)X +3221(character)X +3539(and)X +3678(word)X +3866(erase)X +776 5637(characters,)N +1148(respectively,)X +1581(regardless)X +1932(of)X +2024(the)X +2146(current)X +2398(terminal)X +2689(settings.)X +2997(This)X +3163(implementation)X +3689(accepts,)X +3970(in)X +776 5727(addition)N +1058(to)X +1140(these)X +1325(two)X +1465(characters,)X +1832(the)X +1950(current)X +2198(terminal)X +2485(characters)X +2832(for)X +2946(those)X +3135(operations.)X + +31 p +%%Page: 31 30 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Vi)X +1364(Commands\))X +3658(USD:13-31)X +776 762(<nul>)N +1 f +976 852(If)N +1050(the)X +1168(\256rst)X +1312(character)X +1628(of)X +1715(the)X +1833(input)X +2017(is)X +2090(a)X +7 f +2146(<nul>)X +1 f +(,)S +2426(the)X +2544(previous)X +2840(input)X +3024(is)X +3097(replayed,)X +3414(as)X +3501(if)X +3570(just)X +3705(entered.)X +3 f +776 1032(<control-D>)N +1 f +976 1122(If)N +1058(the)X +1184(previous)X +1488(character)X +1813(on)X +1922(the)X +2049(line)X +2198(was)X +2352(an)X +2457(autoindent)X +2824(character,)X +3169(erase)X +3364(it.)X +3477(Otherwise,)X +3856(if)X +3934(the)X +976 1212(user)N +1135(is)X +1213(entering)X +1501(the)X +1624(\256rst)X +1773(character)X +2094(in)X +2181(the)X +2304(line,)X +7 f +2469(<control-D>)X +1 f +3022(is)X +3100(ignored.)X +3410(Otherwise,)X +3785(a)X +3845(literal)X +7 f +976 1302(<control-D>)N +1 f +1524(character)X +1840(is)X +1913(entered.)X +3 f +776 1482(\303<control-D>)N +1 f +976 1572(If)N +1058(the)X +1184(previous)X +1488(character)X +1812(on)X +1920(the)X +2047(line)X +2196(was)X +2350(an)X +2455(autoindent)X +2822(character,)X +3167(erase)X +3362(all)X +3471(of)X +3567(the)X +3694(autoindent)X +976 1662(characters)N +1323(on)X +1423(the)X +1541(line.)X +1721(In)X +1808(addition,)X +2110(the)X +2228(autoindent)X +2586(level)X +2762(is)X +2835(reset)X +3007(to)X +3089(0.)X +3 f +776 1842(0<control-D>)N +1 f +976 1932(If)N +1058(the)X +1184(previous)X +1488(character)X +1812(on)X +1920(the)X +2047(line)X +2196(was)X +2350(an)X +2455(autoindent)X +2822(character,)X +3167(erase)X +3362(all)X +3471(of)X +3567(the)X +3694(autoindent)X +976 2022(characters)N +1323(on)X +1423(the)X +1541(line.)X +3 f +776 2202(<control-T>)N +1 f +976 2292(Insert)N +1191(suf\256cient)X +7 f +1521(<tab>)X +1 f +1793(and)X +7 f +1941(<space>)X +1 f +2309(characters)X +2669(to)X +2764(move)X +2975(the)X +3106(cursor)X +3340(forward)X +3628(to)X +3723(a)X +3792(column)X +976 2382(immediately)N +1396(after)X +1564(the)X +1682(next)X +1840(column)X +2100(which)X +2316(is)X +2389(an)X +2485(even)X +2657(multiple)X +2943(of)X +3030(the)X +3 f +3148(shiftwidth)X +1 f +3514(option.)X +976 2562(Historically,)N +3 f +1397(vi)X +1 f +1482(did)X +1607(not)X +1732(permit)X +1965(the)X +7 f +2087(<control-T>)X +1 f +2639(command)X +2979(to)X +3065(be)X +3165(used)X +3336(unless)X +3560(the)X +3682(cursor)X +3907(was)X +976 2652(at)N +1056(the)X +1176(\256rst)X +1322(column)X +1584(of)X +1673(a)X +1731(new)X +1887(line)X +2029(or)X +2117(it)X +2182(was)X +2328(preceded)X +2640(only)X +2803(by)X +2904(autoindent)X +3263(characters.)X +3 f +3651(Nvi)X +1 f +3792(permits)X +976 2742(it)N +1040(to)X +1122(be)X +1218(used)X +1385(at)X +1463(any)X +1599(time)X +1761(during)X +1990(insert)X +2188(mode.)X +3 f +776 2922(<erase>)N +776 3012(<control-H>)N +1 f +976 3102(Erase)N +1175(the)X +1293(last)X +1424(character.)X +3 f +776 3282(<literal)N +1047(next>)X +1 f +976 3372(Quote)N +1197(the)X +1320(next)X +1483(character.)X +1844(The)X +1994(next)X +2157(character)X +2479(will)X +2629(not)X +2757(be)X +2859(mapped)X +3139(\(see)X +3295(the)X +3 f +3419(map)X +1 f +3596(command)X +3938(for)X +976 3462(more)N +1162(information\))X +1588(or)X +1676(interpreted)X +2045(specially.)X +2391(A)X +2470(carat)X +2648(\(``)X +7 f +2729(\303)X +1 f +(''\))S +2878(character)X +3194(will)X +3338(be)X +3434(displayed)X +3761(immedi-)X +976 3552(ately)N +1152(as)X +1239(a)X +1295(placeholder,)X +1710(but)X +1832(will)X +1976(be)X +2072(replaced)X +2365(by)X +2465(the)X +2583(next)X +2741(character.)X +3 f +776 3732(<escape>)N +1 f +976 3822(Resolve)N +1254(all)X +1354(text)X +1494(input)X +1678(into)X +1822(the)X +1940(\256le,)X +2082(and)X +2218(return)X +2430(to)X +2512(command)X +2848(mode.)X +3 f +776 4002(<line)N +966(erase>)X +1 f +976 4092(Erase)N +1175(the)X +1293(current)X +1541(line.)X +3 f +776 4272(<control-W>)N +776 4362(<word)N +1020(erase>)X +1 f +976 4452(Erase)N +1188(the)X +1319(last)X +1463(word.)X +1701(The)X +1859(de\256nition)X +2198(of)X +2298(word)X +2496(is)X +2582(dependent)X +2945(on)X +3059(the)X +3 f +3191(altwerase)X +1 f +3551(and)X +3 f +3701(ttywerase)X +1 f +976 4542(options.)N +3 f +776 4722 0.2102(<control-X>[0-9A-Fa-f]*)AN +1 f +976 4812(Insert)N +1179(a)X +1235(character)X +1551(with)X +1713(the)X +1831(speci\256ed)X +2136(hexadecimal)X +2562(value)X +2756(into)X +2900(the)X +3018(text.)X +3 f +776 4992(<interrupt>)N +1 f +976 5082(Interrupt)N +1288(text)X +1439(input)X +1634(mode,)X +1863(returning)X +2188(to)X +2281(command)X +2628(mode.)X +2877(If)X +2962(the)X +7 f +3091(<interrupt>)X +1 f +3651(character)X +3979(is)X +976 5172(used)N +1151(to)X +1241(interrupt)X +1545(inserting)X +1852(text)X +1999(into)X +2150(the)X +2275(\256le,)X +2424(it)X +2495(is)X +2575(as)X +2669(if)X +2745(the)X +7 f +2870(<escape>)X +1 f +3281(character)X +3604(was)X +3756(used;)X +3952(all)X +976 5262(text)N +1116(input)X +1300(up)X +1400(to)X +1482(the)X +1600(interruption)X +1998(is)X +2071(resolved)X +2363(into)X +2507(the)X +2625(\256le.)X +3 f +776 5448(12.)N +916(Ex)X +1029(Addressing)X +1 f +976 5571(Addressing)N +1363(in)X +3 f +1447(ex)X +1 f +1545(\(and)X +1710(when)X +3 f +1906(ex)X +1 f +2004(commands)X +2373(are)X +2494(executed)X +2802(from)X +3 f +2980(vi)X +1 f +3042(\))X +3092(relates)X +3325(to)X +3410(the)X +3531(current)X +3782(line.)X +3965(In)X +776 5661(general,)N +1054(the)X +1172(current)X +1420(line)X +1560(is)X +1633(the)X +1751(last)X +1882(line)X +2022(affected)X +2302(by)X +2402(a)X +2458(command.)X +2834(The)X +2979(exact)X +3169(effect)X +3373(on)X +3473(the)X +3591(current)X +3839(line)X +3979(is)X +776 5751(discussed)N +1103(under)X +1306(the)X +1424(description)X +1800(of)X +1888(each)X +2057(command.)X +2434(When)X +2647(the)X +2766(\256le)X +2889(contains)X +3177(no)X +3278(lines,)X +3470(the)X +3589(current)X +3838(line)X +3979(is)X + +32 p +%%Page: 32 31 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-32)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +1 f +776 762(zero.)N +976 885(Addresses)N +1326(are)X +1445(constructed)X +1835(by)X +1935(one)X +2071(or)X +2158(more)X +2343(of)X +2430(the)X +2548(following)X +2879(methods:)X +816 1008(\(1\))N +1030(The)X +1175(address)X +1436(``)X +7 f +1490(.)X +1 f +('')S +1632(refers)X +1836(to)X +1918(the)X +2036(current)X +2284(line.)X +816 1131(\(2\))N +1030(The)X +1175(address)X +1436(``)X +7 f +1490($)X +1 f +('')S +1612(refers)X +1816(to)X +1898(the)X +2016(last)X +2147(line)X +2287(of)X +2374(the)X +2492(\256le.)X +816 1254(\(3\))N +1030(The)X +1175(address)X +1436(``)X +7 f +1490(N)X +1 f +('',)S +1632(where)X +7 f +1849(N)X +1 f +1917(is)X +1990(a)X +2046(positive)X +2319(number,)X +2604(refers)X +2808(to)X +2890(the)X +3008(N-th)X +3175(line)X +3315(of)X +3402(the)X +3520(\256le.)X +816 1377(\(4\))N +1030(The)X +1178(address)X +1442(``)X +7 f +1496('<character>)X +1 f +('')S +2149(or)X +2239(``)X +7 f +2293(`<character>)X +1 f +('')S +2946(refers)X +3153(to)X +3238(the)X +3359(line)X +3503(marked)X +3768(with)X +3934(the)X +1030 1467(name)N +7 f +1234(<character>)X +1 f +(.)S +1832(\(See)X +2005(the)X +3 f +2133(k)X +1 f +2207(or)X +3 f +2304(m)X +1 f +2400(commands)X +2776(for)X +2899(more)X +3093(information)X +3500(on)X +3609(how)X +3776(to)X +3867(mark)X +1030 1557(lines.\))N +816 1680(\(5\))N +1030(A)X +1113(regular)X +1366(expression)X +1734(\(RE\))X +1915(enclosed)X +2221(by)X +2326(slashes)X +2578(\(``)X +7 f +2659(/)X +1 f +(''\))S +2813(is)X +2891(an)X +2992(address,)X +3278(and)X +3419(it)X +3488(refers)X +3697(to)X +3784(the)X +3908(\256rst)X +1030 1770(line)N +1171(found)X +1379(by)X +1480(searching)X +1809(forward)X +2085(from)X +2262(the)X +2381(line)X +2 f +2522(after)X +1 f +2694(the)X +2813(current)X +3062(line)X +3203(toward)X +3447(the)X +3566(end)X +3703(of)X +3791(the)X +3910(\256le,)X +1030 1860(and)N +1170(stopping)X +1469(at)X +1551(the)X +1673(\256rst)X +1821(line)X +1965(containing)X +2327(a)X +2387(string)X +2593(matching)X +2915(the)X +3037(RE.)X +3203(\(The)X +3379(trailing)X +3634(slash)X +3819(can)X +3956(be)X +1030 1950(omitted)N +1294(at)X +1372(the)X +1490(end)X +1626(of)X +1713(the)X +1831(command)X +2167(line.\))X +1030 2130(If)N +1104(no)X +1204(RE)X +1326(is)X +1399(speci\256ed,)X +1724(i.e.)X +1842(the)X +1960(pattern)X +2203(is)X +2276(``)X +7 f +2330(//)X +1 f +('',)S +2520(the)X +2638(last)X +2769(RE)X +2891(used)X +3058(in)X +3140(any)X +3276(command)X +3612(is)X +3685(used)X +3852(in)X +3934(the)X +1030 2220(search.)N +1030 2400(If)N +1111(the)X +3 f +1236(extended)X +1 f +1570(option)X +1801(is)X +1881(set,)X +2017(the)X +2142(RE)X +2271(is)X +2351(handled)X +2632(as)X +2726(an)X +2829(extended)X +3146(RE,)X +3295(not)X +3425(a)X +3489(basic)X +3682(RE.)X +3852(If)X +3934(the)X +3 f +1030 2490(wrapscan)N +1 f +1381(option)X +1607(is)X +1681(set,)X +1811(the)X +1930(search)X +2157(wraps)X +2370(around)X +2614(to)X +2697(the)X +2816(beginning)X +3157(of)X +3245(the)X +3364(\256le)X +3487(and)X +3624(continues)X +3952(up)X +1030 2580(to)N +1112(and)X +1248(including)X +1570(the)X +1688(current)X +1936(line,)X +2096(so)X +2187(that)X +2327(the)X +2445(entire)X +2648(\256le)X +2770(is)X +2843(searched.)X +1030 2760(The)N +1175(form)X +1351(``)X +7 f +1405(\\/)X +1 f +('')S +1575(is)X +1648(accepted)X +1950(for)X +2064(historic)X +2324(reasons,)X +2605(and)X +2741(is)X +2814(identical)X +3110(to)X +3192(``)X +7 f +3246(//)X +1 f +(''.)S +816 2883(\(6\))N +1030(An)X +1153(RE)X +1280(enclosed)X +1586(in)X +1673(question)X +1969(marks)X +2190(\(``)X +7 f +2271(?)X +1 f +(''\))S +2446(addresses)X +2780(the)X +2904(\256rst)X +3054(line)X +3200(found)X +3413(by)X +3519(searching)X +3853(back-)X +1030 2973(ward)N +1212(from)X +1389(the)X +1508(line)X +2 f +1648(preceding)X +1 f +1989(the)X +2107(current)X +2355(line,)X +2515(toward)X +2758(the)X +2876(beginning)X +3216(of)X +3303(the)X +3421(\256le)X +3543(and)X +3679(stopping)X +3974(at)X +1030 3063(the)N +1149(\256rst)X +1294(line)X +1435(containing)X +1794(a)X +1851(string)X +2054(matching)X +2373(the)X +2492(RE.)X +2655(\(The)X +2828(trailing)X +3080(question)X +3372(mark)X +3558(can)X +3691(be)X +3788(omitted)X +1030 3153(at)N +1108(the)X +1226(end)X +1362(of)X +1449(a)X +1505(command)X +1841(line.\))X +1030 3333(If)N +1104(no)X +1204(RE)X +1326(is)X +1399(speci\256ed,)X +1724(i.e.)X +1842(the)X +1960(pattern)X +2203(is)X +2276(``)X +7 f +2330(??)X +1 f +('',)S +2520(the)X +2638(last)X +2769(RE)X +2891(used)X +3058(in)X +3140(any)X +3276(command)X +3612(is)X +3685(used)X +3852(in)X +3934(the)X +1030 3423(search.)N +1030 3603(If)N +1111(the)X +3 f +1236(extended)X +1 f +1570(option)X +1801(is)X +1881(set,)X +2017(the)X +2142(RE)X +2271(is)X +2351(handled)X +2632(as)X +2726(an)X +2829(extended)X +3146(RE,)X +3295(not)X +3425(a)X +3489(basic)X +3682(RE.)X +3852(If)X +3934(the)X +3 f +1030 3693(wrapscan)N +1 f +1382(option)X +1609(is)X +1685(set,)X +1817(the)X +1938(search)X +2187(wraps)X +2402(around)X +2648(from)X +2827(the)X +2948(beginning)X +3290(of)X +3379(the)X +3499(\256le)X +3623(to)X +3707(the)X +3827(end)X +3965(of)X +1030 3783(the)N +1148(\256le)X +1270(and)X +1406(continues)X +1733(up)X +1833(to)X +1915(and)X +2051(including)X +2373(the)X +2491(current)X +2739(line,)X +2899(so)X +2990(that)X +3130(the)X +3248(entire)X +3451(\256le)X +3573(is)X +3646(searched.)X +1030 3963(The)N +1175(form)X +1351(``)X +7 f +1405(\\?)X +1 f +('')S +1595(is)X +1668(accepted)X +1970(for)X +2084(historic)X +2344(reasons,)X +2625(and)X +2761(is)X +2834(identical)X +3130(to)X +3212(``)X +7 f +3266(??)X +1 f +(''.)S +816 4086(\(7\))N +1030(An)X +1148(address)X +1409(followed)X +1714(by)X +1814(a)X +1870(plus)X +2023(sign)X +2176(\(``)X +7 f +2257(+)X +1 f +(''\))S +2406(or)X +2494(a)X +2551(minus)X +2767(sign)X +2921(\(``)X +7 f +3002(-)X +1 f +(''\))S +3152(followed)X +3458(by)X +3559(a)X +3616(number)X +3882(is)X +3956(an)X +1030 4176(offset)N +1237(address)X +1502(and)X +1642(refers)X +1850(to)X +1936(the)X +2058(address)X +2323(plus)X +2480(\(or)X +2598(minus\))X +2844(the)X +2966(indicated)X +3284(number)X +3553(of)X +3643(lines.)X +3857(If)X +3934(the)X +1030 4266(address)N +1291(is)X +1364(omitted,)X +1648(the)X +1766(addition)X +2048(or)X +2135(subtraction)X +2511(is)X +2584(done)X +2760(with)X +2922(respect)X +3170(to)X +3252(the)X +3370(current)X +3618(line.)X +816 4389(\(8\))N +1030(An)X +1158(address)X +1429(of)X +1526(``)X +7 f +1580(+)X +1 f +('')S +1712(or)X +1809(``)X +7 f +9 f +1863(-)X +1 f +1907('')X +1991(followed)X +2306(by)X +2416(a)X +2482(number)X +2757(is)X +2840(an)X +2946(offset)X +3159(from)X +3345(the)X +3473(current)X +3731(line.)X +3921(For)X +1030 4479(example,)N +1342(``)X +7 f +9 f +1396(-)X +7 f +1440(5)X +1 f +('')S +1562(is)X +1635(the)X +1753(same)X +1938(as)X +2025(``)X +7 f +2079(.)X +9 f +(-)S +7 f +2171(5)X +1 f +(''.)S +816 4602(\(9\))N +1030(An)X +1151(address)X +1415(ending)X +1656(with)X +1821(``)X +7 f +1875(+)X +1 f +('')S +2000(or)X +2090(``)X +7 f +2144(-)X +1 f +('')S +2270(has)X +2401(1)X +2465(added)X +2681(to)X +2767(or)X +2858(subtracted)X +3212(from)X +3392(the)X +3514(address,)X +3799(respec-)X +1030 4692(tively.)N +1276(As)X +1389(a)X +1449(consequence)X +1884(of)X +1975(this)X +2114(rule)X +2263(and)X +2403(of)X +2494(the)X +2615(previous)X +2914(rule,)X +3082(the)X +3203(address)X +3467(``)X +7 f +9 f +3521(-)X +1 f +3565('')X +3642(refers)X +3849(to)X +3934(the)X +1030 4782(line)N +1173(preceding)X +1513(the)X +1634(current)X +1886(line.)X +2070(Moreover,)X +2431(trailing)X +2686(``)X +7 f +2740(+)X +1 f +('')S +2866(and)X +3006(``)X +7 f +9 f +3060(-)X +1 f +3104('')X +3182(characters)X +3533(have)X +3709(a)X +3769(cumula-)X +1030 4872(tive)N +1170(effect.)X +1414(For)X +1545(example,)X +1857(``)X +7 f +1911(++)X +9 f +(-)S +7 f +2051(++)X +1 f +('')S +2221(refers)X +2425(to)X +2507(the)X +2625(current)X +2873(line)X +3013(plus)X +3166(3.)X +816 4995(\(10\))N +1030(A)X +1108(percent)X +1365(sign)X +1518(\(``)X +7 f +1599(%)X +1 f +(''\))S +1748(is)X +1821(equivalent)X +2175(to)X +2257(the)X +2375(address)X +2636(range)X +2835(``)X +7 f +2889(1,$)X +1 f +(''.)S +3 f +976 5118(Ex)N +1 f +1099(commands)X +1476(require)X +1734(zero,)X +1923(one,)X +2089(or)X +2186(two)X +2336(addresses.)X +2714(It)X +2793(is)X +2876(an)X +2982(error)X +3169(to)X +3261(specify)X +3524(an)X +3631(address)X +3903(to)X +3996(a)X +776 5208(command)N +1112(which)X +1328(requires)X +1607(zero)X +1766(addresses.)X +976 5331(If)N +1053(the)X +1174(user)X +1331(provides)X +1630(more)X +1818(than)X +1979(the)X +2100(expected)X +2409(number)X +2677(of)X +2768(addresses)X +3100(to)X +3186(any)X +3 f +3326(ex)X +1 f +3426(command,)X +3786(the)X +3908(\256rst)X +776 5421(addresses)N +1108(speci\256ed)X +1417(are)X +1540(discarded.)X +1912(For)X +2047(example,)X +2362(``)X +7 f +2416(1,2,3,5)X +1 f +(''print)S +2980(prints)X +3185(lines)X +3359(3)X +3422(through)X +3694(5,)X +3777(because)X +776 5511(the)N +3 f +894(print)X +1 f +1087(command)X +1423(only)X +1585(takes)X +1770(two)X +1910(addresses.)X +976 5634(The)N +1131(addresses)X +1469(in)X +1561(a)X +1627(range)X +1836(are)X +1965(separated)X +2299(from)X +2485(each)X +2663(other)X +2858(by)X +2968(a)X +3034(comma)X +3300(\(``)X +7 f +3381(,)X +1 f +(''\))S +3540(or)X +3637(a)X +3703(semicolon)X +776 5724(\(``)N +7 f +857(;)X +1 f +(''\).)S +1058(In)X +1157(the)X +1287(latter)X +1484(case,)X +1675(the)X +1805(current)X +2065(line)X +2217(\(``)X +7 f +2298(.)X +1 f +(''\))S +2479(is)X +2564(set)X +2685(to)X +2779(the)X +2909(\256rst)X +3065(address,)X +3358(and)X +3506(only)X +3680(then)X +3850(is)X +3934(the)X + +33 p +%%Page: 33 32 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3658(USD:13-33)X +1 f +776 762(second)N +1026(address)X +1295(calculated.)X +1689(This)X +1859(feature)X +2111(can)X +2251(be)X +2355(used)X +2530(to)X +2620(determine)X +2969(the)X +3095(starting)X +3363(line)X +3511(for)X +3633(forward)X +3916(and)X +776 852(backward)N +1116(searches)X +1416(\(see)X +1572(rules)X +1754(\(5\))X +1874(and)X +2016(\(6\))X +2136(above\).)X +2421(The)X +2572(second)X +2821(address)X +3088(of)X +3181(any)X +3323(two-address)X +3737(sequence)X +776 942(corresponds)N +1193(to)X +1284(a)X +1349(line)X +1498(that)X +1647(follows,)X +1936(in)X +2027(the)X +2154(\256le,)X +2305(the)X +2432(line)X +2581(corresponding)X +3069(to)X +3160(the)X +3288(\256rst)X +3442(address.)X +3753(The)X +3908(\256rst)X +776 1032(address)N +1044(must)X +1226(be)X +1329(less)X +1475(than)X +1639(or)X +1732(equal)X +1932(to)X +2020(the)X +2144(second)X +2393(address.)X +2700(The)X +2851(\256rst)X +3001(address)X +3268(must)X +3449(be)X +3551(greater)X +3801(than)X +3965(or)X +776 1122(equal)N +973(to)X +1058(the)X +1179(\256rst)X +1326(line)X +1469(of)X +1559(the)X +1680(\256le,)X +1825(and)X +1964(the)X +2085(last)X +2219(address)X +2483(must)X +2661(be)X +2761(less)X +2905(than)X +3067(or)X +3158(equal)X +3356(to)X +3442(the)X +3564(last)X +3699(line)X +3843(of)X +3934(the)X +776 1212(\256le.)N +3 f +776 1398(13.)N +916(Ex)X +1029(Description)X +1 f +976 1521(The)N +1121(following)X +1452(words)X +1668(have)X +1840(special)X +2083(meanings)X +2410(for)X +3 f +2524(ex)X +1 f +2620(commands.)X +3 f +776 1701(<eof>)N +1 f +976 1791(The)N +1130(end-of-\256le)X +1498(character)X +1823(is)X +1905(used)X +2081(to)X +2172(scroll)X +2379(the)X +2506(screen)X +2741(in)X +2832(the)X +3 f +2959(ex)X +1 f +3064(editor.)X +3320(This)X +3491(character)X +3816(is)X +3898(nor-)X +976 1881(mally)N +7 f +1178(<control-D>)X +1 f +(,)S +1746(however,)X +2063(whatever)X +2378(character)X +2694(is)X +2767(set)X +2876(for)X +2990(the)X +3108(current)X +3356(terminal)X +3643(is)X +3716(used.)X +3 f +776 2061(line)N +1 f +976 2151(A)N +1054(single-line)X +1412(address,)X +1693(given)X +1891(in)X +1973(any)X +2109(of)X +2196(the)X +2314(forms)X +2521(described)X +2849(in)X +2931(the)X +3049(section)X +3296(entitled)X +3557(``)X +3 f +3611(Ex)X +3725(Address-)X +976 2241(ing)N +1 f +1082(''.)X +1196(The)X +1341(default)X +1584(for)X +7 f +1698(line)X +1 f +1910(is)X +1983(the)X +2101(current)X +2349(line.)X +3 f +776 2421(range)N +1 f +976 2511(A)N +1058(line,)X +1222(or)X +1313(a)X +1373(pair)X +1522(of)X +1613(line)X +1757(addresses,)X +2109(separated)X +2437(by)X +2541(a)X +2601(comma)X +2861(or)X +2952(semicolon.)X +3345(\(See)X +3512(the)X +3634(section)X +3885(enti-)X +976 2601(tled)N +1123(``)X +3 f +1177(Ex)X +1297(Addressing)X +1 f +1683('')X +1764(for)X +1884(more)X +2075(information.\))X +2546(The)X +2697(default)X +2946(for)X +3066(range)X +3271(is)X +3350(the)X +3474(current)X +3728(line)X +2 f +3874(only)X +1 f +4012(,)X +976 2691(i.e.)N +1114(``)X +7 f +1168(.,.)X +1 f +(''.)S +1426(A)X +1504(percent)X +1761(sign)X +1914(\(``)X +7 f +1995(%)X +1 f +(''\))S +2144(stands)X +2364(for)X +2479(the)X +2598(range)X +2798(``)X +7 f +2852(1,$)X +1 f +(''.)S +3111(The)X +3257(starting)X +3518(address)X +3780(must)X +3956(be)X +976 2781(less)N +1116(than,)X +1294(or)X +1381(equal)X +1575(to,)X +1677(the)X +1795(ending)X +2033(address.)X +3 f +776 2961(count)N +1 f +976 3051(A)N +1058(positive)X +1335(integer,)X +1602(specifying)X +1961(the)X +2084(number)X +2354(of)X +2446(lines)X +2622(to)X +2709(be)X +2810(affected)X +3095(by)X +3200(the)X +3323(command;)X +3686(the)X +3809(default)X +976 3141(is)N +1055(1.)X +1161(Generally,)X +1524(a)X +1586(count)X +1790(past)X +1945(the)X +2068(end-of-\256le)X +2432(may)X +2595(be)X +2696(speci\256ed,)X +3026(e.g.)X +3167(the)X +3290(command)X +3631(``)X +7 f +3685(p)X +3786(3000)X +1 f +('')S +976 3231(in)N +1064(a)X +1127(10)X +1234(line)X +1381(\256le)X +1510(is)X +1590(acceptable,)X +1977(and)X +2120(will)X +2271(print)X +2449(from)X +2632(the)X +2757(current)X +3012(line)X +3159(through)X +3435(the)X +3560(last)X +3698(line)X +3845(in)X +3934(the)X +976 3321(\256le.)N +3 f +776 3501(\257ags)N +1 f +976 3591(One)N +1132(or)X +1221(more)X +1408(of)X +1497(the)X +1617(characters)X +1966(``#'',)X +2156(``p'',)X +2346(and)X +2484(``l''.)X +2677(When)X +2892(a)X +2951(command)X +3290(that)X +3433(accepts)X +3693(these)X +3881(\257ags)X +976 3681(completes,)N +1343(the)X +1463(addressed)X +1802(line\(s\))X +2029(are)X +2150(written)X +2399(out)X +2523(as)X +2612(if)X +2683(by)X +2785(the)X +2905(corresponding)X +3 f +3386(#)X +1 f +(,)S +3 f +3468(l)X +1 f +3512(or)X +3 f +3600(p)X +1 f +3665(commands.)X +976 3771(In)N +1064(addition,)X +1367(any)X +1504(number)X +1770(of)X +1858(``)X +7 f +1912(+)X +1 f +('')S +2035(or)X +2123(``)X +7 f +9 f +2177(-)X +1 f +2221('')X +2296(characters)X +2644(can)X +2777(be)X +2874(speci\256ed)X +3180(before,)X +3427(after,)X +3616(or)X +3704(during)X +3934(the)X +976 3861(\257ags,)N +1175(in)X +1265(which)X +1489(case)X +1656(the)X +1782(line)X +1930(written)X +2185(is)X +2266(not)X +2396(necessarily)X +2780(the)X +2905(one)X +3048(affected)X +3335(by)X +3442(the)X +3567(command,)X +3930(but)X +976 3951(rather)N +1184(the)X +1302(line)X +1442(addressed)X +1779(by)X +1879(the)X +1997(offset)X +2200(address)X +2461(speci\256ed.)X +2806(The)X +2951(default)X +3194(for)X +7 f +3308(flags)X +1 f +3568(is)X +3641(none.)X +3 f +776 4131(\256le)N +1 f +976 4221(A)N +1055(pattern)X +1299(used)X +1467(to)X +1550(derive)X +1772(a)X +1829(pathname;)X +2184(the)X +2303(default)X +2547(is)X +2621(the)X +2740(current)X +2989(\256le.)X +3152(File)X +3297(names)X +3524(are)X +3645(subjected)X +3970(to)X +976 4311(normal)N +2 f +1223(sh)X +1 f +1294(\(1\))X +1408(word)X +1593(expansions.)X +976 4434(Anywhere)N +1336(a)X +1397(\256le)X +1524(name)X +1723(is)X +1801(speci\256ed,)X +2131(it)X +2200(is)X +2279(also)X +2434(possible)X +2722(to)X +2810(use)X +2943(the)X +3067(special)X +3316(string)X +3524(``)X +7 f +3578(/tmp)X +1 f +(''.)S +3890(This)X +776 4524(will)N +936(be)X +1048(replaced)X +1357(with)X +1535(a)X +1607(temporary)X +1973(\256le)X +2111(name)X +2321(which)X +2553(can)X +2701(be)X +2813(used)X +2996(for)X +3126(temporary)X +3491(work,)X +3711(e.g.)X +3882(``)X +7 f +3936(:e)X +776 4614(/tmp)N +1 f +('')S +1042(creates)X +1286(and)X +1422(edits)X +1593(a)X +1649(new)X +1803(\256le.)X +976 4737(If)N +1052(both)X +1216(a)X +1274(count)X +1474(and)X +1613(a)X +1672(range)X +1874(are)X +1996(speci\256ed)X +2304(for)X +2421(commands)X +2791(that)X +2934(use)X +3064(either,)X +3290(the)X +3411(starting)X +3674(line)X +3817(for)X +3934(the)X +776 4827(command)N +1120(is)X +1200(the)X +2 f +1325(last)X +1 f +1467(line)X +1614(addressed)X +1958(by)X +2065(the)X +2190(range,)X +2416(and)X +7 f +2559(count)X +1 f +(-)S +2853(subsequent)X +3236(lines)X +3414(are)X +3540(affected)X +3827(by)X +3934(the)X +776 4917(command,)N +1132(e.g.)X +1268(the)X +1386(command)X +1722(``)X +7 f +1776(2,3p4)X +1 f +('')S +2090(prints)X +2292(out)X +2414(lines)X +2585(3,)X +2665(4,)X +2745(5)X +2805(and)X +2941(6.)X +976 5040(When)N +1188(only)X +1350(a)X +1406(line)X +1546(or)X +1633(range)X +1833(is)X +1907(speci\256ed,)X +2233(with)X +2396(no)X +2497(command,)X +2854(the)X +2973(implied)X +3238(command)X +3575(is)X +3649(either)X +3853(a)X +3 f +3910(list)X +1 f +4012(,)X +3 f +776 5130(number)N +1 f +1073(or)X +3 f +1166(print)X +1 f +1365(command.)X +1747(The)X +1898(command)X +2240(used)X +2413(is)X +2492(the)X +2616(most)X +2797(recent)X +3020(of)X +3112(the)X +3235(three)X +3421(commands)X +3793(to)X +3880(have)X +776 5220(been)N +949(used)X +1117(\(including)X +1467(any)X +1604(use)X +1732(as)X +1820(a)X +1877(\257ag\).)X +2085(If)X +2160(none)X +2337(of)X +2425(these)X +2611(commands)X +2979(have)X +3152(been)X +3325(used)X +3493(before,)X +3740(the)X +3 f +3859(print)X +1 f +776 5310(command)N +1117(is)X +1195(the)X +1318(implied)X +1587(command.)X +1968(When)X +2185(no)X +2290(range)X +2494(or)X +2585(count)X +2787(is)X +2864(speci\256ed)X +3173(and)X +3313(the)X +3435(command)X +3775(line)X +3919(is)X +3996(a)X +776 5400(blank)N +974(line,)X +1134(the)X +1252(current)X +1500(line)X +1640(is)X +1713(incremented)X +2130(by)X +2230(1)X +2290(and)X +2426(then)X +2584(the)X +2702(current)X +2950(line)X +3090(is)X +3163(displayed.)X +976 5523(Zero)N +1149(or)X +1237(more)X +1423(whitespace)X +1801(characters)X +2149(may)X +2308(precede)X +2580(or)X +2668(follow)X +2898(the)X +3017(addresses,)X +3366(count,)X +3585(\257ags,)X +3778(or)X +3867(com-)X +776 5613(mand)N +980(name.)X +1220(Any)X +1384(object)X +1606(following)X +1943(a)X +2004(command)X +2345(name)X +2544(\(such)X +2743(as)X +2835(buffer,)X +3077(\256le,)X +3224(etc.\),)X +3410(that)X +3555(begins)X +3789(with)X +3956(an)X +776 5703(alphabetic)N +1130(character,)X +1471(should)X +1709(be)X +1810(separated)X +2139(from)X +2320(the)X +2443(command)X +2784(name)X +2983(by)X +3088(at)X +3171(least)X +3343(one)X +3484(whitespace)X +3866(char-)X +776 5793(acter.)N + +34 p +%%Page: 34 33 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-34)N +2813(Nvi/Nex)X +3109 0.3906(Reference)AX +3474(\(Ex)X +3614(Commands\))X +1 f +976 762(Any)N +1148(character,)X +1498(including)X +7 f +1834(<carriage-return>)X +1 f +(,)S +2704(``)X +7 f +2758(%)X +1 f +('')S +2894(and)X +3045(``)X +7 f +3099(#)X +1 f +('')S +3236(retain)X +3454(their)X +3636(literal)X +3858(value)X +776 852(when)N +970(preceded)X +1281(by)X +1381(a)X +1437(backslash.)X +3 f +776 1038(14.)N +916(Ex)X +1029(Commands)X +1 f +976 1161(The)N +1122(following)X +1454(section)X +1702(describes)X +2022(the)X +2141(commands)X +2509(available)X +2820(in)X +2903(the)X +3 f +3023(ex)X +1 f +3121(editor.)X +3370(In)X +3459(each)X +3629(entry)X +3816(below,)X +776 1251(the)N +894(tag)X +1012(line)X +1152(is)X +1225(a)X +1281(usage)X +1484(synopsis)X +1779(for)X +1893(the)X +2011(command.)X +976 1374(Each)N +1161(command)X +1501(can)X +1637(be)X +1737(entered)X +1998(as)X +2089(the)X +2211(abbreviation)X +2636(\(those)X +2856(characters)X +3207(in)X +3293(the)X +3416(synopsis)X +3716(command)X +776 1464(word)N +966(preceding)X +1307(the)X +1429(``['')X +1588 0.3375(character\),)AX +1955(the)X +2077(full)X +2212(command)X +2552(\(all)X +2683(characters)X +3034(shown)X +3267(for)X +3385(the)X +3507(command)X +3847(word,)X +776 1554(omitting)N +1067(the)X +1187(``['')X +1344(and)X +1482(``]'')X +1639 0.2955(characters\),)AX +2035(or)X +2124(any)X +2262(leading)X +2520(subset)X +2742(of)X +2831(the)X +2951(full)X +3084(command)X +3422(down)X +3622(to)X +3706(the)X +3826(abbre-)X +776 1644(viation.)N +1064(For)X +1201(example,)X +1519(the)X +1643(args)X +1803(command)X +2145(\(shown)X +2407(as)X +2500(``)X +7 f +2554(ar[gs])X +1 f +('')S +2922(in)X +3010(the)X +3134(synopsis\))X +3462(can)X +3600(be)X +3702(entered)X +3965(as)X +776 1734(``)N +7 f +830(ar)X +1 f +('',)S +1020(``)X +7 f +1074(arg)X +1 f +('')S +1292(or)X +1379(``)X +7 f +1433(args)X +1 f +(''.)S +976 1857(Each)N +3 f +1163(ex)X +1 f +1265(command)X +1607(described)X +1941(below)X +2163(notes)X +2359(the)X +2484(new)X +2645(current)X +2900(line)X +3047(after)X +3222(it)X +3293(is)X +3373(executed,)X +3706(as)X +3800(well)X +3965(as)X +776 1947(any)N +912(options)X +1167(that)X +1307(affect)X +1511(the)X +1629(command.)X +976 2127(A)N +1063(comment.)X +1430(Command)X +1792(lines)X +1972(beginning)X +2321(with)X +2492(the)X +2619(double-quote)X +3072(character)X +3398(\(``)X +7 f +3479(")X +1 f +(''\))S +3638(are)X +3767(ignored.)X +976 2217(This)N +1138(permits)X +1398(comments)X +1747(in)X +1829(editor)X +2036(scripts)X +2265(and)X +2401(startup)X +2639(\256les.)X +3 f +776 2397(<end-of-\256le>)N +1 f +976 2487(Scroll)N +1189(the)X +1309(screen.)X +1577(Write)X +1782(the)X +1902(next)X +2062(N)X +2142(lines,)X +2336(where)X +2556(N)X +2637(is)X +2713(the)X +2834(value)X +3031(of)X +3121(the)X +3 f +3242(scroll)X +1 f +3452(option.)X +3719(The)X +3867(com-)X +976 2577(mand)N +1191(is)X +1281(the)X +1416(end-of-\256le)X +1792(terminal)X +2096(character,)X +2449(which)X +2682(may)X +2857(be)X +2970(different)X +3284(on)X +3401(different)X +3714(terminals.)X +976 2667(Traditionally,)N +1434(it)X +1498(is)X +1571(the)X +7 f +1689(<control-D>)X +1 f +2237(key.)X +976 2847(Historically,)N +1397(the)X +3 f +1518(eof)X +1 f +1644(command)X +1984(ignored)X +2253(any)X +2393(preceding)X +2734(count,)X +2956(and)X +3096(the)X +7 f +3218(<end-of-file>)X +1 f +3866(char-)X +976 2937(acter)N +1155(was)X +1302(ignored)X +1569(unless)X +1791(it)X +1857(was)X +2004(entered)X +2263(as)X +2352(the)X +2472(\256rst)X +2618(character)X +2936(of)X +3025(the)X +3145(command.)X +3522(This)X +3685(implemen-)X +976 3027(tation)N +1178(treats)X +1372(it)X +1436(as)X +1523(a)X +1579(command)X +2 f +1915(only)X +1 f +2073(if)X +2142(entered)X +2399(as)X +2486(the)X +2604(\256rst)X +2748(character)X +3064(of)X +3151(the)X +3269(command)X +3605(line,)X +3766(and)X +3903(oth-)X +976 3117(erwise)N +1206(treats)X +1400(it)X +1464(as)X +1551(any)X +1687(other)X +1872(character.)X +976 3297(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(last)X +1789(line)X +1929(written.)X +976 3387(Options:)N +1336(None.)X +3 f +776 3567(!)N +823(argument\(s\))X +776 3657([range]!)N +1073(argument\(s\))X +1 f +976 3747(Execute)N +1263(a)X +1327(shell)X +1506(command,)X +1870(or)X +1966(\256lter)X +2146(lines)X +2326(through)X +2604(a)X +2669(shell)X +2849(command.)X +3234(In)X +3330(the)X +3457(\256rst)X +3610(synopsis,)X +3934(the)X +976 3837(remainder)N +1333(of)X +1430(the)X +1558(line)X +1708(after)X +1886(the)X +2014(``)X +7 f +2068(!)X +1 f +('')S +2220(character)X +2546(is)X +2629(passed)X +2873(to)X +2965(the)X +3093(program)X +3395(named)X +3639(by)X +3749(the)X +3 f +3877(shell)X +1 f +976 3927(option,)N +1220(as)X +1307(a)X +1363(single)X +1574(argument.)X +976 4107(Within)N +1227(the)X +1354(rest)X +1499(of)X +1595(the)X +1722(line,)X +1891(``)X +7 f +1945(%)X +1 f +('')S +2076(and)X +2221(``)X +7 f +2275(#)X +1 f +('')S +2407(are)X +2536(expanded)X +2874(into)X +3028(the)X +3156(current)X +3414(and)X +3560(alternate)X +3867(path-)X +976 4197(names,)N +1223(respectively.)X +1673(The)X +1820(character)X +2138(``)X +7 f +2192(!)X +1 f +('')S +2336(is)X +2411(expanded)X +2741(with)X +2904(the)X +3023(command)X +3360(text)X +3501(of)X +3589(the)X +3708(previous)X +3 f +4005(!)X +1 f +976 4287(command.)N +1354 0.3125(\(Therefore,)AX +1741(the)X +1861(command)X +3 f +2199(!!)X +1 f +2295(repeats)X +2545(the)X +2665(previous)X +3 f +2963(!)X +1 f +3032(command.\))X +3437(The)X +3585(special)X +3831(mean-)X +976 4377(ings)N +1130(of)X +1218(``)X +7 f +1272(%)X +1 f +('',)S +1415(``)X +7 f +1469(#)X +1 f +('',)S +1612(and)X +1749(``)X +7 f +1803(!)X +1 f +('')S +1946(can)X +2079(be)X +2176(overridden)X +2545(by)X +2646(escaping)X +2948(them)X +3129(with)X +3292(a)X +3349(backslash.)X +3722(If)X +3797(no)X +3 f +3898(!)X +1 f +3965(or)X +3 f +976 4467(:!)N +1 f +1075(command)X +1416(has)X +1548(yet)X +1671(been)X +1848(executed,)X +2179(it)X +2248(is)X +2326(an)X +2427(error)X +2609(to)X +2696(use)X +2828(an)X +2929(unescaped)X +3290(``)X +7 f +3344(!)X +1 f +('')S +3492(character.)X +3854(The)X +3 f +4005(!)X +1 f +976 4557(command)N +1325(does)X +2 f +1505(not)X +1 f +1640(do)X +1752(shell)X +1935(expansion)X +2292(on)X +2404(the)X +2534(strings)X +2779(provided)X +3096(as)X +3195(arguments.)X +3601(If)X +3687(any)X +3835(of)X +3934(the)X +976 4647(above)N +1197(expansions)X +1582(change)X +1839(the)X +1966(command)X +2311(the)X +2438(user)X +2602(entered,)X +2889(the)X +3017(command)X +3363(is)X +3446(redisplayed)X +3846(at)X +3934(the)X +976 4737(bottom)N +1222(of)X +1309(the)X +1427(screen.)X +3 f +976 4917(Ex)N +1 f +1092(then)X +1253(executes)X +1553(the)X +1674(program)X +1969(named)X +2206(by)X +2309(the)X +3 f +2430(shell)X +1 f +2608(option,)X +2855(with)X +3020(a)X +3 f +9 f +3079(-)X +3081(-)X +3 f +3125(c)X +1 f +3184(\257ag)X +3327(followed)X +3636(by)X +3740(the)X +3862(argu-)X +976 5007(ments)N +1187(\(which)X +1430(are)X +1549(bundled)X +1827(into)X +1971(a)X +2027(single)X +2238(argument\).)X +976 5187(The)N +3 f +1121(!)X +1 f +1188(command)X +1524(is)X +1597(permitted)X +1924(in)X +2006(an)X +2102(empty)X +2322(\256le.)X +976 5367(If)N +1050(the)X +1168(\256le)X +1290(has)X +1417(been)X +1589(modi\256ed)X +1893(since)X +2078(it)X +2142(was)X +2287(last)X +2418(completely)X +2794(written,)X +3061(the)X +3179(command)X +3515(will)X +3659(warn)X +3840(you.)X +976 5547(A)N +1054(single)X +1265(``)X +7 f +1319(!)X +1 f +('')S +1461(character)X +1777(is)X +1850(displayed)X +2177(when)X +2371(the)X +2489(command)X +2825(completes.)X +976 5727(In)N +1064(the)X +1183(second)X +1427(form)X +1604(of)X +1692(the)X +3 f +1811(!)X +1 f +1879(command,)X +2236(the)X +2355(remainder)X +2702(of)X +2790(the)X +2909(line)X +3051(after)X +3221(the)X +3341(``)X +7 f +3395(!)X +1 f +('')S +3539(is)X +3614(passed)X +3850(to)X +3934(the)X + +35 p +%%Page: 35 34 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Ex)X +1377(Commands\))X +3658(USD:13-35)X +1 f +976 762(program)N +1273(named)X +1512(by)X +1617(the)X +3 f +1740(shell)X +1 f +1920(option,)X +2169(as)X +2261(described)X +2594(above.)X +2851(The)X +3001(speci\256ed)X +3311(lines)X +3487(are)X +3610(passed)X +3848(to)X +3934(the)X +976 852(program)N +1273(as)X +1365(standard)X +1662(input,)X +1871(and)X +2012(the)X +2135(standard)X +2432(and)X +2573(standard)X +2871(error)X +3054(output)X +3284(of)X +3377(the)X +3501(program)X +3799(replace)X +976 942(the)N +1094(original)X +1363(lines.)X +976 1122(Line:)N +1336(Unchanged)X +1722(if)X +1791(no)X +1891(range)X +2090(was)X +2235(speci\256ed,)X +2560(otherwise)X +2892(set)X +3001(to)X +3083(the)X +3201(\256rst)X +3345(line)X +3485(of)X +3572(the)X +3690(range.)X +976 1212(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(autowrite)X +1 f +2206(and)X +3 f +2342(writeany)X +1 f +2665(options.)X +3 f +776 1392([range])N +1046(nu[mber])X +1391([count])X +1656([\257ags])X +776 1482([range])N +1046(#)X +1106([count])X +1371([\257ags])X +1 f +976 1572(Display)N +1245(the)X +1363(selected)X +1642(lines,)X +1833(each)X +2001(preceded)X +2312(with)X +2474(its)X +2569(line)X +2709(number.)X +976 1752(The)N +1121(line)X +1261(number)X +1526(format)X +1760(is)X +1833(``%6d'',)X +2128(followed)X +2433(by)X +2533(two)X +2673(spaces.)X +976 1932(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(last)X +1789(line)X +1929(displayed.)X +976 2022(Options:)N +1336(None.)X +3 f +776 2202(@)N +870(buffer)X +776 2292(*)N +836(buffer)X +1 f +976 2382(Execute)N +1255(a)X +1311(buffer.)X +1568(Each)X +1749(line)X +1890(in)X +1973(the)X +2092(named)X +2327(buffer)X +2545(is)X +2619(executed)X +2926(as)X +3014(an)X +3 f +3111(ex)X +1 f +3208(command.)X +3585(If)X +3660(no)X +3761(buffer)X +3979(is)X +976 2472(speci\256ed,)N +1301(or)X +1388(if)X +1457(the)X +1575(speci\256ed)X +1880(buffer)X +2097(is)X +2170(``)X +7 f +2224(@)X +1 f +('')S +2346(or)X +2433(``)X +7 f +2487(*)X +1 f +('',)S +2629(the)X +2747(last)X +2878(buffer)X +3095(executed)X +3401(is)X +3474(used.)X +3 f +776 2652([range])N +1046(<[<)X +1185(...])X +1292([count])X +1557([\257ags])X +1 f +976 2742(Shift)N +1154(lines)X +1328(left)X +1458(or)X +1548(right.)X +1762(The)X +1910(speci\256ed)X +2218(lines)X +2392(are)X +2514(shifted)X +2755(to)X +2840(the)X +2961(left)X +3091(\(for)X +3235(the)X +3 f +3356(<)X +1 f +3425(command\))X +3791(or)X +3881(right)X +976 2832(\(for)N +1130(the)X +3 f +1261(>)X +1 f +1340(command\),)X +1736(by)X +1849(the)X +1980(number)X +2257(of)X +2356(columns)X +2659(speci\256ed)X +2976(by)X +3088(the)X +3 f +3218(shiftwidth)X +1 f +3596(option.)X +3872(Only)X +976 2922(leading)N +1237(whitespace)X +1619(characters)X +1971(are)X +2095(deleted)X +2352(when)X +2552(shifting)X +2822(left;)X +2977(once)X +3155(the)X +3279(\256rst)X +3429(column)X +3695(of)X +3788(the)X +3912(line)X +976 3012(contains)N +1283(a)X +1359(nonblank)X +1697(character,)X +2053(the)X +3 f +2191(shift)X +1 f +2382(command)X +2738(will)X +2901(succeed,)X +3215(but)X +3356(the)X +3493(line)X +3652(will)X +3815(not)X +3956(be)X +976 3102(modi\256ed.)N +976 3282(If)N +1050(the)X +1168(command)X +1504(character)X +3 f +1820(<)X +1 f +1886(or)X +3 f +1973(>)X +1 f +2039(is)X +2112(repeated)X +2405(more)X +2590(than)X +2748(once,)X +2941(the)X +3060(command)X +3397(is)X +3471(repeated)X +3765(once)X +3938(for)X +976 3372(each)N +1144(additional)X +1484(command)X +1820(character.)X +976 3552(Line:)N +1336(If)X +1416(the)X +1540(current)X +1794(line)X +1940(is)X +2019(set)X +2134(to)X +2222(one)X +2364(of)X +2457(the)X +2581(lines)X +2758(that)X +2904(are)X +3029(affected)X +3315(by)X +3421(the)X +3545(command,)X +3908(it)X +3979(is)X +1336 3642(unchanged.)N +1751(Otherwise,)X +2128(it)X +2199(is)X +2279(set)X +2395(to)X +2484(the)X +2609(\256rst)X +2760(nonblank)X +3085(character)X +3408(of)X +3502(the)X +3627(lowest)X +3863(num-)X +1336 3732(bered)N +1535(line)X +1675(shifted.)X +976 3822(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(shiftwidth)X +1 f +2222(option.)X +3 f +776 4002([line])N +974(=)X +1040([\257ags])X +1 f +976 4092(Display)N +1250(the)X +1373(line)X +1518(number.)X +1828(Display)X +2102(the)X +2225(line)X +2370(number)X +2640(of)X +7 f +2732(line)X +1 f +2949(\(which)X +3197(defaults)X +3476(to)X +3563(the)X +3687(last)X +3824(line)X +3970(in)X +976 4182(the)N +1094(\256le\).)X +976 4362(Line:)N +1336(Unchanged.)X +976 4452(Options:)N +1336(None.)X +3 f +776 4632([range])N +1046(>[>)X +1185(...])X +1292([count])X +1557([\257ags])X +1 f +976 4722(Shift)N +1155(right.)X +1370(The)X +1519(speci\256ed)X +1828(lines)X +2003(are)X +2127(shifted)X +2370(to)X +2457(the)X +2580(right)X +2756(by)X +2861(the)X +2984(number)X +3254(of)X +3346(columns)X +3642(speci\256ed)X +3952(by)X +976 4812(the)N +3 f +1094(shiftwidth)X +1 f +1460(option,)X +1704(by)X +1804(inserting)X +2104(tab)X +2222(and)X +2358(space)X +2557(characters.)X +2944(Empty)X +3177(lines)X +3348(are)X +3467(not)X +3589(changed.)X +976 4992(If)N +1053(the)X +1174(command)X +1513(character)X +1832(``)X +7 f +1886(>)X +1 f +('')S +2011(is)X +2087(repeated)X +2383(more)X +2571(than)X +2732(once,)X +2927(the)X +3048(command)X +3388(is)X +3465(repeated)X +3762(once)X +3938(for)X +976 5082(each)N +1144(additional)X +1484(command)X +1820(character.)X +976 5262(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(last)X +1789(line)X +1929(modi\256ed)X +2233(by)X +2333(the)X +2451(command.)X +976 5352(Options:)N +1336(None.)X +3 f +776 5532(ab[brev])N +1090(lhs)X +1207(rhs)X +1 f +976 5622(Add)N +1135(an)X +1232(abbreviation)X +1654(to)X +1737(the)X +1856(current)X +2105(abbreviation)X +2527(list.)X +2686(In)X +3 f +2775(vi)X +1 f +2837(,)X +2879(if)X +7 f +2950(lhs)X +1 f +3116(is)X +3191(entered)X +3450(such)X +3619(that)X +3761(it)X +3827(is)X +3902(pre-)X +976 5712(ceded)N +1194(and)X +1340(followed)X +1655(by)X +1765(characters)X +2122(that)X +2272(cannot)X +2516(be)X +2622(part)X +2777(of)X +2874(a)X +2940(word,)X +3155(it)X +3229(is)X +3312(replaced)X +3614(by)X +3723(the)X +3850(string)X +7 f +976 5802(rhs)N +1 f +(.)S + +36 p +%%Page: 36 35 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-36)N +2813(Nvi/Nex)X +3109 0.3906(Reference)AX +3474(\(Ex)X +3614(Commands\))X +1 f +976 762(Line:)N +1336(Unchanged.)X +976 852(Options:)N +1336(None.)X +3 f +776 1032([line])N +974(a[ppend][!])X +1 f +976 1122(The)N +1123(input)X +1309(text)X +1451(is)X +1526(appended)X +1856(to)X +1940(the)X +2060(speci\256ed)X +2367(line.)X +2549(If)X +2626(line)X +2769(0)X +2832(is)X +2908(speci\256ed,)X +3236(the)X +3357(text)X +3500(is)X +3576(inserted)X +3853(at)X +3934(the)X +976 1212(beginning)N +1317(of)X +1405(the)X +1524(\256le.)X +1687(Set)X +1810(to)X +1893(the)X +2012(last)X +2144(line)X +2285(input.)X +2510(If)X +2585(no)X +2686(lines)X +2858(are)X +2978(input,)X +3183(then)X +3342(set)X +3451(to)X +7 f +3533(line)X +1 f +(,)S +3765(or)X +3852(to)X +3934(the)X +976 1302(\256rst)N +1125(line)X +1270(of)X +1362(the)X +1485(\256le)X +1612(if)X +1686(a)X +7 f +1747(line)X +1 f +1965(of)X +2058(0)X +2124(was)X +2275(speci\256ed.)X +2626(Following)X +2980(the)X +3104(command)X +3446(name)X +3646(with)X +3814(a)X +3876(``)X +7 f +3930(!)X +1 f +('')S +976 1392(character)N +1292(causes)X +1522(the)X +3 f +1640(autoindent)X +1 f +2028(option)X +2252(to)X +2334(be)X +2430(toggled)X +2690(for)X +2804(the)X +2922(duration)X +3209(of)X +3296(the)X +3414(command.)X +976 1572(Line:)N +1336(Unchanged.)X +976 1662(Options:)N +1336(Affected)X +1661(by)X +1784(the)X +3 f +1925(altwerase)X +1 f +2251(,)X +3 f +2314(autoindent)X +1 f +2682(,)X +3 f +2746(beautify)X +1 f +(,)S +3 f +3090(showmatch)X +1 f +3477(,)X +3 f +3541(ttywerase)X +1 f +3916(and)X +3 f +1336 1752(wrapmargin)N +1 f +1783(options.)X +3 f +776 1932(ar[gs])N +1 f +976 2022(Display)N +1248(the)X +1369(argument)X +1695(list.)X +1855(The)X +2003(current)X +2254(argument)X +2580(is)X +2657(displayed)X +2988(inside)X +3203(of)X +3294(``)X +7 f +3348([)X +1 f +('')S +3474(and)X +3614(``)X +7 f +3668(])X +1 f +('')S +3794(charac-)X +976 2112(ters.)N +1154(The)X +1300(argument)X +1624(list)X +1742(is)X +1816(the)X +1935(list)X +2053(of)X +2141(operands)X +2452(speci\256ed)X +2758(on)X +2859(startup,)X +3118(which)X +3335(can)X +3468(be)X +3565(replaced)X +3859(using)X +976 2202(the)N +3 f +1094(next)X +1 f +1261(command.)X +976 2382(Line:)N +1336(Unchanged.)X +976 2472(Options:)N +1336(None.)X +3 f +776 2652(bg)N +976 2742(Vi)N +1 f +1076(mode)X +1274(only.)X +1476(Background)X +1888(the)X +2006(current)X +2254(screen.)X +976 2922(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(current)X +1906(line)X +2046(when)X +2240(the)X +2358(screen)X +2584(was)X +2729(last)X +2860(edited.)X +976 3012(Options:)N +1336(None.)X +3 f +776 3192([range])N +1046(c[hange][!])X +1441([count])X +1 f +976 3282(Replace)N +1256(the)X +1375(lines)X +1548(with)X +1712(input)X +1898(text.)X +2080(Following)X +2430(the)X +2550(command)X +2888(name)X +3084(with)X +3248(a)X +3306(``)X +7 f +3360(!)X +1 f +('')S +3504(character)X +3822(causes)X +976 3372(the)N +3 f +1094(autoindent)X +1 f +1482(option)X +1706(to)X +1788(be)X +1884(toggled)X +2144(for)X +2258(the)X +2376(duration)X +2663(of)X +2750(the)X +2868(command.)X +976 3552(Line:)N +1336(Set)X +1463(to)X +1550(the)X +1673(last)X +1809(line)X +1954(input,)X +2163(or,)X +2275(if)X +2349(no)X +2454(lines)X +2630(were)X +2812(input,)X +3021(set)X +3135(to)X +3223(the)X +3347(line)X +3493(before)X +3725(the)X +3849(target)X +1336 3642(line,)N +1496(or)X +1583(to)X +1665(the)X +1783(\256rst)X +1927(line)X +2067(of)X +2154(the)X +2272(\256le)X +2394(if)X +2463(there)X +2644(are)X +2763(no)X +2863(lines)X +3034(preceding)X +3371(the)X +3489(target)X +3692(line.)X +976 3732(Options:)N +1336(Affected)X +1661(by)X +1784(the)X +3 f +1925(altwerase)X +1 f +2251(,)X +3 f +2314(autoindent)X +1 f +2682(,)X +3 f +2746(beautify)X +1 f +(,)S +3 f +3090(showmatch)X +1 f +3477(,)X +3 f +3541(ttywerase)X +1 f +3916(and)X +3 f +1336 3822(wrapmargin)N +1 f +1783(options.)X +3 f +776 4002(chd[ir][!])N +1113([directory])X +776 4092(cd[!])N +957([directory])X +1 f +976 4182(Change)N +1244(the)X +1365(current)X +1616(working)X +1906(directory.)X +2259(The)X +7 f +2407(directory)X +1 f +2862(argument)X +3188(is)X +3265(subjected)X +3592(to)X +2 f +3678(sh)X +1 f +3749(\(1\))X +3867(word)X +976 4272(expansions.)N +1395(When)X +1610(invoked)X +1891(with)X +2056(no)X +2159(directory)X +2472(argument)X +2798(and)X +2937(the)X +7 f +3057(HOME)X +1 f +3271(environment)X +3698(variable)X +3979(is)X +976 4362(set,)N +1105(the)X +1223(directory)X +1533(named)X +1767(by)X +1867(the)X +7 f +1985(HOME)X +1 f +2197(environment)X +2622(variable)X +2901(becomes)X +3202(the)X +3320(new)X +3474(current)X +3722(directory.)X +976 4452(Otherwise,)N +1353(the)X +1478(new)X +1639(current)X +1894(directory)X +2211(becomes)X +2519(the)X +2644(directory)X +2961(returned)X +3256(by)X +3363(the)X +2 f +3488(getpwent)X +1 f +3777(\(3\))X +3898(rou-)X +976 4542(tine.)N +976 4722(The)N +3 f +1125(chdir)X +1 f +1331(command)X +1671(will)X +1819(fail)X +1950(if)X +2023(the)X +2145(\256le)X +2271(has)X +2402(been)X +2578(modi\256ed)X +2886(since)X +3075(the)X +3197(last)X +3333(complete)X +3652(write)X +3842(of)X +3934(the)X +976 4812(\256le.)N +1138(You)X +1296(can)X +1428(override)X +1716(this)X +1851(check)X +2059(by)X +2159(appending)X +2513(a)X +2569(``)X +7 f +2623(!)X +1 f +('')S +2765(character)X +3081(to)X +3163(the)X +3281(command.)X +976 4992(Line:)N +1336(Unchanged.)X +976 5082(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(cdpath)X +1 f +2111(option.)X +3 f +776 5262([range])N +1046(co[py])X +1280(line)X +1424([\257ags])X +776 5352([range])N +1046(t)X +1093(line)X +1237([\257ags])X +1 f +976 5442(Copy)N +1169(the)X +1288(speci\256ed)X +1594(lines)X +1766(\(range\))X +2020(after)X +2189(the)X +2308(destination)X +2680(line.)X +2861(Line)X +3029(0)X +3090(may)X +3249(be)X +3346(speci\256ed)X +3652(to)X +3735(insert)X +3934(the)X +976 5532(lines)N +1147(at)X +1225(the)X +1343(beginning)X +1683(of)X +1770(the)X +1888(\256le.)X +976 5712(Line:)N +1336(Unchanged.)X + +37 p +%%Page: 37 36 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Ex)X +1377(Commands\))X +3658(USD:13-37)X +1 f +976 762(Options:)N +1336(None.)X +3 f +776 942([range])N +1046(d[elete])X +1321([buffer])X +1609([count])X +1874([\257ags])X +1 f +976 1032(Delete)N +1208(the)X +1329(lines)X +1503(from)X +1682(the)X +1803(\256le.)X +1968(The)X +2116(deleted)X +2371(text)X +2514(is)X +2590(saved)X +2796(in)X +2881(the)X +3002(speci\256ed)X +3310(buffer,)X +3550(or,)X +3660(if)X +3732(no)X +3835(buffer)X +976 1122(is)N +1051(speci\256ed,)X +1378(in)X +1462(the)X +1582(unnamed)X +1898(buffer.)X +2157(If)X +2233(the)X +2353(command)X +2691(name)X +2887(is)X +2962(followed)X +3269(by)X +3371(a)X +3429(letter)X +3616(that)X +3757(could)X +3956(be)X +976 1212(interpreted)N +1346(as)X +1435(either)X +1640(a)X +1698(buffer)X +1917(name)X +2113(or)X +2202(a)X +2261(\257ag)X +2404(value)X +2601(\(because)X +2906(neither)X +3152(a)X +7 f +3211(count)X +1 f +3474(or)X +7 f +3564(flags)X +1 f +3827(values)X +976 1302(were)N +1160(given\),)X +3 f +1412(ex)X +1 f +1515(treats)X +1716(the)X +1841(letter)X +2033(as)X +2127(a)X +7 f +2190(flags)X +1 f +2457(value)X +2658(if)X +2734(the)X +2859(letter)X +3051(immediately)X +3477(follows)X +3743(the)X +3867(com-)X +976 1392(mand)N +1174(name,)X +1388(without)X +1652(any)X +1788(whitespace)X +2165(separation.)X +2555(If)X +2629(the)X +2747(letter)X +2932(is)X +3005(preceded)X +3316(by)X +3416(whitespace)X +3794(charac-)X +976 1482(ters,)N +1132(it)X +1196(treats)X +1390(it)X +1454(as)X +1541(a)X +1597(buffer)X +1814(name.)X +976 1662(Line:)N +1336(Set)X +1459(to)X +1542(the)X +1661(line)X +1802(following)X +2134(the)X +2253(deleted)X +2506(lines,)X +2698(or)X +2786(to)X +2869(the)X +2988(last)X +3120(line)X +3261(if)X +3331(the)X +3450(deleted)X +3703(lines)X +3875(were)X +1336 1752(at)N +1414(the)X +1532(end.)X +976 1842(Options:)N +1336(None.)X +3 f +776 2022(di[splay])N +1093(b[uffers])X +1412(|)X +1450(s[creens])X +1774(|)X +1812(t[ags])X +1 f +976 2112(Display)N +1256(buffers,)X +1535(screens)X +1803(or)X +1901(tags.)X +2101(The)X +3 f +2257(display)X +1 f +2531(command)X +2878(takes)X +3074(one)X +3221(of)X +3319(three)X +3511(additional)X +3862(argu-)X +976 2202(ments,)N +1207(which)X +1423(are)X +1542(as)X +1629(follows:)X +976 2382(b[uffers])N +1336(Display)X +1605(all)X +1705(buffers)X +1953(\(including)X +2302(named,)X +2556(unnamed,)X +2890(and)X +3026(numeric\))X +3336(that)X +3476(contain)X +3732(text.)X +976 2472(s[creens])N +1336(Display)X +1605(the)X +1723(\256le)X +1845(names)X +2070(of)X +2157(all)X +2257(background)X +2656(screens.)X +976 2562(t[ags])N +1336(Display)X +1605(the)X +1723(tags)X +1872(stack.)X +976 2742(Line:)N +1336(Unchanged.)X +976 2832(Options:)N +1336(None.)X +3 f +776 3012(e[dit][!])N +1060([+cmd])X +1327([\256le])X +776 3102(ex[!])N +953([+cmd])X +1220([\256le])X +1 f +976 3192(Edit)N +1133(a)X +1193(different)X +1494(\256le.)X +1661(If)X +1740(the)X +1863(current)X +2116(buffer)X +2338(has)X +2470(been)X +2647(modi\256ed)X +2956(since)X +3146(the)X +3269(last)X +3405(complete)X +3724(write,)X +3934(the)X +976 3282(command)N +1324(will)X +1480(fail.)X +1659(You)X +1829(can)X +1972(override)X +2271(this)X +2417(by)X +2528(appending)X +2893(a)X +2960(``)X +7 f +3014(!)X +1 f +('')S +3167(character)X +3494(to)X +3587(the)X +3716(command)X +976 3372(name.)N +976 3552(If)N +1053(the)X +1174(``)X +7 f +1228(+cmd)X +1 f +('')S +1497(option)X +1724(is)X +1800(speci\256ed,)X +2128(that)X +3 f +2271(ex)X +1 f +2370(command)X +2709(will)X +2856(be)X +2955(executed)X +3264(in)X +3349(the)X +3470(new)X +3628(\256le.)X +3794(Any)X +3 f +3956(ex)X +1 f +976 3642(command)N +1326(may)X +1498(be)X +1607(used,)X +1807(although)X +2120(the)X +2251(most)X +2439(common)X +2752(use)X +2892(of)X +2992(this)X +3140(feature)X +3397(is)X +3483(to)X +3578(specify)X +3843(a)X +3912(line)X +976 3732(number)N +1241(or)X +1328(search)X +1554(pattern)X +1797(to)X +1879(set)X +1988(the)X +2106(initial)X +2312(location)X +2590(in)X +2672(the)X +2790(new)X +2944(\256le.)X +976 3912(Line:)N +1336(If)X +1415(you)X +1560(have)X +1737(previously)X +2100(edited)X +2321(the)X +2444(\256le,)X +2591(the)X +2714(current)X +2967(line)X +3112(will)X +3261(be)X +3362(set)X +3476(to)X +3563(your)X +3735(last)X +3872(posi-)X +1336 4002(tion)N +1482(in)X +1566(the)X +1686(\256le.)X +1850(If)X +1926(that)X +2068(position)X +2347(does)X +2516(not)X +2640(exist,)X +2833(or)X +2921(you)X +3062(have)X +3235(not)X +3358(previously)X +3717(edited)X +3934(the)X +1336 4092(\256le,)N +1481(the)X +1602(current)X +1853(line)X +1996(will)X +2143(be)X +2242(set)X +2354(to)X +2439(the)X +2560(\256rst)X +2707(line)X +2850(of)X +2940(the)X +3061(\256le)X +3186(if)X +3258(you)X +3401(are)X +3523(in)X +3 f +3608(vi)X +1 f +3694(mode,)X +3916(and)X +1336 4182(the)N +1454(last)X +1585(line)X +1725(of)X +1812(the)X +1930(\256le)X +2052(if)X +2121(you)X +2261(are)X +2380(in)X +3 f +2462(ex)X +1 f +2538(.)X +976 4272(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(autowrite)X +1 f +2206(and)X +3 f +2342(writeany)X +1 f +2665(options.)X +3 f +776 4452(exu[sage])N +1117([command])X +1 f +976 4542(Display)N +1249(usage)X +1456(for)X +1574(an)X +3 f +1674(ex)X +1 f +1774(command.)X +2154(If)X +7 f +2233(command)X +1 f +2594(is)X +2672(speci\256ed,)X +3002(a)X +3063(usage)X +3271(statement)X +3603(for)X +3722(that)X +3867(com-)X +976 4632(mand)N +1174(is)X +1247(displayed.)X +1614(Otherwise,)X +1984(usage)X +2187(statements)X +2545(for)X +2659(all)X +3 f +2759(ex)X +1 f +2855(commands)X +3222(are)X +3341(displayed.)X +976 4812(Line:)N +1336(Unchanged.)X +976 4902(Options:)N +1336(None.)X +3 f +776 5082(f[ile])N +957([\256le])X +1 f +976 5172(Display)N +1249(and)X +1389(optionally)X +1737(change)X +1989(the)X +2111(\256le)X +2237(name.)X +2475(If)X +2553(a)X +2613(\256le)X +2739(name)X +2937(is)X +3014(speci\256ed,)X +3344(the)X +3467(current)X +3720(pathname)X +976 5262(is)N +1054(changed)X +1347(to)X +1434(the)X +1557(speci\256ed)X +1867(name.)X +2106(The)X +2256(current)X +2509(pathname,)X +2865(the)X +2987(number)X +3256(of)X +3347(lines,)X +3542(and)X +3682(the)X +3804(current)X +976 5352(position)N +1253(in)X +1335(the)X +1453(\256le)X +1575(are)X +1694(displayed.)X +976 5532(Line:)N +1336(Unchanged.)X +976 5622(Options:)N +1336(None.)X + +38 p +%%Page: 38 37 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-38)N +2813(Nvi/Nex)X +3109 0.3906(Reference)AX +3474(\(Ex)X +3614(Commands\))X +776 762(fg)N +863([name])X +976 852(Vi)N +1 f +1085(mode)X +1292(only.)X +1503(Foreground)X +1906(the)X +2033(speci\256ed)X +2347(screen.)X +2622(Swap)X +2829(the)X +2956(current)X +3213(screen)X +3448(with)X +3619(the)X +3747(speci\256ed)X +976 942(backgrounded)N +1451(screen.)X +1717(If)X +1791(no)X +1891(screen)X +2117(is)X +2190(speci\256ed,)X +2515(the)X +2633(\256rst)X +2777(background)X +3176(screen)X +3402(is)X +3475(foregrounded.)X +976 1122(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(current)X +1906(line)X +2046(when)X +2240(the)X +2358(screen)X +2584(was)X +2729(last)X +2860(edited.)X +976 1212(Options:)N +1336(None.)X +3 f +776 1392([range])N +1046(g[lobal])X +1328(/pattern/)X +1646([commands])X +776 1482([range])N +1046(v)X +1106(/pattern/)X +1424([commands])X +1 f +976 1572(Apply)N +1206(commands)X +1583(to)X +1675(lines)X +1856(matching)X +2184(\(or)X +2308(not)X +2440(matching\))X +2795(a)X +2861(pattern.)X +3154(The)X +3309(lines)X +3490(within)X +3725(the)X +3854(given)X +976 1662(range)N +1191(that)X +1347(match)X +1579(\(``)X +7 f +1660(g[lobal])X +1 f +(''\),)S +2181(or)X +2284(do)X +2400(not)X +2538(match)X +2770(\(``)X +7 f +2851(v)X +1 f +(''\))S +3015(the)X +3148(given)X +3361(pattern)X +3619(are)X +3753(selected.)X +976 1752(Then,)N +1197(the)X +1331(speci\256ed)X +3 f +1652(ex)X +1 f +1764(command\(s\))X +2201(are)X +2336(executed)X +2658(with)X +2836(the)X +2970(current)X +3235(line)X +3392(\(``)X +7 f +3473(.)X +1 f +(''\))S +3659(set)X +3785(to)X +3884(each)X +976 1842(selected)N +1257(line.)X +1439(If)X +1515(no)X +1617(range)X +1818(is)X +1893(speci\256ed,)X +2220(the)X +2340(entire)X +2545(\256le)X +2669(is)X +2744(searched)X +3048(for)X +3164(matching,)X +3503(or)X +3591(not)X +3714(matching,)X +976 1932(lines.)N +976 2112(Multiple)N +1279(commands)X +1654(can)X +1794(be)X +1899(speci\256ed,)X +2233(one)X +2378(per)X +2510(line,)X +2679(by)X +2788(escaping)X +3098(each)X +7 f +3275(<newline>)X +1 f +3736(character)X +976 2202(with)N +1152(a)X +1222(backslash,)X +1588(or)X +1689(by)X +1803(separating)X +2167(commands)X +2548(with)X +2724(a)X +2794(``)X +7 f +2848(|)X +1 f +('')S +2984(character.)X +3353(If)X +3440(no)X +3553(commands)X +3933(are)X +976 2292(speci\256ed,)N +1301(the)X +1419(command)X +1755(defaults)X +2029(to)X +2111(the)X +3 f +2229(print)X +1 f +2422(command.)X +976 2472(For)N +1111(the)X +3 f +1233(append)X +1 f +1485(,)X +3 f +1529(change)X +1 f +1793(and)X +3 f +1933(insert)X +1 f +2153(commands,)X +2544(the)X +2666(input)X +2854(text)X +2998(must)X +3177(be)X +3277(part)X +3427(of)X +3519(the)X +3642(global)X +3867(com-)X +976 2562(mand)N +1174(line.)X +1354(In)X +1441(this)X +1576(case,)X +1755(the)X +1873(terminating)X +2262(period)X +2487(can)X +2619(be)X +2715(omitted)X +2979(if)X +3048(it)X +3112(ends)X +3279(the)X +3397(commands.)X +976 2742(The)N +3 f +1123(visual)X +1 f +1344(command)X +1682(may)X +1842(also)X +1993(be)X +2091(speci\256ed)X +2398(as)X +2487(one)X +2625(of)X +2714(the)X +3 f +2834(ex)X +1 f +2933(commands.)X +3343(In)X +3433(this)X +3571(mode,)X +3792(input)X +3979(is)X +976 2832(taken)N +1173(from)X +1352(the)X +1473(terminal.)X +1803(Entering)X +2102(a)X +3 f +2161(Q)X +1 f +2246(command)X +2585(in)X +3 f +2670(vi)X +1 f +2755(mode)X +2956(causes)X +3189(the)X +3310(next)X +3471(line)X +3614(matching)X +3934(the)X +976 2922(pattern)N +1219(to)X +1301(be)X +1397(selected)X +1676(and)X +3 f +1812(vi)X +1 f +1894(to)X +1976(be)X +2072(reentered,)X +2412(until)X +2578(the)X +2696(list)X +2813(is)X +2886(exhausted.)X +976 3102(The)N +3 f +1121(global)X +1 f +1329(,)X +3 f +1369(v)X +1 f +1429(and)X +3 f +1565(undo)X +1 f +1757(commands)X +2124(cannot)X +2358(be)X +2454(used)X +2621(as)X +2708(part)X +2853(of)X +2940(these)X +3125(commands.)X +976 3282(The)N +1131(editor)X +1348(options)X +3 f +1613(autoprint)X +1 f +1937(,)X +3 f +1987(autoindent)X +1 f +2355(,)X +2405(and)X +3 f +2551(report)X +1 f +2800(are)X +2929(turned)X +3164(off)X +3288(for)X +3412(the)X +3540(duration)X +3837(of)X +3934(the)X +3 f +976 3372(global)N +1 f +1204(and)X +3 f +1340(v)X +1 f +1400(commands.)X +976 3552(Line:)N +1336(The)X +1481(last)X +1612(line)X +1752(modi\256ed.)X +976 3642(Options:)N +1336(None.)X +3 f +776 3822(he[lp])N +1 f +3912(Display)Y +1245(a)X +1301(help)X +1459(message.)X +976 4092(Line:)N +1336(Unchanged.)X +976 4182(Options:)N +1336(None.)X +3 f +776 4362([line])N +974(i[nsert][!])X +1 f +976 4452(The)N +1123(input)X +1309(text)X +1451(is)X +1526(inserted)X +1803(before)X +2032(the)X +2153(speci\256ed)X +2461(line.)X +2644(Following)X +2995(the)X +3116(command)X +3455(name)X +3652(with)X +3817(a)X +3876(``)X +7 f +3930(!)X +1 f +('')S +976 4542(character)N +1292(causes)X +1522(the)X +3 f +1640(autoindent)X +1 f +2028(option)X +2252(setting)X +2485(to)X +2567(be)X +2663(toggled)X +2923(for)X +3037(the)X +3155(duration)X +3442(of)X +3529(this)X +3664(command.)X +976 4722(Line:)N +1336(Set)X +1460(to)X +1544(the)X +1664(last)X +1797(line)X +1939(input;)X +2147(if)X +2218(no)X +2320(lines)X +2493(were)X +2672(input,)X +2878(set)X +2989(to)X +3073(the)X +3193(line)X +3336(before)X +3565(the)X +3686(target)X +3892(line,)X +1336 4812(or)N +1423(to)X +1505(the)X +1623(\256rst)X +1767(line)X +1907(of)X +1994(the)X +2112(\256le)X +2234(if)X +2303(there)X +2484(are)X +2603(no)X +2703(lines)X +2874(preceding)X +3211(the)X +3329(target)X +3532(line.)X +976 4902(Options:)N +1336(Affected)X +1661(by)X +1784(the)X +3 f +1925(altwerase)X +1 f +2251(,)X +3 f +2314(autoindent)X +1 f +2682(,)X +3 f +2746(beautify)X +1 f +(,)S +3 f +3090(showmatch)X +1 f +3477(,)X +3 f +3541(ttywerase)X +1 f +3916(and)X +3 f +1336 4992(wrapmargin)N +1 f +1783(options.)X +3 f +776 5172([range])N +1046(j[oin][!])X +1334([count])X +1599([\257ags])X +1 f +976 5262(Join)N +1129(lines)X +1300(of)X +1387(text)X +1527(together.)X +976 5442(A)N +7 f +1056(count)X +1 f +1318(speci\256ed)X +1625(to)X +1709(the)X +1829(command)X +2167(speci\256es)X +2465(that)X +2607(the)X +2727(last)X +2860(line)X +3002(of)X +3091(the)X +7 f +3212(range)X +1 f +3475(plus)X +7 f +3631(count)X +1 f +3894(sub-)X +976 5532(sequent)N +1258(lines)X +1445(will)X +1605(be)X +1717(joined.)X +1993(\(Note,)X +2232(this)X +2383(differs)X +2629(by)X +2745(one)X +2897(from)X +3089(the)X +3223(general)X +3496(rule)X +3657(where)X +3890(only)X +7 f +976 5622(count)N +1 f +(-)S +1263(subsequent)X +1639(lines)X +1810(are)X +1929(affected.\))X +976 5802(If)N +1057(the)X +1182(current)X +1438(line)X +1586(ends)X +1761(with)X +1931(a)X +1995(whitespace)X +2380(character,)X +2724(all)X +2832(whitespace)X +3217(is)X +3298(stripped)X +3584(from)X +3768(the)X +3894(next)X + +39 p +%%Page: 39 38 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Ex)X +1377(Commands\))X +3658(USD:13-39)X +1 f +976 762(line.)N +1160(Otherwise,)X +1534(if)X +1607(the)X +1729(next)X +1891(line)X +2035(starts)X +2228(with)X +2394(a)X +2454(open)X +2634(parenthesis)X +3019(\(``)X +7 f +3100(\()X +1 f +(''\),)S +3272(do)X +3375(nothing.)X +3682(Otherwise,)X +976 852(if)N +1061(the)X +1195(current)X +1459(line)X +1615(ends)X +1798(with)X +1976(a)X +2049(question)X +2357(mark)X +2559(\(``)X +7 f +2640(?)X +1 f +(''\),)S +2826(period)X +3068(\(``)X +7 f +3149(.)X +1 f +(''\))S +3335(or)X +3439(exclamation)X +3868(point)X +976 942(\(``)N +7 f +1057(!)X +1 f +(''\),)S +1226(insert)X +1424(two)X +1564(spaces.)X +1834(Otherwise,)X +2204(insert)X +2402(a)X +2458(single)X +2669(space.)X +976 1122(Appending)N +1355(a)X +1414(``)X +7 f +1468(!)X +1 f +('')S +1613(character)X +1932(to)X +2017(the)X +2138(command)X +2477(name)X +2674(causes)X +2907(a)X +2966(simpler)X +3230(join)X +3378(with)X +3544(no)X +3648(white-space)X +976 1212(processing.)N +976 1392(Line:)N +1336(Unchanged.)X +976 1482(Options:)N +1336(None.)X +3 f +776 1662([range])N +1046(l[ist])X +1222([count])X +1487([\257ags])X +1 f +976 1752(Display)N +1258(the)X +1389(lines)X +1573(unambiguously.)X +2139(Tabs)X +2328(are)X +2460(displayed)X +2801(as)X +2902(``)X +7 f +2956(\303I)X +1 f +('',)S +3160(and)X +3310(the)X +3442(end)X +3592(of)X +3693(the)X +3825(line)X +3979(is)X +976 1842(marked)N +1237(with)X +1399(a)X +1455(``)X +7 f +1509($)X +1 f +('')S +1631(character.)X +976 2022(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(last)X +1789(line)X +1929(displayed.)X +976 2112(Options:)N +1336(None.)X +3 f +776 2292(map[!])N +1028([lhs)X +1172(rhs])X +1 f +976 2382(De\256ne)N +1210(or)X +1297(display)X +1548(maps)X +1737(\(for)X +3 f +1878(vi)X +1 f +1960(only\).)X +976 2562(If)N +1050(``)X +7 f +1104(lhs)X +1 f +('')S +1322(and)X +1458(``)X +7 f +1512(rhs)X +1 f +('')S +1730(are)X +1849(not)X +1971(speci\256ed,)X +2296(the)X +2414(current)X +2662(set)X +2771(of)X +2859(command)X +3196(mode)X +3395(maps)X +3585(are)X +3705(displayed.)X +976 2652(If)N +1050(a)X +1106(``)X +7 f +1160(!)X +1 f +('')S +1302(character)X +1618(is)X +1691(appended)X +2019(to)X +2101(to)X +2183(the)X +2301(command,)X +2657(the)X +2775(text)X +2915(input)X +3099(mode)X +3297(maps)X +3486(are)X +3605(displayed.)X +976 2832(Otherwise,)N +1365(when)X +1578(the)X +1715(``)X +7 f +1769(lhs)X +1 f +('')S +2006(character)X +2342(sequence)X +2677(is)X +2770(entered)X +3047(in)X +3 f +3149(vi)X +1 f +3211(,)X +3271(the)X +3409(action)X +3645(is)X +3738(as)X +3845(if)X +3934(the)X +976 2922(corresponding)N +1466(``)X +7 f +1520(rhs)X +1 f +('')S +1749(had)X +1896(been)X +2079(entered.)X +2387(If)X +2472(a)X +2539(``)X +7 f +2593(!)X +1 f +('')S +2746(character)X +3073(is)X +3157(appended)X +3496(to)X +3588(the)X +3716(command)X +976 3012(name,)N +1196(the)X +1320(mapping)X +1626(is)X +1705(effective)X +2013(during)X +2249(text)X +2396(input)X +2587(mode,)X +2812(otherwise,)X +3171(it)X +3242(is)X +3322(effective)X +3631(during)X +3867(com-)X +976 3102(mand)N +1175(mode.)X +1414(This)X +1577(allows)X +1807(``)X +7 f +1861(lhs)X +1 f +('')S +2080(to)X +2163(have)X +2336(two)X +2476(different)X +2773(macro)X +2994(de\256nitions)X +3351(at)X +3429(the)X +3547(same)X +3732(time:)X +3916(one)X +976 3192(for)N +1090(command)X +1426(mode)X +1624(and)X +1760(one)X +1896(for)X +2010(input)X +2194(mode.)X +976 3372(Whitespace)N +1373(characters)X +1722(require)X +1972(escaping)X +2275(with)X +2439(a)X +7 f +2497(<literal)X +1 f +(next>)S +3086(character)X +3405(to)X +3490(be)X +3589(entered)X +3849(in)X +3934(the)X +7 f +976 3462(lhs)N +1 f +1140(string)X +1342(in)X +1424(visual)X +1635(mode.)X +976 3642(Normally,)N +1330(keys)X +1504(in)X +1593(the)X +7 f +1718(rhs)X +1 f +1889(string)X +2098(are)X +2224(remapped)X +2569(\(see)X +2727(the)X +3 f +2853(remap)X +1 f +3104(option\),)X +3383(and)X +3527(it)X +3599(is)X +3680(possible)X +3970(to)X +976 3732(create)N +1207(in\256nite)X +1471(loops.)X +1722(However,)X +2075(keys)X +2260(which)X +2494(map)X +2670(to)X +2770(themselves)X +3164(are)X +3300(not)X +3439(further)X +3695(remapped,)X +976 3822(regardless)N +1327(of)X +1419(the)X +1542(setting)X +1780(of)X +1872(the)X +3 f +1995(remap)X +1 f +2243(option.)X +2512(For)X +2648(example,)X +2966(the)X +3090(command)X +3432(``)X +7 f +3486(:map)X +3732(n)X +3834(nz.)X +1 f +('')S +976 3912(maps)N +1165(the)X +1283(``)X +7 f +1337(n)X +1 f +('')S +1459(key)X +1595(to)X +1677(the)X +3 f +1795(n)X +1 f +1859(and)X +3 f +1995(z)X +1 f +2051(commands.)X +976 4092(To)N +1085(exit)X +1225(an)X +1321(in\256nitely)X +1629(looping)X +1893(map,)X +2071(use)X +2198(the)X +2316(terminal)X +7 f +2603(<interrupt>)X +1 f +3151(character.)X +976 4272(Line:)N +1336(Unchanged.)X +976 4362(Options:)N +1336(None.)X +3 f +776 4542([line])N +974(ma[rk])X +1235 0.3125(<character>)AX +776 4632([line])N +974(k)X +1038 0.3125(<character>)AX +1 f +976 4722(Mark)N +1189(the)X +1326(line)X +1485(with)X +1666(the)X +1803(mark)X +7 f +2007(<character>)X +1 f +(.)S +2614(The)X +2778(expressions)X +3192(``)X +7 f +3246('<character>)X +1 f +('')S +3916(and)X +976 4812(``)N +7 f +1030(`<character>)X +1 f +('')S +1680(can)X +1812(then)X +1970(be)X +2066(used)X +2233(as)X +2320(an)X +2416(address)X +2677(in)X +2759(any)X +2895(command)X +3231(that)X +3371(uses)X +3529(one.)X +976 4992(Line:)N +1336(Unchanged.)X +976 5082(Options:)N +1336(None.)X +3 f +776 5262([range])N +1046(m[ove])X +1303(line)X +1 f +976 5352(Move)N +1188(the)X +1312(speci\256ed)X +1623(lines)X +1800(after)X +1974(the)X +2098(target)X +2307(line.)X +2493(A)X +2577(target)X +2786(line)X +2932(of)X +3025(0)X +3091(places)X +3318(the)X +3442(lines)X +3619(at)X +3703(the)X +3827(begin-)X +976 5442(ning)N +1138(of)X +1225(the)X +1343(\256le.)X +976 5622(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(\256rst)X +1802(of)X +1889(the)X +2007(moved)X +2245(lines.)X +976 5712(Options:)N +1336(None.)X + +40 p +%%Page: 40 39 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-40)N +2813(Nvi/Nex)X +3109 0.3906(Reference)AX +3474(\(Ex)X +3614(Commands\))X +776 762 0.3250(mk[exrc][!])AN +1190(\256le)X +1 f +976 852(Write)N +1180(the)X +1299(abbreviations,)X +1772(editor)X +1980(options)X +2237(and)X +2375(maps)X +2566(to)X +2650(the)X +2770(speci\256ed)X +3077(\256le.)X +3241(Information)X +3646(is)X +3721(written)X +3970(in)X +976 942(a)N +1034(form)X +1212(which)X +1430(can)X +1564(later)X +1729(be)X +1827(read)X +1988(back)X +2162(in)X +2246(using)X +2441(the)X +3 f +2561(ex)X +2659(source)X +1 f +2904(command.)X +3282(If)X +7 f +3358(file)X +1 f +3572(already)X +3830(exists,)X +976 1032(the)N +3 f +1097(mkexrc)X +1 f +1379(command)X +1718(will)X +1865(fail.)X +2035(This)X +2200(check)X +2411(can)X +2546(be)X +2645(overridden)X +3016(by)X +3119(appending)X +3476(a)X +3536(``)X +7 f +3590(!)X +1 f +('')S +3736(character)X +976 1122(to)N +1058(the)X +1176(command.)X +976 1302(Line:)N +1336(Unchanged.)X +976 1392(Options:)N +1336(None.)X +3 f +776 1572(n[ext][!])N +1078([\256le)X +1227(...])X +1 f +976 1662(Edit)N +1142(the)X +1273(next)X +1444(\256le)X +1579(from)X +1768(the)X +1899(argument)X +2235(list.)X +2405(The)X +3 f +2563(next)X +1 f +2743(command)X +3092(will)X +3249(fail)X +3389(if)X +3471(the)X +3603(\256le)X +3739(has)X +3880(been)X +976 1752(modi\256ed)N +1287(since)X +1478(the)X +1602(last)X +1739(complete)X +2059(write.)X +2290(This)X +2458(check)X +2672(can)X +2810(be)X +2912(overridden)X +3286(by)X +3392(appending)X +3752(the)X +3876(``)X +7 f +3930(!)X +1 f +('')S +976 1842(character)N +1294(to)X +1378(the)X +1498(command)X +1836(name.)X +2072(The)X +2219(argument)X +2544(list)X +2663(can)X +2797(optionally)X +3143(be)X +3241(replaced)X +3536(by)X +3639(specifying)X +3996(a)X +976 1932(new)N +1131(one)X +1268(as)X +1355(arguments)X +1709(to)X +1791(this)X +1926(command.)X +2302(In)X +2389(this)X +2524(case,)X +2703(editing)X +2945(starts)X +3134(with)X +3296(the)X +3414(\256rst)X +3558(\256le)X +3680(on)X +3780(the)X +3898(new)X +976 2022(list.)N +976 2202(Line:)N +1336(Set)X +1458(as)X +1545(described)X +1873(for)X +1987(the)X +3 f +2105(edit)X +1 f +2254(command.)X +976 2292(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +1856(options)X +3 f +2111(autowrite)X +1 f +2461(and)X +3 f +2597(writeany)X +1 f +2900(.)X +3 f +776 2472([line])N +974(o[pen])X +1212(/pattern/)X +1530([\257ags])X +1 f +976 2562(Enter)N +1172(open)X +1350(mode.)X +1590(Open)X +1786(mode)X +1987(is)X +2063(the)X +2184(same)X +2372(as)X +2462(being)X +2663(in)X +3 f +2748(vi)X +1 f +2810(,)X +2853(but)X +2978(with)X +3143(a)X +3202(one-line)X +3488(window.)X +3809(All)X +3934(the)X +976 2652(standard)N +3 f +1278(vi)X +1 f +1370(commands)X +1747(are)X +1876(available.)X +2236(If)X +2320(a)X +2386(match)X +2612(is)X +2694(found)X +2910(for)X +3033(the)X +3160(optional)X +3451(RE)X +3582(argument,)X +3934(the)X +976 2742(cursor)N +1197(is)X +1270(set)X +1379(to)X +1461(the)X +1579(start)X +1737(of)X +1824(the)X +1942(matching)X +2260(pattern.)X +2 f +976 2922(This)N +1133(command)X +1465(is)X +1538(not)X +1660(yet)X +1774(implemented.)X +1 f +976 3102(Line:)N +1336(Unchanged,)X +1750(unless)X +1978(the)X +2104(optional)X +2394(RE)X +2524(is)X +2605(speci\256ed,)X +2938(in)X +3028(which)X +3253(case)X +3421(it)X +3494(is)X +3576(set)X +3694(to)X +3785(the)X +3912(line)X +1336 3192(where)N +1553(the)X +1671(matching)X +1989(pattern)X +2232(is)X +2305(found.)X +976 3282(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(open)X +1 f +2040(option.)X +3 f +776 3462(pre[serve])N +1 f +976 3552(Save)N +1161(the)X +1288(\256le)X +1419(in)X +1510(a)X +1575(form)X +1760(that)X +1909(can)X +2050(later)X +2222(be)X +2327(recovered)X +2674(using)X +2877(the)X +3 f +3005(ex)X +9 f +3111(-)X +3113(-)X +3 f +3157(r)X +1 f +3223(option.)X +3497(When)X +3719(the)X +3847(\256le)X +3979(is)X +976 3642(preserved,)N +1329(an)X +1425(email)X +1623(message)X +1915(is)X +1988(sent)X +2137(to)X +2219(the)X +2337(user.)X +976 3822(Line:)N +1336(Unchanged.)X +976 3912(Options:)N +1336(None.)X +3 f +776 4092(prev[ious][!])N +1 f +976 4182(Edit)N +1136(the)X +1261(previous)X +1564(\256le)X +1693(from)X +1876(the)X +2001(argument)X +2331(list.)X +2495(The)X +3 f +2647(previous)X +1 f +2967(command)X +3310(will)X +3461(fail)X +3595(if)X +3671(the)X +3796(\256le)X +3925(has)X +976 4272(been)N +1155(modi\256ed)X +1466(since)X +1658(the)X +1783(last)X +1921(complete)X +2241(write.)X +2472(This)X +2640(check)X +2854(can)X +2992(be)X +3094(overridden)X +3468(by)X +3574(appending)X +3934(the)X +976 4362(``)N +7 f +1030(!)X +1 f +('')S +1172(character)X +1488(to)X +1570(the)X +1688(command)X +2024(name.)X +976 4542(Line:)N +1336(Set)X +1458(as)X +1545(described)X +1873(for)X +1987(the)X +3 f +2105(edit)X +1 f +2254(command.)X +976 4632(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +1856(options)X +3 f +2111(autowrite)X +1 f +2461(and)X +3 f +2597(writeany)X +1 f +2900(.)X +2960(None.)X +3 f +776 4812([range])N +1046(p[rint])X +1293([count])X +1558([\257ags])X +1 f +976 4902(Display)N +1245(the)X +1363(speci\256ed)X +1668(lines.)X +976 5082(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(last)X +1789(line)X +1929(displayed.)X +976 5172(Options:)N +1336(None.)X +3 f +776 5352([line])N +974(pu[t])X +1163([buffer])X +1 f +976 5442(Append)N +1250(buffer)X +1467(contents)X +1755(to)X +1838(the)X +1957(current)X +2206(line.)X +2387(If)X +2462(a)X +2519(buffer)X +2737(is)X +2811(speci\256ed,)X +3137(its)X +3233(contents)X +3521(are)X +3641(appended)X +3970(to)X +976 5532(the)N +1094(line,)X +1254(otherwise,)X +1606(the)X +1724(contents)X +2011(of)X +2098(the)X +2216(unnamed)X +2530(buffer)X +2747(are)X +2866(used.)X +976 5712(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(line)X +1798(after)X +1966(the)X +2084(current)X +2332(line.)X + +41 p +%%Page: 41 40 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Ex)X +1377(Commands\))X +3658(USD:13-41)X +1 f +976 762(Options:)N +1336(None.)X +3 f +776 942(q[uit][!])N +1 f +976 1032(End)N +1133(the)X +1259(editing)X +1509(session.)X +1808(If)X +1890(the)X +2016(\256le)X +2146(has)X +2281(been)X +2461(modi\256ed)X +2773(since)X +2966(the)X +3092(last)X +3231(complete)X +3554(write,)X +3768(the)X +3 f +3895(quit)X +1 f +976 1122(command)N +1314(will)X +1460(fail.)X +1629(This)X +1793(check)X +2003(may)X +2163(be)X +2261(overridden)X +2631(by)X +2733(appending)X +3089(a)X +3147(``)X +7 f +3201(!)X +1 f +('')S +3345(character)X +3663(to)X +3747(the)X +3867(com-)X +976 1212(mand.)N +976 1392(If)N +1053(there)X +1237(are)X +1359(more)X +1547(\256les)X +1703(to)X +1788(edit,)X +1951(the)X +3 f +2072(quit)X +1 f +2232(command)X +2571(will)X +2718(fail.)X +2888(Appending)X +3268(a)X +3328(``)X +7 f +3382(!)X +1 f +('')S +3528(character)X +3848(to)X +3934(the)X +976 1482(command)N +1315(name)X +1511(or)X +1600(entering)X +1885(two)X +3 f +2027(quit)X +1 f +2186(commands)X +2555(\(i.e.)X +3 f +2722(wq)X +1 f +2824(,)X +3 f +2866(quit)X +1 f +3003(,)X +3 f +3045(xit)X +1 f +3156(or)X +3 f +3245(ZZ)X +1 f +3351(\))X +3400(in)X +3484(a)X +3542(row\))X +3716(will)X +3862(over-)X +976 1572(ride)N +1121(this)X +1256(check)X +1464(and)X +1600(the)X +1718(editor)X +1925(will)X +2069(exit.)X +976 1752(Line:)N +1336(Unchanged.)X +976 1842(Options:)N +1336(None.)X +3 f +776 2022([line])N +974(r[ead][!])X +1285([\256le])X +1 f +976 2112(Read)N +1171(a)X +1237(\256le.)X +1409(A)X +1497(copy)X +1683(of)X +1780(the)X +1908(speci\256ed)X +2223(\256le)X +2355(is)X +2438(appended)X +2776(to)X +2868(the)X +2996(line.)X +3186(If)X +7 f +3270(line)X +1 f +3492(is)X +3575(0,)X +3665(the)X +3793(copy)X +3979(is)X +976 2202(inserted)N +1252(at)X +1332(the)X +1452(beginning)X +1794(of)X +1883(the)X +2003(\256le.)X +2167(If)X +2243(no)X +2345(\256le)X +2469(is)X +2544(speci\256ed,)X +2871(the)X +2991(current)X +3241(\256le)X +3365(is)X +3440(read;)X +3623(if)X +3694(there)X +3877(is)X +3952(no)X +976 2292(current)N +1233(\256le,)X +1384(then)X +7 f +1552(file)X +1 f +1774(becomes)X +2085(the)X +2213(current)X +2471(\256le.)X +2643(If)X +2727(there)X +2918(is)X +3001(no)X +3111(current)X +3369(\256le)X +3501(and)X +3647(no)X +7 f +3757(file)X +1 f +3979(is)X +976 2382(speci\256ed,)N +1301(then)X +1459(the)X +3 f +1577(read)X +1 f +1753(command)X +2089(will)X +2233(fail.)X +976 2562(If)N +7 f +1054(file)X +1 f +1270(is)X +1347(preceded)X +1662(by)X +1766(a)X +1826(``)X +7 f +1880(!)X +1 f +('')S +2026(character,)X +7 f +2366(file)X +1 f +2582(is)X +2659(treated)X +2902(as)X +2993(if)X +3067(it)X +3136(were)X +3318(a)X +3379(shell)X +3555(command,)X +3916(and)X +976 2652(passed)N +1213(to)X +1298(the)X +1419(program)X +1713(named)X +1949(by)X +2051(the)X +7 f +2171(SHELL)X +1 f +2433(environment)X +2860(variable.)X +3181(The)X +3328(standard)X +3622(and)X +3760(standard)X +976 2742(error)N +1155(outputs)X +1412(of)X +1501(that)X +1643(command)X +1981(are)X +2102(read)X +2263(into)X +2409(the)X +2529(\256le)X +2654(after)X +2825(the)X +2946(speci\256ed)X +3254(line.)X +3437(The)X +3585(special)X +3831(mean-)X +976 2832(ing)N +1098(of)X +1185(the)X +1303(``)X +7 f +1357(!)X +1 f +('')S +1499(character)X +1815(can)X +1947(be)X +2043(overridden)X +2411(by)X +2511(escaping)X +2812(it)X +2876(with)X +3038(a)X +3094(backslash)X +3426(\(``)X +7 f +3507(\\)X +1 f +(''\))S +3656(character.)X +976 3012(Line:)N +1336(When)X +1550(executed)X +1858(from)X +3 f +2036(ex)X +1 f +2112(,)X +2154(the)X +2274(current)X +2524(line)X +2666(is)X +2741(set)X +2852(to)X +2936(the)X +3056(last)X +3189(line)X +3331(read.)X +3532(When)X +3746(executed)X +1336 3102(from)N +3 f +1512(vi)X +1 f +1574(,)X +1614(the)X +1732(current)X +1980(line)X +2120(is)X +2193(set)X +2302(to)X +2384(the)X +2502(\256rst)X +2646(line)X +2786(read.)X +976 3192(Options:)N +1336(None.)X +3 f +776 3372 0.4063(rec[over])AN +1110(\256le)X +1 f +976 3462(Recover)N +7 f +1273(file)X +1 f +1494(if)X +1572(it)X +1645(was)X +1799(previously)X +2166(saved.)X +2418(If)X +2501(no)X +2610(saved)X +2822(\256le)X +2953(by)X +3062(that)X +3211(name)X +3414(exists,)X +3645(the)X +3 f +3772(recover)X +1 f +976 3552(command)N +1312(behaves)X +1591(similarly)X +1895(to)X +1977(the)X +3 f +2095(edit)X +1 f +2244(command.)X +976 3732(Line:)N +1336(Set)X +1458(as)X +1545(described)X +1873(for)X +1987(the)X +3 f +2105(edit)X +1 f +2254(command.)X +976 3822(Options:)N +1336(None.)X +3 f +776 4002(res[ize])N +1047([+|-]size)X +976 4092(Vi)N +1 f +1081(mode)X +1284(only.)X +1492(Grow)X +1701(or)X +1794(shrink)X +2020(the)X +2144(current)X +2398(screen.)X +2670(If)X +7 f +2750(size)X +1 f +2968(is)X +3047(a)X +3109(positive,)X +3408(signed)X +3643(number,)X +3934(the)X +976 4182(current)N +1227(screen)X +1456(is)X +1532(grown)X +1760(by)X +1863(that)X +2006(many)X +2207(lines.)X +2421(If)X +7 f +2498(size)X +1 f +2713(is)X +2789(a)X +2848(negative,)X +3163(signed)X +3395(number,)X +3683(the)X +3804(current)X +976 4272(screen)N +1212(is)X +1295(shrunk)X +1543(by)X +1653(that)X +1803(many)X +2011(lines.)X +2232(If)X +7 f +2316(size)X +1 f +2538(is)X +2621(not)X +2753(signed,)X +3012(the)X +3141(current)X +3400(screen)X +3637(is)X +3721(set)X +3841(to)X +3934(the)X +976 4362(speci\256ed)N +7 f +1281(size)X +1 f +(.)S +1533(Applicable)X +1905(only)X +2067(to)X +2149(split)X +2306(screens.)X +976 4542(Line:)N +1336(Unchanged.)X +976 4632(Options:)N +1336(None.)X +3 f +776 4812(rew[ind][!])N +1 f +976 4902(Rewind)N +1251(the)X +1375(argument)X +1704(list.)X +1867(If)X +1947(the)X +2071(current)X +2325(\256le)X +2453(has)X +2586(been)X +2764(modi\256ed)X +3074(since)X +3265(the)X +3389(last)X +3526(complete)X +3847(write,)X +976 4992(the)N +3 f +1097(rewind)X +1 f +1360(command)X +1699(will)X +1846(fail.)X +2016(This)X +2180(check)X +2390(may)X +2550(be)X +2648(overridden)X +3018(by)X +3120(appending)X +3476(the)X +3596(``)X +7 f +3650(!)X +1 f +('')S +3794(charac-)X +976 5082(ter)N +1081(to)X +1163(the)X +1281(command.)X +976 5262(Otherwise,)N +1346(the)X +1464(current)X +1712(\256le)X +1834(is)X +1907(set)X +2016(to)X +2098(the)X +2216(\256rst)X +2360(\256le)X +2482(in)X +2564(the)X +2682(argument)X +3005(list.)X +976 5442(Line:)N +1336(Set)X +1458(as)X +1545(described)X +1873(for)X +1987(the)X +3 f +2105(edit)X +1 f +2254(command.)X +976 5532(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(autowrite)X +1 f +2206(and)X +3 f +2342(writeany)X +1 f +2665(options.)X +3 f +776 5712(se[t])N +944([option[=[value]])X +1544(...])X +1651([nooption)X +1999(...])X +2106([option?)X +2410(...])X +2517([all])X +1 f +976 5802(Display)N +1252(or)X +1346(set)X +1462(editor)X +1676(options.)X +1979(When)X +2199(no)X +2307(arguments)X +2669(are)X +2796(speci\256ed,)X +3129(the)X +3255(editor)X +3470(option)X +3 f +3702(term)X +1 f +3868(,)X +3916(and)X + +42 p +%%Page: 42 41 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-42)N +2813(Nvi/Nex)X +3109 0.3906(Reference)AX +3474(\(Ex)X +3614(Commands\))X +1 f +976 762(any)N +1115(editor)X +1325(options)X +1583(whose)X +1811(values)X +2039(have)X +2214(been)X +2389(changed)X +2679(from)X +2857(the)X +2977(default)X +3222(settings)X +3488(are)X +3609(displayed.)X +3978(If)X +976 852(the)N +1094(argument)X +7 f +1417(all)X +1 f +1581(is)X +1654(speci\256ed,)X +1979(the)X +2097(values)X +2322(of)X +2409(all)X +2509(of)X +2596(editor)X +2803(options)X +3058(are)X +3177(displayed.)X +976 1032(Specifying)N +1353(an)X +1459(option)X +1693(name)X +1897(followed)X +2212(by)X +2322(the)X +2450(character)X +2776(``)X +7 f +2830(?)X +1 f +('')S +2982(causes)X +3222(the)X +3350(current)X +3609(value)X +3814(of)X +3912(that)X +976 1122(option)N +1203(to)X +1288(be)X +1387(displayed.)X +1757(The)X +1905(``)X +7 f +1959(?)X +1 f +('')S +2104(can)X +2239(be)X +2338(separated)X +2665(from)X +2843(the)X +2963(option)X +3189(name)X +3385(by)X +3487(whitespace)X +3866(char-)X +976 1212(acters.)N +1225(The)X +1371(``)X +7 f +1425(?)X +1 f +('')S +1568(is)X +1642(necessary)X +1976(only)X +2139(for)X +2254(Boolean)X +2543(valued)X +2779(options.)X +3076(Boolean)X +3365(options)X +3622(can)X +3756(be)X +3854(given)X +976 1302(values)N +1209(by)X +1317(the)X +1443(form)X +1627(``)X +7 f +1681(set)X +1881(option)X +1 f +('')S +2251(to)X +2341(turn)X +2498(them)X +2686(on,)X +2814(or)X +2909(``)X +7 f +2963(set)X +3162(nooption)X +1 f +('')S +3627(to)X +3716(turn)X +3872(them)X +976 1392(off.)N +1131(String)X +1347(and)X +1484(numeric)X +1768(options)X +2024(can)X +2158(be)X +2256(assigned)X +2554(by)X +2656(the)X +2776(form)X +2954(``)X +7 f +3008(set)X +3202(option=value)X +1 f +(''.)S +3894(Any)X +976 1482(whitespace)N +1359(characters)X +1712(in)X +1800(strings)X +2039(can)X +2176(be)X +2277(included)X +2578(literally)X +2852(by)X +2957(preceding)X +3299(each)X +3472(with)X +3639(a)X +3700(backslash.)X +976 1572(More)N +1180(than)X +1349(one)X +1496(option)X +1731(can)X +1874(be)X +1981(set)X +2101(or)X +2199(listed)X +2403(by)X +2514(a)X +2581(single)X +2803(set)X +2923(command,)X +3290(by)X +3401(specifying)X +3766(multiple)X +976 1662(arguments,)N +1350(each)X +1518(separated)X +1842(from)X +2018(the)X +2136(next)X +2294(by)X +2394(whitespace)X +2771(characters.)X +976 1842(Line:)N +1336(Unchanged.)X +976 1932(Options:)N +1336(None.)X +3 f +776 2112(sh[ell])N +1 f +976 2202(Run)N +1131(a)X +1189(shell)X +1362(program.)X +1696(The)X +1843(program)X +2137(named)X +2373(by)X +2475(the)X +3 f +2596(shell)X +1 f +2774(option)X +3001(is)X +3077(run)X +3207(with)X +3372(a)X +3 f +9 f +3431(-)X +3433(-)X +3 f +3477(i)X +1 f +3522(\(for)X +3666(interactive\))X +976 2292(\257ag.)N +1156(Editing)X +1411(is)X +1484(resumed)X +1776(when)X +1970(that)X +2110(program)X +2402(exits.)X +976 2472(Line:)N +1336(Unchanged.)X +976 2562(Options:)N +1336(None.)X +3 f +776 2742(so[urce])N +1073(\256le)X +1 f +976 2832(Read)N +1161(and)X +1297(execute)X +3 f +1563(ex)X +1 f +1659(commands)X +2026(from)X +2202(a)X +2258(\256le.)X +3 f +2420(Source)X +1 f +2676(commands)X +3043(may)X +3201(be)X +3297(nested.)X +976 3012(Line:)N +1336(Unchanged.)X +976 3102(Options:)N +1336(None.)X +3 f +776 3282(sp[lit])N +996([\256le)X +1145(...])X +976 3372(Vi)N +1 f +1078(mode)X +1278(only.)X +1482(Split)X +1655(the)X +1776(screen.)X +2045(The)X +2193(current)X +2444(screen)X +2673(is)X +2749(split)X +2909(into)X +3056(two)X +3199(screens,)X +3479(of)X +3569(approximately)X +976 3462(equal)N +1173(size.)X +1361(If)X +1438(the)X +1559(cursor)X +1783(is)X +1859(in)X +1944(the)X +2065(lower)X +2271(half)X +2419(of)X +2509(the)X +2630(screen,)X +2879(the)X +3000(screen)X +3229(will)X +3376(split)X +3536(up,)X +3658(i.e.)X +3778(the)X +3898(new)X +976 3552(screen)N +1213(will)X +1368(be)X +1475(above)X +1699(the)X +1829(old)X +1963(one.)X +2151(If)X +2237(the)X +2367(cursor)X +2600(is)X +2685(in)X +2779(the)X +2909(upper)X +3124(half)X +3281(of)X +3380(the)X +3510(screen,)X +3768(the)X +3898(new)X +976 3642(screen)N +1202(will)X +1346(be)X +1442(below)X +1658(the)X +1776(old)X +1898(one.)X +976 3822(If)N +7 f +1052(file)X +1 f +1267(is)X +1343(speci\256ed,)X +1671(the)X +1792(new)X +1949(screen)X +2178(is)X +2254(editing)X +2499(that)X +2642(\256le,)X +2787(otherwise,)X +3142(both)X +3307(screens)X +3567(are)X +3689(editing)X +3934(the)X +976 3912(same)N +1165(\256le,)X +1310(and)X +1449(changes)X +1731(in)X +1816(each)X +1987(will)X +2134(be)X +2233(be)X +2332(re\257ected)X +2632(in)X +2717(the)X +2838(other.)X +3066(The)X +3214(argument)X +3540(list)X +3660(for)X +3777(the)X +3898(new)X +976 4002(screen)N +1204(consists)X +1479(of)X +1568(the)X +1688(list)X +1807(of)X +1896(\256les)X +2051(speci\256ed)X +2358(as)X +2447(arguments)X +2803(to)X +2888(this)X +3026(command,)X +3385(or,)X +3495(the)X +3616(current)X +3867(path-)X +976 4092(name)N +1170(if)X +1239(no)X +1339(\256les)X +1492(are)X +1611(speci\256ed.)X +976 4272(Line:)N +1336(If)X +7 f +1410(file)X +1 f +1622(is)X +1695(speci\256ed,)X +2020(set)X +2129(as)X +2216(for)X +2330(the)X +3 f +2448(edit)X +1 f +2597(command,)X +2953(otherwise)X +3285(unchanged.)X +976 4362(Options:)N +1336(None.)X +3 f +776 4542([range])N +1046(s[ubstitute])X +1453([/pattern/replace/])X +2097([options])X +2419([count])X +2684([\257ags])X +776 4632([range])N +1046(&)X +1133([options])X +1455([count])X +1720([\257ags])X +776 4722([range])N +1046(\304)X +1093([options])X +1415([count])X +1680([\257ags])X +1 f +976 4812(Make)N +1185(substitutions.)X +1654(Replace)X +1939(the)X +2063(\256rst)X +2214(instance)X +2504(of)X +7 f +2598(pattern)X +1 f +2961(with)X +3130(the)X +3255(string)X +7 f +3464(replace)X +1 f +3827(on)X +3934(the)X +976 4902(speci\256ed)N +1343(line\(s\).)X +1670(If)X +1806(the)X +1986(``)X +7 f +2040(/pattern/repl/)X +1 f +('')S +2847(argument)X +3231(is)X +3365(not)X +3548(speci\256ed,)X +3934(the)X +976 4992(``)N +7 f +1030(/pattern/repl/)X +1 f +('')S +1776(from)X +1952(the)X +2070(previous)X +3 f +2366(substitute)X +1 f +2719(command)X +3055(is)X +3128(used.)X +976 5172(If)N +7 f +1054(options)X +1 f +1414(includes)X +1705(the)X +1827(letter)X +2017(``)X +7 f +2071(c)X +1 f +('')S +2198(\(con\256rm\),)X +2546(you)X +2691(will)X +2840(be)X +2941(prompted)X +3273(for)X +3392(con\256rmation)X +3826(before)X +976 5262(each)N +1152(replacement)X +1573(is)X +1654(done.)X +1878(An)X +2004(af\256rmative)X +2384(response)X +2693(\(in)X +2810(English,)X +3101(a)X +3164(``)X +7 f +3218(y)X +1 f +('')S +3347 0.3750(character\))AX +3697(causes)X +3934(the)X +976 5352(replacement)N +1393(to)X +1479(be)X +1579(made.)X +1817(A)X +1899(quit)X +2047(response)X +2352(\(in)X +2465(English,)X +2753(a)X +2813(``)X +7 f +2867(q)X +1 f +('')S +2993 0.3750(character\))AX +3341(causes)X +3576(the)X +3 f +3699(substitute)X +1 f +976 5442(command)N +1320(to)X +1410(be)X +1514(terminated.)X +1925(Any)X +2091(other)X +2284(response)X +2592(causes)X +2829(the)X +2954(replacement)X +3374(not)X +3503(to)X +3592(be)X +3695(made,)X +3916(and)X +976 5532(the)N +3 f +1094(substitute)X +1 f +1447(command)X +1783(continues.)X +2150(If)X +7 f +2224(options)X +1 f +2580(includes)X +2867(the)X +2985(letter)X +3170(``)X +7 f +3224(g)X +1 f +('')S +3346(\(global\),)X +3641(all)X +3742(nonover-)X +976 5622(lapping)N +1236(instances)X +1550(of)X +7 f +1637(pattern)X +1 f +1993(in)X +2075(the)X +2193(line)X +2333(are)X +2452(replaced.)X +976 5802(The)N +3 f +1122(&)X +1 f +1210(version)X +1467(of)X +1555(the)X +1674(command)X +2011(is)X +2085(the)X +2204(same)X +2390(as)X +2479(not)X +2603(specifying)X +2959(a)X +3017(pattern)X +3262(or)X +3351(replacement)X +3766(string)X +3970(to)X + +43 p +%%Page: 43 42 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Ex)X +1377(Commands\))X +3658(USD:13-43)X +1 f +976 762(the)N +3 f +1098(substitute)X +1 f +1455(command,)X +1815(and)X +1955(the)X +2077(``)X +7 f +2131(&)X +1 f +('')S +2257(is)X +2333(replaced)X +2629(by)X +2732(the)X +2853(pattern)X +3099(and)X +3238(replacement)X +3654(information)X +976 852(from)N +1152(the)X +1270(previous)X +1566(substitute)X +1892(command.)X +976 1032(The)N +3 f +1121(\304)X +1 f +1168(version)X +1424(of)X +1511(the)X +1629(command)X +1966(is)X +2040(the)X +2159(same)X +2345(as)X +3 f +2433(&)X +1 f +2521(and)X +3 f +2658(s)X +1 f +2689(,)X +2730(except)X +2961(that)X +3102(the)X +3221(search)X +3448(pattern)X +3692(used)X +3860(is)X +3934(the)X +976 1122(last)N +1107(RE)X +1229(used)X +1396(in)X +2 f +1478(any)X +1 f +1614(command,)X +1970(not)X +2092(necessarily)X +2469(the)X +2587(one)X +2723(used)X +2890(in)X +2972(the)X +3090(last)X +3 f +3221(substitute)X +1 f +3574(command.)X +976 1302(For)N +1107(example,)X +1419(in)X +1501(the)X +1619(sequence)X +7 f +1296 1425(s/red/blue/)N +1296 1515(/green)N +1296 1605(\304)N +1 f +976 1728(the)N +1094(``)X +7 f +1148(\304)X +1 f +('')S +1270(is)X +1343(equivalent)X +1697(to)X +1779(``)X +7 f +1833(s/green/blue/)X +1 f +(''.)S +976 1908(The)N +3 f +1126(substitute)X +1 f +1484(command)X +1825(may)X +1988(be)X +2089(interrupted,)X +2486(using)X +2685(the)X +2809(terminal)X +3102(interrupt)X +3404(character.)X +3766(All)X +3894(sub-)X +976 1998(stitutions)N +1288(completed)X +1642(before)X +1868(the)X +1986(interrupt)X +2282(are)X +2401(retained.)X +976 2178(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(last)X +1789(line)X +1929(upon)X +2109(which)X +2325(a)X +2381(substitution)X +2773(was)X +2918(made.)X +976 2268(Options:)N +1336(None.)X +3 f +776 2448(su[spend][!])N +776 2538(st[op][!])N +776 2628(<control-Z>)N +1 f +976 2718(Suspend)N +1285(the)X +1422(edit)X +1581(session.)X +1891(Appending)X +2286(a)X +2361(``)X +7 f +2415(!)X +1 f +('')S +2576(character)X +2911(to)X +3012(these)X +3216(commands)X +3602(turns)X +3801(off)X +3934(the)X +3 f +976 2808(autowrite)N +1 f +1326(option)X +1550(for)X +1664(the)X +1782(command.)X +976 2988(Line:)N +1336(Unchanged.)X +976 3078(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(autowrite)X +1 f +2206(option.)X +3 f +776 3258(ta[g][!])N +1038(tagstring)X +1 f +976 3348(Edit)N +1133(the)X +1255(\256le)X +1381(containing)X +1743(the)X +1865(speci\256ed)X +2174(tag.)X +2337(Search)X +2581(for)X +2700(the)X +2823(tagstring,)X +3148(which)X +3369(can)X +3506(be)X +3607(in)X +3694(a)X +3755(different)X +976 3438(\256le.)N +1149(If)X +1234(the)X +1363(tag)X +1492(is)X +1576(in)X +1669(a)X +1736(different)X +2044(\256le,)X +2197(then)X +2366(the)X +2495(new)X +2660(\256le)X +2792(is)X +2875(edited.)X +3141(If)X +3225(the)X +3353(current)X +3611(\256le)X +3743(has)X +3880(been)X +976 3528(modi\256ed)N +1283(since)X +1471(the)X +1592(last)X +1726(complete)X +2043(write,)X +2251(the)X +3 f +2372(tag)X +1 f +2502(command)X +2841(will)X +2988(fail.)X +3159(This)X +3325(check)X +3537(can)X +3673(be)X +3773(overrid-)X +976 3618(den)N +1112(by)X +1212(appending)X +1566(the)X +1684(``)X +7 f +1738(!)X +1 f +('')S +1880(character)X +2196(to)X +2278(the)X +2396(command)X +2732(name.)X +976 3798(The)N +3 f +1128(tag)X +1 f +1262(command)X +1605(searches)X +1905(for)X +7 f +2026(tagstring)X +1 f +2485(in)X +2574(the)X +2699(tags)X +2855(\256le\(s\))X +3070(speci\256ed)X +3383(by)X +3491(the)X +3617(option.)X +3889(\(See)X +2 f +976 3888(ctags)N +1 f +1145(\(1\))X +1259(for)X +1373(more)X +1558(information)X +1956(on)X +2056(tags)X +2205(\256les.\))X +976 4068(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(line)X +1798(indicated)X +2112(by)X +2212(the)X +2330(tag.)X +976 4158(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(autowrite)X +1 f +2186(,)X +3 f +2226(taglength)X +1 f +(,)S +3 f +2586(tags)X +1 f +2744(and)X +3 f +2880(writeany)X +1 f +3203(options.)X +3 f +776 4338(tagp[op][!])N +1166([\256le)X +1315(|)X +1353(number])X +1 f +976 4428(Pop)N +1122(to)X +1206(the)X +1326(speci\256ed)X +1633(tag)X +1753(in)X +1837(the)X +1957(tags)X +2108(stack.)X +2335(If)X +2411(neither)X +7 f +2656(file)X +1 f +2871(or)X +7 f +2961(number)X +1 f +3272(is)X +3348(speci\256ed,)X +3676(the)X +3 f +3797(tagpop)X +1 f +976 4518(command)N +1313(pops)X +1485(to)X +1568(the)X +1686(most)X +1861(recent)X +2078(entry)X +2263(on)X +2363(the)X +2481(tags)X +2630(stack.)X +2855(If)X +7 f +2929(file)X +1 f +3141(or)X +7 f +3228(number)X +1 f +3536(is)X +3609(speci\256ed,)X +3934(the)X +3 f +976 4608(tagpop)N +1 f +1242(command)X +1589(pops)X +1771(to)X +1864(the)X +1993(most)X +2179(recent)X +2407(entry)X +2603(in)X +2696(the)X +2825(tags)X +2985(stack)X +3181(for)X +3306(that)X +3458(\256le,)X +3612(or)X +3711(numbered)X +976 4698(entry)N +1165(in)X +1251(the)X +1373(tags)X +1526(stack,)X +1735(respectively.)X +2186(\(See)X +2352(the)X +3 f +2473(display)X +1 f +2739(command)X +3078(for)X +3195(information)X +3596(on)X +3699(displaying)X +976 4788(the)N +1094(tags)X +1243(stack.\))X +976 4968(If)N +1051(the)X +1170(\256le)X +1293(has)X +1421(been)X +1594(modi\256ed)X +1899(since)X +2085(the)X +2204(last)X +2337(complete)X +2653(write,)X +2860(the)X +3 f +2980(tagpop)X +1 f +3237(command)X +3575(will)X +3721(fail.)X +3890(This)X +976 5058(check)N +1184(may)X +1342(be)X +1438(overridden)X +1806(by)X +1906(appending)X +2260(a)X +2316(``)X +7 f +2370(!)X +1 f +('')S +2512(character)X +2828(to)X +2910(the)X +3028(command)X +3364(name.)X +976 5238(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(line)X +1798(indicated)X +2112(by)X +2212(the)X +2330(tag.)X +976 5328(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(autowrite)X +1 f +2186(,)X +2226(and)X +3 f +2362(writeany)X +1 f +2685(options.)X +3 f +776 5508(tagt[op][!])N +1 f +976 5598(Pop)N +1120(to)X +1202(the)X +1320(least)X +1487(recent)X +1704(tag)X +1822(on)X +1922(the)X +2040(tags)X +2189(stack,)X +2394(clearing)X +2673(the)X +2791(tags)X +2940(stack.)X +976 5778(If)N +1051(the)X +1170(\256le)X +1293(has)X +1421(been)X +1594(modi\256ed)X +1899(since)X +2085(the)X +2204(last)X +2337(complete)X +2653(write,)X +2860(the)X +3 f +2980(tagpop)X +1 f +3237(command)X +3575(will)X +3721(fail.)X +3890(This)X + +44 p +%%Page: 44 43 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-44)N +2813(Nvi/Nex)X +3109 0.3906(Reference)AX +3474(\(Ex)X +3614(Commands\))X +1 f +976 762(check)N +1184(may)X +1342(be)X +1438(overridden)X +1806(by)X +1906(appending)X +2260(a)X +2316(``)X +7 f +2370(!)X +1 f +('')S +2512(character)X +2828(to)X +2910(the)X +3028(command)X +3364(name.)X +976 942(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(line)X +1798(indicated)X +2112(by)X +2212(the)X +2330(tag.)X +976 1032(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(autowrite)X +1 f +2186(,)X +2226(and)X +3 f +2362(writeany)X +1 f +2685(options.)X +3 f +776 1212(una[bbrev])N +1178(lhs)X +1 f +976 1302(Delete)N +1206(an)X +1302(abbreviation.)X +1763(Delete)X +7 f +1993(lhs)X +1 f +2157(from)X +2333(the)X +2451(current)X +2699(list)X +2816(of)X +2903(abbreviations.)X +976 1482(Line:)N +1336(Unchanged.)X +976 1572(Options:)N +1336(None.)X +3 f +776 1752(u[ndo])N +1 f +976 1842(Undo)N +1177(the)X +1298(last)X +1432(change)X +1683(made)X +1880(to)X +1965(the)X +2086(\256le.)X +2251(Changes)X +2550(made)X +2747(by)X +3 f +2850(global)X +1 f +3058(,)X +3 f +3101(v)X +1 f +(,)S +3 f +3184(visual)X +1 f +3406(and)X +3545(map)X +3706(sequences)X +976 1932(are)N +1103(considered)X +1479(a)X +1543(single)X +1762(command.)X +2146(If)X +2228(repeated,)X +2549(the)X +3 f +2675(u)X +1 f +2747(command)X +3090(alternates)X +3425(between)X +3720(these)X +3912(two)X +976 2022(states,)N +1194(and)X +1330(is)X +1403(its)X +1498(own)X +1656(inverse.)X +976 2202(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(last)X +1789(line)X +1929(modi\256ed)X +2233(by)X +2333(the)X +2451(command.)X +976 2292(Options:)N +1336(None.)X +3 f +776 2472(unm[ap][!])N +1170(lhs)X +1 f +976 2562(Unmap)N +1235(a)X +1294(mapped)X +1571(string.)X +1816(Delete)X +2049(the)X +2170(command)X +2509(mode)X +2710(map)X +2872(de\256nition)X +3202(for)X +7 f +3320(lhs)X +1 f +(.)S +3528(If)X +3606(a)X +3666(``)X +7 f +3720(!)X +1 f +('')S +3866(char-)X +976 2652(acter)N +1153(is)X +1226(appended)X +1554(to)X +1636(the)X +1754(command)X +2090(name,)X +2304(delete)X +2516(the)X +2634(text)X +2774(input)X +2958(mode)X +3156(map)X +3314(de\256nition)X +3640(instead.)X +976 2832(Line:)N +1336(Unchanged.)X +976 2922(Options:)N +1336(None.)X +3 f +776 3102(ve[rsion])N +1 f +976 3192(Display)N +1245(the)X +1363(version)X +1619(of)X +1706(the)X +3 f +1824(ex/vi)X +1 f +2004(editor.)X +3 f +776 3372([line])N +974(vi[sual])X +1247([type])X +1468([count])X +1733([\257ags])X +976 3462(Ex)N +1 f +1092(mode)X +1293(only.)X +1498(Enter)X +3 f +1695(vi)X +1 f +1757(.)X +1820(The)X +7 f +1968(type)X +1 f +2183(is)X +2259(optional,)X +2564(and)X +2703(can)X +2838(be)X +2937(``)X +7 f +9 f +2991(-)X +1 f +3035('',)X +3132(``)X +7 f +3186(+)X +1 f +('')S +3311(or)X +3401(``)X +7 f +3455(\303)X +1 f +('',)S +3600(as)X +3690(in)X +3775(the)X +3 f +3896(ex)X +3996(z)X +1 f +976 3552(command,)N +1337(to)X +1424(specify)X +1681(the)X +1804(the)X +1926(position)X +2207(of)X +2298(the)X +2420(speci\256ed)X +2729(line)X +2873(in)X +2959(the)X +3081(screen)X +3311(window.)X +3633(\(The)X +3809(default)X +976 3642(is)N +1054(to)X +1141(place)X +1336(the)X +1459(line)X +1605(at)X +1689(the)X +1813(top)X +1941(of)X +2034(the)X +2158(screen)X +2390(window.\))X +2741(A)X +7 f +2825(count)X +1 f +3091(speci\256es)X +3393(the)X +3517(number)X +3788(of)X +3881(lines)X +976 3732(that)N +1116(will)X +1260(initially)X +1528(be)X +1624(displayed.)X +1991(\(The)X +2163(default)X +2406(is)X +2479(the)X +2597(value)X +2791(of)X +2878(the)X +3 f +2996(window)X +1 f +3282(editor)X +3489(option.\))X +976 3912(Line:)N +1336(Unchanged)X +1722(unless)X +7 f +1942(line)X +1 f +2154(is)X +2227(speci\256ed,)X +2552(in)X +2634(which)X +2850(case)X +3009(it)X +3073(is)X +3146(set)X +3255(to)X +3337(that)X +3477(line.)X +976 4002(Options:)N +1336(None.)X +3 f +776 4182(vi[sual][!])N +1130([+cmd])X +1397([\256le])X +976 4272(Vi)N +1 f +1076(mode)X +1274(only.)X +1476(Edit)X +1629(a)X +1685(new)X +1839(\256le.)X +2001(Identical)X +2302(to)X +2384(the)X +2502(``)X +7 f +2556(edit[!])X +2940([+cmd])X +3276([file])X +1 f +('')S +3638(command.)X +3 f +776 4452(viu[sage])N +1103([command])X +1 f +976 4542(Display)N +1253(usage)X +1464(for)X +1586(a)X +3 f +1650(vi)X +1 f +1740(command.)X +2124(If)X +7 f +2206(command)X +1 f +2570(is)X +2651(speci\256ed,)X +2984(a)X +3048(usage)X +3259(statement)X +3595(for)X +3718(that)X +3867(com-)X +976 4632(mand)N +1174(is)X +1247(displayed.)X +1614(Otherwise,)X +1984(usage)X +2187(statements)X +2545(for)X +2659(all)X +3 f +2759(vi)X +1 f +2841(commands)X +3208(are)X +3327(displayed.)X +976 4812(Line:)N +1336(Unchanged.)X +976 4902(Options:)N +1336(None.)X +3 f +776 5082([range])N +1046 0.3611(w[rite][!])AX +1380([>>])X +1546([\256le])X +776 5172([range])N +1046(w[rite])X +1299([!])X +1400([\256le])X +776 5262([range])N +1046(wn[!])X +1249([>>])X +1415([\256le])X +776 5352([range])N +1046(wq[!])X +1249([>>])X +1415([\256le])X +1 f +976 5442(Write)N +1183(the)X +1305(\256le.)X +1472(The)X +1622(speci\256ed)X +1932(lines)X +2108(\(the)X +2258(entire)X +2466(\256le,)X +2613(if)X +2687(no)X +2792(range)X +2996(is)X +3074(given\))X +3304(is)X +3382(written)X +3634(to)X +7 f +3721(file)X +1 f +(.)S +3978(If)X +7 f +976 5532(file)N +1 f +1195(is)X +1275(not)X +1403(speci\256ed,)X +1734(the)X +1858(current)X +2112(pathname)X +2450(is)X +2529(used.)X +2742(If)X +7 f +2822(file)X +1 f +3040(is)X +3119(speci\256ed,)X +3450(and)X +3592(it)X +3662(exists,)X +3890(or)X +3983(if)X +976 5622(the)N +1101(current)X +1356(pathname)X +1695(was)X +1847(set)X +1963(using)X +2163(the)X +3 f +2288(\256le)X +1 f +2417(command,)X +2780(and)X +2923(the)X +3049(\256le)X +3179(already)X +3444(exists,)X +3674(these)X +3867(com-)X +976 5712(mands)N +1212(will)X +1363(fail.)X +1537(Appending)X +1919(a)X +1981(``)X +7 f +2035(!)X +1 f +('')S +2183(character)X +2505(to)X +2593(the)X +2717(command)X +3059(name)X +3259(will)X +3409(override)X +3703(this)X +3844(check)X +976 5802(and)N +1112(the)X +1230(write)X +1415(will)X +1559(be)X +1655(attempted,)X +2011(regardless.)X + +45 p +%%Page: 45 44 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +1237(\(Ex)X +1377(Commands\))X +3658(USD:13-45)X +1 f +976 762(Specifying)N +1348(the)X +1471(optional)X +1758(``)X +7 f +1812(>>)X +1 f +('')S +1987(string)X +2194(will)X +2344(cause)X +2549(the)X +2673(write)X +2864(to)X +2952(be)X +3054(appended)X +3388(to)X +3476(the)X +3600(\256le,)X +3748(in)X +3836(which)X +976 852(case)N +1135(no)X +1235(tests)X +1397(are)X +1516(made)X +1710(for)X +1824(the)X +1942(\256le)X +2064(already)X +2321(existing.)X +976 1032(If)N +1060(the)X +1188(\256le)X +1320(is)X +1403(preceded)X +1724(by)X +1834(a)X +1900(``)X +7 f +1954(!)X +1 f +('')S +2106(character,)X +2452(the)X +2580(program)X +2882(named)X +3126(in)X +3218(the)X +3347(SHELL)X +3627(environment)X +976 1122(variable)N +1258(is)X +1334(invoked)X +1615(with)X +1780(\256le)X +1905(as)X +1995(its)X +2093(second)X +2339(argument,)X +2685(and)X +2824(the)X +2945(speci\256ed)X +3253(lines)X +3427(are)X +3549(passed)X +3786(as)X +3876(stan-)X +976 1212(dard)N +1143(input)X +1331(to)X +1417(that)X +1561(command.)X +1941(The)X +2090(``)X +7 f +2144(!)X +1 f +('')S +2291(in)X +2378(this)X +2518(usage)X +2726(must)X +2906(be)X +3007(separated)X +3336(from)X +3517(command)X +3858(name)X +976 1302(by)N +1080(at)X +1162(least)X +1333(one)X +1473(whitespace)X +1854(character.)X +2214(The)X +2363(special)X +2610(meaning)X +2910(of)X +3001(the)X +3122(``)X +7 f +3176(!)X +1 f +('')S +3321(may)X +3482(be)X +3581(overridden)X +3952(by)X +976 1392(escaping)N +1277(it)X +1341(with)X +1503(a)X +1559(backslash)X +1891(\(``)X +7 f +1972(\\)X +1 f +(''\))S +2121(character.)X +976 1572(The)N +3 f +1124(wq)X +1 f +1249(version)X +1509(of)X +1600(the)X +1722(write)X +1911(command)X +2251(will)X +2399(exit)X +2543(the)X +2665(editor)X +2876(after)X +3048(writing)X +3303(the)X +3425(\256le,)X +3571(if)X +3644(there)X +3829(are)X +3952(no)X +976 1662(further)N +1232(\256les)X +1402(to)X +1501(edit.)X +1698(Appending)X +2091(a)X +2164(``)X +7 f +2218(!)X +1 f +('')S +2377(character)X +2710(to)X +2809(the)X +2944(command)X +3297(name)X +3508(or)X +3612(entering)X +3912(two)X +976 1752(``quit'')N +1232(commands)X +1603(\(i.e.)X +3 f +1772(wq)X +1 f +1874(,)X +3 f +1918(quit)X +1 f +2055(,)X +3 f +2099(xit)X +1 f +2212(or)X +3 f +2303(ZZ)X +1 f +2409(\))X +2461(in)X +2548(a)X +2609(row\))X +2786(will)X +2935(override)X +3228(this)X +3368(check)X +3581(and)X +3722(the)X +3845(editor)X +976 1842(will)N +1120(exit,)X +1280(ignoring)X +1571(any)X +1707(\256les)X +1860(that)X +2000(have)X +2172(not)X +2294(yet)X +2412(been)X +2584(edited.)X +976 2022(The)N +3 f +1127(wn)X +1 f +1255(version)X +1517(of)X +1610(the)X +1734(write)X +1925(command)X +2267(will)X +2417(move)X +2621(to)X +2709(the)X +2833(next)X +2997(\256le)X +3125(after)X +3300(writing)X +3558(the)X +3683(\256le,)X +3832(unless)X +976 2112(the)N +1094(write)X +1279(fails.)X +976 2292(Line:)N +1336(Unchanged.)X +976 2382(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(readonly)X +1 f +2178(and)X +3 f +2314(writeany)X +1 f +2637(options.)X +3 f +776 2562([range])N +1046(x[it][!])X +1290([\256le])X +1 f +976 2652(Write)N +1185(the)X +1309(\256le)X +1437(if)X +1512(it)X +1582(has)X +1715(been)X +1894(modi\256ed.)X +2245(The)X +2397(speci\256ed)X +2709(lines)X +2887(are)X +3013(written)X +3267(to)X +7 f +3356(file)X +1 f +(,)S +3595(if)X +3671(the)X +3796(\256le)X +3925(has)X +976 2742(been)N +1149(modi\256ed)X +1454(since)X +1640(the)X +1759(last)X +1891(complete)X +2206(write)X +2392(to)X +2475(any)X +2612(\256le.)X +2775(If)X +2850(no)X +7 f +2951(range)X +1 f +3211(is)X +3284(speci\256ed,)X +3609(the)X +3727(entire)X +3930(\256le)X +976 2832(is)N +1049(written.)X +976 3012(The)N +3 f +1126(xit)X +1 f +1240(command)X +1581(will)X +1730(exit)X +1875(the)X +1998(editor)X +2210(after)X +2383(writing)X +2639(the)X +2762(\256le,)X +2909(if)X +2983(there)X +3169(are)X +3294(no)X +3400(further)X +3645(\256les)X +3804(to)X +3892(edit.)X +976 3102(Appending)N +1362(a)X +1428(``)X +7 f +1482(!)X +1 f +('')S +1634(character)X +1960(to)X +2052(the)X +2180(command)X +2526(name)X +2730(or)X +2827(entering)X +3120(two)X +3270(``quit'')X +3531(commands)X +3907(\(i.e.)X +3 f +976 3192(wq)N +1 f +1078(,)X +3 f +1125(quit)X +1 f +1262(,)X +3 f +1309(xit)X +1 f +1425(or)X +3 f +1519(ZZ)X +1 f +1625(\))X +1679(in)X +1768(a)X +1831(row\))X +2010(will)X +2161(override)X +2456(this)X +2598(check)X +2813(and)X +2956(the)X +3082(editor)X +3297(will)X +3449(exit,)X +3617(ignoring)X +3916(any)X +976 3282(\256les)N +1129(that)X +1269(have)X +1441(not)X +1563(yet)X +1681(been)X +1853(edited.)X +976 3462(Line:)N +1336(Unchanged.)X +976 3552(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +3 f +1856(readonly)X +1 f +2178(and)X +3 f +2314(writeany)X +1 f +2637(options.)X +3 f +776 3732([range])N +1046(ya[nk])X +1288([buffer])X +1576([count])X +1 f +976 3822(Copy)N +1169(the)X +1287(speci\256ed)X +1592(lines)X +1763(to)X +1845(a)X +1901(buffer.)X +2158(If)X +2232(no)X +2332(buffer)X +2549(is)X +2622(speci\256ed,)X +2947(the)X +3065(unnamed)X +3379(buffer)X +3596(is)X +3669(used.)X +976 4002(Line:)N +1336(Unchanged.)X +976 4092(Options:)N +1336(None.)X +3 f +776 4272([line])N +974(z)X +1030([type])X +1251([count])X +1516([\257ags])X +1 f +976 4362(Adjust)N +1210(the)X +1329(window.)X +1648(If)X +1723(no)X +7 f +1824(type)X +1 f +2037(is)X +2111(speci\256ed,)X +2437(then)X +7 f +2596(count)X +1 f +2858(lines)X +3031(following)X +3364(the)X +3484(speci\256ed)X +3791(line)X +3933(are)X +976 4452(displayed.)N +1362(The)X +1526(default)X +7 f +1788(count)X +1 f +2067(is)X +2159(the)X +2296(value)X +2509(of)X +2614(the)X +3 f +2750(window)X +1 f +3054(option.)X +3336(The)X +7 f +3499(type)X +1 f +3729(argument)X +976 4542(changes)N +1266(the)X +1395(position)X +1683(at)X +1772(which)X +7 f +1999(line)X +1 f +2222(is)X +2306(displayed)X +2644(on)X +2755(the)X +2884(screen)X +3121(by)X +3232(changing)X +3558(the)X +3688(number)X +3965(of)X +976 4632(lines)N +1147(displayed)X +1474(before)X +1700(and)X +1836(after)X +7 f +2004(line)X +1 f +(.)S +2256(The)X +2401(following)X +7 f +2732(type)X +1 f +2944(characters)X +3291(may)X +3449(be)X +3545(used:)X +9 f +976 4812(-)N +1 f +1336(Place)X +1530(the)X +1648(line)X +1788(at)X +1866(the)X +1984(bottom)X +2230(of)X +2317(the)X +2435(screen.)X +976 4902(+)N +1336(Place)X +1530(the)X +1648(line)X +1788(at)X +1866(the)X +1984(top)X +2106(of)X +2193(the)X +2311(screen.)X +976 4992(.)N +1336(Place)X +1530(the)X +1648(line)X +1788(in)X +1870(the)X +1988(middle)X +2230(of)X +2317(the)X +2435(screen.)X +976 5082(\303)N +1336(Write)X +1540(out)X +1663(count)X +1862(lines)X +2034(starting)X +7 f +2295(count)X +2584(*)X +2681(2)X +1 f +2750(lines)X +2922(before)X +7 f +3149(line)X +1 f +(;)S +3384(the)X +3503(net)X +3622(effect)X +3828(of)X +3917(this)X +1336 5172(is)N +1409(that)X +1549(a)X +1605(``)X +7 f +1659(z\303)X +1 f +('')S +1829(command)X +2165(following)X +2496(a)X +3 f +2552(z)X +1 f +2608(command)X +2944(writes)X +3160(the)X +3278(previous)X +3574(page.)X +976 5262(=)N +1336(Center)X +7 f +1580(line)X +1 f +1802(on)X +1912(the)X +2040(screen)X +2276(with)X +2448(a)X +2514(line)X +2664(of)X +2761(hyphens)X +3058(displayed)X +3395(immediately)X +3826(before)X +1336 5352(and)N +1485(after)X +1666(it.)X +1783(The)X +1941(number)X +2219(of)X +2319(preceding)X +2669(and)X +2817(following)X +3160(lines)X +3343(of)X +3442(text)X +3594(displayed)X +3933(are)X +1336 5442(reduced)N +1611(to)X +1693(account)X +1963(for)X +2077(those)X +2266(lines.)X +976 5622(Line:)N +1336(Set)X +1458(to)X +1540(the)X +1658(last)X +1789(line)X +1929(displayed,)X +2276(with)X +2438(the)X +2556(exception)X +2888(of)X +2975(the)X +7 f +3093(type)X +1 f +(,)S +3326(where)X +3544(the)X +3663(current)X +3912(line)X +1336 5712(is)N +1409(set)X +1518(to)X +1600(the)X +1718(line)X +1858(speci\256ed)X +2163(by)X +2263(the)X +2381(command.)X + +46 p +%%Page: 46 45 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-46)N +2813(Nvi/Nex)X +3109 0.3906(Reference)AX +3474(\(Ex)X +3614(Commands\))X +1 f +976 762(Options:)N +1336(Affected)X +1638(by)X +1738(the)X +1856(option.)X +3 f +776 948(15.)N +916(Set)X +1043(Options)X +1 f +976 1071(There)N +1186(are)X +1307(a)X +1365(large)X +1548(number)X +1815(of)X +1904(options)X +2161(that)X +2303(may)X +2463(be)X +2561(set)X +2672(\(or)X +2788(unset\))X +3006(to)X +3091(change)X +3342(the)X +3463(editor's)X +3731(behavior.)X +776 1161(This)N +938(section)X +1185(describes)X +1504(the)X +1622(options,)X +1897(their)X +2064(abbreviations)X +2516(and)X +2652(their)X +2819(default)X +3062(values.)X +976 1284(In)N +1064(each)X +1233(entry)X +1419(below,)X +1656(the)X +1775(\256rst)X +1920(part)X +2066(of)X +2154(the)X +2273(tag)X +2392(line)X +2533(is)X +2607(the)X +2726(full)X +2858(name)X +3053(of)X +3141(the)X +3261(option,)X +3507(followed)X +3814(by)X +3916(any)X +776 1374(equivalent)N +1135(abbreviations.)X +1632(\(Regardless)X +2036(of)X +2128(the)X +2251(abbreviations,)X +2728(it)X +2797(is)X +2875(only)X +3042(necessary)X +3380(to)X +3467(use)X +3599(the)X +3722(minimum)X +776 1464(number)N +1047(of)X +1140(characters)X +1493(necessary)X +1832(to)X +1920(distinguish)X +2296(an)X +2398(abbreviation)X +2825(from)X +3007(all)X +3113(other)X +3304(commands)X +3677(for)X +3797(it)X +3867(to)X +3956(be)X +776 1554(accepted,)N +1099(in)X +3 f +1182(nex)X +1 f +(/)S +3 f +1324(nvi)X +1 f +1430(.)X +1491(Historically,)X +1910(only)X +2073(the)X +2192(full)X +2324(name)X +2519(and)X +2656(the)X +2774(of\256cial)X +3021(abbreviations)X +3473(were)X +3650(accepted)X +3952(by)X +3 f +776 1644(ex)N +1 f +852(/)X +3 f +874(vi)X +1 f +936(.)X +1002(Using)X +1220(full)X +1358(names)X +1590(in)X +1679(your)X +1853(startup)X +2098(\256les)X +2258(and)X +2401(environmental)X +2891(variables)X +3208(will)X +3359(probably)X +3671(make)X +3872(them)X +776 1734(more)N +968(portable.\))X +1325(The)X +1477(part)X +1629(in)X +1718(square)X +1955(brackets)X +2250(is)X +2330(the)X +2454(default)X +2703(value)X +2903(of)X +2996(the)X +3120(option.)X +3390(Most)X +3580(of)X +3673(the)X +3797(options)X +776 1824(are)N +895(boolean,)X +1189(i.e.)X +1307(they)X +1465(are)X +1584(either)X +1787(on)X +1887(or)X +1974(off,)X +2108(and)X +2244(do)X +2344(not)X +2466(have)X +2638(an)X +2734(associated)X +3084(value.)X +976 1947(Options)N +1249(apply)X +1447(to)X +1529(both)X +3 f +1691(ex)X +1 f +1787(and)X +3 f +1923(vi)X +1 f +2005(modes,)X +2254(unless)X +2474(otherwise)X +2806(speci\256ed.)X +976 2070(For)N +1107(information)X +1505(on)X +1605(modifying)X +1958(the)X +2076(options)X +2331(or)X +2419(to)X +2502(display)X +2754(the)X +2873(options)X +3129(and)X +3266(their)X +3434(current)X +3683(values,)X +3929(see)X +776 2160(the)N +894(``set'')X +1111(command)X +1447(in)X +1529(the)X +1647(section)X +1894(entitled)X +2154(``)X +3 f +2208(Ex)X +2321(Commands)X +1 f +2712(''.)X +3 f +776 2340(altwerase)N +1122([off])X +976 2430(Vi)N +1 f +1084(only.)X +1295(Change)X +1569(how)X +3 f +1736(vi)X +1 f +1827(does)X +2003(word)X +2197(erase)X +2392(during)X +2630(text)X +2779(input.)X +3012(When)X +3233(this)X +3377(option)X +3610(is)X +3692(set,)X +3830(text)X +3979(is)X +976 2520(broken)N +1230(up)X +1340(into)X +1494(three)X +1685(classes:)X +1960(alphabetic,)X +2340(numeric)X +2633(and)X +2779(underscore)X +3162(characters,)X +3539(other)X +3734(nonblank)X +976 2610(characters,)N +1343(and)X +1479(blank)X +1677(characters.)X +2064(Changing)X +2395(from)X +2571(one)X +2707(class)X +2884(to)X +2967(another)X +3229(marks)X +3446(the)X +3565(end)X +3702(of)X +3790(a)X +3847(word.)X +976 2700(In)N +1070(addition,)X +1379(the)X +1504(class)X +1687(of)X +1781(the)X +1906(\256rst)X +2057(character)X +2380(erased)X +2612(is)X +2691(ignored)X +2962(\(which)X +3211(is)X +3290(exactly)X +3548(what)X +3730(you)X +3876(want)X +976 2790(when)N +1170(erasing)X +1422(pathname)X +1754(components\).)X +3 f +776 2970(autoindent,)N +1184(ai)X +1266([off])X +1 f +976 3060(If)N +1052(this)X +1189(option)X +1415(is)X +1490(set,)X +1621(whenever)X +1956(you)X +2098(create)X +2313(a)X +2371(new)X +2527(line)X +2669(\(using)X +2891(the)X +3 f +3012(vi)X +3097(A)X +1 f +3155(,)X +3 f +3198(a)X +1 f +(,)S +3 f +3281(C)X +1 f +3339(,)X +3 f +3382(c)X +1 f +3418(,)X +3 f +3461(I)X +1 f +3492(,)X +3 f +3535(i)X +1 f +3557(,)X +3 f +3600(O)X +1 f +3662(,)X +3 f +3705(o)X +1 f +(,)S +3 f +3788(R)X +1 f +3846(,)X +3 f +3889(r)X +1 f +3925(,)X +3 f +3968(S)X +1 f +4012(,)X +976 3150(and)N +3 f +1117(s)X +1 f +1173(commands,)X +1565(or)X +1657(the)X +3 f +1780(ex)X +1881(append)X +1 f +2133(,)X +3 f +2178(change)X +1 f +(,)S +2463(and)X +3 f +2604(insert)X +1 f +2825(commands\))X +3224(the)X +3346(new)X +3504(line)X +3648(is)X +3725(automati-)X +976 3240(cally)N +1156(indented)X +1456(to)X +1542(align)X +1726(the)X +1848(cursor)X +2073(with)X +2239(the)X +2361(\256rst)X +2509(nonblank)X +2831(character)X +3151(of)X +3242(the)X +3365(line)X +3510(from)X +3691(which)X +3912(you)X +976 3330(created)N +1231(it.)X +1337(Lines)X +1537(are)X +1658(indented)X +1956(using)X +2150(tab)X +2269(characters)X +2617(to)X +2700(the)X +2819(extent)X +3036(possible)X +3319(\(based)X +3550(on)X +3651(the)X +3770(value)X +3965(of)X +976 3420(the)N +3 f +1094(tabstop)X +1 f +1367(option\))X +1618(and)X +1754(then)X +1912(using)X +2105(space)X +2304(characters)X +2651(as)X +2738(necessary.)X +3111(For)X +3243(commands)X +3611(inserting)X +3912(text)X +976 3510(into)N +1124(the)X +1246(middle)X +1492(of)X +1583(a)X +1643(line,)X +1807(any)X +1947(blank)X +2149(characters)X +2500(to)X +2586(the)X +2708(right)X +2883(of)X +2974(the)X +3096(cursor)X +3321(are)X +3444(discarded,)X +3795(and)X +3934(the)X +976 3600(\256rst)N +1120(nonblank)X +1438(character)X +1754(to)X +1836(the)X +1954(right)X +2125(of)X +2212(the)X +2330(cursor)X +2551(is)X +2624(aligned)X +2880(as)X +2967(described)X +3295(above.)X +976 3780(The)N +1128(indent)X +1355(characters)X +1709(are)X +1835(themselves)X +2218(somewhat)X +2570(special.)X +2860(If)X +2941(you)X +3088(do)X +3195(not)X +3324(enter)X +3512(more)X +3705(characters)X +976 3870(on)N +1085(the)X +1212(new)X +1375(line)X +1524(before)X +1759(moving)X +2032(to)X +2123(another)X +2393(line,)X +2562(or)X +2658(entering)X +7 f +2950(<escape>)X +1 f +(,)S +3382(the)X +3508(indent)X +3736(character)X +976 3960(will)N +1121(be)X +1218(deleted)X +1471(and)X +1608(the)X +1727(line)X +1868(will)X +2013(be)X +2111(empty.)X +2373(For)X +2506(example,)X +2820(if)X +2891(you)X +3033(enter)X +7 f +3216(<carriage-return>)X +1 f +976 4050(twice)N +1181(in)X +1274(succession,)X +1668(the)X +1797(line)X +1947(created)X +2210(by)X +2320(the)X +2448(\256rst)X +7 f +2602(<carriage-return>)X +1 f +3448(will)X +3602(not)X +3734(have)X +3916(any)X +976 4140(characters)N +1323(in)X +1405(it,)X +1489(regardless)X +1835(of)X +1922(the)X +2040(indentation)X +2420(of)X +2507(the)X +2625(previous)X +2921(or)X +3008(subsequent)X +3384(line.)X +976 4320(Indent)N +1210(characters)X +1566(also)X +1725(require)X +1983(that)X +2133(you)X +2283(enter)X +2474(additional)X +2824(erase)X +3020(characters)X +3377(to)X +3469(delete)X +3691(them.)X +3921(For)X +976 4410(example,)N +1290(if)X +1361(you)X +1503(have)X +1677(an)X +1775(indented)X +2072(line,)X +2233(containing)X +2592(only)X +2755(blanks,)X +3005(the)X +3124(\256rst)X +7 f +3269(<word-erase>)X +1 f +3866(char-)X +976 4500(acter)N +1156(you)X +1299(enter)X +1483(will)X +1630(erase)X +1819(up)X +1922(to)X +2007(end)X +2146(of)X +2236(the)X +2357(indent)X +2580(characters,)X +2950(and)X +3089(the)X +3210(second)X +3456(will)X +3604(erase)X +3794(back)X +3970(to)X +976 4590(the)N +1094(beginning)X +1434(of)X +1521(the)X +1639(line.)X +1819(\(Historically,)X +2264(only)X +2426(the)X +3 f +2544(<control-D>)X +1 f +2986(key)X +3122(would)X +3342(erase)X +3528(the)X +3646(indent)X +3866(char-)X +976 4680(acters.)N +1231(Both)X +1413(the)X +3 f +1538(<control-D>)X +1 f +1988(key)X +2132(and)X +2276(the)X +2402(usual)X +2599(erase)X +2793(keys)X +2968(work)X +3161(in)X +3 f +3251(nvi)X +1 f +3357(.\))X +3452(In)X +3547(addition,)X +3857(if)X +3934(the)X +976 4770(cursor)N +1211(is)X +1298(positioned)X +1665(at)X +1756(the)X +1887(end)X +2036(of)X +2136(the)X +2267(indent)X +2500(characters,)X +2880(the)X +3011(keys)X +3191(``)X +7 f +3245(0<control-D>)X +1 f +('')S +3908(will)X +976 4860(erase)N +1163(all)X +1264(of)X +1352(the)X +1472(indent)X +1694(characters)X +2043(for)X +2159(the)X +2279(current)X +2529(line,)X +2691(resetting)X +2989(the)X +3109(indentation)X +3491(level)X +3669(to)X +3753(0.)X +3855(Simi-)X +976 4950(larly,)N +1168(the)X +1291(keys)X +1462(``)X +7 f +1516(\303<control-D>)X +1 f +('')S +2170(will)X +2318(erase)X +2508(all)X +2612(of)X +2703(the)X +2825(indent)X +3049(characters)X +3400(for)X +3518(the)X +3640(current)X +3892(line,)X +976 5040(leaving)N +1232(the)X +1350(indentation)X +1730(level)X +1906(for)X +2020(future)X +2232(created)X +2485(lines)X +2656(unaffected.)X +976 5220(Finally,)N +1243(if)X +1313(the)X +3 f +1432(autoindent)X +1 f +1821(option)X +2047(is)X +2122(set,)X +2253(the)X +3 f +2373(S)X +1 f +2439(and)X +3 f +2577(cc)X +1 f +2671(commands)X +3040(change)X +3290(from)X +3468(the)X +3588(\256rst)X +3734(nonblank)X +976 5310(of)N +1063(the)X +1181(line)X +1321(to)X +1403(the)X +1521(end)X +1657(of)X +1744(the)X +1862(line,)X +2022(instead)X +2269(of)X +2356(from)X +2532(the)X +2650(beginning)X +2990(of)X +3077(the)X +3195(line)X +3335(to)X +3417(the)X +3535(end)X +3671(of)X +3758(the)X +3876(line.)X +3 f +776 5490(autoprint,)N +1140(ap)X +1244([off])X +976 5580(Ex)N +1 f +1099(only.)X +1311(Cause)X +1537(the)X +1665(current)X +1923(line)X +2073(to)X +2165(be)X +2271(automatically)X +2738(displayed)X +3076(after)X +3255(the)X +3 f +3384(ex)X +1 f +3491(commands)X +3 f +3869(<)X +1 f +3915(,)X +3 f +3966(>)X +1 f +4012(,)X +3 f +976 5670(copy)N +1 f +(,)S +3 f +1176(delete)X +1 f +1377(,)X +3 f +1417(join)X +1 f +1550(,)X +3 f +1590(move)X +1 f +1773(,)X +3 f +1813(put)X +1 f +1928(,)X +3 f +1968(t)X +1 f +1995(,)X +3 f +2035(Undo)X +1 f +2221(,)X +2261(and)X +3 f +2397(undo)X +1 f +2569(.)X +2629(This)X +2791(automatic)X +3127(display)X +3378(is)X +3451(suppressed)X +3823(during)X +3 f +976 5760(global)N +1 f +1226(and)X +3 f +1384(vglobal)X +1 f +1675(commands,)X +2085(and)X +2244(for)X +2381(any)X +2540(command)X +2899(where)X +3139(optional)X +3444(\257ags)X +3638(are)X +3780(used)X +3970(to)X + +47 p +%%Page: 47 46 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3658(USD:13-47)X +1 f +976 762(explicitly)N +1298(display)X +1549(the)X +1667(line.)X +3 f +776 942(autowrite,)N +1146(aw)X +1264([off])X +1 f +976 1032(If)N +1053(this)X +1191(option)X +1418(is)X +1494(set,)X +1626(the)X +3 f +1747(vi)X +1832(!)X +1 f +1859(,)X +3 f +1902(\303\303)X +1 f +1956(,)X +3 f +1999(\303])X +1 f +2076(and)X +3 f +2215(<control-Z>)X +1 f +2655(commands,)X +3046(and)X +3186(the)X +3 f +3308(ex)X +3408(edit)X +1 f +3537(,)X +3 f +3581(next)X +1 f +3728(,)X +3 f +3772(rewind)X +1 f +(,)S +3 f +976 1122(stop)N +1 f +1118(,)X +3 f +1161(suspend)X +1 f +1435(,)X +3 f +1478(tag)X +1 f +1585(,)X +3 f +1628(tagpop)X +1 f +1863(,)X +1906(and)X +3 f +2045(tagtop)X +1 f +2286(commands)X +2656(automatically)X +3115(write)X +3302(the)X +3422(current)X +3672(\256le)X +3796(back)X +3970(to)X +976 1212(the)N +1103(current)X +1360(\256le)X +1491(name)X +1694(if)X +1772(it)X +1845(has)X +1981(been)X +2163(modi\256ed)X +2477(since)X +2672(it)X +2746(was)X +2901(last)X +3042(written.)X +3339(If)X +3423(the)X +3551(write)X +3746(fails,)X +3934(the)X +976 1302(command)N +1312(fails)X +1470(and)X +1606(goes)X +1773(no)X +1873(further.)X +976 1482(Appending)N +1363(the)X +1492(optional)X +1785(force)X +1982(\257ag)X +2133(character)X +2460(``)X +7 f +2514(!)X +1 f +('')S +2668(to)X +2762(the)X +3 f +2892(ex)X +1 f +3000(commands)X +3 f +3379(next)X +1 f +3526(,)X +3 f +3578(rewind)X +1 f +(,)S +3 f +3870(stop)X +1 f +4012(,)X +3 f +976 1572(suspend)N +1 f +1250(,)X +3 f +1290(tag)X +1 f +1397(,)X +3 f +1437(tagpop)X +1 f +1672(,)X +1712(and)X +3 f +1848(tagtop)X +1 f +2086(stops)X +2270(the)X +2388(automatic)X +2724(write)X +2909(from)X +3085(being)X +3283(attempted.)X +976 1752(\(Historically,)N +1421(the)X +3 f +1539(next)X +1 f +1706(command)X +2042(ignored)X +2307(the)X +2425(optional)X +2707(force)X +2894(\257ag.\))X +3102(Note,)X +3299(the)X +3 f +3418(ex)X +1 f +3515(commands)X +3 f +3883(edit)X +1 f +4012(,)X +3 f +976 1842(quit)N +1 f +1113(,)X +3 f +1153(shell)X +1 f +1308(,)X +1348(and)X +3 f +1484(xit)X +1 f +1593(are)X +2 f +1712(not)X +1 f +1834(affected)X +2114(by)X +2214(the)X +3 f +2332(autowrite)X +1 f +2682(option.)X +3 f +776 2022(beautify,)N +1096(bf)X +1187([off])X +1 f +976 2112(If)N +1061(this)X +1207(option)X +1442(is)X +1527(set,)X +1668(all)X +1780(control)X +2039(characters)X +2398(that)X +2550(are)X +2681(not)X +2815(currently)X +3137(being)X +3347(specially)X +3664(interpreted,)X +976 2202(other)N +1166(than)X +7 f +1329(<tab>)X +1 f +(,)S +7 f +1613(<newline>)X +1 f +(,)S +2089(and)X +7 f +2229(<form-feed>)X +1 f +(,)S +2801(are)X +2924(discarded)X +3256(from)X +3436(commands)X +3807(read)X +3970(in)X +976 2292(by)N +3 f +1078(ex)X +1 f +1176(from)X +1354(command)X +1692(\256les,)X +1867(and)X +2005(from)X +2183(input)X +2369(text)X +2511(entered)X +2770(to)X +3 f +2854(vi)X +1 f +2938(\(either)X +3170(into)X +3316(the)X +3436(\256le)X +3560(or)X +3649(to)X +3733(the)X +3854(colon)X +976 2382(command)N +1312(line\).)X +1519(Text)X +1686(\256les)X +1839(read)X +1998(by)X +3 f +2098(ex)X +1 f +2174(/)X +3 f +2196(vi)X +1 f +2278(are)X +2 f +2397(not)X +1 f +2519(affected)X +2799(by)X +2899(the)X +3 f +3017(beautify)X +1 f +3317(option.)X +3 f +776 2562(cdpath)N +1031([environment)X +1514(variable)X +1814(CDPATH,)X +2192(or)X +2288(current)X +2567(directory])X +1 f +976 2652(This)N +1152(option)X +1390(is)X +1477(used)X +1658(to)X +1754(specify)X +2020(a)X +2090(colon)X +2302(separated)X +2640(list)X +2771(of)X +2872(directories)X +3245(which)X +3476(are)X +3610(used)X +3792(as)X +3894(path)X +976 2742(pre\256xes)N +1252(for)X +1368(any)X +1506(relative)X +1769(path)X +1929(names)X +2156(used)X +2325(as)X +2414(arguments)X +2770(for)X +2886(the)X +3 f +3006(cd)X +1 f +3108(command.)X +3486(The)X +3633(value)X +3829(of)X +3917(this)X +976 2832(option)N +1202(defaults)X +1478(to)X +1562(the)X +1682(value)X +1878(of)X +1967(the)X +2088(environmental)X +2574(variable)X +7 f +2856(CDPATH)X +1 f +3167(if)X +3239(it)X +3306(is)X +3382(set,)X +3514(otherwise)X +3849(to)X +3934(the)X +976 2922(current)N +1232(directory.)X +1590(For)X +1729(compatibility)X +2183(with)X +2353(the)X +2478(POSIX)X +2736(1003.2)X +2983(shell,)X +3181(the)X +3 f +3306(cd)X +1 f +3413(command)X +3756(does)X +2 f +3930(not)X +1 f +976 3012(check)N +1200(the)X +1334(current)X +1598(directory)X +1924(as)X +2027(a)X +2099(path)X +2273(pre\256x)X +2496(for)X +2627(relative)X +2905(path)X +3080(names)X +3322(unless)X +3559(it)X +3640(is)X +3730(explicitly)X +976 3102(speci\256ed.)N +1334(It)X +1416(may)X +1586(be)X +1694(so)X +1797(speci\256ed)X +2114(by)X +2226(entering)X +2521(an)X +2629(empty)X +2861(string)X +3075(or)X +3174(a)X +3242(``)X +7 f +3296(.)X +1 f +('')S +3450(character)X +3778(into)X +3934(the)X +7 f +976 3192(CDPATH)N +1 f +1284(variable)X +1563(or)X +1650(the)X +1768(option)X +1992(value.)X +3 f +776 3372(columns,)N +1100(co)X +1196([80])X +1 f +976 3462(The)N +1132(number)X +1408(of)X +1506(columns)X +1808(in)X +1901(the)X +2030(screen.)X +2307(Setting)X +2565(this)X +2712(option)X +2948(causes)X +3 f +3190(ex)X +1 f +3266(/)X +3 f +3288(vi)X +1 f +3382(to)X +3476(set)X +3597(\(or)X +3723(reset\))X +3934(the)X +976 3552(environmental)N +1464(variable)X +7 f +1748(COLUMNS)X +1 f +(.)S +2149(See)X +2290(the)X +2413(section)X +2665(entitled)X +2930(``)X +3 f +2984(Sizing)X +3217(the)X +3349(Screen)X +1 f +3581('')X +3660(more)X +3849(infor-)X +976 3642(mation.)N +3 f +776 3822(comment)N +1113([off])X +976 3912(Vi)N +1 f +1079(only.)X +1284(If)X +1361(the)X +1482(\256rst)X +1629(non-empty)X +1999(line)X +2142(of)X +2232(the)X +2354(\256le)X +2480(begins)X +2713(with)X +2879(the)X +3001(string)X +3207(``)X +7 f +3261(/*)X +1 f +('',)S +3455(this)X +3594(option)X +3822(causes)X +3 f +976 4002(vi)N +1 f +1072(to)X +1167(skip)X +1333(to)X +1428(the)X +1559(end)X +1708(of)X +1808(that)X +1961(C-language)X +2364(comment)X +2695(\(probably)X +3040(a)X +3109(terribly)X +3378(boring)X +3620(legal)X +3809(notice\))X +976 4092(before)N +1202(displaying)X +1555(the)X +1673(\256le.)X +3 f +776 4272(directory,)N +1133(dir)X +1255([environment)X +1738(variable)X +2038(TMPDIR,)X +2403(or)X +2499(/tmp])X +1 f +976 4362(The)N +1123(directory)X +1435(where)X +1655(temporary)X +2008(\256les)X +2164(are)X +2286(created.)X +2582(The)X +2730(environmental)X +3216(variable)X +7 f +3498(TMPDIR)X +1 f +3809(is)X +3885(used)X +976 4452(as)N +1063(the)X +1181(default)X +1424(value)X +1618(if)X +1687(it)X +1751(exists,)X +1973(otherwise)X +7 f +2305(/tmp)X +1 f +2517(is)X +2590(used.)X +3 f +776 4632(edcompatible,)N +1274(ed)X +1374([off])X +1 f +976 4722(Remember)N +1349(the)X +1468(values)X +1694(of)X +1782(the)X +1901(``c'')X +2066(and)X +2203(``g'')X +2372(suf\256ces)X +2638(to)X +2721(the)X +3 f +2840(substitute)X +1 f +3194(commands,)X +3583(instead)X +3832(of)X +3921(ini-)X +976 4812(tializing)N +1262(them)X +1446(as)X +1537(unset)X +1730(for)X +1848(each)X +2020(new)X +2178(command.)X +2558(Specifying)X +2929(pattern)X +3176(and)X +3316(replacement)X +3733(strings)X +3970(to)X +976 4902(the)N +3 f +1094(substitute)X +1 f +1447(command)X +1783(unsets)X +2003(the)X +2121(``c'')X +2285(and)X +2421(``g'')X +2589(suf\256ces)X +2854(as)X +2941(well.)X +3 f +776 5082(errorbells,)N +1155(eb)X +1255([off])X +976 5172(Ex)N +1 f +1089(only.)X +3 f +1292(Ex)X +1 f +1406(error)X +1584(messages)X +1908(are)X +2028(normally)X +2338(presented)X +2667(in)X +2750(inverse)X +3003(video.)X +3242(If)X +3317(that)X +3458(is)X +3532(not)X +3655(possible)X +3938(for)X +976 5262(the)N +1096(terminal,)X +1405(setting)X +1640(this)X +1777(option)X +2003(causes)X +2235(error)X +2414(messages)X +2739(to)X +2823(be)X +2921(announced)X +3291(by)X +3393(ringing)X +3646(the)X +3765(terminal)X +976 5352(bell.)N +3 f +776 5532(exrc,)N +964(ex)X +1060([off])X +1 f +976 5622(If)N +1061(this)X +1207(option)X +1442(is)X +1526(turned)X +1762(off)X +1887(in)X +1980(the)X +2109(system)X +2362(or)X +2460($HOME)X +2767(startup)X +3016(\256les,)X +3200(the)X +3330(local)X +3518(startup)X +3768(\256les)X +3933(are)X +976 5712(never)N +1177(read)X +1338(\(unless)X +1587(they)X +1747(are)X +1868(the)X +1988(same)X +2175(as)X +2264(the)X +2384(system)X +2628(or)X +2717($HOME)X +3015(startup)X +3255(\256les\).)X +3477(Turning)X +3757(it)X +3823(on)X +3925(has)X +976 5802(no)N +1091(effect,)X +1330(i.e.)X +1463(the)X +1596(normal)X +1858(checks)X +2112(for)X +2241(local)X +2432(startup)X +2685(\256les)X +2854(are)X +2989(performed,)X +3380(regardless.)X +3782(See)X +3934(the)X + +48 p +%%Page: 48 47 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-48)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +1 f +976 762(section)N +1223(entitled)X +1483(``)X +3 f +1537(Startup)X +1819(Information)X +1 f +2237('')X +2311(for)X +2425(more)X +2610(information.)X +3 f +776 942(extended)N +1103([off])X +1 f +976 1032(This)N +1147(option)X +1380(causes)X +1619(all)X +1728(regular)X +1986(expressions)X +2390(to)X +2482(be)X +2588(treated)X +2837(as)X +2934(POSIX)X +3195(1003.2)X +3445(Extended)X +3778(Regular)X +976 1122(Expressions)N +1383(\(which)X +1626(are)X +1745(similar)X +1987(to)X +2069(historic)X +2 f +2329(egrep)X +1 f +2512(\(1\))X +2626(style)X +2797(expressions\).)X +3 f +776 1302(\257ash)N +955([on])X +1 f +976 1392(This)N +1139(option)X +1364(causes)X +1595(the)X +1714(screen)X +1941(to)X +2025(\257ash)X +2198(instead)X +2447(of)X +2536(beeping)X +2812(the)X +2932(keyboard,)X +3273(on)X +3375(error,)X +3574(if)X +3645(the)X +3765(terminal)X +976 1482(has)N +1103(the)X +1221(capability.)X +3 f +776 1662(hardtabs,)N +1122(ht)X +1213([8])X +1 f +976 1752(This)N +1141(option)X +1369(de\256nes)X +1620(the)X +1742(spacing)X +2011(between)X +2303(hardware)X +2627(tab)X +2749(settings,)X +3037(i.e.)X +3179(the)X +3301(tab)X +3423(expansion)X +3772(done)X +3952(by)X +976 1842(the)N +1099(operating)X +1427(system)X +1674(and/or)X +1904(the)X +2027(terminal)X +2319(itself.)X +2544(As)X +3 f +2658(nex)X +1 f +(/)S +3 f +2800(nvi)X +1 f +2931(never)X +3135(writes)X +7 f +3355(<tab>)X +1 f +3619(characters)X +3970(to)X +976 1932(the)N +1094(terminal,)X +1401(unlike)X +1621(historic)X +1881(versions)X +2168(of)X +3 f +2255(ex)X +1 f +2331(/)X +3 f +2353(vi)X +1 f +2415(,)X +2455(this)X +2590(option)X +2814(does)X +2981(not)X +3103(currently)X +3413(have)X +3585(any)X +3721(affect.)X +3 f +776 2112(ignorecase,)N +1177(ic)X +1255([off])X +1 f +976 2202(This)N +1141(option)X +1368(causes)X +1602(regular)X +1854(expressions,)X +2272(both)X +2438(in)X +3 f +2524(ex)X +1 f +2624(commands)X +2995(and)X +3135(in)X +3221(searches,)X +3538(to)X +3624(be)X +3724(evaluated)X +976 2292(in)N +1058(a)X +1114(case-insensitive)X +1642(manner.)X +3 f +776 2472(keytime)N +1068([6])X +1 f +976 2562(The)N +1121(10th's)X +1341(of)X +1428(a)X +1484(second)X +3 f +1727(ex)X +1 f +1803(/)X +3 f +1825(vi)X +1 f +1907(waits)X +2096(for)X +2210(a)X +2266(subsequent)X +2642(key)X +2778(to)X +2860(complete)X +3174(a)X +3230(key)X +3366(mapping.)X +3 f +776 2742(leftright)N +1077([off])X +976 2832(Vi)N +1 f +1083(only.)X +1293(This)X +1463(option)X +1695(causes)X +1933(the)X +2059(screen)X +2293(to)X +2383(be)X +2487(scrolled)X +2769(left-right)X +3082(to)X +3172(view)X +3356(lines)X +3535(longer)X +3768(than)X +3934(the)X +976 2922(screen,)N +1232(instead)X +1489(of)X +1586(the)X +1714(traditional)X +3 f +2073(vi)X +1 f +2165(screen)X +2401(interface)X +2713(which)X +2939(folds)X +3129(long)X +3301(lines)X +3482(at)X +3570(the)X +3698(right-hand)X +976 3012(margin)N +1223(of)X +1310(the)X +1428(terminal.)X +3 f +776 3192(lines,)N +971(li)X +1035([24])X +976 3282(Vi)N +1 f +1076(only.)X +1278(The)X +1423(number)X +1688(of)X +1775(lines)X +1946(in)X +2028(the)X +2146(screen.)X +2412(Setting)X +2658(this)X +2793(option)X +3017(causes)X +3 f +3247(ex)X +1 f +3323(/)X +3 f +3345(vi)X +1 f +3427(to)X +3509(set)X +3619(\(or)X +3734(reset\))X +3934(the)X +976 3372(environmental)N +1462(variable)X +7 f +1744(LINES)X +1 f +(.)S +2047(See)X +2186(the)X +2307(section)X +2557(entitled)X +2820(``)X +3 f +2874(Sizing)X +3105(the)X +3235(Screen)X +1 f +3467('')X +3544(for)X +3661(more)X +3849(infor-)X +976 3462(mation.)N +3 f +776 3642(lisp)N +915([off])X +976 3732(Vi)N +1 f +1078(only.)X +1282(This)X +1447(option)X +1674(changes)X +1956(the)X +2077(behavior)X +2381(of)X +2471(the)X +3 f +2592(vi)X +2677(\()X +1 f +2704(,)X +3 f +2747(\))X +1 f +2774(,)X +3 f +2817({)X +1 f +2849(,)X +3 f +2892(})X +1 f +2924(,)X +3 f +2967([[)X +1 f +3044(and)X +3 f +3183(]])X +1 f +3260(commands)X +3630(to)X +3715(match)X +3934(the)X +976 3822(Lisp)N +1138(language.)X +1488(Also,)X +1679(the)X +3 f +1797(autoindent)X +1 f +2185(option's)X +2467(behavior)X +2768(is)X +2841(changed)X +3129(to)X +3211(be)X +3307(appropriate)X +3693(for)X +3807(Lisp.)X +2 f +976 4002(This)N +1133(option)X +1357(is)X +1430(not)X +1552(yet)X +1666(implemented.)X +3 f +776 4182(list)N +898([off])X +1 f +976 4272(This)N +1151(option)X +1388(causes)X +1631(lines)X +1815(to)X +1910(be)X +2019(displayed)X +2359(in)X +2454(an)X +2563(unambiguous)X +3028(fashion.)X +3338(Speci\256cally,)X +3770(tabs)X +3933(are)X +976 4362(displayed)N +1305(as)X +1394(control)X +1643(characters,)X +2012(i.e.)X +2152(``)X +7 f +2206(\303I)X +1 f +('',)S +2398(and)X +2536(the)X +2656(ends)X +2825(of)X +2914(lines)X +3087(are)X +3207(marked)X +3469(with)X +3632(a)X +3689(``)X +7 f +3743($)X +1 f +('')S +3866(char-)X +976 4452(acter.)N +3 f +776 4632(magic)N +1001([on])X +1 f +976 4722(This)N +1141(option)X +1368(is)X +1444(on)X +1547(by)X +1650(default.)X +1936(Turning)X +2217(the)X +3 f +2338(magic)X +1 f +2566(option)X +2793(off)X +2910(causes)X +3143(all)X +3247(regular)X +3499(expression)X +3866(char-)X +976 4812(acters)N +1189(except)X +1423(for)X +1541(``)X +7 f +1595(\303)X +1 f +('')S +1721(and)X +1861(``)X +7 f +1915($)X +1 f +('',)S +2061(to)X +2147(be)X +2247(treated)X +2490(as)X +2581(ordinary)X +2877(characters.)X +3268(To)X +3381(re-enable)X +3705(characters)X +976 4902(individually,)N +1402(when)X +1597(the)X +3 f +1716(magic)X +1 f +1942(option)X +2167(is)X +2241(off,)X +2376(precede)X +2648(them)X +2829(with)X +2992(a)X +3049(backslash)X +3382(``)X +7 f +3436(\\)X +1 f +('')S +3559(character.)X +3916(See)X +976 4992(the)N +1094(section)X +1341(entitled)X +1601(``)X +3 f +1655(Regular)X +1951(Expressions)X +2379(and)X +2527(Replacement)X +2993(Strings)X +1 f +3237('')X +3311(for)X +3425(more)X +3610(information.)X +3 f +776 5172(matchtime)N +1162([7])X +976 5262(Vi)N +1 f +1078(only.)X +1282(The)X +1429(10th's)X +1651(of)X +1740(a)X +1798(second)X +3 f +2043(ex)X +1 f +2119(/)X +3 f +2141(vi)X +1 f +2226(pauses)X +2463(on)X +2566(the)X +2687(matching)X +3008(character)X +3327(when)X +3524(the)X +3 f +3645(showmatch)X +1 f +976 5352(option)N +1200(is)X +1273(set.)X +3 f +776 5532(mesg)N +970([on])X +1 f +976 5622(This)N +1140(option)X +1366(allows)X +1597(other)X +1784(users)X +1972(to)X +2057(contact)X +2312(you)X +2455(using)X +2651(the)X +2 f +2772(talk)X +1 f +(\(1\))S +3009(and)X +2 f +3148(write)X +1 f +3312(\(1\))X +3429(utilities,)X +3711(while)X +3912(you)X +976 5712(are)N +1101(editing.)X +3 f +1389(Ex)X +1 f +1482(/)X +3 f +1504(vi)X +1 f +1592(does)X +1764(not)X +1891(turn)X +2045(message)X +2342(on,)X +2467(i.e.)X +2590(if)X +2664(messages)X +2992(were)X +3174(turned)X +3404(off)X +3523(when)X +3722(the)X +3845(editor)X +976 5802(was)N +1124(invoked,)X +1425(they)X +1586(will)X +1733(stay)X +1885(turned)X +2113(off.)X +2270(This)X +2435(option)X +2662(only)X +2827(permits)X +3090(you)X +3233(to)X +3318(disallow)X +3612(messages)X +3938(for)X + +49 p +%%Page: 49 48 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3658(USD:13-49)X +1 f +976 762(the)N +1094(edit)X +1234(session.)X +1525(See)X +1661(the)X +2 f +1779(mesg)X +1 f +1944(\(1\))X +2058(utility)X +2268(for)X +2382(more)X +2567(information.)X +3 f +776 942(modelines,)N +1158(modeline)X +1489([off])X +1 f +976 1032(If)N +1052(the)X +3 f +1172(modelines)X +1 f +1536(option)X +1762(is)X +1837(set,)X +3 f +1968(ex)X +1 f +2044(/)X +3 f +2066(vi)X +1 f +2150(has)X +2279(historically)X +2661(scanned)X +2942(the)X +3062(\256rst)X +3208(and)X +3346(last)X +3479(\256ve)X +3621(lines)X +3794(of)X +3884(each)X +976 1122(\256le)N +1101(as)X +1191(it)X +1258(is)X +1334(read)X +1496(for)X +1613(editing,)X +1877(looking)X +2143(for)X +2259(any)X +3 f +2397(ex)X +1 f +2495(commands)X +2864(that)X +3006(have)X +3180(been)X +3354(placed)X +3586(in)X +3670(those)X +3861(lines.)X +976 1212(After)N +1167(the)X +1286(startup)X +1525(information)X +1924(has)X +2052(been)X +2225(processed,)X +2583(and)X +2720(before)X +2947(the)X +3066(user)X +3221(starts)X +3411(editing)X +3654(the)X +3773(\256le,)X +3916(any)X +976 1302(commands)N +1343(embedded)X +1693(in)X +1775(the)X +1893(\256le)X +2015(are)X +2134(executed.)X +976 1482(Commands)N +1362(were)X +1541(recognized)X +1916(by)X +2018(the)X +2138(letters)X +2356(``e'')X +2522(or)X +2611(``v'')X +2781(followed)X +3088(by)X +3191(``x'')X +3362(or)X +3452(``i'',)X +3625(at)X +3706(the)X +3827(begin-)X +976 1572(ning)N +1144(of)X +1237(a)X +1299(line)X +1445(or)X +1538(following)X +1875(a)X +1937(tab)X +2061(or)X +2154(space)X +2359(character,)X +2701(and)X +2843(followed)X +3153(by)X +3258(a)X +3319(``:'',)X +3494(an)X +3 f +3595(ex)X +1 f +3696(command,)X +976 1662(and)N +1112(another)X +1373(``:''.)X +976 1842(This)N +1144(option)X +1374(is)X +1453(a)X +1516(security)X +1797(problem)X +2091(of)X +2185(immense)X +2501(proportions,)X +2917(and)X +3060(should)X +3300(not)X +3429(be)X +3532(used)X +3706(under)X +3916(any)X +976 1932(circumstances.)N +2 f +976 2112(This)N +1133(option)X +1357(will)X +1496(never)X +1695(be)X +1791(implemented.)X +3 f +776 2292(number,)N +1087(nu)X +1195([off])X +1 f +976 2382(Precede)N +1251(each)X +1419(line)X +1559(displayed)X +1886(with)X +2048(its)X +2143(current)X +2391(line)X +2531(number.)X +3 f +776 2562(octal)N +961([off])X +1 f +976 2652(Display)N +1245(unknown)X +1563(characters)X +1910(as)X +1997(octal)X +2173(numbers,)X +2489(instead)X +2736(of)X +2823(the)X +2941(default)X +3184(hexadecimal.)X +3 f +776 2832(open)N +960([on])X +976 2922(Ex)N +1 f +1089(only.)X +1291(If)X +1365(this)X +1500(option)X +1724(is)X +1797(not)X +1919(set,)X +2048(the)X +3 f +2166(open)X +1 f +2350(and)X +3 f +2486(visual)X +1 f +2705(commands)X +3072(are)X +3191(disallowed.)X +3 f +776 3102(optimize,)N +1110(opt)X +1241([on])X +976 3192(Vi)N +1 f +1081(only.)X +1288(Throughput)X +1691(of)X +1783(text)X +1929(is)X +2008(expedited)X +2346(by)X +2452(setting)X +2691(the)X +2815(terminal)X +3108(not)X +3236(to)X +3324(do)X +3430(automatic)X +3772(carriage)X +976 3282(returns)N +1222(when)X +1419(printing)X +1695(more)X +1883(than)X +2044(one)X +2183(\(logical\))X +2478(line)X +2621(of)X +2710(output,)X +2956(greatly)X +3201(speeding)X +3508(output)X +3734(on)X +3836(termi-)X +976 3372(nals)N +1125(without)X +1389(addressable)X +1784(cursors)X +2036(when)X +2230(text)X +2370(with)X +2532(leading)X +2788(white)X +2986(space)X +3185(is)X +3258(printed.)X +2 f +976 3552(This)N +1133(option)X +1357(is)X +1430(not)X +1552(yet)X +1666(implemented.)X +3 f +776 3732(paragraphs,)N +1211(para)X +1391([IPLPPPQPP)X +1878 -0.3625(LIpplpipbp])AX +976 3822(Vi)N +1 f +1079(only.)X +1284(De\256ne)X +1521(additional)X +1864(paragraph)X +2209(boundaries)X +2584(for)X +2701(the)X +3 f +2822({)X +1 f +2877(and)X +3 f +3016(})X +1 f +3071(commands.)X +3481(The)X +3629(value)X +3826(of)X +3917(this)X +976 3912(option)N +1200(must)X +1375(be)X +1471(a)X +1527(character)X +1843(string)X +2045(consisting)X +2389(of)X +2476(zero)X +2635(or)X +2722(more)X +2907(character)X +3223(pairs.)X +976 4092(In)N +1070(the)X +1195(text)X +1342(to)X +1431(be)X +1534(edited,)X +1777(the)X +1902(character)X +2226(string)X +7 f +2436(<newline>.<char-pair>)X +1 f +(,)S +3492(\(where)X +7 f +3744(<char-)X +976 4182(pair>)N +1 f +1241(is)X +1319(one)X +1460(of)X +1552(the)X +1675(character)X +1996(pairs)X +2177(in)X +2264(the)X +2386(option's)X +2672(value\))X +2897(de\256nes)X +3148(a)X +3208(paragraph)X +3554(boundary.)X +3921(For)X +976 4272(example,)N +1291(if)X +1363(the)X +1484(option)X +1711(were)X +1891(set)X +2003(to)X +7 f +2088(LaA<space>##)X +1 f +(,)S +2708(then)X +2870(all)X +2974(of)X +3065(the)X +3187(following)X +3522(additional)X +3866(para-)X +976 4362(graph)N +1179(boundaries)X +1551(would)X +1771(be)X +1867(recognized:)X +1296 4575(<newline>.La)N +1296 4665(<newline>.A<space>)N +1296 4755(<newline>.##)N +3 f +776 4968(prompt)N +1054([on])X +976 5058(Ex)N +1 f +1090(only.)X +1293(This)X +1456(option)X +1681(causes)X +3 f +1912(ex)X +1 f +2009(to)X +2092(prompt)X +2344(for)X +2459(command)X +2796(input)X +2981(with)X +3144(a)X +3201(``)X +7 f +3255(:)X +1 f +('')S +3378(character;)X +3717(when)X +3913(it)X +3979(is)X +976 5148(not)N +1098(set,)X +1227(no)X +1327(prompt)X +1578(is)X +1651(displayed.)X +3 f +776 5328(readonly,)N +1118(ro)X +1214([off])X +1 f +976 5418(This)N +1138(option)X +1362(causes)X +1592(a)X +1648(force)X +1834(\257ag)X +1974(to)X +2056(be)X +2152(required)X +2440(to)X +2522(attempt)X +2782(to)X +2864(write)X +3049(the)X +3167(\256le)X +3289(back)X +3461(to)X +3543(the)X +3661(original)X +3930(\256le)X +976 5508(name.)N +1215(Setting)X +1466(this)X +1605(option)X +1833(is)X +1910(equivalent)X +2268(to)X +2354(using)X +2551(the)X +3 f +9 f +2673(-)X +2675(-)X +3 f +2719(R)X +1 f +2801(command)X +3141(line)X +3285(option,)X +3533(or)X +3624(editing)X +3870(a)X +3930(\256le)X +976 5598(which)N +1192(lacks)X +1377(write)X +1562(permission.)X + +50 p +%%Page: 50 49 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-50)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +776 762(recdir)N +1006([/var/tmp/vi.recover])X +1 f +976 852(The)N +1121(directory)X +1431(where)X +1648(recovery)X +1950(\256les)X +2103(are)X +2222(stored.)X +976 1032(If)N +1051(you)X +1192(change)X +1441(the)X +1561(value)X +1757(of)X +3 f +1846(recdir)X +1 f +2056(,)X +2098(be)X +2196(careful)X +2442(to)X +2526(choose)X +2771(a)X +2829(directory)X +3141(whose)X +3368(contents)X +3657(are)X +3778(not)X +3902(reg-)X +976 1122(ularly)N +1197(deleted.)X +1503(Bad)X +1666(choices)X +1941(include)X +2211(directories)X +2584(in)X +2680(memory)X +2981(based)X +3198(\256lesystems,)X +3607(or)X +7 f +3707(/tmp)X +1 f +(,)S +3952(on)X +976 1212(most)N +1151(systems,)X +1444(as)X +1531(their)X +1698(contents)X +1985(are)X +2104(removed)X +2405(when)X +2599(the)X +2717(machine)X +3009(is)X +3082(rebooted.)X +976 1392(Public)N +1219(directories)X +1597(like)X +7 f +1757(/usr/tmp)X +1 f +2181(and)X +7 f +2337(/var/tmp)X +1 f +2761(are)X +2900(usually)X +3171(safe,)X +3361(although)X +3681(some)X +3890(sites)X +976 1482(periodically)N +1387(prune)X +1598(old)X +1728(\256les)X +1889(from)X +2073(them.)X +2301(There)X +2517(is)X +2598(no)X +2706(requirement)X +3122(that)X +3270(you)X +3418(use)X +3553(a)X +3617(public)X +3844(direc-)X +976 1572(tory,)N +1145(e.g.)X +1281(a)X +1337(sub-directory)X +1785(of)X +1872(your)X +2039(home)X +2237(directory)X +2547(will)X +2691(work)X +2876(\256ne.)X +976 1752(Finally,)N +1248(if)X +1323(you)X +1469(change)X +1723(the)X +1847(value)X +2047(of)X +3 f +2140(recdir)X +1 f +2350(,)X +2396(you)X +2542(must)X +2723(modify)X +2980(the)X +3104(recovery)X +3412(script)X +3617(to)X +3706(operate)X +3970(in)X +976 1842(your)N +1143(chosen)X +1386(recovery)X +1688(area.)X +976 2022(See)N +1112(the)X +1230(section)X +1477(entitled)X +1737(``)X +3 f +1791(Recovery)X +1 f +2113('')X +2187(for)X +2301(further)X +2540(information.)X +3 f +776 2202(redraw,)N +1066(re)X +1158([off])X +976 2292(Vi)N +1 f +1087(only.)X +1301(The)X +1458(editor)X +1677(simulates)X +2011(\(using)X +2243(great)X +2436(amounts)X +2739(of)X +2838(output\),)X +3121(an)X +3229(intelligent)X +3585(terminal)X +3884(on)X +3996(a)X +976 2382(dumb)N +1200(terminal)X +1509(\(e.g.)X +1694(during)X +1945(insertions)X +2297(in)X +3 f +2400(vi)X +1 f +2503(the)X +2642(characters)X +3010(to)X +3113(the)X +3252(right)X +3444(of)X +3552(the)X +3691(cursor)X +3933(are)X +976 2472(refreshed)N +1296(as)X +1383(each)X +1551(input)X +1735(character)X +2051(is)X +2124(typed\).)X +2 f +976 2652(This)N +1133(option)X +1357(is)X +1430(not)X +1552(yet)X +1666(implemented.)X +3 f +776 2832(remap)N +1019([on])X +1 f +976 2922(If)N +1055(this)X +1195(option)X +1424(is)X +1502(set,)X +1636(it)X +1705(is)X +1783(possible)X +2070(to)X +2157(de\256ne)X +2378(macros)X +2635(in)X +2722(terms)X +2926(of)X +3019(other)X +3210(macros.)X +3508(Otherwise,)X +3884(each)X +976 3012(key)N +1121(is)X +1203(only)X +1374(remapped)X +1720(up)X +1829(to)X +1920(one)X +2064(time.)X +2274(For)X +2413(example,)X +2733(if)X +2810(``)X +7 f +2864(A)X +1 f +('')S +2994(is)X +3075(mapped)X +3357(to)X +3447(``)X +7 f +3501(B)X +1 f +('',)S +3651(and)X +3795(``)X +7 f +3849(B)X +1 f +('')S +3979(is)X +976 3102(mapped)N +1251(to)X +1334(``)X +7 f +1388(C)X +1 f +('',)S +1531(The)X +1677(keystroke)X +2010(``)X +7 f +2064(A)X +1 f +('')S +2187(will)X +2332(be)X +2429(mapped)X +2704(to)X +2787(``)X +7 f +2841(C)X +1 f +('')S +2964(if)X +3035(the)X +3 f +3155(remap)X +1 f +3400(option)X +3626(is)X +3701(set,)X +3832(and)X +3970(to)X +976 3192(``)N +7 f +1030(B)X +1 f +('')S +1152(if)X +1221(it)X +1285(is)X +1358(not)X +1480(set.)X +3 f +776 3372(report)N +1015([5])X +1 f +976 3462(Set)N +1103(the)X +1226(threshold)X +1549(of)X +1642(the)X +1766(number)X +2037(of)X +2130(lines)X +2307(that)X +2453(need)X +2631(to)X +2719(be)X +2821(changed)X +3115(or)X +3208(yanked)X +3466(before)X +3698(a)X +3760(message)X +976 3552(will)N +1127(be)X +1230(displayed)X +1564(to)X +1653(the)X +1778(user.)X +1979(For)X +2117(everything)X +2487(but)X +2616(the)X +2741(yank)X +2924(command,)X +3287(the)X +3412(value)X +3613(is)X +3693(the)X +3818(largest)X +976 3642(value)N +1172(about)X +1372(which)X +1590(the)X +1711(editor)X +1921(is)X +1997(silent,)X +2213(i.e.)X +2334(by)X +2437(default,)X +2703(6)X +2766(lines)X +2940(must)X +3118(be)X +3217(deleted)X +3472(before)X +3701(the)X +3822(user)X +3979(is)X +976 3732(noti\256ed.)N +1283(However,)X +1621(if)X +1693(the)X +1814(number)X +2082(of)X +2172(lines)X +2346(yanked)X +2601(is)X +2677(greater)X +2924(than)X +2 f +3085(or)X +3179(equal)X +3380(to)X +1 f +3465(the)X +3586(set)X +3697(value,)X +3913(it)X +3979(is)X +976 3822(reported)N +1264(to)X +1346(the)X +1464(user.)X +3 f +776 4002(ruler)N +970([off])X +976 4092(Vi)N +1 f +1076(only.)X +1278(Display)X +1547(a)X +1603(row/column)X +2010(ruler)X +2182(on)X +2282(the)X +2400(colon)X +2598(command)X +2934(line.)X +3 f +776 4272(scroll,)N +1003(scr)X +1126([window)X +1439(/)X +1481(2])X +1 f +976 4362(Set)N +1098(the)X +1216(number)X +1481(of)X +1568(lines)X +1739(scrolled)X +2013(by)X +2113(the)X +3 f +2231(vi)X +2313(<control-D>)X +1 f +2755(and)X +3 f +2891(<control-U>)X +1 f +3333(commands.)X +976 4542(Historically,)N +1395(the)X +3 f +1514(ex)X +1611(z)X +1 f +1668(command,)X +2025(when)X +2221(speci\256ed)X +2528(without)X +2794(a)X +2852(count,)X +3072(used)X +3241(two)X +3383(times)X +3578(the)X +3698(size)X +3845(of)X +3934(the)X +976 4632(scroll)N +1174(value;)X +1390(the)X +1508(POSIX)X +1759(1003.2)X +1999(standard)X +2291(speci\256ed)X +2596(the)X +2714(window)X +2992(size,)X +3157(which)X +3373(is)X +3446(a)X +3502(better)X +3705(choice.)X +3 f +776 4812(sections,)N +1083(sect)X +1233([NHSHH)X +1568(HUnhsh])X +976 4902(Vi)N +1 f +1076(only.)X +1278(De\256ne)X +1512(additional)X +1852(section)X +2099(boundaries)X +2471(for)X +2585(the)X +3 f +2703([[)X +1 f +2777(and)X +3 f +2913(]])X +1 f +2987(commands.)X +3394(The)X +3 f +3540(sections)X +1 f +3828(option)X +976 4992(should)N +1213(be)X +1313(set)X +1426(to)X +1512(a)X +1572(character)X +1892(string)X +2098(consisting)X +2446(of)X +2537(zero)X +2700(or)X +2791(more)X +2979(character)X +3298(pairs.)X +3517(In)X +3607(the)X +3728(text)X +3871(to)X +3956(be)X +976 5082(edited,)N +1219(the)X +1344(character)X +1667(string)X +7 f +1876(<newline>.<char-pair>)X +1 f +(,)S +2932(\(where)X +7 f +3184(<char-pair>)X +1 f +3740(is)X +3821(one)X +3965(of)X +976 5172(the)N +1100(character)X +1422(pairs)X +1604(in)X +1692(the)X +1816(option's)X +2104(value\),)X +2351(de\256nes)X +2604(a)X +2666(section)X +2918(boundary)X +3246(in)X +3333(the)X +3456(same)X +3646(manner)X +3912(that)X +3 f +976 5262(paragraph)N +1 f +1360(option)X +1584(boundaries)X +1956(are)X +2075(de\256ned.)X +3 f +776 5442(shell,)N +971(sh)X +1066([environment)X +1549(variable)X +1849(SHELL,)X +2154(or)X +2250(/bin/sh])X +1 f +976 5532(Select)N +1195(the)X +1316(shell)X +1490(used)X +1660(by)X +1763(the)X +1884(editor.)X +2134(The)X +2282(speci\256ed)X +2590(path)X +2751(is)X +2827(the)X +2948(pathname)X +3283(of)X +3373(the)X +3495(shell)X +3670(invoked)X +3952(by)X +976 5622(the)N +3 f +1103(vi)X +1194(!)X +1 f +1270(shell)X +1450(escape)X +1694(command)X +2038(and)X +2182(by)X +2290(the)X +3 f +2416(ex)X +2520(shell)X +1 f +2703(command.)X +3087(This)X +3257(program)X +3557(is)X +3638(also)X +3795(used)X +3970(to)X +976 5712(resolve)N +1228(any)X +1364(shell)X +1535 0.2679(meta-characters)AX +2065(in)X +3 f +2147(ex)X +1 f +2243(commands.)X + +51 p +%%Page: 51 50 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3658(USD:13-51)X +776 762(shiftwidth,)N +1162(sw)X +1271([8])X +1 f +976 852(Set)N +1098(the)X +1216(autoindent)X +1575(and)X +1712(shift)X +1875(command)X +2212(indentation)X +2593(width.)X +2836(This)X +2999(width)X +3202(is)X +3276(used)X +3444(by)X +3545(the)X +3 f +3664(autoindent)X +1 f +976 942(option)N +1200(and)X +1336(by)X +1436(the)X +3 f +1554(<)X +1 f +1600(,)X +3 f +1640(>)X +1 f +1686(,)X +1726(and)X +3 f +1862(shift)X +1 f +2033(commands.)X +3 f +776 1122(showdirty)N +1138([off])X +976 1212(Vi)N +1 f +1076(only.)X +1278(Display)X +1547(an)X +1643(asterisk)X +1908(on)X +2008(the)X +2126(colon)X +2324(command)X +2660(line)X +2800(if)X +2869(the)X +2987(\256le)X +3109(has)X +3236(been)X +3408(modi\256ed.)X +3 f +776 1392(showmatch,)N +1203(sm)X +1321([off])X +976 1482(Vi)N +1 f +1078(only.)X +1282(This)X +1446(option)X +1673(causes)X +3 f +1906(vi)X +1 f +1968(,)X +2011(when)X +2208(a)X +2267(``)X +7 f +2321(})X +1 f +('')S +2446(or)X +2536(``)X +7 f +2590(\))X +1 f +('')S +2715(is)X +2791(entered,)X +3071(to)X +3156(brie\257y)X +3388(move)X +3589(the)X +3710(cursor)X +3934(the)X +976 1572(matching)N +1294(``)X +7 f +1348({)X +1 f +('')S +1470(or)X +1557(``)X +7 f +1611(\()X +1 f +(''.)S +1773(See)X +1909(the)X +3 f +2027(matchtime)X +1 f +2413(option)X +2637(for)X +2751(more)X +2936(information.)X +3 f +776 1752(showmode)N +1156([off])X +976 1842(Vi)N +1 f +1083(only.)X +1292(This)X +1461(option)X +1693(causes)X +3 f +1931(vi)X +1 f +2021(to)X +2111(display)X +2370(a)X +2434(string)X +2644(identifying)X +3023(the)X +3149(current)X +3405(editor)X +3620(mode)X +3826(on)X +3934(the)X +976 1932(colon)N +1174(command)X +1510(line.)X +3 f +776 2112(sidescroll)N +1116([16])X +976 2202(Vi)N +1 f +1078(only.)X +1282(Sets)X +1437(the)X +1557(number)X +1825(of)X +1915(columns)X +2209(that)X +2352(are)X +2474(shifted)X +2715(to)X +2800(the)X +2921(left)X +3051(or)X +3141(right,)X +3335(when)X +3 f +3532(vi)X +1 f +3617(is)X +3693(doing)X +3898(left-)X +976 2292(right)N +1151(scrolling)X +1455(and)X +1595(the)X +1717(left)X +1848(or)X +1939(right)X +2114(margin)X +2365(is)X +2442(crossed.)X +2747(See)X +2887(the)X +3 f +3009(leftright)X +1 f +3314(option)X +3542(for)X +3660(more)X +3849(infor-)X +976 2382(mation.)N +3 f +776 2562(slowopen,)N +1131(slow)X +1302([off])X +1 f +976 2652(This)N +1141(option)X +1368(affects)X +1606(the)X +1727(display)X +1981(algorithm)X +2315(used)X +2485(by)X +3 f +2588(vi)X +1 f +2650(,)X +2693(holding)X +2960(off)X +3077(display)X +3331(updating)X +3635(during)X +3868(input)X +976 2742(of)N +1063(new)X +1217(text)X +1357(to)X +1439(improve)X +1726(throughput)X +2097(when)X +2291(the)X +2409(terminal)X +2696(in)X +2778(use)X +2905(is)X +2978(slow)X +3149(and)X +3285(unintelligent.)X +2 f +976 2922(This)N +1133(option)X +1357(is)X +1430(not)X +1552(yet)X +1666(implemented.)X +3 f +776 3102(sourceany)N +1143([off])X +1 f +976 3192(If)N +1054(this)X +1193(option)X +1421(is)X +1498(turned)X +1727(on,)X +3 f +1851(vi)X +1 f +1937(historically)X +2321(read)X +2485(startup)X +2728(\256les)X +2886(that)X +3031(were)X +3213(owned)X +3452(by)X +3557(someone)X +3867(other)X +976 3282(than)N +1142(the)X +1268(editor)X +1483(user.)X +1685(See)X +1829(the)X +1955(section)X +2210(entitled)X +2478(``)X +3 f +2532(Startup)X +2822(Information)X +1 f +3240('')X +3321(for)X +3442(more)X +3634(information.)X +976 3372(This)N +1144(option)X +1374(is)X +1453(a)X +1516(security)X +1797(problem)X +2091(of)X +2185(immense)X +2501(proportions,)X +2917(and)X +3060(should)X +3300(not)X +3429(be)X +3532(used)X +3706(under)X +3916(any)X +976 3462(circumstances.)N +2 f +976 3642(This)N +1133(option)X +1357(will)X +1496(never)X +1695(be)X +1791(implemented.)X +3 f +776 3822(tabstop,)N +1069(ts)X +1147([8])X +1 f +976 3912(This)N +1138(option)X +1362(sets)X +1502(tab)X +1620(widths)X +1853(for)X +1967(the)X +2085(editor)X +2292(display.)X +3 f +776 4092(taglength,)N +1136(tl)X +1205([0])X +1 f +976 4182(This)N +1148(option)X +1383(sets)X +1534(the)X +1663(maximum)X +2018(number)X +2294(of)X +2392(characters)X +2750(that)X +2901(are)X +3031(considered)X +3410(signi\256cant)X +3774(in)X +3867(a)X +3934(tag)X +976 4272(name.)N +1210(Setting)X +1456(the)X +1574(value)X +1768(to)X +1850(0)X +1910(makes)X +2135(all)X +2235(of)X +2322(the)X +2440(characters)X +2787(in)X +2869(the)X +2987(tag)X +3105(name)X +3299(signi\256cant.)X +3 f +776 4452(tags,)N +954(tag)X +1081([tags)X +1266(/var/db/libc.tags)X +1838(/sys/kern/tags])X +1 f +976 4542(Sets)N +1129(the)X +1247(list)X +1364(of)X +1451(tags)X +1600(\256les,)X +1773(in)X +1855(search)X +2081(order,)X +2291(which)X +2507(are)X +2626(used)X +2793(when)X +2987(the)X +3105(editor)X +3312(searches)X +3605(for)X +3719(a)X +3775(tag.)X +3 f +776 4722(term,)N +982(ttytype,)X +1263(tty)X +1377([environment)X +1860(variable)X +2160(TERM])X +1 f +976 4812(Set)N +1101(the)X +1223(terminal)X +1514(type.)X +1716(Setting)X +1966(this)X +2105(option)X +2333(causes)X +3 f +2567(ex)X +1 f +2643(/)X +3 f +2665(vi)X +1 f +2751(to)X +2837(set)X +2950(\(or)X +3068(reset\))X +3271(the)X +3393(environmental)X +3880(vari-)X +976 4902(able)N +7 f +1130(TERM)X +1 f +(.)S +3 f +776 5082(terse)N +962([off])X +1 f +976 5172(This)N +1142(option)X +1370(has)X +1501(historically)X +1885(made)X +2083(editor)X +2294(messages)X +2621(less)X +2765(verbose.)X +3079(It)X +3152(has)X +3283(no)X +3387(effect)X +3596(in)X +3683(this)X +3823(imple-)X +976 5262(mentation.)N +1356(See)X +1492(the)X +3 f +1610(verbose)X +1 f +1893(option)X +2117(for)X +2231(more)X +2416(information.)X +3 f +776 5442(tildeop)N +1 f +976 5532(Modify)N +1236(the)X +3 f +1354(\304)X +1 f +1401(command)X +1737(to)X +1819(take)X +1973(an)X +2069(associated)X +2419(motion.)X +3 f +776 5712(timeout,)N +1079(to)X +1166([on])X +1 f +976 5802(If)N +1057(this)X +1199(option)X +1431(is)X +1512(set,)X +3 f +1649(ex)X +1 f +1725(/)X +3 f +1747(vi)X +1 f +1837(waits)X +2034(for)X +2156(a)X +2220(speci\256c)X +2493(period)X +2726(for)X +2848(a)X +2912(subsequent)X +3296(key)X +3440(to)X +3530(complete)X +3852(a)X +3916(key)X + +52 p +%%Page: 52 51 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-52)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +1 f +976 762(mapping)N +1282(\(see)X +1438(the)X +3 f +1561(keytime)X +1 f +1858(option\).)X +2154(If)X +2233(the)X +2356(option)X +2585(is)X +2663(not)X +2790(set,)X +2924(the)X +3047(editor)X +3259(waits)X +3453(until)X +3624(enough)X +3885(keys)X +976 852(are)N +1095(entered)X +1352(to)X +1434(resolve)X +1686(the)X +1804(ambiguity,)X +2168(regardless)X +2514(of)X +2601(how)X +2759(long)X +2921(it)X +2985(takes.)X +3 f +776 1032(ttywerase)N +1127([off])X +976 1122(Vi)N +1 f +1082(only.)X +1290(This)X +1458(option)X +1688(changes)X +1973(how)X +3 f +2137(vi)X +1 f +2225(does)X +2398(word)X +2589(erase)X +2781(during)X +3016(text)X +3162(input.)X +3392(If)X +3472(this)X +3613(option)X +3843(is)X +3923(set,)X +976 1212(text)N +1123(is)X +1203(broken)X +1452(up)X +1558(into)X +1708(two)X +1854(classes,)X +2123(blank)X +2327(characters)X +2680(and)X +2822(nonblank)X +3146(characters.)X +3539(Changing)X +3876(from)X +976 1302(one)N +1112(class)X +1288(to)X +1370(another)X +1631(marks)X +1847(the)X +1965(end)X +2101(of)X +2188(a)X +2244(word.)X +3 f +776 1482(verbose)N +1059([off])X +976 1572(Vi)N +1 f +1078(only.)X +3 f +1282(Vi)X +1 f +1384(historically)X +1766(bells)X +1939(the)X +2059(terminal)X +2348(for)X +2464(many)X +2665(obvious)X +2941(mistakes,)X +3264(e.g.)X +3403(trying)X +3617(to)X +3702(move)X +3903(past)X +976 1662(the)N +1108(left-hand)X +1432(margin,)X +1713(or)X +1814(past)X +1977(the)X +2109(end)X +2259(of)X +2360(the)X +2492(\256le.)X +2668(If)X +2756(this)X +2905(option)X +3143(is)X +3230(set,)X +3373(an)X +3483(error)X +3674(message)X +3979(is)X +976 1752(displayed)N +1303(for)X +1417(all)X +1517(errors.)X +3 f +776 1932(w300)N +974([no)X +1105(default])X +976 2022(Vi)N +1 f +1080(only.)X +1286(Set)X +1412(the)X +1534(window)X +1816(size)X +1965(if)X +2038(the)X +2160(baud)X +2340(rate)X +2485(is)X +2562(less)X +2706(than)X +2868(1200)X +3052(baud.)X +3273(See)X +3414(the)X +3 f +3537(window)X +1 f +3828(option)X +976 2112(for)N +1090(more)X +1275(information.)X +3 f +776 2292(w1200)N +1014([no)X +1145(default])X +976 2382(Vi)N +1 f +1081(only.)X +1288(Set)X +1415(the)X +1538(window)X +1821(size)X +1971(if)X +2045(the)X +2168(baud)X +2349(rate)X +2495(is)X +2574(equal)X +2774(to)X +2862(1200)X +3048(baud.)X +3270(See)X +3412(the)X +3 f +3536(window)X +1 f +3828(option)X +976 2472(for)N +1090(more)X +1275(information.)X +3 f +776 2652(w9600)N +1014([no)X +1145(default])X +976 2742(Vi)N +1 f +1087(only.)X +1300(Set)X +1433(the)X +1562(window)X +1851(size)X +2007(if)X +2087(the)X +2216(baud)X +2404(rate)X +2557(is)X +2642(greater)X +2898(than)X +3068(1200)X +3260(baud.)X +3488(See)X +3636(the)X +3 f +3766(window)X +1 f +976 2832(option)N +1200(for)X +1314(more)X +1499(information.)X +3 f +776 3012(warn)N +974([on])X +976 3102(Ex)N +1 f +1094(only.)X +1302(This)X +1470(option)X +1700(causes)X +1936(a)X +1998(warning)X +2287(message)X +2585(to)X +2673(the)X +2797(terminal)X +3090(if)X +3165(the)X +3289(\256le)X +3417(has)X +3550(been)X +3728(modi\256ed,)X +976 3192(since)N +1161(it)X +1225(was)X +1370(last)X +1501(written,)X +1768(before)X +1994(a)X +3 f +2050(!)X +1 f +2117(command.)X +3 f +776 3372(window,)N +1082(w,)X +1180(wi)X +1280([environment)X +1763(variable)X +2063(LINES])X +1 f +976 3462(This)N +1148(option)X +1382(determines)X +1764(the)X +1892(default)X +2145(number)X +2420(of)X +2517(lines)X +2698(in)X +2791(a)X +2858(screenful,)X +3204(as)X +3302(written)X +3560(by)X +3671(the)X +3 f +3800(z)X +1 f +3867(com-)X +976 3552(mand.)N +1221(It)X +1297(also)X +1453(determines)X +1832(the)X +1957(number)X +2229(of)X +2323(lines)X +2501(scrolled)X +2782(by)X +2889(the)X +3 f +3014(vi)X +1 f +3103(commands)X +3 f +3477(<control-F>)X +1 f +3916(and)X +3 f +976 3642(<control-B>)N +1 f +1393(.)X +1457(The)X +1606(value)X +1804(of)X +1895(window)X +2177(can)X +2313(be)X +2413(unrelated)X +2736(to)X +2822(the)X +2944(real)X +3089(screen)X +3319(size,)X +3489(although)X +3794(it)X +3863(starts)X +976 3732(out)N +1110(as)X +1209(the)X +1338(number)X +1614(of)X +1712(lines)X +1894(on)X +2005(the)X +2134(screen)X +2371(\(see)X +2532(the)X +2661(section)X +2919(entitled)X +3190(``)X +3 f +3244(Sizing)X +3483(the)X +3621(Screen)X +1 f +3853('')X +3938(for)X +976 3822(more)N +1165(information\).)X +1634(Setting)X +1884(the)X +2006(value)X +2204(of)X +2295(the)X +3 f +2417(window)X +1 f +2707(option)X +2935(is)X +3012(the)X +3135(same)X +3325(as)X +3417(using)X +3615(the)X +3 f +9 f +3738(-)X +3740(-)X +3 f +3784(w)X +1 f +3867(com-)X +976 3912(mand)N +1174(line)X +1314(option.)X +976 4092(If)N +1055(the)X +1178(value)X +1377(of)X +1469(the)X +3 f +1592(window)X +1 f +1883(option)X +2112(\(as)X +2231(set)X +2345(by)X +2450(the)X +3 f +2574(window)X +1 f +2840(,)X +3 f +2886(w300)X +1 f +3064(,)X +3 f +3110(w1200)X +1 f +3354(or)X +3 f +3447(w9600)X +1 f +3691(options\))X +3979(is)X +976 4182(smaller)N +1233(than)X +1391(the)X +1509(actual)X +1721(size)X +1866(of)X +1953(the)X +2071(screen,)X +2317(large)X +2498(screen)X +2724(movements)X +3113(will)X +3257(result)X +3455(in)X +3537(displaying)X +3890(only)X +976 4272(that)N +1116(smaller)X +1373(number)X +1639(of)X +1727(lines)X +1899(on)X +2000(the)X +2119(screen.)X +2386(\(Further)X +2670(movements)X +3060(in)X +3143(that)X +3284(same)X +3470(area)X +3626(will)X +3771(result)X +3970(in)X +976 4362(the)N +1097(screen)X +1325(being)X +1525(\256lled.\))X +1778(This)X +1942(can)X +2076(provide)X +2343(a)X +2401(performance)X +2830(improvement)X +3279(when)X +3475(viewing)X +3755(different)X +976 4452(places)N +1197(in)X +1279(one)X +1415(or)X +1502(more)X +1687(\256les)X +1840(over)X +2003(a)X +2059(slow)X +2230(link.)X +3 f +776 4632(wrapmargin,)N +1243(wm)X +1388([0])X +976 4722(Vi)N +1 f +1077(only.)X +1280(If)X +1356(the)X +1476(value)X +1672(of)X +1761(the)X +3 f +1881(wrapmargin)X +1 f +2330(option)X +2556(is)X +2631(non-zero,)X +3 f +2959(vi)X +1 f +3043(will)X +3189(split)X +3348(lines)X +3521(so)X +3614(that)X +3756(they)X +3916(end)X +976 4812(at)N +1057(least)X +1227(that)X +1370(number)X +1638(of)X +1728(characters)X +2078(before)X +2307(the)X +2428(right-hand)X +2785(margin)X +3035(of)X +3125(the)X +3245(screen.)X +3513(\(Note,)X +3738(the)X +3858(value)X +976 4902(of)N +3 f +1063(wrapmargin)X +1 f +1510(is)X +2 f +1583(not)X +1 f +1705(a)X +1761(text)X +1901(length.)X +2161(In)X +2248(a)X +2304(screen)X +2530(that)X +2670(is)X +2743(80)X +2843(columns)X +3134(wide,)X +3330(the)X +3449(command)X +3786(``)X +7 f +3840(:set)X +976 4992(wrapmargin=8)N +1 f +('')S +1626(attempts)X +1917(to)X +1999(keep)X +2171(the)X +2289(lines)X +2460(less)X +2600(than)X +2758(or)X +2845(equal)X +3039(to)X +3121(72)X +3221(columns)X +3512(wide.\))X +976 5172(Lines)N +1181(are)X +1307(split)X +1471(at)X +1556(the)X +1681(previous)X +1984(whitespace)X +2368(character)X +2691(closest)X +2936(to)X +3025(the)X +3150(number.)X +3462(Any)X +3627(trailing)X +3885(whi-)X +976 5262(tespace)N +1239(characters)X +1592(before)X +1824(that)X +1970(character)X +2292(are)X +2417(deleted.)X +2715(If)X +2795(the)X +2919(line)X +3065(is)X +3143(split)X +3305(because)X +3585(of)X +3677(an)X +3778(inserted)X +7 f +976 5352(<space>)N +1 f +1346(or)X +7 f +1447(<tab>)X +1 f +1721(character,)X +2072(and)X +2223(you)X +2378(then)X +2551(enter)X +2747(another)X +7 f +3023(<space>)X +1 f +3394(character,)X +3745(it)X +3824(is)X +3912(dis-)X +976 5442(carded.)N +976 5622(If)N +1052(wrapmargin)X +1462(is)X +1537(set)X +1648(to)X +1732(0,)X +1815(or)X +1905(if)X +1977(there)X +2161(is)X +2237(no)X +2340(blank)X +2541(character)X +2860(upon)X +3043(which)X +3262(to)X +3347(split)X +3507(the)X +3628(line,)X +3791(the)X +3912(line)X +976 5712(is)N +1049(not)X +1171(broken.)X + +53 p +%%Page: 53 52 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3658(USD:13-53)X +776 762(wrapscan,)N +1145(ws)X +1254([on])X +1 f +976 852(This)N +1138(option)X +1362(causes)X +1592(searches)X +1885(to)X +1967(wrap)X +2148(around)X +2391(the)X +2509(end)X +2645(or)X +2732(the)X +2850(beginning)X +3191(of)X +3279(the)X +3398(\256le,)X +3541(and)X +3678(back)X +3851(to)X +3934(the)X +976 942(starting)N +1236(point.)X +1460(Otherwise,)X +1830(the)X +1948(end)X +2084(or)X +2171(beginning)X +2511(of)X +2598(the)X +2716(\256le)X +2838(terminates)X +3192(the)X +3310(search.)X +3 f +776 1122(writeany,)N +1119(wa)X +1237([off])X +1 f +976 1212(If)N +1056(this)X +1197(option)X +1427(is)X +1506(set,)X +1641(\256le-overwriting)X +2170(checks)X +2416(that)X +2563(would)X +2790(usually)X +3048(be)X +3151(made)X +3352(before)X +3585(the)X +3 f +3710(write)X +1 f +3916(and)X +3 f +976 1302(xit)N +1 f +1094(commands,)X +1490(or)X +1586(before)X +1821(an)X +1926(automatic)X +2271(write)X +2465(\(see)X +2624(the)X +3 f +2751(autowrite)X +1 f +3110(option\),)X +3390(are)X +3518(not)X +3648(made.)X +3890(This)X +976 1392(allows)N +1205(a)X +1261(write)X +1446(to)X +1528(any)X +1664(\256le,)X +1806(provided)X +2111(the)X +2229(\256le)X +2351(permissions)X +2753(allow)X +2951(it.)X +3 f +776 1578(16.)N +916(Additional)X +1299(Features)X +1618(in)X +1704(Nex/Nvi)X +1 f +976 1701(There)N +1190(are)X +1315(a)X +1377(few)X +1524(features)X +1805(in)X +3 f +1894(nex)X +1 f +(/)S +3 f +2036(nvi)X +1 f +2169(that)X +2316(are)X +2442(not)X +2571(found)X +2785(in)X +2874(historic)X +3141(versions)X +3435(of)X +3 f +3529(ex)X +1 f +3605(/)X +3 f +3627(vi)X +1 f +3689(.)X +3756(Some)X +3965(of)X +776 1791(the)N +894(more)X +1079(interesting)X +1437(of)X +1524(those)X +1713(features)X +1988(are)X +2107(as)X +2194(follows:)X +3 f +776 1971(8-bit)N +956(clean)X +1154(data,)X +1345(large)X +1539(lines,)X +1734(\256les)X +976 2061(Nex)N +1 f +1110(/)X +3 f +1132(nvi)X +1 f +1260(will)X +1407(edit)X +1550(any)X +1689(format)X +1926(\256le.)X +2091(Line)X +2261(lengths)X +2515(are)X +2637(limited)X +2886(by)X +2989(available)X +3302(memory,)X +3612(and)X +3751(\256le)X +3876(sizes)X +976 2151(are)N +1099(limited)X +1349(by)X +1453(available)X +1767(disk)X +1924(space.)X +2167(The)X +3 f +2316(vi)X +1 f +2402(text)X +2546(input)X +2734(mode)X +2935(command)X +3 f +3274(<control-X>)X +1 f +3719(can)X +3854(insert)X +976 2241(any)N +1112(possible)X +1394(character)X +1710(value)X +1904(into)X +2048(the)X +2166(text.)X +3 f +776 2421(Split)N +955(screens)X +1 f +976 2511(The)N +3 f +1127(split)X +1 f +1299(command)X +1641(divides)X +1898(the)X +2022(screen)X +2254(into)X +2404(multiple)X +2696(editing)X +2944(regions.)X +3246(The)X +3 f +3397(<control-W>)X +1 f +3867(com-)X +976 2601(mand)N +1183(rotates)X +1426(between)X +1723(the)X +1850(foreground)X +2236(screens.)X +2541(The)X +3 f +2694(resize)X +1 f +2919(command)X +3263(can)X +3403(be)X +3507(used)X +3682(to)X +3772(grow)X +3965(or)X +976 2691(shrink)N +1196(a)X +1252(particular)X +1580(screen.)X +3 f +776 2871(Background)N +1217(and)X +1365(foreground)X +1772(screens)X +1 f +976 2961(The)N +3 f +1134(bg)X +1 f +1251(command)X +1600(backgrounds)X +2044(the)X +2176(current)X +2438(screen,)X +2698(and)X +2848(the)X +3 f +2980(fg)X +1 f +3081(command)X +3431(foregrounds)X +3853(back-)X +976 3051(grounded)N +1299(screens.)X +1596(The)X +3 f +1741(display)X +1 f +2004(command)X +2340(can)X +2472(be)X +2568(used)X +2735(to)X +2817(list)X +2934(the)X +3052(background)X +3451(screens.)X +3 f +776 3231(Tag)N +929(stacks)X +1 f +976 3321(Tags)N +1159(are)X +1285(now)X +1450(maintained)X +1834(in)X +1924(a)X +1988(stack.)X +2221(The)X +3 f +2374(<control-T>)X +1 f +2819(command)X +3163(returns)X +3414(to)X +3504(the)X +3630(previous)X +3934(tag)X +976 3411(location.)N +1299(The)X +3 f +1449(tagpop)X +1 f +1709(command)X +2050(returns)X +2298(to)X +2385(the)X +2508(most)X +2688(recent)X +2910(tag)X +3033(location)X +3316(by)X +3421(default,)X +3689(or,)X +3801(option-)X +976 3501(ally)N +1119(to)X +1204(a)X +1263(speci\256c)X +1531(tag)X +1652(number)X +1920(in)X +2005(the)X +2126(tag)X +2248(stack,)X +2457(or)X +2548(the)X +2670(most)X +2849(recent)X +3070(tag)X +3192(from)X +3372(a)X +3432(speci\256ed)X +3741(\256le.)X +3907(The)X +3 f +976 3591(display)N +1 f +1241(command)X +1579(can)X +1713(be)X +1810(used)X +1978(to)X +2061(list)X +2179(the)X +2298(tags)X +2448(stack.)X +2674(The)X +3 f +2820(tagtop)X +1 f +3059(command)X +3396(returns)X +3640(to)X +3723(the)X +3842(top)X +3965(of)X +976 3681(the)N +1094(tag)X +1212(stack.)X +3 f +776 3861(New)N +948(displays)X +1 f +976 3951(The)N +3 f +1128(display)X +1 f +1398(command)X +1741(can)X +1880(be)X +1984(used)X +2159(to)X +2249(display)X +2508(the)X +2634(current)X +2890(buffers,)X +3166(the)X +3292(backgrounded)X +3775(screens,)X +976 4041(and)N +1112(the)X +1230(tags)X +1379(stack.)X +3 f +776 4221(In\256nite)N +1044(undo)X +1 f +976 4311(Changes)N +1282(made)X +1486(during)X +1725(an)X +1832(edit)X +1983(session)X +2245(may)X +2414(be)X +2521(rolled)X +2739(backward)X +3083(and)X +3230(forward.)X +3556(A)X +3 f +3645(.)X +1 f +3716(command)X +976 4401(immediately)N +1403(after)X +1578(a)X +3 f +1640(u)X +1 f +1710(command)X +2052(continues)X +2385(either)X +2594(forward)X +2875(or)X +2968(backward)X +3307(depending)X +3667(on)X +3773(whether)X +976 4491(the)N +3 f +1094(u)X +1 f +1158(command)X +1494(was)X +1639(an)X +1735(undo)X +1915(or)X +2002(a)X +2058(redo.)X +3 f +776 4671(Usage)N +1001(information)X +1 f +976 4761(The)N +3 f +1126(exusage)X +1 f +1418(and)X +3 f +1559(viusage)X +1 f +1837(commands)X +2209(provide)X +2479(usage)X +2688(information)X +3092(for)X +3212(all)X +3318(of)X +3411(the)X +3 f +3535(ex)X +1 f +3637(and)X +3 f +3779(vi)X +1 f +3867(com-)X +976 4851(mands)N +1205(by)X +1305(default,)X +1568(or,)X +1675(optionally,)X +2039(for)X +2153(a)X +2209(speci\256c)X +2474(command)X +2810(or)X +2897(key.)X +3 f +776 5031(Extended)N +1120(Regular)X +1416(Expressions)X +1 f +976 5121(The)N +3 f +1133(extended)X +1 f +1472(option)X +1708(causes)X +1950(Regular)X +2237(Expressions)X +2657(to)X +2752(be)X +2861(interpreted)X +3242(as)X +3342(as)X +3442(Extended)X +3778(Regular)X +976 5211(Expressions,)N +1403(\(i.e.)X +2 f +1548(egrep)X +1 f +1731(\(1\))X +1845(style)X +2016(Regular)X +2290(Expressions\).)X +3 f +776 5391(Word)N +996(search)X +1 f +976 5481(The)N +3 f +1121(<control-A>)X +1 f +1563(command)X +1899(searches)X +2192(for)X +2306(the)X +2424(word)X +2609 0.4028(referenced)AX +2970(by)X +3070(the)X +3188(cursor.)X +3 f +776 5661(Number)N +1081(increment)X +1 f +976 5751(The)N +3 f +1121(#)X +1 f +1181(command)X +1517(increments)X +1889(or)X +1976(decrements)X +2362(the)X +2480(number)X +2745 0.4028(referenced)AX +3106(by)X +3206(the)X +3324(cursor.)X + +54 p +%%Page: 54 53 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-54)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +776 762(Previous)N +1094(\256le)X +1 f +976 852(The)N +3 f +1121(previous)X +1 f +1434(command)X +1770(edits)X +1941(the)X +2059(previous)X +2355(\256le)X +2477(from)X +2653(the)X +2771(argument)X +3094(list.)X +3 f +776 1032(Left-right)N +1135(scrolling)X +1 f +976 1122(The)N +3 f +1130(leftright)X +1 f +1440(option)X +1673(causes)X +3 f +1912(nvi)X +1 f +2047(to)X +2138(do)X +2248(left-right)X +2563(screen)X +2799(scrolling,)X +3129(instead)X +3386(of)X +3483(the)X +3611(traditional)X +3 f +3970(vi)X +1 f +976 1212(line)N +1116(wrapping.)X + +55 p +%%Page: 55 54 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(Nvi/Nex)N +872 0.3906(Reference)AX +3658(USD:13-55)X +776 762(17.)N +916(Index)X +1 f +776 885(.)N +1549(18)X +776 975(!)N +1429(15,)X +1549(34)X +776 1065("")N +1549(34)X +776 1155(#)N +1429(16,)X +1549(35)X +776 1245($)N +1549(16)X +776 1335(%)N +1549(16)X +776 1425(&)N +1429(17,)X +1549(42)X +776 1515(\()N +1549(17)X +776 1605(\))N +1549(17)X +776 1695(*)N +1549(35)X +776 1785(+)N +1549(13)X +776 1875(,)N +1549(18)X +776 1965(/RE/)N +1549(18)X +776 2055(0)N +1549(19)X +776 2145(0<control-D>)N +1549(31)X +776 2235(:)N +1549(19)X +776 2325(;)N +1549(19)X +776 2415(<)N +1429(20,)X +1549(35)X +776 2505(<control-A>)N +1549(11)X +776 2595(<control-B>)N +1549(11)X +776 2685(<control-D>)N +1429(12,)X +1549(31)X +776 2775(<control-E>)N +1549(12)X +776 2865(<control-F>)N +1549(12)X +776 2955(<control-G>)N +1549(12)X +776 3045(<control-H>)N +1429(12,)X +1549(31)X +776 3135(<control-J>)N +1549(13)X +776 3225(<control-L>)N +1549(13)X +776 3315(<control-M>)N +1549(13)X +776 3405(<control-N>)N +1549(13)X +776 3495(<control-P>)N +1549(13)X +776 3585(<control-R>)N +1549(13)X +776 3675(<control-T>)N +1429(14,)X +1549(31)X +776 3765(<control-U>)N +1549(14)X +776 3855(<control-W>)N +1429(14,)X +1549(31)X +776 3945(<control-X>)N +1549(31)X +776 4035(<control-Y>)N +1549(14)X +776 4125(<control-Z>)N +1429(14,)X +1549(43)X +776 4215(<control-]>)N +1549(15)X +776 4305(<control-\303>)N +1549(15)X +776 4395(<end-of-\256le>)N +1549(34)X +776 4485(<eof>)N +1549(33)X +776 4575(<erase>)N +1549(31)X +776 4665(<escape>)N +1429(14,)X +1549(31)X +776 4755(<interrupt>)N +1349(7,)X +1429(30,)X +1549(31)X +776 4845(<line)N +961(erase>)X +1549(31)X +776 4935(<literal)N +1028(next>)X +1469(7,)X +1549(31)X +776 5025(<nul>)N +1549(30)X +776 5115(<space>)N +1549(15)X +776 5205(<word)N +1006(erase>)X +1549(31)X +776 5295(=)N +1549(35)X +776 5385(>)N +1429(20,)X +1549(35)X +776 5475(?RE?)N +1549(18)X +776 5565(@)N +1429(20,)X +1549(35)X +776 5655(A)N +1549(20)X +776 5745(B)N +1549(20)X +2077 885(C)N +2850(21)X +2077 975(D)N +2850(21)X +2077 1065(E)N +2850(21)X +2077 1155(F)N +2850(21)X +2077 1245(G)N +2850(21)X +2077 1335(H)N +2850(21)X +2077 1425(I)N +2850(22)X +2077 1515(J)N +2850(22)X +2077 1605(L)N +2850(22)X +2077 1695(M)N +2850(22)X +2077 1785(N)N +2850(18)X +2077 1875(O)N +2850(22)X +2077 1965(P)N +2850(23)X +2077 2055(Q)N +2850(23)X +2077 2145(R)N +2850(23)X +2077 2235(S)N +2850(23)X +2077 2325(T)N +2850(23)X +2077 2415(U)N +2850(23)X +2077 2505(W)N +2850(24)X +2077 2595(X)N +2850(24)X +2077 2685(Y)N +2850(24)X +2077 2775(ZZ)N +2850(24)X +2077 2865([[)N +2850(24)X +9 f +2077 2955(-)N +1 f +2850(18)X +2077 3045(]])N +2850(25)X +2077 3135(\303)N +2850(25)X +2077 3225(\303<control-D>)N +2850(31)X +2077 3315(_)N +2850(25)X +2077 3405 0.2841(`<character>)AN +2850(17)X +2077 3495(a)N +2850(25)X +2077 3585(abbrev)N +2850(35)X +2077 3675(alternate)N +2374(pathname)X +2890(8)X +2077 3765(altwerase)N +2850(46)X +2077 3855(append)N +2850(36)X +2077 3945(args)N +2850(36)X +2077 4035(autoindent)N +2850(46)X +2077 4125(autoprint)N +2850(46)X +2077 4215(autowrite)N +2850(47)X +2077 4305(b)N +2850(25)X +2077 4395(beautify)N +2850(47)X +2077 4485(bg)N +2850(36)X +2077 4575(bigword)N +2850(10)X +2077 4665(buffer)N +2890(8)X +2077 4755(c)N +2850(26)X +2077 4845(cd)N +2850(36)X +2077 4935(cdpath)N +2850(47)X +2077 5025(change)N +2850(36)X +2077 5115(chdir)N +2850(36)X +2077 5205(columns)N +2850(47)X +2077 5295(comment)N +2850(47)X +2077 5385(copy)N +2850(36)X +2077 5475(count)N +2730(10,)X +2850(33)X +2077 5565(current)N +2325(pathname)X +2890(8)X +2077 5655(d)N +2850(26)X +2077 5745(delete)N +2850(37)X +3378 885(directory)N +4151(47)X +3378 975(display)N +4151(37)X +3378 1065(e)N +4151(26)X +3378 1155(edcompatible)N +4151(47)X +3378 1245(edit)N +4151(37)X +3378 1335(errorbells)N +4151(47)X +3378 1425(exrc)N +4151(47)X +3378 1515(extended)N +4151(48)X +3378 1605(exusage)N +4151(37)X +3378 1695(f)N +4151(26)X +3378 1785(fg)N +4151(37)X +3378 1875(\256le)N +4031(33,)X +4151(37)X +3378 1965(\257ags)N +4151(33)X +3378 2055(\257ash)N +4151(48)X +3378 2145(global)N +4151(38)X +3378 2235(hardtabs)N +4151(48)X +3378 2325(help)N +4151(38)X +3378 2415(i)N +4151(26)X +3378 2505(ignorecase)N +4151(48)X +3378 2595(insert)N +4151(38)X +3378 2685(j)N +4151(13)X +3378 2775(join)N +4151(38)X +3378 2865(k)N +4031(13,)X +4151(39)X +3378 2955(keytime)N +4151(48)X +3378 3045(l)N +4151(15)X +3378 3135(leftright)N +4151(48)X +3378 3225(line)N +4151(33)X +3378 3315(lines)N +4151(48)X +3378 3405(lisp)N +4151(48)X +3378 3495(list)N +4031(39,)X +4151(48)X +3378 3585(m)N +4151(27)X +3378 3675(magic)N +4151(48)X +3378 3765(map)N +4151(39)X +3378 3855(mark)N +4151(39)X +3378 3945(matchtime)N +4151(48)X +3378 4035(mesg)N +4151(48)X +3378 4125(mkexrc)N +4151(39)X +3378 4215(modelines)N +4151(49)X +3378 4305(motion)N +4151(10)X +3378 4395(move)N +4151(39)X +3378 4485(n)N +4151(18)X +3378 4575(next)N +4151(40)X +3378 4665(number)N +4031(35,)X +4151(49)X +3378 4755(o)N +4151(27)X +3378 4845(octal)N +4151(49)X +3378 4935(open)N +4031(40,)X +4151(49)X +3378 5025(optimize)N +4151(49)X +3378 5115(p)N +4151(27)X +3378 5205(paragraph)N +4151(11)X +3378 5295(paragraphs)N +4151(49)X +3378 5385(preserve)N +4151(40)X +3378 5475(previous)N +4151(40)X +3378 5565(previous)N +3674(context)X +4191(9)X +3378 5655(print)N +4151(40)X +3378 5745(prompt)N +4151(49)X + +56 p +%%Page: 56 55 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-56)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +1 f +776 762(put)N +1549(40)X +776 852(quit)N +1549(41)X +776 942(r)N +1549(27)X +776 1032(range)N +1549(33)X +776 1122(read)N +1549(41)X +776 1212(readonly)N +1549(49)X +776 1302(recdir)N +1549(49)X +776 1392(recover)N +1549(41)X +776 1482(redraw)N +1549(50)X +776 1572(remap)N +1549(50)X +776 1662(report)N +1549(50)X +776 1752(resize)N +1549(41)X +776 1842(rewind)N +1549(41)X +776 1932(ruler)N +1549(50)X +776 2022(s)N +1549(27)X +776 2112(scroll)N +1549(50)X +776 2202(section)N +1549(11)X +776 2292(sections)N +1549(50)X +776 2382(sentence)N +1549(11)X +776 2472(set)N +1549(41)X +776 2562(shell)N +1429(42,)X +1549(50)X +776 2652(shiftwidth)N +1549(50)X +776 2742(showdirty)N +1549(51)X +776 2832(showmatch)N +1549(51)X +776 2922(showmode)N +1549(51)X +776 3012(sidescroll)N +1549(51)X +776 3102(slowopen)N +1549(51)X +776 3192(source)N +1549(42)X +776 3282(sourceany)N +1549(51)X +776 3372(split)N +1549(42)X +776 3462(stop)N +1549(43)X +776 3552(substitute)N +1549(42)X +776 3642(suspend)N +1549(43)X +776 3732(t)N +1429(27,)X +1549(36)X +776 3822(tabstop)N +1549(51)X +776 3912(tag)N +1549(43)X +776 4002(taglength)N +1549(51)X +776 4092(tagpop)N +1549(43)X +776 4182(tags)N +1549(51)X +776 4272(tagtop)N +1549(43)X +776 4362(term)N +1549(51)X +776 4452(terse)N +1549(51)X +776 4542(tildeop)N +1549(51)X +776 4632(timeout)N +1549(51)X +776 4722(ttywerase)N +1549(52)X +776 4812(u)N +1549(28)X +776 4902(unabbrev)N +1549(44)X +776 4992(undo)N +1549(44)X +776 5082(unmap)N +1549(44)X +776 5172(unnamed)N +1090(buffer)X +1589(8)X +776 5262(v)N +1549(38)X +776 5352(verbose)N +1549(52)X +776 5442(version)N +1549(44)X +776 5532(visual)N +1549(44)X +776 5622(viusage)N +1549(44)X +776 5712(w)N +1549(28)X +776 5802(w1200)N +1549(52)X +2077 762(w300)N +2850(52)X +2077 852(w9600)N +2850(52)X +2077 942(warn)N +2850(52)X +2077 1032(window)N +2850(52)X +2077 1122(wn)N +2850(44)X +2077 1212(word)N +2850(10)X +2077 1302(wq)N +2850(44)X +2077 1392(wrapmargin)N +2850(52)X +2077 1482(wrapscan)N +2850(52)X +2077 1572(write)N +2850(44)X +2077 1662(writeany)N +2850(53)X +2077 1752(x)N +2850(28)X +2077 1842(xit)N +2850(45)X +2077 1932(y)N +2850(28)X +2077 2022(yank)N +2850(45)X +2077 2112(z)N +2730(28,)X +2850(45)X +2077 2202({)N +2850(29)X +2077 2292(|)N +2850(29)X +2077 2382(})N +2850(29)X +2077 2472(\304)N +2610(29,)X +2730(30,)X +2850(42)X + +2 p +%%Page: 2 56 +10 s 10 xH 0 xS 1 f 1 i +3 f +576 474(USD:13-2)N +3391(Nvi/Nex)X +3687 0.3906(Reference)AX +12 s +2039 762(Table)N +2298(of)X +2402(Contents)X +1 f +10 s +776 961(Description)N +1184(................................................................................................................................)X +3992(3)X +776 1070(Startup)N +1027(Information)X +1444(...................................................................................................................)X +3992(3)X +776 1179(Recovery)N +1104(....................................................................................................................................)X +3992(3)X +776 1288(Sizing)N +1000(the)X +1118(Screen)X +1364(.......................................................................................................................)X +3992(5)X +776 1397(Character)N +1109(Display)X +1384(......................................................................................................................)X +3992(5)X +776 1506(Multiple)N +1071(Screens)X +1344(........................................................................................................................)X +3992(6)X +776 1615(Regular)N +1050(Expressions)X +1457(and)X +1593(Replacement)X +2032(Strings)X +2284(.........................................................................)X +3992(6)X +776 1724(General)N +1051(Editor)X +1271(Description)X +1684(.......................................................................................................)X +3992(7)X +776 1833(Vi)N +876(Description)X +1284(...........................................................................................................................)X +3992(8)X +776 1942(Vi)N +876(Commands)X +1264(............................................................................................................................)X +3952(11)X +776 2051(Vi)N +876(Text)X +1043(Input)X +1232(Commands)X +1624(..........................................................................................................)X +3952(30)X +776 2160(Ex)N +885(Addressing)X +1284(...........................................................................................................................)X +3952(31)X +776 2269(Ex)N +885(Description)X +1284(...........................................................................................................................)X +3952(33)X +776 2378(Ex)N +885(Commands)X +1284(...........................................................................................................................)X +3952(34)X +776 2487(Set)N +898(Options)X +1184(................................................................................................................................)X +3952(46)X +776 2596(Additional)N +1138(Features)X +1430(in)X +1512(Nex/Nvi)X +1824(................................................................................................)X +3952(53)X +776 2705(Index)N +984(..........................................................................................................................................)X +3952(55)X + +56 p +%%Trailer +xt + +xs diff --git a/usr.bin/vi/USD.doc/vi.ref/set.opt.roff b/usr.bin/vi/USD.doc/vi.ref/set.opt.roff new file mode 100644 index 0000000..d59599d --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/set.opt.roff @@ -0,0 +1,949 @@ +.\" Copyright (c) 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)set.opt.roff 8.26 (Berkeley) 8/11/94 +.\" +.SH 1 "Set Options" +.pp +There are a large number of options that may be set (or unset) to +change the editor's behavior. +This section describes the options, their abbreviations and their +default values. +.pp +In each entry below, the first part of the tag line is the full name +of the option, followed by any equivalent abbreviations. +(Regardless of the abbreviations, it is only necessary to use the +minimum number of characters necessary to distinguish an abbreviation +from all other commands for it to be accepted, in +.EV nex nvi . +Historically, only the full name and the official abbreviations +were accepted by +.EV ex vi . +Using full names in your startup files and environmental variables will +probably make them more portable.) +The part in square brackets is the default value of the option. +Most of the options are boolean, i.e. they are either on or off, +and do not have an associated value. +.pp +Options apply to both +.CO ex +and +.CO vi +modes, unless otherwise specified. +.pp +For information on modifying the options or to display the options and +their current values, see the +.QQ set +command in the section entitled +.QB "Ex Commands" . +.KY altwerase +.IP "altwerase [off]" +.CO Vi +only. +Change how +.CO vi +does word erase during text input. +When this option is set, text is broken up into three classes: +alphabetic, numeric and underscore characters, other nonblank +characters, and blank characters. +Changing from one class to another marks the end of a word. +In addition, the class of the first character erased is ignored +(which is exactly what you want when erasing pathname components). +.KY autoindent +.IP "autoindent, ai [off]" +If this option is set, whenever you create a new line (using the +.CO vi +.CO A , +.CO a , +.CO C , +.CO c , +.CO I , +.CO i , +.CO O , +.CO o , +.CO R , +.CO r , +.CO S , +and +.CO s +commands, or the +.CO ex +.CO append , +.CO change , +and +.CO insert +commands) the new line is automatically indented to align the cursor with +the first nonblank character of the line from which you created it. +Lines are indented using tab characters to the extent possible (based on +the value of the +.OP tabstop +option) and then using space characters as necessary. +For commands inserting text into the middle of a line, any blank characters +to the right of the cursor are discarded, and the first nonblank character +to the right of the cursor is aligned as described above. +.sp +The indent characters are themselves somewhat special. +If you do not enter more characters on the new line before moving to +another line, or entering +.LI <escape> , +the indent character will be deleted and the line will be empty. +For example, if you enter +.LI <carriage-return> +twice in succession, +the line created by the first +.LI <carriage-return> +will not have any characters in it, +regardless of the indentation of the previous or subsequent line. +.sp +Indent characters also require that you enter additional erase characters +to delete them. +For example, +if you have an indented line, containing only blanks, the first +.LI <word-erase> +character you enter will erase up to end of the indent characters, +and the second will erase back to the beginning of the line. +(Historically, only the +.CO <control-D> +key would erase the indent characters. +Both the +.CO <control-D> +key and the usual erase keys work in +.CO nvi .) +In addition, if the cursor is positioned at the end of the indent +characters, the keys +.QT 0<control-D> +will erase all of the indent characters for the current line, +resetting the indentation level to 0. +Similarly, the keys +.QT ^<control-D> +will erase all of the indent characters for the current line, +leaving the indentation level for future created lines unaffected. +.sp +Finally, if the +.OP autoindent +option is set, the +.CO S +and +.CO cc +commands change from the first nonblank of the line to the end of the +line, instead of from the beginning of the line to the end of the line. +.KY autoprint +.IP "autoprint, ap [off]" +.CO Ex +only. +Cause the current line to be automatically displayed after the +.CO ex +commands +.CO < , +.CO > , +.CO copy , +.CO delete , +.CO join , +.CO move , +.CO put , +.CO t , +.CO Undo , +and +.CO undo . +This automatic display is suppressed during +.CO global +and +.CO vglobal +commands, and for any command where optional flags are used to explicitly +display the line. +.KY autowrite +.IP "autowrite, aw [off]" +If this option is set, the +.CO vi +.CO ! , +.CO ^^ , +.CO ^] +and +.CO <control-Z> +commands, and the +.CO ex +.CO edit , +.CO next , +.CO rewind , +.CO stop , +.CO suspend , +.CO tag , +.CO tagpop , +and +.CO tagtop +commands automatically write the current file back to the current file name +if it has been modified since it was last written. +If the write fails, the command fails and goes no further. +.sp +Appending the optional force flag character +.QT ! +to the +.CO ex +commands +.CO next , +.CO rewind , +.CO stop , +.CO suspend , +.CO tag , +.CO tagpop , +and +.CO tagtop +stops the automatic write from being attempted. +.sp +(Historically, the +.CO next +command ignored the optional force flag.) +Note, the +.CO ex +commands +.CO edit , +.CO quit , +.CO shell , +and +.CO xit +are +.i not +affected by the +.OP autowrite +option. +.KY beautify +.IP "beautify, bf [off]" +If this option is set, all control characters that are not currently being +specially interpreted, other than +.LI <tab> , +.LI <newline> , +and +.LI <form-feed> , +are +discarded from commands read in by +.CO ex +from command files, and from input text entered to +.CO vi +(either into the file or to the colon command line). +Text files read by +.EV ex vi +are +.i not +affected by the +.OP beautify +option. +.KY cdpath +.IP "cdpath [environment variable CDPATH, or current directory]" +This option is used to specify a colon separated list of directories +which are used as path prefixes for any relative path names used as +arguments for the +.CO cd +command. +The value of this option defaults to the value of the environmental +variable +.LI CDPATH +if it is set, otherwise to the current directory. +For compatibility with the POSIX 1003.2 shell, the +.CO cd +command does +.i not +check the current directory as a path prefix for relative path names +unless it is explicitly specified. +It may be so specified by entering an empty string or a +.QT \&. +character into the +.LI CDPATH +variable or the option value. +.KY columns +.IP "columns, co [80]" +The number of columns in the screen. +Setting this option causes +.EV ex vi +to set (or reset) the environmental variable +.LI COLUMNS . +See the section entitled +.QB "Sizing the Screen" +more information. +.KY comment +.IP "comment [off]" +.CO Vi +only. +If the first non-empty line of the file begins with the string +.QT /\&* , +this option causes +.CO vi +to skip to the end of that C-language comment (probably a terribly boring +legal notice) before displaying the file. +.KY directory +.IP "directory, dir [environment variable TMPDIR, or /tmp]" +The directory where temporary files are created. +The environmental variable +.LI TMPDIR +is used as the default value if it exists, otherwise +.LI /tmp +is used. +.KY edcompatible +.IP "edcompatible, ed [off]" +Remember the values of the +.QQ c +and +.QQ g +suffices to the +.CO substitute +commands, instead of initializing them as unset for each new +command. +Specifying pattern and replacement strings to the +.CO substitute +command unsets the +.QQ c +and +.QQ g +suffices as well. +.KY errorbells +.IP "errorbells, eb [off]" +.CO Ex +only. +.CO Ex +error messages are normally presented in inverse video. +If that is not possible for the terminal, setting this option causes +error messages to be announced by ringing the terminal bell. +.KY exrc +.IP "exrc, ex [off]" +If this option is turned off in the system or $HOME startup files, +the local startup files are never read (unless they are the same +as the system or $HOME startup files). +Turning it on has no effect, i.e. the normal checks for local startup +files are performed, regardless. +See the section entitled +.QB "Startup Information" +for more information. +.KY extended +.IP "extended [off]" +This option causes all regular expressions to be treated as POSIX +1003.2 Extended Regular Expressions (which are similar to historic +.XR egrep 1 +style expressions). +.KY flash +.IP "flash [on]" +This option causes the screen to flash instead of beeping the keyboard, +on error, if the terminal has the capability. +.KY hardtabs +.IP "hardtabs, ht [8]" +This option defines the spacing between hardware tab settings, i.e. +the tab expansion done by the operating system and/or the terminal +itself. +As +.EV nex nvi +never writes +.LI <tab> +characters to the terminal, unlike historic versions of +.EV ex vi , +this option does not currently have any affect. +.KY ignorecase +.IP "ignorecase, ic [off]" +This option causes regular expressions, both in +.CO ex +commands and in searches, +to be evaluated in a case-insensitive manner. +.KY keytime +.IP "keytime [6]" +The 10th's of a second +.EV ex vi +waits for a subsequent key to complete a key mapping. +.KY leftright +.IP "leftright [off]" +.CO Vi +only. +This option causes the screen to be scrolled left-right to view +lines longer than the screen, instead of the traditional +.CO vi +screen interface which folds long lines at the right-hand margin +of the terminal. +.KY lines +.IP "lines, li [24]" +.CO Vi +only. +The number of lines in the screen. +Setting this option causes +.EV ex vi +to set (or reset) the environmental variable +.LI LINES . +See the section entitled +.QB "Sizing the Screen" +for more information. +.KY lisp +.IP "lisp [off]" +.CO Vi +only. +This option changes the behavior of the +.CO vi +.CO ( , +.CO ) , +.CO { , +.CO } , +.CO [[ +and +.CO ]] +commands to match the Lisp language. +Also, the +.OP autoindent +option's behavior is changed to be appropriate for Lisp. +.sp +.i "This option is not yet implemented." +.KY list +.IP "list [off]" +This option causes lines to be displayed in an unambiguous fashion. +Specifically, tabs are displayed as control characters, i.e. +.QT ^I , +and the ends of lines are marked with a +.QT $ +character. +.KY magic +.IP "magic [on]" +This option is on by default. +Turning the +.OP magic +option off causes all regular expression characters except for +.QT ^ +and +.QT $ , +to be treated as ordinary characters. +To re-enable characters individually, when the +.OP magic +option is off, +precede them with a backslash +.QT \e +character. +See the section entitled +.QB "Regular Expressions and Replacement Strings" +for more information. +.KY matchtime +.IP "matchtime [7]" +.CO Vi +only. +The 10th's of a second +.EV ex vi +pauses on the matching character when the +.OP showmatch +option is set. +.KY mesg +.IP "mesg [on]" +This option allows other users to contact you using the +.XR talk 1 +and +.XR write 1 +utilities, while you are editing. +.EV Ex vi +does not turn message on, i.e. if messages were turned off when the +editor was invoked, they will stay turned off. +This option only permits you to disallow messages for the edit session. +See the +.XR mesg 1 +utility for more information. +.KY modelines +.IP "modelines, modeline [off]" +If the +.OP modelines +option is set, +.EV ex vi +has historically scanned the first and last five lines of each file as +it is read for editing, looking for any +.CO ex +commands that have been placed in those lines. +After the startup information has been processed, and before the user +starts editing the file, any commands embedded in the file are executed. +.sp +Commands were recognized by the letters +.QQ e +or +.QQ v +followed by +.QQ x +or +.QQ i , +at the beginning of a line or following a tab or space character, +and followed by a +.QQ : , +an +.CO ex +command, and another +.QQ : . +.sp +This option is a security problem of immense proportions, +and should not be used under any circumstances. +.sp +.i "This option will never be implemented." +.KY number +.IP "number, nu [off]" +Precede each line displayed with its current line number. +.KY octal +.IP "octal [off]" +Display unknown characters as octal numbers, instead of the default +hexadecimal. +.KY open +.IP "open [on]" +.CO Ex +only. +If this option is not set, the +.CO open +and +.CO visual +commands are disallowed. +.KY optimize +.IP "optimize, opt [on]" +.CO Vi +only. +Throughput of text is expedited by setting the terminal not to do automatic +carriage returns when printing more than one (logical) line of output, +greatly speeding output on terminals without addressable cursors when text +with leading white space is printed. +.sp +.i "This option is not yet implemented." +.KY paragraphs +.IP "paragraphs, para [IPLPPPQPP LIpplpipbp]" +.CO Vi +only. +Define additional paragraph boundaries for the +.CO { +and +.CO } +commands. +The value of this option must be a character string consisting +of zero or more character pairs. +.sp +In the text to be edited, the character string +.LI "<newline>.<char-pair>" , +(where +.LI <char-pair> +is one of the character pairs in the option's value) +defines a paragraph boundary. +For example, if the option were set to +.LI "LaA<space>##" , +then all of the following additional paragraph boundaries would be +recognized: +.sp +.(l +<newline>.La +<newline>.A<space> +<newline>.## +.)l +.KY prompt +.IP "prompt [on]" +.CO Ex +only. +This option causes +.CO ex +to prompt for command input with a +.QT : +character; when it is not set, no prompt is displayed. +.KY readonly +.IP "readonly, ro [off]" +This option causes a force flag to be required to attempt to write +the file back to the original file name. +Setting this option is equivalent to using the +.b \-R +command line option, or editing a file which lacks write permission. +.KY recdir +.IP "recdir [/var/tmp/vi.recover]" +The directory where recovery files are stored. +.sp +If you change the value of +.CO recdir , +be careful to choose a directory whose contents are not regularly +deleted. +Bad choices include directories in memory based filesystems, +or +.LI /tmp , +on most systems, +as their contents are removed when the machine is rebooted. +.sp +Public directories like +.LI /usr/tmp +and +.LI /var/tmp +are usually safe, although some sites periodically prune old files +from them. +There is no requirement that you use a public directory, +e.g. a sub-directory of your home directory will work fine. +.sp +Finally, if you change the value of +.CO recdir , +you must modify the recovery script to operate in your chosen recovery +area. +.sp +See the section entitled +.QB "Recovery" +for further information. +.KY redraw +.IP "redraw, re [off]" +.CO Vi +only. +The editor simulates (using great amounts of output), an intelligent +terminal on a dumb terminal (e.g. during insertions in +.CO vi +the characters to the right of the cursor are refreshed as each input +character is typed). +.sp +.i "This option is not yet implemented." +.KY remap +.IP "remap [on]" +If this option is set, +it is possible to define macros in terms of other macros. +Otherwise, each key is only remapped up to one time. +For example, if +.QT A +is mapped to +.QT B , +and +.QT B +is mapped to +.QT C , +The keystroke +.QT A +will be mapped to +.QT C +if the +.OP remap +option is set, and to +.QT B +if it is not set. +.KY report +.IP "report [5]" +Set the threshold of the number of lines that need to be changed or +yanked before a message will be displayed to the user. +For everything but the yank command, the value is the largest value +about which the editor is silent, i.e. by default, 6 lines must be +deleted before the user is notified. +However, if the number of lines yanked is greater than +.i "or equal to" +the set value, it is reported to the user. +.KY ruler +.IP "ruler [off]" +.CO Vi +only. +Display a row/column ruler on the colon command line. +.KY scroll +.IP "scroll, scr [window / 2]" +Set the number of lines scrolled by the +.CO vi +.CO <control-D> +and +.CO <control-U> +commands. +.sp +Historically, the +.CO ex +.CO z +command, when specified without a count, used two times the size of the +scroll value; the POSIX 1003.2 standard specified the window size, which +is a better choice. +.KY sections +.IP "sections, sect [NHSHH HUnhsh]" +.CO Vi +only. +Define additional section boundaries for the +.CO [[ +and +.CO ]] +commands. +The +.OP sections +option should be set to a character string consisting of zero or +more character pairs. +In the text to be edited, the character string +.LI "<newline>.<char-pair>" , +(where +.LI <char-pair> +is one of the character pairs in the option's value), +defines a section boundary in the same manner that +.OP paragraph +option boundaries are defined. +.KY shell +.IP "shell, sh [environment variable SHELL, or /bin/sh]" +Select the shell used by the editor. +The specified path is the pathname of the shell invoked by the +.CO vi +.CO ! +shell escape command and by the +.CO ex +.CO shell +command. +This program is also used to resolve any shell meta-characters in +.CO ex +commands. +.KY shiftwidth +.IP "shiftwidth, sw [8]" +Set the autoindent and shift command indentation width. +This width is used by the +.OP autoindent +option and by the +.CO < , +.CO > , +and +.CO shift +commands. +.KY showdirty +.IP "showdirty [off]" +.CO Vi +only. +Display an asterisk on the colon command line if the file has been modified. +.KY showmatch +.IP "showmatch, sm [off]" +.CO Vi +only. +This option causes +.CO vi , +when a +.QT } +or +.QT ) +is entered, to briefly move the cursor the matching +.QT { +or +.QT ( . +See the +.OP matchtime +option for more information. +.KY showmode +.IP "showmode [off]" +.CO Vi +only. +This option causes +.CO vi +to display a string identifying the current editor mode on the +colon command line. +.KY sidescroll +.IP "sidescroll [16]" +.CO Vi +only. +Sets the number of columns that are shifted to the left or right, +when +.CO vi +is doing left-right scrolling and the left or right margin is +crossed. +See the +.OP leftright +option for more information. +.KY slowopen +.IP "slowopen, slow [off]" +This option affects the display algorithm used by +.CO vi , +holding off display updating during input of new text to improve +throughput when the terminal in use is slow and unintelligent. +.sp +.i "This option is not yet implemented." +.KY sourceany +.IP "sourceany [off]" +If this option is turned on, +.CO vi +historically read startup files that were owned by someone other than +the editor user. +See the section entitled +.QB "Startup Information" +for more information. +This option is a security problem of immense proportions, +and should not be used under any circumstances. +.sp +.i "This option will never be implemented." +.KY tabstop +.IP "tabstop, ts [8]" +This option sets tab widths for the editor display. +.KY taglength +.IP "taglength, tl [0]" +This option sets the maximum number of characters that are considered +significant in a tag name. +Setting the value to 0 makes all of the characters in the tag name +significant. +.KY tags +.IP "tags, tag [tags /var/db/libc.tags /sys/kern/tags]" +Sets the list of tags files, in search order, +which are used when the editor searches for a tag. +.KY term +.IP "term, ttytype, tty [environment variable TERM]" +Set the terminal type. +Setting this option causes +.EV ex vi +to set (or reset) the environmental variable +.LI TERM . +.KY terse +.IP "terse [off]" +This option has historically made editor messages less verbose. +It has no effect in this implementation. +See the +.OP verbose +option for more information. +.KY tildeop +.IP "tildeop" +Modify the +.CO ~ +command to take an associated motion. +.KY timeout +.IP "timeout, to [on]" +If this option is set, +.EV ex vi +waits for a specific period for a subsequent key to complete a key +mapping (see the +.OP keytime +option). +If the option is not set, the editor waits until enough keys are +entered to resolve the ambiguity, regardless of how long it takes. +.KY ttywerase +.IP "ttywerase [off]" +.CO Vi +only. +This option changes how +.CO vi +does word erase during text input. +If this option is set, text is broken up into two classes, +blank characters and nonblank characters. +Changing from one class to another marks the end of a word. +.KY verbose +.IP "verbose [off]" +.CO Vi +only. +.CO Vi +historically bells the terminal for many obvious mistakes, e.g. trying +to move past the left-hand margin, or past the end of the file. +If this option is set, an error message is displayed for all errors. +.KY w300 +.IP "w300 [no default]" +.CO Vi +only. +Set the window size if the baud rate is less than 1200 baud. +See the +.OP window +option for more information. +.KY w1200 +.IP "w1200 [no default]" +.CO Vi +only. +Set the window size if the baud rate is equal to 1200 baud. +See the +.OP window +option for more information. +.KY w9600 +.IP "w9600 [no default]" +.CO Vi +only. +Set the window size if the baud rate is greater than 1200 baud. +See the +.OP window +option for more information. +.KY warn +.IP "warn [on]" +.CO Ex +only. +This option causes a warning message to the terminal if the file has +been modified, since it was last written, before a +.CO ! +command. +.KY window +.IP "window, w, wi [environment variable LINES]" +This option determines the default number of lines in a screenful, +as written by the +.CO z +command. +It also determines the number of lines scrolled by the +.CO vi +commands +.CO <control-F> +and +.CO <control-B> . +The value of window can be unrelated to the real screen size, +although it starts out as the number of lines on the screen (see +the section entitled +.QB "Sizing the Screen" +for more information). +Setting the value of the +.OP window +option is the same as using the +.b \-w +command line option. +.sp +If the value of the +.OP window +option (as set by the +.OP window , +.OP w300 , +.OP w1200 +or +.OP w9600 +options) is smaller than the actual size of the screen, large screen +movements will result in displaying only that smaller number of lines +on the screen. +(Further movements in that same area will result in the screen being +filled.) +This can provide a performance improvement when viewing different +places in one or more files over a slow link. +.KY wrapmargin +.IP "wrapmargin, wm [0]" +.CO Vi +only. +If the value of the +.OP wrapmargin +option is non-zero, +.CO vi +will split lines so that they end at least that number of characters +before the right-hand margin of the screen. +(Note, the value of +.OP wrapmargin +is +.i not +a text length. +In a screen that is 80 columns wide, the command +.QT ":set wrapmargin=8" +attempts to keep the lines less than or equal to 72 columns wide.) +.sp +Lines are split at the previous whitespace character closest to the +number. +Any trailing whitespace characters before that character are deleted. +If the line is split because of an inserted +.LI <space> +or +.LI <tab> +character, and you then enter another +.LI <space> +character, it is discarded. +.sp +If wrapmargin is set to 0, +or if there is no blank character upon which to split the line, +the line is not broken. +.KY wrapscan +.IP "wrapscan, ws [on]" +This option causes searches to wrap around the end or the beginning +of the file, and back to the starting point. +Otherwise, the end or beginning of the file terminates the search. +.KY writeany +.IP "writeany, wa [off]" +If this option is set, file-overwriting checks that would usually be +made before the +.CO write +and +.CO xit +commands, or before an automatic write (see the +.OP autowrite +option), are not made. +This allows a write to any file, provided the file permissions allow it. diff --git a/usr.bin/vi/USD.doc/vi.ref/spell.ok b/usr.bin/vi/USD.doc/vi.ref/spell.ok new file mode 100644 index 0000000..60084e3 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/spell.ok @@ -0,0 +1,270 @@ +Amir +Autoprint +BRE's +Bostic +Bourne +DOUBLEQUOTE +Dq +Ds +ERE's +EXINIT +Englar +Ev +FF +Fa +Fl +HUnhsh +IPLPPPQPP +Kirkendall +Korn +LIpplpipbp +LaA +Li +Lowercase +MINUSSIGN +Makefiles +NEX +NEXINIT +NHSHH +NVI +Nex +Nvi +OS +POSIX +PostScript +RE's +README +RECDIR +Reference''USD:13 +SIGHUP +SIGWINCH +SQUOTE +Se +Std +Std1003.2 +Sy +TANDARDS +TIOCGWINSZ +TMPDIR +Todo +USD.doc +USD:13 +UUNET +Vx +Whitespace +XOFF +XON +XOptions +XXCOLUMNS +XXXX +XXXXXX +XXb +ZZ +ab +abbrev +ags +ai +al +altwerase +arg +args +autoindent +autoprint +autowrite +aw +bbrev +bf +bigword +bigwords +bostic +brev +bugs.current +c2w +carat +cdy +changelog +chd +cmd +count1 +count2 +creens +cs.berkeley.edu +db +dbopen +def +di +dir +dit +docs +eFlRsv +eFlRv +ead +eb +edcompatible +elete +elvis +email +enum +eof +errorbells +esc +ex.cmd.roff +exrc +ext +exu +exusage +fi +filesystem +filesystems +ftp.cs.berkeley.edu +ftp.uu.net +gdb +gdb.script +gs +gzip'd +halfbyte +hange +hangup +hardtabs +ht +ic +ifdef +ignorecase +ile +ind +ious +ir +ist +ize +keystroke +keystrokes +keytime +leftright +lhs +li +lib +libc.tags +lobal +lowercase +lp +matchtime +mber +meta +mk +mkexrc +modeful +modeline +modelines +ndo +nex +nexrc +nk +nomagic +nooption +nsert +nul +nvi +nvi.tar.Z +nvi.tar.z +nz +oin +op +ove +para +pathname +pathnames +ppend +pu +py +rc.local +readonly +rec +recdir +recfile +recover.XXXX +recover.XXXXXX +recover.c +recover.script +remapmax +res +rew +rhs +ript +rk +ro +roff +rsion +sc +scr +screeen +se +set.opt.roff +shiftwidth +showmatch +showmode +sidescroll +slowopen +sm +sourceany +sp +spell.ok +st +sual +svi +sw +ta +tabstop +taglength +tagp +tagpop +tagstring +tagt +tagtop +terminfo +th +tildeop +tl +tmp +ts +ttytype +ttywerase +uR +ubstitute +ucb +uffers +uit +una +unabbrev +unm +uppercase +urce +uunet +var +ve +vglobal +vi.0.ps +vi.0.txt +vi.1 +vi.XXXX +vi.XXXXXX +vi.cmd.roff +vi.exrc +vi.recover +vibackup +virecovery +viu +viusage +wa +whitespace +wi +wm +wn +wq +wrapmargin +wrapscan +writeany +ws +xaw +xit +ya +yy diff --git a/usr.bin/vi/USD.doc/vi.ref/vi.cmd.roff b/usr.bin/vi/USD.doc/vi.ref/vi.cmd.roff new file mode 100644 index 0000000..57c0d37 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/vi.cmd.roff @@ -0,0 +1,2984 @@ +.\" Copyright (c) 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vi.cmd.roff 8.28 (Berkeley) 7/17/94 +.\" +.SH 1 "Vi Description" +.pp +.CO Vi +takes up the entire screen to display the edited file, +except for the bottom line of the screen. +The bottom line of the screen is used to enter +.CO ex +commands, and for +.CO vi +error and informational messages. +If no other information is being displayed, +the default display can show the current cursor row and cursor column, +an indication of whether the file has been modified, +and the current mode of the editor. +See the +.OP ruler , +.OP showdirty +and +.OP showmode +options for more information. +.pp +Empty lines do not have any special representation on the screen, +but lines on the screen that would logically come after the end of +the file are displayed as a single tilde +.PQ ~ +character. +To differentiate between empty lines and lines consisting of only +whitespace characters, use the +.OP list +option. +Historically, implementations of +.CO vi +have also displayed some lines as single asterisk +.PQ @ +characters. +These were lines that were not correctly displayed, i.e. lines on the +screen that did not correspond to lines in the file, or lines that did +not fit on the current screen. +.CO Nvi +never displays lines in this fashion. +.pp +.CO Vi +is a modeful editor, i.e. it has two modes, +.QQ command +mode and +.QQ "text input" +mode. +When +.CO vi +first starts, it is in command mode. +There are several commands that change +.CO vi +into text input mode. +The +.LI <escape> +character is used to resolve the text input into the file, +and exit back into command mode. +In +.CO vi +command mode, the cursor is always positioned on the last column of +characters which take up more than one column on the screen. +In +.CO vi +text insert mode, the cursor is positioned on the first column of +characters which take up more than one column on the screen. +.pp +Generally, if the cursor line and cursor column are not on the screen, +then the screen is scrolled (if the target cursor is close) or repainted +(if the target cursor is far away) so that the cursor is on the screen. +If the screen is scrolled, it is moved a minimal amount, and the cursor +line will usually appear at the top or bottom of the screen. +In the screen is repainted, the cursor line will appear in the center of +the screen, unless the cursor is sufficiently close to the beginning or +end of the file that this is not possible. +If the +.OP leftright +option is set, the screen may be scrolled or repainted in a horizontal +direction as well as in a vertical one. +.pp +A major difference between the historical +.CO vi +presentation and +.CO nvi +is in the scrolling and screen oriented position commands, +.CO <control-B> , +.CO <control-D> , +.CO <control-E> , +.CO <control-F> , +.CO <control-U> , +.CO <control-Y> , +.CO H , +.CO L +and +.CO M . +In historical implementations of +.CO vi , +these commands acted on physical (as opposed to logical, or screen) +lines. +For lines that were sufficiently long in relation to the size of the +screen, this meant that single line scroll commands might repaint the +entire screen, scrolling or screen positioning command might not change +the screen or move the cursor at all, and some lines simply could not +be displayed, even though +.CO vi +would edit the file that contained them. +In +.CO nvi , +these commands act on logical, i.e. screen lines. +You are unlikely to notice any difference unless you are editing files +with lines significantly longer than a screen width. +.pp +.CO Vi +keeps track of the currently +.QQ "most attractive" +cursor position. +Each command description (for commands that can change the current +cursor position), +specifies if the cursor is set to a specific location in the line, +or if it is moved to the +.QQ "most attractive cursor position" . +The latter means that the cursor is moved to the cursor position +that is vertically as close as possible to the current cursor +position. +If the current line is shorter than the cursor position +.CO vi +would select, the cursor is positioned on the last character in the line. +(If the line is empty, the cursor is positioned on the first column +of the line.) +If a command moves the cursor to the most attractive position, +it does not alter the current cursor position, and a subsequent +movement will again attempt to move the cursor to that position. +Therefore, although a movement to a line shorter than the currently +most attractive position will cause the cursor to move to the end of +that line, a subsequent movement to a longer line will cause the +cursor to move back to the most attractive position. +.pp +In addition, the +.CO $ +command makes the end of each line the most attractive cursor position +rather than a specific column. +.pp +Each +.CO vi +command described below notes where the cursor ends up after it is +executed. +This position is described in terms of characters on the line, i.e. +.QQ "the previous character" , +or, +.QQ "the last character in the line" . +This is to avoid needing to continually refer to on what part of the +character the cursor rests. +.pp +The following words have special meaning for +.CO vi +commands. +.KY "previous context" +.IP "previous context" +The position of the cursor before the command which caused the +last absolute movement was executed. +Each +.CO vi +command described in the next section that is considered an +absolute movement is so noted. +In addition, specifying +.i any +address to an +.CO ex +command is considered an absolute movement. +.KY "motion" +.IP "motion" +A second +.CO vi +command can be used as an optional trailing argument to the +.CO vi +.CO \&! , +.CO \&< , +.CO \&> , +.CO \&c , +.CO \&d , +.CO \&y , +and (depending on the +.OP tildeop +option) +.CO \&~ +commands. +This command indicates the end of the region of text that's affected by +the command. +The motion command may be either the command character repeated (in +which case it means the current line) or a cursor movement command. +In the latter case, the region affected by the command is from the +starting or stopping cursor position which comes first in the file, +to immediately before the starting or stopping cursor position which +comes later in the file. +Commands that operate on lines instead of using beginning and ending +cursor positions operate on all of the lines that are wholly or +partially in the region. +In addition, some other commands become line oriented depending on +where in the text they are used. +The command descriptions below note these special cases. +.sp +The following commands may all be used as motion components for +.CO vi +commands: +.sp +.ne 12v +.ft C +.TS +r r r r. +<control-A> <control-H> <control-J> <control-M> +<control-N> <control-P> <space> $ +% '<character> ( ) ++ , - / +0 ; ? B +E F G H +L M N T +W [[ ]] ^ +\&_ `<character> b e +f h j k +l n t w +{ | } +.TE +.ft R +.sp +The optional count prefix available for some of the +.CO vi +commands that take motion commands, or the count prefix available +for the +.CO vi +commands that are used as motion components, +may be included and is +.i always +considered part of the motion argument. +For example, the commands +.QT c2w +and +.QT 2cw +are equivalent, and the region affected by the +.CO c +command is two words of text. +In addition, if the optional count prefix is specified for both the +.CO vi +command and its motion component, the effect is multiplicative and +is considered part of the motion argument. +For example, the commands +.QT 4cw +and +.QT 2c2w +are equivalent, and the region affected by the +.CO c +command is four words of text. +.KY "count" +.IP "count" +A positive number used as an optional argument to most commands, +either to give a size or a position (for display or movement commands), +or as a repeat count (for commands that modify text). +The count argument is always optional and defaults to 1 unless otherwise +noted in the command description. +.sp +When a +.CO vi +command synopsis shows both a +.LI [buffer] +and +.LI [count] , +they may be presented in any order. +.KY "bigword" +.IP "bigword" +A set of non-whitespace characters preceded and followed by whitespace +characters or the beginning or end of the file or line. +.sp +Groups of empty lines (or lines containing only whitespace characters) +are treated as a single bigword. +.KY word +.IP word +Generally, in languages where it is applicable, +.CO vi +recognizes two kinds of words. +First, a sequence of letters, digits and underscores, delimited at both +ends by: characters other than letters, digits, or underscores; the +beginning or end of a line; the beginning or end of the file. +Second, a sequence of characters other than letters, digits, underscores, +or whitespace characters, delimited at both ends by: a letter, digit, +underscore, or whitespace character; +the beginning or end of a line; the beginning or end of the file. +.sp +Groups of empty lines (or lines containing only whitespace characters) +are treated as a single word. +.KY "paragraph" +.IP "paragraph" +An area of text that begins with either the beginning of a file, +an empty line, or a section boundary, and continues until either +an empty line, section boundary, or the end of the file. +.sp +Groups of empty lines (or lines containing only whitespace characters) +are treated as a single paragraph. +.sp +Additional paragraph boundaries can be defined using the +.OP paragraph +option. +.KY "section" +.IP "section" +An area of text that starts with the beginning of the file or a line +whose first character is an open brace +.PQ { +and continues until the next section or the end of the file. +.sp +Additional section boundaries can be defined using the +.OP sections +option. +.KY "sentence" +.IP "sentence" +An area of text that begins with either the beginning of the file or the +first nonblank character following the previous sentence, paragraph, or +section boundary and continues until the end of the file or a or a period +.PQ \&. +exclamation point +.PQ ! +or question mark +.PQ ? +character, +followed by either an end-of-line or two whitespace characters. +Any number of closing parentheses +.PQ ) , +brackets +.PQ ] +or double-quote +.PQ """" +characters can appear between the period, exclamation point, +or question mark and the whitespace characters or end-of-line. +.sp +Groups of empty lines (or lines containing only whitespace characters) +are treated as a single sentence. +.SH 1 "Vi Commands" +.pp +The following section describes the commands available in the command +mode of the +.CO vi +editor. +In each entry below, the tag line is a usage synopsis for the command +character. +In addition, the final line and column the cursor rests upon, +and any options which affect the command are noted. +.KY <control-A> +.IP "[count] <control-A>" +Search forward +.LI count +times for the current word. +The current word begins at the first non-whitespace character on or +after the current cursor position, +and extends up to the next non-word character or the end of the line. +The search is literal, i.e. no characters in the word have any special +meaning in terms of Regular Expressions. +It is an error if no matching pattern is found between the starting position +and the end of the file. +.sp +The +.CO <control-A> +command is an absolute movement. +The +.CO <control-A> +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Set to the line where the word is found. +.SP Column: +Set to the first character of the word. +.SP Options: +Affected by the +.OP extended , +.OP ignorecase +and +.OP wrapscan +options. +.SE +.KY <control-B> +.IP "[count] <control-B>" +Page backward +.LI count +screens. +Two lines of overlap are maintained by displaying the window +starting at line +.LI "(top_line - count * window_size) + 2" , +where +.LI window_size +is the value of the +.OP window +option. +(In the case of split screens, this size is corrected to the +current screen size.) +This is an error if the movement is past the beginning of the file. +.sp +The +.CO <control-B> +command is an absolute movement. +.SS +.SP Line: +Set to the last line of text displayed on the screen. +.SP Column: +Set to the first nonblank character of the line. +.SP Options: +None. +.SE +.KY <control-D> +.IP "[count] <control-D>" +Scroll forward +.LI count +lines. +If +.LI count +is not specified, scroll forward the number of lines specified by the last +.CO <control-D> +or +.CO <control-U> +command. +If this is the first +.CO <control-D> +or +.CO <control-U> +command, +scroll forward half the number of lines in the screen. +(In the case of split screens, the default scrolling distance is +corrected to half the current screen size.) +This is an error if the movement is past the end of the file. +.sp +The +.CO <control-D> +command is an absolute movement. +.SS +.SP Line: +Set to the current line plus the number of lines scrolled. +.SP Column: +Set to the first nonblank character of the line. +.SP Options: +None. +.SE +.KY <control-E> +.IP "[count] <control-E>" +Scroll forward +.LI count +lines, leaving the cursor on the current line and column, if possible. +This is an error if the movement is past the end of the file. +.SS +.SP Line: +Unchanged unless the current line scrolls off the screen, +in which case it is set to the first line on the screen. +.SP Column: +Unchanged unless the current line scrolls off the screen, +in which case it is set to the most attractive cursor position. +.SP Options: +None. +.SE +.KY <control-F> +.IP "[count] <control-F>" +Page forward +.LI count +screens. +Two lines of overlap are maintained by displaying the window +starting at line +.LI "top_line + count * window_size - 2" , +where +.LI window_size +is the value of the +.OP window +option. +(In the case of split screens, this size is corrected to the +current screen size.) +This is an error if the movement is past the end of the file. +.sp +The +.CO <control-F> +command is an absolute movement. +.SS +.SP Line: +Set to the first line on the screen. +.SP Column: +Set to the first nonblank character of the current line. +.SP Options: +None. +.SE +.KY <control-G> +.IP "<control-G>" +Display the file information. +The information includes the current pathname, the current line, +the number of total lines in the file, the current line as a percentage +of the total lines in the file, if the file has been modified, +was able to be locked, if the file's name has been changed, +and if the edit session is read-only. +.SS +.SP Line: +Unchanged. +.SP Column: +Unchanged. +.SP Options: +None. +.SE +.KY <control-H> +.IP "<control-H>" +.Ip "[count] h" +Move the cursor back +.LI count +characters in the current line. +This is an error if the cursor is on the first character in the line. +.sp +The +.CO <control-H> +and +.CO h +commands may be used as the motion component of other +.CO vi +commands, +in which case any text copied into a buffer is character oriented. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the +.LI "current - count" +character, or, the first character in the line if +.LI count +is greater than or equal to the number of characters in the line +before the cursor. +.SP Options: +None. +.SE +.KY <control-J> +.IP "[count] <control-J>" +.KY <control-N> +.Ip "[count] <control-N>" +.KY j +.Ip "[count] j" +Move the cursor down +.LI count +lines without changing the current column. +This is an error if the movement is past the end of the file. +.sp +The +.CO <control-J> , +.CO <control-N> +and +.CO j +commands may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.SS +.SP Line: +Set to the current line plus +.LI count . +.SP Column: +The most attractive cursor position. +.SP Options: +None. +.SE +.KY <control-L> +.IP "<control-L>" +.KY <control-R> +.Ip "<control-R>" +Repaint the screen. +.SS +.SP Line: +Unchanged. +.SP Column: +Unchanged. +.SP Options: +None. +.SE +.KY <control-M> +.IP "[count] <control-M>" +.KY + +.Ip "[count] +" +Move the cursor down +.LI count +lines to the first nonblank character of that line. +This is an error if the movement is past the end of the file. +.sp +The +.CO <control-M> +and +.CO + +commands may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.SS +.SP Line: +Set to the current line plus +.LI count . +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +None. +.SE +.KY <control-P> +.IP "[count] <control-P>" +.KY k +.Ip "[count] k" +Move the cursor up +.LI count +lines, without changing the current column. +This is an error if the movement is past the beginning of the file. +.sp +The +.CO <control-P> +and +.CO k +commands may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.SS +.SP Line: +Set to the current line minus count. +.SP Column: +The most attractive cursor position. +.SP Options: +None. +.SE +.KY <control-T> +.IP "<control-T>" +Return to the most recent tag context. +The +.CO <control-T> +command is an absolute movement. +.SS +.SP Line: +Set to the context of the previous tag command. +.SP Column: +Set to the context of the previous tag command. +.SP Options: +None. +.SE +.KY <control-U> +.IP "<control-U>" +Scroll backward +.LI count +lines. +If +.LI count +is not specified, scroll backward the number of lines specified by the +last +.CO <control-D> +or +.CO <control-U> +command. +If this is the first +.CO <control-D> +or +.CO <control-U> +command, +scroll backward half the number of lines in the screen. +(In the case of split screens, the default scrolling distance is +corrected to half the current screen size.) +This is an error if the movement is past the beginning of the file. +.sp +The +.CO <control-U> +command is an absolute movement. +.SS +.SP Line: +Set to the current line minus the amount scrolled. +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +None. +.SE +.KY <control-W> +.IP "<control-W>" +Switch to the next lower screen in the window, or, to the first +screen if there are no lower screens in the window. +.SS +.SP Line: +Set to the previous cursor position in the window. +.SP Column: +Set to the previous cursor position in the window. +.SP Options: +None. +.SE +.KY <control-Y> +.IP "<control-Y>" +Scroll backward +.LI count +lines, leaving the current line and column as is, if possible. +This is an error if the movement is past the beginning of the file. +.SS +.SP Line: +Unchanged unless the current line scrolls off the screen, +in which case it is set to the last line of text displayed +on the screen. +.SP Column: +Unchanged unless the current line scrolls off the screen, +in which case it is the most attractive cursor position. +.SP Options: +None. +.SE +.KY <control-Z> +.IP "<control-Z>" +Suspend the current editor session. +If the file has been modified since it was last completely written, +and the +.OP autowrite +option is set, the file is written before the editor session is +suspended. +If this write fails, the editor session is not suspended. +.SS +.SP Line: +Unchanged. +.SP Column: +Unchanged. +.SP Options: +Affected by the +.OP autowrite +option. +.SE +.KY <escape> +.IP "<escape>" +Execute +.CO ex +commands or cancel partial commands. +If an +.CO ex +command is being entered (e.g. +.CO / , +.CO ? , +.CO : +or +.CO ! ), +the command is executed. +If a partial command has been entered, e.g. +.QL "[0-9]*" , +or +.QL "[0-9]*[!<>cdy]" , +the command is cancelled. +Otherwise, it is an error. +.SS +.SP Line: +When an +.CO ex +command is being executed, the current line is set as described for +that command. +Otherwise, unchanged. +.SP Column: +When an +.CO ex +command is being executed, the current column is set as described for +that command. +Otherwise, unchanged. +.SP Options: +None. +.SE +.KY <control-]> +.IP "<control-]>" +Push a tag reference onto the tag stack. +The tags files (see the +.OP tags +option for more information) are searched for a tag matching the +current word. +The current word begins at the first non-whitespace character on or +after the current cursor position, +and extends up to the next non-word character or the end of the line. +If a matching tag is found, the current file is discarded and the +file containing the tag reference is edited. +.sp +If the current file has been modified since it was last completely +written, the command will fail. +The +.CO <control-]> +command is an absolute movement. +.SS +.SP Line: +Set to the line containing the matching tag string. +.SP Column: +Set to the start of the matching tag string. +.SP Options: +Affected by the +.OP tags +and +.OP taglength +options. +.SE +.KY <control-^> +.IP "<control-^>" +Switch to the most recently edited file. +.sp +If the file has been modified since it was last completely written, +and the +.OP autowrite +option is set, the file is written out. +If this write fails, the command will fail. +Otherwise, if the current file has been modified since it was last +completely written, the command will fail. +.SS +.SP Line: +Set to the line the cursor was on when the file was last edited. +.SP Column: +Set to the column the cursor was on when the file was last edited. +.SP Options: +Affected by the +.OP autowrite +option. +.SE +.KY <space> +.IP "[count] <space>" +.KY l +.Ip "[count] l" +Move the cursor forward +.LI count +characters without changing the current line. +This is an error if the cursor is on the last character in the line. +.sp +The +.CO <space> +and +.CO \&l +commands may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +In addition, these commands may be used as the motion components +of other commands when the cursor is on the last character in the +line, without error. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the current character plus the next +.LI count +characters, or to the last character on the line if +.LI count +is greater than the number of characters in the line after the +current character. +.SP Options: +None. +.SE +.KY ! +.IP "[count] ! motion shell-argument(s)" +Replace text with results from a shell command. +Pass the lines specified by the +.LI count +and +.LI motion +arguments as standard input to the program named by the +.OP shell +option, and replace those lines with the output (both +standard error and standard output) of that command. +.sp +After the motion is entered, +.CO vi +prompts for arguments to the shell command. +.sp +Within those arguments, +.QT % +and +.QT # +characters are expanded to the current and alternate pathnames, +respectively. +The +.QT ! +character is expanded with the command text of the previous +.CO ! +or +.CO :! +commands. +(Therefore, the command +.CO !! +repeats the previous +.CO ! +command.) +The special meanings of +.QT % , +.QT # +and +.QT ! +can be overridden by escaping them with a backslash. +If no +.CO ! +or +.CO :! +command has yet been executed, it is an error to use an unescaped +.QT ! +character. +The +.CO ! +command does +.i not +do shell expansion on the strings provided as arguments. +If any of the above expansions change the arguments the user entered, +the command is redisplayed at the bottom of the screen. +.sp +.CO Vi +then executes the program named by the +.OP shell +option, with a +.b \-c +flag followed by the arguments (which are bundled into a single argument). +.sp +The +.CO ! +command is permitted in an empty file. +.sp +If the file has been modified since it was last completely written, +the +.CO ! +command will warn you. +.SS +.SP Line: +The first line of the replaced text. +.SP Column: +The first column of the replaced text. +.SP Options: +Affected by the +.OP shell +option. +.SE +.KY # +.IP "[count] # +|-|#" +Increment or decrement the current number. +The current number begins at the first non-number character on or +before the current cursor position, or the beginning of the line, +and extends up to the first non-number character on or after the +current cursor position or the end of the line. +If the trailing character is a +.LI \&+ , +the number is incremented by +.LI count . +If the trailing character is a +.LI \&- , +the number is decremented by +.LI count . +If the trailing character is a +.LI \&# , +the previous increment or decrement is repeated. +.sp +The format of the number (decimal, hexadecimal, and octal, +and leading 0's) is retained unless the new value cannot be +represented in the previous format. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the first character in the cursor word. +.SP Options: +None. +.SE +.KY $ +.IP "[count] $" +Move the cursor to the end of a line. +If +.LI count +is specified, the cursor moves down +.LI "count - 1" +lines. +.sp +It is not an error to use the +.CO $ +command when the cursor is on the last character in the line or +when the line is empty. +.sp +The +.CO $ +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the cursor is at, or before the first +nonblank character in the line, in which case it is line oriented. +It is not an error to use the +.CO $ +command as a motion component when the cursor is on the last character +in the line, although it is an error when the line is empty. +.SS +.SP Line: +Set to the current line plus +.LI count +minus 1. +.SP Column: +Set to the last character in the line. +.SP Options: +None. +.SE +.KY % +.IP % +Move to the matching character. +The cursor moves to the parenthesis or curly brace which +.i matches +the parenthesis or curly brace found at the current cursor position +or which is the closest one to the right of the cursor on the line. +It is an error to execute the +.CO % +command on a line without a parenthesis or curly brace. +Historically, any +.LI count +specified to the +.CO % +command was ignored. +.sp +The +.CO % +command is an absolute movement. +The +.CO % +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the starting point of the region is at +or before the first nonblank character on its line, and the ending +point is at or after the last nonblank character on its line, in +which case it is line oriented. +.SS +.SP Line: +Set to the line containing the matching character. +.SP Column: +Set to the matching character. +.SP Options: +None. +.SE +.KY & +.IP "&" +Repeat the previous substitution command on the current line. +.sp +Historically, any +.LI count +specified to the +.CO & +command was ignored. +.SS +.SP Line: +Unchanged. +.SP Column: +Unchanged if the cursor was on the last character in the line, +otherwise, set to the first nonblank character in the line. +.SP Options: +Affected by the +.OP edcompatible , +.OP extended , +.OP ignorecase +and +.OP magic +options. +.SE +.KY SQUOTE<character> +.IP \'<character> +.KY `<character> +.Ip `<character> +Return to a context marked by the character +.LI <character> . +If +.LI <character> +is the +.QT ' +or +.QT ` +character, return to the previous context. +If +.LI <character> +is any other character, +return to the context marked by that character (see the +.CO m +command for more information). +If the command is the +.CO \' +command, only the line value is restored, +and the cursor is placed on the first nonblank character of that line. +If the command is the +.CO ` +command, both the line and column values are restored. +.sp +It is an error if the context no longer exists because of +line deletion. +(Contexts follow lines that are moved, or which are deleted +and then restored.) +.sp +The +.CO \' +and +.CO ` +commands are both absolute movements. +They may be used as a motion component for other +.CO vi +commands. +For the +.CO \' +command, any text copied into a buffer is line oriented. +For the +.CO ` +command, any text copied into a buffer is character oriented, unless +it both starts and stops at the first character in the line, in which +case it is line oriented. +In addition, when using the +.CO ` +command as a motion component, +commands which move backward and started at the first character in the +line, or move forward and ended at the first character in the line, +are corrected to the last character of the starting and ending lines, +respectively. +.SS +.SP Line: +Set to the line from the context. +.SP Column: +Set to the first nonblank character in the line, for the +.CO \' +command, and set to the context's column for the +.CO ` +command. +.SP Options: +None. +.SE +.KY ( +.IP "[count] (" +Back up +.LI count +sentences. +.sp +The +.CO ( +command is an absolute movement. +The +.CO ( +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the starting and stopping points of the +region are the first character in the line, in which case it is +line oriented. +In the latter case, the stopping point of the region is adjusted +to be the end of the line immediately before it, and not the original +cursor position. +.SS +.SP Line: +Set to the line containing the beginning of the sentence. +.SP Column: +Set to the first nonblank character of the sentence. +.SP Options: +None. +.SE +.KY ) +.IP "[count] )" +Move forward +.LI count +sentences. +.sp +The +.CO ) +command is an absolute movement. +The +.CO ) +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the starting point of the region is the +first character in the line, in which case it is line oriented. +In the latter case, if the stopping point of the region is also +the first character in the line, it is adjusted to be the end of the +line immediately before it. +.SS +.SP Line: +Set to the line containing the beginning of the sentence. +.SP Column: +Set to the first nonblank character of the sentence. +.SP Options: +None. +.SE +.KY , +.IP "[count] ," +Reverse find character +.LI count +times. +Reverse the last +.CO F , +.CO f , +.CO T +or +.CO t +command, searching the other way in the line, +.LI count +times. +.sp +The +.CO , +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the searched-for character. +.SP Options: +None. +.SE +.KY MINUSSIGN +.IP "[count] \-" +Move to first nonblank of the previous line, +.LI count +times. +.sp +This is an error if the movement is past the beginning of the file. +.sp +The +.CO - +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.SS +.SP Line: +Set to the current line minus +.LI count . +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +None. +.SE +.KY \&. +.IP "[count] \&." +Repeat the last +.CO vi +command that modified text. +The repeated command may be a command and motion component combination. +If +.LI count +is specified, it replaces +.i both +the count specified for the repeated command, and, if applicable, for +the repeated motion component. +If +.LI count +is not specified, the counts originally specified to the command being +repeated are used again. +.sp +As a special case, if the +.CO \. +command is executed immediately after the +.CO u +command, the change log is rolled forward or backward, depending on +the action of the +.CO u +command. +.SS +.SP Line: +Set as described for the repeated command. +.SP Column: +Set as described for the repeated command. +.SP Options: +None. +.SE +.KY /RE/ +.IP "/RE<carriage-return>" +.Ip "/RE/ [offset]<carriage-return>" +.KY ?RE? +.Ip "?RE<carriage-return>" +.Ip "?RE? [offset]<carriage-return>" +.KY N +.Ip "N" +.KY n +.Ip "n" +Search forward or backward for a regular expression. +The commands beginning with a slash +.PQ / +character are forward searches, the commands beginning with a +question mark +.PQ ? +are backward searches. +.CO Vi +prompts with the leading character on the last line of the screen +for a string. +It then searches forward or backward in the file for the next +occurrence of the string, which is interpreted as a Basic Regular +Expression. +.sp +The +.CO / +and +.CO ? +commands are absolute movements. +They may be used as the motion components of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the search started and ended on +the first column of a line, in which case it is line oriented. +In addition, forward searches ending at the first character of a line, +and backward searches beginning at the first character in the line, +are corrected to begin or end at the last character of the previous line. +(Note, forward and backward searches can occur for both +.CO / +and +.CO ? +commands, if the +.OP wrapscan +option is set.) +.sp +If an offset from the matched line is specified (i.e. a trailing +.QT / +or +.QT ? +character is followed by a signed offset), the buffer will always +be line oriented (e.g. +.QT /string/+0 +will always guarantee a line orientation). +.sp +The +.CO n +command repeats the previous search. +.sp +The +.CO N +command repeats the previous search, but in the reverse direction. +.sp +Missing RE's (e.g. +.QT //<carriage-return> , +.QT /<carriage-return> , +.QT ??<carriage-return> , +or +.QT ?<carriage-return> +search for the last search RE, in the indicated direction. +.sp +Searches may be interrupted using the +.LI <interrupt> +character. +.SS +.SP Line: +Set to the line in which the match occurred. +.SP Column: +Set to the first character of the matched string. +.SP Options: +Affected by the +.OP edcompatible , +.OP extended , +.OP ignorecase , +.OP magic , +and +.OP wrapscan +options. +.SE +.KY 0 +.IP "0" +Move to the first character in the current line. +It is not an error to use the +.CO 0 +command when the cursor is on the first character in the line, +.sp +The +.CO 0 +command may be used as the motion component of other +.CO vi +commands, in which case it is an error if the cursor is on the +first character in the line. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the first character in the line. +.SP Options: +None. +.SE +.KY : +.IP ":" +Execute an ex command. +.CO Vi +prompts for an +.CO ex +command on the last line of the screen, using a colon +.PQ : +character. +The command is terminated by a +.LI <carriage-return> , +.LI <newline> +or +.LI <escape> +character; all of these characters may be escaped by using a +.LI "<literal next>" +character. +The command is then executed. +.sp +If the +.CO ex +command writes to the screen, +.CO vi +will prompt the user for a +.LI <carriage-return> +before continuing +when the +.CO ex +command finishes. +Large amounts of output from the +.CO ex +command will be paged for the user, and the user prompted for a +.LI <carriage-return> +or +.LI <space> +key to continue. +In some cases, a quit (normally a +.QQ q +character) or +.LI <interrupt> +may be entered to interrupt the +.CO ex +command. +.sp +When the +.CO ex +command finishes, and the user is prompted to resume visual mode, +it is also possible to enter another +.QT : +character followed by another +.CO ex +command. +.SS +.SP Line: +The current line is set as described for the +.CO ex +command. +.SP Column: +The current column is set as described for the +.CO ex +command. +.SP Options: +None. +.SE +.KY ; +.IP "[count] ;" +Repeat the last character find +.LI count +times. +The last character find is one of the +.CO F , +.CO f , +.CO T +or +.CO t +commands. +.sp +The +.CO ; +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the searched-for character. +.SP Options: +None. +.SE +.KY < +.IP "[count] < motion" +.KY > +.Ip "[count] > motion" +Shift lines left or right. +Shift the number of lines in the region specified by the motion component, +times +.LI count , +left (for the +.CO < +command) or right (for the +.CO > +command) by the number of columns specified by the +.OP shiftwidth +option. +Only whitespace characters are deleted when shifting left; +once the first character in the line contains a nonblank character, +the +.CO shift +will succeed, but the line will not be modified. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +Affected by the +.OP shiftwidth +option. +.SE +.KY @ +.IP "@ buffer" +Execute a named buffer. +Execute the named buffer as +.CO vi +commands. +The buffer may include +.CO ex +commands, too, but they must be expressed as a +.CO : +command. +If the buffer is line oriented, +.LI <newline> +characters are logically appended to each line of the buffer. +If the buffer is character oriented, +.LI <newline> +characters are logically appended to all but the last line in the buffer. +.sp +If the buffer name is +.QT @ , +or +.QT * , +then the last buffer executed shall be used. +It is an error to specify +.QT @@ +or +.QT ** +if there were no buffer previous executions. +The text of a macro may contain an +.CO @ +command, +and it is possible to create infinite loops in this manner. +(The +.LI <interrupt> +character may be used to interrupt the loop.) +.SS +.SP Line: +The current line is set as described for the command(s). +.SP Column: +The current column is set as described for the command(s). +.SP Options: +None. +.SE +.KY A +.IP "[count] A" +Enter input mode, appending the text after the end of the line. +If +.LI count +is specified, the text is repeatedly input +.LI "count - 1" +more times after input mode is exited. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY B +.IP "[count] B" +Move backward +.LI count +bigwords. +Move the cursor backward to the beginning of a bigword by repeating the +following algorithm: if the current position is at the beginning of a +bigword or the character at the current position cannot be part of a bigword, +move to the first character of the preceding bigword. +Otherwise, move to the first character of the bigword at the current position. +If no preceding bigword exists on the current line, move to the first +character of the last bigword on the first preceding line that contains a +bigword. +.sp +The +.CO B +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Set to the line containing the word selected. +.SP Column: +Set to the first character of the word selected. +.SP Options: +None. +.SE +.KY C +.IP "[buffer] [count] C" +Change text from the current position to the end-of-line. +If +.LI count +is specified, the input text replaces from the current position to +the end-of-line, plus +.LI "count - 1" +subsequent lines. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY D +.IP "[buffer] D" +Delete text from the current position to the end-of-line. +.sp +It is not an error to execute the +.CO D +command on an empty line. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the character before the current character, or, column 1 if +the cursor was on column 1. +.SP Options: +None. +.SE +.KY E +.IP "[count] E" +Move forward +.LI count +end-of-bigwords. +Move the cursor forward to the end of a bigword by repeating the +following algorithm: if the current position is the end of a +bigword or the character at that position cannot be part of a bigword, +move to the last character of the following bigword. +Otherwise, move to the last character of the bigword at the current +position. +If no succeeding bigword exists on the current line, +move to the last character of the first bigword on the next following +line that contains a bigword. +.sp +The +.CO E +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Set to the line containing the word selected. +.SP Column: +Set to the last character of the word selected. +.SP Options: +None. +.SE +.KY F +.IP "[count] F <character>" +Search +.LI count +times backward through the current line for +.LI <character> . +.sp +The +.CO F +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the searched-for character. +.SP Options: +None. +.SE +.KY G +.IP "[count] G" +Move to line +.LI count , +or the last line of the file if +.LI count +not specified. +.sp +The +.CO G +command is an absolute movement. +The +.CO \&G +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.SS +.SP Line: +Set to +.LI count , +if specified, otherwise, the last line. +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +None. +.SE +.KY H +.IP "[count] H" +Move to the screen line +.LI "count - 1" +lines below the top of the screen. +.sp +The +.CO H +command is an absolute movement. +The +.CO H +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.SS +.SP Line: +Set to the line +.LI "count - 1" +lines below the top of the screen. +.SP Column: +Set to the first nonblank character of the +.i screen +line. +.SP Options: +None. +.SE +.KY I +.IP "[count] I" +Enter input mode, inserting the text at the beginning of the line. +If +.LI count +is specified, the text input is repeatedly input +.LI "count - 1" +more times. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +None. +.SE +.KY J +.IP "[count] J" +Join lines. +If +.LI count +is specified, +.LI count +lines are joined; a minimum of two lines are always joined, +regardless of the value of +.LI count . +.sp +If the current line ends with a whitespace character, all whitespace +is stripped from the next line. +Otherwise, if the next line starts with a open parenthesis +.PQ ( +do nothing. +Otherwise, if the current line ends with a question mark +.PQ ? , +period +.PQ \&. +or exclamation point +.PQ ! , +insert two spaces. +Otherwise, insert a single space. +.sp +It is not an error to join lines past the end of the file, +i.e. lines that do not exist. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the character after the last character of the next-to-last +joined line. +.SP Options: +None. +.SE +.KY L +.IP "[count] L" +Move to the screen line +.LI "count - 1" +lines above the bottom of the screen. +.sp +The +.CO L +command is an absolute movement. +The +.CO L +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.SS +.SP Line: +Set to the line +.LI "count - 1" +lines above the bottom of the screen. +.SP Column: +Set to the first nonblank character of the +.i screen +line. +.SP Options: +None. +.SE +.KY M +.IP " M" +Move to the screen line in the middle of the screen. +.sp +The +.CO M +command is an absolute movement. +The +.CO M +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.sp +Historically, any +.LI count +specified to the +.CO M +command was ignored. +.SS +.SP Line: +Set to the line in the middle of the screen. +.SP Column: +Set to the first nonblank character of the +.i screen +line. +.SP Options: +None. +.SE +.KY O +.IP "[count] O" +Enter input mode, appending text in a new line above the current line. +If +.LI count +is specified, the text input is repeatedly input +.LI "count - 1" +more times. +.sp +Historically, any +.LI count +specified to the +.CO O +command was ignored. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY P +.IP "[buffer] P" +Insert text from a buffer. +Text from the buffer (the unnamed buffer by default) is inserted +before the current column or, if the buffer is line oriented, +before the current line. +.SS +.SP Line: +Set to the lowest numbered line insert, +if the buffer is line oriented, otherwise unchanged. +.SP Column: +Set to the first nonblank character of the appended text, +if the buffer is line oriented, otherwise, the last character +of the appended text. +.SP Options: +None. +.SE +.KY Q +.IP "Q" +Exit +.CO vi +(or visual) mode and switch to +.CO ex +mode. +.SS +.SP Line: +Unchanged. +.SP Column: +No longer relevant. +.SP Options: +None. +.SE +.KY R +.IP "[count] R" +Enter input mode, replacing the characters in the current line. +If +.LI count +is specified, the text input is repeatedly input +.LI "count - 1" +more times. +.sp +If the end of the current line is reached, no more characters are +replaced and any further characters input are appended to the line. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY S +.IP "[buffer] [count] S" +Substitute +.LI count +lines. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY T +.IP "[count] T <character>" +Search backward, +.LI count +times, +through the current line for the character +.i after +the specified +.LI <character> . +.sp +The +.CO T +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the character +.i after +the searched-for character. +.SP Options: +None. +.SE +.KY U +.IP "U" +Restore the current line to its state before the cursor last +moved to it. +.SS +.SP Line: +Unchanged. +.SP Column: +The first character in the line. +.SP Options: +None. +.SE +.KY W +.IP "[count] W" +Move forward +.LI count +bigwords. +Move the cursor forward to the beginning of a bigword by repeating the +following algorithm: if the current position is within a bigword or the +character at that position cannot be part of a bigword, move to the first +character of the next bigword. +If no subsequent bigword exists on the current line, +move to the first character of the first bigword on the first following +line that contains a bigword. +.sp +The +.CO W +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +The line containing the word selected. +.SP Column: +The first character of the word selected. +.SP Options: +None. +.SE +.KY X +.IP "[buffer] [count] X" +Delete +.LI count +characters before the cursor. +If the number of characters to be deleted is greater than or equal to +the number of characters to the beginning of the line, all of the +characters before the current cursor position, to the beginning of the +line, are deleted. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the current character minus +.LI count , +or the first character if count is greater than the number of +characters in the line before the cursor. +.SP Options: +None. +.SE +.KY Y +.IP "[buffer] [count] Y" +Copy (or +.QQ yank ) +.LI count +lines into the specified buffer. +.SS +.SP Line: +Unchanged. +.SP Column: +Unchanged. +.SP Options: +None. +.SE +.KY ZZ +.IP "ZZ" +Write the file and exit +.CO vi . +The file is only written if it has been modified since the last +complete write of the file to any file. +.sp +The +.CO ZZ +command will exit the editor after writing the file, +if there are no further files to edit. +Entering two +.QQ quit +commands (i.e. +.CO wq , +.CO quit , +.CO xit +or +.CO ZZ ) +in a row will override this check and the editor will exit, +ignoring any files that have not yet been edited. +.SS +.SP Line: +Unchanged. +.SP Column: +Unchanged. +.SP Options: +None. +.SE +.KY [[ +.IP "[count] [[" +Back up +.LI count +section boundaries. +.sp +The +.CO [[ +command is an absolute movement. +The +.CO [[ +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the starting position is column 0, +in which case it is line oriented. +.sp +This is an error if the movement is past the beginning of the file. +.SS +.SP Line: +Set to the previous line that is +.LI count +section boundaries back, +or the first line of the file if no more section boundaries exist +preceding the current line. +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +Affected by the +.OP sections +option. +.SE +.KY ]] +.IP "[count] ]]" +Move forward +.LI count +section boundaries. +.sp +The +.CO ]] +command is an absolute movement. +The +.CO ]] +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the starting position is column 0, +in which case it is line oriented. +.sp +This is an error if the movement is past the end of the file. +.SS +.SP Line: +Set to the line that is +.LI count +section boundaries forward, +or to the last line of the file if no more section +boundaries exist following the current line. +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +Affected by the +.OP sections +option. +.SE +.KY ^ +.IP "\&^" +Move to first nonblank character on the current line. +.sp +The +.CO ^ +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the first nonblank character of the current line. +.SP Options: +None. +.SE +.KY _ +.IP "[count] _" +Move down +.LI "count - 1" +lines, to the first nonblank character. +The +.CO _ +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +line oriented. +.sp +It is not an error to execute the +.CO _ +command when the cursor is on the first character in the line. +.SS +.SP Line: +The current line plus +.LI "count - 1" . +.SP Column: +The first nonblank character in the line. +.SP Options: +None. +.SE +.KY a +.IP "[count] a" +Enter input mode, appending the text after the cursor. +If +.LI count +is specified, the text input is repeatedly input +.LI "count - 1" +more times. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY b +.IP "[count] b" +Move backward +.LI count +words. +Move the cursor backward to the beginning of a word by repeating the +following algorithm: if the current position is at the beginning of a word, +move to the first character of the preceding word. +Otherwise, the current position moves to the first character of the word +at the current position. +If no preceding word exists on the current line, move to the first +character of the last word on the first preceding line that contains +a word. +.sp +The +.CO b +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Set to the line containing the word selected. +.SP Column: +Set to the first character of the word selected. +.SP Options: +None. +.SE +.KY c +.IP "[buffer] [count] c motion" +Change a region of text. +If only part of a single line is affected, then the last character +being changed is marked with a +.QT $ . +Otherwise, the region of text is deleted, and input mode is entered. +.sp +If +.LI count +is specified, it is applied to the +.LI motion . +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY d +.IP "[buffer] [count] d motion" +Delete a region of text. +If +.LI count +is specified, it is applied to the +.LI motion . +.SS +.SP Line: +Set to the line where the region starts. +.SP Column: +Set to the first character in the line after the last character in the +region. +If no such character exists, set to the last character before the region. +.SP Options: +None. +.SE +.KY e +.IP "[count] e" +Move forward +.LI count +end-of-words. +Move the cursor forward to the end of a word by repeating the following +algorithm: if the current position is the end of a word, +move to the last character of the following word. +Otherwise, move to the last character of the word at the current position. +If no succeeding word exists on the current line, move to the last character +of the first word on the next following line that contains a word. +.sp +The +.CO e +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Set to the line containing the word selected. +.SP Column: +Set to the last character of the word selected. +.SP Options: +None. +.SE +.KY f +.IP "[count] f <character>" +Search forward, +.LI count +times, through the rest of the current line for +.LI <character> . +.sp +The +.CO f +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the searched-for character. +.SP Options: +None. +.SE +.KY i +.IP "[count] i" +Enter input mode, inserting the text before the cursor. +If +.LI count +is specified, the text input is repeatedly input +.LI "count - 1" +more times. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY m +.IP "m <character>" +Save the current context (line and column) as +.LI <character> . +The exact position is referred to by +.QT `<character> . +The line is referred to by +.QT '<character> . +.sp +Historically, +.LI <character> +was restricted to lower-case letters only, +.CO nvi +permits the use of any character. +.SS +.SP Line: +Unchanged. +.SP Column: +Unchanged. +.SP Options: +None. +.SE +.KY o +.IP "[count] o" +Enter input mode, appending text in a new line under the current line. +If +.LI count +is specified, the text input is repeatedly input +.LI "count - 1" +more times. +.sp +Historically, any +.LI count +specified to the +.CO o +command was ignored. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY p +.IP "[buffer] p" +Append text from a buffer. +Text from the buffer (the unnamed buffer by default) is appended +after the current column or, if the buffer is line oriented, +after the current line. +.SS +.SP Line: +Set to the first line appended, if the buffer is line oriented, +otherwise unchanged. +.SP Column: +Set to the first nonblank character of the appended text if the buffer +is line oriented, otherwise, the last character of the appended text. +.SP Options: +None. +.SE +.KY r +.IP "[count] r <character>" +Replace characters. +The next +.LI count +characters in the line are replaced with +.LI <character> . +Replacing characters with +.LI <newline> +characters results in creating new, empty lines into the file. +.sp +If +.LI <character> +is +.LI <escape> , +the command is cancelled. +.SS +.SP Line: +Unchanged unless the replacement character is a +.LI <newline> , +in which case it is set to the current line plus +.LI "count - 1" . +.SP Column: +Set to the last character replaced, +unless the replacement character is a +.LI <newline> , +in which case the cursor is in column 1 of the last line inserted. +.SP Options: +None. +.SE +.KY s +.IP "[buffer] [count] s" +Substitute +.LI count +characters in the current line starting with the current character. +.SS +.SP Line: +Set to the last line upon which characters were entered. +.SP Column: +Set to the last character entered. +.SP Options: +Affected by the +.OP altwerase , +.OP autoindent , +.OP beautify , +.OP showmatch , +.OP ttywerase +and +.OP wrapmargin +options. +.SE +.KY t +.IP "[count] t <character>" +Search forward, +.LI count +times, through the current line for the character immediately +.i before +.LI <character> . +.sp +The +.CO t +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the character +.i before +the searched-for character. +.SP Options: +None. +.SE +.KY u +.IP "u" +Undo the last change made to the file. +If repeated, the +.CO u +command alternates between these two states, and is its own inverse. +When used after an insert that inserted text on more than one line, +the lines are saved in the numeric buffers. +.sp +The +.CO \&. +command, when used immediately after the +.CO u +command, causes the change log to be rolled forward or backward, +depending on the action of the +.CO u +command. +.SS +.SP Line: +Set to the position of the first line changed, if the reversal affects +only one line or represents an addition or change; otherwise, the line +preceding the deleted text. +.SP Column: +Set to the cursor position before the change was made. +.SP Options: +None. +.SE +.KY w +.IP "[count] w" +Move forward +.LI count +words. +Move the cursor forward to the beginning of a word by repeating the +following algorithm: if the current position is at the +beginning of a word, move to the first character of the next word. +If no subsequent word exists on the current line, move to the first +character of the first word on the first following line that contains +a word. +.sp +The +.CO w +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +.SS +.SP Line: +Set to the line containing the word selected. +.SP Column: +Set to the first character of the word selected. +.SP Options: +None. +.SE +.KY x +.IP "[buffer] [count] x" +Delete +.LI count +characters. +The deletion is at the current character position. +If the number of characters to be deleted is greater than or equal to +the number of characters to the end of the line, all of the characters +from the current cursor position to the end of the line are deleted. +.SS +.SP Line: +Unchanged. +.SP Column: +Unchanged unless the last character in the line is deleted and the cursor +is not already on the first character in the line, in which case it is +set to the previous character. +.SP Options: +None. +.SE +.KY y +.IP "[buffer] [count] y motion" +Copy (or +.QQ yank ) +a text region specified by the +.LI count +and motion into a buffer. +If +.LI count +is specified, it is applied to the +.LI motion . +.SS +.SP Line: +Unchanged, unless the region covers more than a single line, +in which case it is set to the line where the region starts. +.SP Column: +Unchanged, unless the region covers more than a single line, +in which case it is set to the character were the region starts. +.SP Options: +None. +.SE +.KY z +.IP "[count1] z [count2] type" +Redraw the screen with a window +.LI count2 +lines long, with line +.LI count1 +placed as specified by the +.LI type +character. +If +.LI count1 +is not specified, it defaults to the current line. +If +.LI count2 +is not specified, it defaults to the current window size. +.sp +The following +.LI type +characters may be used: +.SS +.SP + +If +.LI count1 +is specified, place the line +.LI count1 +at the top of the screen. +Otherwise, display the screen after the current screen, similarly to the +.CO <control-F> +command. +.SP <carriage-return> +Place the line +.LI count1 +at the top of the screen. +.SP \&. +Place the line +.LI count1 +in the center of the screen. +.SP \- +Place the line +.LI count1 +at the bottom of the screen. +.SP ^ +If +.LI count1 +is specified, place the line that is at the top of the screen +when +.LI count1 +is at the bottom of the screen, at the bottom of the screen, +i.e. display the screen before the screen before +.LI count1 . +Otherwise, display the screen before the current screen, similarly to the +.CO <control-B> +command. +.SE +.SS +.SP Line: +Set to +.LI count1 +unless +.LI count1 +is not specified and the +.LI type +character was either +.QT ^ +or +.QT + , +in which case it is set to the line before the first line on the +previous screen or the line after the last line on the previous +screen, respectively. +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +None. +.SE +.KY { +.IP "[count] {" +Move backward +.LI count +paragraphs. +.sp +The +.CO { +command is an absolute movement. +The +.CO { +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the starting character is the first +character on its line, in which case it is line oriented. +.SS +.SP Line: +Set to the line containing the beginning of the previous paragraph. +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +Affected by the +.OP paragraph +option. +.SE +.KY | +.IP "[count] |" +Move to a specific +.i column +position on the current line. +.sp +The +.CO | +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented. +It is an error to use the +.CO | +command as a motion component and for the cursor not to move. +.SS +.SP Line: +Unchanged. +.SP Column: +Set to the character occupying the column position identified by +.LI count , +if the position exists in the line. +If the column length of the current line is less than +.LI count , +the cursor is moved to the last character in the line. +.SP Options: +None. +.SE +.KY } +.IP "[count] }" +Move forward +.LI count +paragraphs. +.sp +The +.CO } +command is an absolute movement. +The +.CO } +command may be used as the motion component of other +.CO vi +commands, in which case any text copied into a buffer is +character oriented, unless the starting character is at or +before any nonblank characters in its line, +in which case it is line oriented. +.SS +.SP Line: +Set to the line containing the beginning of the next paragraph. +.SP Column: +Set to the first nonblank character in the line. +.SP Options: +Affected by the +.OP paragraph +option. +.SE +.KY ~ +.IP "[count] ~" +Reverse the case of the next +.LI count +character(s). +This is the historic semantic for the +.CO ~ +command and it is only in effect if the +.OP tildeop +option is not set. +.sp +Lowercase alphabetic characters are changed to uppercase, +and uppercase characters are changed to lowercase. +No other characters are affected. +.sp +Historically, the +.CO ~ +command did not take an associated count, nor did it move past the +end of the current line. +As it had no associated motion it was difficult to change the case +of large blocks of text. +In +.CO nvi , +if the cursor is on the last character of a line, and there are +more lines in the file, the cursor moves to the next line. +.sp +It is not an error to specify a count larger than the number of +characters between the cursor and the end of the file. +.SS +.SP Line: +Set to the line of the character after +.LI count +characters, or, end of file. +.SP Column: +Set to the character after +.LI count +characters, or, end-of-file. +.SP Options: +Affected by the +.OP tildeop +option. +.SE +.KY ~ +.IP "[count] ~ motion" +Reverse the case of the characters in a text region specified by the +.LI count +and +.LI motion . +Only in effect if the +.OP tildeop +option is set. +.sp +Lowercase characters are changed to uppercase, +and uppercase characters are changed to lowercase. +No other characters are affected. +.SS +.SP Line: +Set to the line of the character after the last character in the region. +.SP Column: +Set to the character after the last character in the region. +.SP Options: +Affected by the +.OP tildeop +option. +.SE +.KY <interrupt> +.IP "<interrupt>" +Interrupt the current operation. +Many of the potentially long-running +.CO vi +commands may be interrupted using the terminal interrupt character. +These operations include searches, file reading and writing, filter +operations and map character expansion. +Interrupts are also enabled when running commands outside of +.CO vi . +.sp +If the +.LI <interrupt> +character is used to interrupt while entering an +.CO ex +command, the command is aborted, the cursor returns to its previous +position, and +.CO vi +remains in command mode. +.sp +Generally, if the +.LI <interrupt> +character is used to interrupt any +operation, any changes made before the interrupt are left in place. +.SS +.SP Line: +Dependent on the operation being interrupted. +.SP Column: +Dependent on the operation being interrupted. +.SP Options: +None. +.SH 1 "Vi Text Input Commands" +.pp +The following section describes the commands available in the text +input mode of the +.CO vi +editor. +.pp +Historically, +.CO vi +implementations only permitted the characters inserted on the current +line to be erased. +In addition, only the +.LI <control-D> +erase character and the +.QT 0<control-D> +and +.QT ^<control-D> +erase strings could erase autoindent characters. +This implementation permits erasure to continue past the beginning +of the current line, and back to where text input mode was entered. +In addition, autoindent characters may be erased using the standard +erase characters. +For the line and word erase characters, reaching the autoindent +characters forms a +.QQ soft +boundary, denoting the end of the current word or line erase. +Repeating the word or line erase key will erase the autoindent characters. +.pp +Historically, +.CO vi +always used +.LI <control-H> +and +.LI <control-W> +as character and word erase characters, respectively, regardless of +the current terminal settings. +This implementation accepts, in addition to these two characters, +the current terminal characters for those operations. +.KY <nul> +.IP "<nul>" +If the first character of the input is a +.LI <nul> , +the previous input is replayed, as if just entered. +.KY <control-D> +.IP "<control-D>" +If the previous character on the line was an autoindent character, +erase it. +Otherwise, if the user is entering the first character in the line, +.LI <control-D> +is ignored. +Otherwise, a literal +.LI <control-D> +character is entered. +.KY ^<control-D> +.IP "^<control-D>" +If the previous character on the line was an autoindent character, +erase all of the autoindent characters on the line. +In addition, the autoindent level is reset to 0. +.KY 0<control-D> +.IP "0<control-D>" +If the previous character on the line was an autoindent character, +erase all of the autoindent characters on the line. +.KY <control-T> +.IP "<control-T>" +Insert sufficient +.LI <tab> +and +.LI <space> +characters to move the cursor forward to a column immediately +after the next column which is an even multiple of the +.OP shiftwidth +option. +.sp +Historically, +.CO vi +did not permit the +.LI <control-T> +command to be used unless the cursor was at the first column of a new +line or it was preceded only by autoindent characters. +.CO Nvi +permits it to be used at any time during insert mode. +.KY <erase> +.IP <erase> +.KY <control-H> +.Ip <control-H> +Erase the last character. +.KY "<literal next>" +.IP "<literal next>" +Quote the next character. +The next character will not be mapped (see the +.CO map +command for more information) +or interpreted specially. +A carat +.PQ ^ +character will be displayed immediately as a placeholder, +but will be replaced by the next character. +.KY <escape> +.IP <escape> +Resolve all text input into the file, and return to command mode. +.KY "<line erase>" +.IP "<line erase>" +Erase the current line. +.KY "<control-W>" +.IP "<control-W>" +.KY "<word erase>" +.Ip "<word erase>" +Erase the last word. +The definition of word is dependent on the +.OP altwerase +and +.OP ttywerase +options. +.KY "<control-X>" +.IP "<control-X>[0-9A-Fa-f]*" +Insert a character with the specified hexadecimal value into the text. +.KY <interrupt> +.IP "<interrupt>" +Interrupt text input mode, returning to command mode. +If the +.LI <interrupt> +character is used to interrupt inserting text into the file, +it is as if the +.LI <escape> +character was used; all text input up to the interruption is +resolved into the file. diff --git a/usr.bin/vi/USD.doc/vi.ref/vi.ref b/usr.bin/vi/USD.doc/vi.ref/vi.ref new file mode 100644 index 0000000..5058cc7 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/vi.ref @@ -0,0 +1,1270 @@ +.\" Copyright (c) 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vi.ref 8.52 (Berkeley) 8/13/94 +.\" +.\" +.so ref.so +.tp +.(l C +.ps 12 +.ft B +Ex/Vi Reference Manual +.ft +.ps +.sp +.i "Keith Bostic" +.sp +Computer Science Division +Department of Electrical Engineering and Computer Science +University of California, Berkeley +Berkeley, California 94720 +.sp 1 +\*(td +.sp 3 +.i Abstract +.sp +.)l +.(q +.pp +This document is the reference guide for the 4.4BSD +implementations of +.EV nex nvi , +which are reimplementations of the historic Berkeley +.EV ex vi +editors. +.)q +.sp 3 +.(l C +.i Acknowledgements +.)l +.sp +.(q +.pp +Bruce Englar encouraged the early development of the historic +.EV ex vi +editor. +Peter Kessler helped bring sanity to version 2's command layout. +Bill Joy wrote versions 1 and 2.0 through 2.7, +and created the framework that users see in the present editor. +Mark Horton added macros and other features and made +.EV ex vi +work on a large number of terminals and Unix systems. +.pp +.CO Nvi +is originally derived from software contributed to the University of +California, Berkeley by Steve Kirkendall, the author of the +.CO vi +clone +.CO elvis . +.pp +IEEE Standard Portable Operating System Interface for Computer +Environments (POSIX) 1003.2 style Regular Expression support was +done by Henry Spencer. +.pp +The curses library was originally done by Ken Arnold. +Scrolling and reworking for +.CO nvi +was done by Elan Amir. +.pp +The Institute of Electrical and Electronics Engineers has +given us permission to reprint portions of their documentation. +Portions of this document are reprinted and reproduced from +IEEE Std 1003.2-1992, IEEE Standard Portable Operating +System Interface for Computer Environments (POSIX), +copyright 1992 by the Institute of Electrical and Electronics +Engineers, Inc. +.pp +The financial support of UUNET Communications Services is gratefully +acknowledged. +.)q +.sy echo -n >index +.oh 'Nvi/Nex Reference''USD:13-%' +.eh 'USD:13-%''Nvi/Nex Reference' +.bp 3 +.SH 1 Description +.pp +.CO Vi +is a screen oriented text editor. +.CO Ex +is a line-oriented text editor. +.CO Ex +and +.CO vi +are different interfaces to the same program, +and it is possible to switch back and forth during an edit session. +.CO View +is the equivalent of using the +.b \-R +(read-only) option of +.CO vi . +.pp +This reference manual is the one provided with the +.EV nex nvi +versions of the +.EV ex vi +text editors. +.EV Nex nvi +are intended as bug-for-bug compatible replacements for the original +Fourth Berkeley Software Distribution (4BSD) +.EV ex vi +programs. +This reference manual is accompanied by a traditional-style manual page. +That manual page describes the functionality found in +.EV ex vi +in far less detail than the description here. +In addition, it describes the system interface to +.EV ex vi , +e.g. command line options, session recovery, signals, +environmental variables, and similar things. +.pp +This reference is intended for users already familiar with +.EV ex vi . +Anyone else should almost certainly read a good tutorial on the +editor first. +If you are in an unfamiliar environment, +and you absolutely have to get work done immediately, +see the section entitled +.QB "Fast Startup" +in the manual page. +It is probably enough to get you started. +.pp +There are a few features in +.EV nex nvi +that are not found in historic versions of +.EV ex vi . +Some of the more interesting of those features are briefly described +in the section entitled +.QB "Additional Features" +near the end of this document. +For the rest of this document, +.EV nex nvi +is used only when it is necessary to distinguish it from the historic +implementations of +.EV ex vi . +.pp +Future versions of this software will be periodically made available +by anonymous ftp, and can be retrieved from +.LI ftp.cs.berkeley.edu , +in the directory +.LI ucb/4bsd . +.SH 1 "Startup Information" +.pp +.EV Ex vi +interprets one of two possible environmental variables and reads up to +three of five possible files during startup. +The variables and files are expected to contain +.CO ex +commands, not +.CO vi +commands. +In addition, they are interpreted +.i before +the file to be edited is read, and therefore many +.CO ex +commands may not be used. +Generally, any command that requires output to the screen or that +needs a file upon which to operate, will cause an error if included +in a startup file or environmental variable. +.pp +Because the +.CO ex +command set supported by +.EV nex nvi +is a superset of the command set supported by most historical +implementations of +.CO ex , +.EV nex nvi +can use the startup files created for the historical implementations, +but the converse may not be true. +.pp +If the +.b \-s +(the historic \- option) +is specified, or if standard input is redirected from a file, +all environmental variables and startup files are ignored. +.pp +Otherwise, startup files and environmental variables are handled +in the following order: +.np +The file +.LI /etc/vi.exrc +is read, +as long as it is owned by root or the effective user ID of the user. +.np +The environmental variable +.LI NEXINIT +(or the variable +.LI EXINIT , +if +.LI NEXINIT +is not set) is interpreted. +.np +If neither +.LI NEXINIT +or +.LI EXINIT +was set, and the +.LI HOME +environmental variable is set, the file +.LI $HOME/.nexrc +(or the file +.LI $HOME/.exrc , +if +.LI $HOME/.nexrc +does not exist) is read, +as long as the effective user ID of the user is root or is the same as +the owner of the file. +.np +If the +.OP exrc +option was turned on by one of the previous startup information +sources, the file +.LI \&.nexrc +(or the file +.LI \&.exrc , +if +.LI \&.nexrc +does not exist) is read, as long as the effective user ID of the user +is the same as the owner of the file. +.pp +No startup file is read if it is writable by anyone other than its owner. +.pp +It is not an error for any of the startup environmental variables or files +not to exist. +.pp +Once all environmental variables are interpreted, +and all startup files are read, +the first file to be edited is read in (or a temporary file is created). +Then, any commands specified using the +.b \-c +option are executed, in the context of that file. +.SH 1 Recovery +.pp +There is no recovery program for +.EV nex nvi , +nor does +.EV nex nvi +run setuid. +Recovery files are created readable and writable by the owner only. +Users may recover any file which they can read, +and the superuser may recover any edit session. +.pp +Edit sessions are backed by files in the directory named by the +.OP recdir +option (the directory +.LI /var/tmp/vi.recover +by default), and are named +.QC vi.XXXXXX , +where +.QC XXXXXX +is a number related to the process ID. +When a file is first modified, +a second recovery file containing an email message for the user is created, +and is named +.QC recover.XXXXXX , +where, again, +.QC XXXXXX +is associated with the process ID. +Both files are removed at the end of a normal edit session, +but will remain if the edit session is abnormally terminated +or the user runs the +.CO ex +.CO preserve +command. +.pp +The +.OP recdir +option may be set in either the user's or system's startup information, +changing the recovery directory. +(Note, however, that if a memory based file system is used as the backup +directory, each system reboot will delete all of the recovery files! +The same caution applies to directories such as +.LI /tmp +which are cleared of their contents by a system reboot, or +.LI /usr/tmp +which is periodically cleared of old files on many systems.) +.pp +The recovery directory should be owned by root, or at least by a pseudo-user. +In addition, if directory +.QQ sticky-bit +semantics are available, the directory should have the sticky-bit +set so that files may only be removed by their owners. +The recovery directory must be read, write, and executable by any user, +i.e. mode 1777. +.pp +If the recovery directory does not exist, +.EV ex vi +will attempt to create it. +This can result in the recovery directory being owned by a normal user, +which means that that user will be able to remove other user's recovery +and backup files. +This is annoying, but is not a security issue as the user cannot +otherwise access or modify the files. +.pp +The recovery file has all of the necessary information in it to enable the +user to recover the edit session. +In addition, it has all of the necessary email headers for +.XR sendmail 8 . +When the system is rebooted, all of the files in +.LI /var/tmp/vi.recover +named +.QC recover.XXXXXX +should be sent to their owners, by email, using the +.b \-t +option of +.CO sendmail +(or a similar mechanism in other mailers). +If +.EV ex vi +receives a hangup (SIGHUP) signal, or the user executes the +.CO ex +.CO preserve +command, +.EV ex vi +will automatically email the recovery information to the user. +.pp +If your system does not have the +.CO sendmail +utility (or a mailer program which supports its interface) +the source file +.LI nvi/common/recover.c +will have to be modified to use your local mail delivery programs. +Note, if +.EV nex nvi +is changed to use another mailer, +it is important to remember that the owner of the file given to +the mailer is the +.EV nex nvi +user, so nothing in the file should be trusted as it may have been +modified in an effort to compromise the system. +.pp +Finally, the owner execute bit is set on backup files when they are +created, and unset when they are first modified, e.g. backup files +that have no associated email recovery file will have this bit set. +(There is also a small window where empty files can be created and +not yet have this bit set. +This is due to the method in which the files are created.) +Such files should be deleted when the system reboots. +.pp +A simple way to do this cleanup is to insert the following Bourne +shell script into your +.LI /etc/rc.local +(or other startup) file. +The script should work with the historic Bourne shell, +a POSIX 1003.2 shell or the Korn shell. +(A copy of this script is included as +.LI nvi/install/recover.script +in the +.EV nex nvi +distribution.) +.sp +.(b +.ft C +.so ../../install/recover.script +.ft R +.)b +.sp +.pp +If you are not using the default value for the +.OP recdir +option, be sure to substitute the value you're using for the +.LI RECDIR +value in the recovery script. +.pp +If the path of your system's +.CO sendmail +program (or whatever mailer you're using) is not +.LI /usr/lib/sendmail , +be sure to substitute the correct pathname for the +.LI SENDMAIL +value in the recovery script. +Consult the manual page for details on recovering preserved or +aborted editing sessions. +.SH 1 "Sizing the Screen" +.pp +The size of the screen can be set in a number of ways. +.EV Ex vi +takes the following steps until values are obtained for both the +number of rows and number of columns in the screen. +.np +If the environmental variable +.LI LINES +exists, +it is used to specify the number of rows in the screen. +.np +If the environmental variable +.LI COLUMNS +exists, +it is used to specify the number of columns in the screen. +.np +The TIOCGWINSZ +.XR ioctl 2 +is attempted on the standard error file descriptor. +.np +The termcap entry (or terminfo entry on System V machines) +is checked for the +.QQ li +entry (rows) and the +.QQ co +entry (columns). +.np +The number of rows is set to 24, and the number of columns is set to 80. +.pp +If a window change size signal (SIGWINCH) is received, +the new window size is retrieved using the TIOCGWINSZ +.XR ioctl 2 +call, and all other information is ignored. +.SH 1 "Character Display" +.pp +In both +.CO ex +and +.CO vi +printable characters as defined by +.XR isprint 3 +are displayed using the local character set. +.pp +Non-printable characters, for which +.XR iscntrl 3 +returns true, and which are less than octal \e076, +are displayed as the string +.QT ^<character> , +where +.LI <character> +is the character that is the original character's value offset from the +.QT @ +character. +For example, the octal character \e001 is displayed as +.QT ^A . +If +.XR iscntrl 3 +returns true for the octal character \e177, +it is displayed as the string +.QT ^? . +All other characters are displayed as either hexadecimal values, +in the form +.QT "0x<high-halfbyte> ... 0x<low-halfbyte>" , +or as octal values, in the form +.QT "\e<high-one-or-two-bits> ... \e<low-three-bits>" . +The display of unknown characters is based on the value of the +.OP octal +option. +.pp +In +.CO vi +command mode, the cursor is always positioned on the last column of +characters which take up more than one column on the screen. +In +.CO vi +text input mode, the cursor is positioned on the first column of +characters which take up more than one column on the screen. +.SH 1 "Multiple Screens" +.pp +.CO Nvi +supports multiple screens by dividing the window into regions. +It also supports stacks of screens by permitting the user to change +the set of screens that are currently displayed. +.pp +The command +.CO split +divides the current screen into two regions of approximately equal +size. +If a list of files are specified as arguments to the +.CO split +command, the list of files to be edited is initialized as if the +.CO next +command had been used. +If no files are specified, the new screen will begin by editing the same +file as the previous screen. +.pp +When more than one screen is editing a file, changes in any screen are +reflected in all other screens editing the same file. +Exiting any screen without saving any changes (or explicitly discarding +them) is permitted until the last screen editing the file is exited. +.pp +The +.CO resize +command permits resizing of individual screens. +Screens may be grown, shrunk or set to an absolute number of rows. +.pp +The +.CO ^W +command is used to switch between screens. +Each +.CO ^W +moves to the next lower screen in the window, or to the first screen +in the window if there are no lower screens. +.pp +The +.CO bg +command +.QQ backgrounds +the current screen. +The screen disappears from the window, +and the rows it occupied are taken over by a neighboring screen. +It is an error to attempt to background the only screen in the window. +.pp +The +.CO "display screens" +command displays the names of the files associated with the current +backgrounded screens in the window. +.pp +The +.CO "fg [file]" +command +.QQ foregrounds +the first screen in the list of backgrounded screens that is +associated with its argument. +If no file argument is specified, the first screen on the list is +foregrounded. +Foregrounding consists of backgrounding the current screen, +and replacing its space in the window with the foregrounded screen. +.pp +If the last screen in the window is exited, and there are backgrounded +screens, the first screen on the list of backgrounded screens takes over +the window. +.SH 1 "Regular Expressions and Replacement Strings" +.pp +Regular expressions are used in line addresses, +as the first part of the +.CO ex +.CO substitute , +.CO global , +and +.CO vglobal +commands, and in search patterns. +.pp +The regular expressions supported by +.EV ex vi +are, by default, the Basic Regular Expressions (BRE's) described in the +IEEE POSIX Standard 1003.2. +The +.OP extended +option causes all regular expressions to be interpreted as the Extended +Regular Expressions (ERE's) described by the same standard. +(See +.XR re_format 7 +for more information.) +Generally speaking, BRE's are the Regular Expressions found in +.XR ed 1 +and +.XR grep 1 , +and ERE's are the Regular Expressions found in +.XR egrep 1 . +.pp +The following is not intended to provide a description of Regular +Expressions. +The information here only describes strings and characters which +have special meanings in the +.EV ex vi +version of RE's, +or options which change the meanings of characters that normally +have special meanings in RE's. +.np +An empty RE (e.g. +.QT // +or +.QT ?? +is equivalent to the last RE used. +.np +The construct +.QT \e< +matches the beginning of a word. +.np +The construct +.QT \e> +matches the end of a word. +.np +The character +.QT ~ +matches the replacement part of the last +.CO substitute +command. +.pp +When the +.OP magic +option is +.i not +set, the only characters with special meanings are a +.QT ^ +character at the beginning of an RE, a +.QT $ +character at the end of an RE, and the escaping character +.QT \e . +The characters +.QT \&. , +.QT * , +.QT [ +and +.QT ~ +are treated as ordinary characters unless preceded by a +.QT \e ; +when preceded by a +.QT \e +they regain their special meaning. +.pp +Replacement strings are the second part of a +.CO substitute +command. +.pp +The character +.QT & +(or +.QT \e& +if the +.OP magic +option is +.i not +set) in the replacement string stands for the text matched by the RE +that is being replaced. +The character +.QT ~ +(or +.QT \e~ +if the +.OP magic +option is +.i not +set) stands for the replacement part of the previous +.CO substitute +command. +It is only valid after a +.CO substitute +command has been performed. +.pp +The string +.QT \e# , +where +.QT # +is an integer value from 1 to 9, stands for the text matched by +the portion of the RE enclosed in the +.QT # 'th +set of escaped parentheses, e.g. +.QT \e( +and +.QT \e) . +For example, +.QT "s/abc\e(.*\e)def/\e1/" +deletes the strings +.QT abc +and +.QT def +from the matched pattern. +.pp +The strings +.QT \el , +.QT \eu , +.QT \eL +and +.QT \eU +can be used to modify the case of elements in the replacement string. +The string +.QT \el +causes the next character to be converted to lowercase; +the string +.QT \eu +behaves similarly, but converts to uppercase +(e.g. +.LI s/abc/\eU&/ +replaces the string +.LI abc +with +.LI ABC ). +The strings +.QT \eL +causes characters up to the end of the string or the next occurrence +of the strings +.QT \ee +or +.QT \eE +to be converted to lowercase; +the string +.QT \eU +behaves similarly, but converts to uppercase. +.pp +If the entire replacement pattern is +.QT % , +then the last replacement pattern is used again. +.pp +In +.CO vi , +inserting a +.LI <control-M> +into the replacement string will cause +the matched line to be split into two lines at that point. +(The +.LI <control-M> +will be discarded.) +.SH 1 "General Editor Description" +.pp +When +.CO ex +or +.CO vi +are executed, +the text of a file is read (or a temporary file is created), +and then all editing changes happen within the context of the +copy of the file. +.i "No changes affect the actual file until the file is written out" , +either using a write command or another command which is affected by the +.OP autowrite +option. +.pp +All files are locked (using the +.XR flock 2 +or +.XR fcntl 2 +interfaces) during the edit session, +to avoid inadvertently making modifications to multiple copies of the file. +If a lock cannot be obtained for a file because it is locked by another +process, the edit session is read-only (as if the +.OP readonly +option or the +.b \-R +flag had been specified). +If a lock cannot be obtained for other reasons, the edit session will +continue, but the file status information +(see the +.CO <control-G> +command) will reflect this fact. +.pp +Both +.CO ex +and +.CO vi +are modeful editors, i.e. they have two modes, +.QQ command +mode and +.QQ "text input" +mode. +The former is intended to permit you to enter commands which modifies +already existing text. +The latter is intended to permit you to enter new text. +When +.CO ex +first starts running, it is in command mode, and usually displays a prompt +(see the +.OP prompt +option for more information). +The prompt is a single colon +.PQ : +character. +There are three commands that switch +.CO ex +into text input mode: +.CO append , +.CO change +and +.CO insert . +Once in input mode, entering a line containing only a single period +.PQ \&. +terminates text input mode and returns to command mode, +where the prompt is redisplayed. +.pp +When +.CO vi +first starts running, it is in command mode as well. +There are eleven commands that switch +.CO vi +into text input mode: +.CO A , +.CO a , +.CO C , +.CO c , +.CO I , +.CO i , +.CO O , +.CO o , +.CO R , +.CO S +and +.CO s . +Once in input mode, entering an +.LI <escape> +character terminates text input mode and returns to command mode. +.pp +The following words have special meanings in both the +.CO ex +and +.CO vi +command descriptions: +.KY <interrupt> +.IP <interrupt> +The interrupt character is used to interrupt the current operation. +Normally +.LI <control-C> , +whatever character is set for the current terminal is used. +.KY "<literal next>" +.IP "<literal next>" +The literal next character is used to escape the subsequent character +from any special meaning. +This character is always +.LI <control-V> . +If the terminal is not set up to do XON/XOFF flow control, +then +.LI <control-Q> +is used to mean literal next as well. +.KY "current pathname" +.IP "current pathname" +The pathname of the file currently being edited by vi. +When the percent character +.PQ % +appears in a file name entered as part of an +.CO ex +command argument, it is replaced by the current pathname. +(The +.QT % +character can be escaped by preceding it with a backslash.) +.KY "alternate pathname" +.IP "alternate pathname" +The name of the last file name mentioned in an +.CO ex +command, or, +the previous current pathname if the last file mentioned +becomes the current file. +When the hash mark character +.PQ # +appears in a file name entered as part of an +.CO ex +command argument, it is replaced by the alternate pathname. +(The +.QT # +character can be escaped by preceding it with a backslash.) +.KY buffer +.IP buffer +One of a number of named areas for saving copies of text. +Commands that change or delete text can save the changed or deleted +text into a specific buffer, for later use, if the command allows +it (i.e. the +.CO ex +.CO change +command cannot save the changed text in a named buffer). +Buffers are named with a single character, preceded by a double quote, +e.g. +.LI """<character>" . +Historic implementations of +.EV ex vi +limited +.LI <character> +to the alphanumeric characters; +.EV nex nvi +permits the use of any character. +.sp +Buffers named by uppercase characters are the same as buffers +named by lowercase characters, e.g. the buffer named by the +English character +.QT A +is the same as the buffer named by the character +.QT a , +with the exception that, if the buffer contents are being changed (as +with a text deletion or +.CO vi +.CO change +command), the text is +.i appended +to the buffer, instead of replacing the current contents. +.sp +The buffers named by the numeric characters (in English, +.QT 1 +through +.QT 9 ), +are special, in that if at least one line is changed or deleted in +the file, +(or a command changes or deletes a region that crosses a line boundary) +a copy of the text is placed into the numeric buffer +.QT 1 , +regardless of the user specifying another buffer in which to save it. +Before this copy is done, the previous contents of buffer +.QT 1 +are moved into buffer +.QT 2 , +.QT 2 +into buffer +.QT 3 , +and so on. +The contents of buffer +.QT 9 +are discarded. +In +.CO vi , +text may be explicitly stored into the numeric buffers. +In this case, the buffer rotation described above occurs before the +replacement of the buffer's contents. +(Text cannot be explicitly stored into the numeric buffers in +.CO ex +because of ambiguities that this would cause in the +.CO ex +command syntax.) +.sp +When a +.CO vi +command synopsis shows both a +.LI [buffer] +and a +.LI [count] , +they may be presented in any order. +.sp +Finally, all buffers are either +.QQ line +or +.QQ character +oriented. +All +.CO ex +commands which store text into buffers are line oriented. +Some +.CO vi +commands which store text into buffers are line oriented, +and some are character oriented; the description for each applicable +.CO vi +command notes whether text copied into buffers using the command +is line or character oriented. +In addition, the +.CO vi +command +.CO "display buffers" +displays the current orientation for each buffer. +Generally, the only importance attached to this orientation is that +if the buffer is subsequently inserted into the text, line oriented +buffers create new lines for each of the lines they contain, and +character oriented buffers create new lines for any lines +.i other +than the first and last lines they contain. +The first and last lines are inserted into the text at the current +cursor position, becoming part of the current line. +If there is more than one line in the buffer, however, the current +line itself will be split. +.KY "unnamed buffer" +.IP "unnamed buffer" +The unnamed buffer is a text storage area which is used by commands +that take a buffer as an argument, when no buffer is specified by +the user. +There is no way to explicitly reference this buffer. +.oh 'Nvi/Nex Reference (Vi Commands)''USD:13-%' +.eh 'USD:13-%''Nvi/Nex Reference (Vi Commands)' +.so vi.cmd.roff +.oh 'Nvi/Nex Reference''USD:13-%' +.eh 'USD:13-%''Nvi/Nex Reference' +.SH 1 "Ex Addressing" +.pp +Addressing in +.CO ex +(and when +.CO ex +commands are executed from +.CO vi ) +relates to the current line. +In general, the current line is the last line affected by a command. +The exact effect on the current line is discussed under the description +of each command. +When the file contains no lines, the current line is zero. +.pp +Addresses are constructed by one or more of the following methods: +.np +The address +.QT \&. +refers to the current line. +.np +The address +.QT $ +refers to the last line of the file. +.np +The address +.QT N , +where +.LI N +is a positive number, refers to the N-th line of the file. +.np +The address +.QT '<character> +or +.QT `<character> +refers to the line marked with the name +.LI <character> . +(See the +.CO k +or +.CO m +commands for more information on how to mark lines.) +.np +A regular expression (RE) enclosed by slashes +.PQ / +is an address, +and it refers to the first line found by searching forward from the line +.i after +the current line toward the end of the file, and stopping at the +first line containing a string matching the RE. +(The trailing slash can be omitted at the end of the command line.) +.sp +If no RE is specified, i.e. the pattern is +.QT // , +the last RE used in any command is used in the search. +.sp +If the +.OP extended +option is set, the RE is handled as an extended RE, not a basic RE. +If the +.OP wrapscan +option is set, the search wraps around to the beginning of the file +and continues up to and including the current line, so that the entire +file is searched. +.sp +The form +.QT \e/ +is accepted for historic reasons, +and is identical to +.QT // . +.np +An RE enclosed in question marks +.PQ ? +addresses the first line found by searching backward from the line +.i preceding +the current line, toward the beginning of the file and stopping at the +first line containing a string matching the RE. +(The trailing question mark can be omitted at the end of a command line.) +.sp +If no RE is specified, i.e. the pattern is +.QT ?? , +the last RE used in any command is used in the search. +.sp +If the +.OP extended +option is set, the RE is handled as an extended RE, not a basic RE. +If the +.OP wrapscan +option is set, the search wraps around from the beginning of the file to +the end of the file and continues up to and including the current line, +so that the entire file is searched. +.sp +The form +.QT \e? +is accepted for historic reasons, and is identical to +.QT ?? . +.np +An address followed by a plus sign +.PQ + +or a minus sign +.PQ - +followed by a number is an offset address and refers to the address +plus (or minus) the indicated number of lines. +If the address is omitted, the addition or subtraction is done with +respect to the current line. +.np +An address of +.QT + +or +.QT \- +followed by a number is an offset from the current line. +For example, +.QT \-5 +is the same as +.QT \&.\-5 . +.np +An address ending with +.QT + +or +.QT - +has 1 added to or subtracted from the address, respectively. +As a consequence of this rule and of the previous rule, the address +.QT \- +refers to the line preceding the current line. +Moreover, trailing +.QT + +and +.QT \- +characters have a cumulative effect. +For example, +.QT ++\-++ +refers to the current line plus 3. +.np +A percent sign +.PQ % +is equivalent to the address range +.QT 1,$ . +.pp +.CO Ex +commands require zero, one, or two addresses. +It is an error to specify an address to a command which requires zero +addresses. +.pp +If the user provides more than the expected number of addresses to any +.CO ex +command, the first addresses specified are discarded. +For example, +.QT 1,2,3,5 print +prints lines 3 through 5, because the +.CO print +command only takes two addresses. +.pp +The addresses in a range are separated from each other by a comma +.PQ , +or a semicolon +.PQ ; . +In the latter case, the current line +.PQ \&. +is set to the first address, and only then is the second address calculated. +This feature can be used to determine the starting line for forward and +backward searches (see rules (5) and (6) above). +The second address of any two-address sequence corresponds to a line that +follows, in the file, the line corresponding to the first address. +The first address must be less than or equal to the second address. +The first address must be greater than or equal to the first line of the +file, and the last address must be less than or equal to the last line +of the file. +.oh 'Nvi/Nex Reference (Ex Commands)''USD:13-%' +.eh 'USD:13-%''Nvi/Nex Reference (Ex Commands)' +.so ex.cmd.roff +.oh 'Nvi/Nex Reference''USD:13-%' +.eh 'USD:13-%''Nvi/Nex Reference' +.so set.opt.roff +.SH 1 "Additional Features in Nex/Nvi" +.pp +There are a few features in +.EV nex nvi +that are not found in historic versions of +.EV ex vi . +Some of the more interesting of those features are as follows: +.IP "8-bit clean data, large lines, files" +.EV Nex nvi +will edit any format file. +Line lengths are limited by available memory, +and file sizes are limited by available disk space. +The +.CO vi +text input mode command +.CO <control-X> +can insert any possible character value into the text. +.IP "Split screens" +The +.CO split +command divides the screen into multiple editing regions. +The +.CO <control-W> +command rotates between the foreground screens. +The +.CO resize +command can be used to grow or shrink a particular screen. +.IP "Background and foreground screens" +The +.CO bg +command backgrounds the current screen, and the +.CO fg +command foregrounds backgrounded screens. +The +.CO display +command can be used to list the background screens. +.\".IP "Shell screens" +.\"The +.\".CO ":sc[ript] [file ...]" +.\"command runs a shell in the screen. +.\"Editing is unchanged, with the exception that a \fC<carriage-return>\fP +.\"enters the current line (stripped of any prompt) as input to the +.\"shell. +.IP "Tag stacks" +Tags are now maintained in a stack. +The +.CO <control-T> +command returns to the previous tag location. +The +.CO tagpop +command returns to the most recent tag location by default, or, +optionally to a specific tag number in the tag stack, +or the most recent tag from a specified file. +The +.CO display +command can be used to list the tags stack. +The +.CO tagtop +command returns to the top of the tag stack. +.IP "New displays" +The +.CO display +command can be used to display the current buffers, the backgrounded +screens, and the tags stack. +.IP "Infinite undo" +Changes made during an edit session may be rolled backward and forward. +A +.CO \&. +command immediately after a +.CO u +command continues either forward or backward depending on whether the +.CO u +command was an undo or a redo. +.IP "Usage information" +The +.CO exusage +and +.CO viusage +commands provide usage information for all of the +.CO ex +and +.CO vi +commands by default, or, optionally, for a specific command or key. +.IP "Extended Regular Expressions" +The +.CO extended +option causes Regular Expressions to be interpreted as as Extended +Regular Expressions, (i.e. \fIegrep\fP(1) style Regular Expressions). +.IP "Word search" +The +.CO <control-A> +command searches for the word referenced by the cursor. +.IP "Number increment" +The +.CO \&# +command increments or decrements the number referenced by the cursor. +.IP "Previous file" +The +.CO previous +command edits the previous file from the argument list. +.IP "Left-right scrolling" +The +.CO leftright +option causes +.CO nvi +to do left-right screen scrolling, instead of the traditional +.CO vi +line wrapping. +.bp +.SH 1 Index +.lp +.2c +0.5i 3 +.ta \n($luR +.nf +.so index.so +.fi +.bp 2 +.1c +.ce 1 +\fB\s+2Table of Contents\s0\fP +.sp +.xp diff --git a/usr.bin/vi/USD.doc/vi.ref/vi.ref.txt b/usr.bin/vi/USD.doc/vi.ref/vi.ref.txt new file mode 100644 index 0000000..88a98c7 --- /dev/null +++ b/usr.bin/vi/USD.doc/vi.ref/vi.ref.txt @@ -0,0 +1,5544 @@ + + + + + + + + + EExx//VVii RReeffeerreennccee MMaannuuaall + + _K_e_i_t_h _B_o_s_t_i_c + + Computer Science Division + Department of Electrical Engineering and Computer Science + University of California, Berkeley + Berkeley, California 94720 + + August 15, 1994 + + + + _A_b_s_t_r_a_c_t + + + + + This document is the reference guide for the 4.4BSD +implementations of nneexx/nnvvii, which are reimplementations +of the historic Berkeley eexx/vvii editors. + + + + + + _A_c_k_n_o_w_l_e_d_g_e_m_e_n_t_s + + + + + Bruce Englar encouraged the early development of +the historic eexx/vvii editor. Peter Kessler helped bring +sanity to version 2's command layout. Bill Joy wrote +versions 1 and 2.0 through 2.7, and created the frame- +work that users see in the present editor. Mark Horton +added macros and other features and made eexx/vvii work on a +large number of terminals and Unix systems. + + NNvvii is originally derived from software contributed +to the University of California, Berkeley by Steve Kirk- +endall, the author of the vvii clone eellvviiss. + + IEEE Standard Portable Operating System Interface +for Computer Environments (POSIX) 1003.2 style Regular +Expression support was done by Henry Spencer. + + The curses library was originally done by Ken +Arnold. Scrolling and reworking for nnvvii was done by +Elan Amir. + + + + + + + + + + + + + + + + The Institute of Electrical and Electronics Engi- +neers has given us permission to reprint portions of +their documentation. Portions of this document are +reprinted and reproduced from IEEE Std 1003.2-1992, IEEE +Standard Portable Operating System Interface for Comput- +er Environments (POSIX), copyright 1992 by the Institute +of Electrical and Electronics Engineers, Inc. + + The financial support of UUNET Communications Ser- +vices is gratefully acknowledged. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--33 + + +11.. DDeessccrriippttiioonn + + VVii is a screen oriented text editor. EExx is a line- +oriented text editor. EExx and vvii are different interfaces to +the same program, and it is possible to switch back and +forth during an edit session. VViieeww is the equivalent of +using the --RR (read-only) option of vvii. + + This reference manual is the one provided with the +nneexx/nnvvii versions of the eexx/vvii text editors. NNeexx/nnvvii are +intended as bug-for-bug compatible replacements for the +original Fourth Berkeley Software Distribution (4BSD) eexx/vvii +programs. This reference manual is accompanied by a tradi- +tional-style manual page. That manual page describes the +functionality found in eexx/vvii in far less detail than the +description here. In addition, it describes the system +interface to eexx/vvii, e.g. command line options, session +recovery, signals, environmental variables, and similar +things. + + This reference is intended for users already familiar +with eexx/vvii. Anyone else should almost certainly read a good +tutorial on the editor first. If you are in an unfamiliar +environment, and you absolutely have to get work done imme- +diately, see the section entitled "FFaasstt SSttaarrttuupp" in the man- +ual page. It is probably enough to get you started. + + There are a few features in nneexx/nnvvii that are not found +in historic versions of eexx/vvii. Some of the more interesting +of those features are briefly described in the section enti- +tled "AAddddiittiioonnaall FFeeaattuurreess" near the end of this document. +For the rest of this document, nneexx/nnvvii is used only when it +is necessary to distinguish it from the historic implementa- +tions of eexx/vvii. + + Future versions of this software will be periodically +made available by anonymous ftp, and can be retrieved from +ffttpp..ccss..bbeerrkkeelleeyy..eedduu, in the directory uuccbb//44bbssdd. + +22.. SSttaarrttuupp IInnffoorrmmaattiioonn + + EExx/vvii interprets one of two possible environmental +variables and reads up to three of five possible files dur- +ing startup. The variables and files are expected to con- +tain eexx commands, not vvii commands. In addition, they are +interpreted _b_e_f_o_r_e the file to be edited is read, and there- +fore many eexx commands may not be used. Generally, any com- +mand that requires output to the screen or that needs a file +upon which to operate, will cause an error if included in a +startup file or environmental variable. + + Because the eexx command set supported by nneexx/nnvvii is a +superset of the command set supported by most historical + + + + + + + + + + +UUSSDD::1133--44 NNvvii//NNeexx RReeffeerreennccee + + +implementations of eexx, nneexx/nnvvii can use the startup files +created for the historical implementations, but the converse +may not be true. + + If the --ss (the historic - option) is specified, or if +standard input is redirected from a file, all environmental +variables and startup files are ignored. + + Otherwise, startup files and environmental variables +are handled in the following order: + + (1) The file //eettcc//vvii..eexxrrcc is read, as long as it is owned + by root or the effective user ID of the user. + + (2) The environmental variable NNEEXXIINNIITT (or the variable + EEXXIINNIITT, if NNEEXXIINNIITT is not set) is interpreted. + + (3) If neither NNEEXXIINNIITT or EEXXIINNIITT was set, and the HHOOMMEE + environmental variable is set, the file $$HHOOMMEE//..nneexxrrcc + (or the file $$HHOOMMEE//..eexxrrcc, if $$HHOOMMEE//..nneexxrrcc does not + exist) is read, as long as the effective user ID of + the user is root or is the same as the owner of the + file. + + (4) If the eexxrrcc option was turned on by one of the previ- + ous startup information sources, the file ..nneexxrrcc (or + the file ..eexxrrcc, if ..nneexxrrcc does not exist) is read, as + long as the effective user ID of the user is the same + as the owner of the file. + + No startup file is read if it is writable by anyone +other than its owner. + + It is not an error for any of the startup environmental +variables or files not to exist. + + Once all environmental variables are interpreted, and +all startup files are read, the first file to be edited is +read in (or a temporary file is created). Then, any com- +mands specified using the --cc option are executed, in the +context of that file. + +33.. RReeccoovveerryy + + There is no recovery program for nneexx/nnvvii, nor does +nneexx/nnvvii run setuid. Recovery files are created readable and +writable by the owner only. Users may recover any file +which they can read, and the superuser may recover any edit +session. + + Edit sessions are backed by files in the directory +named by the rreeccddiirr option (the directory +//vvaarr//ttmmpp//vvii..rreeccoovveerr by default), and are named "vvii..XXXXXXXXXXXX", + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--55 + + +where "XXXXXXXXXXXX" is a number related to the process ID. When +a file is first modified, a second recovery file containing +an email message for the user is created, and is named +"rreeccoovveerr..XXXXXXXXXXXX", where, again, "XXXXXXXXXXXX" is associated with +the process ID. Both files are removed at the end of a nor- +mal edit session, but will remain if the edit session is +abnormally terminated or the user runs the eexx pprreesseerrvvee com- +mand. + + The rreeccddiirr option may be set in either the user's or +system's startup information, changing the recovery direc- +tory. (Note, however, that if a memory based file system is +used as the backup directory, each system reboot will delete +all of the recovery files! The same caution applies to +directories such as //ttmmpp which are cleared of their contents +by a system reboot, or //uussrr//ttmmpp which is periodically +cleared of old files on many systems.) + + The recovery directory should be owned by root, or at +least by a pseudo-user. In addition, if directory "sticky- +bit" semantics are available, the directory should have the +sticky-bit set so that files may only be removed by their +owners. The recovery directory must be read, write, and +executable by any user, i.e. mode 1777. + + If the recovery directory does not exist, eexx/vvii will +attempt to create it. This can result in the recovery +directory being owned by a normal user, which means that +that user will be able to remove other user's recovery and +backup files. This is annoying, but is not a security issue +as the user cannot otherwise access or modify the files. + + The recovery file has all of the necessary information +in it to enable the user to recover the edit session. In +addition, it has all of the necessary email headers for +_s_e_n_d_m_a_i_l(8). When the system is rebooted, all of the files +in //vvaarr//ttmmpp//vvii..rreeccoovveerr named "rreeccoovveerr..XXXXXXXXXXXX" should be sent +to their owners, by email, using the --tt option of sseennddmmaaiill +(or a similar mechanism in other mailers). If eexx/vvii +receives a hangup (SIGHUP) signal, or the user executes the +eexx pprreesseerrvvee command, eexx/vvii will automatically email the +recovery information to the user. + + If your system does not have the sseennddmmaaiill utility (or a +mailer program which supports its interface) the source file +nnvvii//ccoommmmoonn//rreeccoovveerr..cc will have to be modified to use your +local mail delivery programs. Note, if nneexx/nnvvii is changed +to use another mailer, it is important to remember that the +owner of the file given to the mailer is the nneexx/nnvvii user, +so nothing in the file should be trusted as it may have been +modified in an effort to compromise the system. + + + + + + + + + + + + +UUSSDD::1133--66 NNvvii//NNeexx RReeffeerreennccee + + + Finally, the owner execute bit is set on backup files +when they are created, and unset when they are first modi- +fied, e.g. backup files that have no associated email recov- +ery file will have this bit set. (There is also a small +window where empty files can be created and not yet have +this bit set. This is due to the method in which the files +are created.) Such files should be deleted when the system +reboots. + + A simple way to do this cleanup is to insert the fol- +lowing Bourne shell script into your //eettcc//rrcc..llooccaall (or other +startup) file. The script should work with the historic +Bourne shell, a POSIX 1003.2 shell or the Korn shell. (A +copy of this script is included as +nnvvii//iinnssttaallll//rreeccoovveerr..ssccrriipptt in the nneexx/nnvvii distribution.) + + + ## @@((##))rreeccoovveerr..ssccrriipptt 88..44 ((BBeerrkkeelleeyy)) 88//1133//9944 + ## + ## RReeccoovveerr nnvvii eeddiittoorr ffiilleess:: + RREECCDDIIRR==//vvaarr//ttmmpp//vvii..rreeccoovveerr + SSEENNDDMMAAIILL==//uussrr//lliibb//sseennddmmaaiill + eecchhoo ''RReeccoovveerriinngg nnvvii eeddiittoorr sseessssiioonnss..'' + + ## UUnnmmooddiiffiieedd nnvvii eeddiittoorr bbaacckkuupp ffiilleess aarree eeiitthheerr zzeerroo lleennggtthh oorr + ## hhaavvee tthhee eexxeeccuuttee bbiitt sseett.. DDeelleettee bbootthh ccaasseess.. + vviibbaacckkuupp==``eecchhoo $$RREECCDDIIRR//vvii..**`` + iiff [[ ""$$vviibbaacckkuupp"" !!== ""$$RREECCDDIIRR//vvii..**"" ]];; tthheenn + ffoorr ii iinn $$vviibbaacckkuupp;; ddoo + iiff tteesstt --xx $$ii --oo !! --ss $$ii;; tthheenn + rrmm $$ii + ffii + ddoonnee + ffii + + ## IItt iiss ppoossssiibbllee ttoo ggeett iinnccoommpplleettee rreeccoovveerryy ffiilleess,, iiff tthhee eeddiittoorr + ## ccrraasshheess aatt tthhee rriigghhtt ttiimmee.. DDeelleettee aannyy rreeccoovveerryy ffiilleess wwiitthhoouutt + ## ccoorrrreessppoonnddiinngg bbaacckkuupp ffiilleess,, ootthheerrwwiissee sseenndd mmaaiill ttoo tthhee uusseerr.. + vviirreeccoovveerryy==``eecchhoo $$RREECCDDIIRR//rreeccoovveerr..**`` + iiff [[ ""$$vviirreeccoovveerryy"" !!== ""$$RREECCDDIIRR//rreeccoovveerr..**"" ]];; tthheenn + ffoorr ii iinn $$vviirreeccoovveerryy;; ddoo + rreeccffiillee==``aawwkk ''//^^XX--vvii--rreeccoovveerr--ppaatthh:://{{pprriinntt $$22}}'' << $$ii`` + iiff tteesstt !! --nn $$rreeccffiillee --aa --ss $$rreeccffiillee;; tthheenn + $$SSEENNDDMMAAIILL --tt << $$ii + eellssee + rrmm $$ii + ffii + ddoonnee + ffii + + + + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--77 + + + If you are not using the default value for the rreeccddiirr +option, be sure to substitute the value you're using for the +RREECCDDIIRR value in the recovery script. + + If the path of your system's sseennddmmaaiill program (or what- +ever mailer you're using) is not //uussrr//lliibb//sseennddmmaaiill, be sure +to substitute the correct pathname for the SSEENNDDMMAAIILL value in +the recovery script. Consult the manual page for details on +recovering preserved or aborted editing sessions. + +44.. SSiizziinngg tthhee SSccrreeeenn + + The size of the screen can be set in a number of ways. +EExx/vvii takes the following steps until values are obtained +for both the number of rows and number of columns in the +screen. + + (1) If the environmental variable LLIINNEESS exists, it is + used to specify the number of rows in the screen. + + (2) If the environmental variable CCOOLLUUMMNNSS exists, it is + used to specify the number of columns in the screen. + + (3) The TIOCGWINSZ _i_o_c_t_l(2) is attempted on the standard + error file descriptor. + + (4) The termcap entry (or terminfo entry on System V + machines) is checked for the "li" entry (rows) and + the "co" entry (columns). + + (5) The number of rows is set to 24, and the number of + columns is set to 80. + + If a window change size signal (SIGWINCH) is received, +the new window size is retrieved using the TIOCGWINSZ +_i_o_c_t_l(2) call, and all other information is ignored. + +55.. CChhaarraacctteerr DDiissppllaayy + + In both eexx and vvii printable characters as defined by +_i_s_p_r_i_n_t(3) are displayed using the local character set. + + Non-printable characters, for which _i_s_c_n_t_r_l(3) returns +true, and which are less than octal \076, are displayed as +the string "^^<<cchhaarraacctteerr>>", where <<cchhaarraacctteerr>> is the charac- +ter that is the original character's value offset from the +"@@" character. For example, the octal character \001 is +displayed as "^^AA". If _i_s_c_n_t_r_l(3) returns true for the octal +character \177, it is displayed as the string "^^??". All +other characters are displayed as either hexadecimal values, +in the form "00xx<<hhiigghh--hhaallffbbyyttee>> ...... 00xx<<llooww--hhaallffbbyyttee>>", or as +octal values, in the form "\\<<hhiigghh--oonnee--oorr--ttwwoo--bbiittss>> ...... +\\<<llooww--tthhrreeee--bbiittss>>". The display of unknown characters is + + + + + + + + + + +UUSSDD::1133--88 NNvvii//NNeexx RReeffeerreennccee + + +based on the value of the ooccttaall option. + + In vvii command mode, the cursor is always positioned on +the last column of characters which take up more than one +column on the screen. In vvii text input mode, the cursor is +positioned on the first column of characters which take up +more than one column on the screen. + +66.. MMuullttiippllee SSccrreeeennss + + NNvvii supports multiple screens by dividing the window +into regions. It also supports stacks of screens by permit- +ting the user to change the set of screens that are cur- +rently displayed. + + The command sspplliitt divides the current screen into two +regions of approximately equal size. If a list of files are +specified as arguments to the sspplliitt command, the list of +files to be edited is initialized as if the nneexxtt command had +been used. If no files are specified, the new screen will +begin by editing the same file as the previous screen. + + When more than one screen is editing a file, changes in +any screen are reflected in all other screens editing the +same file. Exiting any screen without saving any changes +(or explicitly discarding them) is permitted until the last +screen editing the file is exited. + + The rreessiizzee command permits resizing of individual +screens. Screens may be grown, shrunk or set to an absolute +number of rows. + + The ^^WW command is used to switch between screens. Each +^^WW moves to the next lower screen in the window, or to the +first screen in the window if there are no lower screens. + + The bbgg command "backgrounds" the current screen. The +screen disappears from the window, and the rows it occupied +are taken over by a neighboring screen. It is an error to +attempt to background the only screen in the window. + + The ddiissppllaayy ssccrreeeennss command displays the names of the +files associated with the current backgrounded screens in +the window. + + The ffgg [[ffiillee]] command "foregrounds" the first screen in +the list of backgrounded screens that is associated with its +argument. If no file argument is specified, the first +screen on the list is foregrounded. Foregrounding consists +of backgrounding the current screen, and replacing its space +in the window with the foregrounded screen. + + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--99 + + + If the last screen in the window is exited, and there +are backgrounded screens, the first screen on the list of +backgrounded screens takes over the window. + +77.. RReegguullaarr EExxpprreessssiioonnss aanndd RReeppllaacceemmeenntt SSttrriinnggss + + Regular expressions are used in line addresses, as the +first part of the eexx ssuubbssttiittuuttee, gglloobbaall, and vvgglloobbaall com- +mands, and in search patterns. + + The regular expressions supported by eexx/vvii are, by +default, the Basic Regular Expressions (BRE's) described in +the IEEE POSIX Standard 1003.2. The eexxtteennddeedd option causes +all regular expressions to be interpreted as the Extended +Regular Expressions (ERE's) described by the same standard. +(See _r_e___f_o_r_m_a_t(7) for more information.) Generally speak- +ing, BRE's are the Regular Expressions found in _e_d(1) and +_g_r_e_p(1), and ERE's are the Regular Expressions found in +_e_g_r_e_p(1). + + The following is not intended to provide a description +of Regular Expressions. The information here only describes +strings and characters which have special meanings in the +eexx/vvii version of RE's, or options which change the meanings +of characters that normally have special meanings in RE's. + + (1) An empty RE (e.g. "////" or "????" is equivalent to the + last RE used. + + (2) The construct "\\<<" matches the beginning of a word. + + (3) The construct "\\>>" matches the end of a word. + + (4) The character "~~" matches the replacement part of the + last ssuubbssttiittuuttee command. + + When the mmaaggiicc option is _n_o_t set, the only characters +with special meanings are a "^^" character at the beginning +of an RE, a "$$" character at the end of an RE, and the +escaping character "\\". The characters "..", "**", "[[" and +"~~" are treated as ordinary characters unless preceded by a +"\\"; when preceded by a "\\" they regain their special mean- +ing. + + Replacement strings are the second part of a ssuubbssttiittuuttee +command. + + The character "&&" (or "\\&&" if the mmaaggiicc option is _n_o_t +set) in the replacement string stands for the text matched +by the RE that is being replaced. The character "~~" (or +"\\~~" if the mmaaggiicc option is _n_o_t set) stands for the replace- +ment part of the previous ssuubbssttiittuuttee command. It is only +valid after a ssuubbssttiittuuttee command has been performed. + + + + + + + + + + +UUSSDD::1133--1100 NNvvii//NNeexx RReeffeerreennccee + + + The string "\\##", where "##" is an integer value from 1 +to 9, stands for the text matched by the portion of the RE +enclosed in the "##"'th set of escaped parentheses, e.g. +"\\((" and "\\))". For example, "ss//aabbcc\\((..**\\))ddeeff//\\11//" deletes +the strings "aabbcc" and "ddeeff" from the matched pattern. + + The strings "\\ll", "\\uu", "\\LL" and "\\UU" can be used to +modify the case of elements in the replacement string. The +string "\\ll" causes the next character to be converted to +lowercase; the string "\\uu" behaves similarly, but converts +to uppercase (e.g. ss//aabbcc//\\UU&&// replaces the string aabbcc with +AABBCC). The strings "\\LL" causes characters up to the end of +the string or the next occurrence of the strings "\\ee" or +"\\EE" to be converted to lowercase; the string "\\UU" behaves +similarly, but converts to uppercase. + + If the entire replacement pattern is "%%", then the last +replacement pattern is used again. + + In vvii, inserting a <<ccoonnttrrooll--MM>> into the replacement +string will cause the matched line to be split into two +lines at that point. (The <<ccoonnttrrooll--MM>> will be discarded.) + +88.. GGeenneerraall EEddiittoorr DDeessccrriippttiioonn + + When eexx or vvii are executed, the text of a file is read +(or a temporary file is created), and then all editing +changes happen within the context of the copy of the file. +_N_o _c_h_a_n_g_e_s _a_f_f_e_c_t _t_h_e _a_c_t_u_a_l _f_i_l_e _u_n_t_i_l _t_h_e _f_i_l_e _i_s _w_r_i_t_t_e_n +_o_u_t, either using a write command or another command which +is affected by the aauuttoowwrriittee option. + + All files are locked (using the _f_l_o_c_k(2) or _f_c_n_t_l(2) +interfaces) during the edit session, to avoid inadvertently +making modifications to multiple copies of the file. If a +lock cannot be obtained for a file because it is locked by +another process, the edit session is read-only (as if the +rreeaaddoonnllyy option or the --RR flag had been specified). If a +lock cannot be obtained for other reasons, the edit session +will continue, but the file status information (see the +<<ccoonnttrrooll--GG>> command) will reflect this fact. + + Both eexx and vvii are modeful editors, i.e. they have two +modes, "command" mode and "text input" mode. The former is +intended to permit you to enter commands which modifies +already existing text. The latter is intended to permit you +to enter new text. When eexx first starts running, it is in +command mode, and usually displays a prompt (see the pprroommpptt +option for more information). The prompt is a single colon +("::") character. There are three commands that switch eexx +into text input mode: aappppeenndd, cchhaannggee and iinnsseerrtt. Once in +input mode, entering a line containing only a single period +("..") terminates text input mode and returns to command + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--1111 + + +mode, where the prompt is redisplayed. + + When vvii first starts running, it is in command mode as +well. There are eleven commands that switch vvii into text +input mode: AA, aa, CC, cc, II, ii, OO, oo, RR, SS and ss. Once in +input mode, entering an <<eessccaappee>> character terminates text +input mode and returns to command mode. + + The following words have special meanings in both the +eexx and vvii command descriptions: + +<<iinntteerrrruupptt>> + The interrupt character is used to interrupt the cur- + rent operation. Normally <<ccoonnttrrooll--CC>>, whatever charac- + ter is set for the current terminal is used. + +<<lliitteerraall nneexxtt>> + The literal next character is used to escape the subse- + quent character from any special meaning. This charac- + ter is always <<ccoonnttrrooll--VV>>. If the terminal is not set + up to do XON/XOFF flow control, then <<ccoonnttrrooll--QQ>> is + used to mean literal next as well. + +ccuurrrreenntt ppaatthhnnaammee + The pathname of the file currently being edited by vi. + When the percent character ("%%") appears in a file name + entered as part of an eexx command argument, it is + replaced by the current pathname. (The "%%" character + can be escaped by preceding it with a backslash.) + +aalltteerrnnaattee ppaatthhnnaammee + The name of the last file name mentioned in an eexx com- + mand, or, the previous current pathname if the last + file mentioned becomes the current file. When the hash + mark character ("##") appears in a file name entered as + part of an eexx command argument, it is replaced by the + alternate pathname. (The "##" character can be escaped + by preceding it with a backslash.) + +bbuuffffeerr + One of a number of named areas for saving copies of + text. Commands that change or delete text can save the + changed or deleted text into a specific buffer, for + later use, if the command allows it (i.e. the eexx cchhaannggee + command cannot save the changed text in a named + buffer). Buffers are named with a single character, + preceded by a double quote, e.g. ""<<cchhaarraacctteerr>>. His- + toric implementations of eexx/vvii limited <<cchhaarraacctteerr>> to + the alphanumeric characters; nneexx/nnvvii permits the use of + any character. + + Buffers named by uppercase characters are the same as + buffers named by lowercase characters, e.g. the buffer + + + + + + + + + + +UUSSDD::1133--1122 NNvvii//NNeexx RReeffeerreennccee + + + named by the English character "AA" is the same as the + buffer named by the character "aa", with the exception + that, if the buffer contents are being changed (as with + a text deletion or vvii cchhaannggee command), the text is + _a_p_p_e_n_d_e_d to the buffer, instead of replacing the cur- + rent contents. + + The buffers named by the numeric characters (in + English, "11" through "99"), are special, in that if at + least one line is changed or deleted in the file, (or a + command changes or deletes a region that crosses a line + boundary) a copy of the text is placed into the numeric + buffer "11", regardless of the user specifying another + buffer in which to save it. Before this copy is done, + the previous contents of buffer "11" are moved into + buffer "22", "22" into buffer "33", and so on. The con- + tents of buffer "99" are discarded. In vvii, text may be + explicitly stored into the numeric buffers. In this + case, the buffer rotation described above occurs before + the replacement of the buffer's contents. (Text cannot + be explicitly stored into the numeric buffers in eexx + because of ambiguities that this would cause in the eexx + command syntax.) + + When a vvii command synopsis shows both a [[bbuuffffeerr]] and a + [[ccoouunntt]], they may be presented in any order. + + Finally, all buffers are either "line" or "character" + oriented. All eexx commands which store text into + buffers are line oriented. Some vvii commands which + store text into buffers are line oriented, and some are + character oriented; the description for each applicable + vvii command notes whether text copied into buffers using + the command is line or character oriented. In addi- + tion, the vvii command ddiissppllaayy bbuuffffeerrss displays the cur- + rent orientation for each buffer. Generally, the only + importance attached to this orientation is that if the + buffer is subsequently inserted into the text, line + oriented buffers create new lines for each of the lines + they contain, and character oriented buffers create new + lines for any lines _o_t_h_e_r than the first and last lines + they contain. The first and last lines are inserted + into the text at the current cursor position, becoming + part of the current line. If there is more than one + line in the buffer, however, the current line itself + will be split. + +uunnnnaammeedd bbuuffffeerr + The unnamed buffer is a text storage area which is used + by commands that take a buffer as an argument, when no + buffer is specified by the user. There is no way to + explicitly reference this buffer. + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--1133 + + +99.. VVii DDeessccrriippttiioonn + + VVii takes up the entire screen to display the edited +file, except for the bottom line of the screen. The bottom +line of the screen is used to enter eexx commands, and for vvii +error and informational messages. If no other information +is being displayed, the default display can show the current +cursor row and cursor column, an indication of whether the +file has been modified, and the current mode of the editor. +See the rruulleerr, sshhoowwddiirrttyy and sshhoowwmmooddee options for more +information. + + Empty lines do not have any special representation on +the screen, but lines on the screen that would logically +come after the end of the file are displayed as a single +tilde ("~~") character. To differentiate between empty lines +and lines consisting of only whitespace characters, use the +lliisstt option. Historically, implementations of vvii have also +displayed some lines as single asterisk ("@@") characters. +These were lines that were not correctly displayed, i.e. +lines on the screen that did not correspond to lines in the +file, or lines that did not fit on the current screen. NNvvii +never displays lines in this fashion. + + VVii is a modeful editor, i.e. it has two modes, "com- +mand" mode and "text input" mode. When vvii first starts, it +is in command mode. There are several commands that change +vvii into text input mode. The <<eessccaappee>> character is used to +resolve the text input into the file, and exit back into +command mode. In vvii command mode, the cursor is always +positioned on the last column of characters which take up +more than one column on the screen. In vvii text insert mode, +the cursor is positioned on the first column of characters +which take up more than one column on the screen. + + Generally, if the cursor line and cursor column are not +on the screen, then the screen is scrolled (if the target +cursor is close) or repainted (if the target cursor is far +away) so that the cursor is on the screen. If the screen is +scrolled, it is moved a minimal amount, and the cursor line +will usually appear at the top or bottom of the screen. In +the screen is repainted, the cursor line will appear in the +center of the screen, unless the cursor is sufficiently +close to the beginning or end of the file that this is not +possible. If the lleeffttrriigghhtt option is set, the screen may be +scrolled or repainted in a horizontal direction as well as +in a vertical one. + + A major difference between the historical vvii presenta- +tion and nnvvii is in the scrolling and screen oriented posi- +tion commands, <<ccoonnttrrooll--BB>>, <<ccoonnttrrooll--DD>>, <<ccoonnttrrooll--EE>>, <<ccoonn-- +ttrrooll--FF>>, <<ccoonnttrrooll--UU>>, <<ccoonnttrrooll--YY>>, HH, LL and MM. In histori- +cal implementations of vvii, these commands acted on physical + + + + + + + + + + +UUSSDD::1133--1144 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + +(as opposed to logical, or screen) lines. For lines that +were sufficiently long in relation to the size of the +screen, this meant that single line scroll commands might +repaint the entire screen, scrolling or screen positioning +command might not change the screen or move the cursor at +all, and some lines simply could not be displayed, even +though vvii would edit the file that contained them. In nnvvii, +these commands act on logical, i.e. screen lines. You are +unlikely to notice any difference unless you are editing +files with lines significantly longer than a screen width. + + VVii keeps track of the currently "most attractive" cur- +sor position. Each command description (for commands that +can change the current cursor position), specifies if the +cursor is set to a specific location in the line, or if it +is moved to the "most attractive cursor position". The lat- +ter means that the cursor is moved to the cursor position +that is vertically as close as possible to the current cur- +sor position. If the current line is shorter than the cur- +sor position vvii would select, the cursor is positioned on +the last character in the line. (If the line is empty, the +cursor is positioned on the first column of the line.) If a +command moves the cursor to the most attractive position, it +does not alter the current cursor position, and a subsequent +movement will again attempt to move the cursor to that posi- +tion. Therefore, although a movement to a line shorter than +the currently most attractive position will cause the cursor +to move to the end of that line, a subsequent movement to a +longer line will cause the cursor to move back to the most +attractive position. + + In addition, the $$ command makes the end of each line +the most attractive cursor position rather than a specific +column. + + Each vvii command described below notes where the cursor +ends up after it is executed. This position is described in +terms of characters on the line, i.e. "the previous charac- +ter", or, "the last character in the line". This is to +avoid needing to continually refer to on what part of the +character the cursor rests. + + The following words have special meaning for vvii com- +mands. + +pprreevviioouuss ccoonntteexxtt + The position of the cursor before the command which + caused the last absolute movement was executed. Each + vvii command described in the next section that is con- + sidered an absolute movement is so noted. In addition, + specifying _a_n_y address to an eexx command is considered + an absolute movement. + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--1155 + + +mmoottiioonn + A second vvii command can be used as an optional trailing + argument to the vvii !!, <<, >>, cc, dd, yy, and (depending on + the ttiillddeeoopp option) ~~ commands. This command indicates + the end of the region of text that's affected by the + command. The motion command may be either the command + character repeated (in which case it means the current + line) or a cursor movement command. In the latter + case, the region affected by the command is from the + starting or stopping cursor position which comes first + in the file, to immediately before the starting or + stopping cursor position which comes later in the file. + Commands that operate on lines instead of using begin- + ning and ending cursor positions operate on all of the + lines that are wholly or partially in the region. In + addition, some other commands become line oriented + depending on where in the text they are used. The com- + mand descriptions below note these special cases. + + The following commands may all be used as motion compo- + nents for vvii commands: + + + <<ccoonnttrrooll--AA>> <<ccoonnttrrooll--HH>> <<ccoonnttrrooll--JJ>> <<ccoonnttrrooll--MM>> + <<ccoonnttrrooll--NN>> <<ccoonnttrrooll--PP>> <<ssppaaccee>> $$ + %% ''<<cchhaarraacctteerr>> (( )) + ++ ,, -- // + 00 ;; ?? BB + EE FF GG HH + LL MM NN TT + WW [[[[ ]]]] ^^ + __ ``<<cchhaarraacctteerr>> bb ee + ff hh jj kk + ll nn tt ww + {{ || }} + + + The optional count prefix available for some of the vvii + commands that take motion commands, or the count prefix + available for the vvii commands that are used as motion + components, may be included and is _a_l_w_a_y_s considered + part of the motion argument. For example, the commands + "cc22ww" and "22ccww" are equivalent, and the region affected + by the cc command is two words of text. In addition, if + the optional count prefix is specified for both the vvii + command and its motion component, the effect is multi- + plicative and is considered part of the motion argu- + ment. For example, the commands "44ccww" and "22cc22ww" are + equivalent, and the region affected by the cc command is + four words of text. + + + + + + + + + + + + + +UUSSDD::1133--1166 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + +ccoouunntt + A positive number used as an optional argument to most + commands, either to give a size or a position (for dis- + play or movement commands), or as a repeat count (for + commands that modify text). The count argument is + always optional and defaults to 1 unless otherwise + noted in the command description. + + When a vvii command synopsis shows both a [[bbuuffffeerr]] and + [[ccoouunntt]], they may be presented in any order. + +bbiiggwwoorrdd + A set of non-whitespace characters preceded and fol- + lowed by whitespace characters or the beginning or end + of the file or line. + + Groups of empty lines (or lines containing only whites- + pace characters) are treated as a single bigword. + +wwoorrdd + Generally, in languages where it is applicable, vvii rec- + ognizes two kinds of words. First, a sequence of let- + ters, digits and underscores, delimited at both ends + by: characters other than letters, digits, or under- + scores; the beginning or end of a line; the beginning + or end of the file. Second, a sequence of characters + other than letters, digits, underscores, or whitespace + characters, delimited at both ends by: a letter, digit, + underscore, or whitespace character; the beginning or + end of a line; the beginning or end of the file. + + Groups of empty lines (or lines containing only whites- + pace characters) are treated as a single word. + +ppaarraaggrraapphh + An area of text that begins with either the beginning + of a file, an empty line, or a section boundary, and + continues until either an empty line, section boundary, + or the end of the file. + + Groups of empty lines (or lines containing only whites- + pace characters) are treated as a single paragraph. + + Additional paragraph boundaries can be defined using + the ppaarraaggrraapphh option. + +sseeccttiioonn + An area of text that starts with the beginning of the + file or a line whose first character is an open brace + ("{{") and continues until the next section or the end + of the file. + + Additional section boundaries can be defined using the + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--1177 + + + sseeccttiioonnss option. + +sseenntteennccee + An area of text that begins with either the beginning + of the file or the first nonblank character following + the previous sentence, paragraph, or section boundary + and continues until the end of the file or a or a + period ("..") exclamation point ("!!") or question mark + ("??") character, followed by either an end-of-line or + two whitespace characters. Any number of closing + parentheses ("))"), brackets ("]]") or double-quote ("""") + characters can appear between the period, exclamation + point, or question mark and the whitespace characters + or end-of-line. + + Groups of empty lines (or lines containing only whites- + pace characters) are treated as a single sentence. + +1100.. VVii CCoommmmaannddss + + The following section describes the commands available +in the command mode of the vvii editor. In each entry below, +the tag line is a usage synopsis for the command character. +In addition, the final line and column the cursor rests +upon, and any options which affect the command are noted. + +[[ccoouunntt]] <<ccoonnttrrooll--AA>> + Search forward ccoouunntt times for the current word. The + current word begins at the first non-whitespace charac- + ter on or after the current cursor position, and + extends up to the next non-word character or the end of + the line. The search is literal, i.e. no characters in + the word have any special meaning in terms of Regular + Expressions. It is an error if no matching pattern is + found between the starting position and the end of the + file. + + The <<ccoonnttrrooll--AA>> command is an absolute movement. The + <<ccoonnttrrooll--AA>> command may be used as the motion component + of other vvii commands, in which case any text copied + into a buffer is character oriented. + + Line: Set to the line where the word is found. + Column: Set to the first character of the word. + Options: Affected by the eexxtteennddeedd, iiggnnoorreeccaassee and wwrraapp-- + ssccaann options. + +[[ccoouunntt]] <<ccoonnttrrooll--BB>> + Page backward ccoouunntt screens. Two lines of overlap are + maintained by displaying the window starting at line + ((ttoopp__lliinnee -- ccoouunntt ** wwiinnddooww__ssiizzee)) ++ 22, where wwiinnddooww__ssiizzee + is the value of the wwiinnddooww option. (In the case of + split screens, this size is corrected to the current + + + + + + + + + + +UUSSDD::1133--1188 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + screen size.) This is an error if the movement is past + the beginning of the file. + + The <<ccoonnttrrooll--BB>> command is an absolute movement. + + Line: Set to the last line of text displayed on the + screen. + Column: Set to the first nonblank character of the + line. + Options: None. + +[[ccoouunntt]] <<ccoonnttrrooll--DD>> + Scroll forward ccoouunntt lines. If ccoouunntt is not specified, + scroll forward the number of lines specified by the + last <<ccoonnttrrooll--DD>> or <<ccoonnttrrooll--UU>> command. If this is + the first <<ccoonnttrrooll--DD>> or <<ccoonnttrrooll--UU>> command, scroll + forward half the number of lines in the screen. (In + the case of split screens, the default scrolling dis- + tance is corrected to half the current screen size.) + This is an error if the movement is past the end of the + file. + + The <<ccoonnttrrooll--DD>> command is an absolute movement. + + Line: Set to the current line plus the number of + lines scrolled. + Column: Set to the first nonblank character of the + line. + Options: None. + +[[ccoouunntt]] <<ccoonnttrrooll--EE>> + Scroll forward ccoouunntt lines, leaving the cursor on the + current line and column, if possible. This is an error + if the movement is past the end of the file. + + Line: Unchanged unless the current line scrolls off + the screen, in which case it is set to the + first line on the screen. + Column: Unchanged unless the current line scrolls off + the screen, in which case it is set to the + most attractive cursor position. + Options: None. + +[[ccoouunntt]] <<ccoonnttrrooll--FF>> + Page forward ccoouunntt screens. Two lines of overlap are + maintained by displaying the window starting at line + ttoopp__lliinnee ++ ccoouunntt ** wwiinnddooww__ssiizzee -- 22, where wwiinnddooww__ssiizzee + is the value of the wwiinnddooww option. (In the case of + split screens, this size is corrected to the current + screen size.) This is an error if the movement is past + the end of the file. + + The <<ccoonnttrrooll--FF>> command is an absolute movement. + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--1199 + + + Line: Set to the first line on the screen. + Column: Set to the first nonblank character of the + current line. + Options: None. + +<<ccoonnttrrooll--GG>> + Display the file information. The information includes + the current pathname, the current line, the number of + total lines in the file, the current line as a percent- + age of the total lines in the file, if the file has + been modified, was able to be locked, if the file's + name has been changed, and if the edit session is read- + only. + + Line: Unchanged. + Column: Unchanged. + Options: None. + +<<ccoonnttrrooll--HH>> +[[ccoouunntt]] hh + Move the cursor back ccoouunntt characters in the current + line. This is an error if the cursor is on the first + character in the line. + + The <<ccoonnttrrooll--HH>> and hh commands may be used as the + motion component of other vvii commands, in which case + any text copied into a buffer is character oriented. + + Line: Unchanged. + Column: Set to the ccuurrrreenntt -- ccoouunntt character, or, the + first character in the line if ccoouunntt is + greater than or equal to the number of charac- + ters in the line before the cursor. + Options: None. + +[[ccoouunntt]] <<ccoonnttrrooll--JJ>> +[[ccoouunntt]] <<ccoonnttrrooll--NN>> +[[ccoouunntt]] jj + Move the cursor down ccoouunntt lines without changing the + current column. This is an error if the movement is + past the end of the file. + + The <<ccoonnttrrooll--JJ>>, <<ccoonnttrrooll--NN>> and jj commands may be used + as the motion component of other vvii commands, in which + case any text copied into a buffer is line oriented. + + Line: Set to the current line plus ccoouunntt. + Column: The most attractive cursor position. + Options: None. + +<<ccoonnttrrooll--LL>> +<<ccoonnttrrooll--RR>> + Repaint the screen. + + + + + + + + + + +UUSSDD::1133--2200 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Line: Unchanged. + Column: Unchanged. + Options: None. + +[[ccoouunntt]] <<ccoonnttrrooll--MM>> +[[ccoouunntt]] ++ + Move the cursor down ccoouunntt lines to the first nonblank + character of that line. This is an error if the move- + ment is past the end of the file. + + The <<ccoonnttrrooll--MM>> and ++ commands may be used as the + motion component of other vvii commands, in which case + any text copied into a buffer is line oriented. + + Line: Set to the current line plus ccoouunntt. + Column: Set to the first nonblank character in the + line. + Options: None. + +[[ccoouunntt]] <<ccoonnttrrooll--PP>> +[[ccoouunntt]] kk + Move the cursor up ccoouunntt lines, without changing the + current column. This is an error if the movement is + past the beginning of the file. + + The <<ccoonnttrrooll--PP>> and kk commands may be used as the + motion component of other vvii commands, in which case + any text copied into a buffer is line oriented. + + Line: Set to the current line minus count. + Column: The most attractive cursor position. + Options: None. + +<<ccoonnttrrooll--TT>> + Return to the most recent tag context. The <<ccoonnttrrooll--TT>> + command is an absolute movement. + + Line: Set to the context of the previous tag com- + mand. + Column: Set to the context of the previous tag com- + mand. + Options: None. + +<<ccoonnttrrooll--UU>> + Scroll backward ccoouunntt lines. If ccoouunntt is not speci- + fied, scroll backward the number of lines specified by + the last <<ccoonnttrrooll--DD>> or <<ccoonnttrrooll--UU>> command. If this + is the first <<ccoonnttrrooll--DD>> or <<ccoonnttrrooll--UU>> command, scroll + backward half the number of lines in the screen. (In + the case of split screens, the default scrolling dis- + tance is corrected to half the current screen size.) + This is an error if the movement is past the beginning + of the file. + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2211 + + + The <<ccoonnttrrooll--UU>> command is an absolute movement. + + Line: Set to the current line minus the amount + scrolled. + Column: Set to the first nonblank character in the + line. + Options: None. + +<<ccoonnttrrooll--WW>> + Switch to the next lower screen in the window, or, to + the first screen if there are no lower screens in the + window. + + Line: Set to the previous cursor position in the + window. + Column: Set to the previous cursor position in the + window. + Options: None. + +<<ccoonnttrrooll--YY>> + Scroll backward ccoouunntt lines, leaving the current line + and column as is, if possible. This is an error if the + movement is past the beginning of the file. + + Line: Unchanged unless the current line scrolls off + the screen, in which case it is set to the + last line of text displayed on the screen. + Column: Unchanged unless the current line scrolls off + the screen, in which case it is the most + attractive cursor position. + Options: None. + +<<ccoonnttrrooll--ZZ>> + Suspend the current editor session. If the file has + been modified since it was last completely written, and + the aauuttoowwrriittee option is set, the file is written before + the editor session is suspended. If this write fails, + the editor session is not suspended. + + Line: Unchanged. + Column: Unchanged. + Options: Affected by the aauuttoowwrriittee option. + +<<eessccaappee>> + Execute eexx commands or cancel partial commands. If an + eexx command is being entered (e.g. //, ??, :: or !!), the + command is executed. If a partial command has been + entered, e.g. or the command is cancelled. Otherwise, + it is an error. + + Line: When an eexx command is being executed, the cur- + rent line is set as described for that com- + mand. Otherwise, unchanged. + + + + + + + + + + +UUSSDD::1133--2222 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Column: When an eexx command is being executed, the cur- + rent column is set as described for that com- + mand. Otherwise, unchanged. + Options: None. + +<<ccoonnttrrooll--]]>> + Push a tag reference onto the tag stack. The tags + files (see the ttaaggss option for more information) are + searched for a tag matching the current word. The cur- + rent word begins at the first non-whitespace character + on or after the current cursor position, and extends up + to the next non-word character or the end of the line. + If a matching tag is found, the current file is dis- + carded and the file containing the tag reference is + edited. + + If the current file has been modified since it was last + completely written, the command will fail. The <<ccoonn-- + ttrrooll--]]>> command is an absolute movement. + + Line: Set to the line containing the matching tag + string. + Column: Set to the start of the matching tag string. + Options: Affected by the ttaaggss and ttaagglleennggtthh options. + +<<ccoonnttrrooll--^^>> + Switch to the most recently edited file. + + If the file has been modified since it was last com- + pletely written, and the aauuttoowwrriittee option is set, the + file is written out. If this write fails, the command + will fail. Otherwise, if the current file has been + modified since it was last completely written, the com- + mand will fail. + + Line: Set to the line the cursor was on when the + file was last edited. + Column: Set to the column the cursor was on when the + file was last edited. + Options: Affected by the aauuttoowwrriittee option. + +[[ccoouunntt]] <<ssppaaccee>> +[[ccoouunntt]] ll + Move the cursor forward ccoouunntt characters without chang- + ing the current line. This is an error if the cursor + is on the last character in the line. + + The <<ssppaaccee>> and ll commands may be used as the motion + component of other vvii commands, in which case any text + copied into a buffer is character oriented. In addi- + tion, these commands may be used as the motion compo- + nents of other commands when the cursor is on the last + character in the line, without error. + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2233 + + + Line: Unchanged. + Column: Set to the current character plus the next + ccoouunntt characters, or to the last character on + the line if ccoouunntt is greater than the number + of characters in the line after the current + character. + Options: None. + +[[ccoouunntt]] !! mmoottiioonn sshheellll--aarrgguummeenntt((ss)) + Replace text with results from a shell command. Pass + the lines specified by the ccoouunntt and mmoottiioonn arguments + as standard input to the program named by the sshheellll + option, and replace those lines with the output (both + standard error and standard output) of that command. + + After the motion is entered, vvii prompts for arguments + to the shell command. + + Within those arguments, "%%" and "##" characters are + expanded to the current and alternate pathnames, + respectively. The "!!" character is expanded with the + command text of the previous !! or ::!! commands. + (Therefore, the command !!!! repeats the previous !! + command.) The special meanings of "%%", "##" and "!!" + can be overridden by escaping them with a backslash. + If no !! or ::!! command has yet been executed, it is an + error to use an unescaped "!!" character. The !! com- + mand does _n_o_t do shell expansion on the strings pro- + vided as arguments. If any of the above expansions + change the arguments the user entered, the command is + redisplayed at the bottom of the screen. + + VVii then executes the program named by the sshheellll option, + with a --cc flag followed by the arguments (which are + bundled into a single argument). + + The !! command is permitted in an empty file. + + If the file has been modified since it was last com- + pletely written, the !! command will warn you. + + Line: The first line of the replaced text. + Column: The first column of the replaced text. + Options: Affected by the sshheellll option. + +[[ccoouunntt]] ## ++||--||## + Increment or decrement the current number. The current + number begins at the first non-number character on or + before the current cursor position, or the beginning of + the line, and extends up to the first non-number char- + acter on or after the current cursor position or the + end of the line. If the trailing character is a ++, the + number is incremented by ccoouunntt. If the trailing + + + + + + + + + + +UUSSDD::1133--2244 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + character is a --, the number is decremented by ccoouunntt. + If the trailing character is a ##, the previous incre- + ment or decrement is repeated. + + The format of the number (decimal, hexadecimal, and + octal, and leading 0's) is retained unless the new + value cannot be represented in the previous format. + + Line: Unchanged. + Column: Set to the first character in the cursor word. + Options: None. + +[[ccoouunntt]] $$ + Move the cursor to the end of a line. If ccoouunntt is + specified, the cursor moves down ccoouunntt -- 11 lines. + + It is not an error to use the $$ command when the cursor + is on the last character in the line or when the line + is empty. + + The $$ command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented, unless the cursor is at, + or before the first nonblank character in the line, in + which case it is line oriented. It is not an error to + use the $$ command as a motion component when the cursor + is on the last character in the line, although it is an + error when the line is empty. + + Line: Set to the current line plus ccoouunntt minus 1. + Column: Set to the last character in the line. + Options: None. + +%% + Move to the matching character. The cursor moves to + the parenthesis or curly brace which _m_a_t_c_h_e_s the paren- + thesis or curly brace found at the current cursor posi- + tion or which is the closest one to the right of the + cursor on the line. It is an error to execute the %% + command on a line without a parenthesis or curly brace. + Historically, any ccoouunntt specified to the %% command was + ignored. + + The %% command is an absolute movement. The %% command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + character oriented, unless the starting point of the + region is at or before the first nonblank character on + its line, and the ending point is at or after the last + nonblank character on its line, in which case it is + line oriented. + + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2255 + + + Line: Set to the line containing the matching char- + acter. + Column: Set to the matching character. + Options: None. + +&& + Repeat the previous substitution command on the current + line. + + Historically, any ccoouunntt specified to the && command was + ignored. + + Line: Unchanged. + Column: Unchanged if the cursor was on the last char- + acter in the line, otherwise, set to the first + nonblank character in the line. + Options: Affected by the eeddccoommppaattiibbllee, eexxtteennddeedd, + iiggnnoorreeccaassee and mmaaggiicc options. + +''<<cchhaarraacctteerr>> +``<<cchhaarraacctteerr>> + Return to a context marked by the character <<cchhaarraacc-- + tteerr>>. If <<cchhaarraacctteerr>> is the "''" or "``" character, + return to the previous context. If <<cchhaarraacctteerr>> is any + other character, return to the context marked by that + character (see the mm command for more information). If + the command is the '' command, only the line value is + restored, and the cursor is placed on the first non- + blank character of that line. If the command is the `` + command, both the line and column values are restored. + + It is an error if the context no longer exists because + of line deletion. (Contexts follow lines that are + moved, or which are deleted and then restored.) + + The '' and `` commands are both absolute movements. They + may be used as a motion component for other vvii com- + mands. For the '' command, any text copied into a + buffer is line oriented. For the `` command, any text + copied into a buffer is character oriented, unless it + both starts and stops at the first character in the + line, in which case it is line oriented. In addition, + when using the `` command as a motion component, com- + mands which move backward and started at the first + character in the line, or move forward and ended at the + first character in the line, are corrected to the last + character of the starting and ending lines, respec- + tively. + + Line: Set to the line from the context. + Column: Set to the first nonblank character in the + line, for the '' command, and set to the con- + text's column for the `` command. + + + + + + + + + + +UUSSDD::1133--2266 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Options: None. + +[[ccoouunntt]] (( + Back up ccoouunntt sentences. + + The (( command is an absolute movement. The (( command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + character oriented, unless the starting and stopping + points of the region are the first character in the + line, in which case it is line oriented. In the latter + case, the stopping point of the region is adjusted to + be the end of the line immediately before it, and not + the original cursor position. + + Line: Set to the line containing the beginning of + the sentence. + Column: Set to the first nonblank character of the + sentence. + Options: None. + +[[ccoouunntt]] )) + Move forward ccoouunntt sentences. + + The )) command is an absolute movement. The )) command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + character oriented, unless the starting point of the + region is the first character in the line, in which + case it is line oriented. In the latter case, if the + stopping point of the region is also the first charac- + ter in the line, it is adjusted to be the end of the + line immediately before it. + + Line: Set to the line containing the beginning of + the sentence. + Column: Set to the first nonblank character of the + sentence. + Options: None. + +[[ccoouunntt]] ,, + Reverse find character ccoouunntt times. Reverse the last + FF, ff, TT or tt command, searching the other way in the + line, ccoouunntt times. + + The ,, command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Unchanged. + Column: Set to the searched-for character. + Options: None. + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2277 + + +[[ccoouunntt]] -- + Move to first nonblank of the previous line, ccoouunntt + times. + + This is an error if the movement is past the beginning + of the file. + + The -- command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is line oriented. + + Line: Set to the current line minus ccoouunntt. + Column: Set to the first nonblank character in the + line. + Options: None. + +[[ccoouunntt]] .. + Repeat the last vvii command that modified text. The + repeated command may be a command and motion component + combination. If ccoouunntt is specified, it replaces _b_o_t_h + the count specified for the repeated command, and, if + applicable, for the repeated motion component. If + ccoouunntt is not specified, the counts originally specified + to the command being repeated are used again. + + As a special case, if the .. command is executed imme- + diately after the uu command, the change log is rolled + forward or backward, depending on the action of the uu + command. + + Line: Set as described for the repeated command. + Column: Set as described for the repeated command. + Options: None. + +//RREE<<ccaarrrriiaaggee--rreettuurrnn>> +//RREE// [[ooffffsseett]]<<ccaarrrriiaaggee--rreettuurrnn>> +??RREE<<ccaarrrriiaaggee--rreettuurrnn>> +??RREE?? [[ooffffsseett]]<<ccaarrrriiaaggee--rreettuurrnn>> +NN +nn + Search forward or backward for a regular expression. + The commands beginning with a slash ("//") character are + forward searches, the commands beginning with a ques- + tion mark ("??") are backward searches. VVii prompts + with the leading character on the last line of the + screen for a string. It then searches forward or back- + ward in the file for the next occurrence of the string, + which is interpreted as a Basic Regular Expression. + + The // and ?? commands are absolute movements. They may + be used as the motion components of other vvii commands, + in which case any text copied into a buffer is charac- + ter oriented, unless the search started and ended on + + + + + + + + + + +UUSSDD::1133--2288 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + the first column of a line, in which case it is line + oriented. In addition, forward searches ending at the + first character of a line, and backward searches begin- + ning at the first character in the line, are corrected + to begin or end at the last character of the previous + line. (Note, forward and backward searches can occur + for both // and ?? commands, if the wwrraappssccaann option is + set.) + + If an offset from the matched line is specified (i.e. a + trailing "//" or "??" character is followed by a signed + offset), the buffer will always be line oriented (e.g. + "//ssttrriinngg//++00" will always guarantee a line orientation). + + The nn command repeats the previous search. + + The NN command repeats the previous search, but in the + reverse direction. + + Missing RE's (e.g. "////<<ccaarrrriiaaggee--rreettuurrnn>>", "//<<ccaarrrriiaaggee-- + rreettuurrnn>>", "????<<ccaarrrriiaaggee--rreettuurrnn>>", or "??<<ccaarrrriiaaggee-- + rreettuurrnn>>" search for the last search RE, in the indi- + cated direction. + + Searches may be interrupted using the <<iinntteerrrruupptt>> char- + acter. + + Line: Set to the line in which the match occurred. + Column: Set to the first character of the matched + string. + Options: Affected by the eeddccoommppaattiibbllee, eexxtteennddeedd, + iiggnnoorreeccaassee, mmaaggiicc, and wwrraappssccaann options. + +00 + Move to the first character in the current line. It is + not an error to use the 00 command when the cursor is on + the first character in the line, + + The 00 command may be used as the motion component of + other vvii commands, in which case it is an error if the + cursor is on the first character in the line. + + Line: Unchanged. + Column: Set to the first character in the line. + Options: None. + +:: + Execute an ex command. VVii prompts for an eexx command on + the last line of the screen, using a colon ("::") char- + acter. The command is terminated by a <<ccaarrrriiaaggee-- + rreettuurrnn>>, <<nneewwlliinnee>> or <<eessccaappee>> character; all of these + characters may be escaped by using a <<lliitteerraall nneexxtt>> + character. The command is then executed. + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--2299 + + + If the eexx command writes to the screen, vvii will prompt + the user for a <<ccaarrrriiaaggee--rreettuurrnn>> before continuing when + the eexx command finishes. Large amounts of output from + the eexx command will be paged for the user, and the user + prompted for a <<ccaarrrriiaaggee--rreettuurrnn>> or <<ssppaaccee>> key to con- + tinue. In some cases, a quit (normally a "q" charac- + ter) or <<iinntteerrrruupptt>> may be entered to interrupt the eexx + command. + + When the eexx command finishes, and the user is prompted + to resume visual mode, it is also possible to enter + another "::" character followed by another eexx command. + + Line: The current line is set as described for the + eexx command. + Column: The current column is set as described for the + eexx command. + Options: None. + +[[ccoouunntt]] ;; + Repeat the last character find ccoouunntt times. The last + character find is one of the FF, ff, TT or tt commands. + + The ;; command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Unchanged. + Column: Set to the searched-for character. + Options: None. + +[[ccoouunntt]] << mmoottiioonn +[[ccoouunntt]] >> mmoottiioonn + Shift lines left or right. Shift the number of lines + in the region specified by the motion component, times + ccoouunntt, left (for the << command) or right (for the >> + command) by the number of columns specified by the + sshhiiffttwwiiddtthh option. Only whitespace characters are + deleted when shifting left; once the first character in + the line contains a nonblank character, the sshhiifftt will + succeed, but the line will not be modified. + + Line: Unchanged. + Column: Set to the first nonblank character in the + line. + Options: Affected by the sshhiiffttwwiiddtthh option. + +@@ bbuuffffeerr + Execute a named buffer. Execute the named buffer as vvii + commands. The buffer may include eexx commands, too, but + they must be expressed as a :: command. If the buffer + is line oriented, <<nneewwlliinnee>> characters are logically + appended to each line of the buffer. If the buffer is + + + + + + + + + + +UUSSDD::1133--3300 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + character oriented, <<nneewwlliinnee>> characters are logically + appended to all but the last line in the buffer. + + If the buffer name is "@@", or "**", then the last buffer + executed shall be used. It is an error to specify "@@@@" + or "****" if there were no buffer previous executions. + The text of a macro may contain an @@ command, and it is + possible to create infinite loops in this manner. (The + <<iinntteerrrruupptt>> character may be used to interrupt the + loop.) + + Line: The current line is set as described for the + command(s). + Column: The current column is set as described for the + command(s). + Options: None. + +[[ccoouunntt]] AA + Enter input mode, appending the text after the end of + the line. If ccoouunntt is specified, the text is repeat- + edly input ccoouunntt -- 11 more times after input mode is + exited. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +[[ccoouunntt]] BB + Move backward ccoouunntt bigwords. Move the cursor backward + to the beginning of a bigword by repeating the follow- + ing algorithm: if the current position is at the begin- + ning of a bigword or the character at the current posi- + tion cannot be part of a bigword, move to the first + character of the preceding bigword. Otherwise, move to + the first character of the bigword at the current posi- + tion. If no preceding bigword exists on the current + line, move to the first character of the last bigword + on the first preceding line that contains a bigword. + + The BB command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Set to the line containing the word selected. + Column: Set to the first character of the word + selected. + Options: None. + +[[bbuuffffeerr]] [[ccoouunntt]] CC + Change text from the current position to the end-of- + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3311 + + + line. If ccoouunntt is specified, the input text replaces + from the current position to the end-of-line, plus + ccoouunntt -- 11 subsequent lines. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +[[bbuuffffeerr]] DD + Delete text from the current position to the end-of- + line. + + It is not an error to execute the DD command on an empty + line. + + Line: Unchanged. + Column: Set to the character before the current char- + acter, or, column 1 if the cursor was on col- + umn 1. + Options: None. + +[[ccoouunntt]] EE + Move forward ccoouunntt end-of-bigwords. Move the cursor + forward to the end of a bigword by repeating the fol- + lowing algorithm: if the current position is the end of + a bigword or the character at that position cannot be + part of a bigword, move to the last character of the + following bigword. Otherwise, move to the last charac- + ter of the bigword at the current position. If no suc- + ceeding bigword exists on the current line, move to the + last character of the first bigword on the next follow- + ing line that contains a bigword. + + The EE command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Set to the line containing the word selected. + Column: Set to the last character of the word + selected. + Options: None. + +[[ccoouunntt]] FF <<cchhaarraacctteerr>> + Search ccoouunntt times backward through the current line + for <<cchhaarraacctteerr>>. + + The FF command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + + + + + + + + + + +UUSSDD::1133--3322 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Line: Unchanged. + Column: Set to the searched-for character. + Options: None. + +[[ccoouunntt]] GG + Move to line ccoouunntt, or the last line of the file if + ccoouunntt not specified. + + The GG command is an absolute movement. The GG command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + line oriented. + + Line: Set to ccoouunntt, if specified, otherwise, the + last line. + Column: Set to the first nonblank character in the + line. + Options: None. + +[[ccoouunntt]] HH + Move to the screen line ccoouunntt -- 11 lines below the top + of the screen. + + The HH command is an absolute movement. The HH command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + line oriented. + + Line: Set to the line ccoouunntt -- 11 lines below the top + of the screen. + Column: Set to the first nonblank character of the + _s_c_r_e_e_n line. + Options: None. + +[[ccoouunntt]] II + Enter input mode, inserting the text at the beginning + of the line. If ccoouunntt is specified, the text input is + repeatedly input ccoouunntt -- 11 more times. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: None. + +[[ccoouunntt]] JJ + Join lines. If ccoouunntt is specified, ccoouunntt lines are + joined; a minimum of two lines are always joined, + regardless of the value of ccoouunntt. + + If the current line ends with a whitespace character, + all whitespace is stripped from the next line. Other- + wise, if the next line starts with a open parenthesis + ("((") do nothing. Otherwise, if the current line ends + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3333 + + + with a question mark ("??"), period ("..") or exclama- + tion point ("!!"), insert two spaces. Otherwise, insert + a single space. + + It is not an error to join lines past the end of the + file, i.e. lines that do not exist. + + Line: Unchanged. + Column: Set to the character after the last character + of the next-to-last joined line. + Options: None. + +[[ccoouunntt]] LL + Move to the screen line ccoouunntt -- 11 lines above the bot- + tom of the screen. + + The LL command is an absolute movement. The LL command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + line oriented. + + Line: Set to the line ccoouunntt -- 11 lines above the bot- + tom of the screen. + Column: Set to the first nonblank character of the + _s_c_r_e_e_n line. + Options: None. + + MM + Move to the screen line in the middle of the screen. + + The MM command is an absolute movement. The MM command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + line oriented. + + Historically, any ccoouunntt specified to the MM command was + ignored. + + Line: Set to the line in the middle of the screen. + Column: Set to the first nonblank character of the + _s_c_r_e_e_n line. + Options: None. + +[[ccoouunntt]] OO + Enter input mode, appending text in a new line above + the current line. If ccoouunntt is specified, the text + input is repeatedly input ccoouunntt -- 11 more times. + + Historically, any ccoouunntt specified to the OO command was + ignored. + + Line: Set to the last line upon which characters + were entered. + + + + + + + + + + +UUSSDD::1133--3344 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +[[bbuuffffeerr]] PP + Insert text from a buffer. Text from the buffer (the + unnamed buffer by default) is inserted before the cur- + rent column or, if the buffer is line oriented, before + the current line. + + Line: Set to the lowest numbered line insert, if the + buffer is line oriented, otherwise unchanged. + Column: Set to the first nonblank character of the + appended text, if the buffer is line oriented, + otherwise, the last character of the appended + text. + Options: None. + +QQ + Exit vvii (or visual) mode and switch to eexx mode. + + Line: Unchanged. + Column: No longer relevant. + Options: None. + +[[ccoouunntt]] RR + Enter input mode, replacing the characters in the cur- + rent line. If ccoouunntt is specified, the text input is + repeatedly input ccoouunntt -- 11 more times. + + If the end of the current line is reached, no more + characters are replaced and any further characters + input are appended to the line. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +[[bbuuffffeerr]] [[ccoouunntt]] SS + Substitute ccoouunntt lines. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3355 + + +[[ccoouunntt]] TT <<cchhaarraacctteerr>> + Search backward, ccoouunntt times, through the current line + for the character _a_f_t_e_r the specified <<cchhaarraacctteerr>>. + + The TT command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Unchanged. + Column: Set to the character _a_f_t_e_r the searched-for + character. + Options: None. + +UU + Restore the current line to its state before the cursor + last moved to it. + + Line: Unchanged. + Column: The first character in the line. + Options: None. + +[[ccoouunntt]] WW + Move forward ccoouunntt bigwords. Move the cursor forward + to the beginning of a bigword by repeating the follow- + ing algorithm: if the current position is within a big- + word or the character at that position cannot be part + of a bigword, move to the first character of the next + bigword. If no subsequent bigword exists on the cur- + rent line, move to the first character of the first + bigword on the first following line that contains a + bigword. + + The WW command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: The line containing the word selected. + Column: The first character of the word selected. + Options: None. + +[[bbuuffffeerr]] [[ccoouunntt]] XX + Delete ccoouunntt characters before the cursor. If the num- + ber of characters to be deleted is greater than or + equal to the number of characters to the beginning of + the line, all of the characters before the current cur- + sor position, to the beginning of the line, are + deleted. + + Line: Unchanged. + Column: Set to the current character minus ccoouunntt, or + the first character if count is greater than + the number of characters in the line before + the cursor. + + + + + + + + + + +UUSSDD::1133--3366 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Options: None. + +[[bbuuffffeerr]] [[ccoouunntt]] YY + Copy (or "yank") ccoouunntt lines into the specified buffer. + + Line: Unchanged. + Column: Unchanged. + Options: None. + +ZZZZ + Write the file and exit vvii. The file is only written + if it has been modified since the last complete write + of the file to any file. + + The ZZZZ command will exit the editor after writing the + file, if there are no further files to edit. Entering + two "quit" commands (i.e. wwqq, qquuiitt, xxiitt or ZZZZ) in a + row will override this check and the editor will exit, + ignoring any files that have not yet been edited. + + Line: Unchanged. + Column: Unchanged. + Options: None. + +[[ccoouunntt]] [[[[ + Back up ccoouunntt section boundaries. + + The [[[[ command is an absolute movement. The [[[[ command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + character oriented, unless the starting position is + column 0, in which case it is line oriented. + + This is an error if the movement is past the beginning + of the file. + + Line: Set to the previous line that is ccoouunntt section + boundaries back, or the first line of the file + if no more section boundaries exist preceding + the current line. + Column: Set to the first nonblank character in the + line. + Options: Affected by the sseeccttiioonnss option. + +[[ccoouunntt]] ]]]] + Move forward ccoouunntt section boundaries. + + The ]]]] command is an absolute movement. The ]]]] command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + character oriented, unless the starting position is + column 0, in which case it is line oriented. + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3377 + + + This is an error if the movement is past the end of the + file. + + Line: Set to the line that is ccoouunntt section bound- + aries forward, or to the last line of the file + if no more section boundaries exist following + the current line. + Column: Set to the first nonblank character in the + line. + Options: Affected by the sseeccttiioonnss option. + +^^ + Move to first nonblank character on the current line. + + The ^^ command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Unchanged. + Column: Set to the first nonblank character of the + current line. + Options: None. + +[[ccoouunntt]] __ + Move down ccoouunntt -- 11 lines, to the first nonblank char- + acter. The __ command may be used as the motion compo- + nent of other vvii commands, in which case any text + copied into a buffer is line oriented. + + It is not an error to execute the __ command when the + cursor is on the first character in the line. + + Line: The current line plus ccoouunntt -- 11. + Column: The first nonblank character in the line. + Options: None. + +[[ccoouunntt]] aa + Enter input mode, appending the text after the cursor. + If ccoouunntt is specified, the text input is repeatedly + input ccoouunntt -- 11 more times. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +[[ccoouunntt]] bb + Move backward ccoouunntt words. Move the cursor backward to + the beginning of a word by repeating the following + algorithm: if the current position is at the beginning + of a word, move to the first character of the preceding + + + + + + + + + + +UUSSDD::1133--3388 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + word. Otherwise, the current position moves to the + first character of the word at the current position. + If no preceding word exists on the current line, move + to the first character of the last word on the first + preceding line that contains a word. + + The bb command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Set to the line containing the word selected. + Column: Set to the first character of the word + selected. + Options: None. + +[[bbuuffffeerr]] [[ccoouunntt]] cc mmoottiioonn + Change a region of text. If only part of a single line + is affected, then the last character being changed is + marked with a "$$". Otherwise, the region of text is + deleted, and input mode is entered. + + If ccoouunntt is specified, it is applied to the mmoottiioonn. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +[[bbuuffffeerr]] [[ccoouunntt]] dd mmoottiioonn + Delete a region of text. If ccoouunntt is specified, it is + applied to the mmoottiioonn. + + Line: Set to the line where the region starts. + Column: Set to the first character in the line after + the last character in the region. If no such + character exists, set to the last character + before the region. + Options: None. + +[[ccoouunntt]] ee + Move forward ccoouunntt end-of-words. Move the cursor for- + ward to the end of a word by repeating the following + algorithm: if the current position is the end of a + word, move to the last character of the following word. + Otherwise, move to the last character of the word at + the current position. If no succeeding word exists on + the current line, move to the last character of the + first word on the next following line that contains a + word. + + The ee command may be used as the motion component of + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--3399 + + + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Set to the line containing the word selected. + Column: Set to the last character of the word + selected. + Options: None. + +[[ccoouunntt]] ff <<cchhaarraacctteerr>> + Search forward, ccoouunntt times, through the rest of the + current line for <<cchhaarraacctteerr>>. + + The ff command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Unchanged. + Column: Set to the searched-for character. + Options: None. + +[[ccoouunntt]] ii + Enter input mode, inserting the text before the cursor. + If ccoouunntt is specified, the text input is repeatedly + input ccoouunntt -- 11 more times. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +mm <<cchhaarraacctteerr>> + Save the current context (line and column) as <<cchhaarraacc-- + tteerr>>. The exact position is referred to by "``<<cchhaarraacc-- + tteerr>>". The line is referred to by "''<<cchhaarraacctteerr>>". + + Historically, <<cchhaarraacctteerr>> was restricted to lower-case + letters only, nnvvii permits the use of any character. + + Line: Unchanged. + Column: Unchanged. + Options: None. + +[[ccoouunntt]] oo + Enter input mode, appending text in a new line under + the current line. If ccoouunntt is specified, the text + input is repeatedly input ccoouunntt -- 11 more times. + + Historically, any ccoouunntt specified to the oo command was + ignored. + + + + + + + + + + + + +UUSSDD::1133--4400 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +[[bbuuffffeerr]] pp + Append text from a buffer. Text from the buffer (the + unnamed buffer by default) is appended after the cur- + rent column or, if the buffer is line oriented, after + the current line. + + Line: Set to the first line appended, if the buffer + is line oriented, otherwise unchanged. + Column: Set to the first nonblank character of the + appended text if the buffer is line oriented, + otherwise, the last character of the appended + text. + Options: None. + +[[ccoouunntt]] rr <<cchhaarraacctteerr>> + Replace characters. The next ccoouunntt characters in the + line are replaced with <<cchhaarraacctteerr>>. Replacing charac- + ters with <<nneewwlliinnee>> characters results in creating new, + empty lines into the file. + + If <<cchhaarraacctteerr>> is <<eessccaappee>>, the command is cancelled. + + Line: Unchanged unless the replacement character is + a <<nneewwlliinnee>>, in which case it is set to the + current line plus ccoouunntt -- 11. + Column: Set to the last character replaced, unless the + replacement character is a <<nneewwlliinnee>>, in which + case the cursor is in column 1 of the last + line inserted. + Options: None. + +[[bbuuffffeerr]] [[ccoouunntt]] ss + Substitute ccoouunntt characters in the current line start- + ing with the current character. + + Line: Set to the last line upon which characters + were entered. + Column: Set to the last character entered. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, bbeeaauu-- + ttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraappmmaarrggiinn + options. + +[[ccoouunntt]] tt <<cchhaarraacctteerr>> + Search forward, ccoouunntt times, through the current line + for the character immediately _b_e_f_o_r_e <<cchhaarraacctteerr>>. + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--4411 + + + The tt command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Unchanged. + Column: Set to the character _b_e_f_o_r_e the searched-for + character. + Options: None. + +uu + Undo the last change made to the file. If repeated, + the uu command alternates between these two states, and + is its own inverse. When used after an insert that + inserted text on more than one line, the lines are + saved in the numeric buffers. + + The .. command, when used immediately after the uu com- + mand, causes the change log to be rolled forward or + backward, depending on the action of the uu command. + + Line: Set to the position of the first line changed, + if the reversal affects only one line or rep- + resents an addition or change; otherwise, the + line preceding the deleted text. + Column: Set to the cursor position before the change + was made. + Options: None. + +[[ccoouunntt]] ww + Move forward ccoouunntt words. Move the cursor forward to + the beginning of a word by repeating the following + algorithm: if the current position is at the beginning + of a word, move to the first character of the next + word. If no subsequent word exists on the current + line, move to the first character of the first word on + the first following line that contains a word. + + The ww command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. + + Line: Set to the line containing the word selected. + Column: Set to the first character of the word + selected. + Options: None. + +[[bbuuffffeerr]] [[ccoouunntt]] xx + Delete ccoouunntt characters. The deletion is at the cur- + rent character position. If the number of characters + to be deleted is greater than or equal to the number of + characters to the end of the line, all of the charac- + ters from the current cursor position to the end of the + line are deleted. + + + + + + + + + + +UUSSDD::1133--4422 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Line: Unchanged. + Column: Unchanged unless the last character in the + line is deleted and the cursor is not already + on the first character in the line, in which + case it is set to the previous character. + Options: None. + +[[bbuuffffeerr]] [[ccoouunntt]] yy mmoottiioonn + Copy (or "yank") a text region specified by the ccoouunntt + and motion into a buffer. If ccoouunntt is specified, it is + applied to the mmoottiioonn. + + Line: Unchanged, unless the region covers more than + a single line, in which case it is set to the + line where the region starts. + Column: Unchanged, unless the region covers more than + a single line, in which case it is set to the + character were the region starts. + Options: None. + +[[ccoouunntt11]] zz [[ccoouunntt22]] ttyyppee + Redraw the screen with a window ccoouunntt22 lines long, with + line ccoouunntt11 placed as specified by the ttyyppee character. + If ccoouunntt11 is not specified, it defaults to the current + line. If ccoouunntt22 is not specified, it defaults to the + current window size. + + The following ttyyppee characters may be used: + + + If ccoouunntt11 is specified, place the line ccoouunntt11 + at the top of the screen. Otherwise, display + the screen after the current screen, similarly + to the <<ccoonnttrrooll--FF>> command. + <carriage-return> + Place the line ccoouunntt11 at the top of the + screen. + . Place the line ccoouunntt11 in the center of the + screen. + - Place the line ccoouunntt11 at the bottom of the + screen. + ^ If ccoouunntt11 is specified, place the line that is + at the top of the screen when ccoouunntt11 is at the + bottom of the screen, at the bottom of the + screen, i.e. display the screen before the + screen before ccoouunntt11. Otherwise, display the + screen before the current screen, similarly to + the <<ccoonnttrrooll--BB>> command. + + Line: Set to ccoouunntt11 unless ccoouunntt11 is not specified + and the ttyyppee character was either "^^" or "++", + in which case it is set to the line before the + first line on the previous screen or the line + after the last line on the previous screen, + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--4433 + + + respectively. + Column: Set to the first nonblank character in the + line. + Options: None. + +[[ccoouunntt]] {{ + Move backward ccoouunntt paragraphs. + + The {{ command is an absolute movement. The {{ command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + character oriented, unless the starting character is + the first character on its line, in which case it is + line oriented. + + Line: Set to the line containing the beginning of + the previous paragraph. + Column: Set to the first nonblank character in the + line. + Options: Affected by the ppaarraaggrraapphh option. + +[[ccoouunntt]] || + Move to a specific _c_o_l_u_m_n position on the current line. + + The || command may be used as the motion component of + other vvii commands, in which case any text copied into a + buffer is character oriented. It is an error to use + the || command as a motion component and for the cursor + not to move. + + Line: Unchanged. + Column: Set to the character occupying the column + position identified by ccoouunntt, if the position + exists in the line. If the column length of + the current line is less than ccoouunntt, the cur- + sor is moved to the last character in the + line. + Options: None. + +[[ccoouunntt]] }} + Move forward ccoouunntt paragraphs. + + The }} command is an absolute movement. The }} command + may be used as the motion component of other vvii com- + mands, in which case any text copied into a buffer is + character oriented, unless the starting character is at + or before any nonblank characters in its line, in which + case it is line oriented. + + Line: Set to the line containing the beginning of + the next paragraph. + Column: Set to the first nonblank character in the + line. + + + + + + + + + + +UUSSDD::1133--4444 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + Options: Affected by the ppaarraaggrraapphh option. + +[[ccoouunntt]] ~~ + Reverse the case of the next ccoouunntt character(s). This + is the historic semantic for the ~~ command and it is + only in effect if the ttiillddeeoopp option is not set. + + Lowercase alphabetic characters are changed to upper- + case, and uppercase characters are changed to lower- + case. No other characters are affected. + + Historically, the ~~ command did not take an associated + count, nor did it move past the end of the current + line. As it had no associated motion it was difficult + to change the case of large blocks of text. In nnvvii, if + the cursor is on the last character of a line, and + there are more lines in the file, the cursor moves to + the next line. + + It is not an error to specify a count larger than the + number of characters between the cursor and the end of + the file. + + Line: Set to the line of the character after ccoouunntt + characters, or, end of file. + Column: Set to the character after ccoouunntt characters, + or, end-of-file. + Options: Affected by the ttiillddeeoopp option. + +[[ccoouunntt]] ~~ mmoottiioonn + Reverse the case of the characters in a text region + specified by the ccoouunntt and mmoottiioonn. Only in effect if + the ttiillddeeoopp option is set. + + Lowercase characters are changed to uppercase, and + uppercase characters are changed to lowercase. No + other characters are affected. + + Line: Set to the line of the character after the + last character in the region. + Column: Set to the character after the last character + in the region. + Options: Affected by the ttiillddeeoopp option. + +<<iinntteerrrruupptt>> + Interrupt the current operation. Many of the poten- + tially long-running vvii commands may be interrupted + using the terminal interrupt character. These opera- + tions include searches, file reading and writing, fil- + ter operations and map character expansion. Interrupts + are also enabled when running commands outside of vvii. + + If the <<iinntteerrrruupptt>> character is used to interrupt while + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--4455 + + + entering an eexx command, the command is aborted, the + cursor returns to its previous position, and vvii remains + in command mode. + + Generally, if the <<iinntteerrrruupptt>> character is used to + interrupt any operation, any changes made before the + interrupt are left in place. + + Line: Dependent on the operation being interrupted. + Column: Dependent on the operation being interrupted. + Options: None. + + 1111.. VVii TTeexxtt IInnppuutt CCoommmmaannddss + + The following section describes the commands + available in the text input mode of the vvii editor. + + Historically, vvii implementations only permitted + the characters inserted on the current line to be + erased. In addition, only the <<ccoonnttrrooll--DD>> erase char- + acter and the "00<<ccoonnttrrooll--DD>>" and "^^<<ccoonnttrrooll--DD>>" erase + strings could erase autoindent characters. This imple- + mentation permits erasure to continue past the begin- + ning of the current line, and back to where text input + mode was entered. In addition, autoindent characters + may be erased using the standard erase characters. For + the line and word erase characters, reaching the + autoindent characters forms a "soft" boundary, denoting + the end of the current word or line erase. Repeating + the word or line erase key will erase the autoindent + characters. + + Historically, vvii always used <<ccoonnttrrooll--HH>> and <<ccoonn-- + ttrrooll--WW>> as character and word erase characters, respec- + tively, regardless of the current terminal settings. + This implementation accepts, in addition to these two + characters, the current terminal characters for those + operations. + + <<nnuull>> + If the first character of the input is a <<nnuull>>, + the previous input is replayed, as if just + entered. + + <<ccoonnttrrooll--DD>> + If the previous character on the line was an + autoindent character, erase it. Otherwise, if the + user is entering the first character in the line, + <<ccoonnttrrooll--DD>> is ignored. Otherwise, a literal + <<ccoonnttrrooll--DD>> character is entered. + + ^^<<ccoonnttrrooll--DD>> + If the previous character on the line was an + + + + + + + + + + +UUSSDD::1133--4466 NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) + + + autoindent character, erase all of the autoindent + characters on the line. In addition, the autoin- + dent level is reset to 0. + + 00<<ccoonnttrrooll--DD>> + If the previous character on the line was an + autoindent character, erase all of the autoindent + characters on the line. + + <<ccoonnttrrooll--TT>> + Insert sufficient <<ttaabb>> and <<ssppaaccee>> characters to + move the cursor forward to a column immediately + after the next column which is an even multiple of + the sshhiiffttwwiiddtthh option. + + Historically, vvii did not permit the <<ccoonnttrrooll--TT>> + command to be used unless the cursor was at the + first column of a new line or it was preceded only + by autoindent characters. NNvvii permits it to be + used at any time during insert mode. + + <<eerraassee>> + <<ccoonnttrrooll--HH>> + Erase the last character. + + <<lliitteerraall nneexxtt>> + Quote the next character. The next character will + not be mapped (see the mmaapp command for more infor- + mation) or interpreted specially. A carat ("^^") + character will be displayed immediately as a + placeholder, but will be replaced by the next + character. + + <<eessccaappee>> + Resolve all text input into the file, and return + to command mode. + + <<lliinnee eerraassee>> + Erase the current line. + + <<ccoonnttrrooll--WW>> + <<wwoorrdd eerraassee>> + Erase the last word. The definition of word is + dependent on the aallttwweerraassee and ttttyywweerraassee options. + + <<ccoonnttrrooll--XX>>[[00--99AA--FFaa--ff]]** + Insert a character with the specified hexadecimal + value into the text. + + <<iinntteerrrruupptt>> + Interrupt text input mode, returning to command + mode. If the <<iinntteerrrruupptt>> character is used to + interrupt inserting text into the file, it is as + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((VVii CCoommmmaannddss)) UUSSDD::1133--4477 + + + if the <<eessccaappee>> character was used; all text input + up to the interruption is resolved into the file. + + 1122.. EExx AAddddrreessssiinngg + + Addressing in eexx (and when eexx commands are exe- + cuted from vvii) relates to the current line. In gen- + eral, the current line is the last line affected by a + command. The exact effect on the current line is dis- + cussed under the description of each command. When the + file contains no lines, the current line is zero. + + Addresses are constructed by one or more of the + following methods: + + (1) The address ".." refers to the current line. + + (2) The address "$$" refers to the last line of the + file. + + (3) The address "NN", where NN is a positive number, + refers to the N-th line of the file. + + (4) The address "''<<cchhaarraacctteerr>>" or "``<<cchhaarraacctteerr>>" + refers to the line marked with the name <<cchhaarraacc-- + tteerr>>. (See the kk or mm commands for more infor- + mation on how to mark lines.) + + (5) A regular expression (RE) enclosed by slashes + ("//") is an address, and it refers to the first + line found by searching forward from the line + _a_f_t_e_r the current line toward the end of the + file, and stopping at the first line containing + a string matching the RE. (The trailing slash + can be omitted at the end of the command line.) + + If no RE is specified, i.e. the pattern is "////", + the last RE used in any command is used in the + search. + + If the eexxtteennddeedd option is set, the RE is handled + as an extended RE, not a basic RE. If the wwrraapp-- + ssccaann option is set, the search wraps around to + the beginning of the file and continues up to + and including the current line, so that the + entire file is searched. + + The form "\\//" is accepted for historic reasons, + and is identical to "////". + + (6) An RE enclosed in question marks ("??") + addresses the first line found by searching + backward from the line _p_r_e_c_e_d_i_n_g the current + + + + + + + + + + +UUSSDD::1133--4488 NNvvii//NNeexx RReeffeerreennccee + + + line, toward the beginning of the file and stop- + ping at the first line containing a string + matching the RE. (The trailing question mark + can be omitted at the end of a command line.) + + If no RE is specified, i.e. the pattern is "????", + the last RE used in any command is used in the + search. + + If the eexxtteennddeedd option is set, the RE is handled + as an extended RE, not a basic RE. If the wwrraapp-- + ssccaann option is set, the search wraps around + from the beginning of the file to the end of the + file and continues up to and including the cur- + rent line, so that the entire file is searched. + + The form "\\??" is accepted for historic reasons, + and is identical to "????". + + (7) An address followed by a plus sign ("++") or a + minus sign ("--") followed by a number is an off- + set address and refers to the address plus (or + minus) the indicated number of lines. If the + address is omitted, the addition or subtraction + is done with respect to the current line. + + (8) An address of "++" or "--" followed by a number is + an offset from the current line. For example, + "--55" is the same as "..--55". + + (9) An address ending with "++" or "--" has 1 added to + or subtracted from the address, respectively. + As a consequence of this rule and of the previ- + ous rule, the address "--" refers to the line + preceding the current line. Moreover, trailing + "++" and "--" characters have a cumulative effect. + For example, "++++--++++" refers to the current line + plus 3. + + (10) A percent sign ("%%") is equivalent to the + address range "11,,$$". + + EExx commands require zero, one, or two addresses. + It is an error to specify an address to a command which + requires zero addresses. + + If the user provides more than the expected number + of addresses to any eexx command, the first addresses + specified are discarded. For example, "11,,22,,33,,55"print + prints lines 3 through 5, because the pprriinntt command + only takes two addresses. + + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--4499 + + + The addresses in a range are separated from each + other by a comma (",,") or a semicolon (";;"). In the + latter case, the current line ("..") is set to the + first address, and only then is the second address cal- + culated. This feature can be used to determine the + starting line for forward and backward searches (see + rules (5) and (6) above). The second address of any + two-address sequence corresponds to a line that fol- + lows, in the file, the line corresponding to the first + address. The first address must be less than or equal + to the second address. The first address must be + greater than or equal to the first line of the file, + and the last address must be less than or equal to the + last line of the file. + + 1133.. EExx DDeessccrriippttiioonn + + The following words have special meanings for eexx + commands. + + <<eeooff>> + The end-of-file character is used to scroll the + screen in the eexx editor. This character is nor- + mally <<ccoonnttrrooll--DD>>, however, whatever character is + set for the current terminal is used. + + lliinnee + A single-line address, given in any of the forms + described in the section entitled "EExx AAddddrreessssiinngg". + The default for lliinnee is the current line. + + rraannggee + A line, or a pair of line addresses, separated by + a comma or semicolon. (See the section entitled + "EExx AAddddrreessssiinngg" for more information.) The + default for range is the current line _o_n_l_y, i.e. + "..,,..". A percent sign ("%%") stands for the range + "11,,$$". The starting address must be less than, or + equal to, the ending address. + + ccoouunntt + A positive integer, specifying the number of lines + to be affected by the command; the default is 1. + Generally, a count past the end-of-file may be + specified, e.g. the command "pp 33000000" in a 10 line + file is acceptable, and will print from the cur- + rent line through the last line in the file. + + ffllaaggss + One or more of the characters "#", "p", and "l". + When a command that accepts these flags completes, + the addressed line(s) are written out as if by the + corresponding ##, ll or pp commands. In addition, + + + + + + + + + + +UUSSDD::1133--5500 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + any number of "++" or "--" characters can be speci- + fied before, after, or during the flags, in which + case the line written is not necessarily the one + affected by the command, but rather the line + addressed by the offset address specified. The + default for ffllaaggss is none. + + ffiillee + A pattern used to derive a pathname; the default + is the current file. File names are subjected to + normal _s_h(1) word expansions. + + Anywhere a file name is specified, it is also pos- + sible to use the special string "//ttmmpp". This will be + replaced with a temporary file name which can be used + for temporary work, e.g. "::ee //ttmmpp" creates and edits a + new file. + + If both a count and a range are specified for com- + mands that use either, the starting line for the com- + mand is the _l_a_s_t line addressed by the range, and + ccoouunntt- subsequent lines are affected by the command, + e.g. the command "22,,33pp44" prints out lines 3, 4, 5 and + 6. + + When only a line or range is specified, with no + command, the implied command is either a lliisstt, nnuummbbeerr + or pprriinntt command. The command used is the most recent + of the three commands to have been used (including any + use as a flag). If none of these commands have been + used before, the pprriinntt command is the implied command. + When no range or count is specified and the command + line is a blank line, the current line is incremented + by 1 and then the current line is displayed. + + Zero or more whitespace characters may precede or + follow the addresses, count, flags, or command name. + Any object following a command name (such as buffer, + file, etc.), that begins with an alphabetic character, + should be separated from the command name by at least + one whitespace character. + + Any character, including <<ccaarrrriiaaggee--rreettuurrnn>>, "%%" + and "##" retain their literal value when preceded by a + backslash. + + 1144.. EExx CCoommmmaannddss + + The following section describes the commands + available in the eexx editor. In each entry below, the + tag line is a usage synopsis for the command. + + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5511 + + + Each command can be entered as the abbreviation + (those characters in the synopsis command word preced- + ing the "[" character), the full command (all charac- + ters shown for the command word, omitting the "[" and + "]" characters), or any leading subset of the full com- + mand down to the abbreviation. For example, the args + command (shown as "aarr[[ggss]]" in the synopsis) can be + entered as "aarr", "aarrgg" or "aarrggss". + + Each eexx command described below notes the new cur- + rent line after it is executed, as well as any options + that affect the command. + + "" + A comment. Command lines beginning with the dou- + ble-quote character ("""") are ignored. This per- + mits comments in editor scripts and startup files. + + <<eenndd--ooff--ffiillee>> + Scroll the screen. Write the next N lines, where + N is the value of the ssccrroollll option. The command + is the end-of-file terminal character, which may + be different on different terminals. Tradition- + ally, it is the <<ccoonnttrrooll--DD>> key. + + Historically, the eeooff command ignored any preced- + ing count, and the <<eenndd--ooff--ffiillee>> character was + ignored unless it was entered as the first charac- + ter of the command. This implementation treats it + as a command _o_n_l_y if entered as the first charac- + ter of the command line, and otherwise treats it + as any other character. + + Line: Set to the last line written. + Options: None. + + !! aarrgguummeenntt((ss)) + [[rraannggee]]!! aarrgguummeenntt((ss)) + Execute a shell command, or filter lines through a + shell command. In the first synopsis, the remain- + der of the line after the "!!" character is passed + to the program named by the sshheellll option, as a + single argument. + + Within the rest of the line, "%%" and "##" are + expanded into the current and alternate pathnames, + respectively. The character "!!" is expanded with + the command text of the previous !! command. + (Therefore, the command !!!! repeats the previous !! + command.) The special meanings of "%%", "##", and + "!!" can be overridden by escaping them with a + backslash. If no !! or ::!! command has yet been + executed, it is an error to use an unescaped "!!" + + + + + + + + + + +UUSSDD::1133--5522 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + character. The !! command does _n_o_t do shell + expansion on the strings provided as arguments. + If any of the above expansions change the command + the user entered, the command is redisplayed at + the bottom of the screen. + + EExx then executes the program named by the sshheellll + option, with a --cc flag followed by the arguments + (which are bundled into a single argument). + + The !! command is permitted in an empty file. + + If the file has been modified since it was last + completely written, the command will warn you. + + A single "!!" character is displayed when the com- + mand completes. + + In the second form of the !! command, the remain- + der of the line after the "!!" is passed to the + program named by the sshheellll option, as described + above. The specified lines are passed to the pro- + gram as standard input, and the standard and stan- + dard error output of the program replace the orig- + inal lines. + + Line: Unchanged if no range was specified, oth- + erwise set to the first line of the + range. + Options: Affected by the aauuttoowwrriittee and wwrriitteeaannyy + options. + + [[rraannggee]] nnuu[[mmbbeerr]] [[ccoouunntt]] [[ffllaaggss]] + [[rraannggee]] ## [[ccoouunntt]] [[ffllaaggss]] + Display the selected lines, each preceded with its + line number. + + The line number format is "%6d", followed by two + spaces. + + Line: Set to the last line displayed. + Options: None. + + @@ bbuuffffeerr + ** bbuuffffeerr + Execute a buffer. Each line in the named buffer + is executed as an eexx command. If no buffer is + specified, or if the specified buffer is "@@" or + "**", the last buffer executed is used. + + [[rraannggee]] <<[[<< ......]] [[ccoouunntt]] [[ffllaaggss]] + Shift lines left or right. The specified lines + are shifted to the left (for the << command) or + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5533 + + + right (for the >> command), by the number of + columns specified by the sshhiiffttwwiiddtthh option. Only + leading whitespace characters are deleted when + shifting left; once the first column of the line + contains a nonblank character, the sshhiifftt command + will succeed, but the line will not be modified. + + If the command character << or >> is repeated more + than once, the command is repeated once for each + additional command character. + + Line: If the current line is set to one of the + lines that are affected by the command, + it is unchanged. Otherwise, it is set to + the first nonblank character of the low- + est numbered line shifted. + Options: Affected by the sshhiiffttwwiiddtthh option. + + [[lliinnee]] == [[ffllaaggss]] + Display the line number. Display the line number + of lliinnee (which defaults to the last line in the + file). + + Line: Unchanged. + Options: None. + + [[rraannggee]] >>[[>> ......]] [[ccoouunntt]] [[ffllaaggss]] + Shift right. The specified lines are shifted to + the right by the number of columns specified by + the sshhiiffttwwiiddtthh option, by inserting tab and space + characters. Empty lines are not changed. + + If the command character ">>" is repeated more than + once, the command is repeated once for each addi- + tional command character. + + Line: Set to the last line modified by the com- + mand. + Options: None. + + aabb[[bbrreevv]] llhhss rrhhss + Add an abbreviation to the current abbreviation + list. In vvii, if llhhss is entered such that it is + preceded and followed by characters that cannot be + part of a word, it is replaced by the string rrhhss. + + Line: Unchanged. + Options: None. + + [[lliinnee]] aa[[ppppeenndd]][[!!]] + The input text is appended to the specified line. + If line 0 is specified, the text is inserted at + the beginning of the file. Set to the last line + + + + + + + + + + +UUSSDD::1133--5544 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + input. If no lines are input, then set to lliinnee, + or to the first line of the file if a lliinnee of 0 + was specified. Following the command name with a + "!!" character causes the aauuttooiinnddeenntt option to be + toggled for the duration of the command. + + Line: Unchanged. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, + bbeeaauuttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraapp-- + mmaarrggiinn options. + + aarr[[ggss]] + Display the argument list. The current argument + is displayed inside of "[[" and "]]" characters. + The argument list is the list of operands speci- + fied on startup, which can be replaced using the + nneexxtt command. + + Line: Unchanged. + Options: None. + + bbgg + VVii mode only. Background the current screen. + + Line: Set to the current line when the screen + was last edited. + Options: None. + + [[rraannggee]] cc[[hhaannggee]][[!!]] [[ccoouunntt]] + Replace the lines with input text. Following the + command name with a "!!" character causes the + aauuttooiinnddeenntt option to be toggled for the duration + of the command. + + Line: Set to the last line input, or, if no + lines were input, set to the line before + the target line, or to the first line of + the file if there are no lines preceding + the target line. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, + bbeeaauuttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraapp-- + mmaarrggiinn options. + + cchhdd[[iirr]][[!!]] [[ddiirreeccttoorryy]] + ccdd[[!!]] [[ddiirreeccttoorryy]] + Change the current working directory. The ddiirreecc-- + ttoorryy argument is subjected to _s_h(1) word expan- + sions. When invoked with no directory argument + and the HHOOMMEE environment variable is set, the + directory named by the HHOOMMEE environment variable + becomes the new current directory. Otherwise, the + new current directory becomes the directory + returned by the _g_e_t_p_w_e_n_t(3) routine. + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5555 + + + The cchhddiirr command will fail if the file has been + modified since the last complete write of the + file. You can override this check by appending a + "!!" character to the command. + + Line: Unchanged. + Options: Affected by the ccddppaatthh option. + + [[rraannggee]] ccoo[[ppyy]] lliinnee [[ffllaaggss]] + [[rraannggee]] tt lliinnee [[ffllaaggss]] + Copy the specified lines (range) after the desti- + nation line. Line 0 may be specified to insert + the lines at the beginning of the file. + + Line: Unchanged. + Options: None. + + [[rraannggee]] dd[[eelleettee]] [[bbuuffffeerr]] [[ccoouunntt]] [[ffllaaggss]] + Delete the lines from the file. The deleted text + is saved in the specified buffer, or, if no buffer + is specified, in the unnamed buffer. If the com- + mand name is followed by a letter that could be + interpreted as either a buffer name or a flag + value (because neither a ccoouunntt or ffllaaggss values + were given), eexx treats the letter as a ffllaaggss value + if the letter immediately follows the command + name, without any whitespace separation. If the + letter is preceded by whitespace characters, it + treats it as a buffer name. + + Line: Set to the line following the deleted + lines, or to the last line if the deleted + lines were at the end. + Options: None. + + ddii[[ssppllaayy]] bb[[uuffffeerrss]] || ss[[ccrreeeennss]] || tt[[aaggss]] + Display buffers, screens or tags. The ddiissppllaayy + command takes one of three additional arguments, + which are as follows: + + b[uffers] + Display all buffers (including named, + unnamed, and numeric) that contain text. + s[creens] + Display the file names of all background + screens. + t[ags] Display the tags stack. + + Line: Unchanged. + Options: None. + + ee[[ddiitt]][[!!]] [[++ccmmdd]] [[ffiillee]] + + + + + + + + + + + +UUSSDD::1133--5566 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + eexx[[!!]] [[++ccmmdd]] [[ffiillee]] + Edit a different file. If the current buffer has + been modified since the last complete write, the + command will fail. You can override this by + appending a "!!" character to the command name. + + If the "++ccmmdd" option is specified, that eexx command + will be executed in the new file. Any eexx command + may be used, although the most common use of this + feature is to specify a line number or search pat- + tern to set the initial location in the new file. + + Line: If you have previously edited the file, + the current line will be set to your last + position in the file. If that position + does not exist, or you have not previ- + ously edited the file, the current line + will be set to the first line of the file + if you are in vvii mode, and the last line + of the file if you are in eexx. + Options: Affected by the aauuttoowwrriittee and wwrriitteeaannyy + options. + + eexxuu[[ssaaggee]] [[ccoommmmaanndd]] + Display usage for an eexx command. If ccoommmmaanndd is + specified, a usage statement for that command is + displayed. Otherwise, usage statements for all eexx + commands are displayed. + + Line: Unchanged. + Options: None. + + ff[[iillee]] [[ffiillee]] + Display and optionally change the file name. If a + file name is specified, the current pathname is + changed to the specified name. The current path- + name, the number of lines, and the current posi- + tion in the file are displayed. + + Line: Unchanged. + Options: None. + + ffgg [[nnaammee]] + VVii mode only. Foreground the specified screen. + Swap the current screen with the specified back- + grounded screen. If no screen is specified, the + first background screen is foregrounded. + + Line: Set to the current line when the screen + was last edited. + Options: None. + + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5577 + + + [[rraannggee]] gg[[lloobbaall]] //ppaatttteerrnn// [[ccoommmmaannddss]] + [[rraannggee]] vv //ppaatttteerrnn// [[ccoommmmaannddss]] + Apply commands to lines matching (or not matching) + a pattern. The lines within the given range that + match ("gg[[lloobbaall]]"), or do not match ("vv") the + given pattern are selected. Then, the specified + eexx command(s) are executed with the current line + ("..") set to each selected line. If no range is + specified, the entire file is searched for match- + ing, or not matching, lines. + + Multiple commands can be specified, one per line, + by escaping each <<nneewwlliinnee>> character with a back- + slash, or by separating commands with a "||" char- + acter. If no commands are specified, the command + defaults to the pprriinntt command. + + For the aappppeenndd, cchhaannggee and iinnsseerrtt commands, the + input text must be part of the global command + line. In this case, the terminating period can be + omitted if it ends the commands. + + The vviissuuaall command may also be specified as one of + the eexx commands. In this mode, input is taken + from the terminal. Entering a QQ command in vvii + mode causes the next line matching the pattern to + be selected and vvii to be reentered, until the list + is exhausted. + + The gglloobbaall, vv and uunnddoo commands cannot be used as + part of these commands. + + The editor options aauuttoopprriinntt, aauuttooiinnddeenntt, and + rreeppoorrtt are turned off for the duration of the + gglloobbaall and vv commands. + + Line: The last line modified. + Options: None. + + hhee[[llpp]] + Display a help message. + + Line: Unchanged. + Options: None. + + [[lliinnee]] ii[[nnsseerrtt]][[!!]] + The input text is inserted before the specified + line. Following the command name with a "!!" + character causes the aauuttooiinnddeenntt option setting to + be toggled for the duration of this command. + + Line: Set to the last line input; if no lines + were input, set to the line before the + + + + + + + + + + +UUSSDD::1133--5588 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + target line, or to the first line of the + file if there are no lines preceding the + target line. + Options: Affected by the aallttwweerraassee, aauuttooiinnddeenntt, + bbeeaauuttiiffyy, sshhoowwmmaattcchh, ttttyywweerraassee and wwrraapp-- + mmaarrggiinn options. + + [[rraannggee]] jj[[ooiinn]][[!!]] [[ccoouunntt]] [[ffllaaggss]] + Join lines of text together. + + A ccoouunntt specified to the command specifies that + the last line of the rraannggee plus ccoouunntt subsequent + lines will be joined. (Note, this differs by one + from the general rule where only ccoouunntt- subsequent + lines are affected.) + + If the current line ends with a whitespace charac- + ter, all whitespace is stripped from the next + line. Otherwise, if the next line starts with a + open parenthesis ("(("), do nothing. Otherwise, if + the current line ends with a question mark ("??"), + period ("..") or exclamation point ("!!"), insert + two spaces. Otherwise, insert a single space. + + Appending a "!!" character to the command name + causes a simpler join with no white-space process- + ing. + + Line: Unchanged. + Options: None. + + [[rraannggee]] ll[[iisstt]] [[ccoouunntt]] [[ffllaaggss]] + Display the lines unambiguously. Tabs are dis- + played as "^^II", and the end of the line is marked + with a "$$" character. + + Line: Set to the last line displayed. + Options: None. + + mmaapp[[!!]] [[llhhss rrhhss]] + Define or display maps (for vvii only). + + If "llhhss" and "rrhhss" are not specified, the current + set of command mode maps are displayed. If a "!!" + character is appended to to the command, the text + input mode maps are displayed. + + Otherwise, when the "llhhss" character sequence is + entered in vvii, the action is as if the correspond- + ing "rrhhss" had been entered. If a "!!" character + is appended to the command name, the mapping is + effective during text input mode, otherwise, it is + effective during command mode. This allows "llhhss" + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--5599 + + + to have two different macro definitions at the + same time: one for command mode and one for input + mode. + + Whitespace characters require escaping with a + <<lliitteerraallnext> character to be entered in the llhhss + string in visual mode. + + Normally, keys in the rrhhss string are remapped (see + the rreemmaapp option), and it is possible to create + infinite loops. However, keys which map to them- + selves are not further remapped, regardless of the + setting of the rreemmaapp option. For example, the + command "::mmaapp nn nnzz.." maps the "nn" key to the nn + and zz commands. + + To exit an infinitely looping map, use the termi- + nal <<iinntteerrrruupptt>> character. + + Line: Unchanged. + Options: None. + + [[lliinnee]] mmaa[[rrkk]] <<cchhaarraacctteerr>> + [[lliinnee]] kk <<cchhaarraacctteerr>> + Mark the line with the mark <<cchhaarraacctteerr>>. The + expressions "''<<cchhaarraacctteerr>>" and "``<<cchhaarraacctteerr>>" can + then be used as an address in any command that + uses one. + + Line: Unchanged. + Options: None. + + [[rraannggee]] mm[[oovvee]] lliinnee + Move the specified lines after the target line. A + target line of 0 places the lines at the beginning + of the file. + + Line: Set to the first of the moved lines. + Options: None. + + mmkk[[eexxrrcc]][[!!]] ffiillee + Write the abbreviations, editor options and maps + to the specified file. Information is written in + a form which can later be read back in using the + eexx ssoouurrccee command. If ffiillee already exists, the + mmkkeexxrrcc command will fail. This check can be over- + ridden by appending a "!!" character to the com- + mand. + + Line: Unchanged. + Options: None. + + + + + + + + + + + + +UUSSDD::1133--6600 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + nn[[eexxtt]][[!!]] [[ffiillee ......]] + Edit the next file from the argument list. The + nneexxtt command will fail if the file has been modi- + fied since the last complete write. This check + can be overridden by appending the "!!" character + to the command name. The argument list can + optionally be replaced by specifying a new one as + arguments to this command. In this case, editing + starts with the first file on the new list. + + Line: Set as described for the eeddiitt command. + Options: Affected by the options aauuttoowwrriittee and + wwrriitteeaannyy. + + [[lliinnee]] oo[[ppeenn]] //ppaatttteerrnn// [[ffllaaggss]] + Enter open mode. Open mode is the same as being + in vvii, but with a one-line window. All the stan- + dard vvii commands are available. If a match is + found for the optional RE argument, the cursor is + set to the start of the matching pattern. + + _T_h_i_s _c_o_m_m_a_n_d _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + + Line: Unchanged, unless the optional RE is + specified, in which case it is set to the + line where the matching pattern is found. + Options: Affected by the ooppeenn option. + + pprree[[sseerrvvee]] + Save the file in a form that can later be recov- + ered using the eexx --rr option. When the file is + preserved, an email message is sent to the user. + + Line: Unchanged. + Options: None. + + pprreevv[[iioouuss]][[!!]] + Edit the previous file from the argument list. + The pprreevviioouuss command will fail if the file has + been modified since the last complete write. This + check can be overridden by appending the "!!" + character to the command name. + + Line: Set as described for the eeddiitt command. + Options: Affected by the options aauuttoowwrriittee and + wwrriitteeaannyy. None. + + [[rraannggee]] pp[[rriinntt]] [[ccoouunntt]] [[ffllaaggss]] + Display the specified lines. + + Line: Set to the last line displayed. + Options: None. + + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--6611 + + + [[lliinnee]] ppuu[[tt]] [[bbuuffffeerr]] + Append buffer contents to the current line. If a + buffer is specified, its contents are appended to + the line, otherwise, the contents of the unnamed + buffer are used. + + Line: Set to the line after the current line. + Options: None. + + qq[[uuiitt]][[!!]] + End the editing session. If the file has been + modified since the last complete write, the qquuiitt + command will fail. This check may be overridden + by appending a "!!" character to the command. + + If there are more files to edit, the qquuiitt command + will fail. Appending a "!!" character to the com- + mand name or entering two qquuiitt commands (i.e. wwqq, + qquuiitt, xxiitt or ZZZZ) in a row) will override this + check and the editor will exit. + + Line: Unchanged. + Options: None. + + [[lliinnee]] rr[[eeaadd]][[!!]] [[ffiillee]] + Read a file. A copy of the specified file is + appended to the line. If lliinnee is 0, the copy is + inserted at the beginning of the file. If no file + is specified, the current file is read; if there + is no current file, then ffiillee becomes the current + file. If there is no current file and no ffiillee is + specified, then the rreeaadd command will fail. + + If ffiillee is preceded by a "!!" character, ffiillee is + treated as if it were a shell command, and passed + to the program named by the SSHHEELLLL environment + variable. The standard and standard error outputs + of that command are read into the file after the + specified line. The special meaning of the "!!" + character can be overridden by escaping it with a + backslash ("\\") character. + + Line: When executed from eexx, the current line + is set to the last line read. When exe- + cuted from vvii, the current line is set to + the first line read. + Options: None. + + rreecc[[oovveerr]] ffiillee + Recover ffiillee if it was previously saved. If no + saved file by that name exists, the rreeccoovveerr com- + mand behaves similarly to the eeddiitt command. + + + + + + + + + + + +UUSSDD::1133--6622 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + Line: Set as described for the eeddiitt command. + Options: None. + + rreess[[iizzee]] [[++||--]]ssiizzee + VVii mode only. Grow or shrink the current screen. + If ssiizzee is a positive, signed number, the current + screen is grown by that many lines. If ssiizzee is a + negative, signed number, the current screen is + shrunk by that many lines. If ssiizzee is not signed, + the current screen is set to the specified ssiizzee. + Applicable only to split screens. + + Line: Unchanged. + Options: None. + + rreeww[[iinndd]][[!!]] + Rewind the argument list. If the current file has + been modified since the last complete write, the + rreewwiinndd command will fail. This check may be over- + ridden by appending the "!!" character to the com- + mand. + + Otherwise, the current file is set to the first + file in the argument list. + + Line: Set as described for the eeddiitt command. + Options: Affected by the aauuttoowwrriittee and wwrriitteeaannyy + options. + + ssee[[tt]] [[ooppttiioonn[[==[[vvaalluuee]]]] ......]] [[nnooooppttiioonn ......]] [[ooppttiioonn?? + ......]] [[aallll]] + Display or set editor options. When no arguments + are specified, the editor option tteerrmm, and any + editor options whose values have been changed from + the default settings are displayed. If the argu- + ment aallll is specified, the values of all of editor + options are displayed. + + Specifying an option name followed by the charac- + ter "??" causes the current value of that option + to be displayed. The "??" can be separated from + the option name by whitespace characters. The "??" + is necessary only for Boolean valued options. + Boolean options can be given values by the form + "sseett ooppttiioonn" to turn them on, or "sseett nnooooppttiioonn" to + turn them off. String and numeric options can be + assigned by the form "sseett ooppttiioonn==vvaalluuee". Any + whitespace characters in strings can be included + literally by preceding each with a backslash. + More than one option can be set or listed by a + single set command, by specifying multiple argu- + ments, each separated from the next by whitespace + characters. + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--6633 + + + Line: Unchanged. + Options: None. + + sshh[[eellll]] + Run a shell program. The program named by the + sshheellll option is run with a --ii (for interactive) + flag. Editing is resumed when that program exits. + + Line: Unchanged. + Options: None. + + ssoo[[uurrccee]] ffiillee + Read and execute eexx commands from a file. SSoouurrccee + commands may be nested. + + Line: Unchanged. + Options: None. + + sspp[[lliitt]] [[ffiillee ......]] + VVii mode only. Split the screen. The current + screen is split into two screens, of approximately + equal size. If the cursor is in the lower half of + the screen, the screen will split up, i.e. the new + screen will be above the old one. If the cursor + is in the upper half of the screen, the new screen + will be below the old one. + + If ffiillee is specified, the new screen is editing + that file, otherwise, both screens are editing the + same file, and changes in each will be be + reflected in the other. The argument list for the + new screen consists of the list of files specified + as arguments to this command, or, the current + pathname if no files are specified. + + Line: If ffiillee is specified, set as for the eeddiitt + command, otherwise unchanged. + Options: None. + + [[rraannggee]] ss[[uubbssttiittuuttee]] [[//ppaatttteerrnn//rreeppllaaccee//]] [[ooppttiioonnss]] + [[ccoouunntt]] [[ffllaaggss]] + [[rraannggee]] && [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]] + [[rraannggee]] ~~ [[ooppttiioonnss]] [[ccoouunntt]] [[ffllaaggss]] + Make substitutions. Replace the first instance of + ppaatttteerrnn with the string rreeppllaaccee on the specified + line(s). If the "//ppaatttteerrnn//rreeppll//" argument is not + specified, the "//ppaatttteerrnn//rreeppll//" from the previous + ssuubbssttiittuuttee command is used. + + If ooppttiioonnss includes the letter "cc" (confirm), you + will be prompted for confirmation before each + replacement is done. An affirmative response (in + English, a "yy" character) causes the replacement + + + + + + + + + + +UUSSDD::1133--6644 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + to be made. A quit response (in English, a "qq" + character) causes the ssuubbssttiittuuttee command to be + terminated. Any other response causes the + replacement not to be made, and the ssuubbssttiittuuttee + command continues. If ooppttiioonnss includes the letter + "gg" (global), all nonoverlapping instances of ppaatt-- + tteerrnn in the line are replaced. + + The && version of the command is the same as not + specifying a pattern or replacement string to the + ssuubbssttiittuuttee command, and the "&&" is replaced by the + pattern and replacement information from the pre- + vious substitute command. + + The ~~ version of the command is the same as && and + ss, except that the search pattern used is the last + RE used in _a_n_y command, not necessarily the one + used in the last ssuubbssttiittuuttee command. + + For example, in the sequence + + ss//rreedd//bblluuee// + //ggrreeeenn + ~~ + + the "~~" is equivalent to "ss//ggrreeeenn//bblluuee//". + + The ssuubbssttiittuuttee command may be interrupted, using + the terminal interrupt character. All substitu- + tions completed before the interrupt are retained. + + Line: Set to the last line upon which a substi- + tution was made. + Options: None. + + ssuu[[ssppeenndd]][[!!]] + sstt[[oopp]][[!!]] + <<ccoonnttrrooll--ZZ>> + Suspend the edit session. Appending a "!!" char- + acter to these commands turns off the aauuttoowwrriittee + option for the command. + + Line: Unchanged. + Options: Affected by the aauuttoowwrriittee option. + + ttaa[[gg]][[!!]] ttaaggssttrriinngg + Edit the file containing the specified tag. + Search for the tagstring, which can be in a dif- + ferent file. If the tag is in a different file, + then the new file is edited. If the current file + has been modified since the last complete write, + the ttaagg command will fail. This check can be + overridden by appending the "!!" character to the + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--6655 + + + command name. + + The ttaagg command searches for ttaaggssttrriinngg in the tags + file(s) specified by the option. (See _c_t_a_g_s(1) + for more information on tags files.) + + Line: Set to the line indicated by the tag. + Options: Affected by the aauuttoowwrriittee, ttaagglleennggtthh, + ttaaggss and wwrriitteeaannyy options. + + ttaaggpp[[oopp]][[!!]] [[ffiillee || nnuummbbeerr]] + Pop to the specified tag in the tags stack. If + neither ffiillee or nnuummbbeerr is specified, the ttaaggppoopp + command pops to the most recent entry on the tags + stack. If ffiillee or nnuummbbeerr is specified, the ttaaggppoopp + command pops to the most recent entry in the tags + stack for that file, or numbered entry in the tags + stack, respectively. (See the ddiissppllaayy command for + information on displaying the tags stack.) + + If the file has been modified since the last com- + plete write, the ttaaggppoopp command will fail. This + check may be overridden by appending a "!!" char- + acter to the command name. + + Line: Set to the line indicated by the tag. + Options: Affected by the aauuttoowwrriittee, and wwrriitteeaannyy + options. + + ttaaggtt[[oopp]][[!!]] + Pop to the least recent tag on the tags stack, + clearing the tags stack. + + If the file has been modified since the last com- + plete write, the ttaaggppoopp command will fail. This + check may be overridden by appending a "!!" char- + acter to the command name. + + Line: Set to the line indicated by the tag. + Options: Affected by the aauuttoowwrriittee, and wwrriitteeaannyy + options. + + uunnaa[[bbbbrreevv]] llhhss + Delete an abbreviation. Delete llhhss from the cur- + rent list of abbreviations. + + Line: Unchanged. + Options: None. + + uu[[nnddoo]] + Undo the last change made to the file. Changes + made by gglloobbaall, vv, vviissuuaall and map sequences are + considered a single command. If repeated, the uu + + + + + + + + + + +UUSSDD::1133--6666 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + command alternates between these two states, and + is its own inverse. + + Line: Set to the last line modified by the com- + mand. + Options: None. + + uunnmm[[aapp]][[!!]] llhhss + Unmap a mapped string. Delete the command mode + map definition for llhhss. If a "!!" character is + appended to the command name, delete the text + input mode map definition instead. + + Line: Unchanged. + Options: None. + + vvee[[rrssiioonn]] + Display the version of the eexx//vvii editor. + + [[lliinnee]] vvii[[ssuuaall]] [[ttyyppee]] [[ccoouunntt]] [[ffllaaggss]] + EExx mode only. Enter vvii. The ttyyppee is optional, + and can be "--", "++" or "^^", as in the eexx zz com- + mand, to specify the the position of the specified + line in the screen window. (The default is to + place the line at the top of the screen window.) + A ccoouunntt specifies the number of lines that will + initially be displayed. (The default is the value + of the wwiinnddooww editor option.) + + Line: Unchanged unless lliinnee is specified, in + which case it is set to that line. + Options: None. + + vvii[[ssuuaall]][[!!]] [[++ccmmdd]] [[ffiillee]] + VVii mode only. Edit a new file. Identical to the + "eeddiitt[[!!]] [[++ccmmdd]] [[ffiillee]]" command. + + vviiuu[[ssaaggee]] [[ccoommmmaanndd]] + Display usage for a vvii command. If ccoommmmaanndd is + specified, a usage statement for that command is + displayed. Otherwise, usage statements for all vvii + commands are displayed. + + Line: Unchanged. + Options: None. + + [[rraannggee]] ww[[rriittee]][[!!]] [[>>>>]] [[ffiillee]] + [[rraannggee]] ww[[rriittee]] [[!!]] [[ffiillee]] + [[rraannggee]] wwnn[[!!]] [[>>>>]] [[ffiillee]] + [[rraannggee]] wwqq[[!!]] [[>>>>]] [[ffiillee]] + Write the file. The specified lines (the entire + file, if no range is given) is written to ffiillee. + If ffiillee is not specified, the current pathname is + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) UUSSDD::1133--6677 + + + used. If ffiillee is specified, and it exists, or if + the current pathname was set using the ffiillee com- + mand, and the file already exists, these commands + will fail. Appending a "!!" character to the com- + mand name will override this check and the write + will be attempted, regardless. + + Specifying the optional ">>>>" string will cause the + write to be appended to the file, in which case no + tests are made for the file already existing. + + If the file is preceded by a "!!" character, the + program named in the SHELL environment variable is + invoked with file as its second argument, and the + specified lines are passed as standard input to + that command. The "!!" in this usage must be sep- + arated from command name by at least one whites- + pace character. The special meaning of the "!!" + may be overridden by escaping it with a backslash + ("\\") character. + + The wwqq version of the write command will exit the + editor after writing the file, if there are no + further files to edit. Appending a "!!" character + to the command name or entering two "quit" com- + mands (i.e. wwqq, qquuiitt, xxiitt or ZZZZ) in a row) will + override this check and the editor will exit, + ignoring any files that have not yet been edited. + + The wwnn version of the write command will move to + the next file after writing the file, unless the + write fails. + + Line: Unchanged. + Options: Affected by the rreeaaddoonnllyy and wwrriitteeaannyy + options. + + [[rraannggee]] xx[[iitt]][[!!]] [[ffiillee]] + Write the file if it has been modified. The spec- + ified lines are written to ffiillee, if the file has + been modified since the last complete write to any + file. If no rraannggee is specified, the entire file + is written. + + The xxiitt command will exit the editor after writing + the file, if there are no further files to edit. + Appending a "!!" character to the command name or + entering two "quit" commands (i.e. wwqq, qquuiitt, xxiitt + or ZZZZ) in a row) will override this check and the + editor will exit, ignoring any files that have not + yet been edited. + + + + + + + + + + + + +UUSSDD::1133--6688 NNvvii//NNeexx RReeffeerreennccee ((EExx CCoommmmaannddss)) + + + Line: Unchanged. + Options: Affected by the rreeaaddoonnllyy and wwrriitteeaannyy + options. + + [[rraannggee]] yyaa[[nnkk]] [[bbuuffffeerr]] [[ccoouunntt]] + Copy the specified lines to a buffer. If no + buffer is specified, the unnamed buffer is used. + + Line: Unchanged. + Options: None. + + [[lliinnee]] zz [[ttyyppee]] [[ccoouunntt]] [[ffllaaggss]] + Adjust the window. If no ttyyppee is specified, then + ccoouunntt lines following the specified line are dis- + played. The default ccoouunntt is the value of the + wwiinnddooww option. The ttyyppee argument changes the + position at which lliinnee is displayed on the screen + by changing the number of lines displayed before + and after lliinnee. The following ttyyppee characters may + be used: + + - Place the line at the bottom of the + screen. + + Place the line at the top of the screen. + . Place the line in the middle of the + screen. + ^ Write out count lines starting ccoouunntt ** 22 + lines before lliinnee; the net effect of this + is that a "zz^^" command following a zz com- + mand writes the previous page. + = Center lliinnee on the screen with a line of + hyphens displayed immediately before and + after it. The number of preceding and + following lines of text displayed are + reduced to account for those lines. + + Line: Set to the last line displayed, with the + exception of the ttyyppee, where the current + line is set to the line specified by the + command. + Options: Affected by the option. + + 1155.. SSeett OOppttiioonnss + + There are a large number of options that may be + set (or unset) to change the editor's behavior. This + section describes the options, their abbreviations and + their default values. + + In each entry below, the first part of the tag + line is the full name of the option, followed by any + equivalent abbreviations. (Regardless of the abbrevia- + tions, it is only necessary to use the minimum number + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--6699 + + + of characters necessary to distinguish an abbreviation + from all other commands for it to be accepted, in + nneexx/nnvvii. Historically, only the full name and the + official abbreviations were accepted by eexx/vvii. Using + full names in your startup files and environmental + variables will probably make them more portable.) The + part in square brackets is the default value of the + option. Most of the options are boolean, i.e. they are + either on or off, and do not have an associated value. + + Options apply to both eexx and vvii modes, unless oth- + erwise specified. + + For information on modifying the options or to + display the options and their current values, see the + "set" command in the section entitled "EExx CCoommmmaannddss". + + aallttwweerraassee [[ooffff]] + VVii only. Change how vvii does word erase during + text input. When this option is set, text is bro- + ken up into three classes: alphabetic, numeric and + underscore characters, other nonblank characters, + and blank characters. Changing from one class to + another marks the end of a word. In addition, the + class of the first character erased is ignored + (which is exactly what you want when erasing path- + name components). + + aauuttooiinnddeenntt,, aaii [[ooffff]] + If this option is set, whenever you create a new + line (using the vvii AA, aa, CC, cc, II, ii, OO, oo, RR, rr, + SS, and ss commands, or the eexx aappppeenndd, cchhaannggee, and + iinnsseerrtt commands) the new line is automatically + indented to align the cursor with the first non- + blank character of the line from which you created + it. Lines are indented using tab characters to + the extent possible (based on the value of the + ttaabbssttoopp option) and then using space characters as + necessary. For commands inserting text into the + middle of a line, any blank characters to the + right of the cursor are discarded, and the first + nonblank character to the right of the cursor is + aligned as described above. + + The indent characters are themselves somewhat spe- + cial. If you do not enter more characters on the + new line before moving to another line, or enter- + ing <<eessccaappee>>, the indent character will be deleted + and the line will be empty. For example, if you + enter <<ccaarrrriiaaggee--rreettuurrnn>> twice in succession, the + line created by the first <<ccaarrrriiaaggee--rreettuurrnn>> will + not have any characters in it, regardless of the + indentation of the previous or subsequent line. + + + + + + + + + + +UUSSDD::1133--7700 NNvvii//NNeexx RReeffeerreennccee + + + Indent characters also require that you enter + additional erase characters to delete them. For + example, if you have an indented line, containing + only blanks, the first <<wwoorrdd--eerraassee>> character you + enter will erase up to end of the indent charac- + ters, and the second will erase back to the begin- + ning of the line. (Historically, only the <<ccoonn-- + ttrrooll--DD>> key would erase the indent characters. + Both the <<ccoonnttrrooll--DD>> key and the usual erase keys + work in nnvvii.) In addition, if the cursor is posi- + tioned at the end of the indent characters, the + keys "00<<ccoonnttrrooll--DD>>" will erase all of the indent + characters for the current line, resetting the + indentation level to 0. Similarly, the keys + "^^<<ccoonnttrrooll--DD>>" will erase all of the indent char- + acters for the current line, leaving the indenta- + tion level for future created lines unaffected. + + Finally, if the aauuttooiinnddeenntt option is set, the SS + and cccc commands change from the first nonblank of + the line to the end of the line, instead of from + the beginning of the line to the end of the line. + + aauuttoopprriinntt,, aapp [[ooffff]] + EExx only. Cause the current line to be automati- + cally displayed after the eexx commands <<, >>, ccooppyy, + ddeelleettee, jjooiinn, mmoovvee, ppuutt, tt, UUnnddoo, and uunnddoo. This + automatic display is suppressed during gglloobbaall and + vvgglloobbaall commands, and for any command where + optional flags are used to explicitly display the + line. + + aauuttoowwrriittee,, aaww [[ooffff]] + If this option is set, the vvii !!, ^^^^, ^^]] and <<ccoonn-- + ttrrooll--ZZ>> commands, and the eexx eeddiitt, nneexxtt, rreewwiinndd, + ssttoopp, ssuussppeenndd, ttaagg, ttaaggppoopp, and ttaaggttoopp commands + automatically write the current file back to the + current file name if it has been modified since it + was last written. If the write fails, the command + fails and goes no further. + + Appending the optional force flag character "!!" + to the eexx commands nneexxtt, rreewwiinndd, ssttoopp, ssuussppeenndd, + ttaagg, ttaaggppoopp, and ttaaggttoopp stops the automatic write + from being attempted. + + (Historically, the nneexxtt command ignored the + optional force flag.) Note, the eexx commands eeddiitt, + qquuiitt, sshheellll, and xxiitt are _n_o_t affected by the + aauuttoowwrriittee option. + + bbeeaauuttiiffyy,, bbff [[ooffff]] + If this option is set, all control characters that + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7711 + + + are not currently being specially interpreted, + other than <<ttaabb>>, <<nneewwlliinnee>>, and <<ffoorrmm--ffeeeedd>>, are + discarded from commands read in by eexx from command + files, and from input text entered to vvii (either + into the file or to the colon command line). Text + files read by eexx/vvii are _n_o_t affected by the bbeeaauu-- + ttiiffyy option. + + ccddppaatthh [[eennvviirroonnmmeenntt vvaarriiaabbllee CCDDPPAATTHH,, oorr ccuurrrreenntt ddiirreecc-- + ttoorryy]] + This option is used to specify a colon separated + list of directories which are used as path pre- + fixes for any relative path names used as argu- + ments for the ccdd command. The value of this + option defaults to the value of the environmental + variable CCDDPPAATTHH if it is set, otherwise to the + current directory. For compatibility with the + POSIX 1003.2 shell, the ccdd command does _n_o_t check + the current directory as a path prefix for rela- + tive path names unless it is explicitly specified. + It may be so specified by entering an empty string + or a ".." character into the CCDDPPAATTHH variable or + the option value. + + ccoolluummnnss,, ccoo [[8800]] + The number of columns in the screen. Setting this + option causes eexx/vvii to set (or reset) the environ- + mental variable CCOOLLUUMMNNSS. See the section entitled + "SSiizziinngg tthhee SSccrreeeenn" more information. + + ccoommmmeenntt [[ooffff]] + VVii only. If the first non-empty line of the file + begins with the string "//**", this option causes vvii + to skip to the end of that C-language comment + (probably a terribly boring legal notice) before + displaying the file. + + ddiirreeccttoorryy,, ddiirr [[eennvviirroonnmmeenntt vvaarriiaabbllee TTMMPPDDIIRR,, oorr //ttmmpp]] + The directory where temporary files are created. + The environmental variable TTMMPPDDIIRR is used as the + default value if it exists, otherwise //ttmmpp is + used. + + eeddccoommppaattiibbllee,, eedd [[ooffff]] + Remember the values of the "c" and "g" suffices to + the ssuubbssttiittuuttee commands, instead of initializing + them as unset for each new command. Specifying + pattern and replacement strings to the ssuubbssttiittuuttee + command unsets the "c" and "g" suffices as well. + + eerrrroorrbbeellllss,, eebb [[ooffff]] + EExx only. EExx error messages are normally presented + in inverse video. If that is not possible for the + + + + + + + + + + +UUSSDD::1133--7722 NNvvii//NNeexx RReeffeerreennccee + + + terminal, setting this option causes error mes- + sages to be announced by ringing the terminal + bell. + + eexxrrcc,, eexx [[ooffff]] + If this option is turned off in the system or + $HOME startup files, the local startup files are + never read (unless they are the same as the system + or $HOME startup files). Turning it on has no + effect, i.e. the normal checks for local startup + files are performed, regardless. See the section + entitled "SSttaarrttuupp IInnffoorrmmaattiioonn" for more informa- + tion. + + eexxtteennddeedd [[ooffff]] + This option causes all regular expressions to be + treated as POSIX 1003.2 Extended Regular Expres- + sions (which are similar to historic _e_g_r_e_p(1) + style expressions). + + ffllaasshh [[oonn]] + This option causes the screen to flash instead of + beeping the keyboard, on error, if the terminal + has the capability. + + hhaarrddttaabbss,, hhtt [[88]] + This option defines the spacing between hardware + tab settings, i.e. the tab expansion done by the + operating system and/or the terminal itself. As + nneexx/nnvvii never writes <<ttaabb>> characters to the ter- + minal, unlike historic versions of eexx/vvii, this + option does not currently have any affect. + + iiggnnoorreeccaassee,, iicc [[ooffff]] + This option causes regular expressions, both in eexx + commands and in searches, to be evaluated in a + case-insensitive manner. + + kkeeyyttiimmee [[66]] + The 10th's of a second eexx/vvii waits for a subse- + quent key to complete a key mapping. + + lleeffttrriigghhtt [[ooffff]] + VVii only. This option causes the screen to be + scrolled left-right to view lines longer than the + screen, instead of the traditional vvii screen + interface which folds long lines at the right-hand + margin of the terminal. + + lliinneess,, llii [[2244]] + VVii only. The number of lines in the screen. Set- + ting this option causes eexx/vvii to set (or reset) + the environmental variable LLIINNEESS. See the section + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7733 + + + entitled "SSiizziinngg tthhee SSccrreeeenn" for more information. + + lliisspp [[ooffff]] + VVii only. This option changes the behavior of the + vvii ((, )), {{, }}, [[[[ and ]]]] commands to match the + Lisp language. Also, the aauuttooiinnddeenntt option's + behavior is changed to be appropriate for Lisp. + + _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + + lliisstt [[ooffff]] + This option causes lines to be displayed in an + unambiguous fashion. Specifically, tabs are dis- + played as control characters, i.e. "^^II", and the + ends of lines are marked with a "$$" character. + + mmaaggiicc [[oonn]] + This option is on by default. Turning the mmaaggiicc + option off causes all regular expression charac- + ters except for "^^" and "$$", to be treated as + ordinary characters. To re-enable characters + individually, when the mmaaggiicc option is off, pre- + cede them with a backslash "\\" character. See the + section entitled "RReegguullaarr EExxpprreessssiioonnss aanndd RReeppllaaccee-- + mmeenntt SSttrriinnggss" for more information. + + mmaattcchhttiimmee [[77]] + VVii only. The 10th's of a second eexx/vvii pauses on + the matching character when the sshhoowwmmaattcchh option + is set. + + mmeessgg [[oonn]] + This option allows other users to contact you + using the _t_a_l_k(1) and _w_r_i_t_e(1) utilities, while + you are editing. EExx/vvii does not turn message on, + i.e. if messages were turned off when the editor + was invoked, they will stay turned off. This + option only permits you to disallow messages for + the edit session. See the _m_e_s_g(1) utility for + more information. + + mmooddeelliinneess,, mmooddeelliinnee [[ooffff]] + If the mmooddeelliinneess option is set, eexx/vvii has histori- + cally scanned the first and last five lines of + each file as it is read for editing, looking for + any eexx commands that have been placed in those + lines. After the startup information has been + processed, and before the user starts editing the + file, any commands embedded in the file are exe- + cuted. + + Commands were recognized by the letters "e" or "v" + followed by "x" or "i", at the beginning of a line + + + + + + + + + + +UUSSDD::1133--7744 NNvvii//NNeexx RReeffeerreennccee + + + or following a tab or space character, and fol- + lowed by a ":", an eexx command, and another ":". + + This option is a security problem of immense pro- + portions, and should not be used under any circum- + stances. + + _T_h_i_s _o_p_t_i_o_n _w_i_l_l _n_e_v_e_r _b_e _i_m_p_l_e_m_e_n_t_e_d_. + + nnuummbbeerr,, nnuu [[ooffff]] + Precede each line displayed with its current line + number. + + ooccttaall [[ooffff]] + Display unknown characters as octal numbers, + instead of the default hexadecimal. + + ooppeenn [[oonn]] + EExx only. If this option is not set, the ooppeenn and + vviissuuaall commands are disallowed. + + ooppttiimmiizzee,, oopptt [[oonn]] + VVii only. Throughput of text is expedited by set- + ting the terminal not to do automatic carriage + returns when printing more than one (logical) line + of output, greatly speeding output on terminals + without addressable cursors when text with leading + white space is printed. + + _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + + ppaarraaggrraapphhss,, ppaarraa [[IIPPLLPPPPPPQQPPPP LLIIppppllppiippbbpp]] + VVii only. Define additional paragraph boundaries + for the {{ and }} commands. The value of this + option must be a character string consisting of + zero or more character pairs. + + In the text to be edited, the character string + <<nneewwlliinnee>>..<<cchhaarr--ppaaiirr>>, (where <<cchhaarr--ppaaiirr>> is one + of the character pairs in the option's value) + defines a paragraph boundary. For example, if the + option were set to LLaaAA<<ssppaaccee>>####, then all of the + following additional paragraph boundaries would be + recognized: + + + <newline>.La + <newline>.A<space> + <newline>.## + + + pprroommpptt [[oonn]] + EExx only. This option causes eexx to prompt for + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7755 + + + command input with a "::" character; when it is not + set, no prompt is displayed. + + rreeaaddoonnllyy,, rroo [[ooffff]] + This option causes a force flag to be required to + attempt to write the file back to the original + file name. Setting this option is equivalent to + using the --RR command line option, or editing a + file which lacks write permission. + + rreeccddiirr [[//vvaarr//ttmmpp//vvii..rreeccoovveerr]] + The directory where recovery files are stored. + + If you change the value of rreeccddiirr, be careful to + choose a directory whose contents are not regu- + larly deleted. Bad choices include directories in + memory based filesystems, or //ttmmpp, on most sys- + tems, as their contents are removed when the + machine is rebooted. + + Public directories like //uussrr//ttmmpp and //vvaarr//ttmmpp are + usually safe, although some sites periodically + prune old files from them. There is no require- + ment that you use a public directory, e.g. a sub- + directory of your home directory will work fine. + + Finally, if you change the value of rreeccddiirr, you + must modify the recovery script to operate in your + chosen recovery area. + + See the section entitled "RReeccoovveerryy" for further + information. + + rreeddrraaww,, rree [[ooffff]] + VVii only. The editor simulates (using great + amounts of output), an intelligent terminal on a + dumb terminal (e.g. during insertions in vvii the + characters to the right of the cursor are + refreshed as each input character is typed). + + _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + + rreemmaapp [[oonn]] + If this option is set, it is possible to define + macros in terms of other macros. Otherwise, each + key is only remapped up to one time. For example, + if "AA" is mapped to "BB", and "BB" is mapped to "CC", + The keystroke "AA" will be mapped to "CC" if the + rreemmaapp option is set, and to "BB" if it is not set. + + rreeppoorrtt [[55]] + Set the threshold of the number of lines that need + to be changed or yanked before a message will be + + + + + + + + + + +UUSSDD::1133--7766 NNvvii//NNeexx RReeffeerreennccee + + + displayed to the user. For everything but the + yank command, the value is the largest value about + which the editor is silent, i.e. by default, 6 + lines must be deleted before the user is notified. + However, if the number of lines yanked is greater + than _o_r _e_q_u_a_l _t_o the set value, it is reported to + the user. + + rruulleerr [[ooffff]] + VVii only. Display a row/column ruler on the colon + command line. + + ssccrroollll,, ssccrr [[wwiinnddooww // 22]] + Set the number of lines scrolled by the vvii <<ccoonn-- + ttrrooll--DD>> and <<ccoonnttrrooll--UU>> commands. + + Historically, the eexx zz command, when specified + without a count, used two times the size of the + scroll value; the POSIX 1003.2 standard specified + the window size, which is a better choice. + + sseeccttiioonnss,, sseecctt [[NNHHSSHHHH HHUUnnhhsshh]] + VVii only. Define additional section boundaries for + the [[[[ and ]]]] commands. The sseeccttiioonnss option + should be set to a character string consisting of + zero or more character pairs. In the text to be + edited, the character string <<nneewwlliinnee>>..<<cchhaarr-- + ppaaiirr>>, (where <<cchhaarr--ppaaiirr>> is one of the character + pairs in the option's value), defines a section + boundary in the same manner that ppaarraaggrraapphh option + boundaries are defined. + + sshheellll,, sshh [[eennvviirroonnmmeenntt vvaarriiaabbllee SSHHEELLLL,, oorr //bbiinn//sshh]] + Select the shell used by the editor. The speci- + fied path is the pathname of the shell invoked by + the vvii !! shell escape command and by the eexx sshheellll + command. This program is also used to resolve any + shell meta-characters in eexx commands. + + sshhiiffttwwiiddtthh,, ssww [[88]] + Set the autoindent and shift command indentation + width. This width is used by the aauuttooiinnddeenntt + option and by the <<, >>, and sshhiifftt commands. + + sshhoowwddiirrttyy [[ooffff]] + VVii only. Display an asterisk on the colon command + line if the file has been modified. + + sshhoowwmmaattcchh,, ssmm [[ooffff]] + VVii only. This option causes vvii, when a "}}" or "))" + is entered, to briefly move the cursor the match- + ing "{{" or "((". See the mmaattcchhttiimmee option for more + information. + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7777 + + + sshhoowwmmooddee [[ooffff]] + VVii only. This option causes vvii to display a + string identifying the current editor mode on the + colon command line. + + ssiiddeessccrroollll [[1166]] + VVii only. Sets the number of columns that are + shifted to the left or right, when vvii is doing + left-right scrolling and the left or right margin + is crossed. See the lleeffttrriigghhtt option for more + information. + + sslloowwooppeenn,, ssllooww [[ooffff]] + This option affects the display algorithm used by + vvii, holding off display updating during input of + new text to improve throughput when the terminal + in use is slow and unintelligent. + + _T_h_i_s _o_p_t_i_o_n _i_s _n_o_t _y_e_t _i_m_p_l_e_m_e_n_t_e_d_. + + ssoouurrcceeaannyy [[ooffff]] + If this option is turned on, vvii historically read + startup files that were owned by someone other + than the editor user. See the section entitled + "SSttaarrttuupp IInnffoorrmmaattiioonn" for more information. This + option is a security problem of immense propor- + tions, and should not be used under any circum- + stances. + + _T_h_i_s _o_p_t_i_o_n _w_i_l_l _n_e_v_e_r _b_e _i_m_p_l_e_m_e_n_t_e_d_. + + ttaabbssttoopp,, ttss [[88]] + This option sets tab widths for the editor dis- + play. + + ttaagglleennggtthh,, ttll [[00]] + This option sets the maximum number of characters + that are considered significant in a tag name. + Setting the value to 0 makes all of the characters + in the tag name significant. + + ttaaggss,, ttaagg [[ttaaggss //vvaarr//ddbb//lliibbcc..ttaaggss //ssyyss//kkeerrnn//ttaaggss]] + Sets the list of tags files, in search order, + which are used when the editor searches for a tag. + + tteerrmm,, ttttyyttyyppee,, ttttyy [[eennvviirroonnmmeenntt vvaarriiaabbllee TTEERRMM]] + Set the terminal type. Setting this option causes + eexx/vvii to set (or reset) the environmental variable + TTEERRMM. + + tteerrssee [[ooffff]] + This option has historically made editor messages + less verbose. It has no effect in this + + + + + + + + + + +UUSSDD::1133--7788 NNvvii//NNeexx RReeffeerreennccee + + + implementation. See the vveerrbboossee option for more + information. + + ttiillddeeoopp + Modify the ~~ command to take an associated motion. + + ttiimmeeoouutt,, ttoo [[oonn]] + If this option is set, eexx/vvii waits for a specific + period for a subsequent key to complete a key map- + ping (see the kkeeyyttiimmee option). If the option is + not set, the editor waits until enough keys are + entered to resolve the ambiguity, regardless of + how long it takes. + + ttttyywweerraassee [[ooffff]] + VVii only. This option changes how vvii does word + erase during text input. If this option is set, + text is broken up into two classes, blank charac- + ters and nonblank characters. Changing from one + class to another marks the end of a word. + + vveerrbboossee [[ooffff]] + VVii only. VVii historically bells the terminal for + many obvious mistakes, e.g. trying to move past + the left-hand margin, or past the end of the file. + If this option is set, an error message is dis- + played for all errors. + + ww330000 [[nnoo ddeeffaauulltt]] + VVii only. Set the window size if the baud rate is + less than 1200 baud. See the wwiinnddooww option for + more information. + + ww11220000 [[nnoo ddeeffaauulltt]] + VVii only. Set the window size if the baud rate is + equal to 1200 baud. See the wwiinnddooww option for + more information. + + ww99660000 [[nnoo ddeeffaauulltt]] + VVii only. Set the window size if the baud rate is + greater than 1200 baud. See the wwiinnddooww option for + more information. + + wwaarrnn [[oonn]] + EExx only. This option causes a warning message to + the terminal if the file has been modified, since + it was last written, before a !! command. + + wwiinnddooww,, ww,, wwii [[eennvviirroonnmmeenntt vvaarriiaabbllee LLIINNEESS]] + This option determines the default number of lines + in a screenful, as written by the zz command. It + also determines the number of lines scrolled by + the vvii commands <<ccoonnttrrooll--FF>> and <<ccoonnttrrooll--BB>>. The + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--7799 + + + value of window can be unrelated to the real + screen size, although it starts out as the number + of lines on the screen (see the section entitled + "SSiizziinngg tthhee SSccrreeeenn" for more information). Set- + ting the value of the wwiinnddooww option is the same as + using the --ww command line option. + + If the value of the wwiinnddooww option (as set by the + wwiinnddooww, ww330000, ww11220000 or ww99660000 options) is smaller + than the actual size of the screen, large screen + movements will result in displaying only that + smaller number of lines on the screen. (Further + movements in that same area will result in the + screen being filled.) This can provide a perfor- + mance improvement when viewing different places in + one or more files over a slow link. + + wwrraappmmaarrggiinn,, wwmm [[00]] + VVii only. If the value of the wwrraappmmaarrggiinn option is + non-zero, vvii will split lines so that they end at + least that number of characters before the right- + hand margin of the screen. (Note, the value of + wwrraappmmaarrggiinn is _n_o_t a text length. In a screen that + is 80 columns wide, the command "::sseett wwrraappmmaarr-- + ggiinn==88" attempts to keep the lines less than or + equal to 72 columns wide.) + + Lines are split at the previous whitespace charac- + ter closest to the number. Any trailing whites- + pace characters before that character are deleted. + If the line is split because of an inserted + <<ssppaaccee>> or <<ttaabb>> character, and you then enter + another <<ssppaaccee>> character, it is discarded. + + If wrapmargin is set to 0, or if there is no blank + character upon which to split the line, the line + is not broken. + + wwrraappssccaann,, wwss [[oonn]] + This option causes searches to wrap around the end + or the beginning of the file, and back to the + starting point. Otherwise, the end or beginning + of the file terminates the search. + + wwrriitteeaannyy,, wwaa [[ooffff]] + If this option is set, file-overwriting checks + that would usually be made before the wwrriittee and + xxiitt commands, or before an automatic write (see + the aauuttoowwrriittee option), are not made. This allows + a write to any file, provided the file permissions + allow it. + + + + + + + + + + + + +UUSSDD::1133--8800 NNvvii//NNeexx RReeffeerreennccee + + + 1166.. AAddddiittiioonnaall FFeeaattuurreess iinn NNeexx//NNvvii + + There are a few features in nneexx/nnvvii that are not + found in historic versions of eexx/vvii. Some of the more + interesting of those features are as follows: + + 88--bbiitt cclleeaann ddaattaa,, llaarrggee lliinneess,, ffiilleess + NNeexx/nnvvii will edit any format file. Line lengths + are limited by available memory, and file sizes + are limited by available disk space. The vvii text + input mode command <<ccoonnttrrooll--XX>> can insert any pos- + sible character value into the text. + + SSpplliitt ssccrreeeennss + The sspplliitt command divides the screen into multiple + editing regions. The <<ccoonnttrrooll--WW>> command rotates + between the foreground screens. The rreessiizzee com- + mand can be used to grow or shrink a particular + screen. + + BBaacckkggrroouunndd aanndd ffoorreeggrroouunndd ssccrreeeennss + The bbgg command backgrounds the current screen, and + the ffgg command foregrounds backgrounded screens. + The ddiissppllaayy command can be used to list the back- + ground screens. + + TTaagg ssttaacckkss + Tags are now maintained in a stack. The <<ccoonnttrrooll-- + TT>> command returns to the previous tag location. + The ttaaggppoopp command returns to the most recent tag + location by default, or, optionally to a specific + tag number in the tag stack, or the most recent + tag from a specified file. The ddiissppllaayy command + can be used to list the tags stack. The ttaaggttoopp + command returns to the top of the tag stack. + + NNeeww ddiissppllaayyss + The ddiissppllaayy command can be used to display the + current buffers, the backgrounded screens, and the + tags stack. + + IInnffiinniittee uunnddoo + Changes made during an edit session may be rolled + backward and forward. A .. command immediately + after a uu command continues either forward or + backward depending on whether the uu command was an + undo or a redo. + + UUssaaggee iinnffoorrmmaattiioonn + The eexxuussaaggee and vviiuussaaggee commands provide usage + information for all of the eexx and vvii commands by + default, or, optionally, for a specific command or + key. + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--8811 + + + EExxtteennddeedd RReegguullaarr EExxpprreessssiioonnss + The eexxtteennddeedd option causes Regular Expressions to + be interpreted as as Extended Regular Expressions, + (i.e. _e_g_r_e_p(1) style Regular Expressions). + + WWoorrdd sseeaarrcchh + The <<ccoonnttrrooll--AA>> command searches for the word ref- + erenced by the cursor. + + NNuummbbeerr iinnccrreemmeenntt + The ## command increments or decrements the number + referenced by the cursor. + + PPrreevviioouuss ffiillee + The pprreevviioouuss command edits the previous file from + the argument list. + + LLeefftt--rriigghhtt ssccrroolllliinngg + The lleeffttrriigghhtt option causes nnvvii to do left-right + screen scrolling, instead of the traditional vvii + line wrapping. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +UUSSDD::1133--8822 NNvvii//NNeexx RReeffeerreennccee + + + 1177.. IInnddeexx + + ! 15, 34 @ 20, 35 columns 47 + "" 34 A 20 comment 47 + # 16, 35 B 20 copy 36 + $ 16 C 21 count 10, 33 + % 16 D 21 current pathname 8 + & 17, 42 E 21 d 26 + ( 17 F 21 delete 37 + ) 17 G 21 directory 47 + * 35 H 21 display 37 + + 13 I 22 e 26 + , 18 J 22 edcompatible47 + /RE/ 18 L 22 edit 37 + 0 19 M 22 errorbells 47 + 0<control-D>31 N 18 exrc 47 + : 19 O 22 extended 48 + ; 19 P 23 exusage 37 + < 20, 35 Q 23 f 26 + <control-A> 11 R 23 fg 37 + <control-B> 11 S 23 file 33, 37 + <control-1D2>, 31 T 23 flags 33 + <control-E> 12 U 23 flash 48 + <control-F> 12 W 24 global 38 + <control-G> 12 X 24 hardtabs 48 + <control-1H2>, 31 Y 24 help 38 + <control-J> 13 ZZ 24 i 26 + <control-L> 13 [[ 24 ignorecase 48 + <control-M> 13 - 18 insert 38 + <control-N> 13 ]] 25 j 13 + <control-P> 13 ^ 25 join 38 + <control-R> 13 ^<control-D>31 k 13, 39 + <control-1T4>, 31 _ 25 keytime 48 + <control-U> 14 `<character>17 l 15 + <control-1W4>, 31 a 25 leftright 48 + <control-X> 31 abbrev 35 line 33 + <control-Y> 14 alternate pathname 8 lines 48 + <control-1Z4>, 43 altwerase 46 lisp 48 + <control-]> 15 append 36 list 39, 48 + <control-^> 15 args 36 m 27 + <end-of-file> 34 autoindent 46 magic 48 + <eof> 33 autoprint 46 map 39 + <erase> 31 autowrite 47 mark 39 + <escape>14, 31 b 25 matchtime 48 + <inter7r,up3t0>, 31 beautify 47 mesg 48 + <line erase>31 bg 36 mkexrc 39 + <literal next> 7, 31 bigword 10 modelines 49 + <nul> 30 buffer 8 motion 10 + <space> 15 c 26 move 39 + <word erase>31 cd 36 n 18 + = 35 cdpath 47 next 40 + > 20, 35 change 36 number 35, 49 + ?RE? 18 chdir 36 o 27 + + + + + + + + + + +NNvvii//NNeexx RReeffeerreennccee UUSSDD::1133--8833 + + + octal 49 tildeop 51 + open 40, 49 timeout 51 + optimize 49 ttywerase 52 + p 27 u 28 + paragraph 11 unabbrev 44 + paragraphs 49 undo 44 + preserve 40 unmap 44 + previous 40 unnamed buffer 8 + previous context 9 v 38 + print 40 verbose 52 + prompt 49 version 44 + put 40 visual 44 + quit 41 viusage 44 + r 27 w 28 + range 33 w1200 52 + read 41 w300 52 + readonly 49 w9600 52 + recdir 49 warn 52 + recover 41 window 52 + redraw 50 wn 44 + remap 50 word 10 + report 50 wq 44 + resize 41 wrapmargin 52 + rewind 41 wrapscan 52 + ruler 50 write 44 + s 27 writeany 53 + scroll 50 x 28 + section 11 xit 45 + sections 50 y 28 + sentence 11 yank 45 + set 41 z 28, 45 + shell 42, 50 { 29 + shiftwidth 50 | 29 + showdirty 51 } 29 + showmatch 51 ~ 29, 30, 42 + showmode 51 + sidescroll 51 + slowopen 51 + source 42 + sourceany 51 + split 42 + stop 43 + substitute 42 + suspend 43 + t 27, 36 + tabstop 51 + tag 43 + taglength 51 + tagpop 43 + tags 51 + tagtop 43 + term 51 + terse 51 + + + + + + + + + + +UUSSDD::1133--22 NNvvii//NNeexx RReeffeerreennccee + + + TTaabbllee ooff CCoonntteennttss + + Description ...................................... 3 + Startup Information .............................. 3 + Recovery ......................................... 4 + Sizing the Screen ................................ 7 + Character Display ................................ 7 + Multiple Screens ................................. 8 + Regular Expressions and Replacement Strings ...... 9 + General Editor Description ....................... 10 + Vi Description ................................... 12 + Vi Commands ...................................... 17 + Vi Text Input Commands ........................... 45 + Ex Addressing .................................... 47 + Ex Description ................................... 49 + Ex Commands ...................................... 50 + Set Options ...................................... 68 + Additional Features in Nex/Nvi ................... 79 + Index ............................................ 82 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/usr.bin/vi/USD.doc/vitut/Makefile b/usr.bin/vi/USD.doc/vitut/Makefile new file mode 100644 index 0000000..bfb29bf --- /dev/null +++ b/usr.bin/vi/USD.doc/vitut/Makefile @@ -0,0 +1,17 @@ +# @(#)Makefile 8.1 (Berkeley) 8/14/93 + +DIR= usd/12.vi +SRCS= vi.in vi.chars +MACROS= -msU +CLEANFILES+=summary.* viapwh.* + +paper.ps: ${SRCS} summary.ps viapwh.ps + ${TBL} ${SRCS} | ${ROFF} > ${.TARGET} + +summary.ps: vi.summary + ${TBL} vi.summary | ${ROFF} > ${.TARGET} + +viapwh.ps: vi.apwh.ms + ${ROFF} vi.apwh.ms > ${.TARGET} + +.include <bsd.doc.mk> diff --git a/usr.bin/vi/USD.doc/vitut/vi.apwh.ms b/usr.bin/vi/USD.doc/vitut/vi.apwh.ms new file mode 100644 index 0000000..d0b6261 --- /dev/null +++ b/usr.bin/vi/USD.doc/vitut/vi.apwh.ms @@ -0,0 +1,1079 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vi.apwh.ms 8.1 (Berkeley) 6/8/93 +.\" +.TL +Vi Command & Function Reference +.AU CB 2675 +Alan P.W. Hewett +.sp +Revised for version 2.12 by Mark Horton +.CB +.NH 1 +Author's Disclaimer +.LP +This document does not claim to be 100% complete. There are a +few commands listed in the original document that I was unable +to test either because I do not speak \fBlisp\fR, because they +required programs we don't have, or because I wasn't able to make +them work. In these cases I left the command out. The commands +listed in this document have been tried and are known to work. +It is expected that prospective users of this document will read +it once to get the flavor of everything that \fBvi\fR can do +and then use it as a reference document. Experimentation is +recommended. If you don't understand a command, try it and +see what happens. +.LP +[Note: In revising this document, I have attempted to make it +completely reflect version 2.12 of +.B vi . +It does not attempt to document the VAX version (version 3), +but with one or two exceptions (wrapmargin, arrow keys) +everything said about 2.12 should apply to 3.1. +.I "Mark Horton" ] +.NH 1 +Notation +.LP +\fB[option]\fR is used to denote optional parts of a command. +Many \fBvi\fR commands have an optional count. \fB[cnt]\fR +means that an optional number may precede the command to +multiply or iterate the command. +\fB{variable item}\fR is used to denote parts of the command +which must appear, but can take a number of different values. +\fB<character [-character]>\fR means that the character or +one of the characters in the range described between the +two angle brackets is to be typed. +For example \fB<esc>\fR means +the \fBescape\fR key is to be typed. \fB<a-z>\fR means that a +lower case letter is to be typed. \fB^<character>\fR means that +the character is to be typed as a \fBcontrol\fR character, that is, +with the \fB<cntl>\fR key held down while simultaneously typing +the specified character. In this document control characters will +be denoted using the \fIupper case\fR character, but +^<uppercase chr> and ^<lowercase chr> are equivalent. That is, for +example, \fB<^D>\fR is equal to \fB<^d>\fR. +The most common character abbreviations +used in this list are as follows: +.VL 8 +.IP <esc> 8 +escape, octal 033 +.IP <cr> 8 +carriage return, ^M, octal 015 +.IP <lf> 8 +linefeed ^J, octal 012 +.IP <nl> 8 +newline, ^J, octal 012 (same as linefeed) +.IP <bs> 8 +backspace, ^H, octal 010 +.IP <tab> 8 +tab, ^I, octal 011 +.IP <bell> 8 +bell, ^G, octal 07 +.IP <ff> 8 +formfeed, ^L, octal 014 +.IP <sp> 8 +space, octal 040 +.IP <del> 8 +delete, octal 0177 +.LE +.sp 1 +.NH 1 +Basics +.LP +To run \fBvi\fR the shell variable \fBTERM\fR must be defined and +exported to your environment. +How you do this depends on which shell you are using. +You can tell which shell you have by the character it +prompts you for commands with. +The Bourne shell prompts with `$', and the C shell prompts with `%'. +For these examples, we will suppose +that you are using an HP 2621 terminal, whose termcap name is ``2621''. +.NH 2 +Bourne Shell +.LP +To manually set your terminal type to 2621 you would type: +.DS +TERM=2621 +export TERM +.DE +.PP +There are various ways of having this automatically or +semi-automatically done when you log in. +Suppose you usually dial in on a 2621. +You want to tell this to the machine, but still have it +work when you use a hardwired terminal. +The recommended way, if you have the +.B tset +program, is to use the sequence +.DS +tset \-s \-d 2621 > tset$$ +\&. tset$$ +rm tset$$ +.DE +in your .login (for csh) or the same thing using `.' instead of `source' +in your .profile (for sh). +The above line says that if you are dialing in you are on a 2621, +but if you are on a hardwired terminal it figures out your terminal +type from an on-line list. +.NH 2 +The C Shell +.LP +To manually set your terminal type to 2621 you would type: +.DS +setenv TERM 2621 +.DE +.PP +There are various ways of having this automatically or +semi-automatically done when you log in. +Suppose you usually dial in on a 2621. +You want to tell this to the machine, but still have it +work when you use a hardwired terminal. +The recommended way, if you have the +.B tset +program, is to use the sequence +.DS +tset \-s \-d 2621 > tset$$ +source tset$$ +rm tset$$ +.DE +in your .login.* +.FS +* On a version 6 system +without environments, the invocation of tset +is simpler, just add the line ``tset \-d 2621'' +to your .login or .profile. +.FE +The above line says that if you are dialing in you are on a 2621, +but if you are on a hardwired terminal it figures out your terminal +type from an on-line list. +.NH 1 +Normal Commands +.LP +\fBVi\fR is a visual editor with a window on the file. What +you see on the screen is \fBvi\fR's current notion of +what your file will contain, +(at this point in the file), +when it is written out. +Most commands do not cause any change in the screen until the +complete command is typed. Should you get confused while +typing a command, you can abort the command by typing an +<del> character. You will know you are back to command level +when you hear a <bell>. Usually typing an <esc> will produce the +same result. When \fBvi\fR gets an improperly formatted command +it rings the <bell>. +Following are the \fBvi\fR commands broken down by function. +.NH 2 +Entry and Exit +.LP +To enter +.B vi +on a particular +.I file , +type +.DS +\fBvi\fP \fIfile\fP +.DE +The file will be read in and the cursor will be placed at the beginning +of the first line. +The first screenfull of the file will be displayed on the terminal. +.PP +To get out of the editor, type +.DS +ZZ +.DE +If you are in some special mode, such as input mode +or the middle of a multi-keystroke command, it may +be necessary to type <esc> first. +.NH 2 +Cursor and Page Motion +.LP +.VL 16 +.B NOTE: +The arrow keys (see the next four commands) +on certain kinds of terminals will not work with the +PDP-11 version of vi. The control versions or the hjkl versions will +work on any terminal. Experienced users prefer the hjkl keys because +they are always right under their fingers. Beginners often prefer +the arrow keys, since they do not require memorization of which hjkl +key is which. +The mnemonic value of hjkl is clear from looking at the keyboard of an adm3a. +.sp +.IP "[cnt]<bs> or [cnt]h or [cnt]\(<-" 16 +.br +Move the cursor to the left one character. Cursor stops at the left +margin of the page. +If cnt is given, these commands move that many spaces. +.IP "[cnt]^N or [cnt]j or [cnt]\(da or [cnt]<lf>" 16 +.br +Move down one line. +Moving off the screen scrolls the window to force a new line +onto the screen. +Mnemonic: \fBN\fRext +.IP "[cnt]^P or [cnt]k or [cnt]\(ua" 16 +.br +Move up one line. +Moving off the top of the screen forces new text onto the screen. +Mnemonic: \fBP\fRrevious +.IP "[cnt]<sp> or [cnt]l or [cnt]\(->" 16 +.br +Move to the right one character. +Cursor will not go beyond the end of the line. +.IP [cnt]- 16 +Move the cursor up the screen to the beginning of the next line. +Scroll if necessary. +.IP "[cnt]+ or [cnt]<cr>" 16 +.sp 1 +Move the cursor down the screen to the beginning of the next line. +Scroll up if necessary. +.IP "[cnt]$" 16 +Move the cursor to the end of the line. +If there is a count, move to the end of the line "cnt" lines +forward in the file. +.IP "^" 16 +Move the cursor to the beginning of the first word on the line. +.IP "0" 16 +Move the cursor to the left margin of the current line. +.IP "[cnt]|" 16 +Move the cursor to the column specified by the count. The default is +column zero. +.IP "[cnt]w" 16 +Move the cursor to the beginning of the next word. If there +is a count, then move forward that many words and +position the cursor at the beginning of the word. +Mnemonic: next-\fBw\fRord +.IP "[cnt]W" 16 +Move the cursor to the beginning of the next word which follows +a "white space" (<sp>,<tab>, or <nl>). Ignore other punctuation. +.IP "[cnt]b" 16 +Move the cursor to the preceding word. Mnemonic: \fBb\fRackup-word +.IP "[cnt]B" 16 +Move the cursor to the preceding word that is separated from the +current word by a "white space" (<sp>,<tab>, or <nl>). +.IP "[cnt]e" 16 +Move the cursor to the end of the current word or the end of the +"cnt"'th word hence. Mnemonic: \fBe\fRnd-of-word +.IP "[cnt]E" 16 +Move the cursor to the end of the current word which is delimited by +"white space" (<sp>,<tab>, or <nl>). +.IP "[line number]G" 16 +.br +Move the cursor to the line specified. Of particular use are the +sequences "1G" and "G", which move the cursor to the beginning and +the end of the file respectively. Mnemonic: \fBG\fRo-to +.LP +.B NOTE: +The next four commands (^D, ^U, ^F, ^B) +are not true motion commands, in that they +cannot be used as the object of commands such as delete or change. +.IP "[cnt]^D" 16 +Move the cursor down in the file by "cnt" lines (or the last "cnt" +if a new count isn't given. The initial default is half a page.) The +screen is simultaneously scrolled up. Mnemonic: \fBD\fRown +.IP "[cnt]^U" 16 +Move the cursor up in the file by "cnt" lines. The screen is simultaneously +scrolled down. Mnemonic: \fBU\fRp +.IP "[cnt]^F" 16 +Move the cursor to the next page. A count moves that many pages. +Two lines of the previous page are kept on the screen for continuity if +possible. Mnemonic: \fBF\fRorward-a-page +.IP "[cnt]^B" 16 +Move the cursor to the previous page. Two lines of the current page +are kept if possible. Mnemonic: \fBB\fRackup-a-page +.IP "[cnt](" 16 +Move the cursor to the beginning of the next sentence. +A sentence is defined as ending with a ".", "!", or "?" +followed by two spaces or a <nl>. +.IP "[cnt])" 16 +Move the cursor backwards to the beginning of a sentence. +.IP "[cnt]}" 16 +Move the cursor to the beginning of the next paragraph. This command +works best inside \fBnroff\fR documents. It understands two sets of +\fBnroff\fR macros, \fB\-ms\fR and \fB\-mm\fR, for which the +commands ".IP", ".LP", ".PP", ".QP", "P", as well as the nroff command ".bp" +are considered to be paragraph delimiters. +A blank line also delimits a paragraph. +The \fBnroff\fR macros that it accepts as paragraph delimiters is +adjustable. See \fBparagraphs\fR under the \fBSet Commands\fR section. +.IP "[cnt]{" 16 +Move the cursor backwards to the beginning of a paragraph. +.IP "]]" 16 +Move the cursor to the next "section", where a section is defined by +two sets of \fBnroff\fR macros, \fB\-ms\fR and \fB\-mm\fR, in which +".NH", ".SH", and ".H" delimit a section. A line beginning with a <ff><nl> +sequence, or a line beginning with a "{" are also considered to +be section delimiters. The last option makes it +useful for finding the beginnings of C functions. +The \fBnroff\fR macros that are used for section delimiters can be adjusted. +See \fBsections\fR under the \fBSet Commands\fR section. +.IP "[[" 16 +Move the cursor backwards to the beginning of a section. +.IP "%" 16 +Move the cursor to the matching parenthesis +or brace. This is very useful in C or lisp code. If the +cursor is sitting on a \fB( ) {\fR or \fB}\fR the cursor +is moved to the matching character at the other end of the +section. If the cursor is not sitting on a brace or a +parenthesis, \fBvi\fR searches forward until it finds one +and then jumps to the match mate. +.IP "[cnt]H" 16 +If there is no count move the cursor to the top left position on the screen. +If there is a count, then move the cursor to the beginning of the line +"cnt" lines from the top of the screen. Mnemonic: \fBH\fRome +.IP "[cnt]L" 16 +If there is no count move the cursor to the beginning +of the last line on the screen. +If there is a count, then move the cursor to the beginning of the line +"cnt" lines from the bottom of the screen. Mnemonic: \fBL\fRast +.IP "M" 16 +Move the cursor to the beginning of the middle line on the screen. +Mnemonic: \fBM\fRiddle +.IP "m<a-z>" 16 +This command does not move the cursor, but it \fBmarks\fR the place +in the file and the character "<a-z>" becomes the label for referring +to this location in the file. See the next two commands. Mnemonic: +\fBm\fRark +.B NOTE: +The mark command is not a motion, and cannot be used as the target +of commands such as delete. +.IP "\(aa<a-z>" 16 +Move the cursor to the beginning of the line that is marked with the label +"<a-z>". +.IP "\(ga<a-z>" 16 +Move the cursor to the exact position on the line that was marked with +with the label "<a-z>". +.IP "\(aa\(aa" 16 +Move the cursor back to the beginning of the line where it was before the +last "non-relative" move. A "non-relative" move is something such as a +search or a jump to a specific line in the file, rather than moving the +cursor or scrolling the screen. +.IP "\(ga\(ga" 16 +Move the cursor back to the exact spot on the line where it was located +before the last "non-relative" move. +.LE +.NH 2 +Searches +.LP +The following commands allow you to search for items in a file. +.VL 16 +.IP [cnt]f{chr} 16 +.sp 1 +Search forward on the line for the next or "cnt"'th occurrence of +the character "chr". The cursor is placed \fBat\fR the character +of interest. Mnemonic: \fBf\fRind character +.IP [cnt]F{chr} 16 +.sp 1 +Search backwards on the line for the next or "cnt"'th occurrence of +the character "chr". The cursor is placed \fBat\fR the character +of interest. +.IP [cnt]t{chr} 16 +.sp 1 +Search forward on the line for the next or "cnt"'th occurrence of +the character "chr". The cursor is placed \fBjust preceding\fR +the character of interest. Mnemonic: move cursor up \fBt\fRo character +.IP [cnt]T{chr} 16 +.sp 1 +Search backwards on the line for the next or "cnt"'th occurrence of +the character "chr". The cursor is placed \fBjust preceding\fR +the character of interest. +.IP "[cnt];" 16 +Repeat the last "f", "F", "t" or "T" command. +.IP "[cnt]," 16 +Repeat the last "f", "F", "t" or "T" command, but in the opposite +search direction. This is useful if you overshoot. +.IP "[cnt]/[string]/<nl>" 16 +.br +Search forward for the next occurrence of "string". +Wrap around at the end of the file +does occur. +The final \fB</>\fR is not required. +.IP "[cnt]?[string]?<nl>" 16 +.br +Search backwards for the next occurrence of "string". If a count is +specified, the count becomes the new window size. Wrap around at the beginning +of the file does occur. +The final \fB<?>\fR is not required. +.IP n 16 +Repeat the last /[string]/ or ?[string]? search. Mnemonic: \fBn\fRext +occurrence. +.IP N 16 +Repeat the last /[string]/ or ?[string]? search, but in the reverse +direction. +.IP ":g/[string]/[editor command]<nl>" 16 +.sp 1 +Using the \fB:\fR syntax it is possible to do global searches ala the +standard UNIX "ed" editor. +.LE +.NH 2 +Text Insertion +.LP +The following commands allow for the insertion of text. All multicharacter +text insertions are terminated with an <esc> character. +The last change +can always be \fBundone\fR by typing a \fBu\fR. +The text insert in insertion mode can contain newlines. +.VL 16 +.IP a{text}<esc> 16 +Insert text immediately following the cursor position. +Mnemonic: \fBa\fRppend +.IP A{text}<esc> 16 +Insert text at the end of the current line. +Mnemonic: \fBA\fRppend +.IP i{text}<esc> 16 +Insert text immediately preceding the cursor position. +Mnemonic: \fBi\fRnsert +.IP I{text}<esc> 16 +Insert text at the beginning of the current line. +.IP o{text}<esc> 16 +Insert a new line after the line on which the cursor appears and +insert text there. Mnemonic: \fBo\fRpen new line +.IP O{text}<esc> 16 +Insert a new line preceding the line on which the cursor appears +and insert text there. +.LE +.NH 2 +Text Deletion +.LP +The following commands allow the user to delete text in various ways. +All changes can always be \fBundone\fR by typing the \fBu\fR command. +.VL 16 +.IP "[cnt]x" 16 +Delete the character or characters starting at the cursor position. +.IP "[cnt]X" 16 +Delete the character or characters starting at the character preceding +the cursor position. +.IP "D" 16 +Deletes the remainder of the line starting at the cursor. +Mnemonic: \fBD\fRelete the rest of line +.IP "[cnt]d{motion}" 16 +.br +Deletes one or more occurrences of the specified motion. +Any motion from sections 4.1 and 4.2 can be used here. +The d can be stuttered (e.g. [cnt]dd) to delete cnt lines. +.LE +.NH 2 +Text Replacement +.LP +The following commands allow the user to simultaneously delete and +insert new text. All such actions can be \fBundone\fR by typing +\fBu\fR following the command. +.VL 16 +.IP "r<chr>" 16 +Replaces the character at the current cursor position with <chr>. This +is a one character replacement. No <esc> is required for termination. +Mnemonic: \fBr\fReplace character +.IP "R{text}<esc>" 16 +Starts overlaying the characters on the screen with whatever you type. +It does not stop until an <esc> is typed. +.IP "[cnt]s{text}<esc>" 16 +Substitute for "cnt" characters beginning at the current cursor +position. A "$" will appear at the position in the text where the +"cnt"'th character appears so you will know how much you are erasing. +Mnemonic: \fBs\fRubstitute +.IP "[cnt]S{text}<esc>" 16 +Substitute for the entire current line (or lines). If no count is given, +a "$" appears at the end of the current line. If a count of more than +1 is given, all the lines to be replaced are deleted before the insertion +begins. +.IP "[cnt]c{motion}{text}<esc>" 16 +.br +Change the specified "motion" by replacing it with the +insertion text. A "$" will appear at the end of the last item +that is being deleted unless the deletion involves whole lines. +Motion's can be any motion from sections 4.1 or 4.2. +Stuttering the c (e.g. [cnt]cc) changes cnt lines. +.LE +.NH 2 +Moving Text +.LP +\fBVi\fR provides a number of ways of moving chunks of text around. +There are nine buffers into which each piece of text which is deleted +or "yanked" is put in addition to the "undo" buffer. +The most recent deletion or yank is in the "undo" buffer and also +usually in buffer +1, the next most recent in buffer 2, and so forth. Each new deletion +pushes down all the older deletions. Deletions older than 9 +disappear. There is also +a set of named registers, a-z, into which text can optionally +be placed. If any delete or replacement type command is preceded +by \fB"<a-z>\fR, that named buffer will contain the text deleted +after the command is executed. For example, \fB"a3dd\fR will delete +three lines starting at the current line and put them in buffer \fB"a\fR.* +.FS +* Referring to an upper case letter as a buffer name (A-Z) is the +same as referring to the lower case letter, except that text placed +in such a buffer is appended to it instead of replacing it. +.FE +There are two more basic commands and +some variations useful in getting and putting text into a file. +.VL 16 +.IP ["<a-z>][cnt]y{motion} 16 +.sp 1 +Yank the specified item or "cnt" items and put in the "undo" buffer or +the specified buffer. The variety of "items" that can be yanked +is the same as those that can be deleted with the "d" command or +changed with the "c" command. In the same way that "dd" means +delete the current line and "cc" means replace the current line, +"yy" means yank the current line. +.IP ["<a-z>][cnt]Y 16 +Yank the current line or the "cnt" lines starting from the current +line. If no buffer is specified, they will go into the "undo" buffer, +like any delete would. It is equivalent to "yy". +Mnemonic: \fBY\fRank +.IP ["<a-z>]p 16 +Put "undo" buffer or the specified buffer down \fBafter\fR the cursor. +If whole lines were yanked or deleted into the buffer, then they will be +put down on the line following the line the cursor is on. If +something else was deleted, like a word or sentence, then it will +be inserted immediately following the cursor. +Mnemonic: \fBp\fRut buffer +.IP +It should be noted that text in the named buffers remains there when you +start editing a new file with the \fB:e file<esc>\fR command. Since +this is so, it is possible to copy or delete text from one file and +carry it over to another file in the buffers. +However, the undo buffer and the ability to undo are lost when +changing files. +.IP ["<a-z>]P 16 +Put "undo" buffer or the specified buffer down \fBbefore\fR the cursor. +If whole lines where yanked or deleted into the buffer, then they will be +put down on the line preceding the line the cursor is on. If +something else was deleted, like a word or sentence, then it will +be inserted immediately preceding the cursor. +.IP [cnt]>{motion} 16 +The shift operator will right shift all the text from the line on which +the cursor is located to the line where the \fBmotion\fR is located. +The text is shifted by one \fBshiftwidth\fR. (See section 6.) +\fB>>\fR means right shift the current line or lines. +.IP [cnt]<{motion} 16 +The shift operator will left shift all the text from the line on which +the cursor is located to the line where the \fBitem\fR is located. +The text is shifted by one \fBshiftwidth\fR. (See section 6.) +\fB<<\fR means left shift the current line or lines. +Once the line has reached the left margin it is not further affected. +.IP [cnt]={motion} 16 +Prettyprints the indicated area according to +.B lisp +conventions. +The area should be a lisp s-expression. +.LE +.NH 2 +Miscellaneous Commands +.LP +\fBVi\fR has a number of miscellaneous commands that are very +useful. They are: +.VL 16 +.IP ZZ 16 +This is the normal way to exit from vi. +If any changes have been made, the file is written out. +Then you are returned to the shell. +.IP ^L 16 +Redraw the current screen. This is useful if someone "write"s you +while you are in "vi" or if for any reason garbage gets onto the +screen. +.IP ^R 16 +On dumb terminals, those not having the "delete line" function +(the vt100 is such a terminal), \fBvi\fR saves redrawing the +screen when you delete a line by just marking the line with an +"@" at the beginning and blanking the line. If you want to +actually get rid of the lines marked with "@" and see what the +page looks like, typing a ^R will do this. +.IP \s+4.\s0 16 +"Dot" is a particularly useful command. It repeats the last +text modifying command. Therefore you can type a command once and +then to another place and repeat it by just typing ".". +.IP u 16 +Perhaps the most important command in the editor, +u undoes the last command that changed the buffer. +Mnemonic: \fBu\fRndo +.IP U 16 +Undo all the text modifying commands performed on the current line +since the last time you moved onto it. +.IP [cnt]J 16 +Join the current line and the following line. The <nl> is deleted +and the two lines joined, usually with a space between the +end of the first line and the beginning of what was the second +line. If the first line ended with a "period", then two spaces +are inserted. +A count joins the next cnt lines. +Mnemonic: \fBJ\fRoin lines +.IP Q 16 +Switch to \fBex\fR editing mode. +In this mode \fBvi\fR will behave very much like \fBed\fR. +The editor in this mode will operate on single lines normally and +will not attempt to keep the "window" up to date. +Once in this mode it is also possible to switch to the \fBopen\fR +mode of editing. By entering the command \fB[line number]open<nl>\fR +you enter this mode. It is similar to the normal visual mode +except the window is only \fBone\fR line long. +Mnemonic: \fBQ\fRuit visual mode +.IP ^] 16 +An abbreviation for a tag command. +The cursor should be positioned at the beginning of a word. +That word is taken as a tag name, and the tag with that +name is found as if it had been typed in a :tag command. +.IP [cnt]!{motion}{UNIX\ cmd}<nl> 16 +.br +Any UNIX filter +(e.g. command that reads the standard input and outputs something +to the standard output) can be sent a section of the current file and +have the output of the command replace the original text. Useful +examples are programs like \fBcb\fR, \fBsort\fR, and +\fBnroff\fR. For instance, using \fBsort\fR it would be possible to +sort a section of the current file into a new list. +Using \fB!!\fR means take a line or lines starting at the line the +cursor is currently on and pass them to the UNIX command. +.B NOTE: +To just escape to the shell for one command, +use :!{cmd}<nl>, see section 5. +.IP z{cnt}<nl> 16 +This resets the current window size to "cnt" lines and redraws the screen. +.LE +.NH 2 +Special Insert Characters +.LP +There are some characters that have special meanings during +insert modes. They are: +.VL 16 +.IP ^V 16 +During inserts, typing a ^V allows you to quote control characters +into the file. Any character typed after the ^V will be inserted +into the file. +.IP [^]^D\ or\ [0]^D 16 +<^D> without any argument backs up one \fBshiftwidth\fR. This is necessary +to remove indentation that was inserted by the \fBautoindent\fR feature. +^<^D> temporarily removes all the autoindentation, thus placing the cursor +at the left margin. On the next line, the previous indent level will be +restored. This is useful for putting "labels" at the left margin. +0<^D> says remove all autoindents and stay that way. Thus the cursor +moves to the left margin and stays there on successive lines until +<tab>'s are typed. As with the <tab>, the <^D> is only effective before +any other "non-autoindent" controlling characters are typed. +Mnemonic: \fBD\fRelete a shiftwidth +.IP ^W 16 +If the cursor is sitting on a word, <^W> moves the cursor back to the beginning +of the word, thus erasing the word from the insert. +Mnemonic: erase \fBW\fRord +.IP <bs> 16 +The backspace always serves as an erase during insert modes in addition +to your normal "erase" character. To insert a <bs> into your file, use +the <^V> to quote it. +.LE +.NH 1 +\fB:\fR Commands +.LP +Typing a ":" during command mode causes \fBvi\fR to put the cursor at +the bottom on the screen in preparation for a command. In the +":" mode, \fBvi\fR can be given most \fBed\fR commands. It is +also from this mode that you exit from \fBvi\fR or switch to different +files. All commands of this variety are terminated by a <nl>, <cr>, +or <esc>. +.VL 16 +.IP ":w[!] [file]" 16 +Causes \fBvi\fR to write out the current text to the disk. It is +written to the file you are editing unless "file" is supplied. If +"file" is supplied, the write is directed to that file instead. If +that file already exists, \fBvi\fR will not perform the write unless +the "!" is supplied indicating you +.I really +want to destroy the older copy of the file. +.IP :q[!] 16 +Causes \fBvi\fR to exit. If you have modified the file you are +looking at currently and haven't written it out, \fBvi\fR will +refuse to exit unless the "!" is supplied. +.IP ":e[!] [+[cmd]] [file]" 16 +.sp 1 +Start editing a new file called "file" or start editing the current +file over again. The command ":e!" says "ignore the changes I've made +to this file and start over from the beginning". It is useful if +you really mess up the file. The optional "+" says instead of starting +at the beginning, start at the "end", or, +if "cmd" is supplied, execute "cmd" first. +Useful cases of this are where cmd is "n" (any integer) which starts +at line number n, +and "/text", which searches for "text" and starts at the line where +it is found. +.IP "^^" 16 +Switch back to the place you were before your last tag command. +If your last tag command stayed within the file, ^^ returns to that tag. +If you have no recent tag command, it will return to the +same place in the previous file that it was showing when you switched +to the current file. +.IP ":n[!]" 16 +Start editing the next file in the argument list. Since \fBvi\fR +can be called with multiple file names, the ":n" command tells it to +stop work on the current file and switch to the next file. If the +current file was modifies, it has to be written out before the ":n" +will work or else the "!" must be supplied, which says discard the +changes I made to the current file. +.IP ":n[!] file [file file ...]" 16 +.sp +Replace the current argument list with a new list of files and start +editing the first file in this new list. +.IP ":r file" 16 +Read in a copy of "file" on the line after the cursor. +.IP ":r !cmd" 16 +Execute the "cmd" and take its output and put it into the file after +the current line. +.IP ":!cmd" 16 +Execute any UNIX shell command. +.IP ":ta[!] tag" 16 +.B Vi +looks in the file named +.B tags +in the current directory. +.B Tags +is a file of lines in the format: +.sp 1 +.ti +8 +tag filename \fBvi\fR-search-command +.sp 1 +If \fBvi\fR finds the tag you specified in the \fB:ta\fR command, +it stops editing the current file if necessary and if the current file is +up to date on the disk and switches to the file specified and uses the +search pattern specified to find the "tagged" item of interest. This +is particularly useful when editing multi-file C programs such as the +operating system. There is a program called \fBctags\fR which will +generate an appropriate \fBtags\fR file for C and f77 +programs so that by saying +\fB:ta function<nl>\fR you will be switched to that function. +It could also be useful when editing multi-file documents, though the +\fBtags\fR file would have to be generated manually. +.LE +.NH 1 +Special Arrangements for Startup +.PP +\fBVi\fR takes the value of \fB$TERM\fR and looks up the characteristics +of that terminal in the file \fB/etc/termcap\fR. +If you don't know \fBvi\fR's name for the terminal you are working +on, look in \fB/etc/termcap\fR. +.PP +When \fBvi\fR starts, it attempts to read the variable EXINIT +from your environment.* +If that exists, it takes the values in it as the default values +for certain of its internal constants. See the section on "Set Values" +for further details. +If EXINIT doesn't exist you will get all the normal defaults. +.FS +* On version 6 systems +Instead of EXINIT, put the startup commands in the file .exrc +in your home directory. +.FE +.PP +Should you inadvertently hang up the phone while inside +.B vi , +or should the computer crash, +all may not be lost. +Upon returning to the system, type: +.DS +vi \-r file +.DE +This will normally recover the file. If there is more than one +temporary file for a specific file name, \fBvi\fR recovers the +newest one. You can get an older version by recovering the +file more than once. +The command "vi -r" without a file name gives you the list of files +that were saved in the last system crash +(but +.I not +the file just saved when the phone was hung up). +.NH 1 +Set Commands +.LP +\fBVi\fR has a number of internal variables and switches which can be +set to achieve special affects. +These options come in three forms, those that are switches, which toggle +from off to on and back, those that require a numeric value, and those +that require an alphanumeric string value. +The toggle options are set by a command of the form: +.DS +:set option<nl> +.DE +and turned off with the command: +.DS +:set nooption<nl> +.DE +Commands requiring a value are set with a command of the form: +.DS +:set option=value<nl> +.DE +To display the value of a specific option type: +.DS +:set option?<nl> +.DE +To display only those that you have changed type: +.DS +:set<nl> +.DE +and to display the long table of all the settable parameters and +their current values type: +.DS +:set all<nl> +.DE +.PP +Most of the options have a long form and an abbreviation. Both are +listed in the following table as well as the normal default value. +.PP +To arrange to have values other than the default used every time you +enter +.B vi , +place the appropriate +.B set +command in EXINIT in your environment, e.g. +.DS +EXINIT='set ai aw terse sh=/bin/csh' +export EXINIT +.DE +or +.DS +setenv EXINIT 'set ai aw terse sh=/bin/csh' +.DE +for +.B sh +and +.B csh , +respectively. +These are usually placed in your .profile or .login. +If you are running a system without environments (such as version 6) +you can place the set command in the file .exrc in your home +directory. +.VL 16 +.IP autoindent\ ai 16 +Default: noai Type: toggle +.br +When in autoindent mode, vi helps you indent code by starting each +line in the same column as the preceding line. +Tabbing to the right with <tab> or <^T> will move this boundary to +the right, and it can be moved to the left with <^D>. +.IP autoprint\ ap 16 +Default: ap Type: toggle +.br +Causes the current line to be printed after each ex text modifying command. +This is not of much interest in the normal \fBvi\fR visual mode. +.IP autowrite\ aw 16 +Default: noaw type: toggle +.br +Autowrite causes an automatic write to be done if there are unsaved +changes before certain commands which change files or otherwise +interact with the outside world. +These commands are :!, :tag, :next, :rewind, ^^, and ^]. +.IP beautify\ bf 16 +Default: nobf Type: toggle +.br +Causes all control characters except <tab>, <nl>, and <ff> to be discarded. +.IP directory\ dir 16 +Default: dir=/tmp Type: string +.br +This is the directory in which \fBvi\fR puts its temporary file. +.IP errorbells\ eb 16 +Default: noeb Type: toggle +.br +Error messages are preceded by a <bell>. +.IP hardtabs\ ht 16 +Default: hardtabs=8 Type: numeric +.br +This option contains the value of hardware tabs in your terminal, or +of software tabs expanded by the Unix system. +.IP ignorecase\ ic 16 +Default: noic Type: toggle +.br +All upper case characters are mapped to lower case in regular expression +matching. +.IP lisp 16 +Default: nolisp Type: toggle +.br +Autoindent for \fBlisp\fR code. The commands \fB( ) [[\fR and \fB]]\fR +are modified appropriately to affect s-expressions and functions. +.IP list 16 +Default: nolist Type: toggle +.br +All printed lines have the <tab> and <nl> characters displayed visually. +.IP magic 16 +Default: magic Type: toggle +.br +Enable the metacharacters for matching. These include \fB. * < > [string] +[^string]\fR and \fB[<chr>-<chr>]\fR. +.IP number\ nu 16 +Default: nonu Type: toggle +.br +Each line is displayed with its line number. +.IP open 16 +Default: open Type: toggle +.br +When set, prevents entering open or visual modes from ex or edit. +Not of interest from vi. +.IP optimize\ opt 16 +Default: opt Type: toggle +.br +Basically of use only when using the \fBex\fR capabilities. This +option prevents automatic <cr>s from taking place, +and speeds up output of indented lines, +at the expense of losing typeahead on some versions of UNIX. +.IP paragraphs\ para 16 +Default: para=IPLPPPQPP\ bp Type: string +.br +Each pair of characters in the string indicate \fBnroff\fR macros +which are to be treated as the beginning of a paragraph for the +\fB{\fR and \fB}\fR commands. The default string is for the \fB-ms\fR +and \fB-mm\fR macros. +To indicate one letter \fBnroff\fR macros, such as \fB.P\fR or \fB.H\fR, +quote a space in for the second character position. For example: +.sp 1 +.ti +8 +:set paragraphs=P\e bp<nl> +.sp 1 +would cause \fBvi\fR to consider \fB.P\fR and \fB.bp\fR as paragraph +delimiters. +.IP prompt 16 +Default: prompt Type: toggle +.br +In +.B ex +command mode the prompt character \fB:\fR will be printed when +\fBex\fR is waiting for a command. This is not of interest from vi. +.IP redraw 16 +Default: noredraw Type: toggle +.br +On dumb terminals, force the screen to always be up to date, +by sending great amounts of output. Useful only at high speeds. +.IP report 16 +Default: report=5 Type: numeric +.br +This sets the threshold for the number of lines modified. When +more than this number of lines are modified, removed, or yanked, +\fBvi\fR will report the number of lines changed at the bottom of +the screen. +.IP scroll 16 +Default: scroll={1/2 window} Type: numeric +.br +This is the number of lines that the screen scrolls up or down when +using the <^U> and <^D> commands. +.IP sections 16 +Default: sections=SHNHH HU Type: string +.br +Each two character pair of this string specify \fBnroff\fR macro names +which are to be treated as the beginning of a section by the +\fB]]\fR and \fB[[\fR commands. The default string is for the \fB-ms\fR +and \fB-mm\fR macros. +To enter one letter \fBnroff\fR macros, use a quoted space as the +second character. +See \fBparagraphs\fR for a fuller explanation. +.IP shell\ sh 16 +Default: sh=from environment SHELL or /bin/sh Type: string +.br +This is the name of the \fBsh\fR to be used for "escaped" commands. +.IP shiftwidth\ sw 16 +Default: sw=8 Type: numeric +.br +This is the number of spaces that a <^T> or <^D> will move over for +indenting, and the amount < and > shift by. +.IP showmatch\ sm 16 +Default: nosm Type: toggle +.br +When a \fB)\fR or \fB}\fR is typed, show the matching \fB(\fR or \fB{\fR +by moving the cursor to it for one second if it is on the current screen. +.IP slowopen\ slow 16 +Default: terminal dependent Type: toggle +.br +On terminals that are slow and unintelligent, this option prevents the +updating of the screen some of the time to improve speed. +.IP tabstop\ ts 16 +Default: ts=8 Type: numeric +.br +<tab>s are expanded to boundaries that are multiples of this value. +.IP taglength\ tl 16 +Default: tl=0 Type: numeric +.br +If nonzero, tag names are only significant to this many characters. +.IP term 16 +Default: (from environment \fBTERM\fP, else dumb) Type: string +.br +This is the terminal and controls the visual displays. It cannot be +changed when in "visual" mode, +you have to Q to command mode, type a +set term command, and do ``vi.'' to get back into visual. +Or exit vi, fix $TERM, and reenter. +The definitions that drive a particular +terminal type are found in the file \fB/etc/termcap\fR. +.IP terse 16 +Default: terse Type: toggle +.br +When set, the error diagnostics are short. +.IP warn 16 +Default: warn Type: toggle +.br +The user is warned if she/he tries to escape to +the shell without writing out the current changes. +.IP window 16 +Default: window={8 at 600 baud or less, 16 at 1200 baud, and screen +size \- 1 at 2400 baud or more} Type: numeric +.br +This is the number of lines in the window whenever \fBvi\fR must redraw +an entire screen. It is useful to make this size smaller if you are +on a slow line. +.IP w300,\ w1200,\ w9600 +.br +These set window, but only within the corresponding speed ranges. +They are useful in an EXINIT to fine tune window sizes. +For example, +.DS +set w300=4 w1200=12 +.DE +causes a 4 lines window at speed up to 600 baud, a 12 line window at 1200 +baud, and a full screen (the default) at over 1200 baud. +.IP wrapscan\ ws 16 +Default: ws Type: toggle +.br +Searches will wrap around the end of the file when is option is set. When +it is off, the search will terminate when it reaches the end or the +beginning of the file. +.IP wrapmargin\ wm 16 +Default: wm=0 Type: numeric +.br +\fBVi\fR will automatically insert a <nl> when it finds a natural +break point (usually a <sp> between words) that occurs within +"wm" spaces of the right margin. +Therefore with "wm=0" the option is off. Setting it to 10 would +mean that any time you are within 10 spaces of the right margin +\fBvi\fR would be looking for a <sp> or <tab> which it could +replace with a <nl>. This is convenient for people who forget +to look at the screen while they type. +(In version 3, wrapmargin behaves more like nroff, in that the +boundary specified by the distance from the right edge of the screen +is taken as the rightmost edge of the area where a break is allowed, +instead of the leftmost edge.) +.IP writeany\ wa 16 +Default: nowa Type: toggle +.br +\fBVi\fR normally makes a number of checks before it writes out a file. +This prevents the user from inadvertently destroying a file. When the +"writeany" option is enabled, \fBvi\fR no longer makes these checks. +.LE diff --git a/usr.bin/vi/USD.doc/vitut/vi.chars b/usr.bin/vi/USD.doc/vitut/vi.chars new file mode 100644 index 0000000..147c4ff --- /dev/null +++ b/usr.bin/vi/USD.doc/vitut/vi.chars @@ -0,0 +1,644 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vi.chars 8.1 (Berkeley) 6/8/93 +.\" +.bd S 3 +..pn 21 +.de iP +.IP "\fB\\$1\fR" \\$2 +.. +.SH +Appendix: character functions +.PP +This appendix gives the uses the editor makes of each character. The +characters are presented in their order in the \s-2ASCII\s0 character +set: Control characters come first, then most special characters, then +the digits, upper and then lower case characters. +.PP +For each character we tell a meaning it has as a command and any meaning it +has during an insert. +If it has only meaning as a command, then only this is discussed. +Section numbers in parentheses indicate where the character is discussed; +a `f' after the section number means that the character is mentioned +in a footnote. +.iP "^@" 15 +Not a command character. +If typed as the first character of an insertion it is replaced with the +last text inserted, and the insert terminates. Only 128 characters are +saved from the last insert; if more characters were inserted the mechanism +is not available. +A \fB^@\fR cannot be part of the file due to the editor implementation +(7.5f). +.iP "^A" 15 +Unused. +.iP "^B" 15 +Backward window. +A count specifies repetition. +Two lines of continuity are kept if possible (2.1, 6.1, 7.2). +.iP "^C" 15 +Unused. +.iP "^D" 15 +As a command, scrolls down a half-window of text. +A count gives the number of (logical) lines to scroll, and is remembered +for future \fB^D\fR and \fB^U\fR commands (2.1, 7.2). +During an insert, backtabs over \fIautoindent\fR white space at the beginning +of a line (6.6, 7.5); this white space cannot be backspaced over. +.iP "^E" 15 +Exposes one more line below the current screen in the file, leaving +the cursor where it is if possible. +(Version 3 only.) +.iP "^F" 15 +Forward window. A count specifies repetition. +Two lines of continuity are kept if possible (2.1, 6.1, 7.2). +.iP "^G" 15 +Equivalent to \fB:f\fR\s-2CR\s0, printing the current file, whether +it has been modified, the current line number and the number of lines +in the file, and the percentage of the way through the file that you +are. +.iP "^H (\fR\s-2BS\s0\fP)" 15 +Same as +.B "left arrow" . +(See +.B h ). +During an insert, eliminates the last input character, backing over it +but not erasing it; it remains so you can see what you typed if you +wish to type something only slightly different (3.1, 7.5). +.iP "^I\ (\fR\s-2TAB\s0\fP)" 15 +Not a command character. +When inserted it prints as some +number of spaces. +When the cursor is at a tab character it rests at the last of the spaces +which represent the tab. +The spacing of tabstops is controlled by the \fItabstop\fR option (4.1, 6.6). +.iP "^J\ (\fR\s-2LF\s0\fP)" 15 +Same as +.B "down arrow" +(see +.B j ). +.iP "^K" 15 +Unused. +.iP "^L" 15 +The \s-2ASCII\s0 formfeed character, this causes the screen to be cleared +and redrawn. This is useful after a transmission error, if characters +typed by a program other than the editor scramble the screen, +or after output is stopped by an interrupt (5.4, 7.2f). +.iP "^M\ (\fR\s-2CR\s0\fP)" 15 +A carriage return advances to the next line, at the first non-white position +in the line. Given a count, it advances that many lines (2.3). +During an insert, a \s-2CR\s0 causes the insert to continue onto +another line (3.1). +.iP "^N" 15 +Same as +.B "down arrow" +(see +.B j ). +.iP "^O" 15 +Unused. +.iP "^P" 15 +Same as +.B "up arrow" +(see +.B k ). +.iP "^Q" 15 +Not a command character. +In input mode, +.B ^Q +quotes the next character, the same as +.B ^V , +except that some teletype drivers will eat the +.B ^Q +so that the editor never sees it. +.iP "^R" 15 +Redraws the current screen, eliminating logical lines not corresponding +to physical lines (lines with only a single @ character on them). +On hardcopy terminals in \fIopen\fR mode, retypes the current line +(5.4, 7.2, 7.8). +.iP "^S" 15 +Unused. Some teletype drivers use +.B ^S +to suspend output until +.B ^Q is pressed. +.iP "^T" 15 +Not a command character. +During an insert, with \fIautoindent\fR set and at the beginning of the +line, inserts \fIshiftwidth\fR white space. +.iP "^U" 15 +Scrolls the screen up, inverting \fB^D\fR which scrolls down. Counts work as +they do for \fB^D\fR, and the previous scroll amount is common to both. +On a dumb terminal, \fB^U\fR will often necessitate clearing and redrawing +the screen further back in the file (2.1, 7.2). +.iP "^V" 15 +Not a command character. +In input mode, quotes the next character so that it is possible +to insert non-printing and special characters into the file (4.2, 7.5). +.iP "^W" 15 +Not a command character. +During an insert, backs up as \fBb\fR would in command mode; the deleted +characters remain on the display (see \fB^H\fR) (7.5). +.iP "^X" 15 +Unused. +.iP "^Y" 15 +Exposes one more line above the current screen, leaving the cursor where +it is if possible. (No mnemonic value for this key; however, it is next +to \fB^U\fR which scrolls up a bunch.) +(Version 3 only.) +.iP "^Z" 15 +If supported by the Unix system, +stops the editor, exiting to the top level shell. +Same as \fB:stop\fP\s-2CR\s0. +Otherwise, unused. +.iP "^[\ (\fR\s-2ESC\s0\fP)" 15 +Cancels a partially formed command, such as a \fBz\fR when no following +character has yet been given; terminates inputs on the last line (read +by commands such as \fB: /\fR and \fB?\fR); ends insertions of new text +into the buffer. +If an \s-2ESC\s0 is given when quiescent in command state, the editor +rings the bell or flashes the screen. You can thus hit \s-2ESC\s0 if +you don't know what is happening till the editor rings the bell. +If you don't know if you are in insert mode you can type \s-2ESC\s0\fBa\fR, +and then material to be input; the material will be inserted correctly +whether or not you were in insert mode when you started (1.5, 3.1, 7.5). +.iP "^\e" 15 +Unused. +.iP "^]" 15 +Searches for the word which is after the cursor as a tag. Equivalent +to typing \fB:ta\fR, this word, and then a \s-2CR\s0. +Mnemonically, this command is ``go right to'' (7.3). +.iP "^\(ua" 15 +Equivalent to \fB:e #\fR\s-2CR\s0, returning to the previous position +in the last edited file, or editing a file which you specified if you +got a `No write since last change diagnostic' and do not want to have +to type the file name again (7.3). +(You have to do a \fB:w\fR before \fB^\(ua\fR +will work in this case. If you do not wish to write the file you should +do \fB:e!\ #\fR\s-2CR\s0 instead.) +.iP "^_" 15 +Unused. +Reserved as the command character for the +Tektronix 4025 and 4027 terminal. +.iP "\fR\s-2SPACE\s0\fP" 15 +Same as +.B "right arrow" +(see +.B l ). +.iP "!" 15 +An operator, which processes lines from the buffer with reformatting commands. +Follow \fB!\fR with the object to be processed, and then the command name +terminated by \s-2CR\s0. Doubling \fB!\fR and preceding it by a count +causes count lines to be filtered; otherwise the count +is passed on to the object after the \fB!\fR. Thus \fB2!}\fR\fIfmt\fR\s-2CR\s0 +reformats the next two paragraphs by running them through the program +\fIfmt\fR. If you are working on \s-2LISP\s0, +the command \fB!%\fR\fIgrind\fR\s-2CR\s0,* +.FS +*Both +.I fmt +and +.I grind +are Berkeley programs and may not be present at all installations. +.FE +given at the beginning of a +function, will run the text of the function through the \s-2LISP\s0 grinder +(6.7, 7.3). +To read a file or the output of a command into the buffer use \fB:r\fR (7.3). +To simply execute a command use \fB:!\fR (7.3). +.tr " +.iP 15 +Precedes a named buffer specification. There are named buffers \fB1\-9\fR +used for saving deleted text and named buffers \fBa\-z\fR into which you can +place text (4.3, 6.3) +.tr +.iP "#" 15 +The macro character which, when followed by a number, will substitute +for a function key on terminals without function keys (6.9). +In input mode, +if this is your erase character, it will delete the last character +you typed in input mode, and must be preceded with a \fB\e\fR to insert +it, since it normally backs over the last input character you gave. +.iP "$" 15 +Moves to the end of the current line. If you \fB:se list\fR\s-2CR\s0, +then the end of each line will be shown by printing a \fB$\fR after the +end of the displayed text in the line. Given a count, advances to the +count'th following end of line; thus \fB2$\fR advances to the end of the +following line. +.iP "%" 15 +Moves to the parenthesis or brace \fB{ }\fR which balances the parenthesis +or brace at the current cursor position. +.iP "&" 15 +A synonym for \fB:&\fR\s-2CR\s0, by analogy with the +.I ex +.B & +command. +.iP "\(aa" 15 +When followed by a \fB\(aa\fR returns to the previous context at the +beginning of a line. The previous context is set whenever the current +line is moved in a non-relative way. +When followed by a letter \fBa\fR\-\fBz\fR, returns to the line which +was marked with this letter with a \fBm\fR command, at the first non-white +character in the line. (2.2, 5.3). +When used with an operator such as \fBd\fR, the operation takes place +over complete lines; if you use \fB\(ga\fR, the operation takes place +from the exact marked place to the current cursor position within the +line. +.iP "(" 15 +Retreats to the beginning of a +sentence, or to the beginning of a \s-2LISP\s0 s-expression +if the \fIlisp\fR option is set. +A sentence ends at a \fB. !\fR or \fB?\fR which is followed by either +the end of a line or by two spaces. Any number of closing \fB) ] "\fR +and \fB\(aa\fR characters may appear after the \fB. !\fR or \fB?\fR, +and before the spaces or end of line. Sentences also begin +at paragraph and section boundaries +(see \fB{\fR and \fB[[\fR below). +A count advances that many sentences (4.2, 6.8). +.iP ")" 15 +Advances to the beginning of a sentence. +A count repeats the effect. +See \fB(\fR above for the definition of a sentence (4.2, 6.8). +.iP "*" 15 +Unused. +.iP "+" 15 +Same as \s-2CR\s0 when used as a command. +.iP "," 15 +Reverse of the last \fBf F t\fR or \fBT\fR command, looking the other way +in the current line. Especially useful after hitting too many \fB;\fR +characters. A count repeats the search. +.iP "\-" 15 +Retreats to the previous line at the first non-white character. +This is the inverse of \fB+\fR and \s-2RETURN\s0. +If the line moved to is not on the screen, the screen is scrolled, or +cleared and redrawn if this is not possible. +If a large amount of scrolling would be required the screen is also cleared +and redrawn, with the current line at the center (2.3). +.iP "\&." 15 +Repeats the last command which changed the buffer. Especially useful +when deleting words or lines; you can delete some words/lines and then +hit \fB.\fR to delete more and more words/lines. +Given a count, it passes it on to the command being repeated. Thus after +a \fB2dw\fR, \fB3.\fR deletes three words (3.3, 6.3, 7.2, 7.4). +.iP "/" 15 +Reads a string from the last line on the screen, and scans forward for +the next occurrence of this string. The normal input editing sequences may +be used during the input on the bottom line; an returns to command state +without ever searching. +The search begins when you hit \s-2CR\s0 to terminate the pattern; +the cursor moves to the beginning of the last line to indicate that the search +is in progress; the search may then +be terminated with a \s-2DEL\s0 or \s-2RUB\s0, or by backspacing when +at the beginning of the bottom line, returning the cursor to +its initial position. +Searches normally wrap end-around to find a string +anywhere in the buffer. +.IP +When used with an operator the enclosed region is normally affected. +By mentioning an +offset from the line matched by the pattern you can force whole lines +to be affected. To do this give a pattern with a closing +a closing \fB/\fR and then an offset \fB+\fR\fIn\fR or \fB\-\fR\fIn\fR. +.IP +To include the character \fB/\fR in the search string, you must escape +it with a preceding \fB\e\fR. +A \fB\(ua\fR at the beginning of the pattern forces the match to occur +at the beginning of a line only; this speeds the search. A \fB$\fR at +the end of the pattern forces the match to occur at the end of a line +only. +More extended pattern matching is available, see section 7.4; +unless you set \fBnomagic\fR in your \fI\&.exrc\fR file you will have +to preceed the characters \fB. [ *\fR and \fB~\fR in the search pattern +with a \fB\e\fR to get them to work as you would naively expect (1.5, 2,2, +6.1, 7.2, 7.4). +.iP "0" 15 +Moves to the first character on the current line. +Also used, in forming numbers, after an initial \fB1\fR\-\fB9\fR. +.iP "1\-9" 15 +Used to form numeric arguments to commands (2.3, 7.2). +.iP ":" 15 +A prefix to a set of commands for file and option manipulation and escapes +to the system. Input is given on the bottom line and terminated with +an \s-2CR\s0, and the command then executed. You can return to where +you were by hitting \s-2DEL\s0 or \s-2RUB\s0 if you hit \fB:\fR accidentally +(see primarily 6.2 and 7.3). +.iP ";" 15 +Repeats the last single character find which used \fBf F t\fR or \fBT\fR. +A count iterates the basic scan (4.1). +.iP "<" 15 +An operator which shifts lines left one \fIshiftwidth\fR, normally 8 +spaces. Like all operators, affects lines when repeated, as in +\fB<<\fR. Counts are passed through to the basic object, thus \fB3<<\fR +shifts three lines (6.6, 7.2). +.iP "=" 15 +Reindents line for \s-2LISP\s0, as though they were typed in with \fIlisp\fR +and \fIautoindent\fR set (6.8). +.iP ">" 15 +An operator which shifts lines right one \fIshiftwidth\fR, normally 8 +spaces. Affects lines when repeated as in \fB>>\fR. Counts repeat the +basic object (6.6, 7.2). +.iP "?" 15 +Scans backwards, the opposite of \fB/\fR. See the \fB/\fR description +above for details on scanning (2.2, 6.1, 7.4). +.iP "@" 15 +A macro character (6.9). If this is your kill character, you must escape it with a \e +to type it in during input mode, as it normally backs over the input you +have given on the current line (3.1, 3.4, 7.5). +.iP "A" 15 +Appends at the end of line, a synonym for \fB$a\fR (7.2). +.iP "B" 15 +Backs up a word, where words are composed of non-blank sequences, placing +the cursor at the beginning of the word. A count repeats the effect +(2.4). +.iP "C" 15 +Changes the rest of the text on the current line; a synonym for \fBc$\fR. +.iP "D" 15 +Deletes the rest of the text on the current line; a synonym for \fBd$\fR. +.iP "E" 15 +Moves forward to the end of a word, defined as blanks and non-blanks, +like \fBB\fR and \fBW\fR. A count repeats the effect. +.iP "F" 15 +Finds a single following character, backwards in the current line. +A count repeats this search that many times (4.1). +.iP "G" 15 +Goes to the line number given as preceding argument, or the end of the +file if no preceding count is given. The screen is redrawn with the +new current line in the center if necessary (7.2). +.iP "H" 15 +.B "Home arrow" . +Homes the cursor to the top line on the screen. If a count is given, +then the cursor is moved to the count'th line on the screen. +In any case the cursor is moved to the first non-white character on the +line. If used as the target of an operator, full lines are affected +(2.3, 3.2). +.iP "I" 15 +Inserts at the beginning of a line; a synonym for \fB\(uai\fR. +.iP "J" 15 +Joins together lines, supplying appropriate white space: one space between +words, two spaces after a \fB.\fR, and no spaces at all if the first +character of the joined on line is \fB)\fR. A count causes that many +lines to be joined rather than the default two (6.5, 7.1f). +.iP "K" 15 +Unused. +.iP "L" 15 +Moves the cursor to the first non-white character of the last line on +the screen. With a count, to the first non-white of the count'th line +from the bottom. Operators affect whole lines when used with \fBL\fR +(2.3). +.iP "M" 15 +Moves the cursor to the middle line on the screen, at the first non-white +position on the line (2.3). +.iP "N" 15 +Scans for the next match of the last pattern given to +\fB/\fR or \fB?\fR, but in the reverse direction; this is the reverse +of \fBn\fR. +.iP "O" 15 +Opens a new line above the current line and inputs text there up to an +\s-2ESC\s0. A count can be used on dumb terminals to specify a number +of lines to be opened; this is generally obsolete, as the \fIslowopen\fR +option works better (3.1). +.iP "P" 15 +Puts the last deleted text back before/above the cursor. The text goes +back as whole lines above the cursor if it was deleted as whole lines. +Otherwise the text is inserted between the characters before and at the +cursor. May be preceded by a named buffer specification \fB"\fR\fIx\fR +to retrieve the contents of the buffer; buffers \fB1\fR\-\fB9\fR contain +deleted material, buffers \fBa\fR\-\fBz\fR are available for general +use (6.3). +.iP "Q" 15 +Quits from \fIvi\fR to \fIex\fR command mode. In this mode, whole lines +form commands, ending with a \s-2RETURN\s0. You can give all the \fB:\fR +commands; the editor supplies the \fB:\fR as a prompt (7.7). +.iP "R" 15 +Replaces characters on the screen with characters you type (overlay fashion). +Terminates with an \s-2ESC\s0. +.iP "S" 15 +Changes whole lines, a synonym for \fBcc\fR. A count substitutes for +that many lines. The lines are saved in the numeric buffers, and erased +on the screen before the substitution begins. +.iP "T" 15 +Takes a single following character, locates the character before the +cursor in the current line, and places the cursor just after that character. +A count repeats the effect. Most useful with operators such as \fBd\fR +(4.1). +.iP "U" 15 +Restores the current line to its state before you started changing it +(3.5). +.iP "V" 15 +Unused. +.iP "W" 15 +Moves forward to the beginning of a word in the current line, +where words are defined as sequences of blank/non-blank characters. +A count repeats the effect (2.4). +.iP "X" 15 +Deletes the character before the cursor. A count repeats the effect, +but only characters on the current line are deleted. +.iP "Y" 15 +Yanks a copy of the current line into the unnamed buffer, to be put back +by a later \fBp\fR or \fBP\fR; a very useful synonym for \fByy\fR. +A count yanks that many lines. May be preceded by a buffer name to put +lines in that buffer (7.4). +.iP "ZZ" 15 +Exits the editor. +(Same as \fB:x\fP\s-2CR\s0.) +If any changes have been made, the buffer is written out to the current file. +Then the editor quits. +.iP "[[" 15 +Backs up to the previous section boundary. A section begins at each +macro in the \fIsections\fR option, +normally a `.NH' or `.SH' and also at lines which which start +with a formfeed \fB^L\fR. Lines beginning with \fB{\fR also stop \fB[[\fR; +this makes it useful for looking backwards, a function at a time, in C +programs. If the option \fIlisp\fR is set, stops at each \fB(\fR at the +beginning of a line, and is thus useful for moving backwards at the top +level \s-2LISP\s0 objects. (4.2, 6.1, 6.6, 7.2). +.iP "\e" 15 +Unused. +.iP "]]" 15 +Forward to a section boundary, see \fB[[\fR for a definition (4.2, 6.1, +6.6, 7.2). +.iP "\(ua" 15 +Moves to the first non-white position on the current line (4.4). +.iP "_" 15 +Unused. +.iP "\(ga" 15 +When followed by a \fB\(ga\fR returns to the previous context. +The previous context is set whenever the current +line is moved in a non-relative way. +When followed by a letter \fBa\fR\-\fBz\fR, returns to the position which +was marked with this letter with a \fBm\fR command. +When used with an operator such as \fBd\fR, the operation takes place +from the exact marked place to the current position within the line; +if you use \fB\(aa\fR, the operation takes place over complete lines +(2.2, 5.3). +.iP "a" 15 +Appends arbitrary text after the current cursor position; the insert +can continue onto multiple lines by using \s-2RETURN\s0 within the insert. +A count causes the inserted text to be replicated, but only if the inserted +text is all on one line. +The insertion terminates with an \s-2ESC\s0 (3.1, 7.2). +.iP "b" 15 +Backs up to the beginning of a word in the current line. A word is a +sequence of alphanumerics, or a sequence of special characters. +A count repeats the effect (2.4). +.iP "c" 15 +An operator which changes the following object, replacing it with the +following input text up to an \s-2ESC\s0. If more than part of a single +line is affected, the text which is changed away is saved in the numeric named +buffers. If only part of the current line is affected, then the last +character to be changed away is marked with a \fB$\fR. +A count causes that many objects to be affected, thus both +\fB3c)\fR and \fBc3)\fR change the following three sentences (7.4). +.iP "d" 15 +An operator which deletes the following object. If more than part of +a line is affected, the text is saved in the numeric buffers. +A count causes that many objects to be affected; thus \fB3dw\fR is the +same as \fBd3w\fR (3.3, 3.4, 4.1, 7.4). +.iP "e" 15 +Advances to the end of the next word, defined as for \fBb\fR and \fBw\fR. +A count repeats the effect (2.4, 3.1). +.iP "f" 15 +Finds the first instance of the next character following the cursor on +the current line. A count repeats the find (4.1). +.iP "g" 15 +Unused. +.sp +Arrow keys +.B h , +.B j , +.B k , +.B l , +and +.B H . +.iP "h" 15 +.B "Left arrow" . +Moves the cursor one character to the left. +Like the other arrow keys, either +.B h , +the +.B "left arrow" +key, or one of the synonyms (\fB^H\fP) has the same effect. +On v2 editors, arrow keys on certain kinds of terminals +(those which send escape sequences, such as vt52, c100, or hp) +cannot be used. +A count repeats the effect (3.1, 7.5). +.iP "i" 15 +Inserts text before the cursor, otherwise like \fBa\fR (7.2). +.iP "j" 15 +.B "Down arrow" . +Moves the cursor one line down in the same column. +If the position does not exist, +.I vi +comes as close as possible to the same column. +Synonyms include +.B ^J +(linefeed) and +.B ^N . +.iP "k" 15 +.B "Up arrow" . +Moves the cursor one line up. +.B ^P +is a synonym. +.iP "l" 15 +.B "Right arrow" . +Moves the cursor one character to the right. +\s-2SPACE\s0 is a synonym. +.iP "m" 15 +Marks the current position of the cursor in the mark register which is +specified by the next character \fBa\fR\-\fBz\fR. Return to this position +or use with an operator using \fB\(ga\fR or \fB\(aa\fR (5.3). +.iP "n" 15 +Repeats the last \fB/\fR or \fB?\fR scanning commands (2.2). +.iP "o" 15 +Opens new lines below the current line; otherwise like \fBO\fR (3.1). +.iP "p" 15 +Puts text after/below the cursor; otherwise like \fBP\fR (6.3). +.iP "q" 15 +Unused. +.iP "r" 15 +Replaces the single character at the cursor with a single character you +type. The new character may be a \s-2RETURN\s0; this is the easiest +way to split lines. A count replaces each of the following count characters +with the single character given; see \fBR\fR above which is the more +usually useful iteration of \fBr\fR (3.2). +.iP "s" 15 +Changes the single character under the cursor to the text which follows +up to an \s-2ESC\s0; given a count, that many characters from the current +line are changed. The last character to be changed is marked with \fB$\fR +as in \fBc\fR (3.2). +.iP "t" 15 +Advances the cursor upto the character before the next character typed. +Most useful with operators such as \fBd\fR and \fBc\fR to delete the +characters up to a following character. You can use \fB.\fR to delete +more if this doesn't delete enough the first time (4.1). +.iP "u" 15 +Undoes the last change made to the current buffer. If repeated, will +alternate between these two states, thus is its own inverse. When used +after an insert which inserted text on more than one line, the lines are +saved in the numeric named buffers (3.5). +.iP "v" 15 +Unused. +.iP "w" 15 +Advances to the beginning of the next word, as defined by \fBb\fR (2.4). +.iP "x" 15 +Deletes the single character under the cursor. With a count deletes +deletes that many characters forward from the cursor position, but only +on the current line (6.5). +.iP "y" 15 +An operator, yanks the following object into the unnamed temporary buffer. +If preceded by a named buffer specification, \fB"\fR\fIx\fR, the text +is placed in that buffer also. Text can be recovered by a later \fBp\fR +or \fBP\fR (7.4). +.iP "z" 15 +Redraws the screen with the current line placed as specified by the following +character: \s-2RETURN\s0 specifies the top of the screen, \fB.\fR the +center of the screen, and \fB\-\fR at the bottom of the screen. +A count may be given after the \fBz\fR and before the following character +to specify the new screen size for the redraw. +A count before the \fBz\fR gives the number of the line to place in the +center of the screen instead of the default current line. (5.4) +.iP "{" 15 +Retreats to the beginning of the beginning of the preceding paragraph. +A paragraph begins at each macro in the \fIparagraphs\fR option, normally +`.IP', `.LP', `.PP', `.QP' and `.bp'. +A paragraph also begins after a completely +empty line, and at each section boundary (see \fB[[\fR above) (4.2, 6.8, +7.6). +.iP "|" 15 +Places the cursor on the character in the column specified +by the count (7.1, 7.2). +.iP "}" 15 +Advances to the beginning of the next paragraph. See \fB{\fR for the +definition of paragraph (4.2, 6.8, 7.6). +.iP "~" 15 +Unused. +.iP "^?\ (\s-2\fRDEL\fP\s0)" 15 +Interrupts the editor, returning it to command accepting state (1.5, +7.5) +.bp +\&. diff --git a/usr.bin/vi/USD.doc/vitut/vi.in b/usr.bin/vi/USD.doc/vitut/vi.in new file mode 100644 index 0000000..3bdfeb9 --- /dev/null +++ b/usr.bin/vi/USD.doc/vitut/vi.in @@ -0,0 +1,2064 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vi.in 8.1 (Berkeley) 6/8/93 +.\" +.EH 'USD:12-%''An Introduction to Display Editing with Vi' +.OH 'An Introduction to Display Editing with Vi''USD:12-%' +.bd S 3 +.if t .ds dg \(dg +.if n .ds dg + +.if t .ds dd \(dd +.if n .ds dd ++ +.\".RP +.TL +An Introduction to Display Editing with Vi +.AU +William Joy +.AU +Mark Horton +.AI +Computer Science Division +Department of Electrical Engineering and Computer Science +University of California, Berkeley +Berkeley, Ca. 94720 +.AB +.PP +.I Vi +(visual) is a display oriented interactive text editor. +When using +.I vi +the screen of your terminal acts as a window into the file which you +are editing. Changes which you make to the file are reflected +in what you see. +.PP +Using +.I vi +you can insert new text any place in the file quite easily. +Most of the commands to +.I vi +move the cursor around in the file. +There are commands to move the cursor +forward and backward in units of characters, words, +sentences and paragraphs. +A small set of operators, like +.B d +for delete and +.B c +for change, are combined with the motion commands to form operations +such as delete word or change paragraph, in a simple and natural way. +This regularity and the mnemonic assignment of commands to keys makes the +editor command set easy to remember and to use. +.PP +.I Vi +will work on a large number of display terminals, +and new terminals are easily driven after editing a terminal description file. +While it is advantageous to have an intelligent terminal which can locally +insert and delete lines and characters from the display, the editor will +function quite well on dumb terminals over slow phone lines. +The editor makes allowance for the low bandwidth in these situations +and uses smaller window sizes and +different display updating algorithms to make best use of the +limited speed available. +.PP +It is also possible to use the command set of +.I vi +on hardcopy terminals, storage tubes and ``glass tty's'' using a one line +editing window; thus +.I vi's +command set is available on all terminals. +The full command set of the more traditional, line +oriented editor +.I ex +is available within +.I vi; +it is quite simple to switch between the two modes of editing. +.AE +.NH 1 +Getting started +.PP +.FS +The financial support of an \s-2IBM\s0 Graduate Fellowship and the +National Science Foundation under grants MCS74-07644-A03 and MCS78-07291 +is gratefully acknowledged. +.FE +This document provides a quick introduction to +.I vi. +(Pronounced \fIvee-eye\fP.) +You should be running +.I vi +on a file you are familiar with while you are reading this. +The first part of this document (sections 1 through 5) +describes the basics of using +.I vi. +Some topics of special interest are presented in section 6, and +some nitty-gritty details of how the editor functions are saved for section +7 to avoid cluttering the presentation here. +.PP +There is also a short appendix here, which gives for each character the +special meanings which this character has in \fIvi\fR. Attached to +this document should be a quick reference card. +This card summarizes the commands of +.I vi +in a very compact format. You should have the card handy while you are +learning +.I vi. +.NH 2 +Specifying terminal type +.PP +Before you can start +.I vi +you must tell the system what kind of terminal you are using. +Here is a (necessarily incomplete) list of terminal type codes. +If your terminal does not appear here, you should consult with one of +the staff members on your system to find out the code for your terminal. +If your terminal does not have a code, one can be assigned and a description +for the terminal can be created. +.LP +.TS +center; +ab ab ab +a a a. +Code Full name Type +_ +2621 Hewlett-Packard 2621A/P Intelligent +2645 Hewlett-Packard 264x Intelligent +act4 Microterm ACT-IV Dumb +act5 Microterm ACT-V Dumb +adm3a Lear Siegler ADM-3a Dumb +adm31 Lear Siegler ADM-31 Intelligent +c100 Human Design Concept 100 Intelligent +dm1520 Datamedia 1520 Dumb +dm2500 Datamedia 2500 Intelligent +dm3025 Datamedia 3025 Intelligent +fox Perkin-Elmer Fox Dumb +h1500 Hazeltine 1500 Intelligent +h19 Heathkit h19 Intelligent +i100 Infoton 100 Intelligent +mime Imitating a smart act4 Intelligent +t1061 Teleray 1061 Intelligent +vt52 Dec VT-52 Dumb +.TE +.PP +Suppose for example that you have a Hewlett-Packard HP2621A +terminal. The code used by the system for this terminal is `2621'. +In this case you can use one of the following commands to tell the system +the type of your terminal: +.DS +% \fBsetenv TERM\fP 2621 +.DE +This command works with the +.I csh +shell. +If you are using the standard Bourne shell +.I sh +then you should give the commands +.DS +$ \fBTERM=\fP2621 +$ \fBexport TERM\fP +.DE +.PP +If you want to arrange to have your terminal type set up automatically +when you log in, you can use the +.I tset +program. +If you dial in on a +.I mime , +but often use hardwired ports, a typical line for your +.I .login +file (if you use csh) would be +.DS +\fBsetenv TERM \(gatset\fP \- \-d mime\(ga +.DE +or for your +.I .profile +file (if you use sh) +.DS +\fBTERM=\(gatse\fPt \- \-d mime\(ga +.DE +.I Tset +knows which terminals are hardwired to each port +and needs only to be told that when you dial in you +are probably on a +.I mime . +.I Tset +is usually used to change the erase and kill characters, too. +.NH 2 +Editing a file +.PP +After telling the system which kind of terminal you have, you should +make a copy of a file you are familiar with, and run +.I vi +on this file, giving the command +.DS +% \fBvi\fR \fIname\fR +.DE +replacing \fIname\fR with the name of the copy file you just created. +The screen should clear and the text of your file should appear on the +screen. If something else happens refer to the footnote.\*(dd +.FS +\*(dd If you gave the system an incorrect terminal type code then the +editor may have just made a mess out of your screen. This happens when +it sends control codes for one kind of terminal to some other +kind of terminal. In this case hit +the keys \fB:q\fR (colon and the q key) and then hit the \s-2RETURN\s0 key. +This should get you back to the command level interpreter. +Figure out what you did wrong (ask someone else if necessary) and try again. + Another thing which can go wrong is that you typed the wrong file name and +the editor just printed an error diagnostic. In this case you should +follow the above procedure for getting out of the editor, and try again +this time spelling the file name correctly. + If the editor doesn't seem to respond to the commands which you type +here, try sending an interrupt to it by hitting the \s-2DEL\s0 or \s-2RUB\s0 +key on your terminal, and then hitting the \fB:q\fR command again followed +by a carriage return. +.sp +.FE +.NH 2 +The editor's copy: the buffer +.PP +The editor does not directly modify the file which you are editing. +Rather, the editor makes a copy of this file, in a place called the +.I buffer, +and remembers the file's +name. You do not affect the contents of the file unless and until you +write the changes you make back into the original file. +.NH 2 +Notational conventions +.PP +In our examples, input which must be typed as is will be presented in +\fBbold face\fR. Text which should be replaced with appropriate input +will be given in \fIitalics\fR. We will represent special characters +in \s-2SMALL CAPITALS\s0. +.NH 2 +Arrow keys +.PP +The editor command set is independent of the terminal +you are using. On most terminals with cursor positioning keys, these keys +will also work within the editor. +If you don't have cursor positioning keys, or even if you do, you can use +the \fBh j k\fR and \fBl\fR keys as cursor positioning +keys (these are labelled with arrows on an +.I adm3a).* +.PP +(Particular note for the HP2621: on this terminal the function keys +must be \fIshifted\fR (ick) to send to the machine, otherwise they +only act locally. Unshifted use will leave the cursor positioned +incorrectly.) +.FS +* As we will see later, +.I h +moves back to the left (like control-h which is a backspace), +.I j +moves down (in the same column), +.I k +moves up (in the same column), +and +.I l +moves to the right. +.FE +.NH 2 +Special characters: \s-2ESC\s0, \s-2CR\s0 and \s-2DEL\s0 +.PP +Several of these special characters are very important, so be sure to +find them right now. Look on your keyboard for a key labelled \s-2ESC\s0 +or \s-2ALT\s0. It should be near the upper left corner of your terminal. +Try hitting this key a few times. The editor will ring the bell +to indicate that it is in a quiescent state.\*(dd +.FS +\*(dd On smart terminals where it is possible, the editor will quietly +flash the screen rather than ringing the bell. +.FE +Partially formed commands are cancelled by \s-2ESC\s0, and when you insert +text in the file you end the text insertion +with \s-2ESC\s0. This key is a fairly +harmless one to hit, so you can just hit it if you don't know +what is going on until the editor rings the bell. +.PP +The \s-2CR\s0 or \s-2RETURN\s0 key is important because it is used +to terminate certain commands. +It is usually at the right side of the keyboard, +and is the same command used at the end of each shell command. +.PP +Another very useful key is the \s-2DEL\s0 or \s-2RUB\s0 key, which generates +an interrupt, telling the editor to stop what it is doing. +It is a forceful way of making the editor listen +to you, or to return it to the quiescent state if you don't know or don't +like what is going on. Try hitting the `/' key on your terminal. This +key is used when you want to specify a string to be searched for. The +cursor should now be positioned at the bottom line of the terminal after +a `/' printed as a prompt. You can get the cursor back to the current +position by hitting the \s-2DEL\s0 or \s-2RUB\s0 key; try this now.* +.FS +* Backspacing over the `/' will also cancel the search. +.FE +From now on we will simply refer to hitting the \s-2DEL\s0 or \s-2RUB\s0 +key as ``sending an interrupt.''** +.FS +** On some systems, this interruptibility comes at a price: you cannot type +ahead when the editor is computing with the cursor on the bottom line. +.FE +.PP +The editor often echoes your commands on the last line of the terminal. +If the cursor is on the first position of this last line, then the editor +is performing a computation, such as computing a new position in the +file after a search or running a command to reformat part of the buffer. +When this is happening you can stop the editor by +sending an interrupt. +.NH 2 +Getting out of the editor +.PP +After you have worked with this introduction for a while, and you wish +to do something else, you can give the command \fBZZ\fP +to the editor. +This will write the contents of the editor's buffer back into +the file you are editing, if you made any changes, and then quit from +the editor. You can also end an editor +session by giving the command \fB:q!\fR\s-2CR\s0;\*(dg +.FS +\*(dg All commands which read from the last display line can also be +terminated with a \s-2ESC\s0 as well as an \s-2CR\s0. +.FE +this is a dangerous but occasionally essential +command which ends the editor session and discards all your changes. +You need to know about this command in case you change the editor's +copy of a file you wish only to look at. Be very careful +not to give this command when you really want to save +the changes you have made. +.NH 1 +Moving around in the file +.NH 2 +Scrolling and paging +.PP +The editor has a number of commands for moving around in the file. +The most useful of these is generated by hitting the control and D keys +at the same time, a control-D or `^D'. We will use this two character +notation for referring to these control keys from now on. You may have +a key labelled `^' on your terminal. This key will be represented as `\(ua' +in this document; `^' is exclusively used as part of the `^x' notation +for control characters.\*(dd +.FS +\*(dd If you don't have a `^' key on your terminal +then there is probably a key labelled `\(ua'; in any case these characters +are one and the same. +.FE +.PP +As you know now if you tried hitting \fB^D\fR, this command scrolls down in +the file. The \fBD\fR thus stands for down. Many editor commands are mnemonic +and this makes them much easier to remember. For instance the command +to scroll up is \fB^U\fR. Many dumb terminals can't scroll up at all, in which +case hitting \fB^U\fR clears the screen and refreshes it +with a line which is farther back in the file at the top. +.PP +If you want to see more of the file below where you are, you can +hit \fB^E\fR to expose one more line at the bottom of the screen, +leaving the cursor where it is. +The command \fB^Y\fR (which is hopelessly non-mnemonic, but next to \fB^U\fR +on the keyboard) exposes one more line at the top of the screen. +.PP +There are other ways to move around in the file; the keys \fB^F\fR and \fB^B\fR +move forward and backward a page, +keeping a couple of lines of continuity between screens +so that it is possible to read through a file using these rather than +\fB^D\fR and \fB^U\fR if you wish. +.PP +Notice the difference between scrolling and paging. If you are trying +to read the text in a file, hitting \fB^F\fR to move forward a page +will leave you only a little context to look back at. Scrolling on the +other hand leaves more context, and happens more smoothly. You can continue +to read the text as scrolling is taking place. +.NH 2 +Searching, goto, and previous context +.PP +Another way to position yourself in the file is by giving the editor a string +to search for. Type the character \fB/\fR followed by a string of characters +terminated by \s-2CR\s0. The editor will position the cursor +at the next occurrence of this string. +Try hitting \fBn\fR to then go to the next occurrence of this string. +The character \fB?\fR will search backwards from where you are, and is +otherwise like \fB/\fR.\*(dg +.FS +\*(dg These searches will normally wrap around the end of the file, and thus +find the string even if it is not on a line in the direction you search +provided it is anywhere else in the file. You can disable this wraparound +in scans by giving the command \fB:se nowrapscan\fR\s-2CR\s0, +or more briefly \fB:se nows\fR\s-2CR\s0. +.FE +.PP +If the search string you give the editor is not present in the +file the editor will print +a diagnostic on the last line of the screen, and the cursor will be returned +to its initial position. +.PP +If you wish the search to match only at the beginning of a line, begin +the search string with an \fB\(ua\fR. To match only at the end of +a line, end the search string with a \fB$\fR. +Thus \fB/\(uasearch\fR\s-2CR\s0 will search for the word `search' at +the beginning of a line, and \fB/last$\fR\s-2CR\s0 searches for the +word `last' at the end of a line.* +.FS +*Actually, the string you give to search for here can be a +.I "regular expression" +in the sense of the editors +.I ex (1) +and +.I ed (1). +If you don't wish to learn about this yet, you can disable this more +general facility by doing +\fB:se\ nomagic\fR\s-2CR\s0; +by putting this command in +EXINIT +in your environment, you can have this always be in effect (more +about +.I EXINIT +later.) +.FE +.PP +The command \fBG\fR, when preceded by a number will position the cursor +at that line in the file. +Thus \fB1G\fR will move the cursor to +the first line of the file. If you give \fBG\fR no count, then it moves +to the end of the file. +.PP +If you are near the end of the file, and the last line is not at the bottom +of the screen, the editor will place only the character `~' on each remaining +line. This indicates that the last line in the file is on the screen; +that is, the `~' lines are past the end of the file. +.PP +You can find out the state of the file you are editing by typing a \fB^G\fR. +The editor will show you the name of the file you are editing, the number +of the current line, the number of lines in the buffer, and the percentage +of the way through the buffer which you are. +Try doing this now, and remember the number of the line you are on. +Give a \fBG\fR command to get to the end and then another \fBG\fR command +to get back where you were. +.PP +You can also get back to a previous position by using the command +\fB\(ga\(ga\fR (two back quotes). +This is often more convenient than \fBG\fR because it requires no advance +preparation. +Try giving a \fBG\fR or a search with \fB/\fR or \fB?\fR and then a +\fB\(ga\(ga\fR to get back to where you were. If you accidentally hit +\fBn\fR or any command which moves you far away from a context of interest, you +can quickly get back by hitting \fB\(ga\(ga\fR. +.NH 2 +Moving around on the screen +.PP +Now try just moving the cursor around on the screen. +If your terminal has arrow keys (4 or 5 keys with arrows +going in each direction) try them and convince yourself +that they work. +If you don't have working arrow keys, you can always use +.B h , +.B j , +.B k , +and +.B l . +Experienced users of +.I vi +prefer these keys to arrow keys, +because they are usually right underneath their fingers. +.PP +Hit the \fB+\fR key. Each time you do, notice that the cursor +advances to the next line in the file, at the first non-white position +on the line. The \fB\-\fR key is like \fB+\fR but goes the other way. +.PP +These are very common keys for moving up and down lines in the file. +Notice that if you go off the bottom or top with these keys then the +screen will scroll down (and up if possible) to bring a line at a time +into view. The \s-2RETURN\s0 key has the same effect as the \fB+\fR +key. +.PP +.I Vi +also has commands to take you to the top, middle and bottom of the screen. +\fBH\fR will take you to the top (home) line on the screen. +Try preceding it with a +number as in \fB3H\fR. +This will take you to the third line on the screen. +Many +.I vi +commands take preceding numbers and do interesting things with them. +Try \fBM\fR, +which takes you to the middle line on the screen, +and \fBL\fR, +which takes you to the last line on the screen. +\fBL\fR also takes counts, thus +\fB5L\fR will take you to the fifth line from the bottom. +.NH 2 +Moving within a line +.PP +Now try picking a word on some line on the screen, not the +first word on the line. +move the cursor using \s-2RETURN\s0 and \fB\-\fR to be on the line where +the word is. +Try hitting the \fBw\fR key. This will advance the cursor to the +next word on the line. +Try hitting the \fBb\fR key to back up words +in the line. +Also try the \fBe\fR key which advances you to the end of the current +word rather than to the beginning of the next word. +Also try \s-2SPACE\s0 (the space bar) which moves right one character +and the \s-2BS\s0 (backspace or \fB^H\fR) key which moves left one character. +The key \fBh\fR works as \fB^H\fR does and is useful if you don't have +a \s-2BS\s0 key. +(Also, as noted just above, \fBl\fR will move to the right.) +.PP +If the line had punctuation in it you may have noticed that +that the \fBw\fR and \fBb\fR +keys stopped at each group of punctuation. You can also go back and +forwards words without stopping at punctuation by using \fBW\fR and \fBB\fR +rather than the lower case equivalents. Think of these as bigger words. +Try these on a few lines with punctuation to see how they differ from +the lower case \fBw\fR and \fBb\fR. +.PP +The word keys wrap around the end of line, +rather than stopping at the end. Try moving to a word on a line below +where you are by repeatedly hitting \fBw\fR. +.NH 2 +Summary +.IP +.TS +lw(.50i)b a. +\fR\s-2SPACE\s0\fP advance the cursor one position +^B backwards to previous page +^D scrolls down in the file +^E exposes another line at the bottom +^F forward to next page +^G tell what is going on +^H backspace the cursor +^N next line, same column +^P previous line, same column +^U scrolls up in the file +^Y exposes another line at the top ++ next line, at the beginning +\- previous line, at the beginning +/ scan for a following string forwards +? scan backwards +B back a word, ignoring punctuation +G go to specified line, last default +H home screen line +M middle screen line +L last screen line +W forward a word, ignoring punctuation +b back a word +e end of current word +n scan for next instance of \fB/\fR or \fB?\fR pattern +w word after this word +.TE +.NH 2 +View +.PP +If you want to use the editor to look at a file, +rather than to make changes, +invoke it as +.I view +instead of +.I vi . +This will set the +.I readonly +option which will prevent you from +accidently overwriting the file. +.NH 1 +Making simple changes +.NH 2 +Inserting +.PP +One of the most useful commands is the +\fBi\fR (insert) command. +After you type \fBi\fR, everything you type until you hit \s-2ESC\s0 +is inserted into the file. +Try this now; position yourself to some word in the file and try inserting +text before this word. +If you are on an dumb terminal it will seem, for a minute, +that some of the characters in your line have been overwritten, but they will +reappear when you hit \s-2ESC\s0. +.PP +Now try finding a word which can, but does not, end in an `s'. +Position yourself at this word and type \fBe\fR (move to end of word), then +\fBa\fR for append and then `s\s-2ESC\s0' to terminate the textual insert. +This sequence of commands can be used to easily pluralize a word. +.PP +Try inserting and appending a few times to make sure you understand how +this works; \fBi\fR placing text to the left of the cursor, \fBa\fR to +the right. +.PP +It is often the case that you want to add new lines to the file you are +editing, before or after some specific line in the file. Find a line +where this makes sense and then give the command \fBo\fR to create a +new line after the line you are on, or the command \fBO\fR to create +a new line before the line you are on. After you create a new line in +this way, text you type up to an \s-2ESC\s0 is inserted on the new line. +.PP +Many related editor commands +are invoked by the same letter key and differ only in that one is given +by a lower +case key and the other is given by +an upper case key. In these cases, the +upper case key often differs from the lower case key in its sense of +direction, with +the upper case key working backward and/or up, while the lower case +key moves forward and/or down. +.PP +Whenever you are typing in text, you can give many lines of input or +just a few characters. +To type in more than one line of text, +hit a \s-2RETURN\s0 at the middle of your input. A new line will be created +for text, and you can continue to type. If you are on a slow +and dumb terminal the editor may choose to wait to redraw the +tail of the screen, and will let you type over the existing screen lines. +This avoids the lengthy delay which would occur if the editor attempted +to keep the tail of the screen always up to date. The tail of the screen will +be fixed up, and the missing lines will reappear, when you hit \s-2ESC\s0. +.PP +While you are inserting new text, you can use the characters you normally use +at the system command level (usually \fB^H\fR or \fB#\fR) to backspace +over the last +character which you typed, and the character which you use to kill input lines +(usually \fB@\fR, \fB^X\fR, or \fB^U\fR) +to erase the input you have typed on the current line.\*(dg +.FS +\*(dg In fact, the character \fB^H\fR (backspace) always works to erase the +last input character here, regardless of what your erase character is. +.FE +The character \fB^W\fR +will erase a whole word and leave you after the space after the previous +word; it is useful for quickly backing up in an insert. +.PP +Notice that when you backspace during an insertion the characters you +backspace over are not erased; the cursor moves backwards, and the characters +remain on the display. This is often useful if you are planning to type +in something similar. In any case the characters disappear when when +you hit \s-2ESC\s0; if you want to get rid of them immediately, hit an +\s-2ESC\s0 and then \fBa\fR again. +.PP +Notice also that you can't erase characters which you didn't insert, and that +you can't backspace around the end of a line. If you need to back up +to the previous line to make a correction, just hit \s-2ESC\s0 and move +the cursor back to the previous line. After making the correction you +can return to where you were and use the insert or append command again. +.NH 2 +Making small corrections +.PP +You can make small corrections in existing text quite easily. +Find a single character which is wrong or just pick any character. +Use the arrow keys to find the character, or +get near the character with the word motion keys and then either +backspace (hit the \s-2BS\s0 key or \fB^H\fR or even just \fBh\fR) or +\s-2SPACE\s0 (using the space bar) +until the cursor is on the character which is wrong. +If the character is not needed then hit the \fBx\fP key; this deletes +the character from the file. It is analogous to the way you \fBx\fP +out characters when you make mistakes on a typewriter (except it's not +as messy). +.PP +If the character +is incorrect, you can replace it with the correct character by giving +the command \fBr\fR\fIc\fR, +where \fIc\fR is replaced by the correct character. +Finally if the character which is incorrect should be replaced +by more than one character, give the command \fBs\fR which substitutes +a string of characters, ending with \s-2ESC\s0, for it. +If there are a small number of characters +which are wrong you can precede \fBs\fR with a count of the number of +characters to be replaced. Counts are also useful with \fBx\fR to specify +the number of characters to be deleted. +.NH 2 +More corrections: operators +.PP +You already know almost enough to make changes at a higher level. +All you need to know now is that the +.B d +key acts as a delete operator. Try the command +.B dw +to delete a word. +Try hitting \fB.\fR a few times. Notice that this repeats the effect +of the \fBdw\fR. The command \fB.\fR repeats the last command which +made a change. You can remember it by analogy with an ellipsis `\fB...\fR'. +.PP +Now try +\fBdb\fR. +This deletes a word backwards, namely the preceding word. +Try +\fBd\fR\s-2SPACE\s0. This deletes a single character, and is equivalent +to the \fBx\fR command. +.PP +Another very useful operator is +.B c +or change. The command +.B cw +thus changes the text of a single word. +You follow it by the replacement text ending with an \s-2ESC\s0. +Find a word which you can change to another, and try this +now. +Notice that the end of the text to be changed was marked with the character +`$' so that you can see this as you are typing in the new material. +.NH 2 +Operating on lines +.PP +It is often the case that you want to operate on lines. +Find a line which you want to delete, and type +\fBdd\fR, +the +.B d +operator twice. This will delete the line. +If you are on a dumb terminal, the editor may just erase the line on +the screen, replacing it with a line with only an @ on it. This line +does not correspond to any line in your file, but only acts as a place +holder. It helps to avoid a lengthy redraw of the rest of the screen +which would be necessary to close up the hole created by the deletion +on a terminal without a delete line capability. +.PP +Try repeating the +.B c +operator twice; this will change a whole line, erasing its previous contents and +replacing them with text you type up to an \s-2ESC\s0.\*(dg +.FS +\*(dg The command \fBS\fR is a convenient synonym for for \fBcc\fR, by +analogy with \fBs\fR. Think of \fBS\fR as a substitute on lines, while +\fBs\fR is a substitute on characters. +.FE +.PP +You can delete or change more than one line by preceding the +.B dd +or +.B cc +with a count, i.e. \fB5dd\fR deletes 5 lines. +You can also give a command like \fBdL\fR to delete all the lines up to +and including +the last line on the screen, or \fBd3L\fR to delete through the third from +the bottom line. Try some commands like this now.* +.FS +* One subtle point here involves using the \fB/\fR search after a \fBd\fR. +This will normally delete characters from the current position to the +point of the match. If what is desired is to delete whole lines +including the two points, give the pattern as \fB/pat/+0\fR, a line address. +.FE +Notice that the editor lets you know when you change a large number of +lines so that you can see the extent of the change. +The editor will also always tell you when a change you make affects text which +you cannot see. +.NH 2 +Undoing +.PP +Now suppose that the last change which you made was incorrect; +you could use the insert, delete and append commands to put the correct +material back. However, since it is often the case that we regret a +change or make a change incorrectly, the editor provides a +.B u +(undo) command to reverse the last change which you made. +Try this a few times, and give it twice in a row to notice that an +.B u +also undoes a +.B u. +.PP +The undo command lets you reverse only a single change. After you make +a number of changes to a line, you may decide that you would rather have +the original state of the line back. The +.B U +command restores the current line to the state before you started changing +it. +.PP +You can recover text which you delete, even if +undo will not bring it back; see the section on recovering lost text +below. +.NH 2 +Summary +.IP +.TS +lw(.50i)b a. +\fR\s-2SPACE\s0\fP advance the cursor one position +^H backspace the cursor +^W erase a word during an insert +\fRerase\fP your erase (usually ^H or #), erases a character during an insert +\fRkill\fP your kill (usually @, ^X, or ^U), kills the insert on this line +\&\fB.\fP repeats the changing command +O opens and inputs new lines, above the current +U undoes the changes you made to the current line +a appends text after the cursor +c changes the object you specify to the following text +d deletes the object you specify +i inserts text before the cursor +o opens and inputs new lines, below the current +u undoes the last change +.TE +.NH 1 +Moving about; rearranging and duplicating text +.NH 2 +Low level character motions +.PP +Now move the cursor to a line where there is a punctuation or a bracketing +character such as a parenthesis or a comma or period. Try the command +\fBf\fR\fIx\fR where \fIx\fR is this character. This command finds +the next \fIx\fR character to the right of the cursor in the current +line. Try then hitting a \fB;\fR, which finds the next instance of the +same character. By using the \fBf\fR command and then a sequence of +\fB;\fR's you can often +get to a particular place in a line much faster than with a sequence +of word motions or \s-2SPACE\s0s. +There is also a \fBF\fR command, which is like \fBf\fR, but searches +backward. The \fB;\fR command repeats \fBF\fR also. +.PP +When you are operating on the text in a line it is often desirable to +deal with the characters up to, but not including, the first instance of +a character. Try \fBdf\fR\fIx\fR for some \fIx\fR now and +notice that the \fIx\fR character is deleted. Undo this with \fBu\fR +and then try \fBdt\fR\fIx\fR; the \fBt\fR here stands for to, i.e. +delete up to the next \fIx\fR, but not the \fIx\fR. The command \fBT\fR +is the reverse of \fBt\fR. +.PP +When working with the text of a single line, an \fB\(ua\fR moves the +cursor to the first non-white position on the line, and a +\fB$\fR moves it to the end of the line. Thus \fB$a\fR will append new +text at the end of the current line. +.PP +Your file may have tab (\fB^I\fR) characters in it. These +characters are represented as a number of spaces expanding to a tab stop, +where tab stops are every 8 positions.* +.FS +* This is settable by a command of the form \fB:se ts=\fR\fIx\fR\s-2CR\s0, +where \fIx\fR is 4 to set tabstops every four columns. This has +effect on the screen representation within the editor. +.FE +When the cursor is at a tab, it sits on the last of the several spaces +which represent that tab. Try moving the cursor back and forth over +tabs so you understand how this works. +.PP +On rare occasions, your file may have nonprinting characters in it. +These characters are displayed in the same way they are represented in +this document, that is with a two character code, the first character +of which is `^'. On the screen non-printing characters resemble a `^' +character adjacent to another, but spacing or backspacing over the character +will reveal that the two characters are, like the spaces representing +a tab character, a single character. +.PP +The editor sometimes discards control characters, +depending on the character and the setting of the +.I beautify +option, +if you attempt to insert them in your file. +You can get a control character in the file by beginning +an insert and then typing a \fB^V\fR before the control +character. The +\fB^V\fR quotes the following character, causing it to be +inserted directly into the file. +.PP +.NH 2 +Higher level text objects +.PP +In working with a document it is often advantageous to work in terms +of sentences, paragraphs, and sections. The operations \fB(\fR and \fB)\fR +move to the beginning of the previous and next sentences respectively. +Thus the command \fBd)\fR will delete the rest of the current sentence; +likewise \fBd(\fR will delete the previous sentence if you are at the +beginning of the current sentence, or the current sentence up to where +you are if you are not at the beginning of the current sentence. +.PP +A sentence is defined to end at a `.', `!' or `?' which is followed by +either the end of a line, or by two spaces. Any number of closing `)', +`]', `"' and `\(aa' characters may appear after the `.', `!' or `?' before +the spaces or end of line. +.PP +The operations \fB{\fR and \fB}\fR move over paragraphs and the operations +\fB[[\fR and \fB]]\fR move over sections.\*(dg +.FS +\*(dg The \fB[[\fR and \fB]]\fR operations +require the operation character to be doubled because they can move the +cursor far from where it currently is. While it is easy to get back +with the command \fB\(ga\(ga\fP, +these commands would still be frustrating +if they were easy to hit accidentally. +.FE +.PP +A paragraph begins after each empty line, and also +at each of a set of paragraph macros, specified by the pairs of characters +in the definition of the string valued option \fIparagraphs\fR. +The default setting for this option defines the paragraph macros of the +\fI\-ms\fR and \fI\-mm\fR macro packages, i.e. the `.IP', `.LP', `.PP' +and `.QP', `.P' and `.LI' macros.\*(dd +.FS +\*(dd You can easily change or extend this set of macros by assigning a +different string to the \fIparagraphs\fR option in your EXINIT. +See section 6.2 for details. +The `.bp' directive is also considered to start a paragraph. +.FE +Each paragraph boundary is also a sentence boundary. The sentence +and paragraph commands can +be given counts to operate over groups of sentences and paragraphs. +.PP +Sections in the editor begin after each macro in the \fIsections\fR option, +normally `.NH', `.SH', `.H' and `.HU', and each line with a formfeed \fB^L\fR +in the first column. +Section boundaries are always line and paragraph boundaries also. +.PP +Try experimenting with the sentence and paragraph commands until you are +sure how they work. If you have a large document, try looking through +it using the section commands. +The section commands interpret a preceding count as a different window size in +which to redraw the screen at the new location, and this window size +is the base size for newly drawn windows until another size is specified. +This is very useful +if you are on a slow terminal and are looking for a particular section. +You can give the first section command a small count to then see each successive +section heading in a small window. +.NH 2 +Rearranging and duplicating text +.PP +The editor has a single unnamed buffer where the last deleted or +changed away text is saved, and a set of named buffers \fBa\fR\-\fBz\fR +which you can use to save copies of text and to move text around in +your file and between files. +.PP +The operator +.B y +yanks a copy of the object which follows into the unnamed buffer. +If preceded by a buffer name, \fB"\fR\fIx\fR\|\fBy\fR, where +\fIx\fR here is replaced by a letter \fBa\-z\fR, it places the text in the named +buffer. The text can then be put back in the file with the commands +.B p +and +.B P; +\fBp\fR puts the text after or below the cursor, while \fBP\fR puts the text +before or above the cursor. +.PP +If the text which you +yank forms a part of a line, or is an object such as a sentence which +partially spans more than one line, then when you put the text back, +it will be placed after the cursor (or before if you +use \fBP\fR). If the yanked text forms whole lines, they will be put +back as whole lines, without changing the current line. In this case, +the put acts much like a \fBo\fR or \fBO\fR command. +.PP +Try the command \fBYP\fR. This makes a copy of the current line and +leaves you on this copy, which is placed before the current line. +The command \fBY\fR is a convenient abbreviation for \fByy\fR. +The command \fBYp\fR will also make a copy of the current line, and place +it after the current line. You can give \fBY\fR a count of lines to +yank, and thus duplicate several lines; try \fB3YP\fR. +.PP +To move text within the buffer, you need to delete it in one place, and +put it back in another. You can precede a delete operation by the +name of a buffer in which the text is to be stored as in \fB"a5dd\fR +deleting 5 lines into the named buffer \fIa\fR. You can then move the +cursor to the eventual resting place of the these lines and do a \fB"ap\fR +or \fB"aP\fR to put them back. +In fact, you can switch and edit another file before you put the lines +back, by giving a command of the form \fB:e \fR\fIname\fR\s-2CR\s0 where +\fIname\fR is the name of the other file you want to edit. You will +have to write back the contents of the current editor buffer (or discard +them) if you have made changes before the editor will let you switch +to the other file. +An ordinary delete command saves the text in the unnamed buffer, +so that an ordinary put can move it elsewhere. +However, the unnamed buffer is lost when you change files, +so to move text from one file to another you should use an unnamed buffer. +.NH 2 +Summary. +.IP +.TS +lw(.50i)b a. +\(ua first non-white on line +$ end of line +) forward sentence +} forward paragraph +]] forward section +( backward sentence +{ backward paragraph +[[ backward section +f\fIx\fR find \fIx\fR forward in line +p put text back, after cursor or below current line +y yank operator, for copies and moves +t\fIx\fR up to \fIx\fR forward, for operators +F\fIx\fR f backward in line +P put text back, before cursor or above current line +T\fIx\fR t backward in line +.TE +.NH 1 +High level commands +.NH 2 +Writing, quitting, editing new files +.PP +So far we have seen how to enter +.I vi +and to write out our file using either +\fBZZ\fR or \fB:w\fR\s-2CR\s0. The first exits from +the editor, +(writing if changes were made), +the second writes and stays in the editor. +.PP +If you have changed the editor's copy of the file but do not wish to +save your changes, either because you messed up the file or decided that the +changes are not an improvement to the file, then you can give the command +\fB:q!\fR\s-2CR\s0 to quit from the editor without writing the changes. +You can also reedit the same file (starting over) by giving the command +\fB:e!\fR\s-2CR\s0. These commands should be used only rarely, and with +caution, as it is not possible to recover the changes you have made after +you discard them in this manner. +.PP +You can edit a different file without leaving the editor by giving the +command \fB:e\fR\ \fIname\fR\s-2CR\s0. If you have not written out +your file before you try to do this, then the editor will tell you this, +and delay editing the other file. You can then give the command +\fB:w\fR\s-2CR\s0 to save your work and then the \fB:e\fR\ \fIname\fR\s-2CR\s0 +command again, or carefully give the command \fB:e!\fR\ \fIname\fR\s-2CR\s0, +which edits the other file discarding the changes you have made to the +current file. +To have the editor automatically save changes, +include +.I "set autowrite" +in your EXINIT, +and use \fB:n\fP instead of \fB:e\fP. +.NH 2 +Escaping to a shell +.PP +You can get to a shell to execute a single command by giving a +.I vi +command of the form \fB:!\fIcmd\fR\s-2CR\s0. +The system will run the single command +.I cmd +and when the command finishes, the editor will ask you to hit a \s-2RETURN\s0 +to continue. When you have finished looking at the output on the screen, +you should hit \s-2RETURN\s0 and the editor will clear the screen and +redraw it. You can then continue editing. +You can also give another \fB:\fR command when it asks you for a \s-2RETURN\s0; +in this case the screen will not be redrawn. +.PP +If you wish to execute more than one command in the shell, then you can +give the command \fB:sh\fR\s-2CR\s0. +This will give you a new shell, and when you finish with the shell, ending +it by typing a \fB^D\fR, the editor will clear the screen and continue. +.PP +On systems which support it, \fB^Z\fP will suspend the editor +and return to the (top level) shell. +When the editor is resumed, the screen will be redrawn. +.NH 2 +Marking and returning +.PP +The command \fB\(ga\(ga\fR returned to the previous place +after a motion of the cursor by a command such as \fB/\fR, \fB?\fR or +\fBG\fR. You can also mark lines in the file with single letter tags +and return to these marks later by naming the tags. Try marking the +current line with the command \fBm\fR\fIx\fR, where you should pick some +letter for \fIx\fR, say `a'. Then move the cursor to a different line +(any way you like) and hit \fB\(gaa\fR. The cursor will return to the +place which you marked. +Marks last only until you edit another file. +.PP +When using operators such as +.B d +and referring to marked lines, it is often desirable to delete whole lines +rather than deleting to the exact position in the line marked by \fBm\fR. +In this case you can use the form \fB\(aa\fR\fIx\fR rather than +\fB\(ga\fR\fIx\fR. Used without an operator, \fB\(aa\fR\fIx\fR will move to +the first non-white character of the marked line; similarly \fB\(aa\(aa\fR +moves to the first non-white character of the line containing the previous +context mark \fB\(ga\(ga\fR. +.NH 2 +Adjusting the screen +.PP +If the screen image is messed up because of a transmission error to your +terminal, or because some program other than the editor wrote output +to your terminal, you can hit a \fB^L\fR, the \s-2ASCII\s0 form-feed +character, to cause the screen to be refreshed. +.PP +On a dumb terminal, if there are @ lines in the middle of the screen +as a result of line deletion, you may get rid of these lines by typing +\fB^R\fR to cause the editor to retype the screen, closing up these holes. +.PP +Finally, if you wish to place a certain line on the screen at the top +middle or bottom of the screen, you can position the cursor to that line, +and then give a \fBz\fR command. +You should follow the \fBz\fR command with a \s-2RETURN\s0 if you want +the line to appear at the top of the window, a \fB.\fR if you want it +at the center, or a \fB\-\fR if you want it at the bottom. +.NH 1 +Special topics +.NH 2 +Editing on slow terminals +.PP +When you are on a slow terminal, it is important to limit the amount +of output which is generated to your screen so that you will not suffer +long delays, waiting for the screen to be refreshed. We have already +pointed out how the editor optimizes the updating of the screen during +insertions on dumb terminals to limit the delays, and how the editor erases +lines to @ when they are deleted on dumb terminals. +.PP +The use of the slow terminal insertion mode is controlled by the +.I slowopen +option. You can force the editor to use this mode even on faster terminals +by giving the command \fB:se slow\fR\s-2CR\s0. If your system is sluggish +this helps lessen the amount of output coming to your terminal. +You can disable this option by \fB:se noslow\fR\s-2CR\s0. +.PP +The editor can simulate an intelligent terminal on a dumb one. Try +giving the command \fB:se redraw\fR\s-2CR\s0. This simulation generates +a great deal of output and is generally tolerable only on lightly loaded +systems and fast terminals. You can disable this by giving the command + \fB:se noredraw\fR\s-2CR\s0. +.PP +The editor also makes editing more pleasant at low speed by starting +editing in a small window, and letting the window expand as you edit. +This works particularly well on intelligent terminals. The editor can +expand the window easily when you insert in the middle of the screen +on these terminals. If possible, try the editor on an intelligent terminal +to see how this works. +.PP +You can control the size of the window which is redrawn each time the +screen is cleared by giving window sizes as argument to the commands +which cause large screen motions: +.DS +.B ": / ? [[ ]] \(ga \(aa" +.DE +Thus if you are searching for a particular instance of a common string +in a file you can precede the first search command by a small number, +say 3, and the editor will draw three line windows around each instance +of the string which it locates. +.PP +You can easily expand or contract the window, placing the current line +as you choose, by giving a number on a \fBz\fR command, after the \fBz\fR +and before the following \s-2RETURN\s0, \fB.\fR or \fB\-\fR. Thus the +command \fBz5.\fR redraws the screen with the current line in the center +of a five line window.\*(dg +.FS +\*(dg Note that the command \fB5z.\fR has an entirely different effect, +placing line 5 in the center of a new window. +.FE +.PP +If the editor is redrawing or otherwise updating large portions of the +display, you can interrupt this updating by hitting a \s-2DEL\s0 or \s-2RUB\s0 +as usual. If you do this you may partially confuse the editor about +what is displayed on the screen. You can still edit the text on +the screen if you wish; clear up the confusion +by hitting a \fB^L\fR; or move or search again, ignoring the +current state of the display. +.PP +See section 7.8 on \fIopen\fR mode for another way to use the +.I vi +command set on slow terminals. +.NH 2 +Options, set, and editor startup files +.PP +The editor has a set of options, some of which have been mentioned above. +The most useful options are given in the following table. +.KF +.TS +lb lb lb lb +l l l a. +Name Default Description +_ +autoindent noai Supply indentation automatically +autowrite noaw Automatic write before \fB:n\fR, \fB:ta\fR, \fB^\(ua\fR, \fB!\fR +ignorecase noic Ignore case in searching +lisp nolisp \fB( { ) }\fR commands deal with S-expressions +list nolist Tabs print as ^I; end of lines marked with $ +magic nomagic The characters . [ and * are special in scans +number nonu Lines are displayed prefixed with line numbers +paragraphs para=IPLPPPQPbpP LI Macro names which start paragraphs +redraw nore Simulate a smart terminal on a dumb one +sections sect=NHSHH HU Macro names which start new sections +shiftwidth sw=8 Shift distance for <, > and input \fB^D\fP and \fB^T\fR +showmatch nosm Show matching \fB(\fP or \fB{\fP as \fB)\fP or \fB}\fR is typed +slowopen slow Postpone display updates during inserts +term dumb The kind of terminal you are using. +.TE +.KE +.PP +The options are of three kinds: numeric options, string options, and +toggle options. You can set numeric and string options by a statement +of the form +.DS +\fBset\fR \fIopt\fR\fB=\fR\fIval\fR +.DE +and toggle options can be set or unset by statements of one of the forms +.DS +\fBset\fR \fIopt\fR +\fBset\fR \fBno\fR\fIopt\fR +.DE +These statements can be placed in your EXINIT in your environment, +or given while you are running +.I vi +by preceding them with a \fB:\fR and following them with a \s-2CR\s0. +.PP +You can get a list of all options which you have changed by the +command \fB:set\fR\s-2CR\s0, or the value of a single option by the +command \fB:set\fR \fIopt\fR\fB?\fR\s-2CR\s0. +A list of all possible options and their values is generated by +\fB:set all\fP\s-2CR\s0. +Set can be abbreviated \fBse\fP. +Multiple options can be placed on one line, e.g. +\fB:se ai aw nu\fP\s-2CR\s0. +.PP +Options set by the \fBset\fP command only last +while you stay in the editor. +It is common to want to have certain options set whenever you +use the editor. +This can be accomplished by creating a list of \fIex\fP commands\*(dg +.FS +\*(dg +All commands which start with +.B : +are \fIex\fP commands. +.FE +which are to be run every time you start up \fIex\fP, \fIedit\fP, +or \fIvi\fP. +A typical list includes a \fBset\fP command, and possibly a few +\fBmap\fP commands. +Since it is advisable to get these commands on one line, they can +be separated with the | character, for example: +.DS +\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x +.DE +which sets the options \fIautoindent\fP, \fIautowrite\fP, \fIterse\fP, +(the +.B set +command), +makes @ delete a line, +(the first +.B map ), +and makes # delete a character, +(the second +.B map ). +(See section 6.9 for a description of the \fBmap\fP command) +This string should be placed in the variable EXINIT in your environment. +If you use the shell \fIcsh\fP, +put this line in the file +.I .login +in your home directory: +.DS +setenv EXINIT \(aa\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x\(aa +.DE +If you use the standard shell \fIsh\fP, +put these lines in the file +.I .profile +in your home directory: +.DS +EXINIT=\(aa\fBset\fP ai aw terse|\fBmap\fP @ dd|\fBmap\fP # x\(aa +export EXINIT +.DE +Of course, the particulars of the line would depend on which options +you wanted to set. +.NH 2 +Recovering lost lines +.PP +You might have a serious problem if you delete a number of lines and then +regret that they were deleted. Despair not, the editor saves the last +9 deleted blocks of text in a set of numbered registers 1\-9. +You can get the \fIn\fR'th previous deleted text back in your file by +the command +"\fR\fIn\fR\|\fBp\fR. +The "\fR here says that a buffer name is to follow, +\fIn\fR is the number of the buffer you wish to try +(use the number 1 for now), +and +.B p +is the put command, which puts text in the buffer after the cursor. +If this doesn't bring back the text you wanted, hit +.B u +to undo this and then +\fB\&.\fR +(period) +to repeat the put command. +In general the +\fB\&.\fR +command will repeat the last change you made. +As a special case, when the last command refers to a numbered text buffer, +the \fB.\fR command increments the number of the buffer before repeating +the command. Thus a sequence of the form +.DS +\fB"1pu.u.u.\fR +.DE +will, if repeated long enough, show you all the deleted text which has +been saved for you. +You can omit the +.B u +commands here to gather up all this text in the buffer, or stop after any +\fB\&.\fR command to keep just the then recovered text. +The command +.B P +can also be used rather than +.B p +to put the recovered text before rather than after the cursor. +.NH 2 +Recovering lost files +.PP +If the system crashes, you can recover the work you were doing +to within a few changes. You will normally receive mail when you next +login giving you the name of the file which has been saved for you. +You should then change to the directory where you were when the system +crashed and give a command of the form: +.DS +% \fBvi \-r\fR \fIname\fR +.DE +replacing \fIname\fR with the name of the file which you were editing. +This will recover your work to a point near where you left off.\*(dg +.FS +\*(dg In rare cases, some of the lines of the file may be lost. The +editor will give you the numbers of these lines and the text of the lines +will be replaced by the string `LOST'. These lines will almost always +be among the last few which you changed. You can either choose to discard +the changes which you made (if they are easy to remake) or to replace +the few lost lines by hand. +.FE +.PP +You can get a listing of the files which are saved for you by giving +the command: +.DS +% \fBvi \-r\fR +.DE +If there is more than one instance of a particular file saved, the editor +gives you the newest instance each time you recover it. You can thus +get an older saved copy back by first recovering the newer copies. +.PP +For this feature to work, +.I vi +must be correctly installed by a super user on your system, +and the +.I mail +program must exist to receive mail. +The invocation ``\fIvi -r\fP'' will not always list all saved files, +but they can be recovered even if they are not listed. +.NH 2 +Continuous text input +.PP +When you are typing in large amounts of text it is convenient to have +lines broken near the right margin automatically. You can cause this +to happen by giving the command +\fB:se wm=10\fR\s-2CR\s0. +This causes all lines to be broken at a space at least 10 columns +from the right hand edge of the screen. +.PP +If the editor breaks an input line and you wish to put it back together +you can tell it to join the lines with \fBJ\fR. You can give \fBJ\fR +a count of the number of lines to be joined as in \fB3J\fR to join 3 +lines. The editor supplies white space, if appropriate, +at the juncture of the joined +lines, and leaves the cursor at this white space. +You can kill the white space with \fBx\fR if you don't want it. +.NH 2 +Features for editing programs +.PP +The editor has a number of commands for editing programs. +The thing that most distinguishes editing of programs from editing of text +is the desirability of maintaining an indented structure to the body of +the program. The editor has a +.I autoindent +facility for helping you generate correctly indented programs. +.PP +To enable this facility you can give the command \fB:se ai\fR\s-2CR\s0. +Now try opening a new line with \fBo\fR and type some characters on the +line after a few tabs. If you now start another line, notice that the +editor supplies white space at the beginning of the line to line it up +with the previous line. You cannot backspace over this indentation, +but you can use \fB^D\fR key to backtab over the supplied indentation. +.PP +Each time you type \fB^D\fR you back up one position, normally to an +8 column boundary. This amount is settable; the editor has an option +called +.I shiftwidth +which you can set to change this value. +Try giving the command \fB:se sw=4\fR\s-2CR\s0 +and then experimenting with autoindent again. +.PP +For shifting lines in the program left and right, there are operators +.B < +and +.B >. +These shift the lines you specify right or left by one +.I shiftwidth. +Try +.B << +and +.B >> +which shift one line left or right, and +.B <L +and +.B >L +shifting the rest of the display left and right. +.PP +If you have a complicated expression and wish to see how the parentheses +match, put the cursor at a left or right parenthesis and hit \fB%\fR. +This will show you the matching parenthesis. +This works also for braces { and }, and brackets [ and ]. +.PP +If you are editing C programs, you can use the \fB[[\fR and \fB]]\fR keys +to advance or retreat to a line starting with a \fB{\fR, i.e. a function +declaration at a time. When \fB]]\fR is used with an operator it stops +after a line which starts with \fB}\fR; this is sometimes useful with +\fBy]]\fR. +.NH 2 +Filtering portions of the buffer +.PP +You can run system commands over portions of the buffer using the operator +\fB!\fR. +You can use this to sort lines in the buffer, or to reformat portions +of the buffer with a pretty-printer. +Try typing in a list of random words, one per line and ending them +with a blank line. Back up to the beginning of the list, and then give +the command \fB!}sort\fR\s-2CR\s0. This says to sort the next paragraph +of material, and the blank line ends a paragraph. +.NH 2 +Commands for editing \s-2LISP\s0 +.PP +If you are editing a \s-2LISP\s0 program you should set the option +.I lisp +by doing +\fB:se\ lisp\fR\s-2CR\s0. +This changes the \fB(\fR and \fB)\fR commands to move backward and forward +over s-expressions. +The \fB{\fR and \fB}\fR commands are like \fB(\fR and \fB)\fR but don't +stop at atoms. These can be used to skip to the next list, or through +a comment quickly. +.PP +The +.I autoindent +option works differently for \s-2LISP\s0, supplying indent to align at +the first argument to the last open list. If there is no such argument +then the indent is two spaces more than the last level. +.PP +There is another option which is useful for typing in \s-2LISP\s0, the +.I showmatch +option. +Try setting it with +\fB:se sm\fR\s-2CR\s0 +and then try typing a `(' some words and then a `)'. Notice that the +cursor shows the position of the `(' which matches the `)' briefly. +This happens only if the matching `(' is on the screen, and the cursor +stays there for at most one second. +.PP +The editor also has an operator to realign existing lines as though they +had been typed in with +.I lisp +and +.I autoindent +set. This is the \fB=\fR operator. +Try the command \fB=%\fR at the beginning of a function. This will realign +all the lines of the function declaration. +.PP +When you are editing \s-2LISP\s0,, the \fB[[\fR and \fR]]\fR advance +and retreat to lines beginning with a \fB(\fR, and are useful for dealing +with entire function definitions. +.NH 2 +Macros +.PP +.I Vi +has a parameterless macro facility, which lets you set it up so that +when you hit a single keystroke, the editor will act as though +you had hit some longer sequence of keys. You can set this up if +you find yourself typing the same sequence of commands repeatedly. +.PP +Briefly, there are two flavors of macros: +.IP a) +Ones where you put the macro body in a buffer register, say \fIx\fR. +You can then type \fB@x\fR to invoke the macro. The \fB@\fR may be followed +by another \fB@\fR to repeat the last macro. +.IP b) +You can use the +.I map +command from +.I vi +(typically in your +.I EXINIT ) +with a command of the form: +.DS +:map \fIlhs\fR \fIrhs\fR\s-2CR\f0 +.DE +mapping +.I lhs +into +.I rhs. +There are restrictions: +.I lhs +should be one keystroke (either 1 character or one function key) +since it must be entered within one second +(unless +.I notimeout +is set, in which case you can type it as slowly as you wish, +and +.I vi +will wait for you to finish it before it echoes anything). +The +.I lhs +can be no longer than 10 characters, the +.I rhs +no longer than 100. +To get a space, tab or newline into +.I lhs +or +.I rhs +you should escape them with a \fB^V\fR. +(It may be necessary to double the \fB^V\fR if the map +command is given inside +.I vi, +rather than in +.I ex.) +Spaces and tabs inside the +.I rhs +need not be escaped. +.PP +Thus to make the \fBq\fR key write and exit the editor, you can give +the command +.DS +:map q :wq\fB^V^V\fP\s-2CR CR\s0 +.DE +which means that whenever you type \fBq\fR, it will be as though you +had typed the four characters \fB:wq\fR\s-2CR\s0. +A \fB^V\fR's is needed because without it the \s-2CR\s0 would end the +\fB:\fR command, rather than becoming part of the +.I map +definition. +There are two +.B ^V 's +because from within +.I vi , +two +.B ^V 's +must be typed to get one. +The first \s-2CR\s0 is part of the +.I rhs , +the second terminates the : command. +.PP +Macros can be deleted with +.DS +unmap lhs +.DE +.PP +If the +.I lhs +of a macro is ``#0'' through ``#9'', this maps the particular function key +instead of the 2 character ``#'' sequence. So that terminals without +function keys can access such definitions, the form ``#x'' will mean function +key +.I x +on all terminals (and need not be typed within one second.) +The character ``#'' can be changed by using a macro in the usual way: +.DS +:map \fB^V^V^I\fP # +.DE +to use tab, for example. (This won't affect the +.I map +command, which still uses +.B #, +but just the invocation from visual mode. +.PP +The undo command reverses an entire macro call as a unit, +if it made any changes. +.PP +Placing a `!' after the word +.B map +causes the mapping to apply +to input mode, rather than command mode. +Thus, to arrange for \fB^T\fP to be the same as 4 spaces in input mode, +you can type: +.DS +:map \fB^T\fP \fB^V\fP\o'b/'\o'b/'\o'b/'\o'b/' +.DE +where +.B \o'b/' +is a blank. +The \fB^V\fP is necessary to prevent the blanks from being taken as +white space between the +.I lhs +and +.I rhs . +.NH +Word Abbreviations +.PP +A feature similar to macros in input mode is word abbreviation. +This allows you to type a short word and have it expanded into +a longer word or words. +The commands are +.B :abbreviate +and +.B :unabbreviate +(\fB:ab\fP +and +.B :una ) +and have the same syntax as +.B :map . +For example: +.DS +:ab eecs Electrical Engineering and Computer Sciences +.DE +causes the word `eecs' to always be changed into the +phrase `Electrical Engineering and Computer Sciences'. +Word abbreviation is different from macros in that +only whole words are affected. +If `eecs' were typed as part of a larger word, it would +be left alone. +Also, the partial word is echoed as it is typed. +There is no need for an abbreviation to be a single keystroke, +as it should be with a macro. +.NH 2 +Abbreviations +.PP +The editor has a number of short +commands which abbreviate longer commands which we +have introduced here. You can find these commands easily +on the quick reference card. +They often save a bit of typing and you can learn them as convenient. +.NH 1 +Nitty-gritty details +.NH 2 +Line representation in the display +.PP +The editor folds long logical lines onto many physical lines in the display. +Commands which advance lines advance logical lines and will skip +over all the segments of a line in one motion. The command \fB|\fR moves +the cursor to a specific column, and may be useful for getting near the +middle of a long line to split it in half. Try \fB80|\fR on a line which +is more than 80 columns long.\*(dg +.FS +\*(dg You can make long lines very easily by using \fBJ\fR to join together +short lines. +.FE +.PP +The editor only puts full lines on the display; if there is not enough +room on the display to fit a logical line, the editor leaves the physical +line empty, placing only an @ on the line as a place holder. When you +delete lines on a dumb terminal, the editor will often just clear the +lines to @ to save time (rather than rewriting the rest of the screen.) +You can always maximize the information on the screen by giving the \fB^R\fR +command. +.PP +If you wish, you can have the editor place line numbers before each line +on the display. Give the command \fB:se nu\fR\s-2CR\s0 to enable +this, and the command \fB:se nonu\fR\s-2CR\s0 to turn it off. +You can have tabs represented as \fB^I\fR and the ends of lines indicated +with `$' by giving the command \fB:se list\fR\s-2CR\s0; +\fB:se nolist\fR\s-2CR\s0 turns this off. +.PP +Finally, lines consisting of only the character `~' are displayed when +the last line in the file is in the middle of the screen. These represent +physical lines which are past the logical end of file. +.NH 2 +Counts +.PP +Most +.I vi +commands will use a preceding count to affect their behavior in some way. +The following table gives the common ways in which the counts are used: +.DS +.TS +l lb. +new window size : / ? [[ ]] \` \' +scroll amount ^D ^U +line/column number z G | +repeat effect \fRmost of the rest\fP +.TE +.DE +.PP +The editor maintains a notion of the current default window size. +On terminals which run at speeds greater than 1200 baud +the editor uses the full terminal screen. +On terminals which are slower than 1200 baud +(most dialup lines are in this group) +the editor uses 8 lines as the default window size. +At 1200 baud the default is 16 lines. +.PP +This size is the size used when the editor clears and refills the screen +after a search or other motion moves far from the edge of the current window. +The commands which take a new window size as count all often cause the +screen to be redrawn. If you anticipate this, but do not need as large +a window as you are currently using, you may wish to change the screen +size by specifying the new size before these commands. +In any case, the number of lines used on the screen will expand if you +move off the top with a \fB\-\fR or similar command or off the bottom +with a command such as \s-2RETURN\s0 or \fB^D\fR. +The window will revert to the last specified size the next time it is +cleared and refilled.\*(dg +.FS +\*(dg But not by a \fB^L\fR which just redraws the screen as it is. +.FE +.PP +The scroll commands \fB^D\fR and \fB^U\fR likewise remember the amount +of scroll last specified, using half the basic window size initially. +The simple insert commands use a count to specify a repetition of the +inserted text. Thus \fB10a+\-\-\-\-\fR\s-2ESC\s0 will insert a grid-like +string of text. +A few commands also use a preceding count as a line or column number. +.PP +Except for a few commands which ignore any counts (such as \fB^R\fR), +the rest of the editor commands use a count to indicate a simple repetition +of their effect. Thus \fB5w\fR advances five words on the current line, +while \fB5\fR\s-2RETURN\s0 advances five lines. A very useful instance +of a count as a repetition is a count given to the \fB.\fR command, which +repeats the last changing command. If you do \fBdw\fR and then \fB3.\fR, +you will delete first one and then three words. You can then delete +two more words with \fB2.\fR. +.NH 2 +More file manipulation commands +.PP +The following table lists the file manipulation commands which you can +use when you are in +.I vi. +.KF +.DS +.TS +lb l. +:w write back changes +:wq write and quit +:x write (if necessary) and quit (same as ZZ). +:e \fIname\fP edit file \fIname\fR +:e! reedit, discarding changes +:e + \fIname\fP edit, starting at end +:e +\fIn\fP edit, starting at line \fIn\fP +:e # edit alternate file +:w \fIname\fP write file \fIname\fP +:w! \fIname\fP overwrite file \fIname\fP +:\fIx,y\fPw \fIname\fP write lines \fIx\fP through \fIy\fP to \fIname\fP +:r \fIname\fP read file \fIname\fP into buffer +:r !\fIcmd\fP read output of \fIcmd\fP into buffer +:n edit next file in argument list +:n! edit next file, discarding changes to current +:n \fIargs\fP specify new argument list +:ta \fItag\fP edit file containing tag \fItag\fP, at \fItag\fP +.TE +.DE +.KE +All of these commands are followed by a \s-2CR\s0 or \s-2ESC\s0. +The most basic commands are \fB:w\fR and \fB:e\fR. +A normal editing session on a single file will end with a \fBZZ\fR command. +If you are editing for a long period of time you can give \fB:w\fR commands +occasionally after major amounts of editing, and then finish +with a \fBZZ\fR. When you edit more than one file, you can finish +with one with a \fB:w\fR and start editing a new file by giving a \fB:e\fR +command, +or set +.I autowrite +and use \fB:n\fP <file>. +.PP +If you make changes to the editor's copy of a file, but do not wish to +write them back, then you must give an \fB!\fR after the command you +would otherwise use; this forces the editor to discard any changes +you have made. Use this carefully. +.PP +The \fB:e\fR command can be given a \fB+\fR argument to start at the +end of the file, or a \fB+\fR\fIn\fR argument to start at line \fIn\fR\^. +In actuality, \fIn\fR may be any editor command not containing a space, +usefully a scan like \fB+/\fIpat\fR or \fB+?\fIpat\fR. +In forming new names to the \fBe\fR command, you can use the character +\fB%\fR which is replaced by the current file name, or the character +\fB#\fR which is replaced by the alternate file name. +The alternate file name is generally the last name you typed other than +the current file. Thus if you try to do a \fB:e\fR and get a diagnostic +that you haven't written the file, you can give a \fB:w\fR command and +then a \fB:e #\fR command to redo the previous \fB:e\fR. +.PP +You can write part of the buffer to a file by finding out the lines +that bound the range to be written using \fB^G\fR, and giving these +numbers after the \fB:\fR +and before the \fBw\fP, separated by \fB,\fR's. +You can also mark these lines with \fBm\fR and +then use an address of the form \fB\(aa\fR\fIx\fR\fB,\fB\(aa\fR\fIy\fR +on the \fBw\fR command here. +.PP +You can read another file into the buffer after the current line by using +the \fB:r\fR command. +You can similarly read in the output from a command, just use \fB!\fR\fIcmd\fR +instead of a file name. +.PP +If you wish to edit a set of files in succession, you can give all the +names on the command line, and then edit each one in turn using the command +\fB:n\fR. It is also possible to respecify the list of files to be edited +by giving the \fB:n\fR command a list of file names, or a pattern to +be expanded as you would have given it on the initial +.I vi +command. +.PP +If you are editing large programs, you will find the \fB:ta\fR command +very useful. It utilizes a data base of function names and their locations, +which can be created by programs such as +.I ctags, +to quickly find a function whose name you give. +If the \fB:ta\fR command will require the editor to switch files, then +you must \fB:w\fR or abandon any changes before switching. You can repeat +the \fB:ta\fR command without any arguments to look for the same tag +again. +.NH 2 +More about searching for strings +.PP +When you are searching for strings in the file with \fB/\fR and \fB?\fR, +the editor normally places you at the next or previous occurrence +of the string. If you are using an operator such as \fBd\fR, +\fBc\fR or \fBy\fR, then you may well wish to affect lines up to the +line before the line containing the pattern. You can give a search of +the form \fB/\fR\fIpat\fR\fB/\-\fR\fIn\fR to refer to the \fIn\fR'th line +before the next line containing \fIpat\fR, or you can use \fB\+\fR instead +of \fB\-\fR to refer to the lines after the one containing \fIpat\fR. +If you don't give a line offset, then the editor will affect characters +up to the match place, rather than whole lines; thus use ``+0'' to affect +to the line which matches. +.PP +You can have the editor ignore the case of words in the searches it does +by giving the command \fB:se ic\fR\s-2CR\s0. +The command \fB:se noic\fR\s-2CR\s0 turns this off. +.PP +Strings given to searches may actually be regular expressions. +If you do not want or need this facility, you should +.DS +set nomagic +.DE +in your EXINIT. +In this case, +only the characters \fB\(ua\fR and \fB$\fR are special in patterns. +The character \fB\e\fR is also then special (as it is most everywhere in +the system), and may be used to get at the +an extended pattern matching facility. +It is also necessary to use a \e before a +\fB/\fR in a forward scan or a \fB?\fR in a backward scan, in any case. +The following table gives the extended forms when \fBmagic\fR is set. +.DS +.TS +bl l. +\(ua at beginning of pattern, matches beginning of line +$ at end of pattern, matches end of line +\fB\&.\fR matches any character +\e< matches the beginning of a word +\e> matches the end of a word +[\fIstr\fP] matches any single character in \fIstr\fP +[\(ua\fIstr\fP] matches any single character not in \fIstr\fP +[\fIx\fP\-\fIy\fP] matches any character between \fIx\fP and \fIy\fP +* matches any number of the preceding pattern +.TE +.DE +If you use \fBnomagic\fR mode, then +the \fB. [\fR and \fB*\fR primitives are given with a preceding +\e. +.NH 2 +More about input mode +.PP +There are a number of characters which you can use to make corrections +during input mode. These are summarized in the following table. +.DS +.TS +lb l. +^H deletes the last input character +^W deletes the last input word, defined as by \fBb\fR +erase your erase character, same as \fB^H\fP +kill your kill character, deletes the input on this line +\e escapes a following \fB^H\fP and your erase and kill +\s-2ESC\s0 ends an insertion +\s-2DEL\s0 interrupts an insertion, terminating it abnormally +\s-2CR\s0 starts a new line +^D backtabs over \fIautoindent\fP +0^D kills all the \fIautoindent\fP +\(ua^D same as \fB0^D\fP, but restores indent next line +^V quotes the next non-printing character into the file +.TE +.DE +.PP +The most usual way of making corrections to input is by typing \fB^H\fR +to correct a single character, or by typing one or more \fB^W\fR's to +back over incorrect words. If you use \fB#\fR as your erase character +in the normal system, it will work like \fB^H\fR. +.PP +Your system kill character, normally \fB@\fR, \fB^X\fP or \fB^U\fR, +will erase all +the input you have given on the current line. +In general, you can neither +erase input back around a line boundary nor can you erase characters +which you did not insert with this insertion command. To make corrections +on the previous line after a new line has been started you can hit \s-2ESC\s0 +to end the insertion, move over and make the correction, and then return +to where you were to continue. The command \fBA\fR which appends at the +end of the current line is often useful for continuing. +.PP +If you wish to type in your erase or kill character (say # or @) then +you must precede it with a \fB\e\fR, just as you would do at the normal +system command level. A more general way of typing non-printing characters +into the file is to precede them with a \fB^V\fR. The \fB^V\fR echoes +as a \fB\(ua\fR character on which the cursor rests. This indicates that +the editor expects you to type a control character. In fact you may +type any character and it will be inserted into the file at that point.* +.FS +* This is not quite true. The implementation of the editor does +not allow the \s-2NULL\s0 (\fB^@\fR) character to appear in files. Also +the \s-2LF\s0 (linefeed or \fB^J\fR) character is used by the editor +to separate lines in the file, so it cannot appear in the middle of a +line. You can insert any other character, however, if you wait for the +editor to echo the \fB\(ua\fR before you type the character. In fact, +the editor will treat a following letter as a request for the corresponding +control character. This is the only way to type \fB^S\fR or \fB^Q\fP, +since the system normally uses them to suspend and resume output +and never gives them to the editor to process. +.FE +.PP +If you are using \fIautoindent\fR you can backtab over the indent which +it supplies by typing a \fB^D\fR. This backs up to a \fIshiftwidth\fR +boundary. +This only works immediately after the supplied \fIautoindent\fR. +.PP +When you are using \fIautoindent\fR you may wish to place a label at +the left margin of a line. The way to do this easily is to type \fB\(ua\fR +and then \fB^D\fR. The editor will move the cursor to the left margin +for one line, and restore the previous indent on the next. You can also +type a \fB0\fR followed immediately by a \fB^D\fR if you wish to kill +all the indent and not have it come back on the next line. +.NH 2 +Upper case only terminals +.PP +If your terminal has only upper case, you can still use +.I vi +by using the normal +system convention for typing on such a terminal. +Characters which you normally type are converted to lower case, and you +can type upper case letters by preceding them with a \e. +The characters { ~ } | \(ga are not available on such terminals, but you +can escape them as \e( \e\(ua \e) \e! \e\(aa. +These characters are represented on the display in the same way they +are typed.\*(dd +.FS +\*(dd The \e character you give will not echo until you type another +key. +.FE +.NH 2 +Vi and ex +.PP +.I Vi +is actually one mode of editing within the editor +.I ex. +When you are running +.I vi +you can escape to the line oriented editor of +.I ex +by giving the command +\fBQ\fR. +All of the +.B : +commands which were introduced above are available in +.I ex. +Likewise, most +.I ex +commands can be invoked from +.I vi +using :. +Just give them without the \fB:\fR and follow them with a \s-2CR\s0. +.PP +In rare instances, an internal error may occur in +.I vi. +In this case you will get a diagnostic and be left in the command mode of +.I ex. +You can then save your work and quit if you wish by giving a command +\fBx\fR after the \fB:\fR which \fIex\fR prompts you with, or you can +reenter \fIvi\fR by giving +.I ex +a +.I vi +command. +.PP +There are a number of things which you can do more easily in +.I ex +than in +.I vi. +Systematic changes in line oriented material are particularly easy. +You can read the advanced editing documents for the editor +.I ed +to find out a lot more about this style of editing. +Experienced +users often mix their use of +.I ex +command mode and +.I vi +command mode to speed the work they are doing. +.NH 2 +Open mode: vi on hardcopy terminals and ``glass tty's'' +\(dd +.PP +If you are on a hardcopy terminal or a terminal which does not have a cursor +which can move off the bottom line, you can still use the command set of +.I vi, +but in a different mode. +When you give a +.I vi +command, the editor will tell you that it is using +.I open +mode. +This name comes from the +.I open +command in +.I ex, +which is used to get into the same mode. +.PP +The only difference between +.I visual +mode +and +.I open +mode is the way in which the text is displayed. +.PP +In +.I open +mode the editor uses a single line window into the file, and moving backward +and forward in the file causes new lines to be displayed, always below the +current line. +Two commands of +.I vi +work differently in +.I open: +.B z +and +\fB^R\fR. +The +.B z +command does not take parameters, but rather draws a window of context around +the current line and then returns you to the current line. +.PP +If you are on a hardcopy terminal, +the +.B ^R +command will retype the current line. +On such terminals, the editor normally uses two lines to represent the +current line. +The first line is a copy of the line as you started to edit it, and you work +on the line below this line. +When you delete characters, the editor types a number of \e's to show +you the characters which are deleted. The editor also reprints the current +line soon after such changes so that you can see what the line looks +like again. +.PP +It is sometimes useful to use this mode on very slow terminals which +can support +.I vi +in the full screen mode. +You can do this by entering +.I ex +and using an +.I open +command. +.LP +.SH +Acknowledgements +.PP +Bruce Englar encouraged the early development of this display editor. +Peter Kessler helped bring sanity to version 2's command layout. +Bill Joy wrote versions 1 and 2.0 through 2.7, +and created the framework that users see in the present editor. +Mark Horton added macros and other features and made the +editor work on a large number of terminals and Unix systems. diff --git a/usr.bin/vi/USD.doc/vitut/vi.summary b/usr.bin/vi/USD.doc/vitut/vi.summary new file mode 100644 index 0000000..a7d9938 --- /dev/null +++ b/usr.bin/vi/USD.doc/vitut/vi.summary @@ -0,0 +1,468 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vi.summary 8.1 (Berkeley) 6/8/93 +.\" +.ds CH +.ds CF +.de TS +.br +.if !\\n(1T .RT +.ul 0 +.ti \\n(.iu +.if t .sp 0.25 +.if n .sp +.if \\$1H .TQ +.nr IX 1 +.. +.nr PS 9 +.ps 9 +.nr VS 11 +.vs 11 +.nr HM .50i +.nr FM .25i +.nr PO 0 +.po 0 +.nr LL 3.5i +.ll 3.5i +.de nc +.bp +.. +.de h +.LG +.B +\\$1 +.R +.NL +.. +.LG +.LG +.B +.ce +Ex Quick Reference +.R +.NL +.LP +.LP +.h "Entering/leaving ex" +.TS +aw(1.4i)b aw(1.8i). +% ex \fIname\fP edit \fIname\fP, start at end +% ex +\fIn\fP \fIname\fP ... at line \fIn\fP +% ex \-t \fItag\fP start at \fItag\fP +% ex \-r list saved files +% ex \-r \fIname\fP recover file \fIname\fP +% ex \fIname\fP ... edit first; rest via \fB:n\fP +% ex \-R \fIname\fP read only mode +: x exit, saving changes +: q! exit, discarding changes +.TE +.h "Ex states" +.TS +lw(1i) lw(2.0i). +Command T{ +Normal and initial state. Input prompted for by \fB:\fP. +Your kill character cancels partial command. +T} +Insert T{ +Entered by \fBa\fP \fBi\fP and \fBc\fP. +Arbitrary text then terminates with line having only \fB.\fP +character on it or abnormally with interrupt. +T} +Open/visual T{ +Entered by \fBopen\fP or \fBvi\fP, terminates with \fBQ\fP +or ^\e. +T} +.TE +.h "Ex commands" +.TS +lw(.45i) lw(.08i)b lw(.45i) lw(.08i)b lw(.45i) lw(.08i)b. +abbrev ab next n unabbrev una +append a number nu undo u +args ar open o unmap unm +change c preserve pre version ve +copy co print p visual vi +delete d put pu write w +edit e quit q xit x +file f read re yank ya +global g recover rec \fIwindow\fP z +insert i rewind rew \fIescape\fP ! +join j set se \fIlshift\fP < +list l shell sh \fIprint next\fP \fRCR\fP +map source so \fIresubst\fP & +mark ma stop st \fIrshift\fP > +move m substitute s \fIscroll\fP ^D +.TE +.h "Ex command addresses" +.TS +lw(.3i)b lw(0.8i) lw(.3i)b lw(0.8i). +\fIn\fP line \fIn\fP /\fIpat\fP next with \fIpat\fP +\&. current ?\fIpat\fP previous with \fIpat\fP +$ last \fIx\fP-\fIn\fP \fIn\fP before \fIx\fP ++ next \fIx\fP,\fIy\fP \fIx\fP through \fIy\fP +\- previous \(aa\fIx\fP marked with \fIx\fP ++\fIn\fP \fIn\fP forward \(aa\(aa previous context +% 1,$ +.TE +.nc +.h "Specifying terminal type" +.TS +aw(1.7i)b aw(1.5i). +% setenv TERM \fItype\fP \fIcsh\fP and all version 6 +$ TERM=\fItype\fP; export TERM \fIsh\fP in Version 7 +See also \fItset\fR(1) +.TE +.h "Some terminal types" +.TS +lw(.4i) lw(.4i) lw(.4i) lw(.4i) lw(.4i). +2621 43 adm31 dw1 h19 +2645 733 adm3a dw2 i100 +300s 745 c100 gt40 mime +33 act4 dm1520 gt42 owl +37 act5 dm2500 h1500 t1061 +4014 adm3 dm3025 h1510 vt52 +.TE +.h "Initializing options" +.TS +lw(.9i)b aw(1.5i). +EXINIT place \fBset\fP's here in environment var. +set \fIx\fP enable option +set no\fIx\fP disable option +set \fIx\fP=\fIval\fP give value \fIval\fP +set show changed options +set all show all options +set \fIx\fP? show value of option \fIx\fP +.TE +.h "Useful options" +.TS +lw(.9i)b lw(.3i) lw(1.0i). +autoindent ai supply indent +autowrite aw write before changing files +ignorecase ic in scanning +lisp \fB( ) { }\fP are s-exp's +list print ^I for tab, $ at end +magic \fB. [ *\fP special in patterns +number nu number lines +paragraphs para macro names which start ... +redraw simulate smart terminal +scroll command mode lines +sections sect macro names ... +shiftwidth sw for \fB< >\fP, and input \fB^D\fP +showmatch sm to \fB)\fP and \fB}\fP as typed +slowopen slow choke updates during insert +window visual mode lines +wrapscan ws around end of buffer? +wrapmargin wm automatic line splitting +.TE +.LP +.h "Scanning pattern formation" +.TS +aw(.9i)b aw(1.0i). +\(ua beginning of line +$ end of line +\fB.\fR any character +\e< beginning of word +\e> end of word +[\fIstr\fP] any char in \fIstr\fP +[\(ua\fIstr\fP] ... not in \fIstr\fP +[\fIx\-y\fP] ... between \fIx\fP and \fIy\fP +* any number of preceding +.TE +.nc +.LP +.LG +.LG +.B +.ce +Vi Quick Reference +.NL +.R +.LP +.LP +.h "Entering/leaving vi" +.TS +aw(1.4i)b aw(1.8i). +% vi \fIname\fP edit \fIname\fP at top +% vi +\fIn\fP \fIname\fP ... at line \fIn\fP +% vi + \fIname\fP ... at end +% vi \-r list saved files +% vi \-r \fIname\fP recover file \fIname\fP +% vi \fIname\fP ... edit first; rest via \fB:n\fP +% vi \-t \fItag\fP start at \fItag\fP +% vi +/\fIpat\fP \fIname\fP search for \fIpat\fP +% view \fIname\fP read only mode +ZZ exit from vi, saving changes +^Z stop vi for later resumption +.TE +.h "The display" +.TS +lw(.75i) lw(2.2i). +Last line T{ +Error messages, echoing input to \fB: / ?\fP and \fB!\fR, +feedback about i/o and large changes. +T} +@ lines On screen only, not in file. +~ lines Lines past end of file. +^\fIx\fP Control characters, ^? is delete. +tabs Expand to spaces, cursor at last. +.TE +.LP +.h "Vi states" +.TS +lw(.75i) lw(2.2i). +Command T{ +Normal and initial state. Others return here. +ESC (escape) cancels partial command. +T} +Insert T{ +Entered by \fBa i A I o O c C s S\fP \fBR\fP. +Arbitrary text then terminates with ESC character, +or abnormally with interrupt. +T} +Last line T{ +Reading input for \fB: / ?\fP or \fB!\fP; terminate +with ESC or CR to execute, interrupt to cancel. +T} +.TE +.h "Counts before vi commands" +.TS +lw(1.5i) lw(1.7i)b. +line/column number z G | +scroll amount ^D ^U +replicate insert a i A I +repeat effect \fRmost rest\fP +.TE +.h "Simple commands" +.TS +lw(1.5i)b lw(1.7i). +dw delete a word +de ... leaving punctuation +dd delete a line +3dd ... 3 lines +i\fItext\fP\fRESC\fP insert text \fIabc\fP +cw\fInew\fP\fRESC\fP change word to \fInew\fP +ea\fIs\fP\fRESC\fP pluralize word +xp transpose characters +.TE +.nc +.h "Interrupting, cancelling" +.TS +aw(0.75i)b aw(1.6i). +ESC end insert or incomplete cmd +^? (delete or rubout) interrupts +^L reprint screen if \fB^?\fR scrambles it +.TE +.h "File manipulation" +.TS +aw(0.75i)b aw(1.6i). +:w write back changes +:wq write and quit +:q quit +:q! quit, discard changes +:e \fIname\fP edit file \fIname\fP +:e! reedit, discard changes +:e + \fIname\fP edit, starting at end +:e +\fIn\fR edit starting at line \fIn\fR +:e # edit alternate file +^\(ua synonym for \fB:e #\fP +:w \fIname\fP write file \fIname\fP +:w! \fIname\fP overwrite file \fIname\fP +:sh run shell, then return +:!\fIcmd\fP run \fIcmd\fR, then return +:n edit next file in arglist +:n \fIargs\fP specify new arglist +:f show current file and line +^G synonym for \fB:f\fP +:ta \fItag\fP to tag file entry \fItag\fP +^] \fB:ta\fP, following word is \fItag\fP +.TE +.h "Positioning within file" +.TS +aw(0.75i)b aw(1.6i). +^F forward screenfull +^B backward screenfull +^D scroll down half screen +^U scroll up half screen +G goto line (end default) +/\fIpat\fR next line matching \fIpat\fR +?\fIpat\fR prev line matching \fIpat\fR +n repeat last \fB/\fR or \fB?\fR +N reverse last \fB/\fR or \fB?\fR +/\fIpat\fP/+\fIn\fP n'th line after \fIpat\fR +?\fIpat\fP?\-\fIn\fP n'th line before \fIpat\fR +]] next section/function +[[ previous section/function +% find matching \fB( ) {\fP or \fB}\fP +.TE +.h "Adjusting the screen" +.TS +aw(0.75i)b aw(1.6i). +^L clear and redraw +^R retype, eliminate @ lines +z\fRCR\fP redraw, current at window top +z\- ... at bottom +z\|. ... at center +/\fIpat\fP/z\- \fIpat\fP line at bottom +z\fIn\fP\|. use \fIn\fP line window +^E scroll window down 1 line +^Y scroll window up 1 line +.TE +.nc +.h "Marking and returning +.TS +aw(0.5i)b aw(2.0i). +\(ga\(ga previous context +\(aa\(aa ... at first non-white in line +m\fIx\fP mark position with letter \fIx\fP +\(ga\fIx\fP to mark \fIx\fP +\(aa\fIx\fP ... at first non-white in line +.TE +.h "Line positioning" +.TS +aw(0.5i)b aw(2.0i). +H home window line +L last window line +M middle window line ++ next line, at first non-white +\- previous line, at first non-white +\fRCR\fP return, same as + +\(da \fRor\fP j next line, same column +\(ua \fRor\fP k previous line, same column +.TE +.h "Character positioning" +.TS +aw(0.5i)b aw(2.0i). +\(ua first non white +0 beginning of line +$ end of line +h \fRor\fP \(-> forward +l \fRor\fP \(<- backwards +^H same as \fB\(<-\fP +\fRspace\fP same as \fB\(->\fP +f\fIx\fP find \fIx\fP forward +F\fIx\fP \fBf\fR backward +t\fIx\fP upto \fIx\fP forward +T\fIx\fP back upto \fIx\fP +; repeat last \fBf F t\fP or \fBT\fP +, inverse of \fB;\fP +| to specified column +% find matching \fB( { )\fP or \fB}\fR +.TE +.h "Words, sentences, paragraphs" +.TS +aw(0.5i)b aw(2.0i). +w word forward +b back word +e end of word +) to next sentence +} to next paragraph +( back sentence +{ back paragraph +W blank delimited word +B back \fBW\fP +E to end of \fBW\fP +.TE +.h "Commands for \s-2LISP\s0" +.TS +aw(0.5i)b aw(2.0i). +) Forward s-expression +} ... but don't stop at atoms +( Back s-expression +{ ... but don't stop at atoms +.TE +.nc +.h "Corrections during insert" +.TS +aw(.5i)b aw(2.0i). +^H erase last character +^W erases last word +\fRerase\fP your erase, same as \fB^H\fP +\fRkill\fP your kill, erase input this line +\e escapes \fB^H\fR, your erase and kill +\fRESC\fP ends insertion, back to command +^? interrupt, terminates insert +^D backtab over \fIautoindent\fP +\(ua^D kill \fIautoindent\fP, save for next +0^D ... but at margin next also +^V quote non-printing character +.TE +.h "Insert and replace" +.TS +aw(.5i)b aw(2.0i). +a append after cursor +i insert before +A append at end of line +I insert before first non-blank +o open line below +O open above +r\fIx\fP replace single char with \fIx\fP +R replace characters +.TE +.h "Operators (double to affect lines)" +.TS +aw(0.5i)b aw(2.0i). +d delete +c change +< left shift +> right shift +! filter through command +\&\= indent for \s-2LISP\s0 +y yank lines to buffer +.TE +.h "Miscellaneous operations" +.TS +aw(0.5i)b aw(2.0i). +C change rest of line +D delete rest of line +s substitute chars +S substitute lines +J join lines +x delete characters +X ... before cursor +Y yank lines +.TE +.h "Yank and put" +.TS +aw(0.5i)b aw(2.0i). +p put back lines +P put before +"\fIx\fPp put from buffer \fIx\fP +"\fIx\fPy yank to buffer \fIx\fP +"\fIx\fPd delete into buffer \fIx\fP +.TE +.h "Undo, redo, retrieve" +.TS +aw(0.5i)b aw(2.0i). +u undo last change +U restore current line +\fB.\fP repeat last change +"\fId\fP\|p retrieve \fId\fP'th last delete +.TE diff --git a/usr.bin/vi/common/Makefile b/usr.bin/vi/common/Makefile new file mode 100644 index 0000000..b24e941 --- /dev/null +++ b/usr.bin/vi/common/Makefile @@ -0,0 +1,98 @@ +# @(#)Makefile 8.47 (Berkeley) 8/14/94 + +PROG= nvi +#CFLAGS=-g -DDEBUG +#CFLAGS+=-pg +CFLAGS+=-I. -I${.CURDIR} +#STRIP= +.PATH: ${.CURDIR}/../common ${.CURDIR}/../ex ${.CURDIR}/../sex \ + ${.CURDIR}/../vi ${.CURDIR}/../svi ${.CURDIR}/../xaw +CLEANFILES+=nex + +# General sources. +SRCS= cut.c delete.c exf.c line.c log.c main.c mark.c msg.c options.c \ + options_f.c put.c screen.c search.c seq.c signal.c recover.c \ + term.c trace.c util.c + +# Ex source. +SRCS+= ex.c ex_abbrev.c ex_append.c ex_args.c ex_argv.c ex_at.c ex_bang.c \ + ex_cd.c ex_delete.c ex_digraph.c ex_display.c ex_edit.c ex_equal.c \ + ex_exit.c ex_file.c ex_global.c ex_init.c ex_join.c ex_map.c \ + ex_mark.c ex_mkexrc.c ex_move.c ex_open.c ex_preserve.c ex_print.c \ + ex_put.c ex_read.c ex_screen.c ex_script.c ex_set.c ex_shell.c \ + ex_shift.c ex_source.c ex_stop.c ex_subst.c ex_tag.c ex_undo.c \ + ex_usage.c ex_util.c ex_version.c ex_visual.c ex_write.c ex_yank.c \ + ex_z.c excmd.c filter.c + +# Ex screen source. +SRCS+= sex_confirm.c sex_get.c sex_refresh.c sex_screen.c sex_term.c \ + sex_util.c sex_window.c + +# Vi source. +SRCS+= getc.c v_ch.c v_delete.c v_ex.c v_increment.c v_init.c v_left.c \ + v_mark.c v_match.c v_ntext.c v_paragraph.c v_put.c v_redraw.c \ + v_replace.c v_right.c v_screen.c v_scroll.c v_search.c v_section.c \ + v_sentence.c v_status.c v_stop.c v_text.c v_ulcase.c v_undo.c \ + v_util.c v_word.c v_xchar.c v_yank.c v_z.c v_zexit.c vcmd.c vi.c + +# Vi curses screen source. +SRCS+= svi_confirm.c svi_curses.c svi_ex.c svi_get.c svi_line.c \ + svi_refresh.c svi_relative.c svi_screen.c svi_smap.c svi_split.c \ + svi_term.c svi_util.c + +# Athena widget set screen source. +SRCS+= xaw_screen.c + +#LDADD+=-pg +DPADD+= ${LIBCURSES} ${LIBTERM} ${LIBUTIL} +LDADD+= -lcurses -ltermlib -lutil +SPECHDR=compat.h excmd.h options.h +CLEANFILES+=${SPECHDR} +LINKS= ${BINDIR}/nvi ${BINDIR}/nex + +all: nvi nex vi.0 +nex: nvi + rm -f nex + ln nvi nex + +nvi: compat.h options.h excmd.h + +compat.h: + :> compat.h + +options.h: options.h.stub options.c options.awk + rm -f options.h + cat ${.CURDIR}/options.h.stub > options.h + awk -f ${.CURDIR}/options.awk ${.CURDIR}/options.c >> options.h + +excmd.h: excmd.h.stub excmd.c excmd.awk + rm -f excmd.h + cat ${.CURDIR}/../ex/excmd.h.stub > excmd.h + awk -f ${.CURDIR}/../ex/excmd.awk ${.CURDIR}/../ex/excmd.c >> excmd.h + +vi.0: + rm -f vi.0 + ln -s ${.CURDIR}/../USD.doc/vi.man/vi.0 vi.0 + +tags:: + -(cd ${.CURDIR} && rm -f tags && \ + ctags ../common/*.[ch] ../common/*.stub ../ex/*.[ch] ../ex/*.stub \ + ../vi/*.[ch] ../sex/*.[ch] ../svi/*.[ch] ../xaw/*.[ch]) + +warn:: ${SRCS} + -(cd ${.CURDIR} && gcc -Wall -O4 -DDEBUG \ + -Iobj -I. ${.ALLSRC} -lcurses -ltermlib 2>&1 | \ + sed -e "/warning: .*sccsid.*defined but not used/d" \ + -e "/warning: suggest parentheses around/d" \ + -e "/In function /d" \ + -e "/At top level:/d" \ + -e "/warning: .*inline call to/d" \ + -e "/warning: comparison is always 1 due /d") > \ + ${.CURDIR}/WARN.OUT + +MAN= ${.CURDIR}/../USD.doc/vi.man +REF= ${.CURDIR}/../USD.doc/vi.ref + +.include <bsd.prog.mk> + +.depend: ${SPECHDR} diff --git a/usr.bin/vi/common/args.h b/usr.bin/vi/common/args.h new file mode 100644 index 0000000..5e127de --- /dev/null +++ b/usr.bin/vi/common/args.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)args.h 8.5 (Berkeley) 7/17/94 + */ + +/* + * Structure for building "argc/argv" vector of arguments. + * + * !!! + * All arguments are nul terminated as well as having an associated length. + * The argument vector is NOT necessarily NULL terminated. The proper way + * to check the number of arguments is to use the argc value in the EXCMDARG + * structure or to walk the array until an ARGS structure with a length of 0 + * is found. + */ +typedef struct _args { + CHAR_T *bp; /* Argument. */ + size_t blen; /* Buffer length. */ + size_t len; /* Argument length. */ + +#define A_ALLOCATED 0x01 /* If allocated space. */ + u_int8_t flags; +} ARGS; diff --git a/usr.bin/vi/common/cut.c b/usr.bin/vi/common/cut.c new file mode 100644 index 0000000..df86a95 --- /dev/null +++ b/usr.bin/vi/common/cut.c @@ -0,0 +1,366 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)cut.c 8.32 (Berkeley) 7/28/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +static int cb_rotate __P((SCR *)); + +/* + * cut -- + * Put a range of lines/columns into a TEXT buffer. + * + * There are two buffer areas, both found in the global structure. The first + * is the linked list of all the buffers the user has named, the second is the + * unnamed buffer storage. There is a pointer, too, which is the current + * default buffer, i.e. it may point to the unnamed buffer or a named buffer + * depending on into what buffer the last text was cut. Logically, in both + * delete and yank operations, if the user names a buffer, the text is cut + * into it. If it's a delete of information on more than a single line, the + * contents of the numbered buffers are rotated up one, the contents of the + * buffer named '9' are discarded, and the text is cut into the buffer named + * '1'. The text is always cut into the unnamed buffer. + * + * In all cases, upper-case buffer names are the same as lower-case names, + * with the exception that they cause the buffer to be appended to instead + * of replaced. Note, however, that if text is appended to a buffer, the + * default buffer only contains the appended text, not the entire contents + * of the buffer. + * + * !!! + * The contents of the default buffer would disappear after most operations + * in historic vi. It's unclear that this is useful, so we don't bother. + * + * When users explicitly cut text into the numeric buffers, historic vi became + * genuinely strange. I've never been able to figure out what was supposed to + * happen. It behaved differently if you deleted text than if you yanked text, + * and, in the latter case, the text was appended to the buffer instead of + * replacing the contents. Hopefully it's not worth getting right, and here + * we just treat the numeric buffers like any other named buffer. + */ +int +cut(sp, ep, namep, fm, tm, flags) + SCR *sp; + EXF *ep; + CHAR_T *namep; + int flags; + MARK *fm, *tm; +{ + CB *cbp; + CHAR_T name; + recno_t lno; + int append, copy_one, copy_def; + + /* + * If the user specified a buffer, put it there. (This may require + * a copy into the numeric buffers. We do the copy so that we don't + * have to reference count and so we don't have to deal with things + * like appends to buffers that are used multiple times.) + * + * Otherwise, if it's supposed to be put in a numeric buffer (usually + * a delete) put it there. The rules for putting things in numeric + * buffers were historically a little strange. There were three cases. + * + * 1: Some motions are always line mode motions, which means + * that the cut always goes into the numeric buffers. + * 2: Some motions aren't line mode motions, e.g. d10w, but + * can cross line boundaries. For these commands, if the + * cut crosses a line boundary, it goes into the numeric + * buffers. This includes most of the commands. + * 3: Some motions aren't line mode motions, e.g. d`<char>, + * but always go into the numeric buffers, regardless. This + * was the commands: % ` / ? ( ) N n { } -- and nvi adds ^A. + * + * Otherwise, put it in the unnamed buffer. + */ + append = copy_one = copy_def = 0; + if (namep != NULL) { + name = *namep; + if (LF_ISSET(CUT_NUMREQ) || LF_ISSET(CUT_NUMOPT) && + (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) { + copy_one = 1; + cb_rotate(sp); + } + if ((append = isupper(name)) == 1) { + if (!copy_one) + copy_def = 1; + name = tolower(name); + } +namecb: CBNAME(sp, cbp, name); + } else if (LF_ISSET(CUT_NUMREQ) || LF_ISSET(CUT_NUMOPT) && + (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) { + name = '1'; + cb_rotate(sp); + goto namecb; + } else + cbp = &sp->gp->dcb_store; + +copyloop: + /* + * If this is a new buffer, create it and add it into the list. + * Otherwise, if it's not an append, free its current contents. + */ + if (cbp == NULL) { + CALLOC_RET(sp, cbp, CB *, 1, sizeof(CB)); + cbp->name = name; + CIRCLEQ_INIT(&cbp->textq); + LIST_INSERT_HEAD(&sp->gp->cutq, cbp, q); + } else if (!append) { + text_lfree(&cbp->textq); + cbp->len = 0; + cbp->flags = 0; + } + + +#define ENTIRE_LINE 0 + /* In line mode, it's pretty easy, just cut the lines. */ + if (LF_ISSET(CUT_LINEMODE)) { + cbp->flags |= CB_LMODE; + for (lno = fm->lno; lno <= tm->lno; ++lno) + if (cut_line(sp, ep, lno, 0, 0, cbp)) + goto cut_line_err; + } else { + /* + * Get the first line. A length of 0 causes cut_line + * to cut from the MARK to the end of the line. + */ + if (cut_line(sp, ep, fm->lno, fm->cno, fm->lno != tm->lno ? + ENTIRE_LINE : (tm->cno - fm->cno) + 1, cbp)) + goto cut_line_err; + + /* Get the intermediate lines. */ + for (lno = fm->lno; ++lno < tm->lno;) + if (cut_line(sp, ep, lno, 0, ENTIRE_LINE, cbp)) + goto cut_line_err; + + /* Get the last line. */ + if (tm->lno != fm->lno && + cut_line(sp, ep, lno, 0, tm->cno + 1, cbp)) { +cut_line_err: text_lfree(&cbp->textq); + cbp->len = 0; + cbp->flags = 0; + return (1); + } + } + + append = 0; /* Only append to the named buffer. */ + sp->gp->dcbp = cbp; /* Repoint the default buffer on each pass. */ + + if (copy_one) { /* Copy into numeric buffer 1. */ + name = '1'; + CBNAME(sp, cbp, name); + copy_one = 0; + goto copyloop; + } + if (copy_def) { /* Copy into the default buffer. */ + cbp = &sp->gp->dcb_store; + copy_def = 0; + goto copyloop; + } + return (0); +} + +/* + * cb_rotate -- + * Rotate the numbered buffers up one. + */ +static int +cb_rotate(sp) + SCR *sp; +{ + CB *cbp, *del_cbp; + + del_cbp = NULL; + for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) + switch(cbp->name) { + case '1': + cbp->name = '2'; + break; + case '2': + cbp->name = '3'; + break; + case '3': + cbp->name = '4'; + break; + case '4': + cbp->name = '5'; + break; + case '5': + cbp->name = '6'; + break; + case '6': + cbp->name = '7'; + break; + case '7': + cbp->name = '8'; + break; + case '8': + cbp->name = '9'; + break; + case '9': + del_cbp = cbp; + break; + } + if (del_cbp != NULL) { + LIST_REMOVE(del_cbp, q); + text_lfree(&del_cbp->textq); + FREE(del_cbp, sizeof(CB)); + } + return (0); +} + +/* + * cut_line -- + * Cut a portion of a single line. + */ +int +cut_line(sp, ep, lno, fcno, clen, cbp) + SCR *sp; + EXF *ep; + recno_t lno; + size_t fcno, clen; + CB *cbp; +{ + TEXT *tp; + size_t len; + char *p; + + /* Get the line. */ + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + GETLINE_ERR(sp, lno); + return (1); + } + + /* Create a TEXT structure that can hold the entire line. */ + if ((tp = text_init(sp, NULL, 0, len)) == NULL) + return (1); + + /* + * If the line isn't empty and it's not the entire line, + * copy the portion we want, and reset the TEXT length. + */ + if (len != 0) { + if (clen == 0) + clen = len - fcno; + memmove(tp->lb, p + fcno, clen); + tp->len = clen; + } + + /* Append to the end of the cut buffer. */ + CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q); + cbp->len += tp->len; + + return (0); +} + +/* + * text_init -- + * Allocate a new TEXT structure. + */ +TEXT * +text_init(sp, p, len, total_len) + SCR *sp; + const char *p; + size_t len, total_len; +{ + TEXT *tp; + + CALLOC(sp, tp, TEXT *, 1, sizeof(TEXT)); + if (tp == NULL) + return (NULL); + /* ANSI C doesn't define a call to malloc(2) for 0 bytes. */ + if ((tp->lb_len = total_len) != 0) { + MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len); + if (tp->lb == NULL) { + free(tp); + return (NULL); + } + if (p != NULL && len != 0) + memmove(tp->lb, p, len); + } + tp->len = len; + return (tp); +} + +/* + * text_lfree -- + * Free a chain of text structures. + */ +void +text_lfree(headp) + TEXTH *headp; +{ + TEXT *tp; + + while ((tp = headp->cqh_first) != (void *)headp) { + CIRCLEQ_REMOVE(headp, tp, q); + text_free(tp); + } +} + +/* + * text_free -- + * Free a text structure. + */ +void +text_free(tp) + TEXT *tp; +{ + if (tp->lb != NULL) + FREE(tp->lb, tp->lb_len); + if (tp->wd != NULL) + FREE(tp->wd, tp->wd_len); + FREE(tp, sizeof(TEXT)); +} diff --git a/usr.bin/vi/common/cut.h b/usr.bin/vi/common/cut.h new file mode 100644 index 0000000..3113411 --- /dev/null +++ b/usr.bin/vi/common/cut.h @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cut.h 8.19 (Berkeley) 7/28/94 + */ + +typedef struct _texth TEXTH; /* TEXT list head structure. */ +CIRCLEQ_HEAD(_texth, _text); + +/* Cut buffers. */ +struct _cb { + LIST_ENTRY(_cb) q; /* Linked list of cut buffers. */ + TEXTH textq; /* Linked list of TEXT structures. */ + CHAR_T name; /* Cut buffer name. */ + size_t len; /* Total length of cut text. */ + +#define CB_LMODE 0x01 /* Cut was in line mode. */ + u_int8_t flags; +}; + +/* Lines/blocks of text. */ +struct _text { /* Text: a linked list of lines. */ + CIRCLEQ_ENTRY(_text) q; /* Linked list of text structures. */ + char *lb; /* Line buffer. */ + size_t lb_len; /* Line buffer length. */ + size_t len; /* Line length. */ + + /* These fields are used by the vi text input routine. */ + recno_t lno; /* 1-N: line number. */ + size_t ai; /* 0-N: autoindent bytes. */ + size_t insert; /* 0-N: bytes to insert (push). */ + size_t offset; /* 0-N: initial, unerasable chars. */ + size_t owrite; /* 0-N: chars to overwrite. */ + size_t R_erase; /* 0-N: 'R' erase count. */ + size_t sv_cno; /* 0-N: Saved line cursor. */ + size_t sv_len; /* 0-N: Saved line length. */ + + /* These fields are used by the ex text input routine. */ + u_char *wd; /* Width buffer. */ + size_t wd_len; /* Width buffer length. */ +}; + +/* + * Get named buffer 'name'. + * Translate upper-case buffer names to lower-case buffer names. + */ +#define CBNAME(sp, cbp, nch) { \ + CHAR_T __name; \ + __name = isupper(nch) ? tolower(nch) : (nch); \ + for (cbp = sp->gp->cutq.lh_first; \ + cbp != NULL; cbp = cbp->q.le_next) \ + if (cbp->name == __name) \ + break; \ +} + +#define CUT_LINEMODE 0x01 /* Cut in line mode. */ +#define CUT_NUMOPT 0x02 /* Numeric buffer: optional. */ +#define CUT_NUMREQ 0x04 /* Numeric buffer: required. */ +int cut __P((SCR *, EXF *, CHAR_T *, MARK *, MARK *, int)); + +int cut_line __P((SCR *, EXF *, recno_t, size_t, size_t, CB *)); +int delete __P((SCR *, EXF *, MARK *, MARK *, int)); +int put __P((SCR *, EXF *, CB *, CHAR_T *, MARK *, MARK *, int)); + +void text_free __P((TEXT *)); +TEXT *text_init __P((SCR *, const char *, size_t, size_t)); +void text_lfree __P((TEXTH *)); diff --git a/usr.bin/vi/common/delete.c b/usr.bin/vi/common/delete.c new file mode 100644 index 0000000..4edd008 --- /dev/null +++ b/usr.bin/vi/common/delete.c @@ -0,0 +1,193 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)delete.c 8.10 (Berkeley) 4/26/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +/* + * delete -- + * Delete a range of text. + */ +int +delete(sp, ep, fm, tm, lmode) + SCR *sp; + EXF *ep; + MARK *fm, *tm; + int lmode; +{ + recno_t lno; + size_t blen, len, nlen, tlen; + char *bp, *p; + int eof; + + bp = NULL; + + /* Case 1 -- delete in line mode. */ + if (lmode) { + for (lno = tm->lno; lno >= fm->lno; --lno) + if (file_dline(sp, ep, lno)) + return (1); + goto vdone; + } + + /* + * Case 2 -- delete to EOF. This is a special case because it's + * easier to pick it off than try and find it in the other cases. + */ + if (file_lline(sp, ep, &lno)) + return (1); + if (tm->lno >= lno) { + if (tm->lno == lno) { + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + GETLINE_ERR(sp, lno); + return (1); + } + eof = tm->cno >= len ? 1 : 0; + } else + eof = 1; + if (eof) { + for (lno = tm->lno; lno > fm->lno; --lno) { + if (file_dline(sp, ep, lno)) + return (1); + ++sp->rptlines[L_DELETED]; + } + if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) { + GETLINE_ERR(sp, fm->lno); + return (1); + } + GET_SPACE_RET(sp, bp, blen, fm->cno); + memmove(bp, p, fm->cno); + if (file_sline(sp, ep, fm->lno, bp, fm->cno)) + return (1); + goto done; + } + } + + /* Case 3 -- delete within a single line. */ + if (tm->lno == fm->lno) { + if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) { + GETLINE_ERR(sp, fm->lno); + return (1); + } + GET_SPACE_RET(sp, bp, blen, len); + if (fm->cno != 0) + memmove(bp, p, fm->cno); + memmove(bp + fm->cno, p + (tm->cno + 1), len - (tm->cno + 1)); + if (file_sline(sp, ep, fm->lno, + bp, len - ((tm->cno - fm->cno) + 1))) + goto err; + goto done; + } + + /* + * Case 4 -- delete over multiple lines. + * + * Copy the start partial line into place. + */ + if ((tlen = fm->cno) != 0) { + if ((p = file_gline(sp, ep, fm->lno, NULL)) == NULL) { + GETLINE_ERR(sp, fm->lno); + return (1); + } + GET_SPACE_RET(sp, bp, blen, tlen + 256); + memmove(bp, p, tlen); + } + + /* Copy the end partial line into place. */ + if ((p = file_gline(sp, ep, tm->lno, &len)) == NULL) { + GETLINE_ERR(sp, tm->lno); + goto err; + } + if (len != 0 && tm->cno != len - 1) { + /* + * XXX + * We can overflow memory here, if the total length is greater + * than SIZE_T_MAX. The only portable way I've found to test + * is depending on the overflow being less than the value. + */ + nlen = (len - (tm->cno + 1)) + tlen; + if (tlen > nlen) { + msgq(sp, M_ERR, "Error: line length overflow"); + goto err; + } + if (tlen == 0) { + GET_SPACE_RET(sp, bp, blen, nlen); + } else + ADD_SPACE_RET(sp, bp, blen, nlen); + + memmove(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1)); + tlen += len - (tm->cno + 1); + } + + /* Set the current line. */ + if (file_sline(sp, ep, fm->lno, bp, tlen)) + goto err; + + /* Delete the last and intermediate lines. */ + for (lno = tm->lno; lno > fm->lno; --lno) + if (file_dline(sp, ep, lno)) + goto err; + + /* Reporting. */ +vdone: sp->rptlines[L_DELETED] += tm->lno - fm->lno + 1; + +done: if (bp != NULL) + FREE_SPACE(sp, bp, blen); + + return (0); + + /* Free memory. */ +err: if (bp != NULL) + FREE_SPACE(sp, bp, blen); + return (1); +} diff --git a/usr.bin/vi/common/exf.c b/usr.bin/vi/common/exf.c new file mode 100644 index 0000000..b18565e --- /dev/null +++ b/usr.bin/vi/common/exf.c @@ -0,0 +1,830 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)exf.c 8.94 (Berkeley) 8/7/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +/* + * We include <sys/file.h>, because the flock(2) and open(2) #defines + * were found there on historical systems. We also include <fcntl.h> + * because the open(2) #defines are found there on newer systems. + */ +#include <sys/file.h> + +#include <bitstring.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> +#include <pathnames.h> + +#include "vi.h" +#include "excmd.h" + +/* + * file_add -- + * Insert a file name into the FREF list, if it doesn't already + * appear in it. + * + * !!! + * The "if it doesn't already appear" changes vi's semantics slightly. If + * you do a "vi foo bar", and then execute "next bar baz", the edit of bar + * will reflect the line/column of the previous edit session. Historic nvi + * did not do this. The change is a logical extension of the change where + * vi now remembers the last location in any file that it has ever edited, + * not just the previously edited file. + */ +FREF * +file_add(sp, name) + SCR *sp; + CHAR_T *name; +{ + FREF *frp; + + /* + * Return it if it already exists. Note that we test against the + * user's name, whatever that happens to be, including if it's a + * temporary file. + */ + if (name != NULL) + for (frp = sp->frefq.cqh_first; + frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next) + if (!strcmp(frp->name, name)) + return (frp); + + /* Allocate and initialize the FREF structure. */ + CALLOC(sp, frp, FREF *, 1, sizeof(FREF)); + if (frp == NULL) + return (NULL); + + /* + * If no file name specified, or if the file name is a request + * for something temporary, file_init() will allocate the file + * name. Temporary files are always ignored. + */ + if (name != NULL && strcmp(name, TEMPORARY_FILE_STRING) && + (frp->name = strdup(name)) == NULL) { + FREE(frp, sizeof(FREF)); + msgq(sp, M_SYSERR, NULL); + return (NULL); + } + + /* Append into the chain of file names. */ + CIRCLEQ_INSERT_TAIL(&sp->frefq, frp, q); + + return (frp); +} + +/* + * file_init -- + * Start editing a file, based on the FREF structure. If successsful, + * let go of any previous file. Don't release the previous file until + * absolutely sure we have the new one. + */ +int +file_init(sp, frp, rcv_name, force) + SCR *sp; + FREF *frp; + char *rcv_name; + int force; +{ + EXF *ep; + RECNOINFO oinfo; + struct stat sb; + size_t psize; + int fd; + char *oname, tname[MAXPATHLEN]; + + /* + * If the file is a recovery file, let the recovery code handle it. + * Clear the FR_RECOVER flag first -- the recovery code does set up, + * and then calls us! If the recovery call fails, it's probably + * because the named file doesn't exist. So, move boldly forward, + * presuming that there's an error message the user will get to see. + */ + if (F_ISSET(frp, FR_RECOVER)) { + F_CLR(frp, FR_RECOVER); + return (rcv_read(sp, frp)); + } + + /* + * Required FRP initialization; the only flag we keep is the + * cursor information. + */ + F_CLR(frp, ~FR_CURSORSET); + + /* + * Required EXF initialization: + * Flush the line caches. + * Default recover mail file fd to -1. + * Set initial EXF flag bits. + */ + CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF)); + ep->c_lno = ep->c_nlines = OOBLNO; + ep->rcv_fd = ep->fcntl_fd = -1; + LIST_INIT(&ep->marks); + F_SET(ep, F_FIRSTMODIFY); + + /* + * If no name or backing file, create a backing temporary file, saving + * the temp file name so we can later unlink it. If the user never + * named this file, copy the temporary file name to the real name (we + * display that until the user renames it). + */ + if ((oname = frp->name) == NULL || stat(oname, &sb)) { + (void)snprintf(tname, + sizeof(tname), "%s/vi.XXXXXX", O_STR(sp, O_DIRECTORY)); + if ((fd = mkstemp(tname)) == -1) { + msgq(sp, M_SYSERR, "Temporary file"); + goto err; + } + (void)close(fd); + + if (frp->name == NULL) + F_SET(frp, FR_TMPFILE); + if ((frp->tname = strdup(tname)) == NULL || + frp->name == NULL && (frp->name = strdup(tname)) == NULL) { + if (frp->tname != NULL) + free(frp->tname); + msgq(sp, M_SYSERR, NULL); + (void)unlink(tname); + goto err; + } + oname = frp->tname; + psize = 4 * 1024; + F_SET(frp, FR_NEWFILE); + } else { + /* + * Try to keep it at 10 pages or less per file. This + * isn't friendly on a loaded machine, btw. + */ + if (sb.st_size < 40 * 1024) + psize = 4 * 1024; + else if (sb.st_size < 320 * 1024) + psize = 32 * 1024; + else + psize = 64 * 1024; + + ep->mtime = sb.st_mtime; + + if (!S_ISREG(sb.st_mode)) + msgq(sp, M_ERR, + "Warning: %s is not a regular file", oname); + } + + /* Set up recovery. */ + memset(&oinfo, 0, sizeof(RECNOINFO)); + oinfo.bval = '\n'; /* Always set. */ + oinfo.psize = psize; + oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0; + if (rcv_name == NULL) { + if (!rcv_tmp(sp, ep, frp->name)) + oinfo.bfname = ep->rcv_path; + } else { + if ((ep->rcv_path = strdup(rcv_name)) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + oinfo.bfname = ep->rcv_path; + F_SET(ep, F_MODIFIED); + } + + /* Open a db structure. */ + if ((ep->db = dbopen(rcv_name == NULL ? oname : NULL, + O_NONBLOCK | O_RDONLY, DEFFILEMODE, DB_RECNO, &oinfo)) == NULL) { + msgq(sp, M_SYSERR, rcv_name == NULL ? oname : rcv_name); + goto err; + } + + /* + * Do the remaining things that can cause failure of the new file, + * mark and logging initialization. + */ + if (mark_init(sp, ep) || log_init(sp, ep)) + goto err; + + /* + * Close the previous file; if that fails, close the new one and + * run for the border. + * + * !!! + * There's a nasty special case. If the user edits a temporary file, + * and then does an ":e! %", we need to re-initialize the backing + * file, but we can't change the name. (It's worse -- we're dealing + * with *names* here, we can't even detect that it happened.) Set a + * flag so that the file_end routine ignores the backing information + * of the old file if it happens to be the same as the new one. + * + * !!! + * Side-effect: after the call to file_end(), sp->frp may be NULL. + */ + F_SET(frp, FR_DONTDELETE); + if (sp->ep != NULL && file_end(sp, sp->ep, force)) { + (void)file_end(sp, ep, 1); + goto err; + } + F_CLR(frp, FR_DONTDELETE); + + /* + * Lock the file; if it's a recovery file, it should already be + * locked. Note, we acquire the lock after the previous file + * has been ended, so that we don't get an "already locked" error + * for ":edit!". + * + * XXX + * While the user can't interrupt us between the open and here, + * there's a race between the dbopen() and the lock. Not much + * we can do about it. + * + * XXX + * We don't make a big deal of not being able to lock the file. As + * locking rarely works over NFS, and often fails if the file was + * mmap(2)'d, it's far too common to do anything like print an error + * message, let alone make the file readonly. At some future time, + * when locking is a little more reliable, this should change to be + * an error. + */ + if (rcv_name == NULL) + switch (file_lock(oname, + &ep->fcntl_fd, ep->db->fd(ep->db), 0)) { + case LOCK_FAILED: + F_SET(frp, FR_UNLOCKED); + break; + case LOCK_UNAVAIL: + msgq(sp, M_INFO, + "%s already locked, session is read-only", oname); + F_SET(frp, FR_RDONLY); + break; + case LOCK_SUCCESS: + break; + } + + /* + * The -R flag, or doing a "set readonly" during a session causes + * all files edited during the session (using an edit command, or + * even using tags) to be marked read-only. Changing the file name + * (see ex/ex_file.c), clears this flag. + * + * Otherwise, try and figure out if a file is readonly. This is a + * dangerous thing to do. The kernel is the only arbiter of whether + * or not a file is writeable, and the best that a user program can + * do is guess. Obvious loopholes are files that are on a file system + * mounted readonly (access catches this one on a few systems), or + * alternate protection mechanisms, ACL's for example, that we can't + * portably check. Lots of fun, and only here because users whined. + * + * !!! + * Historic vi displayed the readonly message if none of the file + * write bits were set, or if an an access(2) call on the path + * failed. This seems reasonable. If the file is mode 444, root + * users may want to know that the owner of the file did not expect + * it to be written. + * + * Historic vi set the readonly bit if no write bits were set for + * a file, even if the access call would have succeeded. This makes + * the superuser force the write even when vi expects that it will + * succeed. I'm less supportive of this semantic, but it's historic + * practice and the conservative approach to vi'ing files as root. + * + * It would be nice if there was some way to update this when the user + * does a "^Z; chmod ...". The problem is that we'd first have to + * distinguish between readonly bits set because of file permissions + * and those set for other reasons. That's not too hard, but deciding + * when to reevaluate the permissions is trickier. An alternative + * might be to turn off the readonly bit if the user forces a write + * and it succeeds. + * + * XXX + * Access(2) doesn't consider the effective uid/gid values. This + * probably isn't a problem for vi when it's running standalone. + */ + if (O_ISSET(sp, O_READONLY) || !F_ISSET(frp, FR_NEWFILE) && + (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) || + access(frp->name, W_OK))) + F_SET(frp, FR_RDONLY); + + /* + * Set the alternate file name to be the file we've just discarded. + * + * !!! + * If the current file was a temporary file, the call to file_end() + * unlinked it and free'd the name. So, there is no previous file, + * and there is no alternate file name. This matches historical + * practice, although in historical vi it could only happen as the + * result of the initial command, i.e. if vi was executed without a + * file name. + */ + set_alt_name(sp, sp->frp == NULL ? NULL : sp->frp->name); + + /* Switch... */ + ++ep->refcnt; + sp->ep = ep; + sp->frp = frp; + return (0); + +err: if (frp->name != NULL) { + free(frp->name); + frp->name = NULL; + } + if (frp->tname != NULL) { + (void)unlink(frp->tname); + free(frp->tname); + frp->tname = NULL; + } + if (ep->rcv_path != NULL) { + free(ep->rcv_path); + ep->rcv_path = NULL; + } + if (ep->db != NULL) + (void)ep->db->close(ep->db); + FREE(ep, sizeof(EXF)); + return (1); +} + +/* + * file_end -- + * Stop editing a file. + */ +int +file_end(sp, ep, force) + SCR *sp; + EXF *ep; + int force; +{ + FREF *frp; + + /* + * Clean up the FREF structure. + * + * Save the cursor location. + * + * XXX + * It would be cleaner to do this somewhere else, but by the time + * ex or vi knows that we're changing files it's already happened. + */ + frp = sp->frp; + frp->lno = sp->lno; + frp->cno = sp->cno; + F_SET(frp, FR_CURSORSET); + + /* + * We may no longer need the temporary backing file, so clean it + * up. We don't need the FREF structure either, if the file was + * never named, so lose it. + * + * !!! + * Re: FR_DONTDELETE, see the comment above in file_init(). + */ + if (!F_ISSET(frp, FR_DONTDELETE) && frp->tname != NULL) { + if (unlink(frp->tname)) + msgq(sp, M_SYSERR, "%s: remove", frp->tname); + free(frp->tname); + frp->tname = NULL; + if (F_ISSET(frp, FR_TMPFILE)) { + CIRCLEQ_REMOVE(&sp->frefq, frp, q); + free(frp->name); + free(frp); + } + sp->frp = NULL; + } + + /* + * Clean up the EXF structure. + * + * sp->ep MAY NOT BE THE SAME AS THE ARGUMENT ep, SO DON'T USE IT! + * + * If multiply referenced, just decrement the count and return. + */ + if (--ep->refcnt != 0) + return (0); + + /* Close the db structure. */ + if (ep->db->close != NULL && ep->db->close(ep->db) && !force) { + msgq(sp, M_ERR, "%s: close: %s", frp->name, strerror(errno)); + ++ep->refcnt; + return (1); + } + + /* COMMITTED TO THE CLOSE. THERE'S NO GOING BACK... */ + + /* Stop logging. */ + (void)log_end(sp, ep); + + /* Free up any marks. */ + (void)mark_end(sp, ep); + + /* + * Delete recovery files, close the open descriptor, free recovery + * memory. See recover.c for a description of the protocol. + * + * XXX + * Unlink backup file first, we can detect that the recovery file + * doesn't reference anything when the user tries to recover it. + * There's a race, here, obviously, but it's fairly small. + */ + if (!F_ISSET(ep, F_RCV_NORM)) { + if (ep->rcv_path != NULL && unlink(ep->rcv_path)) + msgq(sp, M_ERR, + "%s: remove: %s", ep->rcv_path, strerror(errno)); + if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath)) + msgq(sp, M_ERR, + "%s: remove: %s", ep->rcv_mpath, strerror(errno)); + } + if (ep->fcntl_fd != -1) + (void)close(ep->fcntl_fd); + if (ep->rcv_fd != -1) + (void)close(ep->rcv_fd); + if (ep->rcv_path != NULL) + free(ep->rcv_path); + if (ep->rcv_mpath != NULL) + free(ep->rcv_mpath); + + FREE(ep, sizeof(EXF)); + return (0); +} + +/* + * file_write -- + * Write the file to disk. Historic vi had fairly convoluted + * semantics for whether or not writes would happen. That's + * why all the flags. + */ +int +file_write(sp, ep, fm, tm, name, flags) + SCR *sp; + EXF *ep; + MARK *fm, *tm; + char *name; + int flags; +{ + struct stat sb; + FILE *fp; + FREF *frp; + MARK from, to; + u_long nlno, nch; + int btear, fd, noname, oflags, rval; + char *msg; + + frp = sp->frp; + if (name == NULL) { + noname = 1; + name = frp->name; + } else + noname = 0; + + /* Can't write files marked read-only, unless forced. */ + if (!LF_ISSET(FS_FORCE) && noname && F_ISSET(frp, FR_RDONLY)) { + if (LF_ISSET(FS_POSSIBLE)) + msgq(sp, M_ERR, + "Read-only file, not written; use ! to override"); + else + msgq(sp, M_ERR, "Read-only file, not written"); + return (1); + } + + /* If not forced, not appending, and "writeany" not set ... */ + if (!LF_ISSET(FS_FORCE | FS_APPEND) && !O_ISSET(sp, O_WRITEANY)) { + /* Don't overwrite anything but the original file. */ + if ((!noname || F_ISSET(frp, FR_NAMECHANGE)) && + !stat(name, &sb)) { + if (LF_ISSET(FS_POSSIBLE)) + msgq(sp, M_ERR, + "%s exists, not written; use ! to override", name); + else + msgq(sp, M_ERR, "%s exists, not written", name); + return (1); + } + + /* + * Don't write part of any existing file. Only test for the + * original file, the previous test catches anything else. + */ + if (!LF_ISSET(FS_ALL) && noname && !stat(name, &sb)) { + if (LF_ISSET(FS_POSSIBLE)) + msgq(sp, M_ERR, + "Use ! to write a partial file"); + else + msgq(sp, M_ERR, "Partial file, not written"); + return (1); + } + } + + /* + * Figure out if the file already exists -- if it doesn't, we display + * the "new file" message. The stat might not be necessary, but we + * just repeat it because it's easier than hacking the previous tests. + * The information is only used for the user message and modification + * time test, so we can ignore the obvious race condition. + * + * If the user is overwriting a file other than the original file, and + * O_WRITEANY was what got us here (neither force nor append was set), + * display the "existing file" messsage. Since the FR_NAMECHANGE flag + * is cleared on a successful write, the message only appears once when + * the user changes a file name. This is historic practice. + * + * One final test. If we're not forcing or appending, and we have a + * saved modification time, stop the user if it's been written since + * we last edited or wrote it, and make them force it. + */ + if (stat(name, &sb)) + msg = ": new file"; + else { + msg = ""; + if (!LF_ISSET(FS_FORCE | FS_APPEND)) { + if (ep->mtime && sb.st_mtime > ep->mtime) { + msgq(sp, M_ERR, + "%s: file modified more recently than this copy%s", + name, LF_ISSET(FS_POSSIBLE) ? + "; use ! to override" : ""); + return (1); + } + if (!noname || F_ISSET(frp, FR_NAMECHANGE)) + msg = ": existing file"; + } + } + + /* Set flags to either append or truncate. */ + oflags = O_CREAT | O_WRONLY; + if (LF_ISSET(FS_APPEND)) + oflags |= O_APPEND; + else + oflags |= O_TRUNC; + + /* Open the file. */ + if ((fd = open(name, oflags, DEFFILEMODE)) < 0) { + msgq(sp, M_SYSERR, name); + return (1); + } + + /* Use stdio for buffering. */ + if ((fp = fdopen(fd, "w")) == NULL) { + (void)close(fd); + msgq(sp, M_SYSERR, name); + return (1); + } + + /* Build fake addresses, if necessary. */ + if (fm == NULL) { + from.lno = 1; + from.cno = 0; + fm = &from; + if (file_lline(sp, ep, &to.lno)) + return (1); + to.cno = 0; + tm = &to; + } + + /* Turn on the busy message. */ + btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Writing..."); + rval = ex_writefp(sp, ep, name, fp, fm, tm, &nlno, &nch); + if (btear) + busy_off(sp); + + /* + * Save the new last modification time -- even if the write fails + * we re-init the time. That way the user can clean up the disk + * and rewrite without having to force it. + */ + ep->mtime = stat(name, &sb) ? 0 : sb.st_mtime; + + /* If the write failed, complain loudly. */ + if (rval) { + if (!LF_ISSET(FS_APPEND)) + msgq(sp, M_ERR, "%s: WARNING: file truncated!", name); + return (1); + } + + /* + * Once we've actually written the file, it doesn't matter that the + * file name was changed -- if it was, we've already whacked it. + */ + F_CLR(frp, FR_NAMECHANGE); + + /* + * If wrote the entire file clear the modified bit. If the file was + * written back to the original file name and the file is a temporary, + * set the "no exit" bit. This permits the user to write the file and + * use it in the context of the file system, but still keeps them from + * losing their changes by exiting. + */ + if (LF_ISSET(FS_ALL)) { + F_CLR(ep, F_MODIFIED); + if (F_ISSET(frp, FR_TMPFILE)) + if (noname) + F_SET(frp, FR_TMPEXIT); + else + F_CLR(frp, FR_TMPEXIT); + } + + msgq(sp, M_INFO, "%s%s%s: %lu line%s, %lu characters", + INTERRUPTED(sp) ? "Interrupted write: " : "", + name, msg, nlno, nlno == 1 ? "" : "s", nch); + + return (0); +} + +/* + * file_m1 -- + * First modification check routine. The :next, :prev, :rewind, :tag, + * :tagpush, :tagpop, ^^ modifications check. + */ +int +file_m1(sp, ep, force, flags) + SCR *sp; + EXF *ep; + int force, flags; +{ + /* + * If the file has been modified, we'll want to write it back or + * fail. If autowrite is set, we'll write it back automatically, + * unless force is also set. Otherwise, we fail unless forced or + * there's another open screen on this file. + */ + if (F_ISSET(ep, F_MODIFIED)) + if (O_ISSET(sp, O_AUTOWRITE)) { + if (!force && + file_write(sp, ep, NULL, NULL, NULL, flags)) + return (1); + } else if (ep->refcnt <= 1 && !force) { + msgq(sp, M_ERR, + "File modified since last complete write; write or use %s to override", + LF_ISSET(FS_POSSIBLE) ? "!" : ":edit!"); + return (1); + } + + return (file_m3(sp, ep, force)); +} + +/* + * file_m2 -- + * Second modification check routine. The :edit, :quit, :recover + * modifications check. + */ +int +file_m2(sp, ep, force) + SCR *sp; + EXF *ep; + int force; +{ + /* + * If the file has been modified, we'll want to fail, unless forced + * or there's another open screen on this file. + */ + if (F_ISSET(ep, F_MODIFIED) && ep->refcnt <= 1 && !force) { + msgq(sp, M_ERR, + "File modified since last complete write; write or use ! to override"); + return (1); + } + + return (file_m3(sp, ep, force)); +} + +/* + * file_m3 -- + * Third modification check routine. + */ +int +file_m3(sp, ep, force) + SCR *sp; + EXF *ep; + int force; +{ + /* + * Don't exit while in a temporary files if the file was ever modified. + * The problem is that if the user does a ":wq", we write and quit, + * unlinking the temporary file. Not what the user had in mind at all. + * We permit writing to temporary files, so that user maps using file + * system names work with temporary files. + */ + if (F_ISSET(sp->frp, FR_TMPEXIT) && ep->refcnt <= 1 && !force) { + msgq(sp, M_ERR, + "File is a temporary; exit will discard modifications"); + return (1); + } + return (0); +} + +/* + * file_lock -- + * Get an exclusive lock on a file. + * + * XXX + * The default locking is flock(2) style, not fcntl(2). The latter is + * known to fail badly on some systems, and its only advantage is that + * it occasionally works over NFS. + * + * Furthermore, the semantics of fcntl(2) are wrong. The problems are + * two-fold: you can't close any file descriptor associated with the file + * without losing all of the locks, and you can't get an exclusive lock + * unless you have the file open for writing. Someone ought to be shot, + * but it's probably too late, they may already have reproduced. To get + * around these problems, nvi opens the files for writing when it can and + * acquires a second file descriptor when it can't. The recovery files + * are examples of the former, they're always opened for writing. The DB + * files can't be opened for writing because the semantics of DB are that + * files opened for writing are flushed back to disk when the DB session + * is ended. So, in that case we have to acquire an extra file descriptor. + */ +enum lockt +file_lock(name, fdp, fd, iswrite) + char *name; + int fd, *fdp, iswrite; +{ +#if !defined(USE_FCNTL) && defined(LOCK_EX) + /* Hurrah! We've got flock(2). */ + /* + * !!! + * We need to distinguish a lock not being available for the file + * from the file system not supporting locking. Flock is documented + * as returning EWOULDBLOCK; add EAGAIN for good measure, and assume + * they are the former. There's no portable way to do this. + */ + errno = 0; + return (flock(fd, LOCK_EX | LOCK_NB) ? + errno == EAGAIN || errno == EWOULDBLOCK ? + LOCK_UNAVAIL : LOCK_FAILED : LOCK_SUCCESS); + +#else /* Gag me. We've got fcntl(2). */ + struct flock arg; + int didopen, sverrno; + + arg.l_type = F_WRLCK; + arg.l_whence = 0; /* SEEK_SET */ + arg.l_start = arg.l_len = 0; + arg.l_pid = 0; + + /* If the file descriptor isn't opened for writing, it must fail. */ + if (!iswrite) { + if (name == NULL || fdp == NULL) + return (LOCK_FAILED); + if ((fd = open(name, O_RDWR, 0)) == -1) + return (LOCK_FAILED); + *fdp = fd; + didopen = 1; + } + + errno = 0; + if (!fcntl(fd, F_SETLK, &arg)) + return (LOCK_SUCCESS); + if (didopen) { + sverrno = errno; + (void)close(fd); + errno = sverrno; + } + + /* + * !!! + * We need to distinguish a lock not being available for the file + * from the file system not supporting locking. Fcntl is documented + * as returning EACCESS and EAGAIN; add EWOULDBLOCK for good measure, + * and assume they are the former. There's no portable way to do this. + */ + return (errno == EACCES || errno == EAGAIN || errno == EWOULDBLOCK ? + LOCK_UNAVAIL : LOCK_FAILED); +#endif +} diff --git a/usr.bin/vi/common/exf.h b/usr.bin/vi/common/exf.h new file mode 100644 index 0000000..1b06649 --- /dev/null +++ b/usr.bin/vi/common/exf.h @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)exf.h 8.35 (Berkeley) 8/4/94 + */ + /* Undo direction. */ +/* + * exf -- + * The file structure. + */ +struct _exf { + int refcnt; /* Reference count. */ + + /* Underlying database state. */ + DB *db; /* File db structure. */ + char *c_lp; /* Cached line. */ + size_t c_len; /* Cached line length. */ + recno_t c_lno; /* Cached line number. */ + recno_t c_nlines; /* Cached lines in the file. */ + + DB *log; /* Log db structure. */ + char *l_lp; /* Log buffer. */ + size_t l_len; /* Log buffer length. */ + recno_t l_high; /* Log last + 1 record number. */ + recno_t l_cur; /* Log current record number. */ + MARK l_cursor; /* Log cursor position. */ + enum direction lundo; /* Last undo direction. */ + + LIST_HEAD(_markh, _lmark) marks;/* Linked list of file MARK's. */ + + time_t mtime; /* Last modification time. */ + + int fcntl_fd; /* Fcntl locking fd; see exf.c. */ + + /* + * Recovery in general, and these fields specifically, are described + * in recover.c. + */ +#define RCV_PERIOD 120 /* Sync every two minutes. */ + char *rcv_path; /* Recover file name. */ + char *rcv_mpath; /* Recover mail file name. */ + int rcv_fd; /* Locked mail file descriptor. */ + struct timeval rcv_tod; /* ITIMER_REAL: recovery time-of-day. */ + +#define F_FIRSTMODIFY 0x001 /* File not yet modified. */ +#define F_MODIFIED 0x002 /* File is currently dirty. */ +#define F_MULTILOCK 0x004 /* Multiple processes running, lock. */ +#define F_NOLOG 0x008 /* Logging turned off. */ +#define F_RCV_NORM 0x010 /* Don't delete recovery files. */ +#define F_RCV_ON 0x020 /* Recovery is possible. */ +#define F_UNDO 0x040 /* No change since last undo. */ + u_int8_t flags; +}; + +#define GETLINE_ERR(sp, lno) { \ + msgq(sp, M_ERR, \ + "Error: %s/%d: unable to retrieve line %u", \ + tail(__FILE__), __LINE__, lno); \ +} + +/* EXF routines. */ +FREF *file_add __P((SCR *, CHAR_T *)); +int file_end __P((SCR *, EXF *, int)); +int file_init __P((SCR *, FREF *, char *, int)); +int file_m1 __P((SCR *, EXF *, int, int)); +int file_m2 __P((SCR *, EXF *, int)); +int file_m3 __P((SCR *, EXF *, int)); + +enum lockt { LOCK_FAILED, LOCK_SUCCESS, LOCK_UNAVAIL }; +enum lockt + file_lock __P((char *, int *, int, int)); + +#define FS_ALL 0x01 /* Write the entire file. */ +#define FS_APPEND 0x02 /* Append to the file. */ +#define FS_FORCE 0x04 /* Force is set. */ +#define FS_POSSIBLE 0x08 /* Force could be set. */ +int file_write __P((SCR *, EXF *, MARK *, MARK *, char *, int)); + +/* Recovery routines. */ +int rcv_init __P((SCR *, EXF *)); +int rcv_list __P((SCR *)); +int rcv_on __P((SCR *, EXF *)); +int rcv_read __P((SCR *, FREF *)); + +#define RCV_EMAIL 0x01 /* Send the user email, IFF file modified. */ +#define RCV_ENDSESSION 0x02 /* End the file session. */ +#define RCV_PRESERVE 0x04 /* Preserve backup file, IFF file modified. */ +#define RCV_SNAPSHOT 0x08 /* Snapshot the recovery, and send email. */ +int rcv_sync __P((SCR *, EXF *, u_int)); +int rcv_tmp __P((SCR *, EXF *, char *)); + +/* DB interface routines */ +int file_aline __P((SCR *, EXF *, int, recno_t, char *, size_t)); +int file_dline __P((SCR *, EXF *, recno_t)); +char *file_gline __P((SCR *, EXF *, recno_t, size_t *)); +int file_iline __P((SCR *, EXF *, recno_t, char *, size_t)); +int file_lline __P((SCR *, EXF *, recno_t *)); +char *file_rline __P((SCR *, EXF *, recno_t, size_t *)); +int file_sline __P((SCR *, EXF *, recno_t, char *, size_t)); diff --git a/usr.bin/vi/common/gs.h b/usr.bin/vi/common/gs.h new file mode 100644 index 0000000..36343f4 --- /dev/null +++ b/usr.bin/vi/common/gs.h @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)gs.h 8.39 (Berkeley) 7/23/94 + */ + +struct _gs { + CIRCLEQ_HEAD(_dqh, _scr) dq; /* Displayed screens. */ + CIRCLEQ_HEAD(_hqh, _scr) hq; /* Hidden screens. */ + + mode_t origmode; /* Original terminal mode. */ + struct termios + original_termios; /* Original terminal values. */ + + MSGH msgq; /* User message list. */ + + char *tmp_bp; /* Temporary buffer. */ + size_t tmp_blen; /* Size of temporary buffer. */ + + sigset_t blockset; /* Signal mask. */ + +#ifdef DEBUG + FILE *tracefp; /* Trace file pointer. */ +#endif + +/* INFORMATION SHARED BY ALL SCREENS. */ + IBUF *tty; /* Key input buffer. */ + + CB *dcbp; /* Default cut buffer pointer. */ + CB dcb_store; /* Default cut buffer storage. */ + LIST_HEAD(_cuth, _cb) cutq; /* Linked list of cut buffers. */ + +#define MAX_BIT_SEQ 128 /* Max + 1 fast check character. */ + LIST_HEAD(_seqh, _seq) seqq; /* Linked list of maps, abbrevs. */ + bitstr_t bit_decl(seqb, MAX_BIT_SEQ); + +#define MAX_FAST_KEY 254 /* Max fast check character.*/ +#define KEY_LEN(sp, ch) \ + ((ch) <= MAX_FAST_KEY ? \ + sp->gp->cname[ch].len : __key_len(sp, ch)) +#define KEY_NAME(sp, ch) \ + ((ch) <= MAX_FAST_KEY ? \ + sp->gp->cname[ch].name : __key_name(sp, ch)) + struct { + CHAR_T name[MAX_CHARACTER_COLUMNS + 1]; + u_int8_t len; + } cname[MAX_FAST_KEY + 1]; /* Fast lookup table. */ + +#define KEY_VAL(sp, ch) \ + ((ch) <= MAX_FAST_KEY ? sp->gp->special_key[ch] : \ + (ch) > sp->gp->max_special ? 0 : __key_val(sp, ch)) + CHAR_T max_special; /* Max special character. */ + u_char /* Fast lookup table. */ + special_key[MAX_FAST_KEY + 1]; + +/* Interrupt macros. */ +#define INTERRUPTED(sp) \ + (F_ISSET((sp), S_INTERRUPTED) || F_ISSET((sp)->gp, G_SIGINT)) +#define CLR_INTERRUPT(sp) { \ + F_CLR((sp), S_INTERRUPTED | S_INTERRUPTIBLE); \ + F_CLR((sp)->gp, G_SIGINT); \ +} + +#define G_ABBREV 0x0001 /* If have abbreviations. */ +#define G_BELLSCHED 0x0002 /* Bell scheduled. */ +#define G_RECOVER_SET 0x0004 /* Recover system initialized. */ +#define G_SETMODE 0x0008 /* Tty mode changed. */ +#define G_SIGALRM 0x0010 /* SIGALRM arrived. */ +#define G_SIGINT 0x0020 /* SIGINT arrived. */ +#define G_SIGWINCH 0x0040 /* SIGWINCH arrived. */ +#define G_SNAPSHOT 0x0080 /* Always snapshot files. */ +#define G_STDIN_TTY 0x0100 /* Standard input is a tty. */ +#define G_TERMIOS_SET 0x0200 /* Termios structure is valid. */ +#define G_TMP_INUSE 0x0400 /* Temporary buffer in use. */ + u_int16_t flags; +}; + +extern GS *__global_list; /* List of screens. */ diff --git a/usr.bin/vi/common/line.c b/usr.bin/vi/common/line.c new file mode 100644 index 0000000..12d22e4 --- /dev/null +++ b/usr.bin/vi/common/line.c @@ -0,0 +1,492 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)line.c 8.30 (Berkeley) 6/30/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +static __inline int scr_update + __P((SCR *, EXF *, recno_t, enum operation, int)); + +/* + * file_gline -- + * Look in the text buffers for a line; if it's not there + * call file_rline to retrieve it from the database. + */ +char * +file_gline(sp, ep, lno, lenp) + SCR *sp; + EXF *ep; + recno_t lno; /* Line number. */ + size_t *lenp; /* Length store. */ +{ + TEXT *tp; + recno_t l1, l2; + + /* + * The underlying recno stuff handles zero by returning NULL, but + * have to have an oob condition for the look-aside into the input + * buffer anyway. + */ + if (lno == 0) + return (NULL); + + /* + * Look-aside into the TEXT buffers and see if the line we want + * is there. + */ + if (F_ISSET(sp, S_INPUT)) { + l1 = ((TEXT *)sp->tiqp->cqh_first)->lno; + l2 = ((TEXT *)sp->tiqp->cqh_last)->lno; + if (l1 <= lno && l2 >= lno) { + for (tp = sp->tiqp->cqh_first; + tp->lno != lno; tp = tp->q.cqe_next); + if (lenp) + *lenp = tp->len; + return (tp->lb); + } + /* + * Adjust the line number for the number of lines used + * by the text input buffers. + */ + if (lno > l2) + lno -= l2 - l1; + } + return (file_rline(sp, ep, lno, lenp)); +} + +/* + * file_rline -- + * Look in the cache for a line; if it's not there retrieve + * it from the file. + */ +char * +file_rline(sp, ep, lno, lenp) + SCR *sp; + EXF *ep; + recno_t lno; /* Line number. */ + size_t *lenp; /* Length store. */ +{ + DBT data, key; + + /* Check the cache. */ + if (lno == ep->c_lno) { + if (lenp) + *lenp = ep->c_len; + return (ep->c_lp); + } + ep->c_lno = OOBLNO; + + /* Get the line from the underlying database. */ + key.data = &lno; + key.size = sizeof(lno); + switch (ep->db->get(ep->db, &key, &data, 0)) { + case -1: + msgq(sp, M_ERR, + "Error: %s/%d: unable to get line %u: %s", + tail(__FILE__), __LINE__, lno, strerror(errno)); + /* FALLTHROUGH */ + case 1: + return (NULL); + /* NOTREACHED */ + } + if (lenp) + *lenp = data.size; + + /* Fill the cache. */ + ep->c_lno = lno; + ep->c_len = data.size; + ep->c_lp = data.data; + + return (data.data); +} + +/* + * file_dline -- + * Delete a line from the file. + */ +int +file_dline(sp, ep, lno) + SCR *sp; + EXF *ep; + recno_t lno; +{ + DBT key; + +#if defined(DEBUG) && 0 + TRACE(sp, "delete line %lu\n", lno); +#endif + /* + * XXX + * Marks and global commands have to know when lines are + * inserted or deleted. + */ + mark_insdel(sp, ep, LINE_DELETE, lno); + global_insdel(sp, ep, LINE_DELETE, lno); + + /* Log change. */ + log_line(sp, ep, lno, LOG_LINE_DELETE); + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + SIGBLOCK(sp->gp); + if (ep->db->del(ep->db, &key, 0) == 1) { + msgq(sp, M_ERR, + "Error: %s/%d: unable to delete line %u: %s", + tail(__FILE__), __LINE__, lno, strerror(errno)); + return (1); + } + SIGUNBLOCK(sp->gp); + + /* Flush the cache, update line count, before screen update. */ + if (lno <= ep->c_lno) + ep->c_lno = OOBLNO; + if (ep->c_nlines != OOBLNO) + --ep->c_nlines; + + /* File now dirty. */ + if (F_ISSET(ep, F_FIRSTMODIFY)) + (void)rcv_init(sp, ep); + F_SET(ep, F_MODIFIED); + + /* Update screen. */ + return (scr_update(sp, ep, lno, LINE_DELETE, 1)); +} + +/* + * file_aline -- + * Append a line into the file. + */ +int +file_aline(sp, ep, update, lno, p, len) + SCR *sp; + EXF *ep; + int update; + recno_t lno; + char *p; + size_t len; +{ + DBT data, key; + recno_t lline; + +#if defined(DEBUG) && 0 + TRACE(sp, "append to %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p); +#endif + /* + * XXX + * Very nasty special case. The historic vi code displays a single + * space (or a '$' if the list option is set) for the first line in + * an "empty" file. If we "insert" a line, that line gets scrolled + * down, not repainted, so it's incorrect when we refresh the the + * screen. This is really hard to find and fix in the vi code -- the + * text input functions detect it explicitly and don't insert a new + * line. The hack here is to repaint the screen if we're appending + * to an empty file. The reason that the test is in file_aline, and + * not in file_iline or file_sline, is that all of the ex commands + * that work in empty files end up here. + */ + if (lno == 0) { + if (file_lline(sp, ep, &lline)) + return (1); + if (lline == 0) + F_SET(sp, S_REDRAW); + } + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + data.data = p; + data.size = len; + SIGBLOCK(sp->gp); + if (ep->db->put(ep->db, &key, &data, R_IAFTER) == -1) { + msgq(sp, M_ERR, + "Error: %s/%d: unable to append to line %u: %s", + tail(__FILE__), __LINE__, lno, strerror(errno)); + return (1); + } + SIGUNBLOCK(sp->gp); + + /* Flush the cache, update line count, before screen update. */ + if (lno < ep->c_lno) + ep->c_lno = OOBLNO; + if (ep->c_nlines != OOBLNO) + ++ep->c_nlines; + + /* File now dirty. */ + if (F_ISSET(ep, F_FIRSTMODIFY)) + (void)rcv_init(sp, ep); + F_SET(ep, F_MODIFIED); + + /* Log change. */ + log_line(sp, ep, lno + 1, LOG_LINE_APPEND); + + /* + * XXX + * Marks and global commands have to know when lines are + * inserted or deleted. + * + * XXX + * See comment above about empty files. If the file was empty, + * then we're adding the first line, which is a replacement, not + * an append. So, we shouldn't whack the marks. + */ + if (lno != 0) { + mark_insdel(sp, ep, LINE_INSERT, lno + 1); + global_insdel(sp, ep, LINE_INSERT, lno + 1); + } + + /* + * Update screen. + * + * XXX + * Nasty hack. If multiple lines are input by the user, they aren't + * committed until an <ESC> is entered. The problem is the screen was + * updated/scrolled as each line was entered. So, when this routine + * is called to copy the new lines from the cut buffer into the file, + * it has to know not to update the screen again. + */ + return (scr_update(sp, ep, lno, LINE_APPEND, update)); +} + +/* + * file_iline -- + * Insert a line into the file. + */ +int +file_iline(sp, ep, lno, p, len) + SCR *sp; + EXF *ep; + recno_t lno; + char *p; + size_t len; +{ + DBT data, key; + recno_t lline; + +#if defined(DEBUG) && 0 + TRACE(sp, + "insert before %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p); +#endif + + /* Very nasty special case. See comment in file_aline(). */ + if (lno == 1) { + if (file_lline(sp, ep, &lline)) + return (1); + if (lline == 0) + F_SET(sp, S_REDRAW); + } + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + data.data = p; + data.size = len; + SIGBLOCK(sp->gp); + if (ep->db->put(ep->db, &key, &data, R_IBEFORE) == -1) { + msgq(sp, M_ERR, + "Error: %s/%d: unable to insert at line %u: %s", + tail(__FILE__), __LINE__, lno, strerror(errno)); + return (1); + } + SIGUNBLOCK(sp->gp); + + /* Flush the cache, update line count, before screen update. */ + if (lno >= ep->c_lno) + ep->c_lno = OOBLNO; + if (ep->c_nlines != OOBLNO) + ++ep->c_nlines; + + /* File now dirty. */ + if (F_ISSET(ep, F_FIRSTMODIFY)) + (void)rcv_init(sp, ep); + F_SET(ep, F_MODIFIED); + + /* Log change. */ + log_line(sp, ep, lno, LOG_LINE_INSERT); + + /* + * XXX + * Marks and global commands have to know when lines are + * inserted or deleted. + */ + mark_insdel(sp, ep, LINE_INSERT, lno); + global_insdel(sp, ep, LINE_INSERT, lno); + + /* Update screen. */ + return (scr_update(sp, ep, lno, LINE_INSERT, 1)); +} + +/* + * file_sline -- + * Store a line in the file. + */ +int +file_sline(sp, ep, lno, p, len) + SCR *sp; + EXF *ep; + recno_t lno; + char *p; + size_t len; +{ + DBT data, key; + +#if defined(DEBUG) && 0 + TRACE(sp, + "replace line %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p); +#endif + /* Log before change. */ + log_line(sp, ep, lno, LOG_LINE_RESET_B); + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + data.data = p; + data.size = len; + SIGBLOCK(sp->gp); + if (ep->db->put(ep->db, &key, &data, 0) == -1) { + msgq(sp, M_ERR, + "Error: %s/%d: unable to store line %u: %s", + tail(__FILE__), __LINE__, lno, strerror(errno)); + return (1); + } + SIGUNBLOCK(sp->gp); + + /* Flush the cache, before logging or screen update. */ + if (lno == ep->c_lno) + ep->c_lno = OOBLNO; + + /* File now dirty. */ + if (F_ISSET(ep, F_FIRSTMODIFY)) + (void)rcv_init(sp, ep); + F_SET(ep, F_MODIFIED); + + /* Log after change. */ + log_line(sp, ep, lno, LOG_LINE_RESET_F); + + /* Update screen. */ + return (scr_update(sp, ep, lno, LINE_RESET, 1)); +} + +/* + * file_lline -- + * Return the number of lines in the file. + */ +int +file_lline(sp, ep, lnop) + SCR *sp; + EXF *ep; + recno_t *lnop; +{ + DBT data, key; + recno_t lno; + + /* Check the cache. */ + if (ep->c_nlines != OOBLNO) { + *lnop = (F_ISSET(sp, S_INPUT) && + ((TEXT *)sp->tiqp->cqh_last)->lno > ep->c_nlines ? + ((TEXT *)sp->tiqp->cqh_last)->lno : ep->c_nlines); + return (0); + } + + key.data = &lno; + key.size = sizeof(lno); + + switch (ep->db->seq(ep->db, &key, &data, R_LAST)) { + case -1: + msgq(sp, M_ERR, + "Error: %s/%d: unable to get last line: %s", + tail(__FILE__), __LINE__, strerror(errno)); + *lnop = 0; + return (1); + case 1: + *lnop = 0; + return (0); + default: + break; + } + + /* Fill the cache. */ + memmove(&lno, key.data, sizeof(lno)); + ep->c_nlines = ep->c_lno = lno; + ep->c_len = data.size; + ep->c_lp = data.data; + + /* Return the value. */ + *lnop = (F_ISSET(sp, S_INPUT) && + ((TEXT *)sp->tiqp->cqh_last)->lno > lno ? + ((TEXT *)sp->tiqp->cqh_last)->lno : lno); + return (0); +} + +/* + * scr_update -- + * Update all of the screens that are backed by the file that + * just changed. + */ +static __inline int +scr_update(sp, ep, lno, op, current) + SCR *sp; + EXF *ep; + recno_t lno; + enum operation op; + int current; +{ + SCR *tsp; + + if (ep->refcnt != 1) + for (tsp = sp->gp->dq.cqh_first; + tsp != (void *)&sp->gp->dq; tsp = tsp->q.cqe_next) + if (sp != tsp && tsp->ep == ep) + (void)sp->s_change(tsp, ep, lno, op); + return (current && sp->s_change(sp, ep, lno, op)); +} diff --git a/usr.bin/vi/common/log.c b/usr.bin/vi/common/log.c new file mode 100644 index 0000000..09f0c27 --- /dev/null +++ b/usr.bin/vi/common/log.c @@ -0,0 +1,698 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)log.c 8.16 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +/* + * The log consists of records, each containing a type byte and a variable + * length byte string, as follows: + * + * LOG_CURSOR_INIT MARK + * LOG_CURSOR_END MARK + * LOG_LINE_APPEND recno_t char * + * LOG_LINE_DELETE recno_t char * + * LOG_LINE_INSERT recno_t char * + * LOG_LINE_RESET_F recno_t char * + * LOG_LINE_RESET_B recno_t char * + * LOG_MARK LMARK + * + * We do before image physical logging. This means that the editor layer + * MAY NOT modify records in place, even if simply deleting or overwriting + * characters. Since the smallest unit of logging is a line, we're using + * up lots of space. This may eventually have to be reduced, probably by + * doing logical logging, which is a much cooler database phrase. + * + * The implementation of the historic vi 'u' command, using roll-forward and + * roll-back, is simple. Each set of changes has a LOG_CURSOR_INIT record, + * followed by a number of other records, followed by a LOG_CURSOR_END record. + * LOG_LINE_RESET records come in pairs. The first is a LOG_LINE_RESET_B + * record, and is the line before the change. The second is LOG_LINE_RESET_F, + * and is the line after the change. Roll-back is done by backing up to the + * first LOG_CURSOR_INIT record before a change. Roll-forward is done in a + * similar fashion. + * + * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END + * record for a line different from the current one. It should be noted that + * this means that a subsequent 'u' command will make a change based on the + * new position of the log's cursor. This is okay, and, in fact, historic vi + * behaved that way. + */ + +static int log_cursor1 __P((SCR *, EXF *, int)); +#if defined(DEBUG) && 0 +static void log_trace __P((SCR *, char *, recno_t, u_char *)); +#endif + +/* Try and restart the log on failure, i.e. if we run out of memory. */ +#define LOG_ERR { \ + msgq(sp, M_ERR, "Error: %s/%d: put log error: %s", \ + tail(__FILE__), __LINE__, strerror(errno)); \ + (void)ep->log->close(ep->log); \ + if (!log_init(sp, ep)) \ + msgq(sp, M_ERR, "Log restarted"); \ + return (1); \ +} + +/* + * log_init -- + * Initialize the logging subsystem. + */ +int +log_init(sp, ep) + SCR *sp; + EXF *ep; +{ + /* + * Initialize the buffer. The logging subsystem has its own + * buffers because the global ones are almost by definition + * going to be in use when the log runs. + */ + ep->l_lp = NULL; + ep->l_len = 0; + ep->l_cursor.lno = 1; /* XXX Any valid recno. */ + ep->l_cursor.cno = 0; + ep->l_high = ep->l_cur = 1; + + ep->log = dbopen(NULL, O_CREAT | O_NONBLOCK | O_RDWR, + S_IRUSR | S_IWUSR, DB_RECNO, NULL); + if (ep->log == NULL) { + msgq(sp, M_ERR, "log db: %s", strerror(errno)); + F_SET(ep, F_NOLOG); + return (1); + } + + return (0); +} + +/* + * log_end -- + * Close the logging subsystem. + */ +int +log_end(sp, ep) + SCR *sp; + EXF *ep; +{ + if (ep->log != NULL) { + (void)(ep->log->close)(ep->log); + ep->log = NULL; + } + if (ep->l_lp != NULL) { + free(ep->l_lp); + ep->l_lp = NULL; + } + ep->l_len = 0; + ep->l_cursor.lno = 1; /* XXX Any valid recno. */ + ep->l_cursor.cno = 0; + ep->l_high = ep->l_cur = 1; + return (0); +} + +/* + * log_cursor -- + * Log the current cursor position, starting an event. + */ +int +log_cursor(sp, ep) + SCR *sp; + EXF *ep; +{ + /* + * If any changes were made since the last cursor init, + * put out the ending cursor record. + */ + if (ep->l_cursor.lno == OOBLNO) { + ep->l_cursor.lno = sp->lno; + ep->l_cursor.cno = sp->cno; + return (log_cursor1(sp, ep, LOG_CURSOR_END)); + } + ep->l_cursor.lno = sp->lno; + ep->l_cursor.cno = sp->cno; + return (0); +} + +/* + * log_cursor1 -- + * Actually push a cursor record out. + */ +static int +log_cursor1(sp, ep, type) + SCR *sp; + EXF *ep; + int type; +{ + DBT data, key; + + BINC_RET(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK)); + ep->l_lp[0] = type; + memmove(ep->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK)); + + key.data = &ep->l_cur; + key.size = sizeof(recno_t); + data.data = ep->l_lp; + data.size = sizeof(u_char) + sizeof(MARK); + if (ep->log->put(ep->log, &key, &data, 0) == -1) + LOG_ERR; + +#if defined(DEBUG) && 0 + TRACE(sp, "%lu: %s: %u/%u\n", ep->l_cur, + type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end", + sp->lno, sp->cno); +#endif + /* Reset high water mark. */ + ep->l_high = ++ep->l_cur; + + return (0); +} + +/* + * log_line -- + * Log a line change. + */ +int +log_line(sp, ep, lno, action) + SCR *sp; + EXF *ep; + recno_t lno; + u_int action; +{ + DBT data, key; + size_t len; + char *lp; + + if (F_ISSET(ep, F_NOLOG)) + return (0); + + /* + * XXX + * + * Kluge for vi. Clear the EXF undo flag so that the + * next 'u' command does a roll-back, regardless. + */ + F_CLR(ep, F_UNDO); + + /* Put out one initial cursor record per set of changes. */ + if (ep->l_cursor.lno != OOBLNO) { + if (log_cursor1(sp, ep, LOG_CURSOR_INIT)) + return (1); + ep->l_cursor.lno = OOBLNO; + } + + /* + * Put out the changes. If it's a LOG_LINE_RESET_B call, it's a + * special case, avoid the caches. Also, if it fails and it's + * line 1, it just means that the user started with an empty file, + * so fake an empty length line. + */ + if (action == LOG_LINE_RESET_B) { + if ((lp = file_rline(sp, ep, lno, &len)) == NULL) { + if (lno != 1) { + GETLINE_ERR(sp, lno); + return (1); + } + len = 0; + lp = ""; + } + } else + if ((lp = file_gline(sp, ep, lno, &len)) == NULL) { + GETLINE_ERR(sp, lno); + return (1); + } + BINC_RET(sp, + ep->l_lp, ep->l_len, len + sizeof(u_char) + sizeof(recno_t)); + ep->l_lp[0] = action; + memmove(ep->l_lp + sizeof(u_char), &lno, sizeof(recno_t)); + memmove(ep->l_lp + sizeof(u_char) + sizeof(recno_t), lp, len); + + key.data = &ep->l_cur; + key.size = sizeof(recno_t); + data.data = ep->l_lp; + data.size = len + sizeof(u_char) + sizeof(recno_t); + if (ep->log->put(ep->log, &key, &data, 0) == -1) + LOG_ERR; + +#if defined(DEBUG) && 0 + switch (action) { + case LOG_LINE_APPEND: + TRACE(sp, "%u: log_line: append: %lu {%u}\n", + ep->l_cur, lno, len); + break; + case LOG_LINE_DELETE: + TRACE(sp, "%lu: log_line: delete: %lu {%u}\n", + ep->l_cur, lno, len); + break; + case LOG_LINE_INSERT: + TRACE(sp, "%lu: log_line: insert: %lu {%u}\n", + ep->l_cur, lno, len); + break; + case LOG_LINE_RESET_F: + TRACE(sp, "%lu: log_line: reset_f: %lu {%u}\n", + ep->l_cur, lno, len); + break; + case LOG_LINE_RESET_B: + TRACE(sp, "%lu: log_line: reset_b: %lu {%u}\n", + ep->l_cur, lno, len); + break; + } +#endif + /* Reset high water mark. */ + ep->l_high = ++ep->l_cur; + + return (0); +} + +/* + * log_mark -- + * Log a mark position. For the log to work, we assume that there + * aren't any operations that just put out a log record -- this + * would mean that undo operations would only reset marks, and not + * cause any other change. + */ +int +log_mark(sp, ep, lmp) + SCR *sp; + EXF *ep; + LMARK *lmp; +{ + DBT data, key; + + if (F_ISSET(ep, F_NOLOG)) + return (0); + + /* Put out one initial cursor record per set of changes. */ + if (ep->l_cursor.lno != OOBLNO) { + if (log_cursor1(sp, ep, LOG_CURSOR_INIT)) + return (1); + ep->l_cursor.lno = OOBLNO; + } + + BINC_RET(sp, ep->l_lp, + ep->l_len, sizeof(u_char) + sizeof(LMARK)); + ep->l_lp[0] = LOG_MARK; + memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK)); + + key.data = &ep->l_cur; + key.size = sizeof(recno_t); + data.data = ep->l_lp; + data.size = sizeof(u_char) + sizeof(LMARK); + if (ep->log->put(ep->log, &key, &data, 0) == -1) + LOG_ERR; + +#if defined(DEBUG) && 0 + TRACE(sp, "%lu: mark %c: %lu/%u\n", + ep->l_cur, lmp->name, lmp->lno, lmp->cno); +#endif + /* Reset high water mark. */ + ep->l_high = ++ep->l_cur; + return (0); +} + +/* + * Log_backward -- + * Roll the log backward one operation. + */ +int +log_backward(sp, ep, rp) + SCR *sp; + EXF *ep; + MARK *rp; +{ + DBT key, data; + LMARK lm; + MARK m; + recno_t lno; + int didop; + u_char *p; + + if (F_ISSET(ep, F_NOLOG)) { + msgq(sp, M_ERR, + "Logging not being performed, undo not possible"); + return (1); + } + + if (ep->l_cur == 1) { + msgq(sp, M_BERR, "No changes to undo"); + return (1); + } + + F_SET(ep, F_NOLOG); /* Turn off logging. */ + + key.data = &ep->l_cur; /* Initialize db request. */ + key.size = sizeof(recno_t); + for (didop = 0;;) { + --ep->l_cur; + if (ep->log->get(ep->log, &key, &data, 0)) + LOG_ERR; +#if defined(DEBUG) && 0 + log_trace(sp, "log_backward", ep->l_cur, data.data); +#endif + switch (*(p = (u_char *)data.data)) { + case LOG_CURSOR_INIT: + if (didop) { + memmove(rp, p + sizeof(u_char), sizeof(MARK)); + F_CLR(ep, F_NOLOG); + return (0); + } + break; + case LOG_CURSOR_END: + break; + case LOG_LINE_APPEND: + case LOG_LINE_INSERT: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (file_dline(sp, ep, lno)) + goto err; + ++sp->rptlines[L_DELETED]; + break; + case LOG_LINE_DELETE: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (file_iline(sp, ep, lno, p + sizeof(u_char) + + sizeof(recno_t), data.size - sizeof(u_char) - + sizeof(recno_t))) + goto err; + ++sp->rptlines[L_ADDED]; + break; + case LOG_LINE_RESET_F: + break; + case LOG_LINE_RESET_B: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (file_sline(sp, ep, lno, p + sizeof(u_char) + + sizeof(recno_t), data.size - sizeof(u_char) - + sizeof(recno_t))) + goto err; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + break; + case LOG_MARK: + didop = 1; + memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); + m.lno = lm.lno; + m.cno = lm.cno; + if (mark_set(sp, ep, lm.name, &m, 0)) + goto err; + break; + default: + abort(); + } + } + +err: F_CLR(ep, F_NOLOG); + return (1); +} + +/* + * Log_setline -- + * Reset the line to its original appearance. + * + * XXX + * There's a bug in this code due to our not logging cursor movements + * unless a change was made. If you do a change, move off the line, + * then move back on and do a 'U', the line will be restored to the way + * it was before the original change. + */ +int +log_setline(sp, ep) + SCR *sp; + EXF *ep; +{ + DBT key, data; + LMARK lm; + MARK m; + recno_t lno; + u_char *p; + + if (F_ISSET(ep, F_NOLOG)) { + msgq(sp, M_ERR, + "Logging not being performed, undo not possible"); + return (1); + } + + if (ep->l_cur == 1) + return (1); + + F_SET(ep, F_NOLOG); /* Turn off logging. */ + + key.data = &ep->l_cur; /* Initialize db request. */ + key.size = sizeof(recno_t); + + for (;;) { + --ep->l_cur; + if (ep->log->get(ep->log, &key, &data, 0)) + LOG_ERR; +#if defined(DEBUG) && 0 + log_trace(sp, "log_setline", ep->l_cur, data.data); +#endif + switch (*(p = (u_char *)data.data)) { + case LOG_CURSOR_INIT: + memmove(&m, p + sizeof(u_char), sizeof(MARK)); + if (m.lno != sp->lno || ep->l_cur == 1) { + F_CLR(ep, F_NOLOG); + return (0); + } + break; + case LOG_CURSOR_END: + memmove(&m, p + sizeof(u_char), sizeof(MARK)); + if (m.lno != sp->lno) { + ++ep->l_cur; + F_CLR(ep, F_NOLOG); + return (0); + } + break; + case LOG_LINE_APPEND: + case LOG_LINE_INSERT: + case LOG_LINE_DELETE: + case LOG_LINE_RESET_F: + break; + case LOG_LINE_RESET_B: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (lno == sp->lno && + file_sline(sp, ep, lno, p + sizeof(u_char) + + sizeof(recno_t), data.size - sizeof(u_char) - + sizeof(recno_t))) + goto err; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + case LOG_MARK: + memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); + m.lno = lm.lno; + m.cno = lm.cno; + if (mark_set(sp, ep, lm.name, &m, 0)) + goto err; + break; + default: + abort(); + } + } + +err: F_CLR(ep, F_NOLOG); + return (1); +} + +/* + * Log_forward -- + * Roll the log forward one operation. + */ +int +log_forward(sp, ep, rp) + SCR *sp; + EXF *ep; + MARK *rp; +{ + DBT key, data; + LMARK lm; + MARK m; + recno_t lno; + int didop; + u_char *p; + + if (F_ISSET(ep, F_NOLOG)) { + msgq(sp, M_ERR, + "Logging not being performed, roll-forward not possible"); + return (1); + } + + if (ep->l_cur == ep->l_high) { + msgq(sp, M_BERR, "No changes to re-do"); + return (1); + } + + F_SET(ep, F_NOLOG); /* Turn off logging. */ + + key.data = &ep->l_cur; /* Initialize db request. */ + key.size = sizeof(recno_t); + for (didop = 0;;) { + ++ep->l_cur; + if (ep->log->get(ep->log, &key, &data, 0)) + LOG_ERR; +#if defined(DEBUG) && 0 + log_trace(sp, "log_forward", ep->l_cur, data.data); +#endif + switch (*(p = (u_char *)data.data)) { + case LOG_CURSOR_END: + if (didop) { + ++ep->l_cur; + memmove(rp, p + sizeof(u_char), sizeof(MARK)); + F_CLR(ep, F_NOLOG); + return (0); + } + break; + case LOG_CURSOR_INIT: + break; + case LOG_LINE_APPEND: + case LOG_LINE_INSERT: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (file_iline(sp, ep, lno, p + sizeof(u_char) + + sizeof(recno_t), data.size - sizeof(u_char) - + sizeof(recno_t))) + goto err; + ++sp->rptlines[L_ADDED]; + break; + case LOG_LINE_DELETE: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (file_dline(sp, ep, lno)) + goto err; + ++sp->rptlines[L_DELETED]; + break; + case LOG_LINE_RESET_B: + break; + case LOG_LINE_RESET_F: + didop = 1; + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + if (file_sline(sp, ep, lno, p + sizeof(u_char) + + sizeof(recno_t), data.size - sizeof(u_char) - + sizeof(recno_t))) + goto err; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + break; + case LOG_MARK: + didop = 1; + memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); + m.lno = lm.lno; + m.cno = lm.cno; + if (mark_set(sp, ep, lm.name, &m, 0)) + goto err; + break; + default: + abort(); + } + } + +err: F_CLR(ep, F_NOLOG); + return (1); +} + +#if defined(DEBUG) && 0 +static void +log_trace(sp, msg, rno, p) + SCR *sp; + char *msg; + recno_t rno; + u_char *p; +{ + LMARK lm; + MARK m; + recno_t lno; + + switch (*p) { + case LOG_CURSOR_INIT: + memmove(&m, p + sizeof(u_char), sizeof(MARK)); + TRACE(sp, "%lu: %s: C_INIT: %u/%u\n", rno, msg, m.lno, m.cno); + break; + case LOG_CURSOR_END: + memmove(&m, p + sizeof(u_char), sizeof(MARK)); + TRACE(sp, "%lu: %s: C_END: %u/%u\n", rno, msg, m.lno, m.cno); + break; + case LOG_LINE_APPEND: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: APPEND: %lu\n", rno, msg, lno); + break; + case LOG_LINE_INSERT: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: INSERT: %lu\n", rno, msg, lno); + break; + case LOG_LINE_DELETE: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: DELETE: %lu\n", rno, msg, lno); + break; + case LOG_LINE_RESET_F: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: RESET_F: %lu\n", rno, msg, lno); + break; + case LOG_LINE_RESET_B: + memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); + TRACE(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno); + break; + case LOG_MARK: + memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); + TRACE(sp, + "%lu: %s: MARK: %u/%u\n", rno, msg, lm.lno, lm.cno); + break; + default: + abort(); + } +} +#endif diff --git a/usr.bin/vi/common/log.h b/usr.bin/vi/common/log.h new file mode 100644 index 0000000..2974df4 --- /dev/null +++ b/usr.bin/vi/common/log.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)log.h 8.5 (Berkeley) 3/16/94 + */ + +#define LOG_NOTYPE 0 +#define LOG_CURSOR_INIT 1 +#define LOG_CURSOR_END 2 +#define LOG_LINE_APPEND 3 +#define LOG_LINE_DELETE 4 +#define LOG_LINE_INSERT 5 +#define LOG_LINE_RESET_F 6 +#define LOG_LINE_RESET_B 7 +#define LOG_MARK 8 + +int log_backward __P((SCR *, EXF *, MARK *)); +int log_cursor __P((SCR *, EXF *)); +int log_end __P((SCR *, EXF *)); +int log_forward __P((SCR *, EXF *, MARK *)); +int log_init __P((SCR *, EXF *)); +int log_line __P((SCR *, EXF *, recno_t, u_int)); +int log_mark __P((SCR *, EXF *, LMARK *)); +int log_setline __P((SCR *, EXF *)); diff --git a/usr.bin/vi/common/main.c b/usr.bin/vi/common/main.c new file mode 100644 index 0000000..5e4593e --- /dev/null +++ b/usr.bin/vi/common/main.c @@ -0,0 +1,711 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1992, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.103 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#include "compat.h" +#include <db.h> +#include <regex.h> +#include <pathnames.h> + +#include "vi.h" +#include "excmd.h" +#include "../ex/tag.h" + +enum rc { NOEXIST, NOPERM, OK }; + +static enum rc exrc_isok __P((SCR *, struct stat *, char *, int, int)); +static void gs_end __P((GS *)); +static GS *gs_init __P((void)); +static void obsolete __P((char *[])); +static void usage __P((int)); + +GS *__global_list; /* GLOBAL: List of screens. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + extern char *optarg; + static int reenter; /* STATIC: Re-entrancy check. */ + struct stat hsb, lsb; + GS *gp; + FREF *frp; + SCR *sp; + u_int flags, saved_vi_mode; + int ch, eval, flagchk, readonly, silent, snapshot; + char *excmdarg, *myname, *p, *tag_f, *trace_f, *wsizearg; + char path[MAXPATHLEN]; + + /* Stop if indirecting through a NULL pointer. */ + if (reenter++) + abort(); + +#ifdef GDBATTACH + (void)printf("%u waiting...\n", getpid()); + (void)read(0, &eval, 1); +#endif + + /* Set screen type and mode based on the program name. */ + readonly = 0; + if ((myname = strrchr(*argv, '/')) == NULL) + myname = *argv; + else + ++myname; + if (!strcmp(myname, "ex") || !strcmp(myname, "nex")) + LF_INIT(S_EX); + else { + /* View is readonly. */ + if (!strcmp(myname, "view")) + readonly = 1; + LF_INIT(S_VI_CURSES); + } + saved_vi_mode = S_VI_CURSES; + + /* Convert old-style arguments into new-style ones. */ + obsolete(argv); + + /* Parse the arguments. */ + flagchk = '\0'; + excmdarg = tag_f = trace_f = wsizearg = NULL; + silent = 0; + snapshot = 1; + while ((ch = getopt(argc, argv, "c:eFRrsT:t:vw:X:")) != EOF) + switch (ch) { + case 'c': /* Run the command. */ + excmdarg = optarg; + break; + case 'e': /* Ex mode. */ + LF_CLR(S_SCREENS); + LF_SET(S_EX); + break; + case 'F': /* No snapshot. */ + snapshot = 0; + break; + case 'R': /* Readonly. */ + readonly = 1; + break; + case 'r': /* Recover. */ + if (flagchk == 't') + errx(1, + "only one of -r and -t may be specified."); + flagchk = 'r'; + break; + case 's': + silent = 1; + break; + case 'T': /* Trace. */ + trace_f = optarg; + break; + case 't': /* Tag. */ + if (flagchk == 'r') + errx(1, + "only one of -r and -t may be specified."); + if (flagchk == 't') + errx(1, + "only one tag file may be specified."); + flagchk = 't'; + tag_f = optarg; + break; + case 'v': /* Vi mode. */ + LF_CLR(S_SCREENS); + LF_SET(S_VI_CURSES); + break; + case 'w': + wsizearg = optarg; + break; + case 'X': + if (!strcmp(optarg, "aw")) { + LF_CLR(S_SCREENS); + LF_SET(S_VI_XAW); + saved_vi_mode = S_VI_XAW; + break; + } + /* FALLTHROUGH */ + case '?': + default: + usage(LF_ISSET(S_EX)); + } + argc -= optind; + argv += optind; + + /* Silent is only applicable to ex. */ + if (silent && !LF_ISSET(S_EX)) + errx(1, "-s only applicable to ex."); + + /* Build and initialize the GS structure. */ + __global_list = gp = gs_init(); + + /* + * If not reading from a terminal, it's like -s was specified. + * Vi always reads from the terminal, so fail if it's not a + * terminal. + */ + if (!F_ISSET(gp, G_STDIN_TTY)) { + silent = 1; + if (!LF_ISSET(S_EX)) { + msgq(NULL, M_ERR, + "Vi's standard input must be a terminal"); + goto err; + } + } + + /* + * Build and initialize the first/current screen. This is a bit + * tricky. If an error is returned, we may or may not have a + * screen structure. If we have a screen structure, put it on a + * display queue so that the error messages get displayed. + */ + if (screen_init(NULL, &sp, flags)) { + if (sp != NULL) + CIRCLEQ_INSERT_HEAD(&__global_list->dq, sp, q); + goto err; + } + sp->saved_vi_mode = saved_vi_mode; + CIRCLEQ_INSERT_HEAD(&__global_list->dq, sp, q); + + if (trace_f != NULL) { +#ifdef DEBUG + if ((gp->tracefp = fopen(trace_f, "w")) == NULL) + err(1, "%s", trace_f); + (void)fprintf(gp->tracefp, "\n===\ntrace: open %s\n", trace_f); +#else + msgq(sp, M_ERR, "-T support not compiled into this version"); +#endif + } + + if (opts_init(sp)) /* Options initialization. */ + goto err; + if (readonly) /* Global read-only bit. */ + O_SET(sp, O_READONLY); + if (silent) { /* Ex batch mode. */ + O_CLR(sp, O_AUTOPRINT); + O_CLR(sp, O_PROMPT); + O_CLR(sp, O_VERBOSE); + O_CLR(sp, O_WARN); + F_SET(sp, S_EXSILENT); + } + if (wsizearg != NULL) { + ARGS *av[2], a, b; + errno = 0; + if (strtol(wsizearg, &p, 10) < 0 || errno || *p) + errx(1, "illegal window size -- %s.", wsizearg); + (void)snprintf(path, sizeof(path), "window=%s", wsizearg); + a.bp = (CHAR_T *)path; + a.len = strlen(path); + b.bp = NULL; + b.len = 0; + av[0] = &a; + av[1] = &b; + if (opts_set(sp, NULL, av)) + msgq(sp, M_ERR, + "Unable to set command line window size option"); + } + + /* Keymaps, special keys, must follow option initializations. */ + if (term_init(sp)) + goto err; + +#ifdef DIGRAPHS + if (digraph_init(sp)) /* Digraph initialization. */ + goto err; +#endif + + /* + * Source the system, environment, $HOME and local .exrc values. + * Vi historically didn't check $HOME/.exrc if the environment + * variable EXINIT was set. This is all done before the file is + * read in, because things in the .exrc information can set, for + * example, the recovery directory. + * + * !!! + * While nvi can handle any of the options settings of historic vi, + * the converse is not true. Since users are going to have to have + * files and environmental variables that work with both, we use nvi + * versions of both the $HOME and local startup files if they exist, + * otherwise the historic ones. + * + * !!! + * For a discussion of permissions and when what .exrc files are + * read, see the the comment above the exrc_isok() function below. + * + * !!! + * If the user started the historic of vi in $HOME, vi read the user's + * .exrc file twice, as $HOME/.exrc and as ./.exrc. We avoid this, as + * it's going to make some commands behave oddly, and I can't imagine + * anyone depending on it. + */ + if (!silent) { + switch (exrc_isok(sp, &hsb, _PATH_SYSEXRC, 1, 0)) { + case NOEXIST: + case NOPERM: + break; + case OK: + (void)ex_cfile(sp, NULL, _PATH_SYSEXRC, 0); + break; + } + + if ((p = getenv("NEXINIT")) != NULL || + (p = getenv("EXINIT")) != NULL) + if ((p = strdup(p)) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } else { + F_SET(sp, S_VLITONLY); + (void)ex_icmd(sp, NULL, p, strlen(p), 0); + F_CLR(sp, S_VLITONLY); + free(p); + } + else if ((p = getenv("HOME")) != NULL && *p) { + (void)snprintf(path, + sizeof(path), "%s/%s", p, _PATH_NEXRC); + switch (exrc_isok(sp, &hsb, path, 0, 1)) { + case NOEXIST: + (void)snprintf(path, + sizeof(path), "%s/%s", p, _PATH_EXRC); + if (exrc_isok(sp, &hsb, path, 0, 1) == OK) + (void)ex_cfile(sp, NULL, path, 0); + break; + case NOPERM: + break; + case OK: + (void)ex_cfile(sp, NULL, path, 0); + break; + } + } + + if (O_ISSET(sp, O_EXRC)) + switch (exrc_isok(sp, &lsb, _PATH_NEXRC, 0, 0)) { + case NOEXIST: + if (exrc_isok(sp, + &lsb, _PATH_EXRC, 0, 0) == OK && + (lsb.st_dev != hsb.st_dev || + lsb.st_ino != hsb.st_ino)) + (void)ex_cfile(sp, NULL, _PATH_EXRC, 0); + break; + case NOPERM: + break; + case OK: + if (lsb.st_dev != hsb.st_dev || + lsb.st_ino != hsb.st_ino) + (void)ex_cfile(sp, + NULL, _PATH_NEXRC, 0); + break; + } + } + + /* List recovery files if -r specified without file arguments. */ + if (flagchk == 'r' && argv[0] == NULL) + exit(rcv_list(sp)); + + /* Set the file snapshot flag. */ + if (snapshot) + F_SET(gp, G_SNAPSHOT); + + /* Use a tag file if specified. */ + if (tag_f != NULL && ex_tagfirst(sp, tag_f)) + goto err; + + /* + * Append any remaining arguments as file names. Files are + * recovery files if -r specified. + */ + if (*argv != NULL) { + sp->argv = sp->cargv = argv; + F_SET(sp, S_ARGNOFREE); + if (flagchk == 'r') + F_SET(sp, S_ARGRECOVER); + } + + /* + * If the tag option hasn't already created a file, create one. + * If no files as arguments, use a temporary file. + */ + if (tag_f == NULL) { + if ((frp = file_add(sp, + sp->argv == NULL ? NULL : (CHAR_T *)(sp->argv[0]))) == NULL) + goto err; + if (F_ISSET(sp, S_ARGRECOVER)) + F_SET(frp, FR_RECOVER); + if (file_init(sp, frp, NULL, 0)) + goto err; + } + + /* + * If there's an initial command, push it on the command stack. + * Historically, it was always an ex command, not vi in vi mode + * or ex in ex mode. So, make it look like an ex command to vi. + * + * !!! + * Historically, all such commands were executed with the last + * line of the file as the current line, and not the first, so + * set up vi to be at the end of the file. + */ + if (excmdarg != NULL) + if (IN_EX_MODE(sp)) { + if (term_push(sp, "\n", 1, 0)) + goto err; + if (term_push(sp, excmdarg, strlen(excmdarg), 0)) + goto err; + } else if (IN_VI_MODE(sp)) { + if (term_push(sp, "\n", 1, 0)) + goto err; + if (term_push(sp, excmdarg, strlen(excmdarg), 0)) + goto err; + if (term_push(sp, ":", 1, 0)) + goto err; + if (file_lline(sp, sp->ep, &sp->frp->lno)) + goto err; + F_SET(sp->frp, FR_CURSORSET); + } + + /* Set up signals. */ + if (sig_init(sp)) + goto err; + + for (;;) { + /* Ignore errors -- other screens may succeed. */ + (void)sp->s_edit(sp, sp->ep); + + /* + * Edit the next screen on the display queue, or, move + * a screen from the hidden queue to the display queue. + */ + if ((sp = __global_list->dq.cqh_first) == + (void *)&__global_list->dq) + if ((sp = __global_list->hq.cqh_first) != + (void *)&__global_list->hq) { + CIRCLEQ_REMOVE(&sp->gp->hq, sp, q); + CIRCLEQ_INSERT_TAIL(&sp->gp->dq, sp, q); + } else + break; + + /* + * The screen type may have changed -- reinitialize the + * functions in case it has. + */ + switch (F_ISSET(sp, S_SCREENS)) { + case S_EX: + if (sex_screen_init(sp)) + goto err; + break; + case S_VI_CURSES: + if (svi_screen_init(sp)) + goto err; + break; + case S_VI_XAW: + if (xaw_screen_init(sp)) + goto err; + break; + default: + abort(); + } + } + + eval = 0; + if (0) +err: eval = 1; + + /* + * NOTE: sp may be GONE when the screen returns, so only + * the gp can be trusted. + */ + gs_end(gp); + + exit(eval); +} + +/* + * gs_init -- + * Build and initialize the GS structure. + */ +static GS * +gs_init() +{ + GS *gp; + int fd; + + CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS)); + if (gp == NULL) + err(1, NULL); + + CIRCLEQ_INIT(&gp->dq); + CIRCLEQ_INIT(&gp->hq); + LIST_INIT(&gp->msgq); + + /* Structures shared by screens so stored in the GS structure. */ + CALLOC_NOMSG(NULL, gp->tty, IBUF *, 1, sizeof(IBUF)); + if (gp->tty == NULL) + err(1, NULL); + + CIRCLEQ_INIT(&gp->dcb_store.textq); + LIST_INIT(&gp->cutq); + LIST_INIT(&gp->seqq); + + /* Set a flag if we're reading from the tty. */ + if (isatty(STDIN_FILENO)) + F_SET(gp, G_STDIN_TTY); + + /* + * Set the G_STDIN_TTY flag. It's purpose is to avoid setting and + * resetting the tty if the input isn't from there. + * + * Set the G_TERMIOS_SET flag. It's purpose is to avoid using the + * original_termios information (mostly special character values) + * if it's not valid. We expect that if we've lost our controlling + * terminal that the open() (but not the tcgetattr()) will fail. + */ + if (F_ISSET(gp, G_STDIN_TTY)) { + if (tcgetattr(STDIN_FILENO, &gp->original_termios) == -1) + err(1, "tcgetattr"); + F_SET(gp, G_TERMIOS_SET); + } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) { + if (tcgetattr(fd, &gp->original_termios) == -1) + err(1, "tcgetattr"); + F_SET(gp, G_TERMIOS_SET); + (void)close(fd); + } + return (gp); +} + + +/* + * gs_end -- + * End the GS structure. + */ +static void +gs_end(gp) + GS *gp; +{ + MSG *mp; + SCR *sp; + char *tty; + + /* Default buffer storage. */ + (void)text_lfree(&gp->dcb_store.textq); + + /* Reset anything that needs resetting. */ + if (gp->flags & G_SETMODE) /* O_MESG */ + if ((tty = ttyname(STDERR_FILENO)) == NULL) + warn("ttyname"); + else if (chmod(tty, gp->origmode) < 0) + warn("%s", tty); + + /* Ring the bell if scheduled. */ + if (F_ISSET(gp, G_BELLSCHED)) + (void)fprintf(stderr, "\07"); /* \a */ + + /* If there are any remaining screens, flush their messages. */ + for (sp = __global_list->dq.cqh_first; + sp != (void *)&__global_list->dq; sp = sp->q.cqe_next) + for (mp = sp->msgq.lh_first; + mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next) + (void)fprintf(stderr, + "%.*s.\n", (int)mp->len, mp->mbuf); + for (sp = __global_list->hq.cqh_first; + sp != (void *)&__global_list->hq; sp = sp->q.cqe_next) + for (mp = sp->msgq.lh_first; + mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next) + (void)fprintf(stderr, + "%.*s.\n", (int)mp->len, mp->mbuf); + /* Flush messages on the global queue. */ + for (mp = gp->msgq.lh_first; + mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next) + (void)fprintf(stderr, "%.*s.\n", (int)mp->len, mp->mbuf); + + /* + * DON'T FREE THE GLOBAL STRUCTURE -- WE DIDN'T TURN + * OFF SIGNALS/TIMERS, SO IT MAY STILL BE REFERENCED. + */ +} + +/* + * exrc_isok -- + * Check a .exrc file for source-ability. + * + * !!! + * Historically, vi read the $HOME and local .exrc files if they were owned + * by the user's real ID, or the "sourceany" option was set, regardless of + * any other considerations. We no longer support the sourceany option as + * it's a security problem of mammoth proportions. We require the system + * .exrc file to be owned by root, the $HOME .exrc file to be owned by the + * user's effective ID (or that the user's effective ID be root) and the + * local .exrc files to be owned by the user's effective ID. In all cases, + * the file cannot be writeable by anyone other than its owner. + * + * In O'Reilly ("Learning the VI Editor", Fifth Ed., May 1992, page 106), + * it notes that System V release 3.2 and later has an option "[no]exrc". + * The behavior is that local .exrc files are read only if the exrc option + * is set. The default for the exrc option was off, so, by default, local + * .exrc files were not read. The problem this was intended to solve was + * that System V permitted users to give away files, so there's no possible + * ownership or writeability test to ensure that the file is safe. + * + * POSIX 1003.2-1992 standardized exrc as an option. It required the exrc + * option to be off by default, thus local .exrc files are not to be read + * by default. The Rationale noted (incorrectly) that this was a change + * to historic practice, but correctly noted that a default of off improves + * system security. POSIX also required that vi check the effective user + * ID instead of the real user ID, which is why we've switched from historic + * practice. + * + * We initialize the exrc variable to off. If it's turned on by the system + * or $HOME .exrc files, and the local .exrc file passes the ownership and + * writeability tests, then we read it. This breaks historic 4BSD practice, + * but it gives us a measure of security on systems where users can give away + * files. + */ +static enum rc +exrc_isok(sp, sbp, path, rootown, rootid) + SCR *sp; + struct stat *sbp; + char *path; + int rootown, rootid; +{ + uid_t euid; + char *emsg, buf[MAXPATHLEN]; + + /* Check for the file's existence. */ + if (stat(path, sbp)) + return (NOEXIST); + + /* Check ownership permissions. */ + euid = geteuid(); + if (!(rootown && sbp->st_uid == 0) && + !(rootid && euid == 0) && sbp->st_uid != euid) { + emsg = rootown ? + "not owned by you or root" : "not owned by you"; + goto denied; + } + + /* Check writeability. */ + if (sbp->st_mode & (S_IWGRP | S_IWOTH)) { + emsg = "writeable by a user other than the owner"; +denied: if (strchr(path, '/') == NULL && + getcwd(buf, sizeof(buf)) != NULL) + msgq(sp, M_ERR, + "%s/%s: not sourced: %s", buf, path, emsg); + else + msgq(sp, M_ERR, + "%s: not sourced: %s", path, emsg); + return (NOPERM); + } + return (OK); +} + +static void +obsolete(argv) + char *argv[]; +{ + size_t len; + char *p; + + /* + * Translate old style arguments into something getopt will like. + * Make sure it's not text space memory, because ex changes the + * strings. + * Change "+" into "-c$". + * Change "+<anything else>" into "-c<anything else>". + * Change "-" into "-s" + */ + while (*++argv) + if (argv[0][0] == '+') { + if (argv[0][1] == '\0') { + MALLOC_NOMSG(NULL, argv[0], char *, 4); + if (argv[0] == NULL) + err(1, NULL); + (void)strcpy(argv[0], "-c$"); + } else { + p = argv[0]; + len = strlen(argv[0]); + MALLOC_NOMSG(NULL, argv[0], char *, len + 2); + if (argv[0] == NULL) + err(1, NULL); + argv[0][0] = '-'; + argv[0][1] = 'c'; + (void)strcpy(argv[0] + 2, p + 1); + } + } else if (argv[0][0] == '-' && argv[0][1] == '\0') { + MALLOC_NOMSG(NULL, argv[0], char *, 3); + if (argv[0] == NULL) + err(1, NULL); + (void)strcpy(argv[0], "-s"); + } +} + +static void +usage(is_ex) + int is_ex; +{ +#define EX_USAGE \ + "ex [-eFRrsv] [-c command] [-t tag] [-w size] [files ...]" +#define VI_USAGE \ + "vi [-eFRrv] [-c command] [-t tag] [-w size] [files ...]" + + (void)fprintf(stderr, "usage: %s\n", is_ex ? EX_USAGE : VI_USAGE); + exit(1); +} diff --git a/usr.bin/vi/common/mark.c b/usr.bin/vi/common/mark.c new file mode 100644 index 0000000..15b0497 --- /dev/null +++ b/usr.bin/vi/common/mark.c @@ -0,0 +1,272 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)mark.c 8.19 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +static LMARK *mark_find __P((SCR *, EXF *, ARG_CHAR_T)); + +/* + * Marks are maintained in a key sorted doubly linked list. We can't + * use arrays because we have no idea how big an index key could be. + * The underlying assumption is that users don't have more than, say, + * 10 marks at any one time, so this will be is fast enough. + * + * Marks are fixed, and modifications to the line don't update the mark's + * position in the line. This can be hard. If you add text to the line, + * place a mark in that text, undo the addition and use ` to move to the + * mark, the location will have disappeared. It's tempting to try to adjust + * the mark with the changes in the line, but this is hard to do, especially + * if we've given the line to v_ntext.c:v_ntext() for editing. Historic vi + * would move to the first non-blank on the line when the mark location was + * past the end of the line. This can be complicated by deleting to a mark + * that has disappeared using the ` command. Historic vi vi treated this as + * a line-mode motion and deleted the line. This implementation complains to + * the user. + * + * In historic vi, marks returned if the operation was undone, unless the + * mark had been subsequently reset. Tricky. This is hard to start with, + * but in the presence of repeated undo it gets nasty. When a line is + * deleted, we delete (and log) any marks on that line. An undo will create + * the mark. Any mark creations are noted as to whether the user created + * it or if it was created by an undo. The former cannot be reset by another + * undo, but the latter may. + * + * All of these routines translate ABSMARK2 to ABSMARK1. Setting either of + * the absolute mark locations sets both, so that "m'" and "m`" work like + * they, ah, for lack of a better word, "should". + */ + +/* + * mark_init -- + * Set up the marks. + */ +int +mark_init(sp, ep) + SCR *sp; + EXF *ep; +{ + LMARK *lmp; + + /* + * Make sure the marks have been set up. If they + * haven't, do so, and create the absolute mark. + */ + MALLOC_RET(sp, lmp, LMARK *, sizeof(LMARK)); + lmp->lno = 1; + lmp->cno = 0; + lmp->name = ABSMARK1; + lmp->flags = 0; + LIST_INSERT_HEAD(&ep->marks, lmp, q); + return (0); +} + +/* + * mark_end -- + * Free up the marks. + */ +int +mark_end(sp, ep) + SCR *sp; + EXF *ep; +{ + LMARK *lmp; + + while ((lmp = ep->marks.lh_first) != NULL) { + LIST_REMOVE(lmp, q); + FREE(lmp, sizeof(LMARK)); + } + return (0); +} + +/* + * mark_get -- + * Get the location referenced by a mark. + */ +int +mark_get(sp, ep, key, mp) + SCR *sp; + EXF *ep; + ARG_CHAR_T key; + MARK *mp; +{ + LMARK *lmp; + size_t len; + + if (key == ABSMARK2) + key = ABSMARK1; + + lmp = mark_find(sp, ep, key); + if (lmp == NULL || lmp->name != key) { + msgq(sp, M_BERR, "Mark %s: not set", KEY_NAME(sp, key)); + return (1); + } + if (F_ISSET(lmp, MARK_DELETED)) { + msgq(sp, M_BERR, + "Mark %s: the line was deleted", KEY_NAME(sp, key)); + return (1); + } + if (file_gline(sp, ep, lmp->lno, &len) == NULL || + lmp->cno > len || lmp->cno == len && len != 0) { + msgq(sp, M_BERR, "Mark %s: cursor position no longer exists", + KEY_NAME(sp, key)); + return (1); + } + mp->lno = lmp->lno; + mp->cno = lmp->cno; + return (0); +} + +/* + * mark_set -- + * Set the location referenced by a mark. + */ +int +mark_set(sp, ep, key, value, userset) + SCR *sp; + EXF *ep; + ARG_CHAR_T key; + MARK *value; + int userset; +{ + LMARK *lmp, *lmt; + + if (key == ABSMARK2) + key = ABSMARK1; + + /* + * The rules are simple. If the user is setting a mark (if it's a + * new mark this is always true), it always happens. If not, it's + * an undo, and we set it if it's not already set or if it was set + * by a previous undo. + */ + lmp = mark_find(sp, ep, key); + if (lmp == NULL || lmp->name != key) { + MALLOC_RET(sp, lmt, LMARK *, sizeof(LMARK)); + if (lmp == NULL) { + LIST_INSERT_HEAD(&ep->marks, lmt, q); + } else + LIST_INSERT_AFTER(lmp, lmt, q); + lmp = lmt; + } else if (!userset && + !F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET)) + return (0); + + lmp->lno = value->lno; + lmp->cno = value->cno; + lmp->name = key; + lmp->flags = userset ? MARK_USERSET : 0; + return (0); +} + +/* + * mark_find -- + * Find the requested mark, or, the slot immediately before + * where it would go. + */ +static LMARK * +mark_find(sp, ep, key) + SCR *sp; + EXF *ep; + ARG_CHAR_T key; +{ + LMARK *lmp, *lastlmp; + + /* + * Return the requested mark or the slot immediately before + * where it should go. + */ + for (lastlmp = NULL, lmp = ep->marks.lh_first; + lmp != NULL; lastlmp = lmp, lmp = lmp->q.le_next) + if (lmp->name >= key) + return (lmp->name == key ? lmp : lastlmp); + return (lastlmp); +} + +/* + * mark_insdel -- + * Update the marks based on an insertion or deletion. + */ +void +mark_insdel(sp, ep, op, lno) + SCR *sp; + EXF *ep; + enum operation op; + recno_t lno; +{ + LMARK *lmp; + + switch (op) { + case LINE_APPEND: + return; + case LINE_DELETE: + for (lmp = ep->marks.lh_first; + lmp != NULL; lmp = lmp->q.le_next) + if (lmp->lno >= lno) + if (lmp->lno == lno) { + F_SET(lmp, MARK_DELETED); + (void)log_mark(sp, ep, lmp); + } else + --lmp->lno; + return; + case LINE_INSERT: + for (lmp = ep->marks.lh_first; + lmp != NULL; lmp = lmp->q.le_next) + if (lmp->lno >= lno) + ++lmp->lno; + return; + case LINE_RESET: + return; + } + /* NOTREACHED */ +} diff --git a/usr.bin/vi/common/mark.h b/usr.bin/vi/common/mark.h new file mode 100644 index 0000000..2c42e50 --- /dev/null +++ b/usr.bin/vi/common/mark.h @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mark.h 8.9 (Berkeley) 7/17/94 + */ + +/* + * The MARK and LMARK structures define positions in the file. There are + * two structures because the mark subroutines are the only places where + * anything cares about something other than line and column. + * + * Because of the different interfaces used by the db(3) package, curses, + * and users, the line number is 1 based and the column number is 0 based. + * Additionally, it is known that the out-of-band line number is less than + * any legal line number. The line number is of type recno_t, as that's + * the underlying type of the database. The column number is of type size_t, + * guaranteeing that we can malloc a line. + */ +struct _mark { +#define OOBLNO 0 /* Out-of-band line number. */ + recno_t lno; /* Line number. */ + size_t cno; /* Column number. */ +}; + +struct _lmark { + LIST_ENTRY(_lmark) q; /* Linked list of marks. */ + recno_t lno; /* Line number. */ + size_t cno; /* Column number. */ + CHAR_T name; /* Mark name. */ + +#define MARK_DELETED 0x01 /* Mark was deleted. */ +#define MARK_USERSET 0x02 /* User set this mark. */ + u_int8_t flags; +}; + +#define ABSMARK1 '\'' /* Absolute mark name. */ +#define ABSMARK2 '`' /* Absolute mark name. */ + +/* Mark routines. */ +int mark_end __P((SCR *, EXF *)); +int mark_get __P((SCR *, EXF *, ARG_CHAR_T, MARK *)); +int mark_init __P((SCR *, EXF *)); +void mark_insdel __P((SCR *, EXF *, enum operation, recno_t)); +int mark_set __P((SCR *, EXF *, ARG_CHAR_T, MARK *, int)); diff --git a/usr.bin/vi/common/mem.h b/usr.bin/vi/common/mem.h new file mode 100644 index 0000000..e61f7ff --- /dev/null +++ b/usr.bin/vi/common/mem.h @@ -0,0 +1,178 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mem.h 8.6 (Berkeley) 6/20/94 + */ + +/* Increase the size of a malloc'd buffer. Two versions, one that + * returns, one that jumps to an error label. + */ +#define BINC_GOTO(sp, lp, llen, nlen) { \ + if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \ + goto binc_err; \ +} +#define BINC_RET(sp, lp, llen, nlen) { \ + if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \ + return (1); \ +} + +/* + * Get some temporary space, preferably from the global temporary buffer, + * from a malloc'd buffer otherwise. Two versions, one that returns, one + * that jumps to an error label. + */ +#define GET_SPACE_GOTO(sp, bp, blen, nlen) { \ + GS *__gp = (sp)->gp; \ + if (F_ISSET(__gp, G_TMP_INUSE)) { \ + bp = NULL; \ + blen = 0; \ + BINC_GOTO(sp, bp, blen, nlen); \ + } else { \ + BINC_GOTO(sp, __gp->tmp_bp, __gp->tmp_blen, nlen); \ + bp = __gp->tmp_bp; \ + blen = __gp->tmp_blen; \ + F_SET(__gp, G_TMP_INUSE); \ + } \ +} +#define GET_SPACE_RET(sp, bp, blen, nlen) { \ + GS *__gp = (sp)->gp; \ + if (F_ISSET(__gp, G_TMP_INUSE)) { \ + bp = NULL; \ + blen = 0; \ + BINC_RET(sp, bp, blen, nlen); \ + } else { \ + BINC_RET(sp, __gp->tmp_bp, __gp->tmp_blen, nlen); \ + bp = __gp->tmp_bp; \ + blen = __gp->tmp_blen; \ + F_SET(__gp, G_TMP_INUSE); \ + } \ +} + +/* + * Add space to a GET_SPACE returned buffer. Two versions, one that + * returns, one that jumps to an error label. + */ +#define ADD_SPACE_GOTO(sp, bp, blen, nlen) { \ + GS *__gp = (sp)->gp; \ + if (bp == __gp->tmp_bp) { \ + F_CLR(__gp, G_TMP_INUSE); \ + BINC_GOTO(sp, __gp->tmp_bp, __gp->tmp_blen, nlen); \ + bp = __gp->tmp_bp; \ + blen = __gp->tmp_blen; \ + F_SET(__gp, G_TMP_INUSE); \ + } else \ + BINC_GOTO(sp, bp, blen, nlen); \ +} +#define ADD_SPACE_RET(sp, bp, blen, nlen) { \ + GS *__gp = (sp)->gp; \ + if (bp == __gp->tmp_bp) { \ + F_CLR(__gp, G_TMP_INUSE); \ + BINC_RET(sp, __gp->tmp_bp, __gp->tmp_blen, nlen); \ + bp = __gp->tmp_bp; \ + blen = __gp->tmp_blen; \ + F_SET(__gp, G_TMP_INUSE); \ + } else \ + BINC_RET(sp, bp, blen, nlen); \ +} + +/* Free memory, optionally making pointers unusable. */ +#ifdef DEBUG +#define FREE(p, sz) { \ + memset(p, 0xff, sz); \ + free(p); \ +} +#else +#define FREE(p, sz) free(p); +#endif + +/* Free a GET_SPACE returned buffer. */ +#define FREE_SPACE(sp, bp, blen) { \ + if (bp == sp->gp->tmp_bp) \ + F_CLR(sp->gp, G_TMP_INUSE); \ + else \ + FREE(bp, blen); \ +} + +/* + * Malloc a buffer, casting the return pointer. Various versions. + * + * !!! + * The cast should be unnecessary, malloc(3) and friends return void *'s, + * which is all we need. However, some systems that nvi needs to run on + * don't do it right yet, resulting in the compiler printing out roughly + * a million warnings. After awhile, it seemed easier to put the casts + * in instead of explaining it all the time. + */ +#define CALLOC_NOMSG(sp, p, cast, nmemb, size) { \ + p = (cast)calloc(nmemb, size); \ +} +#define CALLOC(sp, p, cast, nmemb, size) { \ + if ((p = (cast)calloc(nmemb, size)) == NULL) \ + msgq(sp, M_SYSERR, NULL); \ +} +#define CALLOC_RET(sp, p, cast, nmemb, size) { \ + if ((p = (cast)calloc(nmemb, size)) == NULL) { \ + msgq(sp, M_SYSERR, NULL); \ + return (1); \ + } \ +} +#define MALLOC_NOMSG(sp, p, cast, size) { \ + p = (cast)malloc(size); \ +} +#define MALLOC(sp, p, cast, size) { \ + if ((p = (cast)malloc(size)) == NULL) \ + msgq(sp, M_SYSERR, NULL); \ +} +#define MALLOC_RET(sp, p, cast, size) { \ + if ((p = (cast)malloc(size)) == NULL) { \ + msgq(sp, M_SYSERR, NULL); \ + return (1); \ + } \ +} +/* + * XXX + * Don't depend on realloc(NULL, size) working. + */ +#define REALLOC(sp, p, cast, size) { \ + if ((p = (cast)(p == NULL ? \ + malloc(size) : realloc(p, size))) == NULL) \ + msgq(sp, M_SYSERR, NULL); \ +} + +/* + * Versions of memmove(3) and memset(3) that use the size of the + * initial pointer to figure out how much memory to manipulate. + */ +#define MEMMOVE(p, t, len) memmove(p, t, (len) * sizeof(*(p))) +#define MEMSET(p, value, len) memset(p, value, (len) * sizeof(*(p))) + +int binc __P((SCR *, void *, size_t *, size_t)); diff --git a/usr.bin/vi/common/msg.c b/usr.bin/vi/common/msg.c new file mode 100644 index 0000000..f5fe595 --- /dev/null +++ b/usr.bin/vi/common/msg.c @@ -0,0 +1,427 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)msg.c 8.9 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +/* + * msgq -- + * Display a message. + */ +void +#ifdef __STDC__ +msgq(SCR *sp, enum msgtype mt, const char *fmt, ...) +#else +msgq(sp, mt, fmt, va_alist) + SCR *sp; + enum msgtype mt; + char *fmt; + va_dcl +#endif +{ + va_list ap; + size_t len; + char msgbuf[1024]; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + /* + * It's possible to enter msg when there's no screen to hold + * the message. If sp is NULL, ignore the special cases and + * just build the message, using __global_list. + */ + if (sp == NULL) + goto nullsp; + + switch (mt) { + case M_BERR: + if (!F_ISSET(sp, S_EXSILENT) && + F_ISSET(sp->gp, G_STDIN_TTY) && !O_ISSET(sp, O_VERBOSE)) { + F_SET(sp, S_BELLSCHED); + return; + } + mt = M_ERR; + break; + case M_VINFO: + if (!O_ISSET(sp, O_VERBOSE)) + return; + mt = M_INFO; + /* FALLTHROUGH */ + case M_INFO: + if (F_ISSET(sp, S_EXSILENT)) + return; + break; + case M_ERR: + case M_SYSERR: + break; + default: + abort(); + } + +nullsp: len = 0; + +#define EPREFIX "Error: " + if (mt == M_SYSERR) { + memmove(msgbuf, EPREFIX, sizeof(EPREFIX) - 1); + len += sizeof(EPREFIX) - 1; + } + + if (sp != NULL && sp->if_name != NULL) { + len += snprintf(msgbuf + len, sizeof(msgbuf) - len, + "%s, %d: ", sp->if_name, sp->if_lno); + if (len >= sizeof(msgbuf)) + goto err; + } + + if (fmt != NULL) { + len += vsnprintf(msgbuf + len, sizeof(msgbuf) - len, fmt, ap); + if (len >= sizeof(msgbuf)) + goto err; + } + + if (mt == M_SYSERR) { + len += snprintf(msgbuf + len, + sizeof(msgbuf) - len, ": %s", strerror(errno)); + if (len >= sizeof(msgbuf)) + goto err; + } + + /* + * If len >= the size, some characters were discarded. + * Ignore trailing nul. + */ +err: if (len >= sizeof(msgbuf)) + len = sizeof(msgbuf) - 1; + +#ifdef DEBUG + if (sp != NULL) + TRACE(sp, "%.*s\n", len, msgbuf); +#endif + msg_app(__global_list, sp, mt == M_ERR ? 1 : 0, msgbuf, len); +} + +/* + * msg_app -- + * Append a message into the queue. This can fail, but there's + * nothing we can do if it does. + */ +void +msg_app(gp, sp, inv_video, p, len) + GS *gp; + SCR *sp; + int inv_video; + char *p; + size_t len; +{ + static int reenter; /* STATIC: Re-entrancy check. */ + MSG *mp, *nmp; + + /* + * It's possible to reenter msg when it allocates space. + * We're probably dead anyway, but no reason to drop core. + */ + if (reenter) + return; + reenter = 1; + + /* + * We can be entered as the result of a signal arriving, trying + * to sync the file and failing. This shouldn't be a hot spot, + * block the signals. + */ + SIGBLOCK(gp); + + /* + * Find an empty structure, or allocate a new one. Use the + * screen structure if it exists, otherwise the global one. + */ + if (sp != NULL) { + if ((mp = sp->msgq.lh_first) == NULL) { + CALLOC(sp, mp, MSG *, 1, sizeof(MSG)); + if (mp == NULL) + goto ret; + LIST_INSERT_HEAD(&sp->msgq, mp, q); + goto store; + } + } else if ((mp = gp->msgq.lh_first) == NULL) { + CALLOC(sp, mp, MSG *, 1, sizeof(MSG)); + if (mp == NULL) + goto ret; + LIST_INSERT_HEAD(&gp->msgq, mp, q); + goto store; + } + while (!F_ISSET(mp, M_EMPTY) && mp->q.le_next != NULL) + mp = mp->q.le_next; + if (!F_ISSET(mp, M_EMPTY)) { + CALLOC(sp, nmp, MSG *, 1, sizeof(MSG)); + if (nmp == NULL) + goto ret; + LIST_INSERT_AFTER(mp, nmp, q); + mp = nmp; + } + + /* Get enough memory for the message. */ +store: if (len > mp->blen && binc(sp, &mp->mbuf, &mp->blen, len)) + goto ret; + + /* Store the message. */ + memmove(mp->mbuf, p, len); + mp->len = len; + mp->flags = inv_video ? M_INV_VIDEO : 0; + +ret: reenter = 0; + SIGUNBLOCK(gp); +} + +/* + * msg_rpt -- + * Report on the lines that changed. + * + * !!! + * Historic vi documentation (USD:15-8) claimed that "The editor will also + * always tell you when a change you make affects text which you cannot see." + * This isn't true -- edit a large file and do "100d|1". We don't implement + * this semantic as it would require that we track each line that changes + * during a command instead of just keeping count. + * + * Line counts weren't right in historic vi, either. For example, given the + * file: + * abc + * def + * the command 2d}, from the 'b' would report that two lines were deleted, + * not one. + */ +int +msg_rpt(sp, is_message) + SCR *sp; + int is_message; +{ + static char * const action[] = { + "added", "changed", "deleted", "joined", "moved", + "left shifted", "right shifted", "yanked", + NULL, + }; + recno_t total; + u_long rptval; + int first, cnt; + size_t blen, len; + char * const *ap; + char *bp, *p, number[40]; + + if (F_ISSET(sp, S_EXSILENT)) + return (0); + + if ((rptval = O_VAL(sp, O_REPORT)) == 0) + goto norpt; + + GET_SPACE_RET(sp, bp, blen, 512); + p = bp; + + total = 0; + for (ap = action, cnt = 0, first = 1; *ap != NULL; ++ap, ++cnt) + if (sp->rptlines[cnt] != 0) { + total += sp->rptlines[cnt]; + len = snprintf(number, sizeof(number), + "%s%lu lines %s", + first ? "" : "; ", sp->rptlines[cnt], *ap); + memmove(p, number, len); + p += len; + first = 0; + } + + /* + * If nothing to report, return. + * + * !!! + * And now, a special vi clone test. Historically, vi reported if + * the number of changed lines was > than the value, not >=. Which + * means that users can't report on single line changes, btw.) In + * any case, if it was a yank command, it was >=, not >. No lie. I + * got complaints, so we do it right. + */ + if (total > rptval || sp->rptlines[L_YANKED] >= rptval) { + *p = '\0'; + if (is_message) + msgq(sp, M_INFO, "%s", bp); + else + ex_printf(EXCOOKIE, "%s\n", bp); + } + + FREE_SPACE(sp, bp, blen); + + /* Clear after each report. */ +norpt: sp->rptlchange = OOBLNO; + memset(sp->rptlines, 0, sizeof(sp->rptlines)); + return (0); +} + +/* + * msg_status -- + * Report on the file's status. + */ +int +msg_status(sp, ep, lno, showlast) + SCR *sp; + EXF *ep; + recno_t lno; + int showlast; +{ + recno_t last; + char *mo, *nc, *nf, *pid, *ro, *ul; +#ifdef DEBUG + char pbuf[50]; + + (void)snprintf(pbuf, sizeof(pbuf), " (pid %u)", getpid()); + pid = pbuf; +#else + pid = ""; +#endif + /* + * See nvi/exf.c:file_init() for a description of how and + * when the read-only bit is set. + * + * !!! + * The historic display for "name changed" was "[Not edited]". + */ + if (F_ISSET(sp->frp, FR_NEWFILE)) { + F_CLR(sp->frp, FR_NEWFILE); + nf = "new file"; + mo = nc = ""; + } else { + nf = ""; + if (F_ISSET(sp->frp, FR_NAMECHANGE)) { + nc = "name changed"; + mo = F_ISSET(ep, F_MODIFIED) ? + ", modified" : ", unmodified"; + } else { + nc = ""; + mo = F_ISSET(ep, F_MODIFIED) ? + "modified" : "unmodified"; + } + } + ro = F_ISSET(sp->frp, FR_RDONLY) ? ", readonly" : ""; + ul = F_ISSET(sp->frp, FR_UNLOCKED) ? ", UNLOCKED" : ""; + if (showlast) { + if (file_lline(sp, ep, &last)) + return (1); + if (last >= 1) + msgq(sp, M_INFO, + "%s: %s%s%s%s%s: line %lu of %lu [%ld%%]%s", + sp->frp->name, nf, nc, mo, ul, ro, lno, + last, (lno * 100) / last, pid); + else + msgq(sp, M_INFO, "%s: %s%s%s%s%s: empty file%s", + sp->frp->name, nf, nc, mo, ul, ro, pid); + } else + msgq(sp, M_INFO, "%s: %s%s%s%s%s: line %lu%s", + sp->frp->name, nf, nc, mo, ul, ro, lno, pid); + return (0); +} + +#ifdef MSG_CATALOG +/* + * get_msg -- + * Return a format based on a message number. + */ +char * +get_msg(sp, msgno) + SCR *sp; + char *s_msgno; +{ + DBT data, key; + GS *gp; + recno_t msgno; + char *msg, *p; + + gp = sp == NULL ? __global_list : sp->gp; + if (gp->msgdb == NULL) { + p = sp == NULL ? _PATH_MSGDEF : O_STR(sp, O_CATALOG); + if ((gp->msgdb = dbopen(p, + O_NONBLOCK | O_RDONLY, 444, DB_RECNO, NULL)) == NULL) { + if ((fmt = malloc(256)) == NULL) + return (""); + (void)snprintf(fmt, + "unable to open %s: %s", p, strerror(errno)); + return (fmt); + } + } + msgno = atoi(s_msgno); + key.data = &msgno; + key.size = sizeof(recno_t); + switch (gp->msgdb->get(gp->msgdb, &key, &data, 0)) { + case 0: + return (data.data); + case 1: + p = "no catalog record %ls"; + break; + case -1: + p = "catalog record %s: %s"; + break; + } + if ((fmt = malloc(256)) == NULL) + return (""); + (void)snprintf(fmt, p, msgno, strerror(errno)); + return (fmt); +} +#endif diff --git a/usr.bin/vi/common/msg.h b/usr.bin/vi/common/msg.h new file mode 100644 index 0000000..fc6e365 --- /dev/null +++ b/usr.bin/vi/common/msg.h @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)msg.h 8.13 (Berkeley) 8/8/94 + */ + +/* + * Message types. + * + * !!! + * In historical vi, O_VERBOSE didn't exist, and O_TERSE made the error + * messages shorter. In this implementation, O_TERSE has no effect and + * O_VERBOSE results in informational displays about common errors for + * naive users. + * + * M_BERR Error: M_ERR if O_VERBOSE, else bell. + * M_ERR Error: Display in inverse video. + * M_INFO Info: Display in normal video. + * M_SYSERR Error: M_ERR, using strerror(3) message. + * M_VINFO Info: M_INFO if O_VERBOSE, else ignore. + */ +enum msgtype { M_BERR, M_ERR, M_INFO, M_SYSERR, M_VINFO }; + +typedef struct _msgh MSGH; /* MESG list head structure. */ +LIST_HEAD(_msgh, _msg); + +struct _msg { + LIST_ENTRY(_msg) q; /* Linked list of messages. */ + char *mbuf; /* Message buffer. */ + size_t blen; /* Message buffer length. */ + size_t len; /* Message length. */ + +#define M_EMPTY 0x01 /* No message. */ +#define M_INV_VIDEO 0x02 /* Inverse video. */ + u_int8_t flags; +}; + +/* + * Define MSG_CATALOG for the Makefile compile command + * line to enable message catalogs. + */ +#ifdef MSG_CATALOG +#define M(number, fmt) number +char *get_msg __P((SCR *, char *)); +#else +#define M(number, fmt) fmt +#endif + +/* Messages. */ +void msg_app __P((GS *, SCR *, int, char *, size_t)); +int msg_rpt __P((SCR *, int)); +int msg_status __P((SCR *, EXF *, recno_t, int)); +void msgq __P((SCR *, enum msgtype, const char *, ...)); diff --git a/usr.bin/vi/common/options.awk b/usr.bin/vi/common/options.awk new file mode 100644 index 0000000..a6755d9 --- /dev/null +++ b/usr.bin/vi/common/options.awk @@ -0,0 +1,9 @@ +# @(#)options.awk 8.1 (Berkeley) 4/17/94 + +/^\/\* O_[0-9A-Z_]*/ { + printf("#define %s %d\n", $2, cnt++); + next; +} +END { + printf("#define O_OPTIONCOUNT %d\n", cnt); +} diff --git a/usr.bin/vi/common/options.c b/usr.bin/vi/common/options.c new file mode 100644 index 0000000..1c8496d --- /dev/null +++ b/usr.bin/vi/common/options.c @@ -0,0 +1,890 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)options.c 8.64 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> +#include <pathnames.h> + +#include "vi.h" +#include "excmd.h" + +static int opts_abbcmp __P((const void *, const void *)); +static int opts_cmp __P((const void *, const void *)); +static OPTLIST const *opts_prefix __P((char *)); +static int opts_print __P((SCR *, OPTLIST const *)); + +/* + * O'Reilly noted options and abbreviations are from "Learning the VI Editor", + * Fifth Edition, May 1992. There's no way of knowing what systems they are + * actually from. + * + * HPUX noted options and abbreviations are from "The Ultimate Guide to the + * VI and EX Text Editors", 1990. + */ +static OPTLIST const optlist[] = { +/* O_ALTWERASE 4.4BSD */ + {"altwerase", f_altwerase, OPT_0BOOL, 0}, +/* O_AUTOINDENT 4BSD */ + {"autoindent", NULL, OPT_0BOOL, 0}, +/* O_AUTOPRINT 4BSD */ + {"autoprint", NULL, OPT_1BOOL, 0}, +/* O_AUTOWRITE 4BSD */ + {"autowrite", NULL, OPT_0BOOL, 0}, +/* O_BEAUTIFY 4BSD */ + {"beautify", NULL, OPT_0BOOL, 0}, +/* O_CDPATH 4.4BSD */ + {"cdpath", f_cdpath, OPT_STR, 0}, +/* O_COLUMNS 4.4BSD */ + {"columns", f_columns, OPT_NUM, OPT_NOSAVE}, +/* O_COMMENT 4.4BSD */ + {"comment", NULL, OPT_0BOOL, 0}, +/* O_DIGRAPH XXX: Elvis */ + {"digraph", NULL, OPT_0BOOL, 0}, +/* O_DIRECTORY 4BSD */ + {"directory", NULL, OPT_STR, 0}, +/* O_EDCOMPATIBLE 4BSD */ + {"edcompatible",NULL, OPT_0BOOL, 0}, +/* O_ERRORBELLS 4BSD */ + {"errorbells", NULL, OPT_0BOOL, 0}, +/* O_EXRC System V (undocumented) */ + {"exrc", NULL, OPT_0BOOL, 0}, +/* O_EXTENDED 4.4BSD */ + {"extended", NULL, OPT_0BOOL, 0}, +/* O_FLASH HPUX */ + {"flash", NULL, OPT_1BOOL, 0}, +/* O_HARDTABS 4BSD */ + {"hardtabs", NULL, OPT_NUM, 0}, +/* O_IGNORECASE 4BSD */ + {"ignorecase", NULL, OPT_0BOOL, 0}, +/* O_KEYTIME 4.4BSD */ + {"keytime", NULL, OPT_NUM, 0}, +/* O_LEFTRIGHT 4.4BSD */ + {"leftright", f_leftright, OPT_0BOOL, 0}, +/* O_LINES 4.4BSD */ + {"lines", f_lines, OPT_NUM, OPT_NOSAVE}, +/* O_LISP 4BSD */ +/* + * XXX + * When the lisp option is implemented, delete + * the OPT_NOSAVE flag, so that :mkexrc dumps it. + */ + {"lisp", f_lisp, OPT_0BOOL, OPT_NOSAVE}, +/* O_LIST 4BSD */ + {"list", f_list, OPT_0BOOL, 0}, +/* O_MAGIC 4BSD */ + {"magic", NULL, OPT_1BOOL, 0}, +/* O_MATCHTIME 4.4BSD */ + {"matchtime", NULL, OPT_NUM, 0}, +/* O_MESG 4BSD */ + {"mesg", f_mesg, OPT_1BOOL, 0}, +/* O_META 4.4BSD */ + {"meta", NULL, OPT_STR, 0}, +/* O_MODELINE 4BSD */ + {"modeline", f_modeline, OPT_0BOOL, 0}, +/* O_NUMBER 4BSD */ + {"number", f_number, OPT_0BOOL, 0}, +/* O_OCTAL 4.4BSD */ + {"octal", f_octal, OPT_0BOOL, 0}, +/* O_OPEN 4BSD */ + {"open", NULL, OPT_1BOOL, 0}, +/* O_OPTIMIZE 4BSD */ + {"optimize", NULL, OPT_1BOOL, 0}, +/* O_PARAGRAPHS 4BSD */ + {"paragraphs", f_paragraph, OPT_STR, 0}, +/* O_PROMPT 4BSD */ + {"prompt", NULL, OPT_1BOOL, 0}, +/* O_READONLY 4BSD (undocumented) */ + {"readonly", f_readonly, OPT_0BOOL, 0}, +/* O_RECDIR 4.4BSD */ + {"recdir", NULL, OPT_STR, 0}, +/* O_REDRAW 4BSD */ + {"redraw", NULL, OPT_0BOOL, 0}, +/* O_REMAP 4BSD */ + {"remap", NULL, OPT_1BOOL, 0}, +/* O_REPORT 4BSD */ + {"report", NULL, OPT_NUM, OPT_NOSTR}, +/* O_RULER 4.4BSD */ + {"ruler", NULL, OPT_0BOOL, 0}, +/* O_SCROLL 4BSD */ + {"scroll", NULL, OPT_NUM, 0}, +/* O_SECTIONS 4BSD */ + {"sections", f_section, OPT_STR, 0}, +/* O_SHELL 4BSD */ + {"shell", NULL, OPT_STR, 0}, +/* O_SHIFTWIDTH 4BSD */ + {"shiftwidth", f_shiftwidth, OPT_NUM, 0}, +/* O_SHOWDIRTY 4.4BSD */ + {"showdirty", NULL, OPT_0BOOL, 0}, +/* O_SHOWMATCH 4BSD */ + {"showmatch", NULL, OPT_0BOOL, 0}, +/* O_SHOWMODE 4.4BSD */ + {"showmode", NULL, OPT_0BOOL, 0}, +/* O_SIDESCROLL 4.4BSD */ + {"sidescroll", NULL, OPT_NUM, 0}, +/* O_SLOWOPEN 4BSD */ + {"slowopen", NULL, OPT_0BOOL, 0}, +/* O_SOURCEANY 4BSD (undocumented) */ + {"sourceany", f_sourceany, OPT_0BOOL, 0}, +/* O_TABSTOP 4BSD */ + {"tabstop", f_tabstop, OPT_NUM, 0}, +/* O_TAGLENGTH 4BSD */ + {"taglength", NULL, OPT_NUM, OPT_NOSTR}, +/* O_TAGS 4BSD */ + {"tags", f_tags, OPT_STR, 0}, +/* O_TERM 4BSD */ + {"term", f_term, OPT_STR, OPT_NOSAVE}, +/* O_TERSE 4BSD */ + {"terse", NULL, OPT_0BOOL, 0}, +/* O_TILDEOP 4.4BSD */ + {"tildeop", NULL, OPT_0BOOL, 0}, +/* O_TIMEOUT 4BSD (undocumented) */ + {"timeout", NULL, OPT_1BOOL, 0}, +/* O_TTYWERASE 4.4BSD */ + {"ttywerase", f_ttywerase, OPT_0BOOL, 0}, +/* O_VERBOSE 4.4BSD */ + {"verbose", NULL, OPT_0BOOL, 0}, +/* O_W1200 4BSD */ + {"w1200", f_w1200, OPT_NUM, OPT_NEVER|OPT_NOSAVE}, +/* O_W300 4BSD */ + {"w300", f_w300, OPT_NUM, OPT_NEVER|OPT_NOSAVE}, +/* O_W9600 4BSD */ + {"w9600", f_w9600, OPT_NUM, OPT_NEVER|OPT_NOSAVE}, +/* O_WARN 4BSD */ + {"warn", NULL, OPT_1BOOL, 0}, +/* O_WINDOW 4BSD */ + {"window", f_window, OPT_NUM, 0}, +/* O_WRAPMARGIN 4BSD */ + {"wrapmargin", NULL, OPT_NUM, OPT_NOSTR}, +/* O_WRAPSCAN 4BSD */ + {"wrapscan", NULL, OPT_1BOOL, 0}, +/* O_WRITEANY 4BSD */ + {"writeany", NULL, OPT_0BOOL, 0}, + {NULL}, +}; + +typedef struct abbrev { + char *name; + int offset; +} OABBREV; + +static OABBREV const abbrev[] = { + {"ai", O_AUTOINDENT}, /* 4BSD */ + {"ap", O_AUTOPRINT}, /* 4BSD */ + {"aw", O_AUTOWRITE}, /* 4BSD */ + {"bf", O_BEAUTIFY}, /* 4BSD */ + {"co", O_COLUMNS}, /* 4.4BSD */ + {"dir", O_DIRECTORY}, /* 4BSD */ + {"eb", O_ERRORBELLS}, /* 4BSD */ + {"ed", O_EDCOMPATIBLE}, /* 4BSD */ + {"ex", O_EXRC}, /* System V (undocumented) */ + {"ht", O_HARDTABS}, /* 4BSD */ + {"ic", O_IGNORECASE}, /* 4BSD */ + {"li", O_LINES}, /* 4.4BSD */ + {"modelines", O_MODELINE}, /* HPUX */ + {"nu", O_NUMBER}, /* 4BSD */ + {"opt", O_OPTIMIZE}, /* 4BSD */ + {"para", O_PARAGRAPHS}, /* 4BSD */ + {"re", O_REDRAW}, /* O'Reilly */ + {"ro", O_READONLY}, /* 4BSD (undocumented) */ + {"scr", O_SCROLL}, /* 4BSD (undocumented) */ + {"sect", O_SECTIONS}, /* O'Reilly */ + {"sh", O_SHELL}, /* 4BSD */ + {"slow", O_SLOWOPEN}, /* 4BSD */ + {"sm", O_SHOWMATCH}, /* 4BSD */ + {"sw", O_SHIFTWIDTH}, /* 4BSD */ + {"tag", O_TAGS}, /* 4BSD (undocumented) */ + {"tl", O_TAGLENGTH}, /* 4BSD */ + {"to", O_TIMEOUT}, /* 4BSD (undocumented) */ + {"ts", O_TABSTOP}, /* 4BSD */ + {"tty", O_TERM}, /* 4BSD (undocumented) */ + {"ttytype", O_TERM}, /* 4BSD (undocumented) */ + {"w", O_WINDOW}, /* O'Reilly */ + {"wa", O_WRITEANY}, /* 4BSD */ + {"wi", O_WINDOW}, /* 4BSD (undocumented) */ + {"wm", O_WRAPMARGIN}, /* 4BSD */ + {"ws", O_WRAPSCAN}, /* 4BSD */ + {NULL}, +}; + +/* + * opts_init -- + * Initialize some of the options. Since the user isn't really + * "setting" these variables, don't set their OPT_SET bits. + */ +int +opts_init(sp) + SCR *sp; +{ + ARGS *argv[2], a, b; + OPTLIST const *op; + u_long v; + int cnt; + char *s, b1[1024]; + + a.bp = b1; + a.len = 0; + b.bp = NULL; + b.len = 0; + argv[0] = &a; + argv[1] = &b; + +#define SET_DEF(opt, str) { \ + if (str != b1) /* GCC puts strings in text-space. */ \ + (void)strcpy(b1, str); \ + a.len = strlen(b1); \ + if (opts_set(sp, NULL, argv)) { \ + msgq(sp, M_ERR, \ + "Unable to set default %s option", optlist[opt]); \ + return (1); \ + } \ + F_CLR(&sp->opts[opt], OPT_SET); \ +} + /* Set default values. */ + for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt) + if (op->type == OPT_0BOOL) + O_CLR(sp, cnt); + else if (op->type == OPT_1BOOL) + O_SET(sp, cnt); + + (void)snprintf(b1, sizeof(b1), "cdpath=%s", + (s = getenv("CDPATH")) == NULL ? ":" : s); + SET_DEF(O_CDPATH, b1); + + /* + * !!! + * Vi historically stored temporary files in /var/tmp. We store them + * in /tmp by default, hoping it's a memory based file system. There + * are two ways to change this -- the user can set either the directory + * option or the TMPDIR environmental variable. + */ + (void)snprintf(b1, sizeof(b1), "directory=%s", + (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s); + SET_DEF(O_DIRECTORY, b1); + SET_DEF(O_KEYTIME, "keytime=6"); + SET_DEF(O_MATCHTIME, "matchtime=7"); + SET_DEF(O_META, "meta=~{[*?$`'\"\\"); + SET_DEF(O_REPORT, "report=5"); + SET_DEF(O_PARAGRAPHS, "paragraphs=IPLPPPQPP LIpplpipbp"); + (void)snprintf(b1, sizeof(b1), "recdir=%s", _PATH_PRESERVE); + SET_DEF(O_RECDIR, b1); + SET_DEF(O_SECTIONS, "sections=NHSHH HUnhsh"); + (void)snprintf(b1, sizeof(b1), "shell=%s", + (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s); + SET_DEF(O_SHELL, b1); + SET_DEF(O_SHIFTWIDTH, "shiftwidth=8"); + SET_DEF(O_SIDESCROLL, "sidescroll=16"); + SET_DEF(O_TABSTOP, "tabstop=8"); + (void)snprintf(b1, sizeof(b1), "tags=%s", _PATH_TAGS); + SET_DEF(O_TAGS, b1); + (void)snprintf(b1, sizeof(b1), "term=%s", + (s = getenv("TERM")) == NULL ? "unknown" : s); + SET_DEF(O_TERM, b1); + + /* + * XXX + * Initialize ^D, ^U scrolling value here, after TERM. (We didn't + * have the options information when the screen was initialized.) + * Initializing term should have created a LINES/COLUMNS value. + */ + sp->defscroll = O_VAL(sp, O_LINES) / 2; + (void)snprintf(b1, sizeof(b1), "scroll=%ld", sp->defscroll); + SET_DEF(O_SCROLL, b1); + + /* + * The default window option values are: + * 8 if baud rate <= 600 + * 16 if baud rate <= 1200 + * LINES - 1 if baud rate > 1200 + */ + v = baud_from_bval(sp); + if (v <= 600) + v = 8; + else if (v <= 1200) + v = 16; + else + v = O_VAL(sp, O_LINES) - 1; + (void)snprintf(b1, sizeof(b1), "window=%lu", v); + SET_DEF(O_WINDOW, b1); + + SET_DEF(O_WRAPMARGIN, "wrapmargin=0"); + + /* + * By default, the historic vi always displayed information + * about two options, redraw and term. Term seems sufficient. + */ + F_SET(&sp->opts[O_TERM], OPT_SET); + return (0); +} + +/* + * opts_set -- + * Change the values of one or more options. + */ +int +opts_set(sp, usage, argv) + SCR *sp; + char *usage; + ARGS *argv[]; +{ + enum optdisp disp; + OABBREV atmp, *ap; + OPTLIST const *op; + OPTLIST otmp; + OPTION *spo; + u_long value, turnoff; + int ch, equals, offset, qmark, rval; + char *endp, *name, *p, *sep; + + disp = NO_DISPLAY; + for (rval = 0; argv[0]->len != 0; ++argv) { + /* + * The historic vi dumped the options for each occurrence of + * "all" in the set list. Puhleeze. + */ + if (!strcmp(argv[0]->bp, "all")) { + disp = ALL_DISPLAY; + continue; + } + + /* Find equals sign or question mark. */ + for (sep = NULL, equals = qmark = 0, + p = name = argv[0]->bp; (ch = *p) != '\0'; ++p) + if (ch == '=' || ch == '?') { + if (p == name) { + if (usage != NULL) + msgq(sp, + M_ERR, "Usage: %s", usage); + return (1); + } + sep = p; + if (ch == '=') + equals = 1; + else + qmark = 1; + break; + } + + turnoff = 0; + op = NULL; + if (sep != NULL) + *sep++ = '\0'; + + /* Check list of abbreviations. */ + atmp.name = name; + if ((ap = bsearch(&atmp, abbrev, + sizeof(abbrev) / sizeof(OABBREV) - 1, + sizeof(OABBREV), opts_abbcmp)) != NULL) { + op = optlist + ap->offset; + goto found; + } + + /* Check list of options. */ + otmp.name = name; + if ((op = bsearch(&otmp, optlist, + sizeof(optlist) / sizeof(OPTLIST) - 1, + sizeof(OPTLIST), opts_cmp)) != NULL) + goto found; + + /* Try the name without any leading "no". */ + if (name[0] == 'n' && name[1] == 'o') { + turnoff = 1; + name += 2; + } else + goto prefix; + + /* Check list of abbreviations. */ + atmp.name = name; + if ((ap = bsearch(&atmp, abbrev, + sizeof(abbrev) / sizeof(OABBREV) - 1, + sizeof(OABBREV), opts_abbcmp)) != NULL) { + op = optlist + ap->offset; + goto found; + } + + /* Check list of options. */ + otmp.name = name; + if ((op = bsearch(&otmp, optlist, + sizeof(optlist) / sizeof(OPTLIST) - 1, + sizeof(OPTLIST), opts_cmp)) != NULL) + goto found; + + /* Check for prefix match. */ +prefix: op = opts_prefix(name); + +found: if (op == NULL) { + msgq(sp, M_ERR, + "no %s option: 'set all' gives all option values", + name); + continue; + } + + /* Find current option values. */ + offset = op - optlist; + spo = sp->opts + offset; + + /* + * !!! + * Historically, the question mark could be a separate + * argument. + */ + if (!equals && !qmark && + argv[1]->len == 1 && argv[1]->bp[0] == '?') { + ++argv; + qmark = 1; + } + + /* Set name, value. */ + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + if (equals) { + msgq(sp, M_ERR, + "set: [no]%s option doesn't take a value", + name); + break; + } + if (qmark) { + if (!disp) + disp = SELECT_DISPLAY; + F_SET(spo, OPT_SELECTED); + break; + } + if (op->func != NULL) { + if (op->func(sp, spo, NULL, turnoff)) { + rval = 1; + break; + } + } else if (turnoff) + O_CLR(sp, offset); + else + O_SET(sp, offset); + goto change; + case OPT_NUM: + /* + * !!! + * Extension to historic vi. If the OPT_NOSTR flag is + * set, a numeric option may be turned off by using a + * "no" prefix, e.g. "nowrapmargin". (We assume that + * setting the value to 0 turns a numeric option off.) + */ + if (turnoff) { + if (F_ISSET(op, OPT_NOSTR)) { + value = 0; + goto nostr; + } + msgq(sp, M_ERR, + "set: %s option isn't a boolean", name); + break; + } + if (qmark || !equals) { + if (!disp) + disp = SELECT_DISPLAY; + F_SET(spo, OPT_SELECTED); + break; + } + value = strtol(sep, &endp, 10); + if (*endp && !isblank(*endp)) { + msgq(sp, M_ERR, + "set %s: illegal number %s", name, sep); + break; + } +nostr: if (op->func != NULL) { + if (op->func(sp, spo, sep, value)) { + rval = 1; + break; + } + } else + O_VAL(sp, offset) = value; + goto change; + case OPT_STR: + if (turnoff) { + msgq(sp, M_ERR, + "set: %s option isn't a boolean", name); + break; + } + if (qmark || !equals) { + if (!disp) + disp = SELECT_DISPLAY; + F_SET(spo, OPT_SELECTED); + break; + } + if (op->func != NULL) { + if (op->func(sp, spo, sep, (u_long)0)) { + rval = 1; + break; + } + } else { + if (F_ISSET(&sp->opts[offset], OPT_ALLOCATED)) + free(O_STR(sp, offset)); + if ((O_STR(sp, offset) = strdup(sep)) == NULL) { + msgq(sp, M_SYSERR, NULL); + rval = 1; + break; + } else + F_SET(&sp->opts[offset], OPT_ALLOCATED); + } +change: if (sp->s_optchange != NULL) + (void)sp->s_optchange(sp, offset); + F_SET(&sp->opts[offset], OPT_SET); + break; + default: + abort(); + } + } + if (disp != NO_DISPLAY) + opts_dump(sp, disp); + return (rval); +} + +/* + * opts_dump -- + * List the current values of selected options. + */ +void +opts_dump(sp, type) + SCR *sp; + enum optdisp type; +{ + OPTLIST const *op; + int base, b_num, cnt, col, colwidth, curlen, s_num; + int numcols, numrows, row; + int b_op[O_OPTIONCOUNT], s_op[O_OPTIONCOUNT]; + char nbuf[20]; + + /* + * XXX + * It's possible to get here by putting "set option" in the + * .exrc file. I can't think of a clean way to layer this, + * or a reasonable check to make, so we block it here. + */ + if (sp->stdfp == NULL) { + msgq(sp, M_ERR, + "Option display requires that the screen be initialized"); + return; + } + + /* + * Options are output in two groups -- those that fit in a column and + * those that don't. Output is done on 6 character "tab" boundaries + * for no particular reason. (Since we don't output tab characters, + * we can ignore the terminal's tab settings.) Ignore the user's tab + * setting because we have no idea how reasonable it is. + * + * Find a column width we can live with. + */ + for (cnt = 6; cnt > 1; --cnt) { + colwidth = (sp->cols - 1) / cnt & ~(STANDARD_TAB - 1); + if (colwidth >= 10) { + colwidth = + (colwidth + STANDARD_TAB) & ~(STANDARD_TAB - 1); + break; + } + colwidth = 0; + } + + /* + * Get the set of options to list, entering them into + * the column list or the overflow list. + */ + for (b_num = s_num = 0, op = optlist; op->name != NULL; ++op) { + cnt = op - optlist; + + /* If OPT_NEVER set, it's never displayed. */ + if (F_ISSET(op, OPT_NEVER)) + continue; + + switch (type) { + case ALL_DISPLAY: /* Display all. */ + break; + case CHANGED_DISPLAY: /* Display changed. */ + if (!F_ISSET(&sp->opts[cnt], OPT_SET)) + continue; + break; + case SELECT_DISPLAY: /* Display selected. */ + if (!F_ISSET(&sp->opts[cnt], OPT_SELECTED)) + continue; + break; + default: + case NO_DISPLAY: + abort(); + /* NOTREACHED */ + } + F_CLR(&sp->opts[cnt], OPT_SELECTED); + + curlen = strlen(op->name); + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + if (!O_ISSET(sp, cnt)) + curlen += 2; + break; + case OPT_NUM: + (void)snprintf(nbuf, + sizeof(nbuf), "%ld", O_VAL(sp, cnt)); + curlen += strlen(nbuf); + break; + case OPT_STR: + curlen += strlen(O_STR(sp, cnt)) + 3; + break; + } + /* Offset by two so there's a gap. */ + if (curlen < colwidth - 2) + s_op[s_num++] = cnt; + else + b_op[b_num++] = cnt; + } + + if (s_num > 0) { + /* Figure out the number of columns. */ + numcols = (sp->cols - 1) / colwidth; + if (s_num > numcols) { + numrows = s_num / numcols; + if (s_num % numcols) + ++numrows; + } else + numrows = 1; + + /* Display the options in sorted order. */ + for (row = 0; row < numrows;) { + for (base = row, col = 0; col < numcols; ++col) { + cnt = opts_print(sp, &optlist[s_op[base]]); + if ((base += numrows) >= s_num) + break; + (void)ex_printf(EXCOOKIE, + "%*s", (int)(colwidth - cnt), ""); + } + if (++row < numrows || b_num) + (void)ex_printf(EXCOOKIE, "\n"); + } + } + + for (row = 0; row < b_num;) { + (void)opts_print(sp, &optlist[b_op[row]]); + if (++row < b_num) + (void)ex_printf(EXCOOKIE, "\n"); + } + (void)ex_printf(EXCOOKIE, "\n"); +} + +/* + * opts_print -- + * Print out an option. + */ +static int +opts_print(sp, op) + SCR *sp; + OPTLIST const *op; +{ + int curlen, offset; + + curlen = 0; + offset = op - optlist; + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + curlen += ex_printf(EXCOOKIE, + "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name); + break; + case OPT_NUM: + curlen += ex_printf(EXCOOKIE, + "%s=%ld", op->name, O_VAL(sp, offset)); + break; + case OPT_STR: + curlen += ex_printf(EXCOOKIE, + "%s=\"%s\"", op->name, O_STR(sp, offset)); + break; + } + return (curlen); +} + +/* + * opts_save -- + * Write the current configuration to a file. + */ +int +opts_save(sp, fp) + SCR *sp; + FILE *fp; +{ + OPTLIST const *op; + int ch, cnt; + char *p; + + for (op = optlist; op->name != NULL; ++op) { + if (F_ISSET(op, OPT_NOSAVE)) + continue; + cnt = op - optlist; + switch (op->type) { + case OPT_0BOOL: + case OPT_1BOOL: + if (O_ISSET(sp, cnt)) + (void)fprintf(fp, "set %s\n", op->name); + else + (void)fprintf(fp, "set no%s\n", op->name); + break; + case OPT_NUM: + (void)fprintf(fp, + "set %s=%-3d\n", op->name, O_VAL(sp, cnt)); + break; + case OPT_STR: + (void)fprintf(fp, "set "); + for (p = op->name; (ch = *p) != '\0'; ++p) { + if (isblank(ch) || ch == '\\') + (void)putc('\\', fp); + (void)putc(ch, fp); + } + (void)putc('=', fp); + for (p = O_STR(sp, cnt); (ch = *p) != '\0'; ++p) { + if (isblank(ch) || ch == '\\') + (void)putc('\\', fp); + (void)putc(ch, fp); + } + (void)putc('\n', fp); + break; + } + if (ferror(fp)) { + msgq(sp, M_ERR, "I/O error: %s", strerror(errno)); + return (1); + } + } + return (0); +} + +/* + * opts_prefix -- + * Check to see if the name is the prefix of one (and only one) + * option. If so, return the option. + */ +static OPTLIST const * +opts_prefix(name) + char *name; +{ + OPTLIST const *op, *save_op; + size_t len; + + save_op = NULL; + len = strlen(name); + for (op = optlist; op->name != NULL; ++op) { + if (op->name[0] < name[0]) + continue; + if (op->name[0] > name[0]) + break; + if (!memcmp(op->name, name, len)) { + if (save_op != NULL) + return (NULL); + save_op = op; + } + } + return (save_op); +} + +static int +opts_abbcmp(a, b) + const void *a, *b; +{ + return(strcmp(((OABBREV *)a)->name, ((OABBREV *)b)->name)); +} + +static int +opts_cmp(a, b) + const void *a, *b; +{ + return(strcmp(((OPTLIST *)a)->name, ((OPTLIST *)b)->name)); +} + +/* + * opts_free -- + * Free all option strings + */ +void +opts_free(sp) + SCR *sp; +{ + int cnt; + char *p; + + for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt) + if (F_ISSET(&sp->opts[cnt], OPT_ALLOCATED)) { + p = O_STR(sp, cnt); + FREE(p, strlen(p) + 1); + } +} + +/* + * opts_copy -- + * Copy a screen's OPTION array. + */ +int +opts_copy(orig, sp) + SCR *orig, *sp; +{ + OPTION *op; + int cnt; + + /* Copy most everything without change. */ + memmove(sp->opts, orig->opts, sizeof(orig->opts)); + + /* + * Allocate copies of the strings -- keep trying to reallocate + * after ENOMEM failure, otherwise end up with more than one + * screen referencing the original memory. + */ + for (op = sp->opts, cnt = 0; cnt < O_OPTIONCOUNT; ++cnt, ++op) + if (F_ISSET(&sp->opts[cnt], OPT_ALLOCATED) && + (O_STR(sp, cnt) = strdup(O_STR(sp, cnt))) == NULL) { + msgq(orig, M_SYSERR, NULL); + return (1); + } + return (0); +} diff --git a/usr.bin/vi/common/options.h.stub b/usr.bin/vi/common/options.h.stub new file mode 100644 index 0000000..0e2051d --- /dev/null +++ b/usr.bin/vi/common/options.h.stub @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)options.h.stub 8.22 (Berkeley) 8/8/94 + */ + +struct _option { + union { + u_long val; /* Value or boolean. */ + char *str; /* String. */ + } o_u; + size_t len; /* String length. */ + +#define OPT_ALLOCATED 0x01 /* Allocated space. */ +#define OPT_SELECTED 0x02 /* Selected for display. */ +#define OPT_SET 0x04 /* Set (display for the user). */ + u_char flags; +}; + +struct _optlist { + char *name; /* Name. */ + /* Change function. */ + int (*func) __P((SCR *, OPTION *, char *, u_long)); + /* Type of object. */ + enum { OPT_0BOOL, OPT_1BOOL, OPT_NUM, OPT_STR } type; + +#define OPT_NEVER 0x01 /* Never display the option. */ +#define OPT_NOSAVE 0x02 /* Mkexrc command doesn't save. */ +#define OPT_NOSTR 0x04 /* String that takes a "no". */ + u_int flags; +}; + +/* Clear, set, test boolean options. */ +#define O_SET(sp, o) (sp)->opts[(o)].o_u.val = 1 +#define O_CLR(sp, o) (sp)->opts[(o)].o_u.val = 0 +#define O_ISSET(sp, o) ((sp)->opts[(o)].o_u.val) + +/* Get option values. */ +#define O_LEN(sp, o) (sp)->opts[(o)].len +#define O_STR(sp, o) (sp)->opts[(o)].o_u.str +#define O_VAL(sp, o) (sp)->opts[(o)].o_u.val + +/* Option routines. */ +u_long baud_from_bval __P((SCR *)); + +int opts_copy __P((SCR *, SCR *)); +void opts_free __P((SCR *)); +int opts_init __P((SCR *)); +int opts_save __P((SCR *, FILE *)); +int opts_set __P((SCR *, char *, ARGS *[])); + +enum optdisp { NO_DISPLAY, ALL_DISPLAY, CHANGED_DISPLAY, SELECT_DISPLAY }; +void opts_dump __P((SCR *, enum optdisp)); + +/* Per-option change routines. */ +int f_altwerase __P((SCR *, OPTION *, char *, u_long)); +int f_cdpath __P((SCR *, OPTION *, char *, u_long)); +int f_columns __P((SCR *, OPTION *, char *, u_long)); +int f_leftright __P((SCR *, OPTION *, char *, u_long)); +int f_lines __P((SCR *, OPTION *, char *, u_long)); +int f_lisp __P((SCR *, OPTION *, char *, u_long)); +int f_list __P((SCR *, OPTION *, char *, u_long)); +int f_mesg __P((SCR *, OPTION *, char *, u_long)); +int f_modeline __P((SCR *, OPTION *, char *, u_long)); +int f_number __P((SCR *, OPTION *, char *, u_long)); +int f_octal __P((SCR *, OPTION *, char *, u_long)); +int f_paragraph __P((SCR *, OPTION *, char *, u_long)); +int f_readonly __P((SCR *, OPTION *, char *, u_long)); +int f_section __P((SCR *, OPTION *, char *, u_long)); +int f_shiftwidth __P((SCR *, OPTION *, char *, u_long)); +int f_sourceany __P((SCR *, OPTION *, char *, u_long)); +int f_tabstop __P((SCR *, OPTION *, char *, u_long)); +int f_tags __P((SCR *, OPTION *, char *, u_long)); +int f_term __P((SCR *, OPTION *, char *, u_long)); +int f_ttywerase __P((SCR *, OPTION *, char *, u_long)); +int f_w1200 __P((SCR *, OPTION *, char *, u_long)); +int f_w300 __P((SCR *, OPTION *, char *, u_long)); +int f_w9600 __P((SCR *, OPTION *, char *, u_long)); +int f_window __P((SCR *, OPTION *, char *, u_long)); diff --git a/usr.bin/vi/common/options_f.c b/usr.bin/vi/common/options_f.c new file mode 100644 index 0000000..6e1f060 --- /dev/null +++ b/usr.bin/vi/common/options_f.c @@ -0,0 +1,518 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)options_f.c 8.34 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "../ex/tag.h" + +static int opt_dup __P((SCR *, int, char *)); +static int opt_putenv __P((char *)); + +#define DECL(f) \ + int \ + f(sp, op, str, val) \ + SCR *sp; \ + OPTION *op; \ + char *str; \ + u_long val; +#define CALL(f) \ + f(sp, op, str, val) + +#define turnoff val + +DECL(f_altwerase) +{ + if (turnoff) + O_CLR(sp, O_ALTWERASE); + else { + O_SET(sp, O_ALTWERASE); + O_CLR(sp, O_TTYWERASE); + } + return (0); +} + +DECL(f_cdpath) +{ + return (opt_dup(sp, O_CDPATH, str)); +} + +DECL(f_columns) +{ + char buf[25]; + + /* Validate the number. */ + if (val < MINIMUM_SCREEN_COLS) { + msgq(sp, M_ERR, "Screen columns too small, less than %d", + MINIMUM_SCREEN_COLS); + return (1); + } + /* Set the columns value in the environment for curses. */ + (void)snprintf(buf, sizeof(buf), "COLUMNS=%lu", val); + if (opt_putenv(buf)) + return (1); + + /* This is expensive, don't do it unless it's necessary. */ + if (O_VAL(sp, O_COLUMNS) == val) + return (0); + + /* Set the value. */ + O_VAL(sp, O_COLUMNS) = val; + + F_SET(sp, S_RESIZE); + return (0); +} + +DECL(f_leftright) +{ + if (turnoff) + O_CLR(sp, O_LEFTRIGHT); + else + O_SET(sp, O_LEFTRIGHT); + F_SET(sp, S_REFORMAT | S_REDRAW); + return (0); +} + +DECL(f_lines) +{ + char buf[25]; + + /* Validate the number. */ + if (val < MINIMUM_SCREEN_ROWS) { + msgq(sp, M_ERR, "Screen lines too small, less than %d", + MINIMUM_SCREEN_ROWS); + return (1); + } + + /* Set the rows value in the environment for curses. */ + (void)snprintf(buf, sizeof(buf), "ROWS=%lu", val); + if (opt_putenv(buf)) + return (1); + + /* This is expensive, don't do it unless it's necessary. */ + if (O_VAL(sp, O_LINES) == val) + return (0); + + /* Set the value. */ + O_VAL(sp, O_LINES) = val; + + /* + * If no window value set, set a new default window and, + * optionally, a new scroll value. + */ + if (!F_ISSET(&sp->opts[O_WINDOW], OPT_SET)) { + O_VAL(sp, O_WINDOW) = val - 1; + if (!F_ISSET(&sp->opts[O_SCROLL], OPT_SET)) + O_VAL(sp, O_SCROLL) = val / 2; + } + + F_SET(sp, S_RESIZE); + return (0); +} + +DECL(f_lisp) +{ + msgq(sp, M_ERR, "The lisp option is not implemented"); + return (0); +} + +DECL(f_list) +{ + if (turnoff) + O_CLR(sp, O_LIST); + else + O_SET(sp, O_LIST); + + F_SET(sp, S_REFORMAT | S_REDRAW); + return (0); +} + +DECL(f_mesg) +{ + struct stat sb; + char *tty; + + /* Find the tty. */ + if ((tty = ttyname(STDERR_FILENO)) == NULL) { + msgq(sp, M_ERR, "ttyname: %s", strerror(errno)); + return (1); + } + + /* Save the tty mode for later; only save it once. */ + if (!F_ISSET(sp->gp, G_SETMODE)) { + F_SET(sp->gp, G_SETMODE); + if (stat(tty, &sb) < 0) { + msgq(sp, M_ERR, "%s: %s", tty, strerror(errno)); + return (1); + } + sp->gp->origmode = sb.st_mode; + } + + if (turnoff) { + if (chmod(tty, sp->gp->origmode & ~S_IWGRP) < 0) { + msgq(sp, M_ERR, "messages not turned off: %s: %s", + tty, strerror(errno)); + return (1); + } + O_CLR(sp, O_MESG); + } else { + if (chmod(tty, sp->gp->origmode | S_IWGRP) < 0) { + msgq(sp, M_ERR, "messages not turned on: %s: %s", + tty, strerror(errno)); + return (1); + } + O_SET(sp, O_MESG); + } + return (0); +} + +/* + * f_modeline -- + * This has been documented in historical systems as both "modeline" + * and as "modelines". Regardless of the name, this option represents + * a security problem of mammoth proportions, not to mention a stunning + * example of what your intro CS professor referred to as the perils of + * mixing code and data. Don't add it, or I will kill you. + */ +DECL(f_modeline) +{ + if (!turnoff) + msgq(sp, M_ERR, "The modeline(s) option may never be set"); + return (0); +} + +DECL(f_number) +{ + if (turnoff) + O_CLR(sp, O_NUMBER); + else + O_SET(sp, O_NUMBER); + + F_SET(sp, S_REFORMAT | S_REDRAW); + return (0); +} + +DECL(f_octal) +{ + if (turnoff) + O_CLR(sp, O_OCTAL); + else + O_SET(sp, O_OCTAL); + + key_init(sp); + F_SET(sp, S_REFORMAT | S_REDRAW); + return (0); +} + +DECL(f_paragraph) +{ + if (strlen(str) & 1) { + msgq(sp, M_ERR, + "Paragraph options must be in sets of two characters"); + return (1); + } + return (opt_dup(sp, O_PARAGRAPHS, str)); +} + +DECL(f_readonly) +{ + if (turnoff) { + O_CLR(sp, O_READONLY); + if (sp->frp != NULL) + F_CLR(sp->frp, FR_RDONLY); + } else { + O_SET(sp, O_READONLY); + if (sp->frp != NULL) + F_SET(sp->frp, FR_RDONLY); + } + return (0); +} + +DECL(f_section) +{ + if (strlen(str) & 1) { + msgq(sp, M_ERR, + "Section options must be in sets of two characters"); + return (1); + } + return (opt_dup(sp, O_SECTIONS, str)); +} + +DECL(f_shiftwidth) +{ + if (val == 0) { + msgq(sp, M_ERR, "The shiftwidth can't be set to 0"); + return (1); + } + O_VAL(sp, O_SHIFTWIDTH) = val; + return (0); +} + +/* + * f_sourceany -- + * Historic vi, on startup, source'd $HOME/.exrc and ./.exrc, if they + * were owned by the user. The sourceany option was an undocumented + * feature of historic vi which permitted the startup source'ing of + * .exrc files the user didn't own. This is an obvious security problem, + * and we ignore the option. + */ +DECL(f_sourceany) +{ + if (!turnoff) + msgq(sp, M_ERR, "The sourceany option may never be set"); + return (0); +} + +DECL(f_tabstop) +{ + if (val == 0) { + msgq(sp, M_ERR, "Tab stops can't be set to 0"); + return (1); + } +#define MAXTABSTOP 20 + if (val > MAXTABSTOP) { + msgq(sp, M_ERR, + "Tab stops can't be larger than %d", MAXTABSTOP); + return (1); + } + O_VAL(sp, O_TABSTOP) = val; + + F_SET(sp, S_REFORMAT | S_REDRAW); + return (0); +} + +DECL(f_tags) +{ + return (opt_dup(sp, O_TAGS, str)); +} + +DECL(f_term) +{ + char buf[256]; + + if (opt_dup(sp, O_TERM, str)) + return (1); + + /* Set the terminal value in the environment for curses. */ + (void)snprintf(buf, sizeof(buf), "TERM=%s", str); + if (opt_putenv(buf)) + return (1); + return (0); +} + +DECL(f_ttywerase) +{ + if (turnoff) + O_CLR(sp, O_TTYWERASE); + else { + O_SET(sp, O_TTYWERASE); + O_CLR(sp, O_ALTWERASE); + } + return (0); +} + +DECL(f_w300) +{ + /* Historical behavior for w300 was < 1200. */ + if (baud_from_bval(sp) >= 1200) + return (0); + + if (CALL(f_window)) + return (1); + + if (val > O_VAL(sp, O_LINES) - 1) + val = O_VAL(sp, O_LINES) - 1; + O_VAL(sp, O_W300) = val; + return (0); +} + +DECL(f_w1200) +{ + u_long v; + + /* Historical behavior for w1200 was == 1200. */ + v = baud_from_bval(sp); + if (v < 1200 || v > 4800) + return (0); + + if (CALL(f_window)) + return (1); + + if (val > O_VAL(sp, O_LINES) - 1) + val = O_VAL(sp, O_LINES) - 1; + O_VAL(sp, O_W1200) = val; + return (0); +} + +DECL(f_w9600) +{ + speed_t v; + + /* Historical behavior for w9600 was > 1200. */ + v = baud_from_bval(sp); + if (v <= 4800) + return (0); + + if (CALL(f_window)) + return (1); + + if (val > O_VAL(sp, O_LINES) - 1) + val = O_VAL(sp, O_LINES) - 1; + O_VAL(sp, O_W9600) = val; + return (0); +} + +DECL(f_window) +{ + if (val < MINIMUM_SCREEN_ROWS) { + msgq(sp, M_ERR, "Window too small, less than %d", + MINIMUM_SCREEN_ROWS); + return (1); + } + if (val > O_VAL(sp, O_LINES) - 1) + val = O_VAL(sp, O_LINES) - 1; + O_VAL(sp, O_WINDOW) = val; + O_VAL(sp, O_SCROLL) = val / 2; + + return (0); +} + +/* + * opt_dup -- + * Copy a string value for user display. + */ +static int +opt_dup(sp, opt, str) + SCR *sp; + int opt; + char *str; +{ + char *p; + + /* Copy for user display. */ + if ((p = strdup(str)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + /* Free the old contents. */ + if (F_ISSET(&sp->opts[opt], OPT_ALLOCATED)) + free(O_STR(sp, opt)); + + /* Note that it's set and allocated. */ + F_SET(&sp->opts[opt], OPT_ALLOCATED | OPT_SET); + + /* Assign new contents. */ + O_STR(sp, opt) = p; + return (0); +} + +/* + * opt_putenv -- + * Put a value into the environment. We use putenv(3) because it's + * more portable. The following hack is because some moron decided + * to keep a reference to the memory passed to putenv(3), instead of + * having it allocate its own. Someone clearly needs to get promoted + * into management. + */ +static int +opt_putenv(s) + char *s; +{ + char *t; + + /* + * XXX + * Memory leak. + */ + if ((t = strdup(s)) == NULL) + return (1); + return (putenv(t)); +} + +/* + * baud_from_bval -- + * Return the baud rate using the standard defines. + */ +u_long +baud_from_bval(sp) + SCR *sp; +{ + if (!F_ISSET(sp->gp, G_TERMIOS_SET)) + return (9600); + + /* + * XXX + * There's no portable way to get a "baud rate" -- cfgetospeed(3) + * returns the value associated with some #define, which we may + * never have heard of, or which may be a purely local speed. Vi + * only cares if it's SLOW (w300), slow (w1200) or fast (w9600). + * Try and detect the slow ones, and default to fast. + */ + switch (cfgetospeed(&sp->gp->original_termios)) { + case B50: + case B75: + case B110: + case B134: + case B150: + case B200: + case B300: + case B600: + return (600); + case B1200: + return (1200); + } + return (9600); +} diff --git a/usr.bin/vi/common/pathnames.h b/usr.bin/vi/common/pathnames.h new file mode 100644 index 0000000..6ad165f --- /dev/null +++ b/usr.bin/vi/common/pathnames.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pathnames.h 8.7 (Berkeley) 3/28/94 + */ + +#define _PATH_BSHELL "/bin/sh" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_EXRC ".exrc" +#define _PATH_NEXRC ".nexrc" +#define _PATH_PRESERVE "/var/tmp/vi.recover" +#define _PATH_SENDMAIL "/usr/sbin/sendmail" +#define _PATH_SYSEXRC "/etc/vi.exrc" +#define _PATH_TAGS "tags" +#define _PATH_TMP "/tmp" +#define _PATH_TTY "/dev/tty" diff --git a/usr.bin/vi/common/put.c b/usr.bin/vi/common/put.c new file mode 100644 index 0000000..e6dbf3a --- /dev/null +++ b/usr.bin/vi/common/put.c @@ -0,0 +1,254 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)put.c 8.9 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +/* + * put -- + * Put text buffer contents into the file. + */ +int +put(sp, ep, cbp, namep, cp, rp, append) + SCR *sp; + EXF *ep; + CB *cbp; + CHAR_T *namep; + MARK *cp, *rp; + int append; +{ + CHAR_T name; + TEXT *ltp, *tp; + recno_t lno; + size_t blen, clen, len; + int rval; + char *bp, *p, *t; + + if (cbp == NULL) + if (namep == NULL) { + cbp = sp->gp->dcbp; + if (cbp == NULL) { + msgq(sp, M_ERR, "The default buffer is empty"); + return (1); + } + } else { + name = *namep; + CBNAME(sp, cbp, name); + if (cbp == NULL) { + msgq(sp, M_ERR, + "Buffer %s is empty", KEY_NAME(sp, name)); + return (1); + } + } + tp = cbp->textq.cqh_first; + + /* + * It's possible to do a put into an empty file, meaning that the cut + * buffer simply becomes the file. It's a special case so that we can + * ignore it in general. + * + * !!! + * Historically, pasting into a file with no lines in vi would preserve + * the single blank line. This is surely a result of the fact that the + * historic vi couldn't deal with a file that had no lines in it. This + * implementation treats that as a bug, and does not retain the blank + * line. + * + * Historical practice is that the cursor ends at the first character + * in the file. + */ + if (cp->lno == 1) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) { + for (; tp != (void *)&cbp->textq; + ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next) + if (file_aline(sp, ep, 1, lno, tp->lb, tp->len)) + return (1); + rp->lno = 1; + rp->cno = 0; + return (0); + } + } + + /* If a line mode buffer, append each new line into the file. */ + if (F_ISSET(cbp, CB_LMODE)) { + lno = append ? cp->lno : cp->lno - 1; + rp->lno = lno + 1; + for (; tp != (void *)&cbp->textq; + ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next) + if (file_aline(sp, ep, 1, lno, tp->lb, tp->len)) + return (1); + rp->cno = 0; + (void)nonblank(sp, ep, rp->lno, &rp->cno); + return (0); + } + + /* + * If buffer was cut in character mode, replace the current line with + * one built from the portion of the first line to the left of the + * split plus the first line in the CB. Append each intermediate line + * in the CB. Append a line built from the portion of the first line + * to the right of the split plus the last line in the CB. + * + * Get the first line. + */ + lno = cp->lno; + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + GETLINE_ERR(sp, lno); + return (1); + } + + GET_SPACE_RET(sp, bp, blen, tp->len + len + 1); + t = bp; + + /* Original line, left of the split. */ + if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) { + memmove(bp, p, clen); + p += clen; + t += clen; + } + + /* First line from the CB. */ + memmove(t, tp->lb, tp->len); + t += tp->len; + + /* Calculate length left in original line. */ + clen = len ? len - cp->cno - (append ? 1 : 0) : 0; + + /* + * If no more lines in the CB, append the rest of the original + * line and quit. Otherwise, build the last line before doing + * the intermediate lines, because the line changes will lose + * the cached line. + */ + rval = 0; + if (tp->q.cqe_next == (void *)&cbp->textq) { + /* + * Historical practice is that if a non-line mode put + * is inside a single line, the cursor ends up on the + * last character inserted. + */ + rp->lno = lno; + rp->cno = (t - bp) - 1; + + if (clen > 0) { + memmove(t, p, clen); + t += clen; + } + if (file_sline(sp, ep, lno, bp, t - bp)) + goto mem; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + } else { + /* + * Have to build both the first and last lines of the + * put before doing any sets or we'll lose the cached + * line. Build both the first and last lines in the + * same buffer, so we don't have to have another buffer + * floating around. + * + * Last part of original line; check for space, reset + * the pointer into the buffer. + */ + ltp = cbp->textq.cqh_last; + len = t - bp; + ADD_SPACE_RET(sp, bp, blen, ltp->len + clen); + t = bp + len; + + /* Add in last part of the CB. */ + memmove(t, ltp->lb, ltp->len); + if (clen) + memmove(t + ltp->len, p, clen); + clen += ltp->len; + + /* + * Now: bp points to the first character of the first + * line, t points to the last character of the last + * line, t - bp is the length of the first line, and + * clen is the length of the last. Just figured you'd + * want to know. + * + * Output the line replacing the original line. + */ + if (file_sline(sp, ep, lno, bp, t - bp)) + goto mem; + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + + /* + * Historical practice is that if a non-line mode put + * covers multiple lines, the cursor ends up on the + * first character inserted. (Of course.) + */ + rp->lno = lno; + rp->cno = (t - bp) - 1; + + /* Output any intermediate lines in the CB. */ + for (tp = tp->q.cqe_next; + tp->q.cqe_next != (void *)&cbp->textq; + ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next) + if (file_aline(sp, ep, 1, lno, tp->lb, tp->len)) + goto mem; + + if (file_aline(sp, ep, 1, lno, t, clen)) +mem: rval = 1; + ++sp->rptlines[L_ADDED]; + } + FREE_SPACE(sp, bp, blen); + return (rval); +} diff --git a/usr.bin/vi/common/recover.c b/usr.bin/vi/common/recover.c new file mode 100644 index 0000000..f218c06 --- /dev/null +++ b/usr.bin/vi/common/recover.c @@ -0,0 +1,869 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)recover.c 8.72 (Berkeley) 7/21/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +/* + * We include <sys/file.h>, because the open #defines were found there + * on historical systems. We also include <fcntl.h> because the open(2) + * #defines are found there on newer systems. + */ +#include <sys/file.h> + +#include <netdb.h> /* MAXHOSTNAMELEN on some systems. */ + +#include <bitstring.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> +#include <pathnames.h> + +#include "vi.h" + +/* + * Recovery code. + * + * The basic scheme is as follows. In the EXF structure, we maintain full + * paths of a b+tree file and a mail recovery file. The former is the file + * used as backing store by the DB package. The latter is the file that + * contains an email message to be sent to the user if we crash. The two + * simple states of recovery are: + * + * + first starting the edit session: + * the b+tree file exists and is mode 700, the mail recovery + * file doesn't exist. + * + after the file has been modified: + * the b+tree file exists and is mode 600, the mail recovery + * file exists, and is exclusively locked. + * + * In the EXF structure we maintain a file descriptor that is the locked + * file descriptor for the mail recovery file. NOTE: we sometimes have to + * do locking with fcntl(2). This is a problem because if you close(2) any + * file descriptor associated with the file, ALL of the locks go away. Be + * sure to remember that if you have to modify the recovery code. (It has + * been rhetorically asked of what the designers could have been thinking + * when they did that interface. The answer is simple: they weren't.) + * + * To find out if a recovery file/backing file pair are in use, try to get + * a lock on the recovery file. + * + * To find out if a backing file can be deleted at boot time, check for an + * owner execute bit. (Yes, I know it's ugly, but it's either that or put + * special stuff into the backing file itself, or correlate the files at + * boot time, neither or which looks like fun.) Note also that there's a + * window between when the file is created and the X bit is set. It's small, + * but it's there. To fix the window, check for 0 length files as well. + * + * To find out if a file can be recovered, check the F_RCV_ON bit. Note, + * this DOES NOT mean that any initialization has been done, only that we + * haven't yet failed at setting up or doing recovery. + * + * To preserve a recovery file/backing file pair, set the F_RCV_NORM bit. + * If that bit is not set when ending a file session: + * If the EXF structure paths (rcv_path and rcv_mpath) are not NULL, + * they are unlink(2)'d, and free(3)'d. + * If the EXF file descriptor (rcv_fd) is not -1, it is closed. + * + * The backing b+tree file is set up when a file is first edited, so that + * the DB package can use it for on-disk caching and/or to snapshot the + * file. When the file is first modified, the mail recovery file is created, + * the backing file permissions are updated, the file is sync(2)'d to disk, + * and the timer is started. Then, at RCV_PERIOD second intervals, the + * b+tree file is synced to disk. RCV_PERIOD is measured using SIGALRM, which + * means that the data structures (SCR, EXF, the underlying tree structures) + * must be consistent when the signal arrives. + * + * The recovery mail file contains normal mail headers, with two additions, + * which occur in THIS order, as the FIRST TWO headers: + * + * X-vi-recover-file: file_name + * X-vi-recover-path: recover_path + * + * Since newlines delimit the headers, this means that file names cannot have + * newlines in them, but that's probably okay. As these files aren't intended + * to be long-lived, changing their format won't be too painful. + * + * Btree files are named "vi.XXXX" and recovery files are named "recover.XXXX". + */ + +#define VI_FHEADER "X-vi-recover-file: " +#define VI_PHEADER "X-vi-recover-path: " + +static int rcv_copy __P((SCR *, int, char *)); +static void rcv_email __P((SCR *, char *)); +static char *rcv_gets __P((char *, size_t, int)); +static int rcv_mailfile __P((SCR *, EXF *, int, char *)); +static int rcv_mktemp __P((SCR *, char *, char *, int)); + +/* + * rcv_tmp -- + * Build a file name that will be used as the recovery file. + */ +int +rcv_tmp(sp, ep, name) + SCR *sp; + EXF *ep; + char *name; +{ + struct stat sb; + int fd; + char *dp, *p, path[MAXPATHLEN]; + + /* + * If the recovery directory doesn't exist, try and create it. As + * the recovery files are themselves protected from reading/writing + * by other than the owner, the worst that can happen is that a user + * would have permission to remove other user's recovery files. If + * the sticky bit has the BSD semantics, that too will be impossible. + */ + dp = O_STR(sp, O_RECDIR); + if (stat(dp, &sb)) { + if (errno != ENOENT || mkdir(dp, 0)) { + msgq(sp, M_SYSERR, "%s", dp); + goto err; + } + (void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX); + } + + /* Newlines delimit the mail messages. */ + for (p = name; *p; ++p) + if (*p == '\n') { + msgq(sp, M_ERR, + "Files with newlines in the name are unrecoverable"); + goto err; + } + + (void)snprintf(path, sizeof(path), "%s/vi.XXXXXX", dp); + if ((fd = rcv_mktemp(sp, path, dp, S_IRWXU)) == -1) + goto err; + (void)close(fd); + + if ((ep->rcv_path = strdup(path)) == NULL) { + msgq(sp, M_SYSERR, NULL); + (void)unlink(path); +err: msgq(sp, M_ERR, + "Modifications not recoverable if the session fails"); + return (1); + } + + /* We believe the file is recoverable. */ + F_SET(ep, F_RCV_ON); + return (0); +} + +/* + * rcv_init -- + * Force the file to be snapshotted for recovery. + */ +int +rcv_init(sp, ep) + SCR *sp; + EXF *ep; +{ + recno_t lno; + int btear; + + /* Only do this once. */ + F_CLR(ep, F_FIRSTMODIFY); + + /* If we already know the file isn't recoverable, we're done. */ + if (!F_ISSET(ep, F_RCV_ON)) + return (0); + + /* Turn off recoverability until we figure out if this will work. */ + F_CLR(ep, F_RCV_ON); + + /* Test if we're recovering a file, not editing one. */ + if (ep->rcv_mpath == NULL) { + /* Build a file to mail to the user. */ + if (rcv_mailfile(sp, ep, 0, NULL)) + goto err; + + /* Force a read of the entire file. */ + if (file_lline(sp, ep, &lno)) + goto err; + + /* Turn on a busy message, and sync it to backing store. */ + btear = F_ISSET(sp, S_EXSILENT) ? 0 : + !busy_on(sp, "Copying file for recovery..."); + if (ep->db->sync(ep->db, R_RECNOSYNC)) { + msgq(sp, M_ERR, "Preservation failed: %s: %s", + ep->rcv_path, strerror(errno)); + if (btear) + busy_off(sp); + goto err; + } + if (btear) + busy_off(sp); + } + + /* Turn on the recovery timer, if it's not yet running. */ + if (!F_ISSET(sp->gp, G_RECOVER_SET) && rcv_on(sp, ep)) { +err: msgq(sp, M_ERR, + "Modifications not recoverable if the session fails"); + return (1); + } + + /* Turn off the owner execute bit. */ + (void)chmod(ep->rcv_path, S_IRUSR | S_IWUSR); + + /* We believe the file is recoverable. */ + F_SET(ep, F_RCV_ON); + return (0); +} + +/* + * rcv_sync -- + * Sync the file, optionally: + * flagging the backup file to be preserved + * snapshotting the backup file and send email to the user + * sending email to the user if the file was modified + * ending the file session + */ +int +rcv_sync(sp, ep, flags) + SCR *sp; + EXF *ep; + u_int flags; +{ + int btear, fd, rval; + char *dp, buf[1024]; + + /* Make sure that there's something to recover/sync. */ + if (ep == NULL || !F_ISSET(ep, F_RCV_ON)) + return (0); + + /* Sync the file if it's been modified. */ + if (F_ISSET(ep, F_MODIFIED)) { + if (ep->db->sync(ep->db, R_RECNOSYNC)) { + F_CLR(ep, F_RCV_ON | F_RCV_NORM); + msgq(sp, M_SYSERR, + "File backup failed: %s", ep->rcv_path); + return (1); + } + + /* REQUEST: don't remove backing file on exit. */ + if (LF_ISSET(RCV_PRESERVE)) + F_SET(ep, F_RCV_NORM); + + /* REQUEST: send email. */ + if (LF_ISSET(RCV_EMAIL)) + rcv_email(sp, ep->rcv_mpath); + } + + /* + * !!! + * Each time the user exec's :preserve, we have to snapshot all of + * the recovery information, i.e. it's like the user re-edited the + * file. We copy the DB(3) backing file, and then create a new mail + * recovery file, it's simpler than exiting and reopening all of the + * underlying files. + * + * REQUEST: snapshot the file. + */ + rval = 0; + if (LF_ISSET(RCV_SNAPSHOT)) { + btear = F_ISSET(sp, S_EXSILENT) ? 0 : + !busy_on(sp, "Copying file for recovery..."); + dp = O_STR(sp, O_RECDIR); + (void)snprintf(buf, sizeof(buf), "%s/vi.XXXXXX", dp); + if ((fd = rcv_mktemp(sp, buf, dp, S_IRUSR | S_IWUSR)) == -1) + goto e1; + if (rcv_copy(sp, fd, ep->rcv_path) || close(fd)) + goto e2; + if (rcv_mailfile(sp, ep, 1, buf)) { +e2: (void)unlink(buf); +e1: if (fd != -1) + (void)close(fd); + rval = 1; + } + if (btear) + busy_off(sp); + } + + /* REQUEST: end the file session. */ + if (LF_ISSET(RCV_ENDSESSION) && file_end(sp, ep, 1)) + rval = 1; + + return (rval); +} + +/* + * rcv_mailfile -- + * Build the file to mail to the user. + */ +static int +rcv_mailfile(sp, ep, issync, cp_path) + SCR *sp; + EXF *ep; + int issync; + char *cp_path; +{ + struct passwd *pw; + size_t len; + time_t now; + uid_t uid; + int fd; + char *dp, *p, *t, buf[4096], host[MAXHOSTNAMELEN], mpath[MAXPATHLEN]; + char *t1, *t2, *t3; + + if ((pw = getpwuid(uid = getuid())) == NULL) { + msgq(sp, M_ERR, "Information on user id %u not found", uid); + return (1); + } + + dp = O_STR(sp, O_RECDIR); + (void)snprintf(mpath, sizeof(mpath), "%s/recover.XXXXXX", dp); + if ((fd = rcv_mktemp(sp, mpath, dp, S_IRUSR | S_IWUSR)) == -1) + return (1); + + /* + * XXX + * We keep an open lock on the file so that the recover option can + * distinguish between files that are live and those that need to + * be recovered. There's an obvious window between the mkstemp call + * and the lock, but it's pretty small. + */ + if (file_lock(NULL, NULL, fd, 1) != LOCK_SUCCESS) + msgq(sp, M_SYSERR, "Unable to lock recovery file"); + if (!issync) { + /* Save the recover file descriptor, and mail path. */ + ep->rcv_fd = fd; + if ((ep->rcv_mpath = strdup(mpath)) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + cp_path = ep->rcv_path; + } + + /* + * XXX + * We can't use stdio(3) here. The problem is that we may be using + * fcntl(2), so if ANY file descriptor into the file is closed, the + * lock is lost. So, we could never close the FILE *, even if we + * dup'd the fd first. + */ + t = sp->frp->name; + if ((p = strrchr(t, '/')) == NULL) + p = t; + else + ++p; + (void)time(&now); + (void)gethostname(host, sizeof(host)); + len = snprintf(buf, sizeof(buf), + "%s%s\n%s%s\n%s\n%s\n%s%s\n%s%s\n%s\n\n", + VI_FHEADER, t, /* Non-standard. */ + VI_PHEADER, cp_path, /* Non-standard. */ + "Reply-To: root", + "From: root (Nvi recovery program)", + "To: ", pw->pw_name, + "Subject: Nvi saved the file ", p, + "Precedence: bulk"); /* For vacation(1). */ + if (len > sizeof(buf) - 1) + goto lerr; + if (write(fd, buf, len) != len) + goto werr; + + len = snprintf(buf, sizeof(buf), "%s%.24s%s%s%s%s%s%s%s%s%s%s%s\n\n", + "On ", ctime(&now), ", the user ", pw->pw_name, + " was editing a file named ", t, " on the machine ", + host, ", when it was saved for recovery. ", + "You can recover most, if not all, of the changes ", + "to this file using the -r option to nex or nvi:\n\n", + "\tnvi -r ", t); + if (len > sizeof(buf) - 1) { +lerr: msgq(sp, M_ERR, "recovery file buffer overrun"); + goto err; + } + + /* + * Format the message. (Yes, I know it's silly.) + * Requires that the message end in a <newline>. + */ +#define FMTCOLS 60 + for (t1 = buf; len > 0; len -= t2 - t1, t1 = t2) { + /* Check for a short length. */ + if (len <= FMTCOLS) { + t2 = t1 + (len - 1); + goto wout; + } + + /* Check for a required <newline>. */ + t2 = strchr(t1, '\n'); + if (t2 - t1 <= FMTCOLS) + goto wout; + + /* Find the closest space, if any. */ + for (t3 = t2; t2 > t1; --t2) + if (*t2 == ' ') { + if (t2 - t1 <= FMTCOLS) + goto wout; + t3 = t2; + } + t2 = t3; + + /* t2 points to the last character to display. */ +wout: *t2++ = '\n'; + + /* t2 points one after the last character to display. */ + if (write(fd, t1, t2 - t1) != t2 - t1) { +werr: msgq(sp, M_SYSERR, "recovery file"); + goto err; + } + } + + if (issync) + rcv_email(sp, mpath); + + return (0); + +err: if (!issync) + ep->rcv_fd = -1; + if (fd != -1) + (void)close(fd); + return (1); +} + +/* + * people making love + * never exactly the same + * just like a snowflake + * + * rcv_list -- + * List the files that can be recovered by this user. + */ +int +rcv_list(sp) + SCR *sp; +{ + struct dirent *dp; + struct stat sb; + DIR *dirp; + FILE *fp; + int found; + char *p, *t, file[MAXPATHLEN], path[MAXPATHLEN]; + + /* + * XXX + * Messages aren't yet set up. + */ + if (chdir(O_STR(sp, O_RECDIR)) || (dirp = opendir(".")) == NULL) { + (void)fprintf(stderr, + "vi: %s: %s\n", O_STR(sp, O_RECDIR), strerror(errno)); + return (1); + } + + for (found = 0; (dp = readdir(dirp)) != NULL;) { + if (strncmp(dp->d_name, "recover.", 8)) + continue; + + /* + * If it's readable, it's recoverable. + * + * XXX + * Should be "r", we don't want to write the file. However, + * if we're using fcntl(2), there's no way to lock a file + * descriptor that's not open for writing. + */ + if ((fp = fopen(dp->d_name, "r+")) == NULL) + continue; + + switch (file_lock(NULL, NULL, fileno(fp), 1)) { + case LOCK_FAILED: + /* + * XXX + * Assume that a lock can't be acquired, but that we + * should permit recovery anyway. If this is wrong, + * and someone else is using the file, we're going to + * die horribly. + */ + break; + case LOCK_SUCCESS: + break; + case LOCK_UNAVAIL: + /* If it's locked, it's live. */ + (void)fclose(fp); + continue; + } + + /* Check the headers. */ + if (fgets(file, sizeof(file), fp) == NULL || + strncmp(file, VI_FHEADER, sizeof(VI_FHEADER) - 1) || + (p = strchr(file, '\n')) == NULL || + fgets(path, sizeof(path), fp) == NULL || + strncmp(path, VI_PHEADER, sizeof(VI_PHEADER) - 1) || + (t = strchr(path, '\n')) == NULL) { + msgq(sp, M_ERR, + "%s: malformed recovery file", dp->d_name); + goto next; + } + *p = *t = '\0'; + + /* + * If the file doesn't exist, it's an orphaned recovery file, + * toss it. + * + * XXX + * This can occur if the backup file was deleted and we crashed + * before deleting the email file. + */ + errno = 0; + if (stat(path + sizeof(VI_PHEADER) - 1, &sb) && + errno == ENOENT) { + (void)unlink(dp->d_name); + goto next; + } + + /* Get the last modification time and display. */ + (void)fstat(fileno(fp), &sb); + (void)printf("%s: %s", + file + sizeof(VI_FHEADER) - 1, ctime(&sb.st_mtime)); + found = 1; + + /* Close, discarding lock. */ +next: (void)fclose(fp); + } + if (found == 0) + (void)printf("vi: no files to recover.\n"); + (void)closedir(dirp); + return (0); +} + +/* + * rcv_read -- + * Start a recovered file as the file to edit. + */ +int +rcv_read(sp, frp) + SCR *sp; + FREF *frp; +{ + struct dirent *dp; + struct stat sb; + DIR *dirp; + EXF *ep; + time_t rec_mtime; + int fd, found, locked, requested, sv_fd; + char *name, *p, *t, *recp, *pathp; + char file[MAXPATHLEN], path[MAXPATHLEN], recpath[MAXPATHLEN]; + + if ((dirp = opendir(O_STR(sp, O_RECDIR))) == NULL) { + msgq(sp, M_ERR, + "%s: %s", O_STR(sp, O_RECDIR), strerror(errno)); + return (1); + } + + name = frp->name; + sv_fd = -1; + rec_mtime = 0; + recp = pathp = NULL; + for (found = requested = 0; (dp = readdir(dirp)) != NULL;) { + if (strncmp(dp->d_name, "recover.", 8)) + continue; + (void)snprintf(recpath, sizeof(recpath), + "%s/%s", O_STR(sp, O_RECDIR), dp->d_name); + + /* + * If it's readable, it's recoverable. It would be very + * nice to use stdio(3), but, we can't because that would + * require closing and then reopening the file so that we + * could have a lock and still close the FP. Another tip + * of the hat to fcntl(2). + * + * XXX + * Should be O_RDONLY, we don't want to write it. However, + * if we're using fcntl(2), there's no way to lock a file + * descriptor that's not open for writing. + */ + if ((fd = open(recpath, O_RDWR, 0)) == -1) + continue; + + switch (file_lock(NULL, NULL, fd, 1)) { + case LOCK_FAILED: + /* + * XXX + * Assume that a lock can't be acquired, but that we + * should permit recovery anyway. If this is wrong, + * and someone else is using the file, we're going to + * die horribly. + */ + locked = 0; + break; + case LOCK_SUCCESS: + locked = 1; + break; + case LOCK_UNAVAIL: + /* If it's locked, it's live. */ + (void)close(fd); + continue; + } + + /* Check the headers. */ + if (rcv_gets(file, sizeof(file), fd) == NULL || + strncmp(file, VI_FHEADER, sizeof(VI_FHEADER) - 1) || + (p = strchr(file, '\n')) == NULL || + rcv_gets(path, sizeof(path), fd) == NULL || + strncmp(path, VI_PHEADER, sizeof(VI_PHEADER) - 1) || + (t = strchr(path, '\n')) == NULL) { + msgq(sp, M_ERR, + "%s: malformed recovery file", recpath); + goto next; + } + *p = *t = '\0'; + ++found; + + /* + * If the file doesn't exist, it's an orphaned recovery file, + * toss it. + * + * XXX + * This can occur if the backup file was deleted and we crashed + * before deleting the email file. + */ + errno = 0; + if (stat(path + sizeof(VI_PHEADER) - 1, &sb) && + errno == ENOENT) { + (void)unlink(dp->d_name); + goto next; + } + + /* Check the file name. */ + if (strcmp(file + sizeof(VI_FHEADER) - 1, name)) + goto next; + + ++requested; + + /* + * If we've found more than one, take the most recent. + * + * XXX + * Since we're using st_mtime, for portability reasons, + * we only get a single second granularity, instead of + * getting it right. + */ + (void)fstat(fd, &sb); + if (recp == NULL || rec_mtime < sb.st_mtime) { + p = recp; + t = pathp; + if ((recp = strdup(recpath)) == NULL) { + msgq(sp, M_ERR, + "vi: Error: %s.\n", strerror(errno)); + recp = p; + goto next; + } + if ((pathp = strdup(path)) == NULL) { + msgq(sp, M_ERR, + "vi: Error: %s.\n", strerror(errno)); + FREE(recp, strlen(recp) + 1); + recp = p; + pathp = t; + goto next; + } + if (p != NULL) { + FREE(p, strlen(p) + 1); + FREE(t, strlen(t) + 1); + } + rec_mtime = sb.st_mtime; + if (sv_fd != -1) + (void)close(sv_fd); + sv_fd = fd; + } else +next: (void)close(fd); + } + (void)closedir(dirp); + + if (recp == NULL) { + msgq(sp, M_INFO, + "No files named %s, readable by you, to recover", name); + return (1); + } + if (found) { + if (requested > 1) + msgq(sp, M_INFO, + "There are older versions of this file for you to recover"); + if (found > requested) + msgq(sp, M_INFO, + "There are other files for you to recover"); + } + + /* + * Create the FREF structure, start the btree file. + * + * XXX + * file_init() is going to set ep->rcv_path. + */ + if (file_init(sp, frp, pathp + sizeof(VI_PHEADER) - 1, 0)) { + free(recp); + free(pathp); + (void)close(sv_fd); + return (1); + } + + /* + * We keep an open lock on the file so that the recover option can + * distinguish between files that are live and those that need to + * be recovered. The lock is already acquired, just copy it. + */ + ep = sp->ep; + ep->rcv_mpath = recp; + ep->rcv_fd = sv_fd; + if (!locked) + F_SET(frp, FR_UNLOCKED); + + /* We believe the file is recoverable. */ + F_SET(ep, F_RCV_ON); + return (0); +} + +/* + * rcv_copy -- + * Copy a recovery file. + */ +static int +rcv_copy(sp, wfd, fname) + SCR *sp; + int wfd; + char *fname; +{ + int nr, nw, off, rfd; + char buf[8 * 1024]; + + if ((rfd = open(fname, O_RDONLY, 0)) == -1) + goto err; + while ((nr = read(rfd, buf, sizeof(buf))) > 0) + for (off = 0; nr; nr -= nw, off += nw) + if ((nw = write(wfd, buf + off, nr)) < 0) + goto err; + if (nr == 0) + return (0); + +err: msgq(sp, M_SYSERR, "%s", fname); + return (1); +} + +/* + * rcv_gets -- + * Fgets(3) for a file descriptor. + */ +static char * +rcv_gets(buf, len, fd) + char *buf; + size_t len; + int fd; +{ + ssize_t nr; + char *p; + + if ((nr = read(fd, buf, len - 1)) == -1) + return (NULL); + if ((p = strchr(buf, '\n')) == NULL) + return (NULL); + (void)lseek(fd, (off_t)((p - buf) + 1), SEEK_SET); + return (buf); +} + +/* + * rcv_mktemp -- + * Paranoid make temporary file routine. + */ +static int +rcv_mktemp(sp, path, dname, perms) + SCR *sp; + char *path, *dname; + int perms; +{ + int fd; + + /* + * !!! + * We expect mkstemp(3) to set the permissions correctly. On + * historic System V systems, mkstemp didn't. Do it here, on + * GP's. + * + * XXX + * The variable perms should really be a mode_t, and it would + * be nice to use fchmod(2) instead of chmod(2), here. + */ + if ((fd = mkstemp(path)) == -1) + msgq(sp, M_SYSERR, "%s", dname); + else + (void)chmod(path, perms); + return (fd); +} + +/* + * rcv_email -- + * Send email. + */ +static void +rcv_email(sp, fname) + SCR *sp; + char *fname; +{ + struct stat sb; + char buf[MAXPATHLEN * 2 + 20]; + + if (stat(_PATH_SENDMAIL, &sb)) + msgq(sp, M_SYSERR, "not sending email: %s", _PATH_SENDMAIL); + else { + /* + * !!! + * If you need to port this to a system that doesn't have + * sendmail, the -t flag causes sendmail to read the message + * for the recipients instead of specifying them some other + * way. + */ + (void)snprintf(buf, sizeof(buf), + "%s -t < %s", _PATH_SENDMAIL, fname); + (void)system(buf); + } +} diff --git a/usr.bin/vi/common/screen.c b/usr.bin/vi/common/screen.c new file mode 100644 index 0000000..d3e27e7 --- /dev/null +++ b/usr.bin/vi/common/screen.c @@ -0,0 +1,309 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)screen.c 8.64 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "../vi/vcmd.h" +#include "excmd.h" +#include "../ex/tag.h" + +/* + * screen_init -- + * Do the default initialization of an SCR structure. + */ +int +screen_init(orig, spp, flags) + SCR *orig, **spp; + u_int flags; +{ + SCR *sp; + size_t len; + + *spp = NULL; + CALLOC_RET(orig, sp, SCR *, 1, sizeof(SCR)); + *spp = sp; + +/* INITIALIZED AT SCREEN CREATE. */ + sp->gp = __global_list; /* All ref the GS structure. */ + + LIST_INIT(&sp->msgq); + CIRCLEQ_INIT(&sp->frefq); + + sp->ccnt = 2; /* Anything > 1 */ + + FD_ZERO(&sp->rdfd); + + /* + * XXX + * sp->defscroll is initialized by the opts_init() code because + * we don't have the option information yet. + */ + + sp->tiqp = &sp->__tiq; + CIRCLEQ_INIT(&sp->__tiq); + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ + if (orig == NULL) { + sp->searchdir = NOTSET; + + switch (flags & S_SCREENS) { + case S_EX: + if (sex_screen_init(sp)) + return (1); + break; + case S_VI_CURSES: + if (svi_screen_init(sp)) + return (1); + break; + case S_VI_XAW: + if (xaw_screen_init(sp)) + return (1); + break; + default: + abort(); + } + + sp->flags = flags; + } else { + if (orig->alt_name != NULL && + (sp->alt_name = strdup(orig->alt_name)) == NULL) + goto mem; + + /* Retain all searching/substitution information. */ + if (F_ISSET(orig, S_SRE_SET)) { + F_SET(sp, S_SRE_SET); + sp->sre = orig->sre; + } + if (F_ISSET(orig, S_SUBRE_SET)) { + F_SET(sp, S_SUBRE_SET); + sp->subre = orig->subre; + } + sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD; + + if (orig->repl_len) { + MALLOC(sp, sp->repl, char *, orig->repl_len); + if (sp->repl == NULL) + goto mem; + sp->repl_len = orig->repl_len; + memmove(sp->repl, orig->repl, orig->repl_len); + } + if (orig->newl_len) { + len = orig->newl_len * sizeof(size_t); + MALLOC(sp, sp->newl, size_t *, len); + if (sp->newl == NULL) + goto mem; + sp->newl_len = orig->newl_len; + sp->newl_cnt = orig->newl_cnt; + memmove(sp->newl, orig->newl, len); + } + + sp->saved_vi_mode = orig->saved_vi_mode; + + if (opts_copy(orig, sp)) { +mem: msgq(orig, M_SYSERR, "new screen attributes"); + (void)screen_end(sp); + return (1); + } + + sp->s_bell = orig->s_bell; + sp->s_bg = orig->s_bg; + sp->s_busy = orig->s_busy; + sp->s_change = orig->s_change; + sp->s_clear = orig->s_clear; + sp->s_colpos = orig->s_colpos; + sp->s_column = orig->s_column; + sp->s_confirm = orig->s_confirm; + sp->s_crel = orig->s_crel; + sp->s_edit = orig->s_edit; + sp->s_end = orig->s_end; + sp->s_ex_cmd = orig->s_ex_cmd; + sp->s_ex_run = orig->s_ex_run; + sp->s_ex_write = orig->s_ex_write; + sp->s_fg = orig->s_fg; + sp->s_fill = orig->s_fill; + sp->s_get = orig->s_get; + sp->s_key_read = orig->s_key_read; + sp->s_fmap = orig->s_fmap; + sp->s_optchange = orig->s_optchange; + sp->s_position = orig->s_position; + sp->s_rabs = orig->s_rabs; + sp->s_rcm = orig->s_rcm; + sp->s_refresh = orig->s_refresh; + sp->s_scroll = orig->s_scroll; + sp->s_split = orig->s_split; + sp->s_suspend = orig->s_suspend; + sp->s_window = orig->s_window; + + F_SET(sp, F_ISSET(orig, S_SCREENS)); + } + + if (xaw_screen_copy(orig, sp)) /* Init S_VI_XAW screen. */ + return (1); + if (svi_screen_copy(orig, sp)) /* Init S_VI_CURSES screen. */ + return (1); + if (sex_screen_copy(orig, sp)) /* Init S_EX screen. */ + return (1); + if (v_screen_copy(orig, sp)) /* Init vi. */ + return (1); + if (ex_screen_copy(orig, sp)) /* Init ex. */ + return (1); + + *spp = sp; + return (0); +} + +/* + * screen_end -- + * Release a screen. + */ +int +screen_end(sp) + SCR *sp; +{ + int rval; + + rval = 0; + if (xaw_screen_end(sp)) /* End S_VI_XAW screen. */ + rval = 1; + if (svi_screen_end(sp)) /* End S_VI_CURSES screen. */ + rval = 1; + if (sex_screen_end(sp)) /* End S_EX screen. */ + rval = 1; + if (v_screen_end(sp)) /* End vi. */ + rval = 1; + if (ex_screen_end(sp)) /* End ex. */ + rval = 1; + + /* Free FREF's. */ + { FREF *frp; + while ((frp = sp->frefq.cqh_first) != (FREF *)&sp->frefq) { + CIRCLEQ_REMOVE(&sp->frefq, frp, q); + if (frp->name != NULL) + free(frp->name); + if (frp->tname != NULL) + free(frp->tname); + FREE(frp, sizeof(FREF)); + } + } + + /* Free file names. */ + { char **ap; + if (!F_ISSET(sp, S_ARGNOFREE) && sp->argv != NULL) { + for (ap = sp->argv; *ap != NULL; ++ap) + free(*ap); + free(sp->argv); + } + } + + /* Free any text input. */ + text_lfree(&sp->__tiq); + + /* Free any script information. */ + if (F_ISSET(sp, S_SCRIPT)) + sscr_end(sp); + + /* Free alternate file name. */ + if (sp->alt_name != NULL) + free(sp->alt_name); + + /* Free up search information. */ + if (sp->repl != NULL) + FREE(sp->repl, sp->repl_len); + if (sp->newl != NULL) + FREE(sp->newl, sp->newl_len); + + /* Free all the options */ + opts_free(sp); + + /* + * Free the message chain last, so previous failures have a place + * to put messages. Copy messages to (in order) a related screen, + * any screen, the global area. + */ + { SCR *c_sp; MSG *mp, *next; + if ((c_sp = sp->q.cqe_prev) != (void *)&sp->gp->dq) { + if (F_ISSET(sp, S_BELLSCHED)) + F_SET(c_sp, S_BELLSCHED); + } else if ((c_sp = sp->q.cqe_next) != (void *)&sp->gp->dq) { + if (F_ISSET(sp, S_BELLSCHED)) + F_SET(c_sp, S_BELLSCHED); + } else if ((c_sp = + sp->gp->hq.cqh_first) != (void *)&sp->gp->hq) { + if (F_ISSET(sp, S_BELLSCHED)) + F_SET(c_sp, S_BELLSCHED); + } else { + c_sp = NULL; + if (F_ISSET(sp, S_BELLSCHED)) + F_SET(sp->gp, G_BELLSCHED); + } + + for (mp = sp->msgq.lh_first; mp != NULL; mp = next) { + if (!F_ISSET(mp, M_EMPTY)) + msg_app(sp->gp, c_sp, + mp->flags & M_INV_VIDEO, mp->mbuf, mp->len); + next = mp->q.le_next; + if (mp->mbuf != NULL) + FREE(mp->mbuf, mp->blen); + FREE(mp, sizeof(MSG)); + } + } + + /* Remove the screen from the displayed queue. */ + CIRCLEQ_REMOVE(&sp->gp->dq, sp, q); + + /* Free the screen itself. */ + FREE(sp, sizeof(SCR)); + + return (rval); +} diff --git a/usr.bin/vi/common/screen.h b/usr.bin/vi/common/screen.h new file mode 100644 index 0000000..31df988 --- /dev/null +++ b/usr.bin/vi/common/screen.h @@ -0,0 +1,342 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)screen.h 8.127 (Berkeley) 8/8/94 + */ + +/* + * There are minimum values that vi has to have to display a screen. The + * row minimum is fixed at 1 line for the text, and 1 line for any error + * messages. The column calculation is a lot trickier. For example, you + * have to have enough columns to display the line number, not to mention + * guaranteeing that tabstop and shiftwidth values are smaller than the + * current column value. It's a lot simpler to have a fixed value and not + * worry about it. + * + * XXX + * MINIMUM_SCREEN_COLS is probably wrong. + */ +#define MINIMUM_SCREEN_ROWS 2 +#define MINIMUM_SCREEN_COLS 20 + +enum adjust { /* Screen adjustment operations. */ + A_DECREASE, A_INCREASE, A_SET }; +enum operation { /* Line operations. */ + LINE_APPEND, LINE_DELETE, LINE_INSERT, LINE_RESET }; +enum position { /* Position operations. */ + P_BOTTOM, P_FILL, P_MIDDLE, P_TOP }; +enum sctype { /* Scroll operations. */ + CNTRL_B, CNTRL_D, CNTRL_E, CNTRL_F, CNTRL_U, CNTRL_Y, Z_CARAT, Z_PLUS }; + +/* + * Structure for holding file references. Each SCR structure contains a + * linked list of these. The structure contains the name of the file, + * along with the information that follows the name. + * + * !!! + * The read-only bit follows the file name, not the file itself. + * + * XXX + * The mtime field should be a struct timespec, but time_t is more portable. + */ +struct _fref { + CIRCLEQ_ENTRY(_fref) q; /* Linked list of file references. */ + char *name; /* File name. */ + char *tname; /* Backing temporary file name. */ + + recno_t lno; /* 1-N: file cursor line. */ + size_t cno; /* 0-N: file cursor column. */ + +#define FR_CURSORSET 0x001 /* If lno/cno values valid. */ +#define FR_DONTDELETE 0x002 /* Don't delete the temporary file. */ +#define FR_FNONBLANK 0x004 /* Move to the first non-<blank>. */ +#define FR_NAMECHANGE 0x008 /* If the name changed. */ +#define FR_NEWFILE 0x010 /* File doesn't really exist yet. */ +#define FR_RDONLY 0x020 /* File is read-only. */ +#define FR_READNAMED 0x040 /* Read renamed the file. */ +#define FR_RECOVER 0x080 /* File is being recovered. */ +#define FR_TMPEXIT 0x100 /* Modified temporary file, no exit. */ +#define FR_TMPFILE 0x200 /* If file has no name. */ +#define FR_UNLOCKED 0x400 /* File couldn't be locked. */ + u_int16_t flags; +}; + +#define TEMPORARY_FILE_STRING "/tmp" /* Default temporary file name. */ + +/* + * SCR -- + * The screen structure. To the extent possible, all screen information + * is stored in the various private areas. The only information here + * is used by global routines or is shared by too many screens. + */ +struct _scr { +/* INITIALIZED AT SCREEN CREATE. */ + CIRCLEQ_ENTRY(_scr) q; /* Screens. */ + + GS *gp; /* Pointer to global area. */ + + SCR *nextdisp; /* Next display screen. */ + + EXF *ep; /* Screen's current EXF structure. */ + + MSGH msgq; /* Message list. */ + /* FREF list. */ + CIRCLEQ_HEAD(_frefh, _fref) frefq; + FREF *frp; /* FREF being edited. */ + + char **argv; /* NULL terminated file name array. */ + char **cargv; /* Current file name. */ + + u_long ccnt; /* Command count. */ + u_long q_ccnt; /* Quit or ZZ command count. */ + + /* Screen's: */ + size_t rows; /* 1-N: number of rows. */ + size_t cols; /* 1-N: number of columns. */ + size_t woff; /* 0-N: row offset in screen. */ + size_t t_rows; /* 1-N: cur number of text rows. */ + size_t t_maxrows; /* 1-N: max number of text rows. */ + size_t t_minrows; /* 1-N: min number of text rows. */ + + /* Cursor's: */ + recno_t lno; /* 1-N: file line. */ + size_t cno; /* 0-N: file character in line. */ + + size_t rcm; /* Vi: 0-N: Most attractive column. */ + int rcm_last; /* Cursor drawn to the last column. */ + +#define L_ADDED 0 /* Added lines. */ +#define L_CHANGED 1 /* Changed lines. */ +#define L_DELETED 2 /* Deleted lines. */ +#define L_JOINED 3 /* Joined lines. */ +#define L_MOVED 4 /* Moved lines. */ +#define L_LSHIFT 5 /* Left shift lines. */ +#define L_RSHIFT 6 /* Right shift lines. */ +#define L_YANKED 7 /* Yanked lines. */ + recno_t rptlchange; /* Ex/vi: last L_CHANGED lno. */ + recno_t rptlines[L_YANKED + 1];/* Ex/vi: lines changed by last op. */ + + FILE *stdfp; /* Ex output file pointer. */ + + char *if_name; /* Ex input file name, for messages. */ + recno_t if_lno; /* Ex input file line, for messages. */ + + fd_set rdfd; /* Ex/vi: read fd select mask. */ + + TEXTH __tiq; /* Ex/vi: text input queue. */ + TEXTH *tiqp; /* Ex/vi: text input queue reference. */ + + SCRIPT *script; /* Vi: script mode information .*/ + + recno_t defscroll; /* Vi: ^D, ^U scroll information. */ + + struct timeval busy_tod; /* ITIMER_REAL: busy time-of-day. */ + char const *busy_msg; /* ITIMER_REAL: busy message. */ + + /* Display character. */ + CHAR_T cname[MAX_CHARACTER_COLUMNS + 1]; + size_t clen; /* Length of display character. */ + +#define MAX_MODE_NAME 12 + char *showmode; /* Mode. */ + + void *ex_private; /* Ex private area. */ + void *sex_private; /* Ex screen private area. */ + void *vi_private; /* Vi private area. */ + void *svi_private; /* Vi curses screen private area. */ + void *xaw_private; /* Vi XAW screen private area. */ + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ + char *alt_name; /* Ex/vi: alternate file name. */ + + /* Ex/vi: search/substitute info. */ + regex_t sre; /* Last search RE. */ + regex_t subre; /* Last substitute RE. */ + enum direction searchdir; /* File search direction. */ + char *repl; /* Substitute replacement. */ + size_t repl_len; /* Substitute replacement length.*/ + size_t *newl; /* Newline offset array. */ + size_t newl_len; /* Newline array size. */ + size_t newl_cnt; /* Newlines in replacement. */ + u_char c_suffix; /* Edcompatible 'c' suffix value. */ + u_char g_suffix; /* Edcompatible 'g' suffix value. */ + + u_int saved_vi_mode; /* Saved vi display type. */ + + OPTION opts[O_OPTIONCOUNT]; /* Options. */ + +/* + * SCREEN SUPPORT ROUTINES. + * + * A SCR * MUST be the first argument to these routines. + */ + /* Ring the screen bell. */ + void (*s_bell) __P((SCR *)); + /* Background the screen. */ + int (*s_bg) __P((SCR *)); + /* Put up a busy message. */ + int (*s_busy) __P((SCR *, char const *)); + /* Change a screen line. */ + int (*s_change) __P((SCR *, EXF *, recno_t, enum operation)); + /* Clear the screen. */ + int (*s_clear) __P((SCR *)); + /* Return column close to specified. */ + size_t (*s_colpos) __P((SCR *, EXF *, recno_t, size_t)); + /* Return the logical cursor column. */ + int (*s_column) __P((SCR *, EXF *, size_t *)); + enum confirm /* Confirm an action with the user. */ + (*s_confirm) __P((SCR *, EXF *, MARK *, MARK *)); + /* Change the relative screen size. */ + int (*s_crel) __P((SCR *, long)); + /* Edit a file. */ + int (*s_edit) __P((SCR *, EXF *)); + /* End a screen. */ + int (*s_end) __P((SCR *)); + /* Run a single ex command. */ + int (*s_ex_cmd) __P((SCR *, EXF *, EXCMDARG *, MARK *)); + /* Run user's ex commands. */ + int (*s_ex_run) __P((SCR *, EXF *, MARK *)); + /* Screen's ex write function. */ + int (*s_ex_write) __P((void *, const char *, int)); + /* Foreground the screen. */ + int (*s_fg) __P((SCR *, CHAR_T *)); + /* Fill the screen's map. */ + int (*s_fill) __P((SCR *, EXF *, recno_t, enum position)); + enum input /* Get a line from the user. */ + (*s_get) __P((SCR *, EXF *, TEXTH *, ARG_CHAR_T, u_int)); + enum input /* Get a key from the user. */ + (*s_key_read) __P((SCR *, int *, struct timeval *)); + /* Map a function key. */ + int (*s_fmap) __P((SCR *, + enum seqtype, CHAR_T *, size_t, CHAR_T *, size_t)); + /* Tell the screen an option changed. */ + int (*s_optchange) __P((SCR *, int)); + /* Return column at screen position. */ + int (*s_position) __P((SCR *, EXF *, + MARK *, u_long, enum position)); + /* Change the absolute screen size. */ + int (*s_rabs) __P((SCR *, long, enum adjust)); + /* Return column close to selection. */ + size_t (*s_rcm) __P((SCR *, EXF *, recno_t)); + /* Refresh the screen. */ + int (*s_refresh) __P((SCR *, EXF *)); + /* Move down the screen. */ + int (*s_scroll) __P((SCR *, EXF *, MARK *, recno_t, enum sctype)); + /* Split the screen. */ + int (*s_split) __P((SCR *, ARGS *[], int)); + /* Suspend the screen. */ + int (*s_suspend) __P((SCR *)); + /* Set the window size. */ + int (*s_window) __P((SCR *, int)); + +/* Editor screens. */ +#define S_EX 0x0000001 /* Ex screen. */ +#define S_VI_CURSES 0x0000002 /* Vi: curses screen. */ +#define S_VI_XAW 0x0000004 /* Vi: Athena widgets screen. */ + +#define IN_EX_MODE(sp) /* If in ex mode. */ \ + (F_ISSET(sp, S_EX)) +#define IN_VI_MODE(sp) /* If in vi mode. */ \ + (F_ISSET(sp, S_VI_CURSES | S_VI_XAW)) +#define S_SCREENS /* Screens. */ \ + (S_EX | S_VI_CURSES | S_VI_XAW) + +/* Major screen/file changes. */ +#define S_EXIT 0x0000008 /* Exiting (not forced). */ +#define S_EXIT_FORCE 0x0000010 /* Exiting (forced). */ +#define S_FSWITCH 0x0000020 /* Switch files. */ +#define S_SSWITCH 0x0000040 /* Switch screens. */ +#define S_MAJOR_CHANGE /* Screen or file changes. */ \ + (S_EXIT | S_EXIT_FORCE | S_FSWITCH | S_SSWITCH) + +#define S_ARGNOFREE 0x0000080 /* Argument list wasn't allocated. */ +#define S_ARGRECOVER 0x0000100 /* Argument list is recovery files. */ +#define S_BELLSCHED 0x0000200 /* Bell scheduled. */ +#define S_CONTINUE 0x0000400 /* Need to ask the user to continue. */ +#define S_EXSILENT 0x0000800 /* Ex batch script. */ +#define S_GLOBAL 0x0001000 /* Doing a global command. */ +#define S_INPUT 0x0002000 /* Doing text input. */ +#define S_INTERRUPTED 0x0004000 /* If have been interrupted. */ +#define S_INTERRUPTIBLE 0x0008000 /* If can be interrupted. */ +#define S_IVIDEO 0x0010000 /* Display in inverse video. */ +#define S_REDRAW 0x0020000 /* Redraw the screen. */ +#define S_REFORMAT 0x0040000 /* Reformat the screen. */ +#define S_REFRESH 0x0080000 /* Refresh the screen. */ +#define S_RENUMBER 0x0100000 /* Renumber the screen. */ +#define S_RESIZE 0x0200000 /* Resize the screen. */ +#define S_SCRIPT 0x0400000 /* Window is a shell script. */ +#define S_SRE_SET 0x0800000 /* The search RE has been set. */ +#define S_SUBRE_SET 0x1000000 /* The substitute RE has been set. */ +#define S_UPDATE_MODE 0x2000000 /* Don't repaint modeline. */ +#define S_VLITONLY 0x4000000 /* ^V literal next only. */ + u_int32_t flags; +}; + +/* + * Signals/timers have no structure, so it's all here. + * + * Block all signals that are being handled. Used to keep the underlying DB + * system calls from being interrupted and not restarted, as it could cause + * consistency problems. Also used when vi forks child processes, to avoid + * a signal arriving after the fork and before the exec, causing both parent + * and child to attempt recovery processing. + */ +#define SIGBLOCK(gp) \ + (void)sigprocmask(SIG_BLOCK, &(gp)->blockset, NULL); +#define SIGUNBLOCK(gp) \ + (void)sigprocmask(SIG_UNBLOCK, &(gp)->blockset, NULL); + +void busy_off __P((SCR *)); +int busy_on __P((SCR *, char const *)); +void sig_end __P((void)); +int sig_init __P((SCR *)); + +/* Generic routines to start/stop a screen. */ +int screen_end __P((SCR *)); +int screen_init __P((SCR *, SCR **, u_int)); + +/* Public interfaces to the underlying screens. */ +int ex_screen_copy __P((SCR *, SCR *)); +int ex_screen_end __P((SCR *)); +int ex_screen_init __P((SCR *)); +int sex_screen_copy __P((SCR *, SCR *)); +int sex_screen_end __P((SCR *)); +int sex_screen_init __P((SCR *)); +int svi_screen_copy __P((SCR *, SCR *)); +int svi_screen_end __P((SCR *)); +int svi_screen_init __P((SCR *)); +int v_screen_copy __P((SCR *, SCR *)); +int v_screen_end __P((SCR *)); +int v_screen_init __P((SCR *)); +int xaw_screen_copy __P((SCR *, SCR *)); +int xaw_screen_end __P((SCR *)); +int xaw_screen_init __P((SCR *)); diff --git a/usr.bin/vi/common/search.c b/usr.bin/vi/common/search.c new file mode 100644 index 0000000..72d9e4b --- /dev/null +++ b/usr.bin/vi/common/search.c @@ -0,0 +1,833 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)search.c 8.46 (Berkeley) 7/2/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +static int check_delta __P((SCR *, EXF *, long, recno_t)); +static int ctag_conv __P((SCR *, char **, int *)); +static int get_delta __P((SCR *, char **, long *, u_int *)); +static int resetup __P((SCR *, regex_t **, enum direction, + char *, char **, long *, u_int *)); + +/* + * resetup -- + * Set up a search for a regular expression. + */ +static int +resetup(sp, rep, dir, ptrn, epp, deltap, flagp) + SCR *sp; + regex_t **rep; + enum direction dir; + char *ptrn, **epp; + long *deltap; + u_int *flagp; +{ + u_int flags; + int delim, eval, re_flags, replaced; + char *p, *t; + + /* Set return information the default. */ + *deltap = 0; + + /* + * Use saved pattern if no pattern supplied, or if only a delimiter + * character is supplied. Only the pattern was saved, historic vi + * did not reuse any delta supplied. + */ + flags = *flagp; + if (ptrn == NULL) + goto prev; + if (ptrn[1] == '\0') { + if (epp != NULL) + *epp = ptrn + 1; + goto prev; + } + if (ptrn[0] == ptrn[1] && ptrn[2] == '\0') { + if (epp != NULL) + *epp = ptrn + 2; +prev: if (!F_ISSET(sp, S_SRE_SET)) { + msgq(sp, M_ERR, "No previous search pattern"); + return (1); + } + *rep = &sp->sre; + + /* Empty patterns set the direction. */ + if (LF_ISSET(SEARCH_SET)) { + F_SET(sp, S_SRE_SET); + sp->searchdir = dir; + sp->sre = **rep; + } + return (0); + } + + re_flags = 0; /* Set RE flags. */ + if (O_ISSET(sp, O_EXTENDED)) + re_flags |= REG_EXTENDED; + if (O_ISSET(sp, O_IGNORECASE)) + re_flags |= REG_ICASE; + + replaced = 0; + if (LF_ISSET(SEARCH_PARSE)) { /* Parse the string. */ + /* Set delimiter. */ + delim = *ptrn++; + + /* Find terminating delimiter, handling escaped delimiters. */ + for (p = t = ptrn;;) { + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + *t = '\0'; + break; + } + if (p[1] == delim && p[0] == '\\') + ++p; + *t++ = *p++; + } + + /* + * If characters after the terminating delimiter, it may + * be an error, or may be an offset. In either case, we + * return the end of the string, whatever it may be. + */ + if (*p) { + if (get_delta(sp, &p, deltap, flagp)) + return (1); + if (*p && LF_ISSET(SEARCH_TERM)) { + msgq(sp, M_ERR, + "Characters after search string and/or delta"); + return (1); + } + } + if (epp != NULL) + *epp = p; + + /* Check for "/ " or other such silliness. */ + if (*ptrn == '\0') + goto prev; + + if (re_conv(sp, &ptrn, &replaced)) + return (1); + } else if (LF_ISSET(SEARCH_TAG)) { + if (ctag_conv(sp, &ptrn, &replaced)) + return (1); + re_flags &= ~(REG_EXTENDED | REG_ICASE); + } + + /* Compile the RE. */ + if (eval = regcomp(*rep, ptrn, re_flags)) + re_error(sp, eval, *rep); + else if (LF_ISSET(SEARCH_SET)) { + F_SET(sp, S_SRE_SET); + sp->searchdir = dir; + sp->sre = **rep; + } + + /* Free up any extra memory. */ + if (replaced) + FREE_SPACE(sp, ptrn, 0); + return (eval); +} + +/* + * ctag_conv -- + * Convert a tags search path into something that the POSIX + * 1003.2 RE functions can handle. + */ +static int +ctag_conv(sp, ptrnp, replacedp) + SCR *sp; + char **ptrnp; + int *replacedp; +{ + size_t blen, len; + int lastdollar; + char *bp, *p, *t; + + *replacedp = 0; + + len = strlen(p = *ptrnp); + + /* Max memory usage is 2 times the length of the string. */ + GET_SPACE_RET(sp, bp, blen, len * 2); + + t = bp; + + /* The last character is a '/' or '?', we just strip it. */ + if (p[len - 1] == '/' || p[len - 1] == '?') + p[len - 1] = '\0'; + + /* The next-to-last character is a '$', and it's magic. */ + if (p[len - 2] == '$') { + lastdollar = 1; + p[len - 2] = '\0'; + } else + lastdollar = 0; + + /* The first character is a '/' or '?', we just strip it. */ + if (p[0] == '/' || p[0] == '?') + ++p; + + /* The second character is a '^', and it's magic. */ + if (p[0] == '^') + *t++ = *p++; + + /* + * Escape every other magic character we can find, stripping the + * backslashes ctags inserts to escape the search delimiter + * characters. + */ + while (p[0]) { + /* Ctags escapes the search delimiter characters. */ + if (p[0] == '\\' && (p[1] == '/' || p[1] == '?')) + ++p; + else if (strchr("^.[]$*", p[0])) + *t++ = '\\'; + *t++ = *p++; + } + if (lastdollar) + *t++ = '$'; + *t++ = '\0'; + + *ptrnp = bp; + *replacedp = 1; + return (0); +} + +#define EMPTYMSG "File empty; nothing to search" +#define EOFMSG "Reached end-of-file without finding the pattern" +#define NOTFOUND "Pattern not found" +#define SOFMSG "Reached top-of-file without finding the pattern" +#define WRAPMSG "Search wrapped" + +int +f_search(sp, ep, fm, rm, ptrn, eptrn, flagp) + SCR *sp; + EXF *ep; + MARK *fm, *rm; + char *ptrn, **eptrn; + u_int *flagp; +{ + regmatch_t match[1]; + regex_t *re, lre; + recno_t lno; + size_t coff, len; + long delta; + u_int flags; + int btear, eval, rval, wrapped; + char *l; + + if (file_lline(sp, ep, &lno)) + return (1); + flags = *flagp; + if (lno == 0) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, EMPTYMSG); + return (1); + } + + re = &lre; + if (resetup(sp, &re, FORWARD, ptrn, eptrn, &delta, flagp)) + return (1); + + /* + * Start searching immediately after the cursor. If at the end of the + * line, start searching on the next line. This is incompatible (read + * bug fix) with the historic vi -- searches for the '$' pattern never + * moved forward, and "-t foo" didn't work if "foo" was the first thing + * in the file. + */ + if (LF_ISSET(SEARCH_FILE)) { + lno = 1; + coff = 0; + } else { + if ((l = file_gline(sp, ep, fm->lno, &len)) == NULL) { + GETLINE_ERR(sp, fm->lno); + return (1); + } + if (fm->cno + 1 >= len) { + if (fm->lno == lno) { + if (!O_ISSET(sp, O_WRAPSCAN)) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, EOFMSG); + return (1); + } + lno = 1; + } else + lno = fm->lno + 1; + coff = 0; + } else { + lno = fm->lno; + coff = fm->cno + 1; + } + } + + /* Turn on busy message. */ + btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching..."); + + for (rval = 1, wrapped = 0;; ++lno, coff = 0) { + if (INTERRUPTED(sp)) { + msgq(sp, M_INFO, "Interrupted."); + break; + } + if (wrapped && lno > fm->lno || + (l = file_gline(sp, ep, lno, &len)) == NULL) { + if (wrapped) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, NOTFOUND); + break; + } + if (!O_ISSET(sp, O_WRAPSCAN)) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, EOFMSG); + break; + } + lno = 0; + wrapped = 1; + continue; + } + + /* If already at EOL, just keep going. */ + if (len && coff == len) + continue; + + /* Set the termination. */ + match[0].rm_so = coff; + match[0].rm_eo = len; + +#if defined(DEBUG) && 0 + TRACE(sp, "F search: %lu from %u to %u\n", + lno, coff, len ? len - 1 : len); +#endif + /* Search the line. */ + eval = regexec(re, l, 1, match, + (match[0].rm_so == 0 ? 0 : REG_NOTBOL) | REG_STARTEND); + if (eval == REG_NOMATCH) + continue; + if (eval != 0) { + re_error(sp, eval, re); + break; + } + + /* Warn if wrapped. */ + if (wrapped && O_ISSET(sp, O_WARN) && LF_ISSET(SEARCH_MSG)) + msgq(sp, M_VINFO, WRAPMSG); + + /* + * If an offset, see if it's legal. It's possible to match + * past the end of the line with $, so check for that case. + */ + if (delta) { + if (check_delta(sp, ep, delta, lno)) + break; + rm->lno = delta + lno; + rm->cno = 0; + } else { +#if defined(DEBUG) && 0 + TRACE(sp, "found: %qu to %qu\n", + match[0].rm_so, match[0].rm_eo); +#endif + rm->lno = lno; + rm->cno = match[0].rm_so; + + /* + * If a change command, it's possible to move beyond + * the end of a line. Historic vi generally got this + * wrong (try "c?$<cr>"). Not all that sure this gets + * it right, there are lots of strange cases. + */ + if (!LF_ISSET(SEARCH_EOL) && rm->cno >= len) + rm->cno = len ? len - 1 : 0; + } + rval = 0; + break; + } + + /* Turn off busy message, interrupts. */ + if (btear) + busy_off(sp); + return (rval); +} + +int +b_search(sp, ep, fm, rm, ptrn, eptrn, flagp) + SCR *sp; + EXF *ep; + MARK *fm, *rm; + char *ptrn, **eptrn; + u_int *flagp; +{ + regmatch_t match[1]; + regex_t *re, lre; + recno_t lno; + size_t coff, len, last; + long delta; + u_int flags; + int btear, eval, rval, wrapped; + char *l; + + if (file_lline(sp, ep, &lno)) + return (1); + flags = *flagp; + if (lno == 0) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, EMPTYMSG); + return (1); + } + + re = &lre; + if (resetup(sp, &re, BACKWARD, ptrn, eptrn, &delta, flagp)) + return (1); + + /* If in the first column, start searching on the previous line. */ + if (fm->cno == 0) { + if (fm->lno == 1) { + if (!O_ISSET(sp, O_WRAPSCAN)) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, SOFMSG); + return (1); + } + } else + lno = fm->lno - 1; + } else + lno = fm->lno; + + /* Turn on busy message. */ + btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching..."); + + for (rval = 1, wrapped = 0, coff = fm->cno;; --lno, coff = 0) { + if (INTERRUPTED(sp)) { + msgq(sp, M_INFO, "Interrupted."); + break; + } + if (wrapped && lno < fm->lno || lno == 0) { + if (wrapped) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, NOTFOUND); + break; + } + if (!O_ISSET(sp, O_WRAPSCAN)) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, SOFMSG); + break; + } + if (file_lline(sp, ep, &lno)) + goto err; + if (lno == 0) { + if (LF_ISSET(SEARCH_MSG)) + msgq(sp, M_INFO, EMPTYMSG); + break; + } + ++lno; + wrapped = 1; + continue; + } + + if ((l = file_gline(sp, ep, lno, &len)) == NULL) + goto err; + + /* Set the termination. */ + match[0].rm_so = 0; + match[0].rm_eo = len; + +#if defined(DEBUG) && 0 + TRACE(sp, "B search: %lu from 0 to %qu\n", lno, match[0].rm_eo); +#endif + /* Search the line. */ + eval = regexec(re, l, 1, match, + (match[0].rm_eo == len ? 0 : REG_NOTEOL) | REG_STARTEND); + if (eval == REG_NOMATCH) + continue; + if (eval != 0) { + re_error(sp, eval, re); + break; + } + + /* Check for a match starting past the cursor. */ + if (coff != 0 && match[0].rm_so >= coff) + continue; + + /* Warn if wrapped. */ + if (wrapped && O_ISSET(sp, O_WARN) && LF_ISSET(SEARCH_MSG)) + msgq(sp, M_VINFO, WRAPMSG); + + if (delta) { + if (check_delta(sp, ep, delta, lno)) + break; + rm->lno = delta + lno; + rm->cno = 0; + } else { +#if defined(DEBUG) && 0 + TRACE(sp, "found: %qu to %qu\n", + match[0].rm_so, match[0].rm_eo); +#endif + /* + * We now have the first match on the line. Step + * through the line character by character until we + * find the last acceptable match. This is painful, + * we need a better interface to regex to make this + * work. + */ + for (;;) { + last = match[0].rm_so++; + if (match[0].rm_so >= len) + break; + match[0].rm_eo = len; + eval = regexec(re, l, 1, match, + (match[0].rm_so == 0 ? 0 : REG_NOTBOL) | + REG_STARTEND); + if (eval == REG_NOMATCH) + break; + if (eval != 0) { + re_error(sp, eval, re); + goto err; + } + if (coff && match[0].rm_so >= coff) + break; + } + rm->lno = lno; + + /* See comment in f_search(). */ + if (!LF_ISSET(SEARCH_EOL) && last >= len) + rm->cno = len ? len - 1 : 0; + else + rm->cno = last; + } + rval = 0; + break; + } + + /* Turn off busy message, interrupts. */ +err: if (btear) + busy_off(sp); + return (rval); +} + +/* + * re_conv -- + * Convert vi's regular expressions into something that the + * the POSIX 1003.2 RE functions can handle. + * + * There are three conversions we make to make vi's RE's (specifically + * the global, search, and substitute patterns) work with POSIX RE's. + * + * 1: If O_MAGIC is not set, strip backslashes from the magic character + * set (.[]*~) that have them, and add them to the ones that don't. + * 2: If O_MAGIC is not set, the string "\~" is replaced with the text + * from the last substitute command's replacement string. If O_MAGIC + * is set, it's the string "~". + * 3: The pattern \<ptrn\> does "word" searches, convert it to use the + * new RE escapes. + */ +int +re_conv(sp, ptrnp, replacedp) + SCR *sp; + char **ptrnp; + int *replacedp; +{ + size_t blen, needlen; + int magic; + char *bp, *p, *t; + + /* + * First pass through, we figure out how much space we'll need. + * We do it in two passes, on the grounds that most of the time + * the user is doing a search and won't have magic characters. + * That way we can skip the malloc and memmove's. + */ + for (p = *ptrnp, magic = 0, needlen = 0; *p != '\0'; ++p) + switch (*p) { + case '\\': + switch (*++p) { + case '<': + magic = 1; + needlen += sizeof(RE_WSTART); + break; + case '>': + magic = 1; + needlen += sizeof(RE_WSTOP); + break; + case '~': + if (!O_ISSET(sp, O_MAGIC)) { + magic = 1; + needlen += sp->repl_len; + } + break; + case '.': + case '[': + case ']': + case '*': + if (!O_ISSET(sp, O_MAGIC)) { + magic = 1; + needlen += 1; + } + break; + default: + needlen += 2; + } + break; + case '~': + if (O_ISSET(sp, O_MAGIC)) { + magic = 1; + needlen += sp->repl_len; + } + break; + case '.': + case '[': + case ']': + case '*': + if (!O_ISSET(sp, O_MAGIC)) { + magic = 1; + needlen += 2; + } + break; + default: + needlen += 1; + break; + } + + if (!magic) { + *replacedp = 0; + return (0); + } + + /* + * Get enough memory to hold the final pattern. + * + * XXX + * It's nul-terminated, for now. + */ + GET_SPACE_RET(sp, bp, blen, needlen + 1); + + for (p = *ptrnp, t = bp; *p != '\0'; ++p) + switch (*p) { + case '\\': + switch (*++p) { + case '<': + memmove(t, RE_WSTART, sizeof(RE_WSTART) - 1); + t += sizeof(RE_WSTART) - 1; + break; + case '>': + memmove(t, RE_WSTOP, sizeof(RE_WSTOP) - 1); + t += sizeof(RE_WSTOP) - 1; + break; + case '~': + if (O_ISSET(sp, O_MAGIC)) + *t++ = '~'; + else { + memmove(t, sp->repl, sp->repl_len); + t += sp->repl_len; + } + break; + case '.': + case '[': + case ']': + case '*': + if (O_ISSET(sp, O_MAGIC)) + *t++ = '\\'; + *t++ = *p; + break; + default: + *t++ = '\\'; + *t++ = *p; + } + break; + case '~': + if (O_ISSET(sp, O_MAGIC)) { + memmove(t, sp->repl, sp->repl_len); + t += sp->repl_len; + } else + *t++ = '~'; + break; + case '.': + case '[': + case ']': + case '*': + if (!O_ISSET(sp, O_MAGIC)) + *t++ = '\\'; + *t++ = *p; + break; + default: + *t++ = *p; + break; + } + *t = '\0'; + + *ptrnp = bp; + *replacedp = 1; + return (0); +} + +/* + * get_delta -- + * Get a line delta. The trickiness is that the delta can be pretty + * complicated, i.e. "+3-2+3++- ++" is allowed. + * + * !!! + * In historic vi, if you had a delta on a search pattern which was used as + * a motion command, the command became a line mode command regardless of the + * cursor positions. A fairly common trick is to use a delta of "+0" to make + * the command a line mode command. This is the only place that knows about + * delta's, so we set the return flag information here. + */ +static int +get_delta(sp, dp, valp, flagp) + SCR *sp; + char **dp; + long *valp; + u_int *flagp; +{ + char *p; + long val, tval; + + for (tval = 0, p = *dp; *p != '\0'; *flagp |= SEARCH_DELTA) { + if (isblank(*p)) { + ++p; + continue; + } + if (*p == '+' || *p == '-') { + if (!isdigit(*(p + 1))) { + if (*p == '+') { + if (tval == LONG_MAX) + goto overflow; + ++tval; + } else { + if (tval == LONG_MIN) + goto underflow; + --tval; + } + ++p; + continue; + } + } else + if (!isdigit(*p)) + break; + + errno = 0; + val = strtol(p, &p, 10); + if (errno == ERANGE) { + if (val == LONG_MAX) +overflow: msgq(sp, M_ERR, "Delta value overflow"); + else if (val == LONG_MIN) +underflow: msgq(sp, M_ERR, "Delta value underflow"); + else + msgq(sp, M_SYSERR, NULL); + return (1); + } + if (val >= 0) { + if (LONG_MAX - val < tval) + goto overflow; + } else + if (-(LONG_MIN - tval) > val) + goto underflow; + tval += val; + } + *dp = p; + *valp = tval; + return (0); +} + +/* + * check_delta -- + * Check a line delta to see if it's legal. + */ +static int +check_delta(sp, ep, delta, lno) + SCR *sp; + EXF *ep; + long delta; + recno_t lno; +{ + /* A delta can overflow a record number. */ + if (delta < 0) { + if (lno < LONG_MAX && delta >= (long)lno) { + msgq(sp, M_ERR, "Search offset before line 1"); + return (1); + } + } else { + if (ULONG_MAX - lno < delta) { + msgq(sp, M_ERR, "Delta value overflow"); + return (1); + } + if (file_gline(sp, ep, lno + delta, NULL) == NULL) { + msgq(sp, M_ERR, "Search offset past end-of-file"); + return (1); + } + } + return (0); +} + +/* + * re_error -- + * Report a regular expression error. + */ +void +re_error(sp, errcode, preg) + SCR *sp; + int errcode; + regex_t *preg; +{ + size_t s; + char *oe; + + s = regerror(errcode, preg, "", 0); + if ((oe = malloc(s)) == NULL) + msgq(sp, M_SYSERR, NULL); + else { + (void)regerror(errcode, preg, oe, s); + msgq(sp, M_ERR, "RE error: %s", oe); + } + free(oe); +} diff --git a/usr.bin/vi/common/search.h b/usr.bin/vi/common/search.h new file mode 100644 index 0000000..1483a04 --- /dev/null +++ b/usr.bin/vi/common/search.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)search.h 8.9 (Berkeley) 3/16/94 + */ + +#define RE_WSTART "[[:<:]]" /* Not-in-word search patterns. */ +#define RE_WSTOP "[[:>:]]" + +#define SEARCH_DELTA 0x001 /* A delta part of the search.*/ +#define SEARCH_EOL 0x002 /* Offset past EOL is okay. */ +#define SEARCH_FILE 0x004 /* Search the entire file. */ +#define SEARCH_MSG 0x008 /* Display search warning messages. */ +#define SEARCH_PARSE 0x010 /* Parse the search pattern. */ +#define SEARCH_SET 0x020 /* Set search direction. */ +#define SEARCH_TAG 0x040 /* Search pattern is a tag pattern. */ +#define SEARCH_TERM 0x080 /* Search pattern should terminate. */ + +enum direction { NOTSET, FORWARD, BACKWARD }; + +/* Search functions. */ +int b_search __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *)); +int f_search __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *)); +int re_conv __P((SCR *, char **, int *)); +void re_error __P((SCR *, int, regex_t *)); diff --git a/usr.bin/vi/common/seq.c b/usr.bin/vi/common/seq.c new file mode 100644 index 0000000..7b21708 --- /dev/null +++ b/usr.bin/vi/common/seq.c @@ -0,0 +1,350 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)seq.c 8.30 (Berkeley) 7/15/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * seq_set -- + * Internal version to enter a sequence. + */ +int +seq_set(sp, name, nlen, input, ilen, output, olen, stype, flags) + SCR *sp; + char *name, *input, *output; + size_t nlen, ilen, olen; + enum seqtype stype; + int flags; +{ + SEQ *lastqp, *qp; + CHAR_T *p; + int sv_errno; + + /* + * An input string must always be present. The output string + * can be NULL, when set internally, that's how we throw away + * input. + * + * Just replace the output field if the string already set. + */ + if ((qp = seq_find(sp, &lastqp, input, ilen, stype, NULL)) != NULL) { + if (output == NULL || olen == 0) { + p = NULL; + olen = 0; + } else if ((p = v_strdup(sp, output, olen)) == NULL) { + sv_errno = errno; + goto mem1; + } + if (qp->output != NULL) + free(qp->output); + qp->olen = olen; + qp->output = p; + return (0); + } + + /* Allocate and initialize SEQ structure. */ + CALLOC(sp, qp, SEQ *, 1, sizeof(SEQ)); + if (qp == NULL) { + sv_errno = errno; + goto mem1; + } + + /* Name. */ + if (name == NULL || nlen == 0) + qp->name = NULL; + else if ((qp->name = v_strdup(sp, name, nlen)) == NULL) { + sv_errno = errno; + goto mem2; + } + qp->nlen = nlen; + + /* Input. */ + if ((qp->input = v_strdup(sp, input, ilen)) == NULL) { + sv_errno = errno; + goto mem3; + } + qp->ilen = ilen; + + /* Output. */ + if (output == NULL) { + qp->output = NULL; + olen = 0; + } else if ((qp->output = v_strdup(sp, output, olen)) == NULL) { + sv_errno = errno; + free(qp->input); +mem3: if (qp->name != NULL) + free(qp->name); +mem2: FREE(qp, sizeof(SEQ)); +mem1: errno = sv_errno; + msgq(sp, M_SYSERR, NULL); + return (1); + } + qp->olen = olen; + + /* Type, flags. */ + qp->stype = stype; + qp->flags = flags; + + /* Link into the chain. */ + if (lastqp == NULL) { + LIST_INSERT_HEAD(&sp->gp->seqq, qp, q); + } else { + LIST_INSERT_AFTER(lastqp, qp, q); + } + + /* Set the fast lookup bit. */ + bit_set(sp->gp->seqb, qp->input[0]); + + return (0); +} + +/* + * seq_delete -- + * Delete a sequence. + */ +int +seq_delete(sp, input, ilen, stype) + SCR *sp; + char *input; + size_t ilen; + enum seqtype stype; +{ + SEQ *qp; + + if ((qp = seq_find(sp, NULL, input, ilen, stype, NULL)) == NULL) + return (1); + return (seq_mdel(qp)); +} + +/* + * seq_mdel -- + * Delete a map entry, without lookup. + */ +int +seq_mdel(qp) + SEQ *qp; +{ + LIST_REMOVE(qp, q); + if (qp->name != NULL) + free(qp->name); + free(qp->input); + if (qp->output != NULL) + free(qp->output); + FREE(qp, sizeof(SEQ)); + return (0); +} + +/* + * seq_find -- + * Search the sequence list for a match to a buffer, if ispartial + * isn't NULL, partial matches count. + */ +SEQ * +seq_find(sp, lastqp, input, ilen, stype, ispartialp) + SCR *sp; + SEQ **lastqp; + char *input; + size_t ilen; + enum seqtype stype; + int *ispartialp; +{ + SEQ *lqp, *qp; + int diff; + + /* + * Ispartialp is a location where we return if there was a + * partial match, i.e. if the string were extended it might + * match something. + * + * XXX + * Overload the meaning of ispartialp; only the terminal key + * search doesn't want the search limited to complete matches, + * i.e. ilen may be longer than the match. + */ + if (ispartialp != NULL) + *ispartialp = 0; + for (lqp = NULL, qp = sp->gp->seqq.lh_first; + qp != NULL; lqp = qp, qp = qp->q.le_next) { + /* Fast checks on the first character and type. */ + if (qp->input[0] > input[0]) + break; + if (qp->input[0] < input[0] || + qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP)) + continue; + + /* Check on the real comparison. */ + diff = memcmp(qp->input, input, MIN(qp->ilen, ilen)); + if (diff > 0) + break; + if (diff < 0) + continue; + /* + * If the entry is the same length as the string, return a + * match. If the entry is shorter than the string, return a + * match if called from the terminal key routine. Otherwise, + * keep searching for a complete match. + */ + if (qp->ilen <= ilen) { + if (qp->ilen == ilen || ispartialp != NULL) { + if (lastqp != NULL) + *lastqp = lqp; + return (qp); + } + continue; + } + /* + * If the entry longer than the string, return partial match + * if called from the terminal key routine. Otherwise, no + * match. + */ + if (ispartialp != NULL) + *ispartialp = 1; + break; + } + if (lastqp != NULL) + *lastqp = lqp; + return (NULL); +} + +/* + * seq_dump -- + * Display the sequence entries of a specified type. + */ +int +seq_dump(sp, stype, isname) + SCR *sp; + enum seqtype stype; + int isname; +{ + SEQ *qp; + int cnt, len, olen; + CHAR_T *p; + + cnt = 0; + for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) { + if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP)) + continue; + ++cnt; + for (p = qp->input, + olen = qp->ilen, len = 0; olen > 0; --olen, ++p) + len += ex_printf(EXCOOKIE, "%s", KEY_NAME(sp, *p)); + for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;) + len -= ex_printf(EXCOOKIE, " "); + + if (qp->output != NULL) + for (p = qp->output, + olen = qp->olen, len = 0; olen > 0; --olen, ++p) + len += + ex_printf(EXCOOKIE, "%s", KEY_NAME(sp, *p)); + else + len = 0; + + if (isname && qp->name != NULL) { + for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;) + len -= ex_printf(EXCOOKIE, " "); + for (p = qp->name, + olen = qp->nlen; olen > 0; --olen, ++p) + (void)ex_printf(EXCOOKIE, + "%s", KEY_NAME(sp, *p)); + } + (void)ex_printf(EXCOOKIE, "\n"); + } + return (cnt); +} + +/* + * seq_save -- + * Save the sequence entries to a file. + */ +int +seq_save(sp, fp, prefix, stype) + SCR *sp; + FILE *fp; + char *prefix; + enum seqtype stype; +{ + SEQ *qp; + size_t olen; + int ch; + char *p; + + /* Write a sequence command for all keys the user defined. */ + for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) { + if (stype != qp->stype || + F_ISSET(qp, SEQ_FUNCMAP) || !F_ISSET(qp, SEQ_USERDEF)) + continue; + if (prefix) + (void)fprintf(fp, "%s", prefix); + for (p = qp->input, olen = qp->ilen; olen > 0; --olen) { + ch = *p++; + if (ch == CH_LITERAL || ch == '|' || + isblank(ch) || KEY_VAL(sp, ch) == K_NL) + (void)putc(CH_LITERAL, fp); + (void)putc(ch, fp); + } + (void)putc(' ', fp); + if (qp->output != NULL) + for (p = qp->output, + olen = qp->olen; olen > 0; --olen) { + ch = *p++; + if (ch == CH_LITERAL || ch == '|' || + KEY_VAL(sp, ch) == K_NL) + (void)putc(CH_LITERAL, fp); + (void)putc(ch, fp); + } + (void)putc('\n', fp); + } + return (0); +} diff --git a/usr.bin/vi/common/seq.h b/usr.bin/vi/common/seq.h new file mode 100644 index 0000000..38c197c --- /dev/null +++ b/usr.bin/vi/common/seq.h @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)seq.h 8.11 (Berkeley) 7/17/94 + */ + +/* + * Map and abbreviation structures. + * + * The map structure is doubly linked list, sorted by input string and by + * input length within the string. (The latter is necessary so that short + * matches will happen before long matches when the list is searched.) + * Additionally, there is a bitmap which has bits set if there are entries + * starting with the corresponding character. This keeps us from walking + * the list unless it's necessary. + * + * The name and the output fields of a SEQ can be empty, i.e. NULL. + * Only the input field is required. + * + * XXX + * The fast-lookup bits are never turned off -- users don't usually unmap + * things, though, so it's probably not a big deal. + */ + /* Sequence type. */ +enum seqtype { SEQ_ABBREV, SEQ_COMMAND, SEQ_INPUT }; + +struct _seq { + LIST_ENTRY(_seq) q; /* Linked list of all sequences. */ + enum seqtype stype; /* Sequence type. */ + char *name; /* Sequence name (if any). */ + size_t nlen; /* Name length. */ + char *input; /* Sequence input keys. */ + size_t ilen; /* Input keys length. */ + char *output; /* Sequence output keys. */ + size_t olen; /* Output keys length. */ + +#define SEQ_FUNCMAP 0x01 /* If unresolved function key.*/ +#define SEQ_SCREEN 0x02 /* If screen specific. */ +#define SEQ_USERDEF 0x04 /* If user defined. */ + u_int8_t flags; +}; + +int seq_delete __P((SCR *, char *, size_t, enum seqtype)); +int seq_dump __P((SCR *, enum seqtype, int)); +SEQ *seq_find __P((SCR *, SEQ **, char *, size_t, enum seqtype, int *)); +void seq_init __P((SCR *)); +int seq_mdel __P((SEQ *)); +int seq_save __P((SCR *, FILE *, char *, enum seqtype)); +int seq_set __P((SCR *, char *, size_t, + char *, size_t, char *, size_t, enum seqtype, int)); diff --git a/usr.bin/vi/common/signal.c b/usr.bin/vi/common/signal.c new file mode 100644 index 0000000..68f2589 --- /dev/null +++ b/usr.bin/vi/common/signal.c @@ -0,0 +1,569 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)signal.c 8.32 (Berkeley) 7/23/94"; +#endif /* not lint */ + +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +static void h_alrm __P((int)); +static void h_hup __P((int)); +static void h_int __P((int)); +static void h_term __P((int)); +static void h_winch __P((int)); +static void sig_sync __P((int, u_int)); + +/* + * There are seven normally asynchronous actions about which vi cares: + * SIGALRM, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP and SIGWINCH. + * + * The assumptions: + * 1: The DB routines are not reentrant. + * 2: The curses routines may not be reentrant. + * + * SIGALRM, SIGHUP, SIGTERM + * Used for file recovery. The DB routines can't be reentered, so + * the vi routines that call DB block all three signals (see line.c). + * This means that DB routines can be called at interrupt time. + * + * SIGALRM + * Used to paint busy messages on the screen. The curses routines + * can't be reentered, so this function of SIGALRM can only be used + * in sections of code that do not use any curses functions (see + * busy_on, busy_off in signal.c). This means that curses can be + * called at interrupt time. + * + * SIGQUIT + * Disabled by the signal initialization routines. Historically, + * ^\ switched vi into ex mode, and we continue that practice. + * + * SIGWINCH: + * The interrupt routine sets a global bit which is checked by the + * key-read routine, so there are no reentrancy issues. This means + * that the screen will not resize until vi runs out of keys, but + * that doesn't seem like a problem. + * + * SIGINT and SIGTSTP are a much more difficult issue to resolve. Vi has + * to permit the user to interrupt long-running operations. Generally, a + * search, substitution or read/write is done on a large file, or, the user + * creates a key mapping with an infinite loop. This problem will become + * worse as more complex semantics are added to vi. There are four major + * solutions on the table, each of which have minor permutations. + * + * 1: Run in raw mode. + * + * The up side is that there's no asynchronous behavior to worry about, + * and obviously no reentrancy problems. The down side is that it's easy + * to misinterpret characters (e.g. :w big_file^Mi^V^C is going to look + * like an interrupt) and it's easy to get into places where we won't see + * interrupt characters (e.g. ":map a ixx^[hxxaXXX" infinitely loops in + * historic implementations of vi). Periodically reading the terminal + * input buffer might solve the latter problem, but it's not going to be + * pretty. + * + * Also, we're going to be checking for ^C's and ^Z's both, all over + * the place -- I hate to litter the source code with that. For example, + * the historic version of vi didn't permit you to suspend the screen if + * you were on the colon command line. This isn't right. ^Z isn't a vi + * command, it's a terminal event. (Dammit.) + * + * 2: Run in cbreak mode. There are two problems in this area. First, the + * current curses implementations (both System V and Berkeley) don't give + * you clean cbreak modes. For example, the IEXTEN bit is left on, turning + * on DISCARD and LNEXT. To clarify, what vi WANTS is 8-bit clean, with + * the exception that flow control and signals are turned on, and curses + * cbreak mode doesn't give you this. + * + * We can either set raw mode and twiddle the tty, or cbreak mode and + * twiddle the tty. I chose to use raw mode, on the grounds that raw + * mode is better defined and I'm less likely to be surprised by a curses + * implementation down the road. The twiddling consists of setting ISIG, + * IXON/IXOFF, and disabling some of the interrupt characters (see the + * comments in svi/svi_screen.c). This is all found in historic System + * V (SVID 3) and POSIX 1003.1-1992, so it should be fairly portable. + * + * The second problem is that vi permits you to enter literal signal + * characters, e.g. ^V^C. There are two possible solutions. First, you + * can turn off signals when you get a ^V, but that means that a network + * packet containing ^V and ^C will lose, since the ^C may take effect + * before vi reads the ^V. (This is particularly problematic if you're + * talking over a protocol that recognizes signals locally and sends OOB + * packets when it sees them.) Second, you can turn the ^C into a literal + * character in vi, but that means that there's a race between entering + * ^V<character>^C, i.e. the sequence may end up being ^V^C<character>. + * Also, the second solution doesn't work for flow control characters, as + * they aren't delivered to the program as signals. + * + * Generally, this is what historic vi did. (It didn't have the curses + * problems because it didn't use curses.) It entered signals following + * ^V characters into the input stream, (which is why there's no way to + * enter a literal flow control character). + * + * 3: Run in mostly raw mode; turn signals on when doing an operation the + * user might want to interrupt, but leave them off most of the time. + * + * This works well for things like file reads and writes. This doesn't + * work well for trying to detect infinite maps. The problem is that + * you can write the code so that you don't have to turn on interrupts + * per keystroke, but the code isn't pretty and it's hard to make sure + * that an optimization doesn't cover up an infinite loop. This also + * requires interaction or state between the vi parser and the key + * reading routines, as an infinite loop may still be returning keys + * to the parser. + * + * Also, if the user inserts an interrupt into the tty queue while the + * interrupts are turned off, the key won't be treated as an interrupt, + * and requiring the user to pound the keyboard to catch an interrupt + * window is nasty. + * + * 4: Run in mostly raw mode, leaving signals on all of the time. Done + * by setting raw mode, and twiddling the tty's termios ISIG bit. + * + * This works well for the interrupt cases, because the code only has + * to check to see if the interrupt flag has been set, and can otherwise + * ignore signals. It's also less likely that we'll miss a case, and we + * don't have to worry about synchronizing between the vi parser and the + * key read routines. + * + * The down side is that we have to turn signals off if the user wants + * to enter a literal character (e.g. ^V^C). If the user enters the + * combination fast enough, or as part of a single network packet, + * the text input routines will treat it as a signal instead of as a + * literal character. To some extent, we have this problem already, + * since we turn off flow control so that the user can enter literal + * XON/XOFF characters. + * + * This is probably the easiest to code, and provides the smoothest + * programming interface. + * + * There are a couple of other problems to consider. + * + * First, System V's curses doesn't handle SIGTSTP correctly. If you use the + * newterm() interface, the TSTP signal will leave you in raw mode, and the + * final endwin() will leave you in the correct shell mode. If you use the + * initscr() interface, the TSTP signal will return you to the correct shell + * mode, but the final endwin() will leave you in raw mode. There you have + * it: proof that drug testing is not making any significant headway in the + * computer industry. The 4BSD curses is deficient in that it does not have + * an interface to the terminal keypad. So, regardless, we have to do our + * own SIGTSTP handling. + * + * The problem with this is that if we do our own SIGTSTP handling, in either + * models #3 or #4, we're going to have to call curses routines at interrupt + * time, which means that we might be reentering curses, which is something we + * don't want to do. + * + * Second, SIGTSTP has its own little problems. It's broadcast to the entire + * process group, not sent to a single process. The scenario goes something + * like this: the shell execs the mail program, which execs vi. The user hits + * ^Z, and all three programs get the signal, in some random order. The mail + * program goes to sleep immediately (since it probably didn't have a SIGTSTP + * handler in place). The shell gets a SIGCHLD, does a wait, and finds out + * that the only child in its foreground process group (of which it's aware) + * is asleep. It then optionally resets the terminal (because the modes aren't + * how it left them), and starts prompting the user for input. The problem is + * that somewhere in the middle of all of this, vi is resetting the terminal, + * and getting ready to send a SIGTSTP to the process group in order to put + * itself to sleep. There's a solution to all of this: when vi starts, it puts + * itself into its own process group, and then only it (and possible child + * processes) receive the SIGTSTP. This permits it to clean up the terminal + * and switch back to the original process group, where it sends that process + * group a SIGTSTP, putting everyone to sleep and waking the shell. + * + * Third, handing SIGTSTP asynchronously is further complicated by the child + * processes vi may fork off. If vi calls ex, ex resets the terminal and + * starts running some filter, and SIGTSTP stops them both, vi has to know + * when it restarts that it can't repaint the screen until ex's child has + * finished running. This is solveable, but it's annoying. + * + * Well, somebody had to make a decision, and this is the way it's going to be + * (unless I get talked out of it). SIGINT is handled asynchronously, so + * that we can pretty much guarantee that the user can interrupt any operation + * at any time. SIGTSTP is handled synchronously, so that we don't have to + * reenter curses and so that we don't have to play the process group games. + * ^Z is recognized in the standard text input and command modes. (^Z should + * also be recognized during operations that may potentially take a long time. + * The simplest solution is probably to twiddle the tty, install a handler for + * SIGTSTP, and then restore normal tty modes when the operation is complete.) + */ + +/* + * sig_init -- + * Initialize signals. + */ +int +sig_init(sp) + SCR *sp; +{ + GS *gp; + struct sigaction act; + + /* Initialize the signals. */ + gp = sp->gp; + (void)sigemptyset(&gp->blockset); + + /* + * Use sigaction(2), not signal(3), since we don't always want to + * restart system calls. The example is when waiting for a command + * mode keystroke and SIGWINCH arrives. Try to set the restart bit + * (SA_RESTART) on SIGALRM anyway, it should result in a lot fewer + * interruptions. We also block every other signal that we can block + * when a signal arrives. This is because the signal functions call + * other nvi functions, which aren't guaranteed to be reentrant. + */ + +#ifndef SA_RESTART +#define SA_RESTART 0 +#endif +#define SETSIG(signal, flags, handler) { \ + if (sigaddset(&gp->blockset, signal)) \ + goto err; \ + act.sa_handler = handler; \ + sigfillset(&act.sa_mask); \ + act.sa_flags = flags; \ + if (sigaction(signal, &act, NULL)) \ + goto err; \ +} + SETSIG(SIGALRM, SA_RESTART, h_alrm); + SETSIG(SIGHUP, 0, h_hup); + SETSIG(SIGINT, 0, h_int); + SETSIG(SIGTERM, 0, h_term); + SETSIG(SIGWINCH, 0, h_winch); + return (0); + +err: msgq(sp, M_SYSERR, "signal init"); + return (1); +} + +/* + * sig_end -- + * End signal setup. + */ +void +sig_end() +{ + /* + * POSIX 1003.1-1990 requires that fork (and, presumably, vfork) clear + * pending alarms, and that the exec functions clear pending signals. + * In addition, after an exec, the child continues to ignore signals + * ignored in the parent, and the child's action for signals caught in + * the parent is set to the default action. So, as we currently don't + * ignore any signals, there's no cleanup to be done. This routine is + * left here as a stub function. + */ + return; +} + +/* + * busy_on -- + * Set a busy message timer. + */ +int +busy_on(sp, msg) + SCR *sp; + char const *msg; +{ + struct itimerval value; + struct timeval tod; + + /* + * Give the oldest busy message precedence, since it's + * the longer running operation. + */ + if (sp->busy_msg != NULL) + return (1); + + /* Get the current time of day, and create a target time. */ + if (gettimeofday(&tod, NULL)) + return (1); +#define USER_PATIENCE_USECS (8 * 100000L) + sp->busy_tod.tv_sec = tod.tv_sec; + sp->busy_tod.tv_usec = tod.tv_usec + USER_PATIENCE_USECS; + + /* We depend on this being an atomic instruction. */ + sp->busy_msg = msg; + + /* + * Busy messages turn around fast. Reset the timer regardless + * of its current state. + */ + value.it_value.tv_sec = 0; + value.it_value.tv_usec = USER_PATIENCE_USECS; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 0; + if (setitimer(ITIMER_REAL, &value, NULL)) + msgq(sp, M_SYSERR, "timer: setitimer"); + return (0); +} + +/* + * busy_off -- + * Turn off a busy message timer. + */ +void +busy_off(sp) + SCR *sp; +{ + /* We depend on this being an atomic instruction. */ + sp->busy_msg = NULL; +} + +/* + * rcv_on -- + * Turn on recovery timer. + */ +int +rcv_on(sp, ep) + SCR *sp; + EXF *ep; +{ + struct itimerval value; + struct timeval tod; + + /* Get the current time of day. */ + if (gettimeofday(&tod, NULL)) + return (1); + + /* Create target time of day. */ + ep->rcv_tod.tv_sec = tod.tv_sec + RCV_PERIOD; + ep->rcv_tod.tv_usec = 0; + + /* + * If there's a busy message happening, we're done, the + * interrupt handler will start our timer as necessary. + */ + if (sp->busy_msg != NULL) + return (0); + + value.it_value.tv_sec = RCV_PERIOD; + value.it_value.tv_usec = 0; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 0; + if (setitimer(ITIMER_REAL, &value, NULL)) { + msgq(sp, M_SYSERR, "timer: setitimer"); + return (1); + } + return (0); +} + +/* + * h_alrm -- + * Handle SIGALRM. + * + * There are two uses of the ITIMER_REAL timer (SIGALRM) in nvi. The first + * is to push the recovery information out to disk at periodic intervals. + * The second is to display a "busy" message if an operation takes more time + * that users are willing to wait before seeing something happen. The SCR + * structure has a wall clock timer structure for each of these. Since the + * busy timer has a much faster timeout than the recovery timer, most of the + * code ignores the recovery timer unless it's the only thing running. + * + * XXX + * It would be nice to reimplement this with two timers, a la POSIX 1003.1, + * but not many systems offer them yet. + */ +static void +h_alrm(signo) + int signo; +{ + struct itimerval value; + struct timeval ntod, tod; + SCR *sp; + EXF *ep; + int sverrno; + + sverrno = errno; + + /* XXX: Get the current time of day; if this fails, we're dead. */ + if (gettimeofday(&tod, NULL)) + goto ret; + + /* + * Fire any timers that are past due, or any that are due + * in a tenth of a second or less. + */ + for (ntod.tv_sec = 0, sp = __global_list->dq.cqh_first; + sp != (void *)&__global_list->dq; sp = sp->q.cqe_next) { + + /* Check the busy timer if the msg pointer is set. */ + if (sp->busy_msg == NULL) + goto skip_busy; + if (sp->busy_tod.tv_sec > tod.tv_sec || + sp->busy_tod.tv_sec == tod.tv_sec && + sp->busy_tod.tv_usec > tod.tv_usec && + sp->busy_tod.tv_usec - tod.tv_usec > 100000L) { + if (ntod.tv_sec == 0 || + ntod.tv_sec > sp->busy_tod.tv_sec || + ntod.tv_sec == sp->busy_tod.tv_sec && + ntod.tv_usec > sp->busy_tod.tv_usec) + ntod = sp->busy_tod; + } else { + (void)sp->s_busy(sp, sp->busy_msg); + sp->busy_msg = NULL; + } + + /* + * Sync the file if the recovery timer has fired. If + * the sync fails, we don't reschedule future sync's. + */ +skip_busy: ep = sp->ep; + if (ep->rcv_tod.tv_sec < tod.tv_sec || + ep->rcv_tod.tv_sec == tod.tv_sec && + ep->rcv_tod.tv_usec < tod.tv_usec + 100000L) { + if (rcv_sync(sp, ep, 0)) + continue; + ep->rcv_tod = tod; + ep->rcv_tod.tv_sec += RCV_PERIOD; + } + if (ntod.tv_sec == 0 || + ntod.tv_sec > ep->rcv_tod.tv_sec || + ntod.tv_sec == ep->rcv_tod.tv_sec && + ntod.tv_usec > ep->rcv_tod.tv_usec) + ntod = ep->rcv_tod; + } + + if (ntod.tv_sec == 0) + goto ret; + + /* XXX: Set the timer; if this fails, we're dead. */ + value.it_value.tv_sec = ntod.tv_sec - tod.tv_sec; + value.it_value.tv_usec = ntod.tv_usec - tod.tv_usec; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 0; + (void)setitimer(ITIMER_REAL, &value, NULL); + +ret: errno = sverrno; +} + +/* + * h_hup -- + * Handle SIGHUP. + */ +static void +h_hup(signo) + int signo; +{ + sig_sync(SIGHUP, RCV_EMAIL); + /* NOTREACHED */ +} + +/* + * h_int -- + * Handle SIGINT. + * + * XXX + * This isn't right if windows are independent of each other. + */ +static void +h_int(signo) + int signo; +{ + F_SET(__global_list, G_SIGINT); +} + +/* + * h_term -- + * Handle SIGTERM. + */ +static void +h_term(signo) + int signo; +{ + sig_sync(SIGTERM, 0); + /* NOTREACHED */ +} + +/* + * h_winch -- + * Handle SIGWINCH. + * + * XXX + * This isn't right if windows are independent of each other. + */ +static void +h_winch(signo) + int signo; +{ + F_SET(__global_list, G_SIGWINCH); +} + + +/* + * sig_sync -- + * + * Sync the files based on a signal. + */ +static void +sig_sync(signo, flags) + int signo; + u_int flags; +{ + SCR *sp; + + /* + * Walk the lists of screens, sync'ing the files; only sync + * each file once. + */ + for (sp = __global_list->dq.cqh_first; + sp != (void *)&__global_list->dq; sp = sp->q.cqe_next) + rcv_sync(sp, sp->ep, RCV_ENDSESSION | RCV_PRESERVE | flags); + for (sp = __global_list->hq.cqh_first; + sp != (void *)&__global_list->hq; sp = sp->q.cqe_next) + rcv_sync(sp, sp->ep, RCV_ENDSESSION | RCV_PRESERVE | flags); + + /* + * Die with the proper exit status. Don't bother using + * sigaction(2) 'cause we want the default behavior. + */ + (void)signal(signo, SIG_DFL); + (void)kill(getpid(), signo); + /* NOTREACHED */ + + exit (1); +} diff --git a/usr.bin/vi/common/term.c b/usr.bin/vi/common/term.c new file mode 100644 index 0000000..457e368 --- /dev/null +++ b/usr.bin/vi/common/term.c @@ -0,0 +1,732 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)term.c 8.79 (Berkeley) 8/2/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +/* + * XXX + * DON'T INCLUDE <curses.h> HERE, IT BREAKS OSF1 V2.0 WHERE IT + * CHANGES THE VALUES OF VERASE/VKILL/VWERASE TO INCORRECT ONES. + */ +#include <db.h> +#include <regex.h> + +#include "vi.h" + +static int keycmp __P((const void *, const void *)); +static enum input term_key_queue __P((SCR *)); +static void term_key_set __P((GS *, int, int)); + +/* + * If we're reading less than 20 characters, up the size of the tty buffer. + * This shouldn't ever happen, other than the first time through, but it's + * possible if a map is large enough. + */ +#define term_read_grow(sp, tty) \ + (tty)->nelem - ((tty)->cnt + (tty)->next) >= 20 ? \ + 0 : __term_read_grow(sp, tty, 64) +static int __term_read_grow __P((SCR *, IBUF *, int)); + +/* + * !!! + * Historic vi always used: + * + * ^D: autoindent deletion + * ^H: last character deletion + * ^W: last word deletion + * ^Q: quote the next character (if not used in flow control). + * ^V: quote the next character + * + * regardless of the user's choices for these characters. The user's erase + * and kill characters worked in addition to these characters. Nvi wires + * down the above characters, but in addition permits the VEOF, VERASE, VKILL + * and VWERASE characters described by the user's termios structure. + * + * Ex was not consistent with this scheme, as it historically ran in tty + * cooked mode. This meant that the scroll command and autoindent erase + * characters were mapped to the user's EOF character, and the character + * and word deletion characters were the user's tty character and word + * deletion characters. This implementation makes it all consistent, as + * described above for vi. + * + * XXX + * THIS REQUIRES THAT ALL SCREENS SHARE A SPECIAL KEY SET. + */ +KEYLIST keylist[] = { + {K_CARAT, '^'}, /* ^ */ + {K_CNTRLD, '\004'}, /* ^D */ + {K_CNTRLR, '\022'}, /* ^R */ + {K_CNTRLT, '\024'}, /* ^T */ + {K_CNTRLZ, '\032'}, /* ^Z */ + {K_COLON, ':'}, /* : */ + {K_CR, '\r'}, /* \r */ + {K_ESCAPE, '\033'}, /* ^[ */ + {K_FORMFEED, '\f'}, /* \f */ + {K_HEXCHAR, '\030'}, /* ^X */ + {K_NL, '\n'}, /* \n */ + {K_RIGHTBRACE, '}'}, /* } */ + {K_RIGHTPAREN, ')'}, /* ) */ + {K_TAB, '\t'}, /* \t */ + {K_VERASE, '\b'}, /* \b */ + {K_VKILL, '\025'}, /* ^U */ + {K_VLNEXT, '\021'}, /* ^Q */ + {K_VLNEXT, '\026'}, /* ^V */ + {K_VWERASE, '\027'}, /* ^W */ + {K_ZERO, '0'}, /* 0 */ + {K_NOTUSED, 0}, /* VEOF, VERASE, VKILL, VWERASE */ + {K_NOTUSED, 0}, + {K_NOTUSED, 0}, + {K_NOTUSED, 0}, +}; +static int nkeylist = (sizeof(keylist) / sizeof(keylist[0])) - 4; + +/* + * term_init -- + * Initialize the special key lookup table. + */ +int +term_init(sp) + SCR *sp; +{ + GS *gp; + KEYLIST *kp; + int cnt; + + /* + * XXX + * 8-bit only, for now. Recompilation should get you any + * 8-bit character set, as long as nul isn't a character. + */ + (void)setlocale(LC_ALL, ""); + key_init(sp); + + gp = sp->gp; +#ifdef VEOF + term_key_set(gp, VEOF, K_CNTRLD); +#endif +#ifdef VERASE + term_key_set(gp, VERASE, K_VERASE); +#endif +#ifdef VKILL + term_key_set(gp, VKILL, K_VKILL); +#endif +#ifdef VWERASE + term_key_set(gp, VWERASE, K_VWERASE); +#endif + + /* Sort the special key list. */ + qsort(keylist, nkeylist, sizeof(keylist[0]), keycmp); + + /* Initialize the fast lookup table. */ + for (gp->max_special = 0, kp = keylist, cnt = nkeylist; cnt--; ++kp) { + if (gp->max_special < kp->value) + gp->max_special = kp->value; + if (kp->ch <= MAX_FAST_KEY) + gp->special_key[kp->ch] = kp->value; + } + return (0); +} + +/* + * term_key_set -- + * Set keys found in the termios structure. VERASE and VKILL are required + * by POSIX 1003.1-1990, VWERASE is a 4.4BSD extension. We've left three + * open slots in the keylist table, if these values exist, put them into + * place. Note, they may reset (or duplicate) values already in the table, + * so we check for that first. + */ +static void +term_key_set(gp, name, val) + GS *gp; + int name, val; +{ + KEYLIST *kp; + cc_t ch; + + if (!F_ISSET(gp, G_TERMIOS_SET)) + return; + if ((ch = gp->original_termios.c_cc[name]) == _POSIX_VDISABLE) + return; + + /* Check for duplication. */ + for (kp = keylist; kp->value != K_NOTUSED; ++kp) + if (kp->ch == ch) { + kp->value = val; + return; + } + /* Add a new entry. */ + if (kp->value == K_NOTUSED) { + keylist[nkeylist].ch = ch; + keylist[nkeylist].value = val; + ++nkeylist; + } +} + +/* + * key_init -- + * Build the fast-lookup key display array. + */ +void +key_init(sp) + SCR *sp; +{ + CHAR_T ch; + + for (ch = 0; ch <= MAX_FAST_KEY; ++ch) { + (void)__key_name(sp, ch); + (void)memmove(sp->gp->cname[ch].name, sp->cname, sp->clen); + sp->gp->cname[ch].len = sp->clen; + } +} + +/* + * __key_len -- + * Return the length of the string that will display the key. + * This routine is the backup for the KEY_LEN() macro. + */ +size_t +__key_len(sp, ch) + SCR *sp; + ARG_CHAR_T ch; +{ + (void)__key_name(sp, ch); + return (sp->clen); +} + +/* + * __key_name -- + * Return the string that will display the key. This routine + * is the backup for the KEY_NAME() macro. + */ +CHAR_T * +__key_name(sp, ach) + SCR *sp; + ARG_CHAR_T ach; +{ + static const CHAR_T hexdigit[] = "0123456789abcdef"; + static const CHAR_T octdigit[] = "01234567"; + CHAR_T ch, *chp, mask; + size_t len; + int cnt, shift; + + /* + * Historical (ARPA standard) mappings. Printable characters are left + * alone. Control characters less than '\177' are represented as '^' + * followed by the character offset from the '@' character in the ASCII + * map. '\177' is represented as '^' followed by '?'. + * + * XXX + * The following code depends on the current locale being identical to + * the ASCII map from '\100' to '\076' (\076 since that's the largest + * character for which we can offset from '@' and get something that's + * a printable character in ASCII. I'm told that this is a reasonable + * assumption... + * + * XXX + * This code will only work with CHAR_T's that are multiples of 8-bit + * bytes. + * + * XXX + * NB: There's an assumption here that all printable characters take + * up a single column on the screen. This is not always correct. + */ + ch = ach; + if (isprint(ch)) { + sp->cname[0] = ch; + len = 1; + } else if (ch <= '\076' && iscntrl(ch)) { + sp->cname[0] = '^'; + sp->cname[1] = ch == '\177' ? '?' : '@' + ch; + len = 2; + } else if (O_ISSET(sp, O_OCTAL)) { +#define BITS (sizeof(CHAR_T) * 8) +#define SHIFT (BITS - BITS % 3) +#define TOPMASK (BITS % 3 == 2 ? 3 : 1) << (BITS - BITS % 3) + sp->cname[0] = '\\'; + sp->cname[1] = octdigit[(ch & TOPMASK) >> SHIFT]; + shift = SHIFT - 3; + for (len = 2, mask = 7 << (SHIFT - 3), + cnt = BITS / 3; cnt-- > 0; mask >>= 3, shift -= 3) + sp->cname[len++] = octdigit[(ch & mask) >> shift]; + } else { + sp->cname[0] = '0'; + sp->cname[1] = 'x'; + for (len = 2, chp = (u_int8_t *)&ch, + cnt = sizeof(CHAR_T); cnt-- > 0; ++chp) { + sp->cname[len++] = hexdigit[(*chp & 0xf0) >> 4]; + sp->cname[len++] = hexdigit[*chp & 0x0f]; + } + } + sp->cname[sp->clen = len] = '\0'; + return (sp->cname); +} + +/* + * term_push -- + * Push keys onto the front of a buffer. + * + * There is a single input buffer in ex/vi. Characters are read onto the + * end of the buffer by the terminal input routines, and pushed onto the + * front of the buffer by various other functions in ex/vi. Each key has + * an associated flag value, which indicates if it has already been quoted, + * if it is the result of a mapping or an abbreviation, as well as a count + * of the number of times it has been mapped. + */ +int +term_push(sp, s, nchars, flags) + SCR *sp; + CHAR_T *s; /* Characters. */ + size_t nchars; /* Number of chars. */ + u_int flags; /* CH_* flags. */ +{ + IBUF *tty; + size_t total; + + /* If we have room, stuff the keys into the buffer. */ + tty = sp->gp->tty; + if (nchars <= tty->next || + (tty->ch != NULL && tty->cnt == 0 && nchars <= tty->nelem)) { + if (tty->cnt != 0) + tty->next -= nchars; + tty->cnt += nchars; + MEMMOVE(tty->ch + tty->next, s, nchars); + MEMSET(tty->chf + tty->next, flags, nchars); + return (0); + } + + /* + * If there are currently characters in the queue, shift them up, + * leaving some extra room. Get enough space plus a little extra. + */ +#define TERM_PUSH_SHIFT 30 + total = tty->cnt + tty->next + nchars + TERM_PUSH_SHIFT; + if (total >= tty->nelem && __term_read_grow(sp, tty, MAX(total, 64))) + return (1); + if (tty->cnt) { + MEMMOVE(tty->ch + TERM_PUSH_SHIFT + nchars, + tty->ch + tty->next, tty->cnt); + MEMMOVE(tty->chf + TERM_PUSH_SHIFT + nchars, + tty->chf + tty->next, tty->cnt); + } + + /* Put the new characters into the queue. */ + tty->next = TERM_PUSH_SHIFT; + tty->cnt += nchars; + MEMMOVE(tty->ch + TERM_PUSH_SHIFT, s, nchars); + MEMSET(tty->chf + TERM_PUSH_SHIFT, flags, nchars); + return (0); +} + +/* + * Remove characters from the queue, simultaneously clearing the flag + * and map counts. + */ +#define QREM_HEAD(q, len) { \ + size_t __off = (q)->next; \ + if (len == 1) \ + tty->chf[__off] = 0; \ + else \ + MEMSET(tty->chf + __off, 0, len); \ + if (((q)->cnt -= len) == 0) \ + (q)->next = 0; \ + else \ + (q)->next += len; \ +} +#define QREM_TAIL(q, len) { \ + size_t __off = (q)->next + (q)->cnt - 1; \ + if (len == 1) \ + tty->chf[__off] = 0; \ + else \ + MEMSET(tty->chf + __off, 0, len); \ + if (((q)->cnt -= len) == 0) \ + (q)->next = 0; \ +} + +/* + * term_key -- + * Get the next key. + * + * !!! + * The flag TXT_MAPNODIGIT probably needs some explanation. First, the idea + * of mapping keys is that one or more keystrokes act like a function key. + * What's going on is that vi is reading a number, and the character following + * the number may or may not be mapped (TXT_MAPCOMMAND). For example, if the + * user is entering the z command, a valid command is "z40+", and we don't want + * to map the '+', i.e. if '+' is mapped to "xxx", we don't want to change it + * into "z40xxx". However, if the user enters "35x", we want to put all of the + * characters through the mapping code. + * + * Historical practice is a bit muddled here. (Surprise!) It always permitted + * mapping digits as long as they weren't the first character of the map, e.g. + * ":map ^A1 xxx" was okay. It also permitted the mapping of the digits 1-9 + * (the digit 0 was a special case as it doesn't indicate the start of a count) + * as the first character of the map, but then ignored those mappings. While + * it's probably stupid to map digits, vi isn't your mother. + * + * The way this works is that the TXT_MAPNODIGIT causes term_key to return the + * end-of-digit without "looking" at the next character, i.e. leaving it as the + * user entered it. Presumably, the next term_key call will tell us how the + * user wants it handled. + * + * There is one more complication. Users might map keys to digits, and, as + * it's described above, the commands "map g 1G|d2g" would return the keys + * "d2<end-of-digits>1G", when the user probably wanted "d21<end-of-digits>G". + * So, if a map starts off with a digit we continue as before, otherwise, we + * pretend that we haven't mapped the character and return <end-of-digits>. + * + * Now that that's out of the way, let's talk about Energizer Bunny macros. + * It's easy to create macros that expand to a loop, e.g. map x 3x. It's + * fairly easy to detect this example, because it's all internal to term_key. + * If we're expanding a macro and it gets big enough, at some point we can + * assume it's looping and kill it. The examples that are tough are the ones + * where the parser is involved, e.g. map x "ayyx"byy. We do an expansion + * on 'x', and get "ayyx"byy. We then return the first 4 characters, and then + * find the looping macro again. There is no way that we can detect this + * without doing a full parse of the command, because the character that might + * cause the loop (in this case 'x') may be a literal character, e.g. the map + * map x "ayy"xyy"byy is perfectly legal and won't cause a loop. + * + * Historic vi tried to detect looping macros by disallowing obvious cases in + * the map command, maps that that ended with the same letter as they started + * (which wrongly disallowed "map x 'x"), and detecting macros that expanded + * too many times before keys were returned to the command parser. It didn't + * get many (most?) of the tricky cases right, however, and it was certainly + * possible to create macros that ran forever. And, even if it did figure out + * what was going on, the user was usually tossed into ex mode. Finally, any + * changes made before vi realized that the macro was recursing were left in + * place. We recover gracefully, but the only recourse the user has in an + * infinite macro loop is to interrupt. + * + * !!! + * It is historic practice that mapping characters to themselves as the first + * part of the mapped string was legal, and did not cause infinite loops, i.e. + * ":map! { {^M^T" and ":map n nz." were known to work. The initial, matching + * characters were returned instead of being remapped. + * + * XXX + * The final issue is recovery. It would be possible to undo all of the work + * that was done by the macro if we entered a record into the log so that we + * knew when the macro started, and, in fact, this might be worth doing at some + * point. Given that this might make the log grow unacceptably (consider that + * cursor keys are done with maps), for now we leave any changes made in place. + */ +enum input +term_key(sp, chp, flags) + SCR *sp; + CH *chp; + u_int flags; +{ + enum input rval; + struct timeval t, *tp; + CHAR_T ch; + GS *gp; + IBUF *tty; + SEQ *qp; + int init_nomap, ispartial, nr; + + /* If we've been interrupted, return an error. */ + if (INTERRUPTED(sp)) + return (INP_INTR); + + gp = sp->gp; + tty = gp->tty; + + /* + * If the queue is empty, read more keys in. Since no timeout is + * requested, s_key_read will either return an error or will read + * some number of characters. + */ +loop: if (tty->cnt == 0) { + if (term_read_grow(sp, tty)) + return (INP_ERR); + if ((rval = sp->s_key_read(sp, &nr, NULL)) != INP_OK) + return (rval); + /* + * If there's something on the mode line that we wanted + * the user to see, they just entered a character so we + * can presume they saw it. + */ + if (F_ISSET(sp, S_UPDATE_MODE)) + F_CLR(sp, S_UPDATE_MODE); + } + + /* If the key is mappable and should be mapped, look it up. */ + if (!(tty->chf[tty->next] & CH_NOMAP) && + LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT)) { + /* Set up timeout value. */ + if (O_ISSET(sp, O_TIMEOUT)) { + tp = &t; + t.tv_sec = O_VAL(sp, O_KEYTIME) / 10; + t.tv_usec = (O_VAL(sp, O_KEYTIME) % 10) * 100000L; + } else + tp = NULL; + + /* Get the next key. */ +newmap: ch = tty->ch[tty->next]; + if (ch < MAX_BIT_SEQ && !bit_test(gp->seqb, ch)) + goto nomap; + + /* Search the map. */ +remap: qp = seq_find(sp, NULL, &tty->ch[tty->next], tty->cnt, + LF_ISSET(TXT_MAPCOMMAND) ? SEQ_COMMAND : SEQ_INPUT, + &ispartial); + + /* If we've been interrupted, return an error. */ + if (INTERRUPTED(sp)) + return (INP_INTR); + + /* + * If get a partial match, read more characters and retry + * the map. If no characters read, return the characters + * unmapped. + */ + if (ispartial) { + if (term_read_grow(sp, tty)) + return (INP_ERR); + if ((rval = sp->s_key_read(sp, &nr, tp)) != INP_OK) + return (rval); + if (nr) + goto remap; + goto nomap; + } + + /* If no map, return the character. */ + if (qp == NULL) + goto nomap; + + /* + * If looking for the end of a digit string, and the first + * character of the map is it, pretend we haven't seen the + * character. + */ + if (LF_ISSET(TXT_MAPNODIGIT) && + qp->output != NULL && !isdigit(qp->output[0])) + goto not_digit_ch; + + /* Find out if the initial segments are identical. */ + init_nomap = !memcmp(&tty->ch[tty->next], qp->output, qp->ilen); + + /* Delete the mapped characters from the queue. */ + QREM_HEAD(tty, qp->ilen); + + /* If keys mapped to nothing, go get more. */ + if (qp->output == NULL) + goto loop; + + /* If remapping characters, push the character on the queue. */ + if (O_ISSET(sp, O_REMAP)) { + if (init_nomap) { + if (term_push(sp, qp->output + qp->ilen, + qp->olen - qp->ilen, CH_MAPPED)) + return (INP_ERR); + if (term_push(sp, + qp->output, qp->ilen, CH_NOMAP | CH_MAPPED)) + return (INP_ERR); + goto nomap; + } else + if (term_push(sp, + qp->output, qp->olen, CH_MAPPED)) + return (INP_ERR); + goto newmap; + } + + /* Else, push the characters on the queue and return one. */ + if (term_push(sp, qp->output, qp->olen, CH_MAPPED | CH_NOMAP)) + return (INP_ERR); + } + +nomap: ch = tty->ch[tty->next]; + if (LF_ISSET(TXT_MAPNODIGIT) && !isdigit(ch)) { +not_digit_ch: chp->ch = CH_NOT_DIGIT; + chp->value = 0; + chp->flags = 0; + return (INP_OK); + } + + /* Fill in the return information. */ + chp->ch = ch; + chp->flags = tty->chf[tty->next]; + chp->value = KEY_VAL(sp, ch); + + /* Delete the character from the queue. */ + QREM_HEAD(tty, 1); + return (INP_OK); +} + +/* + * term_flush -- + * Flush any flagged keys. + */ +void +term_flush(sp, msg, flags) + SCR *sp; + char *msg; + u_int flags; +{ + IBUF *tty; + + tty = sp->gp->tty; + if (!tty->cnt || !(tty->chf[tty->next] & flags)) + return; + do { + QREM_HEAD(tty, 1); + } while (tty->cnt && tty->chf[tty->next] & flags); + msgq(sp, M_ERR, "%s: keys flushed", msg); +} + +/* + * term_user_key -- + * Get the next key, but require the user enter one. + */ +enum input +term_user_key(sp, chp) + SCR *sp; + CH *chp; +{ + enum input rval; + IBUF *tty; + int nr; + + /* + * Read any keys the user has waiting. Make the race + * condition as short as possible. + */ + if ((rval = term_key_queue(sp)) != INP_OK) + return (rval); + + /* Wait and read another key. */ + if ((rval = sp->s_key_read(sp, &nr, NULL)) != INP_OK) + return (rval); + + /* Fill in the return information. */ + tty = sp->gp->tty; + chp->ch = tty->ch[tty->next + (tty->cnt - 1)]; + chp->flags = 0; + chp->value = KEY_VAL(sp, chp->ch); + + QREM_TAIL(tty, 1); + return (INP_OK); +} + +/* + * term_key_queue -- + * Read the keys off of the terminal queue until it's empty. + */ +static enum input +term_key_queue(sp) + SCR *sp; +{ + enum input rval; + struct timeval t; + IBUF *tty; + int nr; + + t.tv_sec = 0; + t.tv_usec = 0; + for (tty = sp->gp->tty;;) { + if (term_read_grow(sp, tty)) + return (INP_ERR); + if ((rval = sp->s_key_read(sp, &nr, &t)) != INP_OK) + return (rval); + if (nr == 0) + break; + } + return (INP_OK); +} + +/* + * __key_val -- + * Fill in the value for a key. This routine is the backup + * for the KEY_VAL() macro. + */ +int +__key_val(sp, ch) + SCR *sp; + ARG_CHAR_T ch; +{ + KEYLIST k, *kp; + + k.ch = ch; + kp = bsearch(&k, keylist, nkeylist, sizeof(keylist[0]), keycmp); + return (kp == NULL ? K_NOTUSED : kp->value); +} + +/* + * __term_read_grow -- + * Grow the terminal queue. This routine is the backup for + * the term_read_grow() macro. + */ +static int +__term_read_grow(sp, tty, add) + SCR *sp; + IBUF *tty; + int add; +{ + size_t new_nelem, olen; + + new_nelem = tty->nelem + add; + olen = tty->nelem * sizeof(tty->ch[0]); + BINC_RET(sp, tty->ch, olen, new_nelem * sizeof(tty->ch[0])); + + olen = tty->nelem * sizeof(tty->chf[0]); + BINC_RET(sp, tty->chf, olen, new_nelem * sizeof(tty->chf[0])); + + tty->nelem = olen / sizeof(tty->chf[0]); + return (0); +} + +static int +keycmp(ap, bp) + const void *ap, *bp; +{ + return (((KEYLIST *)ap)->ch - ((KEYLIST *)bp)->ch); +} diff --git a/usr.bin/vi/common/term.h b/usr.bin/vi/common/term.h new file mode 100644 index 0000000..623a94c --- /dev/null +++ b/usr.bin/vi/common/term.h @@ -0,0 +1,205 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)term.h 8.48 (Berkeley) 7/25/94 + */ + +/* + * Fundamental character types. + * + * CHAR_T An integral type that can hold any character. + * ARG_CHAR_T The type of a CHAR_T when passed as an argument using + * traditional promotion rules. It should also be able + * to be compared against any CHAR_T for equality without + * problems. + * MAX_CHAR_T The maximum value of any character. + * + * If no integral type can hold a character, don't even try the port. + */ +typedef u_char CHAR_T; +typedef u_int ARG_CHAR_T; +#define MAX_CHAR_T 0xff + +/* The maximum number of columns any character can take up on a screen. */ +#define MAX_CHARACTER_COLUMNS 4 + +/* Structure to return a character and associated information. */ +struct _ch { + CHAR_T ch; /* Character. */ + +#define K_NOTUSED 0 +#define K_CARAT 1 +#define K_CNTRLD 2 +#define K_CNTRLR 3 +#define K_CNTRLT 4 +#define K_CNTRLZ 5 +#define K_COLON 6 +#define K_CR 7 +#define K_ESCAPE 8 +#define K_FORMFEED 9 +#define K_HEXCHAR 10 +#define K_NL 11 +#define K_RIGHTBRACE 12 +#define K_RIGHTPAREN 13 +#define K_TAB 14 +#define K_VERASE 15 +#define K_VKILL 16 +#define K_VLNEXT 17 +#define K_VWERASE 18 +#define K_ZERO 19 + u_int8_t value; /* Special character flag values. */ + +#define CH_ABBREVIATED 0x01 /* Character from an abbreviation. */ +#define CH_MAPPED 0x02 /* Character from a map. */ +#define CH_NOMAP 0x04 /* Do not map the character. */ +#define CH_QUOTED 0x08 /* Character is already quoted. */ + u_int8_t flags; +}; + +typedef struct _keylist { + u_int8_t value; /* Special value. */ + CHAR_T ch; /* Key. */ +} KEYLIST; + +extern KEYLIST keylist[]; + +/* Structure for the key input buffer. */ +struct _ibuf { + CHAR_T *ch; /* Array of characters. */ + u_int8_t *chf; /* Array of character flags (CH_*). */ + + size_t cnt; /* Count of remaining characters. */ + size_t nelem; /* Numer of array elements. */ + size_t next; /* Offset of next array entry. */ +}; + /* Return if more keys in queue. */ +#define KEYS_WAITING(sp) ((sp)->gp->tty->cnt) +#define MAPPED_KEYS_WAITING(sp) \ + (KEYS_WAITING(sp) && sp->gp->tty->chf[sp->gp->tty->next] & CH_MAPPED) + +/* + * Routines that return a key as a side-effect return: + * + * INP_OK Returning a character; must be 0. + * INP_EOF EOF. + * INP_ERR Error. + * INP_INTR Interrupted. + * + * The vi structure depends on the key routines being able to return INP_EOF + * multiple times without failing -- eventually enough things will end due to + * INP_EOF that vi will reach the command level for the screen, at which point + * the exit flags will be set and vi will exit. + */ +enum input { INP_OK=0, INP_EOF, INP_ERR, INP_INTR }; + +/* + * Routines that return a confirmation return: + * + * CONF_NO User answered no. + * CONF_QUIT User answered quit, eof or an error. + * CONF_YES User answered yes. + */ +enum confirm { CONF_NO, CONF_QUIT, CONF_YES }; + +/* + * Ex/vi commands are generally separated by whitespace characters. We + * can't use the standard isspace(3) macro because it returns true for + * characters like ^K in the ASCII character set. The 4.4BSD isblank(3) + * macro does exactly what we want, but it's not portable yet. + * + * XXX + * Note side effect, ch is evaluated multiple times. + */ +#ifndef isblank +#define isblank(ch) ((ch) == ' ' || (ch) == '\t') +#endif + +/* The "standard" tab width, for displaying things to users. */ +#define STANDARD_TAB 6 + +/* Various special characters, messages. */ +#define CH_BSEARCH '?' /* Backward search prompt. */ +#define CH_CURSOR ' ' /* Cursor character. */ +#define CH_ENDMARK '$' /* End of a range. */ +#define CH_EXPROMPT ':' /* Ex prompt. */ +#define CH_FSEARCH '/' /* Forward search prompt. */ +#define CH_HEX '\030' /* Leading hex character. */ +#define CH_LITERAL '\026' /* ASCII ^V. */ +#define CH_NO 'n' /* No. */ +#define CH_NOT_DIGIT 'a' /* A non-isdigit() character. */ +#define CH_QUIT 'q' /* Quit. */ +#define CH_YES 'y' /* Yes. */ + +#define STR_CONFIRM "confirm? [ynq]" +#define STR_CMSG "Enter return to continue: " +#define STR_QMSG "Enter return to continue [q to quit]: " + +/* Flags describing how input is handled. */ +#define TXT_AICHARS 0x00000001 /* Leading autoindent chars. */ +#define TXT_ALTWERASE 0x00000002 /* Option: altwerase. */ +#define TXT_APPENDEOL 0x00000004 /* Appending after EOL. */ +#define TXT_AUTOINDENT 0x00000008 /* Autoindent set this line. */ +#define TXT_BACKSLASH 0x00000010 /* Backslashes escape characters. */ +#define TXT_BEAUTIFY 0x00000020 /* Only printable characters. */ +#define TXT_BS 0x00000040 /* Backspace returns the buffer. */ +#define TXT_CNTRLD 0x00000080 /* Control-D is a special command. */ +#define TXT_CNTRLT 0x00000100 /* Control-T is an indent special. */ +#define TXT_CR 0x00000200 /* CR returns the buffer. */ +#define TXT_DOTTERM 0x00000400 /* Leading '.' terminates the input. */ +#define TXT_EMARK 0x00000800 /* End of replacement mark. */ +#define TXT_ESCAPE 0x00001000 /* Escape returns the buffer. */ +#define TXT_EXSUSPEND 0x00002000 /* ^Z should suspend the session. */ +#define TXT_INFOLINE 0x00004000 /* Editing the info line. */ +#define TXT_MAPCOMMAND 0x00008000 /* Apply the command map. */ +#define TXT_MAPINPUT 0x00010000 /* Apply the input map. */ +#define TXT_MAPNODIGIT 0x00020000 /* Return to a digit. */ +#define TXT_NLECHO 0x00040000 /* Echo the newline. */ +#define TXT_OVERWRITE 0x00080000 /* Overwrite characters. */ +#define TXT_PROMPT 0x00100000 /* Display a prompt. */ +#define TXT_RECORD 0x00200000 /* Record for replay. */ +#define TXT_REPLACE 0x00400000 /* Replace; don't delete overwrite. */ +#define TXT_REPLAY 0x00800000 /* Replay the last input. */ +#define TXT_RESOLVE 0x01000000 /* Resolve the text into the file. */ +#define TXT_SHOWMATCH 0x02000000 /* Option: showmatch. */ +#define TXT_TTYWERASE 0x04000000 /* Option: ttywerase. */ +#define TXT_WRAPMARGIN 0x08000000 /* Option: wrapmargin. */ + +/* Support keyboard routines. */ +size_t __key_len __P((SCR *, ARG_CHAR_T)); +CHAR_T *__key_name __P((SCR *, ARG_CHAR_T)); +int __key_val __P((SCR *, ARG_CHAR_T)); +void key_init __P((SCR *)); +void term_flush __P((SCR *, char *, u_int)); +enum input term_key __P((SCR *, CH *, u_int)); +enum input term_user_key __P((SCR *, CH *)); +int term_init __P((SCR *)); +int term_push __P((SCR *, CHAR_T *, size_t, u_int)); diff --git a/usr.bin/vi/common/trace.c b/usr.bin/vi/common/trace.c new file mode 100644 index 0000000..1f63f66 --- /dev/null +++ b/usr.bin/vi/common/trace.c @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)trace.c 8.2 (Berkeley) 3/8/94 + */ + +#ifdef DEBUG +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +void +#ifdef __STDC__ +TRACE(SCR *sp, const char *fmt, ...) +#else +TRACE(sp, fmt, va_alist) + SCR *sp; + char *fmt; + va_dcl +#endif +{ + FILE *tfp; + va_list ap; + + if ((tfp = sp->gp->tracefp) == NULL) + return; +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)vfprintf(tfp, fmt, ap); + va_end(ap); + + (void)fflush(tfp); +} +#endif diff --git a/usr.bin/vi/common/util.c b/usr.bin/vi/common/util.c new file mode 100644 index 0000000..9845e64 --- /dev/null +++ b/usr.bin/vi/common/util.c @@ -0,0 +1,215 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)util.c 8.71 (Berkeley) 8/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" + +/* + * binc -- + * Increase the size of a buffer. + */ +int +binc(sp, argp, bsizep, min) + SCR *sp; /* sp MAY BE NULL!!! */ + void *argp; + size_t *bsizep, min; +{ + size_t csize; + void *bpp; + + /* If already larger than the minimum, just return. */ + if (min && *bsizep >= min) + return (0); + + bpp = *(char **)argp; + csize = *bsizep + MAX(min, 256); + REALLOC(sp, bpp, void *, csize); + + if (bpp == NULL) { + /* + * Theoretically, realloc is supposed to leave any already + * held memory alone if it can't get more. Don't trust it. + */ + *bsizep = 0; + return (1); + } + /* + * Memory is guaranteed to be zero-filled, various parts of + * nvi depend on this. + */ + memset((char *)bpp + *bsizep, 0, csize - *bsizep); + *(char **)argp = bpp; + *bsizep = csize; + return (0); +} +/* + * nonblank -- + * Set the column number of the first non-blank character + * including or after the starting column. On error, set + * the column to 0, it's safest. + */ +int +nonblank(sp, ep, lno, cnop) + SCR *sp; + EXF *ep; + recno_t lno; + size_t *cnop; +{ + char *p; + size_t cnt, len, off; + + /* Default. */ + off = *cnop; + *cnop = 0; + + /* Get the line. */ + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) + return (0); + GETLINE_ERR(sp, lno); + return (1); + } + + /* Set the offset. */ + if (len == 0 || off >= len) + return (0); + + for (cnt = off, p = &p[off], + len -= off; len && isblank(*p); ++cnt, ++p, --len); + + /* Set the return. */ + *cnop = len ? cnt : cnt - 1; + return (0); +} + +/* + * tail -- + * Return tail of a path. + */ +char * +tail(path) + char *path; +{ + char *p; + + if ((p = strrchr(path, '/')) == NULL) + return (path); + return (p + 1); +} + +/* + * set_alt_name -- + * Set the alternate file name. + * + * Swap the alternate file name. It's a routine because I wanted some place + * to hang this comment. The alternate file name (normally referenced using + * the special character '#' during file expansion) is set by many + * operations. In the historic vi, the commands "ex", and "edit" obviously + * set the alternate file name because they switched the underlying file. + * Less obviously, the "read", "file", "write" and "wq" commands set it as + * well. In this implementation, some new commands have been added to the + * list. Where it gets interesting is that the alternate file name is set + * multiple times by some commands. If an edit attempt fails (for whatever + * reason, like the current file is modified but as yet unwritten), it is + * set to the file name that the user was unable to edit. If the edit + * succeeds, it is set to the last file name that was edited. Good fun. + * + * If the user edits a temporary file, there are time when there isn't an + * alternative file name. A name argument of NULL turns it off. + */ +void +set_alt_name(sp, name) + SCR *sp; + char *name; +{ + if (sp->alt_name != NULL) + free(sp->alt_name); + if (name == NULL) + sp->alt_name = NULL; + else if ((sp->alt_name = strdup(name)) == NULL) + msgq(sp, M_SYSERR, NULL); +} + +/* + * v_strdup -- + * Strdup for wide character strings with an associated length. + */ +CHAR_T * +v_strdup(sp, str, len) + SCR *sp; + CHAR_T *str; + size_t len; +{ + CHAR_T *copy; + + MALLOC(sp, copy, CHAR_T *, len + 1); + if (copy == NULL) + return (NULL); + memmove(copy, str, len * sizeof(CHAR_T)); + copy[len] = '\0'; + return (copy); +} + +/* + * vi_putchar -- + * Functional version of putchar, for tputs. + */ +void +vi_putchar(ch) + int ch; +{ + (void)putchar(ch); +} diff --git a/usr.bin/vi/common/vi.h b/usr.bin/vi/common/vi.h new file mode 100644 index 0000000..f98b870 --- /dev/null +++ b/usr.bin/vi/common/vi.h @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vi.h 8.46 (Berkeley) 8/8/94 + */ + +/* + * Forward structure declarations. Not pretty, but the include files + * are far too interrelated for a clean solution. + */ +typedef struct _cb CB; +typedef struct _ch CH; +typedef struct _excmdarg EXCMDARG; +typedef struct _exf EXF; +typedef struct _fref FREF; +typedef struct _gs GS; +typedef struct _ibuf IBUF; +typedef struct _lmark LMARK; +typedef struct _mark MARK; +typedef struct _msg MSG; +typedef struct _option OPTION; +typedef struct _optlist OPTLIST; +typedef struct _scr SCR; +typedef struct _script SCRIPT; +typedef struct _seq SEQ; +typedef struct _tag TAG; +typedef struct _tagf TAGF; +typedef struct _text TEXT; + +/* + * Local includes. + */ +#include "term.h" /* Required by args.h. */ +#include "args.h" /* Required by options.h. */ +#include "options.h" /* Required by screen.h. */ +#include "search.h" /* Required by screen.h. */ + +#include "msg.h" /* Required by gs.h. */ +#include "cut.h" /* Required by gs.h. */ +#include "seq.h" /* Required by screen.h. */ +#include "gs.h" /* Required by screen.h. */ +#include "screen.h" /* Required by exf.h. */ +#include "mark.h" /* Required by exf.h. */ +#include "exf.h" +#include "log.h" +#include "mem.h" + +#if FWOPEN_NOT_AVAILABLE /* See PORT/clib/fwopen.c. */ +#define EXCOOKIE sp +int ex_fflush __P((SCR *)); +int ex_printf __P((SCR *, const char *, ...)); +FILE *fwopen __P((SCR *, void *)); +#else +#define EXCOOKIE sp->stdfp +#define ex_fflush fflush +#define ex_printf fprintf +#endif + +/* Macros to set/clear/test flags. */ +#define F_SET(p, f) (p)->flags |= (f) +#define F_CLR(p, f) (p)->flags &= ~(f) +#define F_ISSET(p, f) ((p)->flags & (f)) + +#define LF_INIT(f) flags = (f) +#define LF_SET(f) flags |= (f) +#define LF_CLR(f) flags &= ~(f) +#define LF_ISSET(f) (flags & (f)) + +/* + * XXX + * MIN/MAX have traditionally been in <sys/param.h>. Don't + * try to get them from there, it's just not worth the effort. + */ +#ifndef MAX +#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a)) +#endif +#ifndef MIN +#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +#endif + +/* Function prototypes that don't seem to belong anywhere else. */ +int nonblank __P((SCR *, EXF *, recno_t, size_t *)); +void set_alt_name __P((SCR *, char *)); +char *tail __P((char *)); +CHAR_T *v_strdup __P((SCR *, CHAR_T *, size_t)); +void vi_putchar __P((int)); + +#ifdef DEBUG +void TRACE __P((SCR *, const char *, ...)); +#endif + +/* Digraphs (not currently real). */ +int digraph __P((SCR *, int, int)); +int digraph_init __P((SCR *)); +void digraph_save __P((SCR *, int)); diff --git a/usr.bin/vi/docs/README b/usr.bin/vi/docs/README new file mode 100644 index 0000000..5bece99 --- /dev/null +++ b/usr.bin/vi/docs/README @@ -0,0 +1,200 @@ +# @(#)README 8.84 (Berkeley) 8/15/94 + +This is the README for version 1.32 of nex/nvi, a freely redistributable +replacement for the Berkeley ex and vi text editors. The compressed or +gzip'd archive, for this and future versions, can be retrieved by using +anonymous ftp to ftp.cs.berkeley.edu, from the file ucb/4bsd/nvi.tar.Z, +or ucb/4bsd/nvi.tar.gz. + +If you have any questions about nvi, or problems making it work, please +contact me by electronic mail at one of the following addresses: + + uunet!bostic + bostic@cs.berkeley.edu + +Keith Bostic + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +o Redistribution: + +This software is copyrighted by the The Regents of the University of +California, but may be freely redistributed (or sold, or used to line +your birdcage) under the following conditions: + +/*- + * Copyright (c) 1991, 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +o Credit where it's due: + + This software was originally derived from software contributed + to the University of California, Berkeley by Steve Kirkendall, + the author of the vi clone elvis. Without his work, this work + would have been far more difficult. + + POSIX 1003.2 style regular expression support is courtesy of + Henry Spencer, for which I am *very* grateful. + + The curses library was originally done by Ken Arnold. Scrolling + and general reworking for 4.4BSD was done by Elan Amir. + +o From the original vi acknowledgements, by William Joy and Mark Horton: + + Bruce Englar encouraged the early development of this display + editor. Peter Kessler helped bring sanity to version 2's + command layout. Bill Joy wrote versions 1 and 2.0 through 2.7, + and created the framework that users see in the present editor. + Mark Horton added macros and other features and made the editor + work on a large number of terminals and Unix systems. + +o And... + The financial support of UUNET Communications Services is gratefully + acknowledged. + +=-=-=-=-=-=-=-=-=-=-= +o Status: + +This software is in beta test, and it's pretty stable. Almost all of +the historic functionality in ex/vi is there, the only major missing +pieces are open mode and the lisp option. (Also, the options hardtabs, +optimize, redraw, and slowopen are recognized, but ignored.) + +Nvi is mostly 8-bit clean. This isn't difficult to fix, and was left +in during initial development to keep things simple. Wide character +support will be integrated at the same time that it is made fully 8-bit +clean. + +There aren't a lot of new features in nex/nvi, but there are a few things +you might like. The "Additional Features" section of the reference page +(USD.doc/vi.ref/vi.ref.txt, USD.doc/vi.ref/vi.ref.ps) has more information. + +=-=-=-=-=-=-=-=-=-=-= +o Porting information: + +The directory "PORT" has directories for specific OS/machine combinations, +including V7-style Makefiles, for building nex/nvi on different machines. +See the file PORT/README for detailed information. + +=-=-=-=-=-=-=-=-=-=-= +o Debugging: + +Code fixes are appreciated, of course, but if you can't provide them, +please email me as much information as you can as to how to reproduce +the bug, and I'll try to fix it locally. Stack traces of core dumps +are only rarely helpful -- an example file with a set of keystrokes that +causes the problem is almost invariably necessary. + +Please include the following in the bug report; + + o The version of nvi you're running (use :version to get it). + o The row/column dimensions of the screen (80 x 32). + o Unless you're confident that they're not part of the problem, + your startup files (.exrc, .nexrc) and the environment variable + (EXININT, NEXINIT) values. (Cutting and pasting the output + of ":set all" is usually sufficient.) + +If you're running a memory checker (e.g. Purify) on nvi, you will want +to recompile everything with "-DPURIFY" in the CFLAGS, first. By +default, allocated pages are not initialized by the DB code, and they +will show up as reads of uninitialized memory in the buffer write routines. + +=-=-=-=-=-=-=-=-=-=-= +o Directory layout: + +nvi/USD.doc: + Ex/vi documentation, both historic and current. + + edit/ Roff source for "Edit: A tutorial", USD:14 in the + 4.3BSD manuals. + ex/ Roff source for "Ex Reference Manual -- Version + 3.7", USD:16 in the 4.3BSD manuals. + vi/ Roff source for "An Introduction to Display + Editing with Vi", USD:15 in the 4.3BSD manuals. + Includes the "Vi Quick Reference" card. + vi.man/ Manual page for nex/nvi; an updated version of + the document distributed with 4.4BSD-Lite. + vi.ref/ Reference document for nex/nvi; an updated version + of the document distributed with 4.4BSD-Lite. + +nvi/common: + Source files for pieces of code that are shared by all the editors, + like searching and logging code or code translating line numbers + into requests to the dbopen(3) database code. It also has the + interface code for modifying "records" in the underlying database. + +nvi/docs: + Random nvi documentation: + + README -- Nvi main README file. + bugs.current -- Major known bugs in the current nvi. + changelog -- Log of changes from version to version. + features -- Todo list, suggested features list. + internals/ + autowrite -- Vi autowrite option discussion. + gdb.script -- GDB debugging scripts. + input -- Vi maps, executable buffers, and input discussion. + quoting -- Vi quoting discussion. + structures -- Out-of-date nvi internal structure description. + tutorial/ -- Historic vi tutorial(s), of unknown quality. + +nvi/ex: + The ex source code. Because vi has the colon command, lots of + this code is used by vi. Generally, if functionality is shared + by both ex and vi, it's in nvi/ex. If it's vi only, it's in + nvi/vi. Files are generally named by the command(s) they support, + but occasionally with a name that describes their functionality. + +nvi/install: + Things to install on the local system. + + recover.script -- Vi recovery script. + +nvi/PORT: + Porting directories, one per OS/architecture combination. See + nvi/PORT/README for porting information. + + curses/ -- 4.4BSD curses implementation + db/ -- 4.4BSD DB routines. + regex/ -- Henry Spencer's POSIX.2 RE support. + +nvi/sex: + The screen support for the ex editor. + +nvi/svi: + The screen support for a curses based vi editor. + +nvi/vi: + The vi source code. + +nvi/xaw: + Place reserved for an X11 (Athena Widget) screen. diff --git a/usr.bin/vi/docs/bugs.current b/usr.bin/vi/docs/bugs.current new file mode 100644 index 0000000..92b2a5c --- /dev/null +++ b/usr.bin/vi/docs/bugs.current @@ -0,0 +1,47 @@ +List of known bugs: + ++ The number option doesn't display line numbers in ex append/insert + mode. + ++ The option sidescroll is completely wrong, and setting it does more + harm than good. + ++ We're not blocking signals when manipulating the SCR/EXF chains. + This is necessary, since we walk them on signal receipt. + ++ When nvi edits files that don't have trailing newlines, it appends + one, regardless. + ++ Open mode is not yet implemented. + ++ ^C isn't passed to the shell in the script windows as an interrupt + character. + ++ The options: + + hardtabs, lisp, optimize, redraw, slowopen + + are recognized, but not implemented. These options are unlikely to + be implemented, so if you want them you might want to say something! + I will implement lisp if anyone ever documents how it worked. + ++ Screen repainting over slow lines, for some screen changes, isn't + as good as the historic vi's. + ++ The line movement commands ('k', 'j' are easy examples) don't find the + most attractive cursor position correctly when wrapped lines are longer + than 80 characters, and they're on the second or subsequent lines. + ++ Colon commands longer than a single line cause the display to be + incorrect. + ++ The usages of S_{REDRAW,REFORMAT,REFRESH,RENUMBER,RESIZE} are + inconsistent, and should be reviewed. In particular, S_REFRESH + in any screen redraws all screens. + ++ Historic vi permitted :g/xxx/vi, i.e. you could execute ex/vi as + global commands. Need to review all of the old commands to verify + which ones could/could not be used as global commands. + ++ If you run out of space in the recovery directory, the recovery + file is left in place. diff --git a/usr.bin/vi/docs/changelog b/usr.bin/vi/docs/changelog new file mode 100644 index 0000000..335acd8 --- /dev/null +++ b/usr.bin/vi/docs/changelog @@ -0,0 +1,519 @@ +1.31 -> 1.32 Mon Aug 15 14:27:49 1994 + + Turn off recno mmap call for Solaris 2.4/SunOS 5.4. +1.30 -> 1.31 Sun Aug 14 13:13:35 1994 + + Fix bug were cG on the last line of a file wasn't done in line mode, + and where the cursor wasn't positioned correctly after exiting text + insert mode. + + Add termcap workaround to make function keys greater than 9 work + correctly (or fail if old-style termcap support). + + Change ex/vi to not flush mapped keys on error -- this is historic + practice, and people depended on it. + + Rework vi parser so that no command including a mapped key ever + becomes the '.' command, matching historic practice. + + Make <escape> cancellation in the vi parser match POSIX 1003.2. + + Fix curses bug where standout string was written for each standout + character, and where standout mode was never exited explicitly. + Fix bugs in curses SF/sf and SR/sr scrolling, as seen on Sun and + x86 consoles. + + The v/global commands execute the print command by default. + + The number option historically applies to ex as well as vi. +1.29 -> 1.30 Mon Aug 8 10:30:42 1994 + + Make first read into a temporary set the file's name. + + Permit any key to continue scrolling or ex commands -- this + allows stacked colon commands, and matches historic practice. + + Don't output normal ! command commentary in ex silent mode. + + Allow +/- flags after substitute commands, make line (flag) + offsets from vi mode match historic practice. + + Return <eof> to ex immediately, even if preceded by spaces. Rework + ex parser to do erase the prompt instead of depending on the print + routines to do it. Minor fixes to the ex parser for display of + default and scrolling commands. MORE EX PARSER CHANGES. +1.28 -> 1.29 Fri Aug 5 10:18:07 1994 + + Make the abbreviated ex delete command work (:dele---###lll for + example, is historically legal. + + When autoprint fires, multiple flags may be set, use ex_print + directly instead of the stub routines. + + Change v/global commands to turn off autoprint while running. + + Minor changes to make the ! command display match historic output. + + Rework the ex parser to permit multiple command separators without + commands -- MAJOR CHANGE, likely to introduce all sorts of new bugs. + + Fix cd command to expand argument in the context of each element + of the cdpath option, make relative paths always relative to the + current directory. + + Rework write/quit cases for temporary files, so that user's don't + discard them accidentally. + + Check for window size changes when continuing after a suspend. + + Fix memory problem in svi_screen, used free'd memory. + + Change the ex change, insert, append commands to match historic + cursor positions if no data entered by the user. + + Change ex format flags (#, l, p) to affect future commands, not + just the current one, to match historic practice. + + Make the user's EOF character an additional scroll character in ex. + + Fix ex ^D scrolling to be the value of the scroll option, not half + the screen. + + Fix buffer execution to match historic practice -- bugs where the + '*' command didn't work, and @<carriage-return> didn't work. + + Fix doubled reporting of deleted lines in filters. + + Rework the % ` / ? ( ) N n { and ^A commands to always cut into + numeric buffers regardless of the location or length of the cut. + This matches historic practice. + + Fix the { command to check the current line if the cursor doesn't + start on the first character of the line. + + Do '!' expansion in the ex read command arguments, it's historic + practice. In addition, it sets the last '!' command. +1.27 -> 1.28 Wed Jul 27 21:29:18 1994 + + Add support for scrolling using the CS and SF/sf/SR/sr termcap + strings to the 4BSD curses. + + Rework of getkey() introduced a bug where command interrupt put + nvi into an infinite loop. + + Piping through a filter historically cut the replaced lines into + the default buffer, although not the numeric ones. + + Read of a filter and !! historically moved to the first nonblank + of the resulting cursor line (most of the time). + + Rework cursor motion flags, to support '!' as a motion command. +1.26 -> 1.27 Tue Jul 26 10:27:58 1994 + + Add the meta option, to specify characters the shell will expand. + + Fix the read command to match historic practice, the white space + and bang characters weren't getting parsed correctly. + + Change SIGALRM handler to save and restore errno. + + Change SunOS include/compat.h to include <vfork.h> so that the + ex/filter.c code works again. + + Don't put lines deleted by the ex delete command into the numeric + buffers, matching historic practice. + + Fix; if appending to a buffer, default buffer historically only + references the appended text, not the resulting text. + + Support multiple, semi-colon separated search strings, and 'z' + commands after search strings. + + Make previous context mark setting match historic practice (see + docs/internals/context). + + Fix the set command to permit whitespace between the option and + the question mark, fix question marks in general. + + Fix bug where ex error messages could be accidentally preceded + by a single space. + + Fix bug where curses reorganization could lose screen specific + mappings as soon as any screen exited. + + Fix bug in paragraph code where invalid macros could be matched. + Make paragraph motions stop at formfeed (^L) characters. + + Change 'c' to match historic practice, it cut text into numeric + buffers. +1.25 -> 1.26 Tue Jul 19 17:46:24 1994 + + Ignore SIGWINCH if the screen size is unchanged; SunOS systems + deliver one when a screen is uncovered. + + Fix: don't permit a command with a motion component to wrap due + to wrapscan and return to the original cursor position. + + Fix: ^E wasn't beeping when reaching the bottom of the file. + + Fix bg/fg bug where tmp file exiting caused a NULL dereference. + + Rework file locking code to use fcntl(2) explicitly. + + Fix bug in section code where invalid macros could be matched. + + Fix bug where line number reset by vi's Q command. + + Add explicit character mode designation to character mode buffers. + + Add <sys/ioctl.h> include to sex/sex_window.c, needed by NET/2 + vintage systems. + + Change to always flush a character during suspend, 4BSD curses + has the optimization where it doesn't flush after a standend(). + + Fix bug on OSF1 where <curses.h> changes the values of VERASE, + VKILL and VWERASE to incorrect ones. + + Fix bug where optarg used incorrectly in main.c. + + Block all signals when acting on a signal delivery. + + Fix recovery bug where RCV_EMAIL could fire even if there wasn't + a backing file; format recovery message. +1.24 -> 1.25 Sun Jul 17 14:33:38 1994 + + Stop allowing keyboard suspends (^Z) in insert mode, it's hard + to get autowrite correct, and it's not historic practice. + + Fix z^, z+ to match historic practice. + + Bug in message handling, "vi +35 non-existent_file" lost the + status message because the "+35" pushed onto the stack erased + it. For now, change so that messages aren't displayed if there + are keys waiting -- may need to add a "don't-erase" bit to the + character in the stack instead. + + Bug in svi_msgflush(), where error messages could come out in + normal video. +1.23 -> 1.24 Sat Jul 16 18:30:18 1994 + + Fix core dump in exf.c, where editing a non-existent file and + exiting could cause already free'd memory to be free'd. + + Clean up numerous memory errors, courtesy of Purify. + + Change process wait code to fail if wait fails, and not attempt + to interpret the wait return information. + + Open recovery and DB files for writing as well as reading, System + V (fcntl) won't let you acquire LOCK_EX locks otherwise. + + Fix substitute bug where could malloc 0 bytes (AIX breaks). + + Permit the mapping of <carriage-return>, it's historic practice. + + Historic vi didn't eat <blank> characters before the force + flag, match historic practice. + + Bug in ex argument parsing, corrected for literal characters + twice. + + Delete screen specific maps when the screen closes. + + Move to the first non-<blank> in the line on startup; historic + practice. + + Change the ex visual command to move directly to a line if no + trailing 'z' command. + + Fix "[[" and "]]" to match historic practice (yet again...). + + Fix "yb" and "y{" commands to update the cursor correctly. + + Change "~<motion>" to match the yank cursor movement semantics + exactly. + + Move all of the curses related code into sex/svi -- major rework, + but should help in future ports. + + Fix bug in split code caused by new file naming code, where would + drop core when a split screen exited. + + Change svi_ex_write to do character display translation, so that + messages with file names in them are displayed correctly. + + Display the file name on split screens instead of a divider line. + + Fix move bug, wasn't copying lines before putting them. + + Fix bug were :n dropped core if no arguments supplied. + + Don't quote characters in executed buffer: "ifoo<esc>" should leave + insert mode after the buffer is executed. + + Tagpop and tagpush should set the absolute mark in case only moving + within a file. + + Skip leading whitespace characters before tags and cursor word + searches. + + Fix bug in ex_global where re_conv() was allocating the temporary + buffer and not freeing it. +1.22 -> 1.23: Wed Jun 29 19:22:33 1994 + + New <sys/cdefs.h> required "inline" to change to "__inline" + + Fix System V curses code for new ^Z support. + + Fix off-by-one in the move code, avoid ":1,$mo$" with only one + line in the buffer. + + Line orientation of motion commands was remembered too long, + i.e. '.' command could be incorrectly marked as line oriented. + + Move file modification time into EXF, so it's shared across + split screens. + + Put the prev[ious] command back in, people complained. + + Random fixes to next/prev semantics changed in 1.22. + + Historically vi doesn't only move to the last address if there's + ANYTHING after the addresses, e.g. ":3" moves to line 3, ":3|" + prints line 3. +1.21 -> 1.22: Mon Jun 27 11:01:41 1994 + + Make the line between split screens inverse video again. + + Delete the prev[ious] command, it's not useful enough to keep. + + Rework :args/file name handling from scratch -- MAJOR CHANGE, + likely to introduce all sorts of new bugs. + + Fix RE bug where no subexpressions in the pattern but there were + subexpressions referenced in the replacement, e.g. "s/XXX/\1/g". + + Change recovery to not leave unmodified files around after a + crash, by using the owner 'x' bit on unmodified backup files. + MAJOR CHANGE, the system recovery script has to change! + + Change -r option to delete recovery.* files that reference non- + existent vi.* files. + + Rework recovery locking so that fcntl(2) locking will work. + + Fix append (upper-case) buffers, broken by cut fixes. + + Fix | to not set the absolute motion mark. + + Read $HOME/.exrc file on startup if the effective user ID is + root. This makes running vi while su(1)'d work correctly. + + Use the full pathname of the file as the recovery name, not + just the last component. Matches historic practice. + + Keep marks in empty files from being destroyed. + + Block all caught signals before calling the DB routines. + + Make the line change report match historic practice (yanked + lines were different than everything else). + + Add section on multiple screens to the reference manual. + + Display all messages at once, combine onto a single line if + possible. Delete the trailing period from all messages. +1.20 -> 1.21: Thu May 19 12:21:58 1994 + + Delete the -l flag from the recover mail. + + Send the user email if ex command :preserve executed, this matches + historic practice. Lots of changes to the preserve and recovery + code, change preserve to snapshot files (again, historic practice). + + Make buffers match historic practice: "add logically stores text + into buffer a, buffer 1, and the unnamed buffer. + + Print <tab> characters as ^I on the colon command line if the + list option set. + + Adjust ^F and ^B scroll values in the presence of split screens + and small windows. + + Break msg* routines out from util.c into msg.c, start thinking + about message catalogs. + + Add tildeop set option, based on stevie's option of the same name. + Changes the ~ command into "[count] ~ motion", i.e. ~ takes a + trailing motion. + + Chose NOT to match historic practice on cursor positioning after + consecutive undo commands on a single line; see vi/v_undo.c for + the comment. + + Add a one line cache so that multiple changes to the same line + are only counted once (e.g. "dl35p" changes one line, not 35). + + Rework signals some more. Block file sync signals in vi routines + that interface to DB, so can sync the files at interrupt time. + Write up all of the signal handling arguments, see signal.c. +1.19 -> 1.20: Thu May 5 19:24:57 1994 + + Return ^Z to synchronous handling. See the dicussion in signal.c + and svi_screen.c:svi_curses_init(). + + Fix bug where line change report was wrong in util.c:msg_rpt(). +1.18 -> 1.19: Thu May 5 12:59:51 1994 + + Block DSUSP so that ^Y isn't delivered at SIGTSTP. + + Fix bug -- put into an empty file leaves the cursor at 1,0, + not the first nonblank. + + Fix bug were number of lines reported for the 'P' command was + off-by-one. + + Fix bug were 0^D wasn't being handled correctly. + + Delete remnants of ^Z as a raw character. + + Fix bug where if a map was an entire colon command, it may never + have been displayed. + + Final cursor position fixes for the vi T and t commands. + + The ex :next command took an optional ex command as it's first + argument similar to the :edit commands. Match historic practice. +1.17 -> 1.18: Wed May 4 13:57:10 1994 + + Rework curses information in the PORT/Makefile's. + + Minor fixes to ^Z asynchronous code. +1.16 -> 1.17: Wed May 4 11:15:56 1994 + + Make ex comment handling match historic practice. + + Make ^Z work asynchronously, we can no longer use the SIGTSTP + handler in the curses library. +1.15 -> 1.16: Mon May 2 19:42:07 1994 + + Make the 'p' and 'P' commands support counts, i.e. "Y10p" works. + + Make characters that map to themselves as the first part of the + mapping work, it's historic practice. + + Fix bug where "s/./\& /" discarded the space in the replacement + string. + + Add support for up/down cursor arrows in text input mode, rework + left/right support to match industry practice. + + Fix bug were enough character remapping could corrupt memory. + + Delete O_REMAPMAX in favor of setting interrupts after N mapped + characters without a read, delete the map counter per character. + MAJOR CHANGE. All of the interrupt signal handling has been + reworked so that interrupts are always turned on instead of + being turned on periodically, when an interruptible operation is + pending. + + Fix bug where vi wait() was interrupted by the recovery alarm. + + Make +cmd's and initial commands execute with the current line + set to the last line of the file. This is historic practice. + + Change "lock failed" error message to a file status message. + It always fails over NFS, and making all NFS files readonly + isn't going to fly. + + Use the historic line number format, but check for overflow. + + Fix bug where vi command parser ignored buffers specified as + part of the motion command. + + Make [@*]buffer commands on character mode buffers match historic + practice. + + Fix bug where the cmap/chf entries of the tty structure weren't + being cleared when new characters were read. + + Fix bug where the default command motion flags were being set + when the command was a motion component. + + Fix wrapmargin bug; if appending characters, and wrapmargin breaks + the line, an additional space is eaten. +1.14 -> 1.15: Fri Apr 29 07:44:57 1994 + + Make the ex delete command work in any empty file. + + Fix bug where 't' command placed the cursor on the character + instead of to its left. + + ^D and ^U didn't set the scroll option value historically. + Note, this change means that any user set value (e.g. 15^D) + will be lost when splitting the screen, since the split code + now resets the scroll value regardless. + + Fix the ( command to set the absolute movement mark. + + Only use TIOCGWINSZ for window information if SIGWINCH signal + caught. + + Delete the -l flag, and make -r work for multiple arguments. + Add the ex "recover[!] file" command. + + Switch into ex terminal mode and use the sex routines when + append/change/insert called from vi mode. + + Make ^F and ^B match historic practice. This required a fairly + extensive rework of the svi scrolling code. + + Cursor positioning in H, M, L, G (first non-blank for 1G) wasn't + being done correctly. Delete the SETLFNB flag. H, M, and L stay + logical movements (SETNNB) and G always moves to the first nonblank. + + System V uses "lines" and "cols", not "li" and "co", change as + necessary. Check termcap function returns for errors. + + Fix `<character> command to do start/end of line correction, + and to set line mode if starting and stopping at column 0. + + Fix bug in delete code where dropped core if deleted in character + mode to an empty line. (Rework the delete code for efficiency.) + + Give up on SunOS 4.1.X, and use "cc" instead of /usr/5bin/cc. + + Protect ex_getline routine from interrupted system calls (if + possible, set SA_RESTART on SIGALRM, too). + + Fix leftright scrolling bug, when moving to a shorter line. + + Do validity checking on the copy, move, t command target line + numbers. + + Change for System V % pattern broke trailing flags for empty + replacement strings. + + Fix bug when RCM flags retained in the saved dot structure. + + Make the ex '=' command work for empty files. + + Fix bug where special_key array was being free'd (it's no longer + allocated). + + Matches cut in line mode only if the starting cursor is at or + before the first nonblank in its line, and the ending cursor is + at or after the last nonblank in its line. + + Add the :wn command, so you can write a file and switch to a new + file in one command. + + Allow only a single key as an argument to :viusage. + + New movement code broke filter/paragraph operations in empty + files ("!}date" in an empty file was dropping core). +1.12 -> 1.14: Mon Apr 18 11:05:10 1994 (PUBLICLY AVAILABLE VERSION, 4.4BSD) + + Fix FILE structure leakage in the ex filter code. + + Rework suspend code for System V curses. Nvi has to do the + the work, there's no way to get curses to do it right. + + Revert SunOS 4.1.X ports to the distributed curses. There's + a bug in Sun's implementation that we can't live with. + + Quit immediately if row/column values are unreasonable. + + Fix the function keys to match vi historic behavior. + + Replace the echo/awk magic in the Makefile's with awk scripts. +1.11 -> 1.12: Thu Apr 14 11:10:19 1994 + + Fix bug where only the first vi key was checked for validity. + + Make 'R' continue to overwrite after a <carriage-return>. + + Only display the "no recovery" message once. + + Rework line backup code to restore the line to its previous + condition. + + Don't permit :q in a .exrc file or EXINIT variable. + + Fix wrapscan option bug where forward searches become backward + searches and do cursor correction accordingly. + + Change "dd" to move the cursor to the first non-blank on the line. + + Delete cursor attraction to the first non-blank, change non-blank + motions to set the most attractive cursor position instead. + + Fix 'r' substitute option to set the RE to the last RE, not the + last substitute RE. + + Fix 'c' and 'g' substitute options to always toggle, and fix + edcompatible option to not reset them. + + Display ex error messages in inverse video. + + Fix errorbells option to match historic practice. + + Delete fixed character display table in favor of table built based + on the current locale. + + Add ":set octal" option, that displays unknown characters as octal + values instead of the default hexadecimal. + + Make all command and text input modes interruptible. + + Fix ex input mode to display error messages immediately, instead + of waiting for the lines to be resolved. + + Fix bug where vi calling append could overwrite the command. + + Fix off-by-one in the ex print routine tab code. + + Fix incorrect ^D test in vi text input routines. + + Add autoindent support for ex text insert routines. + + Add System V substitute command replacement pattern semantics, + where '%' means the last replacement pattern. + + Fix bug that \ didn't escape newlines in ex commands. + + Regularize the names of special characters to CH_*. + + Change hex insert character from ^Vx<hex_char> to ^X<hex_char> + + Integrate System V style curses, so SunOS and Solaris ports can + use the native curses implementation. +1.10 -> 1.11: Thu Mar 24 16:07:45 EST 1994 (PUBLICLY AVAILABLE VERSION) + + Change H, M, and L to set the absolute mark, historical practice. + + Fix bug in stepping through multiple tags files. + + Add "remapmax" option that turns off map counts so you can remap + infinitely. If it's off, term_key() can be interrupted from the + keyboard, which will cause the buffers to flush. I also dropped + the default max number of remaps to 50. (Only Dave Hitz's TM + macros and maze appear to go over that limit.) + + Change :mkexrc to not dump w{300,1200,9600}, lisp options. + + Fix backward search within a line bug. + + Change all the includes of "pathnames.h" to use <>'s so that the + PORT versions can use -I. to replace it with their own versions. + + Make reads and writes interruptible. Rework code that enters and + leaves ex for '!' and filter commands, rework all interrupt and + timer code. + + Fix core dump when user displayed option in .exrc file. + + Fix bug where writing empty files didn't update the saved + modification time. + + Fix bug where /pattern/ addressing was always a backward search. + + Fix bug triggered by autoindent of more than 32 characters, where + nvi wasn't checking the right TEXT length. + + Fix bug where joining only empty lines caused a core dump. +1.09 -> 1.10: Sat Mar 19 15:40:29 EST 1994 + + Fix "set all" core dump. +1.08 -> 1.09: Sat Mar 19 10:11:14 EST 1994 + + If the tag's file path is relative, and it doesn't exist, check + relative to the tag file location. + + Fix ~ command to free temporary buffer on error return. + + Create vi.ref, a first cut at a reference document for vi. + The manual page and the reference document only document the + set options, so far. + + Fix 1G bug not always going to the first non-blank. + + Upgrade PORT/regex to release alpha3.4, from Henry Spencer. + + Add MKS vi's "cdpath" option, supporting a cd search path. + + Handle if search as a motion was discarded, i.e. "d/<erase>". + + Change nvi to not create multiple recovery files if modifying + a recovered file. + + Decide to ignore that the cursor is before the '$' when inserting + in list mode. It's too hard to fix. +1.07 -> 1.08: Wed Mar 16 07:37:36 EST 1994 + + Leftright and big line scrolling fixes. This meant more changes + to the screen display code, so there may be new problems. + + Don't permit search-style addresses until a file has been read. + + "c[Ww]" command incorrectly handled the "in whitespace" case. + + Fix key space allocation bug triggered by cut/paste under SunOS. + + Ex move command got the final cursor position wrong. + + Delete "optimize option not implemented" message. + + Make the literal-next character turn off mapping for the next + character in text input mode. +1.06 -> 1.07: Mon Mar 14 11:10:33 EST 1994 + + The "wire down" change in 1.05 broke ex command parsing, there + wasn't a corresponding change to handle multiple K_VLNEXT chars. + + Fix final position for vi's 't' command. +1.05 -> 1.06: Sun Mar 13 16:12:52 EST 1994 + + Wire down ^D, ^H, ^W, and ^V, regardless of the user's termios + values. + + Add ^D as the ex scroll command. + + Support ^Q as a literal-next character. + + Rework abbreviations to be delimited by any !inword() character. + + Add options description to the manual page. + + Minor screen cache fix for svi_get.c. + + Rework beautify option support to match historical practice. + + Exit immediately if not reading from a tty and a command fails. + + Default the SunOS 4.* ports to the distributed curses, not SMI's. +1.04 -> 1.05: Thu Mar 24 16:07:45 EST 1994 + + Make cursor keys work in input mode. + + Rework screen column code in vi curses screen. MAJOR CHANGE -- + after this, we'll be debugging curses screen presentation from + scratch. + + Explode include files in vi.h into the source files. +1.03 -> 1.04: Sun Mar 6 14:14:16 EST 1994 + + Make the ex move command keep the marks on the moved lines. + + Change resize semantics so you can set the screen size to a + specific value. A couple of screen fixes for the resize code. + + Fixes for foreground/background due to SIGWINCH. + + Complete rework of all of vi's cursor movements. The underlying + assumption in the old code was that the starting cursor position + was part of the range of lines cut or deleted. The command + "d[[" is an example where this isn't true. Change it so that all + motion component commands set the final cursor position separately + from the range, as it can't be done correctly later. This is a + MAJOR CHANGE -- after this change, we'll be debugging the cursor + positioning from scratch. + + Rewrite the B, b, E, e commands to use vi's getc() interface + instead of rolling their own. + + Add a second MARK structure, LMARK, which is the larger mark + needed by the logging and mark queue code. Everything else uses + the reworked MARK structure, which is simply a line/column pair. + + Rework cut/delete to not expect 1-past-the-end in the range, but + to act on text to the end of the range, inclusive. + + Sync on write's, to force NFS to flush. +1.01 -> 1.03: Sun Jan 23 17:50:35 EST 1994 (PUBLICLY AVAILABLE VERSION) + + Tag stack fixes, was returning to the tag, not the position from + which the user tagged. + + Only use from the cursor to the end of the word in cursor word + searches and tags. (Matches historical vi behavior.) + + Fix delete-last-line bug when line number option set. + + Fix usage line for :split command. + + If O_NUMBER set, long input lines would eventually fail, the column + count for the second screen of long lines wasn't set correctly. + + Fix for [[ reaching SOF with a column longer than the first line. + + Fix for multiple error messages if no screen displayed. + + Fix :read to set alternate file name as in historical practice. + + Fix cut to rotate the numeric buffers if line mode flag set. +1.00 -> 1.01: Wed Jan 12 13:37:18 EST 1994 + + Don't put cut items into numeric buffers if cutting less than + parts of two lines. +0.94 -> 1.00: Mon Jan 10 02:27:27 EST 1994 + + Read-ahead not there; BSD tty driver problem, SunOS curses + problem. + + Global command could error if it deleted the last line of + the file. + + Change '.' to only apply to the 'u' if entered immediately + after the 'u' command. "1pu.u.u. is still broken, but I + expect that it's going to be sacrificed for multiple undo. + + If backward motion on a command, now move to the point; get + yank cursor positioning correct. + + Rework cut buffers to match historic practice -- yank/delete + numeric buffers redone sensibly, ignoring historic practice. +0.92 -> 0.93: Mon Dec 20 19:52:14 EST 1993 + + Christos Zoulas reimplemented the script windows using pty's, + which means that they now work reasonably. The down side of + this is that almost all ports other than 4.4BSD need to include + two new files, login_tty.c and pty.c from the PORT/clib directory. + I've added them to the Makefiles. + + All calloc/malloc/realloc functions now cast their pointers, for + SunOS -- there should be far fewer warning messages, during the + build. The remaining messages are where CHAR_T's meet char *'s, + i.e. where 8-bit clean meets strcmp. + + The user's argument list handling has been reworked so that there + is always a single consistent position for use by :next, :prev and + :rewind. + + All of the historical options are now at least accepted, although + not all of them are implemented. (Edcompatible, hardtabs, lisp, + optimize, redraw, and slowopen aren't implemented.) + + The RE's have been reworked so that matches of length 0 are handled + in the same way as vi used to handle them. + + Several more mapping fixes and ex parser addressing fixes. diff --git a/usr.bin/vi/docs/ev b/usr.bin/vi/docs/ev new file mode 100644 index 0000000..144295a --- /dev/null +++ b/usr.bin/vi/docs/ev @@ -0,0 +1,55 @@ +# @(#)ev 8.4 (Berkeley) 4/29/94 + +Ev: Vi: Result: +<CK> <CK> (Cursor keys). Move around the file. + +Meta key commands: +^A<#> <#>G Goto line #. +^A$ G Goto the end of the file. +^A/ / Prompt and execute a forward search. +^A: : Prompt and execute an ex command. +^A? ? Prompt and execute a backward search. +^Ac y'<c> Copy to mark in line mode (or copy the current line). +^AC y`<c> Copy to mark in character mode. +^Ad d'<c> Delete to mark in line mode (or delete the current line). +^AD d`<c> Delete to mark in character mode. +^Aj J Join lines. +^Am m<c> Mark the current cursor position. +^AN N Repeat search in the reverse direction. +^An ^A Search for the word under the cursor. +^Ar u Redo a command. +^Au u Undo a command. + +Single key commands: +^B ^B Page up a screen. +^C ^C Interrupt long-running commands. +^D ^D Page down a half-screen. +^E $ End of line. +^F ^F Page down a screen. +^G ^G File status/information. +^H X Delete the character to the left of the cursor. +^I (TAB) +^J j Cursor down one line. +^K k Cursor up one line. +^L ^L Redraw the screen. +^M (CR) ^M In insert mode, split the line at the current cursor, + creating a new line. + In overwrite mode, cursor down one line. +^N n Repeat previous search, in previous direction. +^O (UNUSED) +^P p Paste the cut text at the cursor position. +^Q (XON/XOFF) +^R (UNUSED) +^S (XON/XOFF) +^T D Truncate the line at the cursor position. +^U ^U Page up a half-screen. +^V<c> ^V<c> Insert/overwrite with a literal next character. +^W w Move forward one whitespace separated word. +^X x Delete the current character. +^Y (UNUSED) +^Z ^Z Suspend. + +New ex mode commands: + +^A:set ov[erwrite] Toggle "insert" mode, so that input keys overwrite + the existing characters. diff --git a/usr.bin/vi/docs/features b/usr.bin/vi/docs/features new file mode 100644 index 0000000..d410722 --- /dev/null +++ b/usr.bin/vi/docs/features @@ -0,0 +1,92 @@ +List of things that should be added at some point: +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + ++ X11 interface. + ++ Message catalogs. + ++ Forms editing package; use RE's to verify field contents. + ++ Internationalization, including wide character support. + ++ Make db, curses real libraries that we load against instead of + compiling directly. + ++ Full editing capability on the : command line. + ++ Rob Pike's sam RE's. + ++ Filename completion. While on the subject of completion, it would be + nice to have the completion mechanism found in tcsh version >= 6.03. + For instance, the completion for the `:cd' command will be directories + only. The completion for the `:set' command will be all options not + set at that moment, and for `:set un' will be all options that are set + at that moment. The completion for `:< count' will be the flags. + +List of suggested features: +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ++ Add a "push" command that would push a file on the tags stack. + (Essentially make tags a special case of the stack, and make + the stack more general purpose.) + ++ Make :script just run a command and edit the output, and :interactive, + which allows interactive shell session, instead of just the current + :script. + ++ Add versioning based on a "set version" variable, that would + create backup copies when the file was written back, i.e. the + ":w" and autowrite's would copy the original. + ++ Add tagging information to the man page so that users can display + the part of the man page that discusses the command in which they're + interested. + ++ Add a zone option so that you can declare that top/bottom few lines + of the screen aren't filled except by accident, so that the text + you ask for is always concentrated in the center of the screen. + ++ Add "set searchdir" for a list of directories to look in for + files to edit. The semantic is that ":e foo" is replaced with + the file name that is found, so there's no confusion as to + which file is written. + ++ Change + :di[splay] tags -> :tags + :di[splay] screens -> :screens + :di[splay] buffers -> :buffers + ++ A macro record function. Add the ability to record a sequence + of keystrokes into a named buffer for later use. Handy when + you're trying to build a semi-complex macro. + ++ The semantics of :split, :bg, and :fg aren't right. Someone needs to + rethink how they should interact. The main problem arises when users + want to get a window into a new file. Currently, the necessary sequence + is ":split newfile|^W|:bg". It would be nice if you could simply + background the current screen and edit a new one. + ++ An option to turn on a ``quarter plane'' model so that you can + go as far to the right or down as you wish. The File or the + current line is only extended if you actually put down a char at + the new location. Very handy for ascii graphics and tables. + ++ Some way of replacing the command bindings. For this to work + cleanly the notion of a command must be separate from that of a + key. (Simulate the Rand editor?) + ++ Vertical splitting, so you can see files side by side. + ++ Tracking. Two or more files are associated so that when one file + is scrolled up/down/left/right other files track by the same amount. + Tracking may be constrained such that two files only track vertically + or horizontally. This is relatively easy to implement. + ++ A status file so that the next time invocation of the editor returns + to the same place, with the same number of windows etc. In case of + change of the screen size, reasonable defaults are used. For each + window size and location of the window, name of the file and position + in it, any tab settings, any other settings for the window (such as + insert/overwrite mode, auto indent etc). Last search RE and maybe + direction. If a file does not exist the next time you invoke the + editor, its window is left in the same place but with some default + message. diff --git a/usr.bin/vi/docs/internals/autowrite b/usr.bin/vi/docs/internals/autowrite new file mode 100644 index 0000000..55cd13b --- /dev/null +++ b/usr.bin/vi/docs/internals/autowrite @@ -0,0 +1,88 @@ +# @(#)autowrite 8.2 (Berkeley) 9/28/93 + +Vi autowrite behavior, the fields with *'s are "don't cares". + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Commands that are affected only by autowrite: + +Command File Autowrite? Action: + modified? +----------------------------------------------- +^Z Y Y Write file and suspend. +^Z Y N Suspend. +^Z N * Suspend. + +# This behavior is NOT identical to :edit. +^ Y Y Write file and jump. +^ Y N Error. +^ N * Jump. + +# The new nvi command ^T (:tagpop) behaves identically to ^]. +# This behavior is identical to :tag, :tagpop, and :tagpush with +# force always set to N. +^] Y Y Write file and jump. +^] Y N Error. +^] N * Jump. + +# There's no way to specify a force flag to the '!' command. +:! Y Y Write file and execute. +:! Y N Warn (if warn option) and execute. +:! N * Execute. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Commands that are affected by both autowrite and force: + +NOTE: the "force" flag is never passed on, i.e. the write +to the file caused by the autowrite flag is never forced. + +Command File Autowrite? Force? Action: + modified? (!) +------------------------------------------------------- +# The first rule (YYY) is historic practice, but seems wrong. +# In nvi, :next and :prev commands behave identically to :rewind. +:next Y Y Y Write changes and jump. +:next Y Y N Write changes and jump. +:next Y N Y Abandon changes and jump. +:next Y N N Error. +:next N * * Jump. + +:rewind Y Y Y Abandon changes and jump. +:rewind Y Y N Write changes and jump. +:rewind Y N Y Abandon changes and jump. +:rewind Y N N Error. +:rewind N * * Jump. + +# The new nvi commands, :tagpop and :tagtop, behave identically to :tag. +# Note, this behavior is the same as :rewind and friends, as well. +:tag Y Y Y Abandon changes and jump. +:tag Y Y N Write changes and jump. +:tag Y N Y Abandon changes and jump. +:tag Y N N Error. +:tag N * * Jump. + +# The command :suspend behaves identically to :stop. +:stop Y Y Y Suspend. +:stop Y Y N Write changes and suspend. +:stop Y N Y Suspend. +:stop Y N N Suspend. +:stop N * * Suspend. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Commands that might be affected by autowrite, but aren't: + +Command File Autowrite? Force? Action: + modified? (!) +------------------------------------------------------- +#:ex, and :vi (executed while in vi mode) behave identically to :edit. +:edit Y * Y Abandon changes and jump. +:edit Y * N Error. +:edit N * * Jump. + +:quit Y * Y Quit. +:quit Y * N Error. +:quit N * * Quit. + +:shell * * * Execute shell. + +:xit Y * * Write changes and exit. +:xit N * * Exit. diff --git a/usr.bin/vi/docs/internals/context b/usr.bin/vi/docs/internals/context new file mode 100644 index 0000000..139a1c3 --- /dev/null +++ b/usr.bin/vi/docs/internals/context @@ -0,0 +1,32 @@ +# @(#)context 8.5 (Berkeley) 7/23/94 + +In historic vi, the previous context mark was always set: + +ex address: + any number, <question-mark>, <slash>, <dollar-sign>, + <single-quote>, <backslash> + +ex commands: undo, "z.", global, vglobal + +vi commands: (, ), {, }, %, [[, ]], ^] + +nvi adds the vi command ^T to this list. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +In historic vi, the previous context mark was set if the +line changed: + +vi commands: '<mark>, G, H, L, M, z + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +In historic vi, the previous context mark was set if the +line or column changed: + +vi commands: `<mark>, /, ?, N, n + +nvi adds the vi command ^A to this list. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +In historic vi, the previous context mark was set in non-visual +mode for ^R and ^L if the line changed, but I have yet to figure +out how the line could change. diff --git a/usr.bin/vi/docs/internals/gdb.script b/usr.bin/vi/docs/internals/gdb.script new file mode 100644 index 0000000..5f180ed --- /dev/null +++ b/usr.bin/vi/docs/internals/gdb.script @@ -0,0 +1,68 @@ +# @(#)gdb.script 8.2 (Berkeley) 9/29/93 + +# display the SVI screen map +# usage dmap(sp) +define dmap + set $h = ((SVI_PRIVATE *)$arg0->svi_private)->h_smap + set $t = ((SVI_PRIVATE *)$arg0->svi_private)->t_smap + while ($h <= $t) + printf "lno: %d; off %d ", (int)$h->lno, (int)$h->off + if ($h->c_ecsize == 0) + printf "flushed\n" + else + printf "\n\tsboff %d; scoff %d\n", \ + (int)$h->c_sboff, (int)$h->c_scoff + printf "\teboff %d; eclen %d; ecsize %d\n", \ + (int)$h->c_eboff, (int)$h->c_eclen, \ + (int)$h->c_ecsize + end + set $h = $h + 1 + end +end + +# display the tail of the SVI screen map +define tmap + set $h = ((SVI_PRIVATE *)$arg0->svi_private)->h_smap + set $t = ((SVI_PRIVATE *)$arg0->svi_private)->t_smap + while ($t >= $h) + printf "lno: %d; off %d ", (int)$t->lno, (int)$t->off + if ($t->c_ecsize == 0) + printf "flushed\n" + else + printf "\n\tsboff %d; scoff %d\n", \ + (int)$t->c_sboff, (int)$t->c_scoff + printf "\teboff %d; eclen %d; ecsize %d\n", \ + (int)$t->c_eboff, (int)$t->c_eclen, \ + (int)$t->c_ecsize + end + set $t = $t - 1 + end +end + +# display the SVI private structure +define svp + print *((SVI_PRIVATE *)sp->svi_private) +end + +# display the marks +define markp + set $h = sp->ep->marks.next + set $t = &sp->ep->marks + while ($h != 0 && $h != $t) + printf "key %c lno: %d cno: %d flags: %x\n", \ + ((MARK *)$h)->name, ((MARK *)$h)->lno, \ + ((MARK *)$h)->cno, ((MARK *)$h)->flags + set $h = ((MARK *)$h)->next + end +end + +# display the tags +define tagp + set $h = sp->taghdr.next + set $t = &sp->taghdr + while ($h != 0 && $h != $t) + printf "tag: %s lno %d cno %d\n", ((TAG *)$h)->frp->fname, \ + ((TAG *)$h)->lno, ((TAG *)$h)->cno + set $h= ((TAG *)$h)->next + end +end diff --git a/usr.bin/vi/docs/internals/input b/usr.bin/vi/docs/internals/input new file mode 100644 index 0000000..9a7506e --- /dev/null +++ b/usr.bin/vi/docs/internals/input @@ -0,0 +1,350 @@ +# @(#)input 5.5 (Berkeley) 7/2/94 + +MAPS, EXECUTABLE BUFFERS AND INPUT IN EX/VI: + +The basic rule is that input in ex/vi is a stack. Every time a key which +gets expanded is encountered, it is expanded and the expansion is treated +as if it were input from the user. So, maps and executable buffers are +simply pushed onto the stack from which keys are returned. The exception +is that if the "remap" option is turned off, only a single map expansion +is done. I intend to be fully backward compatible with this. + +Historically, if the mode of the editor changed (ex to vi or vice versa), +any queued input was silently discarded. I don't see any reason to either +support or not support this semantic. I intend to retain the queued input, +mostly because it's simpler than throwing it away. + +Historically, neither the initial command on the command line (the + flag) +or the +cmd associated with the ex and edit commands was subject to mapping. +Also, while the +cmd appears to be subject to "@buffer" expansion, once +expanded it doesn't appear to work correctly. I don't see any reason to +either support or not support these semantics, so, for consistency, I intend +to pass both the initial command and the command associated with ex and edit +commands through the standard mapping and @ buffer expansion. + +One other difference between the historic ex/vi and nex/nvi is that nex +displays the executed buffers as it executes them. This means that if +the file is: + + set term=xterm + set term=yterm + set term=yterm + +the user will see the following during a typical edit session: + + nex testfile + testfile: unmodified: line 3 + :1,$yank a + :@a + :set term=zterm + :set term=yterm + :set term=xterm + :q! + +This seems like a feature and unlikely to break anything, so I don't +intend to match historic practice in this area. + +The rest of this document is a set of conclusions as to how I believe +the historic maps and @ buffers work. The summary is as follows: + +1: For buffers that are cut in "line mode", or buffers that are not cut + in line mode but which contain portions of more than a single line, a + trailing <newline> character appears in the input for each line in the + buffer when it is executed. For buffers not cut in line mode and which + contain portions of only a single line, no additional characters + appear in the input. +2: Executable buffers that execute other buffers don't load their + contents until they execute them. +3: Maps and executable buffers are copied when they are executed -- + they can be modified by the command but that does not change their + actions. +4: Historically, executable buffers are discarded if the editor + switches between ex and vi modes. +5: Executable buffers inside of map commands are expanded normally. + Maps inside of executable buffers are expanded normally. +6: If an error is encountered while executing a mapped command or buffer, + the rest of the mapped command/buffer is discarded. No user input + characters are discarded. +7: Characters in executable buffers are remapped. +8: Characters in executable buffers are not quoted. + +Individual test cases follow. Note, in the test cases, control characters +are not literal and will have to be replaced to make the test cases work. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +1: For buffers that are cut in "line mode", or buffers that are not cut + in line mode but which contain portions of more than a single line, a + trailing <newline> character appears in the input for each line in the + buffer when it is executed. For buffers not cut in line mode and which + contain portions of only a single line, no additional characters + appear in the input. + +=== test file === +3Gw +w +line 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +=== end test file === + + If the first line is loaded into 'a' and executed: + +1G"ayy@a + + The cursor ends up on the '2', a result of pushing "3Gw^J" onto + the stack. + + If the first two lines are loaded into 'a' and executed: + +1G2"ayy@a + + The cursor ends up on the 'f' in "foo" in the fifth line of the + file, a result of pushing "3Gw^Jw^J" onto the stack. + + If the first line is loaded into 'a', but not using line mode, + and executed: + +1G"ay$@a + + The cursor ends up on the '1', a result of pushing "3Gw" onto + the stack + + If the first two lines are loaded into 'a', but not using line mode, + and executed: + +1G2"ay$@a + + The cursor ends up on the 'f' in "foo" in the fifth line of the + file, a result of pushing "3Gw^Jw^J" onto the stack. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +2: Executable buffers that execute other buffers don't load their + contents until they execute them. + +=== test file === +cwLOAD B^[ +line 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +@a@b +"byy +=== end test file === + + The command is loaded into 'e', and then executed. 'e' executes + 'a', which loads 'b', then 'e' executes 'b'. + +5G"eyy6G"ayy1G@e + + The output should be: + +=== output file === +cwLOAD B^[ +LOAD B 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +@a@b +"byy +=== end output file === + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +3: Maps and executable buffers are copied when they are executed -- + they can be modified by the command but that does not change their + actions. + + Executable buffers: + +=== test file === +line 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +@a@b +"eyy +cwEXECUTE B^[ +=== end test file === + +4G"eyy5G"ayy6G"byy1G@eG"ep + + The command is loaded into 'e', and then executed. 'e' executes + 'a', which loads 'e', then 'e' executes 'b' anyway. + + The output should be: + +=== output file === +line 1 foo bar baz +EXECUTE B 2 foo bar baz +line 3 foo bar baz +@a@b +"eyy +cwEXECUTE B^[ +line 1 foo bar baz +=== end output file === + + Maps: + +=== test file === +Cine 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +=== end test file === + + Entering the command ':map = :map = rB^V^MrA^M1G==' shows that + the first time the '=' is entered the '=' map is set and the + character is changed to 'A', the second time the character is + changed to 'B'. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +4: Historically, executable buffers are discarded if the editor + switches between ex and vi modes. + +=== test file === +line 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +cwCHANGE^[Q:set +set|visual|1Gwww +=== end test file === + +vi testfile +4G"ayy@a + +ex testfile +$p +yank a +@a + + In vi, the command is loaded into 'a' and then executed. The command + subsequent to the 'Q' is (historically, silently) discarded. + + In ex, the command is loaded into 'a' and then executed. The command + subsequent to the 'visual' is (historically, silently) discarded. The + first set command is output by ex, although refreshing the screen usually + causes it not to be seen. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +5: Executable buffers inside of map commands are expanded normally. + Maps inside of executable buffers are expanded normally. + + Buffers inside of map commands: + +=== test file === +line 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +cwREPLACE BY A^[ +=== end test file === + +4G"ay$:map x @a +1Gx + + The output should be: + +=== output file === +REPLACE BY A 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +cwREPLACE BY A^[ +=== end output file === + + Maps commands inside of executable buffers: + +=== test file === +line 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +X +=== end test file === + +:map X cwREPLACE BY XMAP^[ +4G"ay$1G@a + + The output should be: + +=== output file === +REPLACE BY XMAP 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +X +=== end output file === + + Here's a test that does both, repeatedly. + +=== test file === +line 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +X +Y +cwREPLACED BY C^[ +blank line +=== end test file === + +:map x @a +4G"ay$ +:map X @b +5G"by$ +:map Y @c +6G"cy$ +1Gx + + The output should be: + +=== output file === +REPLACED BY C 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +X +Y +cwREPLACED BY C^[ +blank line +=== end output file === + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +6: If an error is encountered while executing a mapped command or + a buffer, the rest of the mapped command/buffer is discarded. No + user input characters are discarded. + +=== test file === +line 1 foo bar baz +line 2 foo bar baz +line 3 foo bar baz +:map = 10GcwREPLACMENT^V^[^[ +=== end test file === + + The above mapping fails, however, if the 10G is changed to 1, 2, + or 3G, it will succeed. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +7: Characters in executable buffers are remapped. + +=== test file === +abcdefghijklmnnop +ggg +=== end test file === + +:map g x +2G"ay$1G@a + + The output should be: + +=== output file === +defghijklmnnop +ggg +=== end output file === + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +8: Characters in executable buffers are not quoted. + +=== test file === +iFOO^[ + +=== end test file === + +1G"ay$2G@a + + The output should be: + +=== output file === +iFOO^[ +FOO +=== end output file === +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= diff --git a/usr.bin/vi/docs/internals/quoting b/usr.bin/vi/docs/internals/quoting new file mode 100644 index 0000000..f20bd3f --- /dev/null +++ b/usr.bin/vi/docs/internals/quoting @@ -0,0 +1,219 @@ +# @(#)quoting 5.4 (Berkeley) 8/20/93 + +QUOTING IN EX/VI: + +There are two escape characters in historic ex/vi, ^V (or whatever +character the user specified as their literal next character) and +backslashes. There are two different areas in ex/vi where escaping +is interesting: the command and text input modes, and within the ex +commands themselves. In the examples below, ^V is used as the +typical literal next character. + +1: Escaping characters in ex and vi command and text input modes. + The set of characters that users might want to escape are as + follows: + + vi text input mode (a, i, o, etc.): + + carriage return (^M) + escape (^[) + autoindent characters + (^D, 0, ^, ^T) + erase, word erase, and line erase + (^H, ^W, ^U) + newline (^J) (not historic practice) + suspend (^Z) (not historic practice) + repaint (^L) (not historic practice) + + vi command line (:colon commands): + + carriage return (^M) + escape (^[) + erase, word erase, and line erase + (^H, ^W, ^U) + newline (^J) (not historic practice) + suspend (^Z) (not historic practice) + repaint (^L) (not historic practice) + + ex text input mode (a, i, o, etc.): + + carriage return (^M) + erase, word erase, and line erase + (^H, ^W, ^U) + newline (^J) (not historic practice) + + ex command line: + + carriage return (^M) + erase, word erase, and line erase + (^H, ^W, ^U) + newline (^J) (not historic practice) + suspend (^Z) + + I intend to follow historic practice for all of these cases, which + was that ^V was the only way to escape any of these characters, and + that whatever character followed the ^V was taken literally, i.e. + ^V^V is a single ^V. + + The historic ex/vi disallowed the insertion of various control + characters (^D, ^T, whatever) during various different modes, or, + permitted the insertion of only a single one, or lots of other random + behaviors (you can use ^D to enter a command in ex). I have + regularized this behavior in nvi, there are no characters that cannot + be entered or which have special meaning other than the ones listed + above. + + One comment regarding the autoindent characters. In historic vi, + if you entered "^V0^D" autoindent erasure was still triggered, + although it wasn't if you entered "0^V^D". In nvi, if you escape + either character, autoindent erasure is not triggered. + + This doesn't permit whitespace in command names, but that wasn't + historic practice and doesn't seem worth doing. + + Fun facts to know and tell: + The historic vi implementation for the 'r' command requires + *three* ^V's to replace a single character with ^V. + +2: Ex commands: + + Ex commands are delimited by '|' or newline characters. Within + the commands, whitespace characters delimit the arguments. + + I intend to treat ^V, followed by any character, as that literal + character. + + This is historic behavior in vi, although there are special + cases where it's impossible to escape a character, generally + a whitespace character. + +3: Escaping characters in file names in ex commands: + + :cd [directory] (directory) + :chdir [directory] (directory) + :edit [+cmd] [file] (file) + :ex [+cmd] [file] (file) + :file [file] (file) + :next [file ...] (file ...) + :read [!cmd | file] (file) + :source [file] (file) + :write [!cmd | file] (file) + :wq [file] (file) + :xit [file] (file) + + I intend to treat a backslash in a file name, followed by any + character, as that literal character. + + This is historic behavior in vi. + + In addition, since file names are also subject to word expansion, + the rules for escape characters in section 3 of this document also + apply. This is NOT historic behavior in vi, making it impossible + to insert a whitespace, newline or carriage return character into + a file name. This change could cause a problem if there were files + with ^V's in their names, but I think that's unlikely. + +4: Escaping characters in non-file arguments in ex commands: + + :abbreviate word string (word, string) +* :edit [+cmd] [file] (+cmd) +* :ex [+cmd] [file] (+cmd) + :k key (key) + :map word string (word, string) + :mark key (key) +* :set [option ...] (option) +* :tag string (string) + :unabbreviate word (word) + :unmap word (word) + + These commands use whitespace to delimit their arguments, and use + ^V to escape those characters. The exceptions are starred in the + above list, and are discussed below. + + In general, I intend to treat a ^V in any argument, followed by + any character, as that literal character. This will permit + editing of files name "foo|", for example, by using the string + "foo\^V|", where the literal next character protects the pipe + from the ex command parser and the backslash protects it from the + shell expansion. + + This is backward compatible with historical vi, although there + were a number of special cases where vi wasn't consistent. + +4.1: The edit/ex commands: + + The edit/ex commands are a special case because | symbols may + occur in the "+cmd" field, for example: + + :edit +10|s/abc/ABC/ file.c + + In addition, the edit and ex commands have historically ignored + literal next characters in the +cmd string, so that the following + command won't work. + + :edit +10|s/X/^V / file.c + + I intend to handle the literal next character in edit/ex consistently + with how it is handled in other commands. + + More fun facts to know and tell: + The acid test for the ex/edit commands: + + date > file1; date > file2 + vi + :edit +1|s/./XXX/|w file1| e file2|1 | s/./XXX/|wq + + No version of vi, of which I'm aware, handles it. + +4.2: The set command: + + The set command treats ^V's as literal characters, so the following + command won't work. Backslashes do work in this case, though, so + the second version of the command does work. + + set tags=tags_file1^V tags_file2 + set tags=tags_file1\ tags_file2 + + I intend to continue permitting backslashes in set commands, but + to also permit literal next characters to work as well. This is + backward compatible, but will also make set consistent with the + other commands. I think it's unlikely to break any historic + .exrc's, given that there are probably very few files with ^V's + in their name. + +4.3: The tag command: + + The tag command ignores ^V's and backslashes; there's no way to + get a space into a tag name. + + I think this is a don't care, and I don't intend to fix it. + +5: Regular expressions: + + :global /pattern/ command + :substitute /pattern/replace/ + :vglobal /pattern/ command + + I intend to treat a backslash in the pattern, followed by the + delimiter character or a backslash, as that literal character. + + This is historic behavior in vi. It would get rid of a fairly + hard-to-explain special case if we could just use the character + immediately following the backslash in all cases, or, if we + changed nvi to permit using the literal next character as a + pattern escape character, but that would probably break historic + scripts. + + There is an additional escaping issue for regular expressions. + Within the pattern and replacement, the '|' character did not + delimit ex commands. For example, the following is legal. + + :substitute /|/PIPE/|s/P/XXX/ + + This is a special case that I will support. + +6: Ending anything with an escape character: + + In all of the above rules, an escape character (either ^V or a + backslash) at the end of an argument or file name is not handled + specially, but used as a literal character. diff --git a/usr.bin/vi/docs/internals/structures b/usr.bin/vi/docs/internals/structures new file mode 100644 index 0000000..d49ab65 --- /dev/null +++ b/usr.bin/vi/docs/internals/structures @@ -0,0 +1,61 @@ +# @(#)structures 5.2 (Berkeley) 11/1/93 + +There are three major data structures in this package. The first is a +single global structure (named GS) which contains information common to +all files and screens. It's really pretty tiny, and functions more as a +single place to hang things than anything else. + +The second and third structures are the file structures (named EXF) and +the screen structures (named SCR). They contain information theoretically +unique to a screen or file, respectively. Each SCR structure has a set +of functions which update the screen and/or return information about the +screen from the underlying screen package. + +The GS structure contains linked lists SCR structures. The structures +can also be classed by persistence. The GS structure never goes away +and the SCR structure persists over instances of files. + +File names have different properties than files themselves, so the name +information for a file is held in an FREF structure which is chained from +the SCR structure. + +In general, functions are always passed an SCR structure and often an EXF +structure as well. The SCR structure is necessary for any routine that +wishes to talk to the screen, the EXF structure is necessary for any +routine that wants to modify the file. The relationship between an SCR +structure and its underlying EXF structure is not fixed, and although you +can translate from an SCR to the underlying EXF, it is discouraged. If +this becomes too onerous, I suspect I'll just stop passing around the EXF +in the future. + +The naming of the structures is consistent across the program. (Macros +even depend on it, so don't try and change it!) The global structure is +"gp", the screen structure is "sp", and the file structure is "ep". + +A few other data structures: + +TEXT In nvi/cut.h. This structure describes a portion of a line, + and is used by the input routines and as the "line" part of a + cut buffer. + +CB In nvi/cut.h. A cut buffer. A cut buffer is a place to + hang a list of TEXT structures. + +MARK In nvi/mark.h. A cursor position, consisting of a line number + and a column number. + +MSG In nvi/msg.h. A chain of messages for the user. + +SEQ In nvi/seq.h. An abbreviation or a map entry. + +EXCMDARG + In nvi/ex/excmd.h.stub. The structure that gets passed around + to the functions that implement the ex commands. (The main + ex command loop (see nvi/ex/ex.c) builds this up and then passes + it to the ex functions.) + +VICMDARG + In nvi/vi/vcmd.h. The structure that gets passed around to the + functions that implement the vi commands. (The main vi command + loop (see nvi/vi/vi.c) builds this up and then passes it to the + vi functions.) diff --git a/usr.bin/vi/docs/tutorial/vi.advanced b/usr.bin/vi/docs/tutorial/vi.advanced new file mode 100644 index 0000000..f757ad1 --- /dev/null +++ b/usr.bin/vi/docs/tutorial/vi.advanced @@ -0,0 +1,1458 @@ +Section 26: Index to the rest of the tutorial + +The remainder of the tutorial can be perused at your leisure. Simply find the +topic of interest in the following list, and {/Section xx:/^M} to get to the +appropriate section. (Remember that ^M means the return key) + +The material in the following sections is not necessarily in a bottom up +order. It should be fairly obvious that if a section mentions something with +which you are not familiar, say, buffers, you might {/buffer/^M} followed by +several {n} to do a keyword search of the file for more details on that item. +Another point to remember is that commands are surrounded by curly-braces and +can therefore be found rather easily. To see where, say, the X command is +used try {/{X}/^M}. Subsequent {n} will show you other places the command was +used. We have tried to maintain the convention of placing the command letter +surrounded by curly-braces on the section line where that command is +mentioned. + +Finally, you should have enough 'savvy' at this point to be able to do your +own experimentation with commands without too much hand-holding on the part of +the tutorial. Experimentation is the best way to learn the effects of the +commands. + + Section Topic - description + ------- ------------------- +(Sections 1 through 25 are located in the file vi.beginner.) + 1 introduction: {^F} {ZZ} + 2 introduction (con't) and positioning: {^F} {^B} + 3 introduction (con't) and positioning: {^F} {^B} + 4 positioning: {^F} {^B} ^M (return key) + 5 quitting: {:q!} ^M key + 6 marking, cursor and screen positioning: {m} {G} {'} {z} + 7 marking, cursor and screen positioning: {m} {G} {'} {z} + 8 marking, cursor and screen positioning: {z} {m} {'} + 9 marking and positioning: {m} {''} + 10 line positioning: {^M} {-} + 11 scrolling with {^M} + 12 scrolling with {-} and screen adjustment {z} + 13 notes on use of tutorial + 14 other scrolling and postioning commands: {^E} {^Y} {^D} {^U} + 15 searching: {/ .. /^M} + 16 searching: {? .. ?^M} {n} (in search strings ^ $) + 17 searching: \ and magic-characters in search strings + 18 colon commands, exiting: {:} {ZZ} + 19 screen positioning: {H} {M} {L} + 20 character positioning: {w} {b} {0} {W} {B} {e} {E} {'} {`} + 21 cursor positioning: {l} {k} {j} {h} + 22 adding text: {i} {a} {I} {A} {o} {O} ^[ (escape key) + 23 character manipulation: {f} {x} {X} {w} {l} {r} {R} {s} {S} {J} + 24 undo: {u} {U} + 25 review +(The following sections are in this file.) + 26 Index to the rest of the tutorial ******** YOU ARE HERE ******* + 27 discussion of repeat counts and the repeat command: {.} + 28 more on low-level character motions: {t} {T} {|} + 29 advanced correction operators: {d} {c} + 30 updating the screen: {^R} + 31 text buffers: {"} + 32 rearranging and duplicating text: {p} {P} {y} {Y} + 33 recovering lost lines + 34 advanced file manipulation with vi + 34.1 more than one file at a time: {:n} + 34.2 reading files and command output: {:r} + 34.3 invoking vi from within vi: {:e} {:vi} + 34.4 escaping to a shell: {:sh} {:!} + 34.5 writing parts of a file: {:w} + 34.6 filtering portions of text: {!} + 35 advanced searching: magic patterns + 36 advanced substitution: {:s} + 37 advanced line addressing: {:p} {:g} {:v} + 38 higher level text objects and nroff: ( ) { } [[ ]] + 39 more about inserting text + 40 more on operators: {d} {c} {<} {>} {!} {=} {y} + 41 abbreviations: {:ab} + 42 vi's relationship with the ex editor: {:} + 43 vi on hardcopy terminals and dumb terminals: open mode + 44 options: {:set} {setenv EXINIT} + 44.1 autoindent + 44.2 autoprint + 44.3 autowrite + 44.4 beautify + 44.5 directory + 44.6 edcompatible + 44.7 errorbells + 44.8 hardtabs + 44.9 ignorecase + 44.10 lisp + 44.11 list + 44.12 magic + 44.13 mesg + 44.14 number + 44.15 open + 44.16 optimize + 44.17 paragraphs + 44.18 prompt + 44.19 readonly + 44.20 redraw + 44.21 remap + 44.22 report + 44.23 scroll + 44.24 sections + 44.25 shell + 44.26 shiftwidth + 44.27 showmatch + 44.28 slowopen + 44.29 tabstop + 44.30 tags + 44.31 taglength + 44.32 term + 44.33 terse + 44.34 timeout + 44.35 ttytype + 44.36 warn + 44.37 window + 44.38 wrapscan + 44.39 wrapmargin + 44.40 writeany + 44.41 w300, w1200, w9600 + +Section 27: repetition counts and the repeat command {.} + +Most vi commands will use a preceding count to affect their behavior in some +way. We have already seen how {3x} deletes three characters, and {22G} moves +us to line 22 of the file. For almost all of the commands, one can survive by +thinking of these leading numbers as a 'repeat count' specifying that the +command is to be repeated so many number of times. + +Other commands use the repeat count slightly differently, like the {G} command +which use it as a line number. + +For example: + +{3^D} means scroll down in the file three lines. Subsequent {^D} OR {^U} will +scroll only three lines in their respective directions! + +{3z^M} says put line three of the file at the top of the screen, while {3z.} +says put line three as close to the middle of the screen as possible. + +{50|} moves the cursor to column fifty in the current line. + +{3^F} says move forward 3 screenfulls. This is a repetition count. The +documents advertise that {3^B} should move BACK three screenfulls, but I +can't get it to work. + +Position the cursor on some text and try {3r.}. This replaces three characters +with '...'. However, {3s.....^[} is the same as {3xi.....^[}. + +Try {10a+----^[}. + +A very useful instance of a repetition count is one given to the '.' command, +which repeats the last 'change' command. If you {dw} and then {3.}, you will +delete first one and then three words. You can then delete two more words with +{2.}. If you {3dw}, you will delete three words. A subsequent {.} will delete +three more words. But a subsequent {2.} will delete only two words, not three +times two words. + +Caveat: The author has noticed that any repetition count with {^B} will NOT +work: indeed, if you are at the end of your file and try {3^B} sufficiently +often, the editor will hang you in an infinite loop. Please don't try it: +take my word for it. + +Section 28: {t} {T} {|} + +Position the cursor on line 13 below: + +Line 13: Four score and seven years ago, our forefathers brought ... + +Note that {fv} moves the cursor on/over the 'v' in 'seven'. Do a {0} to return +to the beginning of the line and try a {tv}. The cursor is now on/over the +first 'e' in 'seven'. The {f} command finds the next occurrence of the +specified letter and moves the cursor to it. The {t} command finds the +specified letter and moves the cursor to the character immediately preceding +it. {T} searches backwards, as does {F}. + +Now try {60|}: the cursor is now on the 'o' in 'brought', which is the +sixtieth character on the line. + +Section 29: {d} {c} + +Due to their complexity we have delayed discussion of two of the most powerful +operators in vi until now. Effective use of these operators requires more +explanation than was deemed appropriate for the first half of the tutorial. + +{d} and {c} are called operators instead of commands because they consist of +three parts: a count specification or a buffer specification (see section +#BUFFERS), the {d} or {c}, and the object or range description. We will not +discuss buffers at this stage, but will limit ourselves to count +specifications. Examples speak louder than words: position the cursor at the +beginning of line 14: + +Line 14: Euclid alone has looked on beauty bear. + +Obviously, there is something wrong with this quotation. Type {2fb} to +position the cursor on the 'b' of 'bear'. Now, type {cwbare^[} +and observe the results. The {cw} specifies that the change command {c} is to +operate on a word object. More accurately, it specifies that the range of the +change command includes the next word. + +Position the cursor on the period in Line 14. (one way is to use {f.}) +Now, type {cbbeast^[}. This specifies the range of the change command to be the +previous word (the 'b' reminiscent of the {b} command). If we had wished to +delete the word rather than change it, we would have used the {d} operator, +rather than the {c} operator. + +Position the cursor at the beginning of the line with {0}. Type +{d/look/^M}. The search string specified the range of the delete. +Everything UP TO the word 'looking' was deleted from the line. + +In general, almost any command that would move the cursor will specify a range +for these commands. The most confusing exception to this rule is when {dd} or +{cc} is entered: they refer to the whole line. Following is a summary of the +suffixes (suffices? suffici?) and the ranges they specify: + + suffix will delete{d}/change{c} + ------ ------------------------ + ^[ cancels the command + w the word to the right of the cursor + W ditto, but ignoring punctuation + b the word to the left of the cursor + B ditto, but ignoring punctuation + e see below. + E ditto + (space) a character + $ to the end of the line + ^ to the beginning of the line + / .. / up to, but not including, the string + ? .. ? back to and including the string + fc up to and including the occurrence of c + Fc back to and including the occurrence of c + tc up to but not including the occurrence of c + Tc back to but not including the occurrence of c + ^M TWO lines (that's right: two) + (number)^M that many lines plus one + (number)G up to and including line (number) + ( the previous sentence if you are at the beginning of + the current sentence, or the current sentence up to where + you are if you are not at the beginning of the current + sentence. Here, 'sentence' refers to the intuitive + notion of an English sentence, ending with '!', '?', + or '.' and followed by an end of line or two spaces. + ) the rest of the current sentence + { analogous to '(', but in reference to paragraphs: + sections of text surrounded by blank lines + } analogous to ')', but in reference to paragraphs + [[ analogous to '(', but in reference to sections + ]] analogous to ')', but in reference to sections + H the first line on the screen + M the middle line on the screen + L the last line on the screen + 3L through the third line from the bottom of the screen + ^F forward a screenful + ^B backward a screenful + : + : etc. etc. etc. + +This list is not exhaustive, but it should be sufficient to get the idea +across: after the {c} or {d} operator, you can specify a range with another +move-the-cursor command, and that is the region of text over which the command +will be effective. + +Section 30: updating the screen {^R} + +Vi tries to be very intelligent about the type of terminal you are working on +and tries to use the in-terminal computing power (if any) of your terminal. +Also if the terminal is running at a low baud rate (say 1200 or below), vi sets +various parameters to make things easier for you. For example, if you were +running on a 300 baud terminal (that's 30 characters per second transmission +rate) not all 24 lines of the screen would be used by vi. In addition, there +is a large portion of the editor keeping track of what your screen currently +looks like, and what it would look like after a command has been executed. Vi +then compares the two, and updates only those portions of the screen that have +changed. + +Furthermore, some of you may have noticed (it depends on your terminal) that +deleting lines or changing large portions of text may leave some lines on the +screen looking like: +@ +meaning that this line of the screen does not correspond to any line in your +file. It would cost more to update the line than to leave it blank for the +moment. If you would like to see your screen fully up-to-date with the +contents of your file, type {^R}. + +To see it in action, delete several lines with {5dd}, type {^R}, and then type +{u} to get the lines back. + +Here is as good a place as any to mention that if the editor is displaying the +end of your file, there may be lines on the screen that look like: +~ +indicating that that screen line would not be affected by {^R}. These lines +simply indicate the end of the file. + +Section 31: text buffers {"} + +Vi gives you the ability to store text away in "buffers". This feature is very +convenient for moving text around in your file. There are a total of thirty- +five buffers available in vi. There is the "unnamed" buffer that is used by all +commands that delete text, including the change operator {c}, the substitute +and replace commands {s} and {r}, as well as the delete operator {d} and delete +commands {x} and {X}. This buffer is filled each time any of these commands +are used. However, the undo command {u} has no effect on the unnamed buffer. + +There are twenty-six buffers named 'a' through 'z' which are available for the +user. If the name of the buffer is capitalized, then the buffer is not +overwritten but appended to. For example, the command {"qdd} will delete one +line and store that line in the 'q' buffer, destroying the previous contents of +the buffer. However, {"Qdd} will delete one line of text and append that line +to the current contents of the 'q' buffer. + +Finally, there are nine buffers named '1' through '9' in which the last nine +deletes are stored. Buffer 1 is the default buffer for the modify commands and +is sometimes called the unnamed buffer. + +To reference a specific buffer, use the double-quote command {"} followed by +the name of the buffer. The next two sections show how buffers can be used to +advantage. + +Section 32: rearranging and duplicating text: {y} {Y} {p} {P} + +Position yourself on line 15 below and {z^M}: + +Line 15: A tree as lovely as a poem ... +Line 16: I think that I shall never see + +Type {dd}. Line 15 has disappeared and been replaced with the empty line (one +with the single character @ on it) or (again depending on your terminal) Line +16 has moved up and taken its place. We could recover Line 15 with an undo +{u} but that would simply return it to its original location. Obviously, the +two lines are reversed, so we want to put line 15 AFTER line 16. This is +simply done with the put command {p}, which you should type now. What has +happened is that {dd} put Line 15 into the unnamed buffer, and the {p} command +retrieved the line from the unnamed buffer. + +Now type {u} and observe that Line 15 disappears again (the put was undone +without affecting the unnamed buffer). Type {P} and see that the capital {P} +puts the line BEFORE the cursor. + +To get Line 15 where it belongs again type {dd}{p}. + +Also in Line 15 note that the words 'tree' and 'poem' are reversed. Using the +unnamed buffer again: {ft}{dw}{ma}{fp}{P}{w}{dw}{`aP} will set things aright +(note the use of the reverse quote). + +The put commands {p} and {P} do not affect the contents of the buffer. +Therefore, multiple {p} or {P} will put multiple copies of the unnamed buffer +into your file. + +Experiment with {d} and {p} on words, paragraphs, etc. Whatever {d} +deletes, {p} can put. + +Position the cursor on Line 17 and {z^M}: + +Line 17: interest apple cat elephant boy dog girl hay farmer + +Our task is to alphabetize the words on line 17. With the named buffers (and a +contrived example) it is quite easy: + +{"idw}{"adw}{"cdw}{"edw}{"bdw}{"ddw}{"gdw}{"hdw}{"fdw} + +stores each of the words in the named buffer corresponding to the first letter +of each of the words ('interest' goes in buffer "i, 'apple' goes in buffer "a, +etc.). Now to put the words in order type: + +{"ap$}{"bp$}{"cp$}{"dp$}{"ep$}{"fp$}{"gp$}{"hp$}{"ip$} + +Notice that, because 'farmer' was at the end of the line, {dw} did not include +a space after it, and that, therefore, there is no space between 'farmer' and +'girl'. This is corrected with {Fg}{i ^[}. + +This example could have been done just as easily with lines as with +words. + +You do not have to delete the text in order to put it into a buffer. If all +you wish to do is to copy the text somewhere else, don't use {d}, rather use +the yank commands {y} or {Y}. {y} is like {d} and {c} - an operator rather +than a command. It, too, takes a buffer specification and a range +specification. Therefore, instead of {dw}{P} to load the unnamed buffer with a +word without deleting the word, use {yw} (yank a word). + +{Y} is designed yank lines, and not arbitrary ranges. That is, {Y} is +equivalent to {yy} (remember that operators doubled means the current line), +and {3Y} is equivalent to {3yy}. + +If the text you yank or modify forms a part of a line, or is an object such as +a sentence which partially spans more than one line, then when you put the text +back, it will be placed after the cursor (or before if you use {P}). If the +yanked text forms whole lines, they will be put back as whole lines, without +changing the current line. In this case, the put acts much like the {o} or {O} +command. + +The named buffers "a through "z are not affected by changing edit files. +However, the unnamed buffer is lost when you change files, so to move text from +one file to another you should use a named buffer. + +Section 33: recovering lost lines + +Vi also keeps track of the last nine deletes, whether you ask for it or not. +This is very convenient if you would like to recover some text that was +accidentally deleted or modified. Position the cursor on line 18 following, +and {z^M}. + + +Line 18: line 1 +Line 19: line 2 +Line 20: line 3 +Line 21: line 4 +Line 22: line 5 +Line 23: line 6 +Line 24: line 7 +Line 25: line 8 +Line 26: line 9 +Type {dd} nine times: now don't cheat with {9dd}! That is totally different. + +The command {"1p} will retrieve the last delete. Furthermore, when the +numbered buffers are used, the repeat-command command {.} will increment the +buffer numbers before executing, so that subsequent {.} will recover all nine +of the deleted lines, albeit in reverse order. If you would like to review the +last nine deletes without affecting the buffers or your file, do an undo {u} +after each put {p} and {.}: + +{"1p}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.} + +will show you all the buffers and leave them and your file intact. + +If you had cheated above and deleted the nine lines with {9dd}, all nine lines +would have been stored in both the unnamed buffer and in buffer number 1. +(Obviously, buffer number 1 IS the unnamed buffer and is just the default +buffer for the modify commands.) + +Section 34: advanced file manipulation: {:r} {:e} {:n} {:w} {!} {:!} + +We've already looked at writing out the file you are editing with the +{:w} command. Now let's look at some other vi commands to make editing +more efficient. + +Section 34.1: more than one file at a time {:n} {:args} + +Many times you will want to edit more than one file in an editing session. +Instead of entering vi and editing the first file, exiting, entering vi and +editing the second, etc., vi will allow you to specify ALL files that you wish +to edit on the invocation line. Therefore, if you wanted to edit file1 and +file2: + +% vi file1 file2 + +will set up file1 for editing. When you are done editing file one, write it +out {:w^M} and then type {:n^M} to get the next file on the list. On large +programming projects with many source files, it is often convenient just to +specify all source files with, say: + +% vi *.c + +If {:n^M} brings in a file that does not need any editing, another {:n^M} +will bring in the next file. + +If you have made changes to the first file, but decide to discard these changes +and proceed to the next file, {:n!^M} forces the editor to discard the current +contents of the editor. + +You can specify a new list of files after {:n}; e.g., {:n f1 f2 f3^M}. This +will replace the current list of files (if any). + +You can see the current list of files being edited with {:args^M}. + +Section 34.2: reading files and command output: {:r} + +Typing {:r fname^M} will read the contents of file fname into the editor and +put the contents AFTER the cursor line. + +Typing {:r !cmd^M} will read the output of the command cmd and place that +output after the cursor line. + +Section 34.3: invoking vi from within vi: {:e} {:vi} + +To edit another file not mentioned on the invocation line, type {:e filename^M} +or {:vi filename^M}. If you wish to discard the changes to the current file, +use the exclamation point after the command, e.g. {:e! filename^M}. + +Section 34.4: escaping to a shell: {:sh} {:!} {^Z} + +Occasionally, it is useful to interrupt the current editing session to perform +a UNIX task. However, there is no need to write the current file out, exit +the editor, perform the task, and then reinvoke the editor on the same file. +One thing to do is to spin off another process. If there are several UNIX +commands you will need to execute, simply create another shell with {:sh^M}. +At this point, the editor is put to sleep and will be reawakened when you log +out of the shell. + +If it is a single command that you want to execute, type {:!cmd^M}, where cmd +is the command that you wish to run. The output of the command will come to +the terminal as normal, and will not be made part of your file. The message +"[Hit return to continue]" will be displayed by vi after the command is +finished. Hitting return will then repaint the screen. Typing another +{:!cmd^M} at this point is also acceptable. + +However, there is a quicker, easier way: type {^Z}. Now this is a little +tricky, but hang in there. When you logged into UNIX, the first program you +began communicating with was a program that is called a "shell" (i.e. it 'lays +over' the operating system protecting you from it, sort of like a considerate +porcupine). When you got your first prompt on the terminal (probably a '%' +character) this was the shell telling you to type your first command. When +you typed {vi filename} for some file, the shell did not go away, it just went +to sleep. The shell is now the parent of vi. When you type {^Z} the editor +goes to sleep, the shell wakes up and says "you rang?" in the form of another +prompt (probably '%'). At this point you are talking to the shell again and +you can do anything that you could before including edit another file! (The +only thing you can't do is log out: you will get the message "There are +stopped jobs.") + +When your business with the shell is done, type {fg} for 'foreground' and the +last process which you ^Z'd out of will be reawakened and the shell will go +back to sleep. I will refer you to the documentation for the Berkeley shell +'csh' for more information on this useful capability. + +Section 34.5: writing parts of a file: {:w} + +The {:w} command will accept a range specifier that will then write only a +selected range of lines to a file. To write this section to a file, position +the cursor on the section line (e.g. {/^Section 34.5:/^M}) and {z^M}. Now type +{^G} to find out the line number (it will be something like "line 513"). Now +{/^Section 34.6:/-1^M} to find the last line of this section, and {^G} to find +its line number (it will be something like 542). To write out this section of +text by itself to a separate file which we will call "sepfile", type +{:510,542w sepfile^M}. If sepfile already exists, you will have to use the +exclamation point: {:1147,1168w! sepfile^M} or write to a different, non- +existent file. + +{:!cat sepfile^M} will display the file just written, and it should be the +contents of this section. + +There is an alternate method of determining the line numbers for the write. +{:set number^M} will repaint the screen with each line numbered. When the file +is written and the numbers no longer needed, {:set nonumber^M} will remove the +numbers, and {^R} will adjust the screen. + +Or, if you remember your earlier lessons about marking lines of text, +mark the beginning and ending lines. Suppose we had used {ma} to mark the +first line of the section and {mb} to mark the last. Then the command +{:'a,'bw sepfile^M} will write the section into "sepfile". In general, +you can replace a line number with the 'name' of a marked line (a single-quote +followed by the letter used to mark the line) + + +Section 34.6: filtering portions of text: {!} + +{!} is an operator like {c} and {d}. That is, it consists of a repetition +count, {!}, and a range specifier. Once the {!} operator is entered in its +entirety, a prompt will be given at the bottom of the screen for a UNIX +command. The text specified by the {!} operator is then deleted and +passed/filtered/piped to the UNIX command you type. The output of the UNIX +command is then placed in your file. For example, place the cursor at the +beginning of the following line and {z^M}: + +ls -l vi.tutorial +********* marks the bottom of the output from the ls command ********** + +Now type {!!csh^M}. The line will be replaced with the output from the ls +command. The {u} command works on {!}, also. + +Here is an extended exercise to display some of these capabilities. When this +tutorial was prepared, certain auxiliary programs were created to aid in its +development. Of major concern was the formatting of sections of the tutorial +to fit on a single screen, particularly the first few sections. What was +needed was a vi command that would 'format' a paragraph; that is, fill out +lines with as many words as would fit in eighty columns. There is no such vi +command. Therefore, another method had to be found. + +Of course, nroff was designed to do text formatting. However, it produces a +'page'; meaning that there may be many blank lines at the end of a formatted +paragraph from nroff. The awk program was used to strip these blank lines from +the output from nroff. Below are the two files used for this purpose: I refer +you to documentation on nroff and awk for a full explanation of their function. +Position the cursor on the next line and {z^M}. + +******** contents of file f ********** +# +nroff -i form.mac | awk "length != 0 { print }" +***** contents of file form.mac ****** +.na +.nh +.ll 79 +.ec +.c2 +.cc +************************************** + +Determine the line numbers of the two lines of file f. They should be +something like 574 and 575, although you better double check: this file is +under constant revision and the line numbers may change inadvertently. Then +{:574,575w f^M}. Do the same for the lines of file form.mac. They will be +approximately 577 and 582. Then {:577,582w form.mac^M}. File f must have +execute privileges as a shell file: {:!chmod 744 f^M}. + +Observe that this paragraph is +rather ratty in appearance. With our newly created files we can +clean it up dramatically. Position the cursor at the beginning +of this paragraph and type the following sequence of +characters +(note that we must abandon temporarily our convention +of curly braces since the command itself contains a curly brace - we +will use square brackets for the nonce): [!}f^M]. + +Here is a brief explanation of what has happened. By typing [!}f^M] we +specified that the paragraph (all text between the cursor and the first blank +line) will be removed from the edit file and piped to a UNIX program called +"f". This is a shell command file that we have created. This shell file runs +nroff, pipes its output to awk to remove blank lines, and the output from awk +is then read back into our file in the place of the old, ratty paragraph. The +file form.mac is a list of commands to nroff to get it to produce paragraphs +to our taste (the right margin is not justified, the line is 79 characters +long, words are not hyphenated, and three nroff characters are renamed to +avoid conflict: note that in this file, the {^G} you see there is vi's display +of the control-G character, and not the two separate characters ^ up-arrow and +G upper-case g). + +This example was created before the existence of the fmt program. I now type +[!}fmt^M] to get the same effect much faster. Actually, I don't type those +six keys each time: I have an abbreviation (which see). + +Section 35: searching with magic patterns + +The documentation available for "magic patterns" (i.e. regular expressions) is +very scanty. The following should explain this possibly very confusing feature +of the editor. This section assumes that the magic option is on. To make +sure, you might want to type {:set magic^M}. + +By "magic pattern" we mean a general description of a piece of text that the +editor attempts to find during a search. Most search patterns consist of +strings of characters that must be matched exactly, e.g. {/card/^M} searches +for a specific string of four characters. Let us suppose that you have +discovered that you consistently have mistyped this simple word as either ccrd +or czrd (this is not so far-fetched for touch typists). You could {/ccrd/^M} +and {n} until there are no more of this spelling, followed by {/czrd/^M} and +{n} until there are no more of these. Or you could {/c.rd/^M} and catch all of +them on the first pass. Try typing {/c.rd/^M} followed by several {n} and +observe the effect. + +Line 27: card cord curd ceard + +When '.' is used in a search string, it has the effect of matching any single +character. + +The character '^' (up-arrow) used at the beginning of a search string means +the beginning of the line. {/^Line 27/^M} will find the example line above, +while {/Line 27/^M} will find an occurrence of this string anywhere in the +line. + +Similarly, {/ the$/^M} will find all occurrences of the word 'the' occurring +at the end of a line. There are several of them in this file. + +Note that {:set nomagic^M} will turn off the special meaning of these magic +characters EXCEPT for '^' and '$' which retain their special meanings at the +beginning and end of a search string. Within the search string they hold no +special meaning. Try {/\/ the$\//^M} and note that the dollar-sign is not the +last character in the search string. Let the dollar-sign be the last +character in the search string, as in {/\/ the$/^M} and observe the result. + +Observe the result of {/back.*file/^M}. This command, followed by sufficient +{n}, will show you all lines in the file that contain both the words 'back' +and 'file' on the same line. The '*' magic character specifies that the +previous regular expression (the '.' in our example) is to be repeatedly +matched zero or more times. In our example we specified that the words 'back' +and 'file' must appear on the same line (they may be parts of words such as +'backwards' or 'workfile') separated by any number (including zero) of +characters. + +We could have specified that 'back' and 'file' are to be words by themselves by +using the magic sequences '\<' or '\>'. E.g. {/\<back\>.*\<file\>/^M}. The +sequence '\<' specifies that this point of the search string must match the +beginning of a word, while '\>' specifies a match at the end of a word. By +surrounding a string with these characters we have specified that they must be +words. + +To find all words that begin with an 'l' or a 'w', followed by an 'a' or an +'e', and ending in 'ing', try {/\<[lw][ea][a-z]*ing\>/^M}. This will match +words like 'learning', 'warning', and 'leading'. The '[..]' notation matches +exactly ONE character. The character matched will be one of the characters +enclosed in the square brackets. The characters may be specified individually +as in [abcd] or a '-' may be used to specify a range of characters as in [a-d]. +That is, [az] will match the letter 'a' OR the letter 'z', while [a-z] will +match any of the lower case letters from 'a' through 'z'. If you would like to +match either an 'a', a '-', or a 'z', then the '-' must be escaped: [a\-z] will +match ONE of the three characters 'a', '-', or 'z'. + +If you wish to find all Capitalized words, try {/\<[A-Z][a-z]*\>/^M}. The +following will find all character sequences that do NOT begin with an +uncapitalized letter by applying a special meaning to the '^' character in +square brackets: {/\<[^a-z][a-z]*\>/^M}. When '^' is the first character of a +square-bracket expression, it specifies "all but these characters". (No +one claimed vi was consistent.) + +To find all variable names (the first character is alphabetic, the remaining +characters are alphanumeric): try {/\<[A-Za-z][A-Za-z0-9]*\>/^M}. + +In summary, here are the primitives for building regular expressions: + + ^ at beginning of pattern, matches beginning of line + $ at end of pattern, matches end of line + . matches any single character + \< matches the beginning of a word + \> matches the end of a word + [str] matches any single character in str + [^str] matches any single character NOT in str + [x-y] matches any character in the ASCII range between x and y + * matches any number (including zero) of the preceding pattern + +Section 36: advanced substitution: {:s} + +The straightforward colon-substitute command looks like the substitute +command of most line-oriented editors. Indeed, vi is nothing more than a +superstructure on the line-oriented editor ex and the colon commands are +simply a way of accessing commands within ex (see section #EX). This gives us +a lot of global file processing not usually found in visual oriented editors. + +The colon-substitute command looks like: {:s/ .. / .. /^M} and will find the +pattern specified after the first slash (this is called the search pattern), +and replace it with the pattern specified after the second slash (called, +obviously enough, the replacement pattern). E.g. position the cursor on line +28 below and {:s/esample/example/^M}: + +Line 28: This is an esample. + +The {u} and {U} commands work for {:s}. The first pattern (the search pattern) +may be a regular expression just as for the search command (after all, it IS a +search, albeit limited to the current line). Do an {u} on the above line, and +try the following substitute, which will do almost the same thing: +{:s/s[^ ]/x/^M}. +Better undo it with {u}. The first pattern {s[^ ]} matches an 's' +NOT followed by a blank: the search therefore ignores the 's'es in 'This' and +'is'. However, the character matched by {[^ ]} must appear in the replacement +pattern. But, in general, we do not know what that character is! (In this +particular example we obviously do, but more complicated examples will follow.) +Therefore, vi (really ex) has a duplication mechanism to copy patterns matched +in the search string into the replacement string. Line 29 below is a copy of +line 28 above so you can adjust your screen. + +Line 29: This is an esample. + +In general, you can nest parts of the search pattern in \( .. \) and refer to +it in the replacement pattern as \n, where n is a digit. The problem outlined +in the previous paragraph is solved with {:s/s\([^ ]\)/x\1/^M}: try it. Here +\1 refers to the first pattern grouping \( .. \) in the search string. + +Obviously, for a single line, this is rather tedious. Where it becomes +powerful, if not necessary, is in colon-substitutes that cover a range of +lines. (See the next section for a particularly comprehensive example.) + +If the entire character sequence matched by the search pattern is needed in +the replacement pattern, then the unescaped character '&' can be used. On +Line 29 above, try {:s/an e.ample/not &/^M}. If another line is to have the +word 'not' prepended to a pattern, then '~' can save you from re-typing the +replacement pattern. E.g. {:s/some pattern/~/^M} after the previous example +would be equivalent to {:s/some pattern/not &/^M}. + +One other useful replacement pattern allows you to change the case of +individual letters. The sequences {\u} and {\l} cause the immediately +following character in the replacement to be converted to upper- or lower-case, +respectively, if this character is a letter. The sequences {\U} and {\L} turn +such conversion on, either until {\E} or {\e} is encountered, or until the end +of the replacement pattern. + +For example, position the cursor on a line: pick a line, any line. Type +{:s/.*/\U&/^M} and observe the result. You can undo it with {u}. + +The search pattern may actually match more than once on a single line. +However, only the first pattern is substituted. If you would like ALL +patterns matched on the line to be substituted, append a 'g' after the +replacement pattern: {:s/123/456/g^M} will substitute EVERY occurrence +on the line of 123 with 456. + +Section 37: advanced line addressing: {:p} {:g} {:v} + +Ex (available through the colon command in vi) offers several methods for +specifying the lines on which a set of commands will act. For example, if you +would like to see lines 50 through 100 of your file: {:50,100p^M} will display +them, wait for you to [Hit return to continue], and leave you on line 100. +Obviously, it would be easier just to do {100G} from within vi. But +what if you would like to make changes to just those lines? Then the +addressing is important and powerful. + +Line 30: This is a text. +Line 31: Here is another text. +Line 32: One more text line. + +The lines above contain a typing error that the author of this tutorial tends +to make every time he attempts to type the word 'test'. To change all of these +'text's into 'test's, try the following: +{:/^Line 30/,/^Line 32/s/text/test/^M}. This finds the beginning and end of +the portion of text to be changed, and limits the substitution to each of the +lines in that range. The {u} command applies to ALL of the substitutions as +a group. + +This provides a mechanism for powerful text manipulations. +And very complicated examples. + +Line 33: This test is a. +Line 34: Here test is another. +Line 35: One line more test. + +The above three lines have the second word out of order. The following command +string will put things right. Be very careful when typing this: it is very +long, full of special characters, and easy to mess up. You may want to +consider reading the following section to understand it before trying the +experiment. Don't worry about messing up the rest of the file, though: the +address range is specified. + +{:/^Line 33/,/^Line 35/s/\([^:]*\): \([^ ]*\) \([^ ]*\) \([^.]*\)/\1: \2 \4 \3/^M} + +There are several things to note about this command string. First of all, the +range of the substitute was limited by the address specification {/^Line +33/,/^Line 35/^M}. It might have been simpler to do {:set number^M} to see the +line numbers directly, and then, in place of the two searches, typed +the line numbers, e.g. {1396,1398}. Or to mark the lines with {ma} and {mb} +and use {'a,'b}. + +Then follows the substitute pattern itself. To make it easier to understand +what the substitute is doing, the command is duplicated below with the various +patterns named for easier reference: + + s/\([^:]*\): \([^ ]*\) \([^ ]*\) \([^.]*\)/\1: \2 \4 \3/ + |--\1---| |--\2---| |--\3---| |--\4---| + |--------search pattern------------------|-replacement| + |--pattern---| + +In overview, the substitute looks for a particular pattern made up of +sub-patterns, which are named \1, \2, \3, and \4. These patterns are specified +by stating what they are NOT. Pattern \1 is the sequence of characters that +are NOT colons: in the search string, {[^:]} will match exactly one character +that is not a colon, while appending the asterisk {[^:]*} specifies that the +'not a colon' pattern is to be repeated until no longer satisfied, and +{\([^:]*\)} then gives the pattern its name, in this case \1. Outside of the +specification of \1 comes {: }, specifying that the next two characters must be +a colon followed by a blank. + +Patterns \2 and \3 are similar, specifying character sequences that are +not blanks. Pattern \4 matches up to the period at the end of the line. + +The replacement pattern then consists of specifying the new order of the +patterns. + +This is a particularly complicated example, perhaps the most complicated +in this tutorial/reference. For our small examples, it is obviously +tedious and error prone. For large files, however, it may be the most +efficient way to make the desired modifications. + +(The reader is advised to look at the documentation for awk. This tool is very +powerful and slightly simpler to use than vi for this kind of file +manipulation. But, it is another command language to learn.) + +Many times, you will not want to operate on every line in a certain +range. Rather you will want to make changes on lines that satisfy +certain patterns; e.g. for every line that has the string 'NPS' on it, +change 'NPS' to 'Naval Postgraduate School'. The {:g} addressing +command was designed for this purpose. The example of this paragraph +could be typed as {:g/NPS/s//Naval Postgraduate School/^M}. + +The general format of the command is {:g/(pattern)/cmds^M} and it +works in the following way: all lines that match the pattern +following the {:g} are 'tagged' in a special way. Then each of these +lines have the commands following the pattern executed over them. + +Line 36: ABC rhino george farmer Dick jester lest +Line 37: george farmer rhino lest jester ABC +Line 38: rhino lest george Dick farmer ABC jester + +Type: + +{:g/^Line.*ABC/s/Dick/Harry Binswanger/|s/george farmer/gentleman george/p^M} + +There are several things of note here. First, lines 36, 37, and 38 above are +tagged by the {:g}. Type {:g/^Line.*ABC/p^M} to verify this. Second, there +are two substitutes on the same line separated by '|'. In general, any colon +commands can be strung together with '|'. Third, both substitutes operate on +all three lines, even though the first stubstitute works on only two of the +lines (36 and 38). Fourth, the second substitute works on only two lines (36 +and 37) and those are the two lines printed by the trailing 'p'. + +The {:v} command works similarly to the {:g} command, except that the sense of +the test for 'tagging' the lines is reversed: all lines NOT matching the search +pattern are tagged and operated on by the commands. + +Using {^V} to quote carriage return (see section 39) can be used in global +substitutions to split two lines. For example, the command +{:g/\. /s//.^V^M/g^M} will change your file so that each sentence is on a +separate line. (Note that we have to 'escape' the '.', because '.' by itself +matches any character. Our command says to find any line which contains a +period followed by 2 spaces, and inserts a carriage return after the period.) + +Caveat: In some of the documentation for ex and vi you may find the +comment to the effect that {\^M} can be used between commands following +{:g}. The author of this tutorial has never gotten this to work and has +crashed the editor trying. + +Section 38: higher level text objects and nroff: {(} {)} [{] [}] {[[} {]]} + +(Note: this section may be a little confusing because of our command +notation. Using curly braces to surround command strings works fine as +long as the command string does not contain any curly braces itself. +However, the curly braces are legitimate commands in vi. Therefore, for +any command sequence that contains curly braces, we will surround that +sequence with SQUARE braces, as on the previous Section line.) + +In working with a document, particularly if using the text formatting +programs nroff or troff, it is often advantageous to work in terms of +sentences, paragraphs, and sections. The operations {(} and {)} move to +the beginning of the previous and next sentences, respectively. Thus +the command {d)} will delete the rest of the current sentence; likewise +{d(} will delete the previous sentence if you are at the beginning of +the current sentence, or, if you are not at the beginning of a sentence, +it will delete the current sentence from the beginning +up to where you are. + +A sentence is defined to end at a '.', '!', or '?' which is followed +by either the end of a line, or by two spaces. Any number of closing +')', ']', '"', and ''' characters may appear after the '.', '!', or '?' +before the spaces or end of line. Therefore, the {(} and {)} commands +would recognize only one sentence in the following line, but two +sentences on the second following line. + +Line 39: This is one sentence. Even though it looks like two. +Line 40: This is two sentences. Because it has two spaces after the '.'. + +The operations [{] and [}] move over paragraphs and the operations {[[} +and {]]} move over sections. + +A paragraph begins after each empty line, and also at each of a set of nroff +paragraph macros. A section begins after each line with a form-feed ^L in the +first column, and at each of a set of nroff section macros. When preparing a +text file as input to nroff, you will probably be using a set of nroff macros +to make the formatting specifications easier, or more to your taste. These +macros are invoked by beginning a line with a period followed by the one or two +letter macro name. Vi has been programmed to recognize these nroff macros, and +if it doesn't recognize your particular macro you can use the {:set paragraphs} +or {:set sections} commands so that it will. + +Section 39: more about inserting text + +There are a number of characters which you can use to make correnctions +during input mode. These are summarized in the following table. + + ^H deletes the last input character + ^W deletes the last input word + (erase) same as ^H; each terminal can define its own erase character; + for some it is ^H, for others it is the DELETE key, and for + others it is '@'. + (kill) deletes the input on this line; each terminal can define its + own line-kill character; for some it is ^U, for others it is + '@'; you will need to experiment on your terminal to find + out what your line-kill and erase characters are. + \ escapes a following ^H, (kill), and (erase) characters: i.e. + this is how to put these characters in your file. + ^[ escape key; ends insertion mode + ^? the delete key; interrupts an insertion, terminating it + abnormally. + ^M the return key; starts a new line. + ^D backtabs over the indentation set by the autoindent option + 0^D backtabs over all indentation back to the beginning of the line + ^^D (up-arrow followed by control-d)same as 0^D, except the indentation + will be restored at the beginning of the next line. + ^V quotes the next non-printing character into the file + +If you wish to type in your erase or kill character (say # or @ or ^U) then you +must precede it with a \, just as you would do at the normal system command +level. A more general way of typing non-printing characters into the file is +to precede them with a ^V. The ^V echoes as a ^ character on which the cursor +rests. This indicates that the editor expects you to type a control character +and it will be inserted into the file at that point. There are a few +exceptions to note. The implementation of the editor does not allow the null +character ^@ to appear in files. Also the linefeed character ^J is used by the +editor to separate lines in the file, so it cannot appear in the middle of a +line. (Trying to insert a ^M into a file, or putting it in the replacement +part of a substitution string will result in the matched line being split in +two. This, in effect, is how to split lines by using a substitution.) You can +insert any other character, however, if you wait for the editor to echo the ^ +before you type the character. In fact, the editor will treat a following +letter as a request for the corresponding control character. This is the only +way to type ^S or ^Q, since the system normally uses them to suspend and resume +output and never gives them to the editor to process. + +If you are using the autoindent option you can backtab over the indent which it +supplies by typing a ^D. This backs up to the boundary specified by the +shiftwidth option. This only works immediately after the supplied autoindent. + +When you are using the autoindent option you may wish to place a label at the +left margin of a line. The way to do this easily is to type ^ (up-arrow) and +then ^D. The editor will move the cursor to the left margin for one line, and +restore the previous indent on the next. You can also type a 0 followed +immediately by a ^D if you wish to kill all indentation and not have it resume +on the next line. + +Section 40: more on operators: {d} {c} {<} {>} {!} {=} {y} + +Below is a non-exhaustive list of commands that can follow the operators +to affect the range over which the operators will work. However, note +that the operators {<}, {>}, {!}, and {=} do not operate on any object +less than a line. Try {!w} and you will get a beep. To get the +operator to work on just the current line, double it. E.g. {<<}. + + suffix will operate on + ------ ------------------------ + ^[ cancels the command + w the word to the right of the cursor + W ditto, but ignoring punctuation + b the word to the left of the cursor + B ditto, but ignoring punctuation + e see below. + E ditto + (space) a character + $ to the end of the line + ^ to the beginning of the line + / .. / up to, but not including, the string + ? .. ? back to and including the string + fc up to and including the occurrence of c + Fc back to and including the occurrence of c + tc up to but not including the occurrence of c + Tc back to but not including the occurrence of c + ^M TWO lines (that's right: two) + (number)^M that many lines plus one + (number)G up to and including line (number) + ( the previous sentence if you are at the beginning of + the current sentence, or the current sentence up to where + you are if you are not at the beginning of the current + sentence. Here, 'sentence' refers to the intuitive + notion of an English sentence, ending with '!', '?', + or '.' and followed by an end of line or two spaces. + ) the rest of the current sentence + { analogous to '(', but in reference to paragraphs: + sections of text surrounded by blank lines + } analogous to ')', but in reference to paragraphs + [[ analogous to '(', but in reference to sections + ]] analogous to ')', but in reference to sections + H the first line on the screen + M the middle line on the screen + L the last line on the screen + 3L through the third line from the bottom of the screen + ^F forward a screenful + ^B backward a screenful + : + : etc. etc. etc. + +This list is not exhaustive, but it should be sufficient to get the idea +across: after the operator, you can specify a range with a move-the-cursor +command, and that is the region of text over which the operator will be +effective. + +Section 41: abbreviations: {:ab} + +When typing large documents you may find yourself typing a large phrase +over and over. Vi gives you the ability to specify an abbreviation for +a long string such that typing the abbreviation will automatically +expand into the longer phrase. + +Type {:ab nps Naval Postgraduate School^M}. Now type: + +{iThis is to show off the nps's UNIX editor.^M^[} + +Section 42: vi's relationship with the ex editor: {:} + +Vi is actually one mode of editing within the editor ex. When you are +running vi you can escape to the line oriented editor of ex by giving +the command {Q}. All of the colon-commands which were introduced above +are available in ex. Likewise, most ex commands can be invoked from vi +using {:}. + +In rare instances, an internal error may occur in vi. In this case you +will get a diagnostic and will be left in the command mode of ex. You can +then save your work and quit if you wish by giving the command {x} after +the colon prompt of ex. Or you can reenter vi (if you are brave) by +giving ex the command {vi}. + +Section 43: vi on hardcopy terminals and dumb terminals: open mode + +(The author has not checked the following documentation for accuracy. It is +abstracted from the Introduction to Vi Editing document.) + +If you are on a hardcopy terminal or a terminal which does not have a cursor +which can move off the bottom line, you can still use the command set of vi, +but in a different mode. When you give the vi command to UNIX, the editor will +tell you that it is using open mode. This name comes from the open command in +ex, which is used to get into the same mode. + +The only difference between visual mode (normal vi) and open mode is the way in +which the text is displayed. + +In open mode the editor uses a single line window into the file, and moving +backward and forward in the file causes new lines to be displayed, always below +the current line. Two commands of vi work differently in open: {z} and {^R}. +The {z} command does not take parameters, but rather draws a window of context +around the current line and then returns you to the current line. + +If you are on a hardcopy terminal, the {^R} command will retype the current +line. On such terminals, the editor normally uses two lines to represent the +current line. The first line is a copy of the line as you started to edit it, +and you work on the line below this line. When you delete characters, the +editor types a number of \'s to show you the characters which are deleted. The +editor also reprints the current line soon after such changes so that you can +see what the line looks like again. + +It is sometimes useful to use this mode on very slow terminals which can +support vi in the full screen mode. You can do this by entering ex and using +an {open} command. + +********************************************************************* +Section 44: options: {:set} {setenv EXINIT} + +You will discover options as you need them. Do not worry about them very much +on the first pass through this document. My advice is to glance through them, +noting the ones that look interesting, ignoring the ones you don't understand, +and try re-scanning them in a couple of weeks. + +If you decide that you have a favorite set of options and would like to change +the default values for the editor, place a {setenv EXINIT} command in your +.login file. When you are given an account under UNIX your directory has +placed in it a file that is executed each time you log in. If one of the +commands in this file sets the environment variable EXINIT to a string of vi +commands, you can have many things done for you each time you invoke vi. For +example, if you decide that you don't like tabstops placed every eight columns +but prefer every four columns, and that you wish the editor to insert linefeeds +for you when your typing gets you close to column 72, and you want +autoindentation, then include the following line in your .login file: + +setenv EXINIT='set tabstop=4 wrapmargin=8 autoindent' + +or equivalently + +setenv EXINIT='se ts=4 wm=8 ai' + +Each time you bring up vi, this command will be executed and the options set. + +There are forty options in the vi/ex editor that the user can set for his/her +own convenience. They are described in more detail in individual sections +below. The section line will show the full spelling of the option name, the +abbreviation, and the default value of the option. The text itself +comes from the ex reference manual and is not the epitome of clarity. + +Section 44.1: {autoindent}, {ai} default: noai + +Can be used to ease the preparation of structured program text. At the +beginning of each append, change or insert command or when a new line is opened +or created by an append, change, insert, or substitute operation within open or +visual mode, ex looks at the line being appended after, the first line changed +or the line inserted before and calculates the amount of white space at the +start of the line. It then aligns the cursor at the level of indentation so +determined. + +If the user then types lines of text in, they will continue to be justified at +the displayed indenting level. If more white space is typed at the beginning +of a line, the following line will start aligned with the first non-white +character of the previous line. To back the cursor up to the preceding tab +stop one can hit {^D}. The tab stops going backwards are defined at multiples +of the shiftwidth option. You cannot backspace over the indent, except by +sending an end-of-file with a {^D}. A line with no characters added to it +turns into a completely blank line (the white space provided for the autoindent +is discarded). Also specially processed in this mode are lines beginning with +an up-arrow `^' and immediately followed by a {^D}. This causes the input to +be repositioned at the beginning of the line, but retaining the previous indent +for the next line. Similarly, a `0' followed by a {^D} repositions at the +beginning but without retaining the previous indent. Autoindent doesn't happen +in global commands or when the input is not a terminal. + +Section 44.2: {autoprint}, {ap} default: ap + +Causes the current line to be printed after each delete, copy, join, move, +substitute, t, undo or shift command. This has the same effect as supplying a +trailing `p' to each such command. Autoprint is suppressed in globals, and +only applies to the last of many commands on a line. + +Section 44.3: {autowrite}, {aw} default: noaw + +Causes the contents of the buffer to be written to the current file if you have +modified it and give a next, rewind, stop, tag, or {!} command, or a control- +up-arrow {^^} (switch files) or {^]} (tag goto) command in visual. Note, that +the edit and ex commands do not autowrite. In each case, there is an +equivalent way of switching when autowrite is set to avoid the autowrite +({edit} for next, rewind! for rewind, stop! for stop, tag! for tag, shell +for {!}, and {:e #} and a {:ta!} command from within visual). + +Section 44.4: {beautify}, {bf} default: nobeautify + +Causes all control characters except tab ^I, newline ^M and form-feed ^L to be +discarded from the input. A complaint is registered the first time a backspace +character is discarded. Beautify does not apply to command input. + +Section 44.5: {directory}, {dir} default: dir=/tmp + +Specifies the directory in which ex places its buffer file. If this directory +in not writable, then the editor will exit abruptly when it fails to be able to +create its buffer there. + +Section 44.6: {edcompatible} default: noedcompatible + +Causes the presence or absence of g and c suffixes on substitute commands to be +remembered, and to be toggled by repeating the suffices. The suffix r makes +the substitution be as in the {~} command, instead of like {&}. + +[Author's note: this should not concern users of vi.] + +Section 44.7: {errorbells}, {eb} default: noeb + +Error messages are preceded by a bell. However, bell ringing in open and +visual modes on errors is not suppressed by setting noeb. If possible the +editor always places the error message in a standout mode of the terminal (such +as inverse video) instead of ringing the bell. + +Section 44.8: {hardtabs}, {ht} default: ht=8 + +Gives the boundaries on which terminal hardware tabs are set (or on which the +system expands tabs). + +Section 44.9: {ignorecase}, {ic} default: noic + +All upper case characters in the text are mapped to lower case in regular +expression matching. In addition, all upper case characters in regular +expressions are mapped to lower case except in character class specifications +(that is, character in square brackets). + +Section 44.10: {lisp} default: nolisp + +Autoindent indents appropriately for lisp code, and the {(}, {)}, [{], [}], +{[[}, and {]]} commands in open and visual modes are modified in a +striaghtforward, intuitive fashion to have meaning for lisp. + +[Author's note: but don't ask me to define them precisely.] + +Section 44.11: {list} default: nolist + +All printed lines will be displayed (more) unambiguously, showing tabs as ^I +and end-of-lines with `$'. This is the same as in the ex command {list}. + +Section 44.12: {magic} default: magic for {ex} and {vi}, nomagic for edit. + +If nomagic is set, the number of regular expression metacharacters is greatly +reduced, with only up-arrow `^' and `$' having special effects. In addition +the metacharacters `~' and `&' of the replacement pattern are treated as normal +characters. All the normal metacharacters may be made magic when nomagic is +set by preceding them with a `\'. + +[Author's note: In other words, if magic is set a back-slant turns the magic +off for the following character, and if nomagic is set a back-slant turns the +magic ON for the following character. And, no, we are not playing Dungeons and +Dragons, although I think the writers of these option notes must have played it +all the time.] + +Section 44.13: {mesg} default: mesg + +Causes write permission to be turned off to the terminal while you are in +visual mode, if nomesg is set. + +[Author's note: I don't know if anyone could have made any one sentence +paragraph more confusing than this one. What it says is: mesg allows people to +write to you even if you are in visual or open mode; nomesg locks your terminal +so they can't write to you and mess up your screen.] + +Section 44.14: {number, nu} default: nonumber + +Causes all output lines to be printed with their line numbers. In addition +each input line will be prompted with its line number. + +Section 44.15: {open} default: open + +If {noopen}, the commands open and visual are not permitted. This is set for +edit to prevent confusion resulting from accidental entry to open or visual +mode. + +[Author's note: As you may have guessed by now, there are actually three +editors available under Berkeley UNIX that are in reality the same +program, ex, with different options set: ex itself, vi, and edit.] + +Section 44.16: {optimize, opt} default: optimize + +Throughput of text is expedited by setting the terminal to not do automatic +carriage returns when printing more than one (logical) line of output, greatly +speeding output on terminals without addressable cursors when text with leading +white space is printed. + +[Author's note: I still don't know what this option does.] + +Section 44.17: {paragraphs, para} default: para=IPLPPPQPP LIbp + +Specifies the paragraphs for the [{] and [}] operations in open and visual. +The pairs of characters in the option's value are the names of the nroff macros +which start paragraphs. + +Section 44.18: {prompt} default: prompt + +Command mode input is prompted for with a `:'. + +[Author's note: Doesn't seem to have any effect on vi.] + +Section 44.19: {readonly}, {ro} default: noro, unless invoked with -R + or insufficient privileges on file + +This option allows you to guarantee that you won't clobber your file by +accident. You can set the option and writes will fail unless you use an `!' +after the write. Commands such as {x}, {ZZ}, the autowrite option, and in +general anything that writes is affected. This option is turned on if you +invoke the editor with the -R flag. + +Section 44.20: {redraw} default: noredraw + +The editor simulates (using great amounts of output), an intelligent terminal +on a dumb terminal (e.g. during insertions in visual the characters to the +right of the cursor position are refreshed as each input character is typed). +Useful only at very high baud rates, and should be used only if the system is +not heavily loaded: you will notice the performance degradation yourself. + +Section 44.21: {remap} default: remap + +If on, macros are repeatedly tried until they are unchanged. For example, if o +is mapped to O, and O is mapped to I, then if remap is set, o will map to I, +but if noremap is set, it will map to O . + +Section 44.22: {report} default: report=5 for ex and vi, 2 for edit + +Specifies a threshold for feedback from commands. Any command which modifies +more than the specified number of lines will provide feedback as to the scope +of its changes. For commands such as global, open, undo, and visual which have +potentially more far reaching scope, the net change in the number of lines in +the buffer is presented at the end of the command, subject to this same +threshold. Thus notification is suppressed during a global command on the +individual commands performed. + +Section 44.23: {scroll} default: scroll=1/2 window + +Determines the number of logical lines scrolled when a {^D} is received from a +terminal in command mode, and determines the number of lines printed by a +command mode z command (double the value of scroll). + +[Author's note: Doesn't seem to affect {^D} and {z} in visual (vi) mode.] + +Section 44.24: sections {sections} default: sections=SHNHH HU + +Specifies the section macros from nroff for the {[[} and {]]} operations in +open and visual. The pairs of characters in the options's value are the names +of the macros which start paragraphs. + +Section 44.25: {shell}, {sh} default: sh=/bin/sh + +Gives the path name of the shell forked for the shell escape command `!', and +by the shell command. The default is taken from SHELL in the environment, if +present. + +[Editor's note: I would suggest that you place the following line in +your .login file: +setenv SHELL '/bin/csh' +] + +Section 44.26: {shiftwidth}, {sw} default: sw=8 + +Used in reverse tabbing with {^D} when using autoindent to append text, and +used by the shift commands. Should probably be the same value as the tabstop +option. + +Section 44.27: {showmatch}, {sm} default: nosm + +In open and visual mode, when a `)' or `}' is typed, if the matching `(' or `{' +is on the screen, move the cursor to it for one second. Extremely useful with +complicated nested expressions, or with lisp. + +Section 44.28: {slowopen}, {slow} default: terminal dependent + +Affects the display algorithm used in visual mode, holding off display updating +during input of new text to improve throughput when the terminal in use is both +slow and unintelligent. See "An Introduction to Display Editing with Vi" for +more details. + +Section 44.29: {tabstop}, {ts} default: ts=8 + +The editor expands tabs ^I to tabstop boundaries in the display. + +Section 44.30: {taglength}, {tl} default: tl=0 + +Tags are not significant beyond this many characters. +A value of zero (the default) means that all characters are significant. + +Section 44.31: {tags} default: tags=tags /usr/lib/tags + +A path of files to be used as tag files for the tag command. A requested tag +is searched for in the specified files, sequentially. By default files called +tags are searched for in the current directory and in /usr/lib (a master file +for the entire system). + +[Author's note: The author of this tutorial has never used this option, nor +seen it used. I'm not even sure I know what they are talking about.] + +Section 44.32: {term} default: from environment variable TERM + +The terminal type of the output device. + +Section 44.33: {terse} default: noterse + +Shorter error diagnostics are produced for the experienced user. + +Section 44.34: {timeout} default: timeout + +Causes macros to time out after one second. Turn it off and they will +wait forever. This is useful if you want multi-character macros, but if +your terminal sends escape sequences for arrow keys, it will be +necessary to hit escape twice to get a beep. + +[Editor's note: Another paragraph which requires a cryptographer.] + +Section 44.35: ttytype + +[Editor's note: I have found no documentation for this option at all.] + +Section 44.36: {warn} default: warn + +Warn if there has been `[No write since last change]' before a `!' command +escape. + +Section 44.37: {window} default: window=speed dependent + +The number of lines in a text window in the visual command. The default is 8 +at slow speeds (600 baud or less), 16 at medium speed (1200 baud), and the full +screen (minus one line) at higher speeds. + +Section 44.38: {wrapscan}, {ws} default: ws + +Searches using the regular expressions in addressing will wrap around past the +end of the file. + +Section 44.39: {wrapmargin}, {wm} default: wm=0 + +Defines a margin for automatic wrapover of text during input in open and visual +modes. The numeric value is the number of columns from the right edge of the +screen around which vi looks for a convenient place to insert a new-line +character (wm=0 is OFF). This is very convenient for touch typists. +Wrapmargin behaves much like fill/nojustify mode does in nroff. + +Section 44.40: {writeany}, {wa} default: nowa + +Inhibit the checks normally made before write commands, allowing a write to any +file which the system protection mechanism will allow. + +Section 44.41: {w300}, {w1200}, {w9600} defaults: w300=8 + w1200=16 + w9600=full screen minus one + +These are not true options but set the default size of the window for when the +speed is slow (300), medium (1200), or high (9600), respectively. They are +suitable for an EXINIT and make it easy to change the 8/16/full screen rule. + +Section 45: Limitations + +Here are some editor limits that the user is likely to encounter: + 1024 characters per line + 256 characters per global command list + 128 characters per file name + 128 characters in the previous inserted and deleted text in open or + visual + 100 characters in a shell escape command + 63 characters in a string valued option + 30 characters in a tag name + 250000 lines in the file (this is silently enforced). + +The visual implementation limits the number of macros defined with map to 32, +and the total number of characters in macros to be less than 512. + +[Editor's note: these limits may not apply to versions after 4.1BSD.] diff --git a/usr.bin/vi/docs/tutorial/vi.beginner b/usr.bin/vi/docs/tutorial/vi.beginner new file mode 100644 index 0000000..3bf35ac --- /dev/null +++ b/usr.bin/vi/docs/tutorial/vi.beginner @@ -0,0 +1,741 @@ +Section 1: {^F} {ZZ} + +To get out of this tutorial, type: ZZ (two capital Z's). + +Learning a new computer system implies learning a new text editor. These +tutorial lessons were created by Dain Samples to help you come to grips with +UC Berkeley's screen oriented editor called vi (for VIsual). This tutorial +uses the vi editor itself as the means of presentation. + +For best use of this tutorial, read all of a screen before performing any of +the indicated actions. This tutorial (or, at least, the first half of it) has +been designed to systematically present the vi commands IF THE INSTRUCTIONS +ARE FOLLOWED! If you are too adventuresome, you may find yourself lost. If +you ever find yourself stuck, remember the first line of this section. + +OK, now find the control key on your keyboard; it usually has CTL or CTRL +written on its upper surface. Your first assignment is to hold the control +key down while you press the 'F' key on your keyboard. Please do so now. + + + +Section 2: {^F} {^B} +Many of vi's commands use the control key and some other key in combination, +as with the control and the 'F' key above. This is abbreviated CTL-F, or ^F. + +As you have probably guessed by now, ^F (CTL-F) moves you forward a fixed +number of lines in the file. Throughout the remainder of the tutorial when +you are ready to advance to the next section of text, hit ^F. + +The opposite command is ^B. Just for fun, you might want to try a ^B to see +the previous section again. Be sure to do a ^F to return you here. + +Determine what the cursor looks like on your screen. Whatever it is (a box, +an underscore, blinking, flashing, inverse, etc.) it should now be positioned +in the upper left-hand corner of your screen under or on the S of Section. +Become familiar with your cursor: to use vi correctly it is important to +always know where the cursor is. + +Did you notice that when you do a ^F the cursor is left at the top of the +screen, and a ^B leaves the cursor near the bottom of the screen? Try the two +commands ^B^F again. And now do another ^F to see the next section. + +Section 3: {^F} {^B} +You now have two basic commands for examining a file, both forwards (^F) and +backwards (^B). + +Note that these are vi text editing commands: they are not commands for the +tutorial. Indeed, this tutorial is nothing but a text file which you are now +editing. Everything you do and learn in this tutorial will be applicable to +editing text files. + +Therefore, when you are editing a file and are ready to see more of the text, +entering ^F will get you to the next section of the file. Entering ^B will +show you the previous section. + +Time for you to do another ^F. + + + + + + + +Section 4: {^F} {^B} {^M} (return key) +We will adopt the notation of putting commands in curly braces so we can write +them unambiguously. For example, if you are to type the command sequence +"control B control F" (as we asked you to do above) it would appear as {^B^F}. +This allows clear delineation of the command strings from the text. Remember +that the curly braces are NOT part of the command string you are to type. Do +NOT type the curly braces. + +Sometimes, the command string in the curly braces will be rather long, and may +be such that the first couple of characters of the command will erase from +the screen the string you are trying to read and type. It is suggested that +you write down the longer commands BEFORE you type them so you won't forget +them once they disappear. + +Now locate the return key on your keyboard: it is usually marked 'RETURN', +indicate hitting the return key. In fact, the control-M key sequence is +exactly the same as if you hit the return key, and vice versa. + +Now type {^F}. + + +Section 5: {:q!} {ZZ} {^M} (return key) +Recognize that this tutorial is nothing more than a text file that you +are editing. This means that if you do something wrong, it is possible +for you to destroy the information in this file. Don't worry. If this +happens, type {ZZ} (two capital Z's) or {:q!^M} to leave the tutorial. +Restart the tutorial. Once in the tutorial, you can then page forward +with {^F} until you are back to where you want to be. (There are +easier ways to do this, some of which will be discussed later, but this +is the most straightforward.) + +You may want to write these commands down in a convenient place for quick +reference: {:q!^M} and {ZZ} + +We will assume that you now know to do a {^F} to advance the file + + + + + + + +Section 6: {m} {G} {'} {z} +Now that you know how to get around in the file via ^F and ^B let's look at +other ways of examining a text file. Sometimes it is necessary, in the midst +of editing a file, to examine another part of the file. You are then faced +with the problem of remembering your place in the file, looking at the other +text, and then getting back to your original location. Vi has a 'mark' +command, m. Type {mp}. You have just 'marked' your current location in the +file and given it the name 'p'. The command string below will do three +things: position you at the beginning of the file (line 1), then return you to +the location 'p' that you just marked with the 'm' command, and, since the +screen will not look exactly the same as it does right now, the 'z' command +will reposition the screen. (You may want to write the string down before +typing it: once you type {1G} it will no longer be on the screen.) + +So now type {1G'pz^M} - a one followed by a capital G, followed by the quote +mark, followed by a lower case 'p', then a lower case 'z', then a return +(which is the same as a ^M). The {1G} moves you to line 1, i.e. the beginning +of the file. The {'p} moves you to the location you marked with {mp}. The +{z^M} command will repaint the screen putting the cursor at the top of the +screen. (Now {^F}.) + +Section 7: {m} {G} {'} {z} +Let's look at some variations on those commands. If you wanted to look at +line 22 in the file and return to this location you could type {mp22G'p}. Do +so now, observing that {22G} puts your cursor at the beginning of section 2 in +the middle of the screen. + +Also note that, without the {z^M} command, the line with 'Section 7' on it is +now in the MIDDLE of the screen, and not at the top. Our cursor is on the +correct line (where we did the {mp} command) but the line is not where we +might like it to be on the screen. That is the function of the {z^M} command. +(Remember, ^M is the same as the 'return' key on your keyboard.) Type {z^M} +now and observe the effect. + +As you can see, the 'Section 7' line is now at the top of the screen with the +cursor happily under the capital S. If you would like the cursor line (i.e. +the line which the cursor is on) in the middle of the screen again, you would +type {z.}. If you wanted the cursor line to be at the BOTTOM of the screen, +type {z-}. Try typing {z-z.z^M} and watch what happens. + +{^F} + +Section 8: {z} {m} {'} + +Note that the z command does not change the position of our cursor in the file +itself, it simply moves the cursor around on the screen by moving the contents +of the file around on the screen. The cursor stays on the same line of the +file when using the z command. + +This brings up an important point. There are two questions that the users of +vi continually need to know the answer to: "Where am I in the file?" and +"Where am I on the screen?" The cursor on your terminal shows the answer to +both questions. Some commands will move you around in the file, usually +changing the location of the cursor on the screen as well. Other commands +move the cursor around on the screen without changing your location in the +file. + +Now type {ma}. Your location in the file has been given the name 'a'. If you +type {'p'a} you will see the previous location we marked in section 7, and +then will be returned to the current location. (You will want to do a {z^M} +to repaint the screen afterwards.) Try it. +{^F} + +Section 9: {m} {''} +Now we can move about in our file pretty freely. By using the {m} command we +can give the current cursor position a lower-case-character name, like 'p', +'a', 'e', 'm', or 'b'. Using the {G} command preceded by a line number we can +look at any line in the file we like. Using the single quote command {'} +followed by a character used in an {m} command, we can return to any location +in the file we have marked. + +However, try {m3}, or {mM}. You should hear a beep, or bell. Only lower-case +letters are acceptable to the {m} and {'} commands: numbers, upper-case +letters, and special characters are not acceptable. + +If you type the {'} command with a character that is lower-case alphabetic but +that has not been used in an {m} command, or for which the 'marked' text has +been deleted, you will also get a beep. Try {'i}. You should get a beep +because the command {mi} has never been issued. (Unless you've been +experimenting.) + +The command {''} attempts to return you to the location at which you last +modified some part of your file. However, my experience has been that it is +difficult to predict exactly where you will end up. +Section 10: {^M} {-} +Now do {ma}, marking your position at the top of the screen. Now hit {^M} (or +return) until the cursor is right ... +* <- here, over/under the asterisk. Now +type {mb'a'b} and watch the cursor move from the asterisk to the top of the +screen and back again. + +The {^M} command moves the cursor to the beginning of the next line. Now type +{^M} until the cursor is right ... +* <- here. The command to move the cursor to the beginning of the +previous line is {-}. Practice moving the cursor around on the screen by using +{^M} and {-}. BE CAREFUL to not move the cursor OFF the screen just yet. If +you do, type {'az^M}. + +Now we can move to any line within the screen. Practice moving around in the +file using the {^F}, {^B}, {-}, {^M}, {z}, and {'} commands. When you are +fairly confident that you can get to where you need to be in the file, and +position the cursor on the screen where you want it type {'az^M^F} (which, of +course, moves you back to the beginning of this section, repositions the +cursor at the top of the screen, and advances you to the next section). + +Section 11: scrolling: {^M} +The cursor should now be on the S of 'Section 11', and this should be on the +first line of the screen. If it is not, do {^M} or {-} as appropriate to put +the cursor on the section line, and type {z^M}. + +Type {mc} to mark your place. + +Now type {^M} until the cursor is on the last line of this screen. Now do one +more {^M} and observe the result. This is called scrolling. When you +attempted to move to a line not displayed on the screen, the line at the top of +the screen was 'scrolled off', and a line at the bottom of the screen was +'scrolled on'. The top line with 'Section 11' should no longer be visible. + +Now type {'cz^M} to reset the screen and type {^F} for the next section. + + + + + + + +Section 12: {-} {z} + +The {-} command moves the cursor to the previous line in the file. Now type +{-}, which attempts to move the cursor to the previous line in this file. +However, that line is not on the screen. The resulting action will depend on +your terminal. (Do a {^Mz^M} to reposition the file). On intelligent +terminals (e.g. VT100s, Z19s, Concept 100s), a top line is 'scrolled on' and +the bottom line is 'scrolled off'. Other terminals, however, may not have +this 'reverse scrolling' feature. They will simply repaint the screen with +the cursor line in the middle of the screen. On such terminals it is +necessary to type {z^M} to get the cursor line back to the top of the screen. + + + + + + + + + + +Section 13: +Up until this point, the tutorial has always tried to make sure that the first +line of each screen has on it the section number and a list of the commands +covered in that section. This will no longer be strictly maintained. If you +want the section line at the top of the screen, you now know enough commands to +do it easily: do {^M} or {-} until the cursor is on the section line and +then {z^M}. Also, from this point on, it may not be the case that a {^F} will +put you at the beginning of the next section. Therefore, be aware of where you +are in the file as we look at other commands. You may have to find your way +back to a particular section without any help from the tutorial. If you do not +feel comfortable with this, then it is suggested that you practice moving from +section 1 to section 13, back and forth, using {^M}, {-}, {^F}, and {^B} +commands for a while. + +Also make liberal use of the mark command {m}: if, for example, you make a +habit of using {mz} to mark your current location in the file, then you will +always be able to return to that location with {'z} if the editor does +something strange and you have no idea where you are or what happened. + +And finally, the proscription against experimentation is hereby lifted: play +with the editor. Feel free to try out variations on the commands and move +around in the file. By this time you should be able to recover from any gross +errors. + +Section 14: {^E} {^Y} {^D} {^U} +Let us now look at a few other commands for moving around in the file, and +moving the file around on the screen. Note that the commands we have already +looked at are sufficient: you really don't need any more commands for looking +in a file. The following commands are not absolutely necessary. However, +they can make editing more convenient, and you should take note of their +existence. But it would be perfectly valid to decide to ignore them on this +first pass: you can learn them later when you see a need for them, if you ever +do. + +First, let's clear up some potentially confusing language. In at least one +place in the official document ('An Introduction to Display Editing with Vi' +by William Joy, and Mark Horton, September 1980), the expression "to scroll +down text" means that the cursor is moved down in your file. However, note +that this may result in the text on the screen moving UP. This use of the +word 'scroll' refers to the action of the cursor within the file. However, +another legitimate use of the word refers to the action of the text on the +screen. That is, if the lines on your screen move up toward the top of the +screen, this would be 'scrolling the screen up'. If the lines move down +toward the bottom of the screen, this would be refered to as scrolling down. + +I have tried to maintain the following jargon: 'scrolling' refers to what the +text does on the screen, not to what the cursor does within the file. For the +latter I will refer to the cursor 'moving', or to 'moving the cursor'. I +realize that this is not necessarily consistent with Joy and Horton, but they +were wrong. + +{^E} scrolls the whole screen up one line, keeping the cursor on the same line, +if possible. However, if the cursor line is the first line on the screen, then +the cursor is moved to the next line in the file. Try typing {^E}. + +{^Y} scrolls the screen down one line, keeping the cursor on the same line, if +possible. However, if the cursor line is the last line on the screen, then the +cursor is moved to the previous line in the file. Try it. + +{^D} moves the cursor down into the file, scrolling the screen up. + +{^U} moves the cursor up into the file, also scrolling the screen if the +terminal you are on has the reverse scroll capability. Otherwise the +screen is repainted. + +Note that {^E} and {^Y} move the cursor on the screen while trying to keep the +cursor at the same place in the file (if possible: however, the cursor can +never move off screen), while {^D} and {^U} keep the cursor at the same place +on the screen while moving the cursor within the file. + +Section 15: {/ .. /^M} + +Another way to position yourself in the file is by giving the editor a string +to search for. Type the following: {/Here 1/^M} and the cursor should end up +right ...........................here ^. Now type {/Section 15:/^M} and the +cursor will end up over/on .....................here ^. Now type {//^M} and +observe that the cursor is now over the capital S five lines above this line. +Typing {//^M} several more times will bounce the cursor back and forth between +the two occurrences of the string. In other words, when you type a string +between the two slashes, it is searched for. Typing the slashes with nothing +between them acts as if you had typed the previous string again. + +Observe that the string you type between the two slashes is entered on the +bottom line of the screen. Now type {/Search for x /^M} except replace the 'x' +in the string with some other character, say 'b'. The message "Pattern not +found" should appear on the bottom of the screen. If you hadn't replaced the +'x', then you would have found the string. Try it. + +Section 16: {? .. ?^M} {n} (search strings: ^ $) + +When you surround the sought-for string with slashes as in {/Search/}, the +file is searched beginning from your current position in the file. If the +string is not found by the end of the file, searching is restarted at the +beginning of the file. However, if you do want the search to find the +PREVIOUS rather than the NEXT occurrence of the string, surround the string +with question marks instead of slash marks. + +Below are several occurrences of the same string. +Here 2 Here 2 Here 2 + Here 2 Here 2. +Observe the effect of the following search commands (try them in the +sequence shown): +{/Here 2/^M} {//^M} {??^M} +{/^Here 2/^M} {//^M} {??^M} +{/Here 2$/^M} {//^M} {??^M} + +The first command looks for the next occurrence of the string 'Here 2'. +However the second line of commands looks for an occurrence of 'Here 2' that +is at the beginning of the line. When the up-arrow is the first character of +a search string it stands for the beginning of the line. When the dollar-sign +is the last character of the search string it stands for the end of the line. +Therefore, the third line of commands searches for the string only when it is +at the end of the line. Since there is only one place the string begins a +line, and only one place the string ends the line, subsequent {//^M} and +{??^M} will find those same strings over and over. + +The {n} command will find the next occurrence of the / or ? search +string. Try {/Here 2/^M} followed by several {n} and observe the +effect. Then try {??^M} followed by several {n}. The {n} command +remembers the direction of the last search. It is just a way to save a +few keystrokes. + +Section 17: \ and magic-characters in search strings + +Now type {/Here 3$/^M}. You might expect the cursor to end up +right......^ here. However, you will get "Pattern not found" at the bottom of +the screen. Remember that the dollar-sign stands for the end of the line. +Somehow, you must tell vi that you do not want the end of the line, but a +dollar-sign. In other words, you must take away the special meaning that the +dollar-sign has for the search mechanism. You do this (for any special +character, including the up-arrow ^) by putting a back-slash ('\', not '/') in +front of the character. + +Now try {/Here 3\$/^M} and you should end up nine lines above this one. Try +{//^M} and note that it returns you to the same place, and not to the first +line of this paragraph: the back-slash character is not part of the search +string and will not be found. To find the string in the first line of this +paragraph, type {/Here 3\\\$/^M}. There are three back-slashes: the first takes +away the special meaning from the second, and the third takes away the special +meaning from the dollar-sign. + +Following is a list of the characters that have special meanings in search +strings. If you wish to find a string containing one of these characters, you +will have to be precede the character with a backslash. These characters are +called magic characters because of the fun and games you can have with them +and they can have with you, if you aren't aware of what they do. + + ^ - (up-arrow) beginning of a line + $ - (dollar-sign) end of a line + . - (period) matches any character + \ - (backslant) the escape character itself + [ - (square bracket) for finding patterns (see section #SEARCH) + ] - (square bracket) ditto + * - (asterisk) ditto + +Without trying to explain it here, note that {:set nomagic^M} turns off the +special meanings of all but the ^ up-arrow, $ dollar-sign, and backslash +characters. + +Section 18: {: (colon commands)} {ZZ} + +In this section we will discuss getting into and out of the editor in more +detail. If you are editing a file and wish to save the results the command +sequence {:w^M} writes the current contents of the file out to disk, using the +file name you used when you invoked the editor. That is, if you are at the +command level in Unix, and you invoke vi with {vi foo} where foo is the name +of the file you wish to edit, then foo is the name of the file used by the +{:w^M} command. + +If you are done, the write and quit commands can be combined into a single +command {:wq^M}. An even simpler way is the command {ZZ} (two capital Z's). + +If, for some reason, you wish to exit without saving any changes you have made, +{:q!^M} does the trick. If you have not made any changes, the exclamation +point is not necessary: {:q^M}. Vi is pretty good about not letting you +get out without warning you that you haven't saved your file. + +We have mentioned before that you are currently in the vi editor, editing a +file. If you wish to start the tutorial over from the very beginning, you +could {ZZ}, and then type {vi.tut beginner} in response to the Unix prompt. +This will create a fresh copy of this file for you, which might be necessary +if you accidentally destroyed the copy you were working with. Just do a +search for the last section you were in: e.g. {/Section 18:/^Mz^M}. + +Section 19: {H} {M} {L} + +Here are a few more commands that will move you around on the screen. Again, +they are not absolutely necessary, but they can make screen positioning easier: + +{H} - puts the cursor at the top of the screen (the 'home' position) + +{M} - puts the cursor in the middle of the screen + +{L} - puts the cursor at the bottom of the screen. + +Try typing {HML} and watch the cursor. + +Try typing {5HM5L} and note that 5H puts you five lines from the top of the +screen, and 5L puts you five lines from the bottom of the screen. + +Section 20: {w} {b} {0} {W} {B} {e} {E} {'} {`} + +Up to this point we have concentrated on positioning in the file, and +positioning on the screen. Now let's look at positioning in a line. Put the +cursor at the beginning of the following line and type {z^M}: + +This is a test line: your cursor should initially be at its beginning. + +The test line should now be at the top of your screen. Type {w} several times. +Note that it moves you forward to the beginning of the next word. Now type +{b} (back to the beginning of the word) several times till you are at the +beginning of the line. (If you accidentally type too many {b}, type {w} until +you are on the beginning of the line again.) Type {wwwww} (five w's) and note +that the cursor is now on the colon in the sentence. The lower-case w command +moves you forward one word, paying attention to certain characters such as +colon and period as delimiters and counting them as words themselves. Now +type {0} (zero, not o 'oh'): this moves you to the beginning of the current +line. Now type {5w} and notice that this has the effect of repeating {w} five +times and that you are now back on the colon. Type {0} (zero) again. To +ignore the delimiters and to move to the beginning of the next word using only +blanks, tabs and carriage-returns (these are called white-space characters) to +delimit the words, use the {W} command: upper-case W. {B} takes you back a +word using white-space characters as word delimiters. + +Note that the commands {wbWB} do not stop at the beginning or end of a line: +they will continue to the next word on the next line in the direction specified +(a blank line counts as a word). + +If you are interested in the END of the word, and not the BEGINNING, then use +the {e} and {E} commands. These commands only move forward and there are no +corresponding 'reverse search' commands for the end of a word. + +Also, we have been using the {'} command to move the cursor to a position that +we have previously marked with the {m} command. However, position the cursor +in the middle of a line (any line, just pick one) and type {mk}, marking that +position with the letter k. Now type a few returns {^M} and type {'k}. +Observe that the cursor is now at the beginning of the line that you marked. +Now try {`k}: note that this is the reverse apostrophe, or back-quote, or grave +accent, or whatever you want to call it. Also note that it moves you to the +character that was marked, not just to the line that was marked. + +In addition, the {``} command works just like the {''} command except that you +are taken to the exact character, not just to the line. (I'm still not +sure which exact character, just as I'm still not sure which line.) + +Section 21: {l} {k} {j} {h} + +There are several commands to move around on the screen on a character by +character basis: + +l - moves the cursor one character to the RIGHT +k - moves the cursor UP one line +j - moves the cursor DOWN one line +h - moves the cursor one character to the LEFT + +Section 22: {i} {a} {I} {A} {o} {O} ^[ (escape key) + +For this and following sections you will need to use the ESCAPE key on your +terminal. It is usually marked ESC. Since the escape key is the same as +typing {^[} we will use ^[ for the escape key. + +Probably the most often used command in an editor is the insert command. Below +are two lines of text, the first correct, the second incorrect. Position your +cursor at the beginning of Line 1 and type {z^M}. + +Line 1: This is an example of the insert command. +Line 2: This is an of the insert command. + +To make line 2 look like line 1, we are going to insert the characters +'example ' before the word 'of'. So, now move the cursor so that it is +positioned on the 'o' of 'of'. (You can do this by typing {^M} to move +to the beginning of line 2, followed by {6w} or {wwwwww} to position the cursor +on the word 'of'.) + +Now carefully type the following string and observe the effects: + {iexample ^[} (remember: ^[ is the escape key)} +The {i} begins the insert mode, and 'example ' is inserted into the line: +be sure to notice the blank in 'example '. The ^[ ends insertion mode, +and the line is updated to include the new string. Line 1 should look exactly +like Line 2. + +Move the cursor to the beginning of Line 3 below and type {z^M}: + +Line 3: These lines are examples for the 'a' command. +Line 4: These line are examples for the ' + +We will change line four to look like line three by using the append command. +We need to append an 's' to the word 'line'. Position the cursor on the 'e' +of 'line'. You can do this in several ways, one way is the following: +First, type {/line /^M}. This puts us on the word 'line' in Line 4 +(the blank in the search string is important!). Next, type {e}. The 'e' puts +us at the end of the word. Now, type {as^[ (^[ is the escape character)}. +The 'a' puts us in insert mode, AFTER the current character. We appended the +'s', and the escape ^[ ended the insert mode. + +The difference between {i} (insert) and {a} (append) is that {i} begins +inserting text BEFORE the cursor, and {a} begins inserting AFTER the cursor. + +Now type {Aa' command.^[}. The cursor is moved to the end of the line and the +string following {A} is inserted into the text. Line 4 should now look like +line 3. + +Just as {A} moves you to the end of the line to begin inserting, {I} would +begin inserting at the FRONT of the line. + +To begin the insertion of a line after the cursor line, type {o}. To insert a +line before the cursor line, type {O}. In other words {o123^[} is equivalent +to {A^M123^[}, and {O123^[} is equivalent to {I123^M^[}. The text after the +{o} or {O} is ended with an escape ^[. + +This paragraph contains information that is terminal dependent: you will just +have to experiment to discover what your terminal does. Once in the insert +mode, if you make a mistake in the typing, ^H will delete the previous +character up to the beginning of the current insertion. ^W will delete the +previous word, and one of ^U, @, or ^X will delete the current line (up to the +beginning of the current insertion). You will need to experiment with ^U, @, +and ^X to determine which works for your terminal. + +Section 23: {f} {x} {X} {w} {l} {r} {R} {s} {S} {J} + +Position the cursor at the beginning of line 5 and {z^M}: + +Line 5: The line as it should be. +Line 6: The line as it shouldn't be. + +To make Line 6 like Line 5, we have to delete the 'n', the apostrophe, and the +'t'. There are several ways to position ourselves at the 'n'. Choose +whichever one suits your fancy: + +{/n't/^M} +{^M7w6l} or {^M7w6 } (note the space) +{^M3fn} (finds the 3rd 'n' on the line) + +Now {xxx} will delete the three characters, as will {3x}. + +Note that {X} deletes the character just BEFORE the cursor, as opposed +to the character AT the cursor. + +Position the cursor at line 7 and {z^M}: + +Line 7: The line as it would be. +Line 8: The line as it could be. + +To change line 8 into line 7 we need to change the 'c' in 'could' into a 'w'. +The 'r' (replace) command was designed for this. Typing {rc} is the same as +typing {xic^[} (i.e. delete the 'bad' character and insert the correct +new character). Therefore, assuming that you have positioned the cursor on the +'c' of 'could', the easiest way to change 'could' into 'would' is {rw}. + +If you would like to now change the 'would' into 'should', use the substitute +command, 's': {ssh^[}. The difference between 'r' and 's' is that 'r' +(replace) replaces the current character with another character, while 's' +(substitute) substitutes the current character with a string, ended with an +escape. + +The capital letter version of replace {R} replaces each character by a +character one at a time until you type an escape, ^[. The 'S' command +substitutes the whole line. + +Position your cursor at the beginning of line 9 and {z^M}. + +Line 9: Love is a many splendored thing. +Line 10: Love is a most splendored thing. + +To change line 10 into line 9, position the cursor at the beginning of 'most', +and type {Rmany^[}. + +You may have noticed that, when inserting text, a new line is formed by typing +{^M}. When changing, replacing, or substituting text you can make a new line +by typing {^M}. However, neither {x} nor {X} will remove ^M to make two lines +into one line. To do this, position the cursor on the first of the two lines +you wish to make into a single line and type {J} (uppercase J for 'Join'). + +Section 24: {u} {U} + +Finally, before we review, let's look at the undo command. Position +your cursor on line 11 below and {z^M}. + +Line 11: The quick brown fox jumped over the lazy hound dog. +Line 12: the qwick black dog dumped over the laxy poune fox. + +Type the following set of commands, and observe carefully the effect of each +of the commands: + +{/^Line 12:/^M} {ft} {rT} {fw} {ru} {w} {Rbrown fox^[} {w} {rj} +{fx} {rz} {w} {Rhound dog^[} + +Line 12 now matches line 11. Now type {U} - capital 'U'. And line 12 now +looks like it did before you typed in the command strings. Now type: + +{ft} {rT} {fw} {ru} {^M} {^M} + +and then type {u}: the cursor jumps back to the line containing the second +change you made and 'undoes' it. That is, {U} 'undoes' all the changes on the +line, and {u} 'undoes' only the last change. Type {u} several times and +observe what happens: {u} can undo a previous {u}! + +Caveat: {U} only works as long as the cursor is still on the line. Move the +cursor off the line and {U} will have no effect, except to possibly beep at +you. However, {u} will undo the last change, no matter where it occurred. + +Section 25: review + +At this point, you have all the commands you need in order to make use of vi. +The remainder of this tutorial will discuss variations on these commands as +well as introduce new commands that make the job of editing more efficient. +Here is a brief review of the basic commands we have covered. They are listed +in the order of increasing complexity and/or decreasing necessity (to say that +a command is less necessary is not to say that it is less useful!). These +commands allow you to comfortably edit any text file. There are other +commands that will make life easier but will require extra time to learn, +obviously. You may want to consider setting this tutorial aside for several +weeks and returning to it later after gaining experience with vi and getting +comfortable with it. The convenience of some of the more exotic commands may +then be apparent and worth the extra investment of time and effort +required to master them. + +to get into the editor from Unix: {vi filename} +to exit the editor + saving all changes {ZZ} or {:wq^M} + throwing away all changes {:q!^M} + when no changes have been made {:q^M} +save a file without exiting the editor {:w^M} +write the file into another file {:w filename^M} +insert text + before the cursor {i ...text... ^[} + at the beginning of the line {I ...text... ^[} + after the cursor (append) {a ...text... ^[} + at the end of the line {A ...text... ^[} + after the current line {o ...text... ^[} + before the current line {O ...text... ^[} +delete the character ... + under the cursor {x} + to the left of the cursor {X} +delete n characters {nx} or {nX} (for n a number) +make two lines into one line (Join) {J} +find a string in the file ... + searching forward {/ ...string... /^M} + searching backwards {? ...string... ?^M} +repeat the last search command {n} +repeat the last search command in the + opposite direction {N} +find the character c on this line ... + searching forward {fc} + searching backward {Fc} +repeat the last 'find character' command {;} +replace a character with character x {rx} +substitute a single character with text {s ...text... ^[} +substitute n characters with text {ns ...text... ^[} +replace characters one-by-one with text {R ...text... ^[} +undo all changes to the current line {U} +undo the last single change {u} +move forward in the file a "screenful" {^F} +move back in the file a "screenful" {^B} +move forward in the file one line {^M} or {+} +move backward in the file one line {-} +move to the beginning of the line {0} +move to the end of the line {$} +move forward one word {w} +move forward one word, ignoring punctuation {W} +move forward to the end of the next word {e} +to the end of the word, ignoring punctuation{E} +move backward one word {b} +move back one word, ignoring punctuation {B} +return to the last line modified {''} +scroll a line onto the top of the screen {^Y} +scroll a line onto the bottom of the screen {^E} +move "up" in the file a half-screen {^U} +move "down" in the file a half-screen {^D} +move the cursor to the top screen line {H} +move the cursor to the bottom screen line {L} +move the cursor to the middle line {M} +move LEFT one character position {h} or {^H} +move RIGHT one character position {l} or { } +move UP in the same column {k} or {^P} +move DOWN in the same column {j} or {^N} +mark the current position, name it x {mx} +move to the line marked/named x {'x} +move to the character position named x {`x} +move to the beginning of the file {1G} +move to the end of the file {G} +move to line 23 in the file {23G} +repaint the screen with the cursor line + at the top of the screen {z^M} + in the middle of the screen {z.} + at the bottom of the screen {z-} + +More information on vi can be found in the file vi.advanced, which you can +peruse at your leisure. From UNIX, type {vi.tut advanced^M}. diff --git a/usr.bin/vi/docs/tutorial/vi.tut.csh b/usr.bin/vi/docs/tutorial/vi.tut.csh new file mode 100755 index 0000000..01554bc --- /dev/null +++ b/usr.bin/vi/docs/tutorial/vi.tut.csh @@ -0,0 +1,24 @@ +#!/bin/csh -f +# +# This makes the user's EXINIT variable set to the 'correct' things. +# I don't know what will happen if they also have a .exrc file! +# +# XXX +# Make sure that user is using a 24 line window!!! +# +if ($1 != "beginner" && $1 != "advanced") then + echo Usage: $0 beginner or $0 advanced + exit +endif + +if ($?EXINIT) then + set oexinit="$EXINIT" + setenv EXINIT 'se ts=4 wm=8 sw=4' +endif + +vi vi.{$1} + +onintr: + if ($?oexinit) then + setenv EXINIT "$oexinit" +endif diff --git a/usr.bin/vi/ex/ex.c b/usr.bin/vi/ex/ex.c new file mode 100644 index 0000000..c0455a1 --- /dev/null +++ b/usr.bin/vi/ex/ex.c @@ -0,0 +1,1866 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex.c 8.155 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +static void badlno __P((SCR *, recno_t)); +static __inline EXCMDLIST const * + ex_comm_search __P((char *, size_t)); +static int ep_line __P((SCR *, EXF *, MARK *, char **, size_t *, int *)); +static int ep_range __P((SCR *, EXF *, EXCMDARG *, char **, size_t *)); + +/* + * ex -- + * Read an ex command and execute it. + */ +int +ex(sp, ep) + SCR *sp; + EXF *ep; +{ + enum input irval; + TEXT *tp; + u_int flags, saved_mode; + int eval; + + if (ex_init(sp, ep)) + return (1); + + if (sp->s_refresh(sp, ep)) + return (ex_end(sp)); + + /* If reading from a file, messages should have line info. */ + if (!F_ISSET(sp->gp, G_STDIN_TTY)) { + sp->if_lno = 1; + sp->if_name = strdup("input"); + } + + /* + * !!! + * Historically, the beautify option applies to ex command input read + * from a file. In addition, the first time a ^H was discarded from + * the input, a message "^H discarded" was displayed. We don't bother. + */ + LF_INIT(TXT_BACKSLASH | TXT_CNTRLD | TXT_CR | TXT_EXSUSPEND); + + for (eval = 0;; ++sp->if_lno) { + /* Set the flags that the user can change. */ + if (O_ISSET(sp, O_BEAUTIFY)) + LF_SET(TXT_BEAUTIFY); + else + LF_CLR(TXT_BEAUTIFY); + if (O_ISSET(sp, O_PROMPT)) + LF_SET(TXT_PROMPT); + else + LF_CLR(TXT_PROMPT); + + /* + * Get the next command. Interrupt flag manipulation is + * safe because ex_icmd clears them all. + */ + CLR_INTERRUPT(sp); + F_SET(sp, S_INTERRUPTIBLE); + irval = sp->s_get(sp, ep, sp->tiqp, ':', flags); + if (INTERRUPTED(sp)) { + (void)fputc('\n', stdout); + (void)fflush(stdout); + goto refresh; + } + switch (irval) { + case INP_OK: + break; + case INP_EOF: + case INP_ERR: + F_SET(sp, S_EXIT_FORCE); + /* FALLTHROUGH */ + case INP_INTR: + goto ret; + } + + /* + * If the user entered a carriage return, send ex_cmd() + * a separator -- it discards single newlines. + */ + tp = sp->tiqp->cqh_first; + if (tp->len == 0) { + tp->len = 1; + tp->lb[0] = ' '; + } + + saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE); + if (ex_icmd(sp, ep, + tp->lb, tp->len, 1) && !F_ISSET(sp->gp, G_STDIN_TTY)) + F_SET(sp, S_EXIT_FORCE); + (void)msg_rpt(sp, 0); + if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE)) + break; + +refresh: if (sp->s_refresh(sp, ep)) { + eval = 1; + break; + } + } +ret: if (sp->if_name != NULL) { + FREE(sp->if_name, strlen(sp->if_name) + 1); + sp->if_name = NULL; + } + return (ex_end(sp) || eval); +} + +/* + * ex_cfile -- + * Execute ex commands from a file. + */ +int +ex_cfile(sp, ep, filename, needsep) + SCR *sp; + EXF *ep; + char *filename; + int needsep; +{ + struct stat sb; + int fd, len, rval; + char *bp; + + bp = NULL; + if ((fd = open(filename, O_RDONLY, 0)) < 0 || fstat(fd, &sb)) + goto err; + + /* + * XXX + * We'd like to test if the file is too big to malloc. Since we don't + * know what size or type off_t's or size_t's are, what the largest + * unsigned integral type is, or what random insanity the local C + * compiler will perpetrate, doing the comparison in a portable way + * is flatly impossible. Hope that malloc fails if the file is too + * large. + */ + MALLOC(sp, bp, char *, (size_t)sb.st_size + 1); + if (bp == NULL) + goto err; + + len = read(fd, bp, (int)sb.st_size); + if (len == -1 || len != sb.st_size) { + if (len != sb.st_size) + errno = EIO; +err: rval = 1; + msgq(sp, M_SYSERR, filename); + } else { + bp[sb.st_size] = '\0'; /* XXX */ + + /* + * Run the command. Messages include file/line information, + * but we don't care if we can't get space. + */ + sp->if_lno = 1; + sp->if_name = strdup(filename); + F_SET(sp, S_VLITONLY); + rval = ex_icmd(sp, ep, bp, len, needsep); + F_CLR(sp, S_VLITONLY); + free(sp->if_name); + sp->if_name = NULL; + } + + /* + * !!! + * THE UNDERLYING EXF MAY HAVE CHANGED. + */ + if (bp != NULL) + FREE(bp, sb.st_size); + if (fd >= 0) + (void)close(fd); + return (rval); +} + +/* + * ex_icmd -- + * Call ex_cmd() after turning off interruptible bits. + */ +int +ex_icmd(sp, ep, cmd, len, needsep) + SCR *sp; + EXF *ep; + char *cmd; + size_t len; + int needsep; +{ + /* + * Ex goes through here for each vi :colon command and for each ex + * command, however, globally executed commands don't go through + * here, instead, they call ex_cmd directly. So, reset all of the + * interruptible flags now. + * + * !!! + * Previous versions of nvi cleared mapped characters on error. This + * feature was removed when users complained that it wasn't historic + * practice. + */ + CLR_INTERRUPT(sp); + return (ex_cmd(sp, ep, cmd, len, needsep)); +} + +/* Special command structure for :s as a repeat substitution command. */ +static EXCMDLIST const cmd_subagain = + {"s", ex_subagain, E_ADDR2|E_NORC, + "s", + "[line [,line]] s [cgr] [count] [#lp]", + "repeat the last subsitution"}; + +/* Special command structure for :d[flags]. */ +static EXCMDLIST const cmd_del2 = + {"delete", ex_delete, E_ADDR2|E_AUTOPRINT|E_NORC, + "1bca1", + "[line [,line]] d[elete][flags] [buffer] [count] [flags]", + "delete lines from the file"}; + +/* + * ex_cmd -- + * Parse and execute a string containing ex commands. + */ +int +ex_cmd(sp, ep, cmd, cmdlen, needsep) + SCR *sp; + EXF *ep; + char *cmd; + size_t cmdlen; + int needsep; +{ + enum { NOTSET, NEEDSEP_N, NEEDSEP_NR, NONE } sep; + EX_PRIVATE *exp; + EXCMDARG exc; + EXCMDLIST const *cp; + MARK cur; + recno_t lno, num; + size_t arg1_len, len, save_cmdlen; + long flagoff; + u_int saved_mode; + int blank, ch, cnt, delim, flags, namelen, nl; + int optnum, uselastcmd, tmp, vi_address; + char *arg1, *save_cmd, *p, *s, *t; + + /* Init. */ + nl = 0; + sep = needsep ? NOTSET : NONE; +loop: if (nl) { + nl = 0; + ++sp->if_lno; + } + arg1 = NULL; + save_cmdlen = 0; + + /* It's possible that we've been interrupted during a command. */ + if (INTERRUPTED(sp)) + return (0); + + /* Skip <blank>s, empty lines. */ + for (blank = 0; cmdlen > 0; ++cmd, --cmdlen) + if ((ch = *cmd) == '\n') + ++sp->if_lno; + else if (isblank(ch)) + blank = 1; + else + break; + + /* + * !!! + * Permit extra colons at the start of the line. Historically, + * ex/vi allowed a single extra one. It's simpler not to count. + * The stripping is done here because, historically, any command + * could have preceding colons, e.g. ":g/pattern/:p" worked. + */ + if (cmdlen != 0 && ch == ':') { + if (sep == NOTSET) + sep = NEEDSEP_N; + while (--cmdlen > 0 && (ch = *++cmd) == ':'); + } + + /* + * Command lines that start with a double-quote are comments. + * + * !!! + * Historically, there was no escape or delimiter for a comment, + * e.g. :"foo|set was a single comment and nothing was output. + * Since nvi permits users to escape <newline> characters into + * command lines, we have to check for that case. + */ + if (cmdlen != 0 && ch == '"') { + while (--cmdlen > 0 && *++cmd != '\n'); + if (*cmd == '\n') { + nl = 1; + ++cmd; + --cmdlen; + } + goto loop; + } + + /* Skip whitespace. */ + for (; cmdlen > 0; ++cmd, --cmdlen) { + ch = *cmd; + if (!isblank(ch)) + break; + } + + /* + * The last point at which an empty line can mean do nothing. + * + * !!! + * Historically, in ex mode, lines containing only <blank> characters + * were the same as a single <carriage-return>, i.e. a default command. + * In vi mode, they were ignored. + * + * In .exrc files this was a serious annoyance, as vi kept trying to + * treat them as print commands. We ignore backward compatibility in + * this case, and discard lines containing only <blank> characters from + * .exrc files. + */ + if (cmdlen == 0 && (!IN_EX_MODE(sp) || ep == NULL || !blank)) + return (0); + + /* Initialize the structure passed to underlying functions. */ + memset(&exc, 0, sizeof(EXCMDARG)); + exp = EXP(sp); + if (argv_init(sp, ep, &exc)) + goto err; + + /* + * Check to see if this is a command for which we may want to output + * a \r separator instead of a \n. (The command :1<CR> puts out a \n, + * but the command :<CR> puts out a \r.) If the line is empty except + * for <blank>s, <carriage-return> or <eof>, we'll probably want to + * output \r. I don't think there's any way to get <blank> characters + * *after* the command character, but this is the ex parser, and I've + * been wrong before. + */ + if (sep == NOTSET) + sep = cmdlen == 0 || cmdlen == 1 && cmd[0] == '\004' ? + NEEDSEP_NR : NEEDSEP_N; + + /* Parse command addresses. */ + if (ep_range(sp, ep, &exc, &cmd, &cmdlen)) + goto err; + + /* Skip whitespace. */ + for (; cmdlen > 0; ++cmd, --cmdlen) { + ch = *cmd; + if (!isblank(ch)) + break; + } + + /* + * If no command, ex does the last specified of p, l, or #, and vi + * moves to the line. Otherwise, determine the length of the command + * name by looking for the first non-alphabetic character. (There + * are a few non-alphabetic characters in command names, but they're + * all single character commands.) This isn't a great test, because + * it means that, for the command ":e +cut.c file", we'll report that + * the command "cut" wasn't known. However, it makes ":e+35 file" work + * correctly. + * + * !!! + * Historically, lines with multiple adjacent (or <blank> separated) + * command separators were very strange. For example, the command + * |||<carriage-return>, when the cursor was on line 1, displayed + * lines 2, 3 and 5 of the file. In addition, the command " | " + * would only display the line after the next line, instead of the + * next two lines. No ideas why. It worked reasonably when executed + * from vi mode, and displayed lines 2, 3, and 4, so we do a default + * command for each separator. + */ +#define SINGLE_CHAR_COMMANDS "\004!#&*<=>@~" + if (cmdlen != 0 && cmd[0] != '|' && cmd[0] != '\n') { + if (strchr(SINGLE_CHAR_COMMANDS, *cmd)) { + p = cmd; + ++cmd; + --cmdlen; + namelen = 1; + } else { + for (p = cmd; cmdlen > 0; --cmdlen, ++cmd) + if (!isalpha(*cmd)) + break; + if ((namelen = cmd - p) == 0) { + msgq(sp, M_ERR, "Unknown command name"); + goto err; + } + } + + /* + * !!! + * Historic vi permitted flags to immediately follow any + * subset of the 'delete' command, but then did not permit + * further arguments (flag, buffer, count). Make it work. + * Permit further arguments for the few shreds of dignity + * it offers. + * + * !!! + * Note, adding commands that start with 'd', and match + * "delete" up to a l, p, +, - or # character can break + * this code. + */ + if (p[0] == 'd') { + for (s = p, + t = cmds[C_DELETE].name; *s == *t; ++s, ++t); + if (s[0] == 'l' || s[0] == 'p' || + s[0] == '+' || s[0] == '-' || s[0] == '#') { + len = (cmd - p) - (s - p); + cmd -= len; + cmdlen += len; + cp = &cmd_del2; + goto skip; + } + } + + /* + * Search the table for the command. + * + * !!! + * Historic vi permitted the mark to immediately follow the + * 'k' in the 'k' command. Make it work. + * + * !!! + * Historic vi permitted pretty much anything to follow the + * substitute command, e.g. "s/e/E/|s|sgc3p" was fine. Make + * the command "sgc" work. + */ + if ((cp = ex_comm_search(p, namelen)) == NULL) + switch (p[0]) { + case 's': + cmd -= namelen - 1; + cmdlen += namelen - 1; + cp = &cmd_subagain; + break; + case 'k': + if (p[1] && !p[2]) { + cmd -= namelen - 1; + cmdlen += namelen - 1; + cp = &cmds[C_K]; + break; + } + /* FALLTHROUGH */ + default: + msgq(sp, M_ERR, + "The %.*s command is unknown", namelen, p); + goto err; + } + + /* Some commands are either not implemented or turned off. */ +skip: if (F_ISSET(cp, E_NOPERM)) { + msgq(sp, M_ERR, + "The %s command is not currently supported", + cp->name); + goto err; + } + + /* Some commands aren't okay in globals. */ + if (F_ISSET(sp, S_GLOBAL) && F_ISSET(cp, E_NOGLOBAL)) { + msgq(sp, M_ERR, + "The %s command can't be used as part of a global command", + cp->name); + goto err; + } + + /* + * Multiple < and > characters; another "feature". Note, + * The string passed to the underlying function may not be + * nul terminated in this case. + */ + if ((cp == &cmds[C_SHIFTL] && *p == '<') || + (cp == &cmds[C_SHIFTR] && *p == '>')) { + for (ch = *p; cmdlen > 0; --cmdlen, ++cmd) + if (*cmd != ch) + break; + if (argv_exp0(sp, ep, &exc, p, cmd - p)) + goto err; + } + + /* + * The visual command has a different syntax when called + * from ex than when called from a vi colon command. FMH. + */ + if (cp == &cmds[C_VISUAL_EX] && IN_VI_MODE(sp)) + cp = &cmds[C_VISUAL_VI]; + + /* Set the format style flags for the next command. */ + if (cp == &cmds[C_HASH]) + exp->fdef = E_F_HASH; + else if (cp == &cmds[C_LIST]) + exp->fdef = E_F_LIST; + else if (cp == &cmds[C_PRINT]) + exp->fdef = E_F_PRINT; + uselastcmd = 0; + } else { + /* Print is the default command. */ + cp = &cmds[C_PRINT]; + + /* Set the saved format flags. */ + F_SET(&exc, exp->fdef); + + /* + * !!! + * If no address was specified, and it's not a global command, + * we up the address by one. (I have not an idea why global + * commands are exempted, but it's (ahem) historic practice. + */ + if (exc.addrcnt == 0 && !F_ISSET(sp, S_GLOBAL)) { + exc.addrcnt = 1; + exc.addr1.lno = sp->lno + 1; + exc.addr1.cno = sp->cno; + } + + uselastcmd = 1; + } + + /* + * !!! + * Historically, the number option applied to both ex and vi. One + * strangeness was that ex didn't switch display formats until a + * command was entered, e.g. <CR>'s after the set didn't change to + * the new format, but :1p would. + */ + if (O_ISSET(sp, O_NUMBER)) { + optnum = 1; + F_SET(&exc, E_F_HASH); + } else + optnum = 0; + + /* Initialize local flags to the command flags. */ + LF_INIT(cp->flags); + + /* + * File state must be checked throughout this code, because it is + * called when reading the .exrc file and similar things. There's + * this little chicken and egg problem -- if we read the file first, + * we won't know how to display it. If we read/set the exrc stuff + * first, we can't allow any command that requires file state. We + * don't have a "reading an rc" bit, because we want the commands + * to work when the user source's the rc file later. Historic vi + * generally took the easy way out and dropped core. + */ + if (LF_ISSET(E_NORC) && ep == NULL) { + msgq(sp, M_ERR, + "The %s command requires that a file have already been read in", + cp->name); + goto err; + } + + /* + * There are three normal termination cases for an ex command. They + * are the end of the string (cmdlen), or unescaped (by literal next + * characters) newline or '|' characters. As we're past any addresses, + * we can now determine how long the command is, so we don't have to + * look for all the possible terminations. There are three exciting + * special cases: + * + * 1: The bang, global, vglobal and the filter versions of the read and + * write commands are delimited by newlines (they can contain shell + * pipes). + * 2: The ex, edit, next and visual in vi mode commands all take ex + * commands as their first arguments. + * 3: The substitute command takes an RE as its first argument, and + * wants it to be specially delimited. + * + * Historically, '|' characters in the first argument of the ex, edit, + * next, vi visual, and substitute commands didn't delimit the command. + * And, in the filter cases for read and write, and the bang, global + * and vglobal commands, they did not delimit the command at all. + * + * For example, the following commands were legal: + * + * :edit +25|s/abc/ABC/ file.c + * :substitute s/|/PIPE/ + * :read !spell % | columnate + * :global/pattern/p|l + * + * It's not quite as simple as it sounds, however. The command: + * + * :substitute s/a/b/|s/c/d|set + * + * was also legal, i.e. the historic ex parser (using the word loosely, + * since "parser" implies some regularity) delimited the RE's based on + * its delimiter and not anything so irretrievably vulgar as a command + * syntax. + * + * One thing that makes this easier is that we can ignore most of the + * command termination conditions for the commands that want to take + * the command up to the next newline. None of them are legal in .exrc + * files, so if we're here, we only dealing with a single line, and we + * can just eat it. + * + * Anyhow, the following code makes this all work. First, for the + * special cases we move past their special argument(s). Then, we + * do normal command processing on whatever is left. Barf-O-Rama. + */ + arg1_len = 0; + save_cmd = cmd; + if (cp == &cmds[C_EDIT] || cp == &cmds[C_EX] || + cp == &cmds[C_NEXT] || cp == &cmds[C_VISUAL_VI]) { + /* + * Move to the next non-whitespace character. A '!' + * immediately following the command is eaten as a + * force flag. + */ + if (cmdlen > 0 && *cmd == '!') { + ++cmd; + --cmdlen; + F_SET(&exc, E_FORCE); + + /* Reset, don't reparse. */ + save_cmd = cmd; + } + for (tmp = 0; cmdlen > 0; --cmdlen, ++cmd) + if (!isblank(*cmd)) + break; + /* + * QUOTING NOTE: + * + * The historic implementation ignored all escape characters + * so there was no way to put a space or newline into the +cmd + * field. We do a simplistic job of fixing it by moving to the + * first whitespace character that isn't escaped by a literal + * next character. The literal next characters are stripped + * as they're no longer useful. + */ + if (cmdlen > 0 && *cmd == '+') { + ++cmd; + --cmdlen; + for (arg1 = p = cmd; cmdlen > 0; --cmdlen, ++cmd) { + ch = *cmd; + if (IS_ESCAPE(sp, ch) && cmdlen > 1) { + --cmdlen; + ch = *++cmd; + } else if (isblank(ch)) + break; + *p++ = ch; + } + arg1_len = cmd - arg1; + + /* Reset, so the first argument isn't reparsed. */ + save_cmd = cmd; + } + } else if (cp == &cmds[C_BANG] || + cp == &cmds[C_GLOBAL] || cp == &cmds[C_VGLOBAL]) { + cmd += cmdlen; + cmdlen = 0; + } else if (cp == &cmds[C_READ] || cp == &cmds[C_WRITE]) { + /* + * Move to the next character. If it's a '!', it's a filter + * command and we want to eat it all, otherwise, we're done. + */ + for (; cmdlen > 0; --cmdlen, ++cmd) { + ch = *cmd; + if (!isblank(ch)) + break; + } + if (cmdlen > 0 && ch == '!') { + cmd += cmdlen; + cmdlen = 0; + } + } else if (cp == &cmds[C_SUBSTITUTE]) { + /* + * Move to the next non-whitespace character, we'll use it as + * the delimiter. If the character isn't an alphanumeric or + * a '|', it's the delimiter, so parse it. Otherwise, we're + * into something like ":s g", so use the special substitute + * command. + */ + for (; cmdlen > 0; --cmdlen, ++cmd) + if (!isblank(cmd[0])) + break; + + if (isalnum(cmd[0]) || cmd[0] == '|') + cp = &cmd_subagain; + else if (cmdlen > 0) { + /* + * QUOTING NOTE: + * + * Backslashes quote delimiter characters for RE's. + * The backslashes are NOT removed since they'll be + * used by the RE code. Move to the third delimiter + * that's not escaped (or the end of the command). + */ + delim = *cmd; + ++cmd; + --cmdlen; + for (cnt = 2; cmdlen > 0 && cnt; --cmdlen, ++cmd) + if (cmd[0] == '\\' && cmdlen > 1) { + ++cmd; + --cmdlen; + } else if (cmd[0] == delim) + --cnt; + } + } + /* + * Use normal quoting and termination rules to find the end of this + * command. + * + * QUOTING NOTE: + * + * Historically, vi permitted ^V's to escape <newline>'s in the .exrc + * file. It was almost certainly a bug, but that's what bug-for-bug + * compatibility means, Grasshopper. Also, ^V's escape the command + * delimiters. Literal next quote characters in front of the newlines, + * '|' characters or literal next characters are stripped as as they're + * no longer useful. + */ + vi_address = cmdlen != 0 && cmd[0] != '\n'; + for (p = cmd, cnt = 0; cmdlen > 0; --cmdlen, ++cmd) { + ch = cmd[0]; + if (IS_ESCAPE(sp, ch) && cmdlen > 1) { + tmp = cmd[1]; + if (tmp == '\n' || tmp == '|') { + if (tmp == '\n') + ++sp->if_lno; + --cmdlen; + ++cmd; + ++cnt; + ch = tmp; + } + } else if (ch == '\n' || ch == '|') { + if (ch == '\n') + nl = 1; + --cmdlen; + break; + } + *p++ = ch; + } + + /* + * Save off the next command information, go back to the + * original start of the command. + */ + p = cmd + 1; + cmd = save_cmd; + save_cmd = p; + save_cmdlen = cmdlen; + cmdlen = ((save_cmd - cmd) - 1) - cnt; + + /* + * !!! + * The "set tags" command historically used a backslash, not the + * user's literal next character, to escape whitespace. Handle + * it here instead of complicating the argv_exp3() code. Note, + * this isn't a particularly complex trap, and if backslashes were + * legal in set commands, this would have to be much more complicated. + */ + if (cp == &cmds[C_SET]) + for (p = cmd, len = cmdlen; len > 0; --len, ++p) + if (*p == '\\') + *p = CH_LITERAL; + + /* + * Set the default addresses. It's an error to specify an address for + * a command that doesn't take them. If two addresses are specified + * for a command that only takes one, lose the first one. Two special + * cases here, some commands take 0 or 2 addresses. For most of them + * (the E_ADDR2_ALL flag), 0 defaults to the entire file. For one + * (the `!' command, the E_ADDR2_NONE flag), 0 defaults to no lines. + * + * Also, if the file is empty, some commands want to use an address of + * 0, i.e. the entire file is 0 to 0, and the default first address is + * 0. Otherwise, an entire file is 1 to N and the default line is 1. + * Note, we also add the E_ZERO flag to the command flags, for the case + * where the 0 address is only valid if it's a default address. + * + * Also, set a flag if we set the default addresses. Some commands + * (ex: z) care if the user specified an address of if we just used + * the current cursor. + */ + switch (LF_ISSET(E_ADDR1|E_ADDR2|E_ADDR2_ALL|E_ADDR2_NONE)) { + case E_ADDR1: /* One address: */ + switch (exc.addrcnt) { + case 0: /* Default cursor/empty file. */ + exc.addrcnt = 1; + F_SET(&exc, E_ADDRDEF); + if (LF_ISSET(E_ZERODEF)) { + if (file_lline(sp, ep, &lno)) + goto err; + if (lno == 0) { + exc.addr1.lno = 0; + LF_SET(E_ZERO); + } else + exc.addr1.lno = sp->lno; + } else + exc.addr1.lno = sp->lno; + exc.addr1.cno = sp->cno; + break; + case 1: + break; + case 2: /* Lose the first address. */ + exc.addrcnt = 1; + exc.addr1 = exc.addr2; + } + break; + case E_ADDR2_NONE: /* Zero/two addresses: */ + if (exc.addrcnt == 0) /* Default to nothing. */ + break; + goto two; + case E_ADDR2_ALL: /* Zero/two addresses: */ + if (exc.addrcnt == 0) { /* Default entire/empty file. */ + exc.addrcnt = 2; + F_SET(&exc, E_ADDRDEF); + if (file_lline(sp, ep, &exc.addr2.lno)) + goto err; + if (LF_ISSET(E_ZERODEF) && exc.addr2.lno == 0) { + exc.addr1.lno = 0; + LF_SET(E_ZERO); + } else + exc.addr1.lno = 1; + exc.addr1.cno = exc.addr2.cno = 0; + F_SET(&exc, E_ADDR2_ALL); + break; + } + /* FALLTHROUGH */ + case E_ADDR2: /* Two addresses: */ +two: switch (exc.addrcnt) { + case 0: /* Default cursor/empty file. */ + exc.addrcnt = 2; + F_SET(&exc, E_ADDRDEF); + if (LF_ISSET(E_ZERODEF) && sp->lno == 1) { + if (file_lline(sp, ep, &lno)) + goto err; + if (lno == 0) { + exc.addr1.lno = exc.addr2.lno = 0; + LF_SET(E_ZERO); + } else + exc.addr1.lno = exc.addr2.lno = sp->lno; + } else + exc.addr1.lno = exc.addr2.lno = sp->lno; + exc.addr1.cno = exc.addr2.cno = sp->cno; + break; + case 1: /* Default to first address. */ + exc.addrcnt = 2; + exc.addr2 = exc.addr1; + break; + case 2: + break; + } + break; + default: + if (exc.addrcnt) /* Error. */ + goto usage; + } + + /* + * !!! + * The ^D scroll command historically scrolled the value of the scroll + * option or to EOF. It was an error if the cursor was already at EOF. + * (Leading addresses were permitted, but were then ignored.) + */ + if (cp == &cmds[C_SCROLL]) { + exc.addrcnt = 2; + exc.addr1.lno = sp->lno + 1; + exc.addr2.lno = sp->lno + O_VAL(sp, O_SCROLL); + exc.addr1.cno = exc.addr2.cno = sp->cno; + if (file_lline(sp, ep, &lno)) + goto err; + if (lno != 0 && lno > sp->lno && exc.addr2.lno > lno) + exc.addr2.lno = lno; + } + + flagoff = 0; + for (p = cp->syntax; *p != '\0'; ++p) { + /* + * The force flag is sensitive to leading whitespace, i.e. + * "next !" is different from "next!". Handle it before + * skipping leading <blank>s. + */ + if (*p == '!') { + if (cmdlen > 0 && *cmd == '!') { + ++cmd; + --cmdlen; + F_SET(&exc, E_FORCE); + } + continue; + } + + /* Skip leading <blank>s. */ + for (; cmdlen > 0; --cmdlen, ++cmd) + if (!isblank(*cmd)) + break; + + /* + * Quit when reach the end of the command, unless it's a + * command that does its own parsing, in which case we want + * to build a reasonable argv for it. This code guarantees + * that there will be an argv when the function gets called, + * so the correct test is for a length of 0, not for the + * argc > 0. Since '!' can precede commands that do their + * own parsing, we have to have already handled it. + */ + if (cmdlen == 0 && *p != 'S' && *p != 's') + break; + + switch (*p) { + case '1': /* +, -, #, l, p */ + /* + * !!! + * Historically, some flags were ignored depending + * on where they occurred in the command line. For + * example, in the command, ":3+++p--#", historic vi + * acted on the '#' flag, but ignored the '-' flags. + * It's unambiguous what the flags mean, so we just + * handle them regardless of the stupidity of their + * location. + */ + for (; cmdlen; --cmdlen, ++cmd) + switch (*cmd) { + case '+': + ++flagoff; + break; + case '-': + --flagoff; + break; + case '#': + optnum = 0; + F_SET(&exc, E_F_HASH); + exp->fdef |= E_F_HASH; + break; + case 'l': + F_SET(&exc, E_F_LIST); + exp->fdef |= E_F_LIST; + break; + case 'p': + F_SET(&exc, E_F_PRINT); + exp->fdef |= E_F_PRINT; + break; + default: + goto end1; + } +end1: break; + case '2': /* -, ., +, ^ */ + case '3': /* -, ., +, ^, = */ + for (; cmdlen; --cmdlen, ++cmd) + switch (*cmd) { + case '-': + F_SET(&exc, E_F_DASH); + break; + case '.': + F_SET(&exc, E_F_DOT); + break; + case '+': + F_SET(&exc, E_F_PLUS); + break; + case '^': + F_SET(&exc, E_F_CARAT); + break; + case '=': + if (*p == '3') { + F_SET(&exc, E_F_EQUAL); + break; + } + /* FALLTHROUGH */ + default: + goto end2; + } +end2: break; + case 'b': /* buffer */ + /* + * !!! + * Historically, "d #" was a delete with a flag, not a + * delete into the '#' buffer. If the current command + * permits a flag, don't use one as a buffer. However, + * the 'l' and 'p' flags were legal buffer names in the + * historic ex, and were used as buffers, not flags. + */ + if ((cmd[0] == '+' || cmd[0] == '-' || cmd[0] == '#') && + strchr(p, '1') != NULL) + break; + /* + * !!! + * Digits can't be buffer names in ex commands, or the + * command "d2" would be a delete into buffer '2', and + * not a two-line deletion. + */ + if (!isdigit(cmd[0])) { + exc.buffer = *cmd; + ++cmd; + --cmdlen; + F_SET(&exc, E_BUFFER); + } + break; + case 'c': /* count [01+a] */ + ++p; + /* Validate any signed value. */ + if (!isdigit(*cmd) && + (*p != '+' || (*cmd != '+' && *cmd != '-'))) + break; + /* If a signed value, set appropriate flags. */ + if (*cmd == '-') + F_SET(&exc, E_COUNT_NEG); + else if (*cmd == '+') + F_SET(&exc, E_COUNT_POS); +/* 8-bit XXX */ if ((lno = strtol(cmd, &t, 10)) == 0 && *p != '0') { + msgq(sp, M_ERR, "Count may not be zero"); + goto err; + } + cmdlen -= (t - cmd); + cmd = t; + /* + * Count as address offsets occur in commands taking + * two addresses. Historic vi practice was to use + * the count as an offset from the *second* address. + * + * Set a count flag; some underlying commands (see + * join) do different things with counts than with + * line addresses. + */ + if (*p == 'a') { + exc.addr1 = exc.addr2; + exc.addr2.lno = exc.addr1.lno + lno - 1; + } else + exc.count = lno; + F_SET(&exc, E_COUNT); + break; + case 'f': /* file */ + if (argv_exp2(sp, ep, + &exc, cmd, cmdlen, cp == &cmds[C_BANG])) + goto err; + goto countchk; + case 'l': /* line */ + if (ep_line(sp, ep, &cur, &cmd, &cmdlen, &tmp)) + goto err; + /* Line specifications are always required. */ + if (!tmp) { + msgq(sp, M_ERR, + "%s: bad line specification", cmd); + goto err; + } + /* The line must exist for these commands. */ + if (file_lline(sp, ep, &lno)) + goto err; + if (cur.lno > lno) { + badlno(sp, lno); + goto err; + } + exc.lineno = cur.lno; + break; + case 'S': /* string, file exp. */ + if (argv_exp1(sp, ep, + &exc, cmd, cmdlen, cp == &cmds[C_BANG])) + goto err; + goto addr2; + case 's': /* string */ + if (argv_exp0(sp, ep, &exc, cmd, cmdlen)) + goto err; + goto addr2; + case 'W': /* word string */ + /* + * QUOTING NOTE: + * + * Literal next characters escape the following + * character. Quoting characters are stripped + * here since they are no longer useful. + * + * First there was the word. + */ + for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd) { + ch = *cmd; + if (IS_ESCAPE(sp, ch) && cmdlen > 1) { + --cmdlen; + *p++ = *++cmd; + } else if (isblank(ch)) { + ++cmd; + --cmdlen; + break; + } else + *p++ = ch; + } + if (argv_exp0(sp, ep, &exc, t, p - t)) + goto err; + + /* Delete intervening whitespace. */ + for (; cmdlen > 0; --cmdlen, ++cmd) { + ch = *cmd; + if (!isblank(ch)) + break; + } + if (cmdlen == 0) + goto usage; + + /* Followed by the string. */ + for (p = t = cmd; cmdlen > 0; --cmdlen, ++cmd, ++p) { + ch = *cmd; + if (IS_ESCAPE(sp, ch) && cmdlen > 1) { + --cmdlen; + *p = *++cmd; + } else + *p = ch; + } + if (argv_exp0(sp, ep, &exc, t, p - t)) + goto err; + goto addr2; + case 'w': /* word */ + if (argv_exp3(sp, ep, &exc, cmd, cmdlen)) + goto err; +countchk: if (*++p != 'N') { /* N */ + /* + * If a number is specified, must either be + * 0 or that number, if optional, and that + * number, if required. + */ + num = *p - '0'; + if ((*++p != 'o' || exp->argsoff != 0) && + exp->argsoff != num) + goto usage; + } + goto addr2; + default: + msgq(sp, M_ERR, + "Internal syntax table error (%s: %c)", + cp->name, *p); + } + } + + /* Skip trailing whitespace. */ + for (; cmdlen; --cmdlen) { + ch = *cmd++; + if (!isblank(ch)) + break; + } + + /* + * There shouldn't be anything left, and no more required + * fields, i.e neither 'l' or 'r' in the syntax string. + */ + if (cmdlen || strpbrk(p, "lr")) { +usage: msgq(sp, M_ERR, "Usage: %s", cp->usage); + goto err; + } + + /* Verify that the addresses are legal. */ +addr2: switch (exc.addrcnt) { + case 2: + if (file_lline(sp, ep, &lno)) + goto err; + /* + * Historic ex/vi permitted commands with counts to go past + * EOF. So, for example, if the file only had 5 lines, the + * ex command "1,6>" would fail, but the command ">300" + * would succeed. Since we don't want to have to make all + * of the underlying commands handle random line numbers, + * fix it here. + */ + if (exc.addr2.lno > lno) + if (F_ISSET(&exc, E_COUNT)) + exc.addr2.lno = lno; + else { + badlno(sp, lno); + goto err; + } + /* FALLTHROUGH */ + case 1: + num = exc.addr1.lno; + /* + * If it's a "default vi command", zero is okay. Historic + * vi allowed this, note, it's also the hack that allows + * "vi +100 nonexistent_file" to work. + */ + if (num == 0 && (IN_EX_MODE(sp) || uselastcmd != 1) && + !LF_ISSET(E_ZERO)) { + msgq(sp, M_ERR, + "The %s command doesn't permit an address of 0", + cp->name); + goto err; + } + if (file_lline(sp, ep, &lno)) + goto err; + if (num > lno) { + badlno(sp, lno); + goto err; + } + break; + } + + /* + * If doing a default command and there's nothing left on the line, + * vi just moves to the line. For example, ":3" and ":'a,'b" just + * move to line 3 and line 'b, respectively, but ":3|" prints line 3. + * + * !!! + * This is done before the absolute mark gets set; historically, + * "/a/,/b/" did NOT set vi's absolute mark, but "/a/,/b/d" did. + */ + if (IN_VI_MODE(sp) && uselastcmd && vi_address == 0) { + switch (exc.addrcnt) { + case 2: + sp->lno = exc.addr2.lno ? exc.addr2.lno : 1; + sp->cno = exc.addr2.cno; + break; + case 1: + sp->lno = exc.addr1.lno ? exc.addr1.lno : 1; + sp->cno = exc.addr1.cno; + break; + } + cmd = save_cmd; + cmdlen = save_cmdlen; + goto loop; + } + + /* + * Set the absolute mark -- we have to set it for vi here, in case + * it's a compound command, e.g. ":5p|6" should set the absolute + * mark for vi. + */ + if (F_ISSET(exp, EX_ABSMARK)) { + cur.lno = sp->lno; + cur.cno = sp->cno; + F_CLR(exp, EX_ABSMARK); + if (mark_set(sp, ep, ABSMARK1, &cur, 1)) + goto err; + } + + /* Final setup for the command. */ + exc.cmd = cp; + +#if defined(DEBUG) && 0 + TRACE(sp, "ex_cmd: %s", exc.cmd->name); + if (exc.addrcnt > 0) { + TRACE(sp, "\taddr1 %d", exc.addr1.lno); + if (exc.addrcnt > 1) + TRACE(sp, " addr2: %d", exc.addr2.lno); + TRACE(sp, "\n"); + } + if (exc.lineno) + TRACE(sp, "\tlineno %d", exc.lineno); + if (exc.flags) + TRACE(sp, "\tflags %0x", exc.flags); + if (F_ISSET(&exc, E_BUFFER)) + TRACE(sp, "\tbuffer %c", exc.buffer); + TRACE(sp, "\n"); + if (exc.argc) { + for (cnt = 0; cnt < exc.argc; ++cnt) + TRACE(sp, "\targ %d: {%s}", cnt, exc.argv[cnt]); + TRACE(sp, "\n"); + } +#endif + /* Clear autoprint flag. */ + F_CLR(exp, EX_AUTOPRINT); + + /* Increment the command count if not called from vi. */ + if (IN_EX_MODE(sp)) + ++sp->ccnt; + + /* + * If file state available, and not doing a global command, + * log the start of an action. + */ + if (ep != NULL && !F_ISSET(sp, S_GLOBAL)) + (void)log_cursor(sp, ep); + + /* + * !!! + * There are two special commands for the purposes of this code: the + * default command (<carriage-return>) or the scrolling commands (^D + * and <EOF>) as the first non-<blank> characters in the line. + * + * If this is the first command in the command line, we received the + * command from the ex command loop and we're talking to a tty, and + * and there's nothing else on the command line, and it's one of the + * special commands, we erase the prompt character with a '\r'. Else, + * we put out a newline character to separate the command from the + * output from the command. It's OK if vi calls us -- we won't be in + * ex mode so we'll do nothing. + * + * !!! + * Historically, ex only put out a \r, so, if the displayed line was + * only a single character long, and <eof> was represented as ^D, the + * output wouldn't overwrite the user's input. Sex currently doesn't + * display the <eof> character if it's going to be the scroll command, + * i.e. if it's the first non-<blank> character in the line. If sex + * is changed to run in cooked mode, i.e. <eof> is displayed, this code + * will have to overwrite it. We also don't treat lines with extra + * prompt characters as empty -- it's not worth the effort since we'd + * have to overwrite some indeterminate number of columns with spaces + * to clean up. For now, put out enough spaces to overwrite the prompt. + */ + if (sep != NONE) { + if (ep != NULL && + IN_EX_MODE(sp) && F_ISSET(sp->gp, G_STDIN_TTY)) + if (sep == NEEDSEP_NR && + (uselastcmd || cp == &cmds[C_SCROLL])) { + (void)putchar('\r'); + for (len = KEY_LEN(sp, PROMPTCHAR); len--;) + (void)putchar(' '); + (void)putchar('\r'); + } else + (void)putchar('\n'); + sep = NONE; + } + + /* Save the current mode. */ + saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE); + + /* Do the command. */ + if (cp->fn(sp, ep, &exc)) + goto err; + +#ifdef DEBUG + /* Make sure no function left the temporary space locked. */ + if (F_ISSET(sp->gp, G_TMP_INUSE)) { + F_CLR(sp->gp, G_TMP_INUSE); + msgq(sp, M_ERR, "Error: ex: temporary buffer not released"); + goto err; + } +#endif + if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE)) { + /* + * Only here if the mode of the underlying file changed, e.g. + * the user switched files or is exiting. Two things that we + * might have to save: first, any "+cmd" field set up for an + * ex/edit command will have to be saved for later, also, any + * part of the current ex command that hasn't been executed + * yet. For example: + * + * :edit +25 file.c|s/abc/ABC/|1 + * + * !!! + * The historic vi just hung, of course; nvi handles it by + * pushing the keys onto the tty queue. Since the commands + * are intended as ex commands, add additional characters + * to make it all work if we're switching modes to vi. Also, + * + commands were oriented to the last line in the file, + * historically, make the cursor start out there. + * + * For the fun of it, if you want to see if a vi clone got the + * ex argument parsing right, try: + * + * echo 'foo|bar' > file1; echo 'foo/bar' > file2; + * vi + * :edit +1|s/|/PIPE/|w file1| e file2|1 | s/\//SLASH/|wq + */ + if (arg1_len == 0 && save_cmdlen == 0) + return (0); + if (term_push(sp, "\n", 1, 0)) + goto err; + if (save_cmdlen != 0) + if (term_push(sp, save_cmd, save_cmdlen, 0)) + goto err; + if (arg1 != NULL) { + if (IN_VI_MODE(sp) && save_cmdlen != 0 && + term_push(sp, "|", 1, 0)) + goto err; + if (term_push(sp, arg1, arg1_len, 0)) + goto err; + if (file_lline(sp, ep, &sp->frp->lno)) + goto err; + F_SET(sp->frp, FR_CURSORSET); + } + if (IN_VI_MODE(sp) && term_push(sp, ":", 1, 0)) + goto err; + return (0); + } + + /* + * Integrate any offset parsed by the underlying command, and make + * sure the referenced line exists. + * + * XXX + * May not match historic practice (I've never been able to completely + * figure it out.) For example, the '=' command from vi mode often + * got the offset wrong, and complained it was too large, but didn't + * seem to have a problem with the cursor. If anyone complains, ask + * them how it's supposed to work, they probably know. + */ + if (ep != NULL && (flagoff += exc.flagoff)) { + if (flagoff < 0) { + if (sp->lno <= -flagoff) { + msgq(sp, M_ERR, "Flag offset before line 1"); + goto err; + } + } else { + if (file_lline(sp, ep, &lno)) + goto err; + if (sp->lno + flagoff > lno) { + msgq(sp, M_ERR, "Flag offset past end-of-file"); + goto err; + } + } + sp->lno += flagoff; + } + + /* + * If the command was successful and we're in ex command mode, we + * may want to display a line. Make sure there's a line to display. + */ + if (ep != NULL && + IN_EX_MODE(sp) && !F_ISSET(sp, S_GLOBAL) && sp->lno != 0) { + /* + * The print commands have already handled the `print' flags. + * If so, clear them. + */ + if (LF_ISSET(E_F_PRCLEAR)) + F_CLR(&exc, E_F_HASH | E_F_LIST | E_F_PRINT); + + /* If hash only set because of the number option, discard it. */ + if (optnum) + F_CLR(&exc, E_F_HASH); + + /* + * If there was an explicit flag to display the new cursor + * line, or we're in ex mode, autoprint is set, and a change + * was made, display the line. If any print flags set use + * them, otherwise default to print. + */ + LF_INIT(F_ISSET(&exc, E_F_HASH | E_F_LIST | E_F_PRINT)); + if (!LF_ISSET(E_F_HASH | E_F_LIST | E_F_PRINT) && + O_ISSET(sp, O_AUTOPRINT) && + (F_ISSET(exp, EX_AUTOPRINT) || F_ISSET(cp, E_AUTOPRINT))) + LF_INIT(E_F_PRINT); + + if (LF_ISSET(E_F_HASH | E_F_LIST | E_F_PRINT)) { + memset(&exc, 0, sizeof(EXCMDARG)); + exc.addrcnt = 2; + exc.addr1.lno = exc.addr2.lno = sp->lno; + exc.addr1.cno = exc.addr2.cno = sp->cno; + (void)ex_print(sp, ep, &exc.addr1, &exc.addr2, flags); + } + } + + cmd = save_cmd; + cmdlen = save_cmdlen; + goto loop; + /* NOTREACHED */ + + /* + * If we haven't put out a separator line, do it now. For more + * detailed comments, see above. + */ +err: if (sep != NONE && + ep != NULL && IN_EX_MODE(sp) && F_ISSET(sp->gp, G_STDIN_TTY)) + (void)fputc('\n', stdout); + /* + * On error, we discard any keys we have left, as well as any keys + * that were mapped. The test of save_cmdlen isn't necessarily + * correct. If we fail early enough we don't know if the entire + * string was a single command or not. Try and guess, it's useful + * to know if part of the command was discarded. + */ + if (save_cmdlen == 0) + for (; cmdlen; --cmdlen) { + ch = *cmd++; + if (IS_ESCAPE(sp, ch) && cmdlen > 1) { + --cmdlen; + ++cmd; + } else if (ch == '\n' || ch == '|') { + if (cmdlen > 1) + save_cmdlen = 1; + break; + } + } + if (save_cmdlen != 0) + msgq(sp, M_ERR, + "Ex command failed: remaining command input discarded"); + /* + * !!! + * Previous versions of nvi cleared mapped characters on error. This + * feature was removed when users complained that it wasn't historic + * practice. + */ + return (1); +} + +/* + * ep_range -- + * Get a line range for ex commands. + */ +static int +ep_range(sp, ep, excp, cmdp, cmdlenp) + SCR *sp; + EXF *ep; + EXCMDARG *excp; + char **cmdp; + size_t *cmdlenp; +{ + MARK cur, savecursor; + size_t cmdlen; + int savecursor_set, tmp; + char *cmd; + + /* Percent character is all lines in the file. */ + cmd = *cmdp; + cmdlen = *cmdlenp; + if (*cmd == '%') { + excp->addr1.lno = 1; + if (file_lline(sp, ep, &excp->addr2.lno)) + return (1); + + /* If an empty file, then the first line is 0, not 1. */ + if (excp->addr2.lno == 0) + excp->addr1.lno = 0; + excp->addr1.cno = excp->addr2.cno = 0; + excp->addrcnt = 2; + + ++*cmdp; + --*cmdlenp; + return (0); + } + + /* Parse comma or semi-colon delimited line specs. */ + for (savecursor_set = 0, excp->addrcnt = 0; cmdlen > 0;) + switch (*cmd) { + case ';': /* Semi-colon delimiter. */ + /* + * Comma delimiters delimit; semi-colon delimiters + * change the current address for the 2nd address + * to be the first address. Trailing or multiple + * delimiters are discarded. + */ + if (excp->addrcnt == 0) + goto done; + if (!savecursor_set) { + savecursor.lno = sp->lno; + savecursor.cno = sp->cno; + sp->lno = excp->addr1.lno; + sp->cno = excp->addr1.cno; + savecursor_set = 1; + } + ++cmd; + --cmdlen; + break; + case ',': /* Comma delimiter. */ + /* If no addresses yet, defaults to ".". */ + if (excp->addrcnt == 0) { + excp->addr1.lno = sp->lno; + excp->addr1.cno = sp->cno; + excp->addrcnt = 1; + } + /* FALLTHROUGH */ + case ' ': /* Whitespace. */ + case '\t': /* Whitespace. */ + ++cmd; + --cmdlen; + break; + default: + if (ep_line(sp, ep, &cur, &cmd, &cmdlen, &tmp)) + return (1); + if (!tmp) + goto done; + + /* + * Extra addresses are discarded, starting with + * the first. + */ + switch (excp->addrcnt) { + case 0: + excp->addr1 = cur; + excp->addrcnt = 1; + break; + case 1: + excp->addr2 = cur; + excp->addrcnt = 2; + break; + case 2: + excp->addr1 = excp->addr2; + excp->addr2 = cur; + break; + } + break; + } + + /* + * XXX + * This is probably not the right behavior for savecursor -- + * need to figure out what the historical ex did for ";,;,;5p" + * or similar stupidity. + */ +done: if (savecursor_set) { + sp->lno = savecursor.lno; + sp->cno = savecursor.cno; + } + if (excp->addrcnt == 2 && excp->addr2.lno < excp->addr1.lno) { + msgq(sp, M_ERR, + "The second address is smaller than the first"); + return (1); + } + *cmdp = cmd; + *cmdlenp = cmdlen; + return (0); +} + +/* + * Get a single line address specifier. + * + * The way the "previous context" mark worked was that any "non-relative" + * motion set it. While ex/vi wasn't totally consistent about this, ANY + * numeric address, search pattern, '$', or mark reference in an address + * was considered non-relative, and set the value. Which should explain + * why we're hacking marks down here. The problem was that the mark was + * only set if the command was called, i.e. we have to set a flag and test + * it later. + * + * XXX + * This is not exactly historic practice, although it's fairly close. + */ +static int +ep_line(sp, ep, cur, cmdp, cmdlenp, addr_found) + SCR *sp; + EXF *ep; + MARK *cur; + char **cmdp; + size_t *cmdlenp; + int *addr_found; +{ + EX_PRIVATE *exp; + MARK m; + long total; + u_int flags; + size_t cmdlen; + int (*sf) __P((SCR *, EXF *, MARK *, MARK *, char *, char **, u_int *)); + char *cmd, *endp; + + exp = EXP(sp); + *addr_found = 0; + + cmd = *cmdp; + cmdlen = *cmdlenp; + switch (*cmd) { + case '$': /* Last line in the file. */ + *addr_found = 1; + F_SET(exp, EX_ABSMARK); + + cur->cno = 0; + if (file_lline(sp, ep, &cur->lno)) + return (1); + ++cmd; + --cmdlen; + break; /* Absolute line number. */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + *addr_found = 1; + F_SET(exp, EX_ABSMARK); + + cur->cno = 0; +/* 8-bit XXX */ cur->lno = strtol(cmd, &endp, 10); + cmdlen -= (endp - cmd); + cmd = endp; + break; + case '\'': /* Use a mark. */ + *addr_found = 1; + F_SET(exp, EX_ABSMARK); + + if (cmdlen == 1) { + msgq(sp, M_ERR, "No mark name supplied"); + return (1); + } + if (mark_get(sp, ep, cmd[1], cur)) + return (1); + cmd += 2; + cmdlen -= 2; + break; + case '\\': /* Search: forward/backward. */ + /* + * !!! + * I can't find any difference between // and \/ or between + * ?? and \?. Mark Horton doesn't remember there being any + * difference. C'est la vie. + */ + if (cmdlen < 2 || cmd[1] != '/' && cmd[1] != '?') { + msgq(sp, M_ERR, "\\ not followed by / or ?"); + return (1); + } + ++cmd; + --cmdlen; + sf = cmd[0] == '/' ? f_search : b_search; + goto search; + case '/': /* Search forward. */ + sf = f_search; + goto search; + case '?': /* Search backward. */ + sf = b_search; +search: F_SET(exp, EX_ABSMARK); + + if (ep == NULL) { + msgq(sp, M_ERR, + "A search address requires that a file have already been read in"); + return (1); + } + *addr_found = 1; + m.lno = sp->lno; + m.cno = sp->cno; + flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET; + if (sf(sp, ep, &m, &m, cmd, &endp, &flags)) + return (1); + cur->lno = m.lno; + cur->cno = m.cno; + cmdlen -= (endp - cmd); + cmd = endp; + break; + case '.': /* Current position. */ + *addr_found = 1; + cur->cno = sp->cno; + + /* If an empty file, then '.' is 0, not 1. */ + if (sp->lno == 1) { + if (file_lline(sp, ep, &cur->lno)) + return (1); + if (cur->lno != 0) + cur->lno = 1; + } else + cur->lno = sp->lno; + ++cmd; + --cmdlen; + break; + } + + /* + * Evaluate any offset. Offsets are +/- any number, or any number + * of +/- signs, or any combination thereof. If no address found + * yet, offset is relative to ".". + */ + for (total = 0; cmdlen > 0 && (cmd[0] == '-' || cmd[0] == '+');) { + if (!*addr_found) { + cur->lno = sp->lno; + cur->cno = sp->cno; + *addr_found = 1; + } + + if (cmdlen > 1 && isdigit(cmd[1])) { +/* 8-bit XXX */ total += strtol(cmd, &endp, 10); + cmdlen -= (endp - cmd); + cmd = endp; + } else { + total += cmd[0] == '-' ? -1 : 1; + --cmdlen; + ++cmd; + } + } + + if (*addr_found) { + if (total < 0 && -total > cur->lno) { + msgq(sp, M_ERR, + "Reference to a line number less than 0"); + return (1); + } + cur->lno += total; + + *cmdp = cmd; + *cmdlenp = cmdlen; + } + return (0); +} + +/* + * ex_is_abbrev - + * The vi text input routine needs to know if ex thinks this is + * an [un]abbreviate command, so it can turn off abbreviations. + * Usual ranting in the vi/v_ntext:txt_abbrev() routine. + */ +int +ex_is_abbrev(name, len) + char *name; + size_t len; +{ + EXCMDLIST const *cp; + + return ((cp = ex_comm_search(name, len)) != NULL && + (cp == &cmds[C_ABBR] || cp == &cmds[C_UNABBREVIATE])); +} + +/* + * ex_is_unmap - + * The vi text input routine needs to know if ex thinks this is + * an unmap command, so it can turn off input mapping. Usual + * ranting in the vi/v_ntext:txt_unmap() routine. + */ +int +ex_is_unmap(name, len) + char *name; + size_t len; +{ + EXCMDLIST const *cp; + + /* + * The command the vi input routines are really interested in + * is "unmap!", not just unmap. + */ + if (name[len - 1] != '!') + return (0); + --len; + return ((cp = ex_comm_search(name, len)) != NULL && + cp == &cmds[C_UNMAP]); +} + +static __inline EXCMDLIST const * +ex_comm_search(name, len) + char *name; + size_t len; +{ + EXCMDLIST const *cp; + + for (cp = cmds; cp->name != NULL; ++cp) { + if (cp->name[0] > name[0]) + return (NULL); + if (cp->name[0] != name[0]) + continue; + if (!memcmp(name, cp->name, len)) + return (cp); + } + return (NULL); +} + +static void +badlno(sp, lno) + SCR *sp; + recno_t lno; +{ + if (lno == 0) + msgq(sp, M_ERR, "Illegal address: the file is empty"); + else + msgq(sp, M_ERR, "Illegal address: only %lu line%s in the file", + lno, lno > 1 ? "s" : ""); +} diff --git a/usr.bin/vi/ex/ex_abbrev.c b/usr.bin/vi/ex/ex_abbrev.c new file mode 100644 index 0000000..a0af8cd --- /dev/null +++ b/usr.bin/vi/ex/ex_abbrev.c @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_abbrev.c 8.12 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "../vi/vcmd.h" + +/* + * ex_abbr -- :abbreviate [key replacement] + * Create an abbreviation or display abbreviations. + */ +int +ex_abbr(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + CHAR_T *p; + size_t len; + + switch (cmdp->argc) { + case 0: + if (seq_dump(sp, SEQ_ABBREV, 0) == 0) + msgq(sp, M_INFO, "No abbreviations to display"); + return (0); + case 2: + break; + default: + abort(); + } + + /* Check for illegal characters. */ + for (p = cmdp->argv[0]->bp, len = cmdp->argv[0]->len; len--; ++p) + if (!inword(*p)) { + msgq(sp, M_ERR, + "%s may not be part of an abbreviated word", + KEY_NAME(sp, *p)); + return (1); + } + + if (seq_set(sp, NULL, 0, cmdp->argv[0]->bp, cmdp->argv[0]->len, + cmdp->argv[1]->bp, cmdp->argv[1]->len, SEQ_ABBREV, SEQ_USERDEF)) + return (1); + + F_SET(sp->gp, G_ABBREV); + return (0); +} + +/* + * ex_unabbr -- :unabbreviate key + * Delete an abbreviation. + */ +int +ex_unabbr(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + ARGS *ap; + + ap = cmdp->argv[0]; + if (!F_ISSET(sp->gp, G_ABBREV) || + seq_delete(sp, ap->bp, ap->len, SEQ_ABBREV)) { + msgq(sp, M_ERR, "\"%s\" is not an abbreviation", ap->bp); + return (1); + } + return (0); +} + +/* + * abbr_save -- + * Save the abbreviation sequences to a file. + */ +int +abbr_save(sp, fp) + SCR *sp; + FILE *fp; +{ + return (seq_save(sp, fp, "abbreviate ", SEQ_ABBREV)); +} diff --git a/usr.bin/vi/ex/ex_append.c b/usr.bin/vi/ex/ex_append.c new file mode 100644 index 0000000..97172dc --- /dev/null +++ b/usr.bin/vi/ex/ex_append.c @@ -0,0 +1,220 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_append.c 8.22 (Berkeley) 8/7/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "../sex/sex_screen.h" + +enum which {APPEND, CHANGE, INSERT}; + +static int aci __P((SCR *, EXF *, EXCMDARG *, enum which)); + +/* + * ex_append -- :[line] a[ppend][!] + * Append one or more lines of new text after the specified line, + * or the current line if no address is specified. + */ +int +ex_append(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (aci(sp, ep, cmdp, APPEND)); +} + +/* + * ex_change -- :[line[,line]] c[hange][!] [count] + * Change one or more lines to the input text. + */ +int +ex_change(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (aci(sp, ep, cmdp, CHANGE)); +} + +/* + * ex_insert -- :[line] i[nsert][!] + * Insert one or more lines of new text before the specified line, + * or the current line if no address is specified. + */ +int +ex_insert(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (aci(sp, ep, cmdp, INSERT)); +} + +static int +aci(sp, ep, cmdp, cmd) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; + enum which cmd; +{ + MARK m; + TEXTH *sv_tiqp, tiq; + TEXT *tp; + struct termios t; + u_int flags; + int rval; + + rval = 0; + + /* + * Set input flags; the ! flag turns off autoindent for append, + * change and insert. + */ + LF_INIT(TXT_DOTTERM | TXT_NLECHO); + if (!F_ISSET(cmdp, E_FORCE) && O_ISSET(sp, O_AUTOINDENT)) + LF_SET(TXT_AUTOINDENT); + if (O_ISSET(sp, O_BEAUTIFY)) + LF_SET(TXT_BEAUTIFY); + + /* Input is interruptible. */ + F_SET(sp, S_INTERRUPTIBLE); + + /* + * If this code is called by vi, the screen TEXTH structure (sp->tiqp) + * may already be in use, e.g. ":append|s/abc/ABC/" would fail as we're + * only halfway through the line when the append code fires. Use the + * local structure instead. + * + * If this code is called by vi, we want to reset the terminal and use + * ex's s_get() routine. It actually works fine if we use vi's s_get() + * routine, but it doesn't look as nice. Maybe if we had a separate + * window or something, but getting a line at a time looks awkward. + */ + if (IN_VI_MODE(sp)) { + memset(&tiq, 0, sizeof(TEXTH)); + CIRCLEQ_INIT(&tiq); + sv_tiqp = sp->tiqp; + sp->tiqp = &tiq; + + if (F_ISSET(sp->gp, G_STDIN_TTY)) + SEX_RAW(t); + (void)write(STDOUT_FILENO, "\n", 1); + LF_SET(TXT_NLECHO); + + } + + /* Set the line number, so that autoindent works correctly. */ + sp->lno = cmdp->addr1.lno; + + if (sex_get(sp, ep, sp->tiqp, 0, flags) != INP_OK) + goto err; + + /* + * If doing a change, replace lines for as long as possible. Then, + * append more lines or delete remaining lines. Changes to an empty + * file are just appends, and inserts are the same as appends to the + * previous line. + * + * !!! + * Adjust the current line number for the commands to match historic + * practice if the user doesn't enter anything, and set the address + * to which we'll append. This is safe because an address of 0 is + * illegal for change and insert. + */ + m = cmdp->addr1; + switch (cmd) { + case INSERT: + --m.lno; + /* FALLTHROUGH */ + case APPEND: + if (sp->lno == 0) + sp->lno = 1; + break; + case CHANGE: + --m.lno; + if (sp->lno != 1) + --sp->lno; + break; + } + + /* + * !!! + * Cut into the unnamed buffer. + */ + if (cmd == CHANGE && + (cut(sp, ep, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) || + delete(sp, ep, &cmdp->addr1, &cmdp->addr2, 1))) + goto err; + + for (tp = sp->tiqp->cqh_first; + tp != (TEXT *)sp->tiqp; tp = tp->q.cqe_next) { + if (file_aline(sp, ep, 1, m.lno, tp->lb, tp->len)) { +err: rval = 1; + break; + } + sp->lno = ++m.lno; + } + + if (IN_VI_MODE(sp)) { + sp->tiqp = sv_tiqp; + text_lfree(&tiq); + + /* Reset the terminal state. */ + if (F_ISSET(sp->gp, G_STDIN_TTY)) { + if (SEX_NORAW(t)) + rval = 1; + F_SET(sp, S_REFRESH); + } + } + return (rval); +} diff --git a/usr.bin/vi/ex/ex_args.c b/usr.bin/vi/ex/ex_args.c new file mode 100644 index 0000000..9213e84 --- /dev/null +++ b/usr.bin/vi/ex/ex_args.c @@ -0,0 +1,263 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_args.c 8.27 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_next -- :next [+cmd] [files] + * Edit the next file, optionally setting the list of files. + * + * !!! + * The :next command behaved differently from the :rewind command in + * historic vi. See nvi/docs/autowrite for details, but the basic + * idea was that it ignored the force flag if the autowrite flag was + * set. This implementation handles them all identically. + */ +int +ex_next(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + ARGS **argv, **pc; + FREF *frp; + int noargs; + char **ap; + + if (file_m1(sp, ep, F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE)) + return (1); + + /* + * If the first argument is a plus sign, '+', it's an initial + * ex command. + */ + argv = cmdp->argv; + if (cmdp->argc && argv[0]->bp[0] == '+') { + --cmdp->argc; + pc = argv++; + } else + pc = NULL; + + /* Any other arguments are a replacement file list. */ + if (cmdp->argc) { + /* Free the current list. */ + if (!F_ISSET(sp, S_ARGNOFREE) && sp->argv != NULL) { + for (ap = sp->argv; *ap != NULL; ++ap) + free(*ap); + free(sp->argv); + } + F_CLR(sp, S_ARGNOFREE | S_ARGRECOVER); + sp->cargv = NULL; + + /* Create a new list. */ + CALLOC_RET(sp, + sp->argv, char **, cmdp->argc + 1, sizeof(char *)); + for (ap = sp->argv, + argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) + if ((*ap = + v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL) + return (1); + *ap = NULL; + + /* Switch to the first one. */ + sp->cargv = sp->argv; + if ((frp = file_add(sp, *sp->cargv)) == NULL) + return (1); + noargs = 0; + } else { + if (sp->cargv == NULL || sp->cargv[1] == NULL) { + msgq(sp, M_ERR, "No more files to edit"); + return (1); + } + if ((frp = file_add(sp, sp->cargv[1])) == NULL) + return (1); + if (F_ISSET(sp, S_ARGRECOVER)) + F_SET(frp, FR_RECOVER); + noargs = 1; + } + + if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE))) + return (1); + if (noargs) + ++sp->cargv; + + /* Push the initial command onto the stack. */ + if (pc != NULL) + if (IN_EX_MODE(sp)) + (void)term_push(sp, pc[0]->bp, pc[0]->len, 0); + else if (IN_VI_MODE(sp)) { + (void)term_push(sp, "\n", 1, 0); + (void)term_push(sp, pc[0]->bp, pc[0]->len, 0); + (void)term_push(sp, ":", 1, 0); + (void)file_lline(sp, sp->ep, &sp->frp->lno); + F_SET(sp->frp, FR_CURSORSET); + } + + F_SET(sp, S_FSWITCH); + return (0); +} + +/* + * ex_prev -- :prev + * Edit the previous file. + */ +int +ex_prev(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + FREF *frp; + + if (file_m1(sp, ep, F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE)) + return (1); + + if (sp->cargv == sp->argv) { + msgq(sp, M_ERR, "No previous files to edit"); + return (1); + } + if ((frp = file_add(sp, sp->cargv[-1])) == NULL) + return (1); + + if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE))) + return (1); + + --sp->cargv; + F_SET(sp, S_FSWITCH); + return (0); +} + +/* + * ex_rew -- :rew + * Re-edit the list of files. + */ +int +ex_rew(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + FREF *frp; + + /* + * !!! + * Historic practice -- you can rewind to the current file. + */ + if (sp->argv == NULL) { + msgq(sp, M_ERR, "No previous files to rewind"); + return (1); + } + + if (file_m1(sp, ep, F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE)) + return (1); + + /* + * !!! + * Historic practice, start at the beginning of the file. + */ + for (frp = sp->frefq.cqh_first; + frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next) + F_CLR(frp, FR_CURSORSET | FR_FNONBLANK); + + /* Switch to the first one. */ + sp->cargv = sp->argv; + if ((frp = file_add(sp, *sp->cargv)) == NULL) + return (1); + if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE))) + return (1); + + F_SET(sp, S_FSWITCH); + return (0); +} + +/* + * ex_args -- :args + * Display the list of files. + */ +int +ex_args(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + int cnt, col, len, sep; + char **ap; + + if (sp->argv == NULL) { + (void)ex_printf(EXCOOKIE, "No file list to display.\n"); + return (0); + } + + col = len = sep = 0; + for (cnt = 1, ap = sp->argv; *ap != NULL; ++ap) { + col += len = strlen(*ap) + sep + (ap == sp->cargv ? 2 : 0); + if (col >= sp->cols - 1) { + col = len; + sep = 0; + (void)ex_printf(EXCOOKIE, "\n"); + } else if (cnt != 1) { + sep = 1; + (void)ex_printf(EXCOOKIE, " "); + } + ++cnt; + + if (ap == sp->cargv) + (void)ex_printf(EXCOOKIE, "[%s]", *ap); + else + (void)ex_printf(EXCOOKIE, "%s", *ap); + } + (void)ex_printf(EXCOOKIE, "\n"); + return (0); +} diff --git a/usr.bin/vi/ex/ex_argv.c b/usr.bin/vi/ex/ex_argv.c new file mode 100644 index 0000000..f93aa76 --- /dev/null +++ b/usr.bin/vi/ex/ex_argv.c @@ -0,0 +1,609 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_argv.c 8.36 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +static int argv_alloc __P((SCR *, size_t)); +static int argv_fexp __P((SCR *, EXCMDARG *, + char *, size_t, char *, size_t *, char **, size_t *, int)); +static int argv_sexp __P((SCR *, char **, size_t *, size_t *)); + +/* + * argv_init -- + * Build a prototype arguments list. + */ +int +argv_init(sp, ep, excp) + SCR *sp; + EXF *ep; + EXCMDARG *excp; +{ + EX_PRIVATE *exp; + + exp = EXP(sp); + exp->argsoff = 0; + argv_alloc(sp, 1); + + excp->argv = exp->args; + excp->argc = exp->argsoff; + return (0); +} + +/* + * argv_exp0 -- + * Append a string to the argument list. + */ +int +argv_exp0(sp, ep, excp, cmd, cmdlen) + SCR *sp; + EXF *ep; + EXCMDARG *excp; + char *cmd; + size_t cmdlen; +{ + EX_PRIVATE *exp; + + exp = EXP(sp); + argv_alloc(sp, cmdlen); + memmove(exp->args[exp->argsoff]->bp, cmd, cmdlen); + exp->args[exp->argsoff]->bp[cmdlen] = '\0'; + exp->args[exp->argsoff]->len = cmdlen; + ++exp->argsoff; + excp->argv = exp->args; + excp->argc = exp->argsoff; + return (0); +} + +/* + * argv_exp1 -- + * Do file name expansion on a string, and append it to the + * argument list. + */ +int +argv_exp1(sp, ep, excp, cmd, cmdlen, is_bang) + SCR *sp; + EXF *ep; + EXCMDARG *excp; + char *cmd; + size_t cmdlen; + int is_bang; +{ + EX_PRIVATE *exp; + size_t blen, len; + char *bp, *p, *t; + + GET_SPACE_RET(sp, bp, blen, 512); + + len = 0; + exp = EXP(sp); + if (argv_fexp(sp, excp, cmd, cmdlen, bp, &len, &bp, &blen, is_bang)) { + FREE_SPACE(sp, bp, blen); + return (1); + } + + /* If it's empty, we're done. */ + if (len != 0) { + for (p = bp, t = bp + len; p < t; ++p) + if (!isblank(*p)) + break; + if (p == t) + goto ret; + } else + goto ret; + + (void)argv_exp0(sp, ep, excp, bp, len); + +ret: FREE_SPACE(sp, bp, blen); + return (0); +} + +/* + * argv_exp2 -- + * Do file name and shell expansion on a string, and append it to + * the argument list. + */ +int +argv_exp2(sp, ep, excp, cmd, cmdlen, is_bang) + SCR *sp; + EXF *ep; + EXCMDARG *excp; + char *cmd; + size_t cmdlen; + int is_bang; +{ + size_t blen, len, n; + int rval; + char *bp, *mp, *p; + + GET_SPACE_RET(sp, bp, blen, 512); + +#define SHELLECHO "echo " +#define SHELLOFFSET (sizeof(SHELLECHO) - 1) + memmove(bp, SHELLECHO, SHELLOFFSET); + p = bp + SHELLOFFSET; + len = SHELLOFFSET; + +#if defined(DEBUG) && 0 + TRACE(sp, "file_argv: {%.*s}\n", (int)cmdlen, cmd); +#endif + + if (argv_fexp(sp, excp, cmd, cmdlen, p, &len, &bp, &blen, is_bang)) { + rval = 1; + goto err; + } + +#if defined(DEBUG) && 0 + TRACE(sp, "before shell: %d: {%s}\n", len, bp); +#endif + + /* + * Do shell word expansion -- it's very, very hard to figure out what + * magic characters the user's shell expects. Historically, it was a + * union of v7 shell and csh meta characters. We match that practice + * by default, so ":read \%" tries to read a file named '%'. It would + * make more sense to pass any special characters through the shell, + * but then, if your shell was csh, the above example will behave + * differently in nvi than in vi. If you want to get other characters + * passed through to your shell, change the "meta" option. + * + * To avoid a function call per character, we do a first pass through + * the meta characters looking for characters that aren't expected + * to be there. + */ + for (p = mp = O_STR(sp, O_META); *p != '\0'; ++p) + if (isblank(*p) || isalnum(*p)) + break; + if (*p != '\0') { + for (p = bp, n = len; n > 0; --n, ++p) + if (strchr(mp, *p) != NULL) + break; + } else + for (p = bp, n = len; n > 0; --n, ++p) + if (!isblank(*p) && + !isalnum(*p) && strchr(mp, *p) != NULL) + break; + if (n > 0) { + if (argv_sexp(sp, &bp, &blen, &len)) { + rval = 1; + goto err; + } + p = bp; + } else { + p = bp + SHELLOFFSET; + len -= SHELLOFFSET; + } + +#if defined(DEBUG) && 0 + TRACE(sp, "after shell: %d: {%s}\n", len, bp); +#endif + + rval = argv_exp3(sp, ep, excp, p, len); + +err: FREE_SPACE(sp, bp, blen); + return (rval); +} + +/* + * argv_exp3 -- + * Take a string and break it up into an argv, which is appended + * to the argument list. + */ +int +argv_exp3(sp, ep, excp, cmd, cmdlen) + SCR *sp; + EXF *ep; + EXCMDARG *excp; + char *cmd; + size_t cmdlen; +{ + EX_PRIVATE *exp; + size_t len; + int ch, off; + char *ap, *p; + + for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) { + /* Skip any leading whitespace. */ + for (; cmdlen > 0; --cmdlen, ++cmd) { + ch = *cmd; + if (!isblank(ch)) + break; + } + if (cmdlen == 0) + break; + + /* + * Determine the length of this whitespace delimited + * argument. + * + * QUOTING NOTE: + * + * Skip any character preceded by the user's quoting + * character. + */ + for (ap = cmd, len = 0; cmdlen > 0; ++cmd, --cmdlen, ++len) { + ch = *cmd; + if (IS_ESCAPE(sp, ch) && cmdlen > 1) { + ++cmd; + --cmdlen; + } else if (isblank(ch)) + break; + } + + /* + * Copy the argument into place. + * + * QUOTING NOTE: + * + * Lose quote chars. + */ + argv_alloc(sp, len); + off = exp->argsoff; + exp->args[off]->len = len; + for (p = exp->args[off]->bp; len > 0; --len, *p++ = *ap++) + if (IS_ESCAPE(sp, *ap)) + ++ap; + *p = '\0'; + } + excp->argv = exp->args; + excp->argc = exp->argsoff; + +#if defined(DEBUG) && 0 + for (cnt = 0; cnt < exp->argsoff; ++cnt) + TRACE(sp, "arg %d: {%s}\n", cnt, exp->argv[cnt]); +#endif + return (0); +} + +/* + * argv_fexp -- + * Do file name and bang command expansion. + */ +static int +argv_fexp(sp, excp, cmd, cmdlen, p, lenp, bpp, blenp, is_bang) + SCR *sp; + EXCMDARG *excp; + char *cmd, *p, **bpp; + size_t cmdlen, *lenp, *blenp; + int is_bang; +{ + EX_PRIVATE *exp; + char *bp, *t; + size_t blen, len, tlen; + + /* Replace file name characters. */ + for (bp = *bpp, blen = *blenp, len = *lenp; cmdlen > 0; --cmdlen, ++cmd) + switch (*cmd) { + case '!': + if (!is_bang) + goto ins_ch; + exp = EXP(sp); + if (exp->lastbcomm == NULL) { + msgq(sp, M_ERR, + "No previous command to replace \"!\""); + return (1); + } + len += tlen = strlen(exp->lastbcomm); + ADD_SPACE_RET(sp, bp, blen, len); + memmove(p, exp->lastbcomm, tlen); + p += tlen; + F_SET(excp, E_MODIFY); + break; + case '%': + if ((t = sp->frp->name) == NULL) { + msgq(sp, M_ERR, + "No filename to substitute for %%"); + return (1); + } + tlen = strlen(t); + len += tlen; + ADD_SPACE_RET(sp, bp, blen, len); + memmove(p, t, tlen); + p += tlen; + F_SET(excp, E_MODIFY); + break; + case '#': + if ((t = sp->alt_name) == NULL) { + msgq(sp, M_ERR, + "No filename to substitute for #"); + return (1); + } + len += tlen = strlen(t); + ADD_SPACE_RET(sp, bp, blen, len); + memmove(p, t, tlen); + p += tlen; + F_SET(excp, E_MODIFY); + break; + case '\\': + /* + * QUOTING NOTE: + * + * Strip any backslashes that protected the file + * expansion characters. + */ + if (cmdlen > 1 && (cmd[1] == '%' || cmd[1] == '#')) { + ++cmd; + --cmdlen; + } + /* FALLTHROUGH */ + default: +ins_ch: ++len; + ADD_SPACE_RET(sp, bp, blen, len); + *p++ = *cmd; + } + + /* Nul termination. */ + ++len; + ADD_SPACE_RET(sp, bp, blen, len); + *p = '\0'; + + /* Return the new string length, buffer, buffer length. */ + *lenp = len - 1; + *bpp = bp; + *blenp = blen; + return (0); +} + +/* + * argv_alloc -- + * Make more space for arguments. + */ +static int +argv_alloc(sp, len) + SCR *sp; + size_t len; +{ + ARGS *ap; + EX_PRIVATE *exp; + int cnt, off; + + /* + * Allocate room for another argument, always leaving + * enough room for an ARGS structure with a length of 0. + */ +#define INCREMENT 20 + exp = EXP(sp); + off = exp->argsoff; + if (exp->argscnt == 0 || off + 2 >= exp->argscnt - 1) { + cnt = exp->argscnt + INCREMENT; + REALLOC(sp, exp->args, ARGS **, cnt * sizeof(ARGS *)); + if (exp->args == NULL) { + (void)argv_free(sp); + goto mem; + } + memset(&exp->args[off], 0, INCREMENT * sizeof(ARGS *)); + exp->argscnt = cnt; + } + + /* First argument. */ + if (exp->args[off] == NULL) { + CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS)); + if (exp->args[off] == NULL) + goto mem; + } + + /* First argument buffer. */ + ap = exp->args[off]; + ap->len = 0; + if (ap->blen < len + 1) { + ap->blen = len + 1; + REALLOC(sp, ap->bp, CHAR_T *, ap->blen * sizeof(CHAR_T)); + if (ap->bp == NULL) { + ap->bp = NULL; + ap->blen = 0; + F_CLR(ap, A_ALLOCATED); +mem: msgq(sp, M_SYSERR, NULL); + return (1); + } + F_SET(ap, A_ALLOCATED); + } + + /* Second argument. */ + if (exp->args[++off] == NULL) { + CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS)); + if (exp->args[off] == NULL) + goto mem; + } + /* 0 length serves as end-of-argument marker. */ + exp->args[off]->len = 0; + return (0); +} + +/* + * argv_free -- + * Free up argument structures. + */ +int +argv_free(sp) + SCR *sp; +{ + EX_PRIVATE *exp; + int off; + + exp = EXP(sp); + if (exp->args != NULL) { + for (off = 0; off < exp->argscnt; ++off) { + if (exp->args[off] == NULL) + continue; + if (F_ISSET(exp->args[off], A_ALLOCATED)) + free(exp->args[off]->bp); + FREE(exp->args[off], sizeof(ARGS)); + } + FREE(exp->args, exp->argscnt * sizeof(ARGS *)); + } + exp->args = NULL; + exp->argscnt = 0; + exp->argsoff = 0; + return (0); +} + +/* + * argv_sexp -- + * Fork a shell, pipe a command through it, and read the output into + * a buffer. + */ +static int +argv_sexp(sp, bpp, blenp, lenp) + SCR *sp; + char **bpp; + size_t *blenp, *lenp; +{ + FILE *ifp; + pid_t pid; + size_t blen, len; + int ch, rval, output[2]; + char *bp, *p, *sh, *sh_path; + + bp = *bpp; + blen = *blenp; + + sh_path = O_STR(sp, O_SHELL); + if ((sh = strrchr(sh_path, '/')) == NULL) + sh = sh_path; + else + ++sh; + + /* + * There are two different processes running through this code. + * They are named the utility and the parent. The utility reads + * from standard input and writes to the parent. The parent reads + * from the utility and writes into the buffer. The parent reads + * from output[0], and the utility writes to output[1]. + */ + if (pipe(output) < 0) { + msgq(sp, M_SYSERR, "pipe"); + return (1); + } + if ((ifp = fdopen(output[0], "r")) == NULL) { + msgq(sp, M_SYSERR, "fdopen"); + goto err; + } + + /* + * Do the minimal amount of work possible, the shell is going + * to run briefly and then exit. Hopefully. + */ + SIGBLOCK(sp->gp); + switch (pid = vfork()) { + case -1: /* Error. */ + SIGUNBLOCK(sp->gp); + + msgq(sp, M_SYSERR, "vfork"); +err: (void)close(output[0]); + (void)close(output[1]); + return (1); + case 0: /* Utility. */ + /* The utility has default signal behavior. */ + sig_end(); + + /* Redirect stdout/stderr to the write end of the pipe. */ + (void)dup2(output[1], STDOUT_FILENO); + (void)dup2(output[1], STDERR_FILENO); + + /* Close the utility's file descriptors. */ + (void)close(output[0]); + (void)close(output[1]); + + /* Assumes that all shells have -c. */ + execl(sh_path, sh, "-c", bp, NULL); + msgq(sp, M_ERR, + "Error: execl: %s: %s", sh_path, strerror(errno)); + _exit(127); + default: /* Parent. */ + SIGUNBLOCK(sp->gp); + + /* Close the pipe end the parent won't use. */ + (void)close(output[1]); + break; + } + + rval = 0; + + /* + * Copy process output into a buffer. + * + * !!! + * Historic vi apparently discarded leading \n and \r's from + * the shell output stream. We don't on the grounds that any + * shell that does that is broken. + */ + for (p = bp, len = 0, ch = EOF; + (ch = getc(ifp)) != EOF; *p++ = ch, --blen, ++len) + if (blen < 5) { + ADD_SPACE_GOTO(sp, bp, blen, *blenp * 2); + p = bp + len; + blen = *blenp - len; + } + + /* Delete the final newline, nul terminate the string. */ + if (p > bp && (p[-1] == '\n' || p[-1] == '\r')) { + --len; + *--p = '\0'; + } else + *p = '\0'; + *lenp = len; + + if (ferror(ifp)) { + msgq(sp, M_ERR, "I/O error: %s", sh); +binc_err: rval = 1; + } + (void)fclose(ifp); + + *bpp = bp; /* *blenp is already updated. */ + + /* Wait for the process. */ + return (proc_wait(sp, (long)pid, sh, 0) || rval); +} diff --git a/usr.bin/vi/ex/ex_at.c b/usr.bin/vi/ex/ex_at.c new file mode 100644 index 0000000..fc5922f --- /dev/null +++ b/usr.bin/vi/ex/ex_at.c @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_at.c 8.25 (Berkeley) 8/1/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_at -- :@[@ | buffer] + * :*[* | buffer] + * + * Execute the contents of the buffer. + */ +int +ex_at(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + CB *cbp; + EX_PRIVATE *exp; + TEXT *tp; + int name; + + exp = EXP(sp); + + /* + * !!! + * Historically, [@*]<carriage-return> and [@*][@*] executed the most + * recently executed buffer in ex mode. In vi mode, only @@ repeated + * the last buffer. We change historic practice and make @* work from + * vi mode as well, it's simpler and more consistent. + */ + name = F_ISSET(cmdp, E_BUFFER) ? cmdp->buffer : '@'; + if (name == '@' || name == '*') { + if (!exp->at_lbuf_set) { + msgq(sp, M_ERR, "No previous buffer to execute"); + return (1); + } + name = exp->at_lbuf; + } + + CBNAME(sp, cbp, name); + if (cbp == NULL) { + msgq(sp, M_ERR, "Buffer %s is empty", KEY_NAME(sp, name)); + return (1); + } + + /* Save for reuse. */ + exp->at_lbuf = name; + exp->at_lbuf_set = 1; + + /* + * !!! + * Historic practice is that if the buffer was cut in line mode, + * <newlines> were appended to each line as it was pushed onto + * the stack. If the buffer was cut in character mode, <newlines> + * were appended to all lines but the last one. + */ + for (tp = cbp->textq.cqh_last; + tp != (void *)&cbp->textq; tp = tp->q.cqe_prev) + if ((F_ISSET(cbp, CB_LMODE) || + tp->q.cqe_next != (void *)&cbp->textq) && + term_push(sp, "\n", 1, 0) || + term_push(sp, tp->lb, tp->len, 0)) + return (1); + return (0); +} diff --git a/usr.bin/vi/ex/ex_bang.c b/usr.bin/vi/ex/ex_bang.c new file mode 100644 index 0000000..70bbb57 --- /dev/null +++ b/usr.bin/vi/ex/ex_bang.c @@ -0,0 +1,242 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_bang.c 8.33 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "../sex/sex_screen.h" + +/* + * ex_bang -- :[line [,line]] ! command + * + * Pass the rest of the line after the ! character to the program named by + * the O_SHELL option. + * + * Historical vi did NOT do shell expansion on the arguments before passing + * them, only file name expansion. This means that the O_SHELL program got + * "$t" as an argument if that is what the user entered. Also, there's a + * special expansion done for the bang command. Any exclamation points in + * the user's argument are replaced by the last, expanded ! command. + * + * There's some fairly amazing slop in this routine to make the different + * ways of getting here display the right things. It took a long time to + * get it right (wrong?), so be careful. + */ +int +ex_bang(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + enum filtertype ftype; + ARGS *ap; + EX_PRIVATE *exp; + MARK rm; + recno_t lno; + size_t blen; + int rval; + char *bp, *msg; + + ap = cmdp->argv[0]; + if (ap->len == 0) { + msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); + } + + /* Set the last bang command. */ + exp = EXP(sp); + if (exp->lastbcomm != NULL) + free(exp->lastbcomm); + if ((exp->lastbcomm = strdup(ap->bp)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + /* + * If the command was modified by the expansion, we redisplay it. + * Redisplaying it in vi mode is tricky, and handled separately + * in each case below. If we're in ex mode, it's easy, so we just + * do it here. + */ + bp = NULL; + if (F_ISSET(cmdp, E_MODIFY) && !F_ISSET(sp, S_EXSILENT)) { + if (IN_EX_MODE(sp)) { + (void)ex_printf(EXCOOKIE, "!%s\n", ap->bp); + (void)ex_fflush(EXCOOKIE); + } + /* + * Vi: Display the command if modified. Historic vi displayed + * the command if it was modified due to file name and/or bang + * expansion. If piping lines, it was immediately overwritten + * by any error or line change reporting. We don't the user to + * have to page through the responses, so we only post it until + * it's erased by something else. Otherwise, pass it on to the + * ex_exec_proc routine to display after the screen has been + * cleaned up. + */ + if (IN_VI_MODE(sp)) { + GET_SPACE_RET(sp, bp, blen, ap->len + 3); + bp[0] = '!'; + memmove(bp + 1, ap->bp, ap->len); + bp[ap->len + 1] = '\n'; + bp[ap->len + 2] = '\0'; + } + } + + /* + * If addresses were specified, pipe lines from the file through the + * command. + * + * Historically, vi lines were replaced by both the stdout and stderr + * lines of the command, but ex by only the stdout lines. This makes + * no sense to me, so nvi makes it consistent for both, and matches + * vi's historic behavior. + */ + if (cmdp->addrcnt != 0) { + /* Autoprint is set historically, even if the command fails. */ + F_SET(exp, EX_AUTOPRINT); + + /* Vi gets a busy message. */ + if (bp != NULL) + (void)sp->s_busy(sp, bp); + + /* + * !!! + * Historical vi permitted "!!" in an empty file. When it + * happens, we get called with two addresses of 1,1 and a + * bad attitude. The simple solution is to turn it into a + * FILTER_READ operation, but that means that we don't put + * an empty line into the default cut buffer as did historic + * vi. Tough. + */ + ftype = FILTER; + if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) { + cmdp->addr1.lno = cmdp->addr2.lno = 0; + ftype = FILTER_READ; + } + } + rval = filtercmd(sp, ep, + &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype); + + /* + * If in vi mode, move to the first nonblank. + * + * !!! + * Historic vi wasn't consistent in this area -- if you used + * a forward motion it moved to the first nonblank, but if you + * did a backward motion it didn't. And, if you followed a + * backward motion with a forward motion, it wouldn't move to + * the nonblank for either. Going to the nonblank generally + * seems more useful, so we do it. + */ + if (rval == 0) { + sp->lno = rm.lno; + if (IN_VI_MODE(sp)) { + sp->cno = 0; + (void)nonblank(sp, ep, sp->lno, &sp->cno); + } + } + goto ret2; + } + + /* + * If no addresses were specified, run the command. If the file + * has been modified and autowrite is set, write the file back. + * If the file has been modified, autowrite is not set and the + * warn option is set, tell the user about the file. + */ + msg = NULL; + if (F_ISSET(ep, F_MODIFIED)) + if (O_ISSET(sp, O_AUTOWRITE)) { + if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL)) { + rval = 1; + goto ret1; + } + } else if (O_ISSET(sp, O_WARN) && !F_ISSET(sp, S_EXSILENT)) + msg = "File modified since last write.\n"; + + /* Run the command. */ + rval = ex_exec_proc(sp, ap->bp, bp, msg); + + /* Vi requires user permission to continue. */ + if (IN_VI_MODE(sp)) + F_SET(sp, S_CONTINUE); + +ret2: if (IN_EX_MODE(sp)) { + /* + * Put ex error messages out so they aren't confused with + * the autoprint output. + */ + if (rval) + (void)sex_refresh(sp, sp->ep); + + /* Ex terminates with a bang, even if the command fails. */ + if (!F_ISSET(sp, S_EXSILENT)) + (void)write(STDOUT_FILENO, "!\n", 2); + } + + /* Free the extra space. */ +ret1: if (bp != NULL) + FREE_SPACE(sp, bp, blen); + + /* + * XXX + * The ! commands never return an error, so that autoprint always + * happens in the ex parser. + */ + return (0); +} diff --git a/usr.bin/vi/ex/ex_cd.c b/usr.bin/vi/ex/ex_cd.c new file mode 100644 index 0000000..3732f7b --- /dev/null +++ b/usr.bin/vi/ex/ex_cd.c @@ -0,0 +1,223 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_cd.c 8.16 (Berkeley) 8/8/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_cd -- :cd[!] [directory] + * Change directories. + */ +int +ex_cd(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + struct passwd *pw; + ARGS *ap; + CDPATH *cdp; + char *dir; /* XXX END OF THE STACK, DON'T TRUST GETCWD. */ + char buf[MAXPATHLEN * 2]; + + /* + * !!! + * Historic practice is that the cd isn't attempted if the file has + * been modified, unless its name begins with a leading '/' or the + * force flag is set. + */ + if (F_ISSET(ep, F_MODIFIED) && + !F_ISSET(cmdp, E_FORCE) && sp->frp->name[0] != '/') { + msgq(sp, M_ERR, + "File modified since last complete write; write or use ! to override"); + return (1); + } + + switch (cmdp->argc) { + case 0: + /* If no argument, change to the user's home directory. */ + if ((dir = getenv("HOME")) == NULL) { + if ((pw = getpwuid(getuid())) == NULL || + pw->pw_dir == NULL || pw->pw_dir[0] == '\0') { + msgq(sp, M_ERR, + "Unable to find home directory location"); + return (1); + } + dir = pw->pw_dir; + } + break; + case 1: + dir = cmdp->argv[0]->bp; + break; + default: + abort(); + } + + /* Try the current directory first. */ + if (!chdir(dir)) + goto ret; + + /* + * If moving to the user's home directory, or, the path begins with + * "/", "./" or "../", it's the only place we try. + */ + if (cmdp->argc == 0 || + (ap = cmdp->argv[0])->bp[0] == '/' || + ap->len == 1 && ap->bp[0] == '.' || + ap->len >= 2 && ap->bp[0] == '.' && ap->bp[1] == '.' && + (ap->bp[2] == '/' || ap->bp[2] == '\0')) + goto err; + + /* If the user has a CDPATH variable, try its elements. */ + for (cdp = EXP(sp)->cdq.tqh_first; cdp != NULL; cdp = cdp->q.tqe_next) { + (void)snprintf(buf, sizeof(buf), "%s/%s", cdp->path, dir); + if (!chdir(buf)) { +ret: if (getcwd(buf, sizeof(buf)) != NULL) + msgq(sp, M_INFO, "New directory: %s", buf); + return (0); + } + } +err: msgq(sp, M_SYSERR, "%s", dir); + return (1); +} + +#define FREE_CDPATH(cdp) { \ + TAILQ_REMOVE(&exp->cdq, (cdp), q); \ + free((cdp)->path); \ + FREE((cdp), sizeof(CDPATH)); \ +} +/* + * ex_cdalloc -- + * Create a new list of cd paths. + */ +int +ex_cdalloc(sp, str) + SCR *sp; + char *str; +{ + EX_PRIVATE *exp; + CDPATH *cdp; + size_t len; + int founddot; + char *p, *t; + + /* Free current queue. */ + exp = EXP(sp); + while ((cdp = exp->cdq.tqh_first) != NULL) + FREE_CDPATH(cdp); + + /* + * Create new queue. The CDPATH environmental variable (and the + * user's manual entry) are delimited by colon characters. + */ + for (p = t = str, founddot = 0;; ++p) { + if (*p == '\0' || *p == ':') { + /* + * Empty strings specify ".". The only way to get an + * empty string is a leading colon, colons in a row, + * or a trailing colon. Or, to put it the other way, + * if the the length is zero, then it's either ":XXX", + * "XXX::XXXX" , "XXX:", or "", and the only failure + * mode is the last one. Note, the string ":" gives + * us two entries of '.', so we only include one of + * them. + */ + if ((len = p - t) == 0) { + if (p == str && *p == '\0') + break; + if (founddot) { + if (*p == '\0') + break; + continue; + } + len = 1; + t = "."; + founddot = 1; + } + MALLOC_RET(sp, cdp, CDPATH *, sizeof(CDPATH)); + MALLOC(sp, cdp->path, char *, len + 1); + if (cdp->path == NULL) { + free(cdp); + return (1); + } + memmove(cdp->path, t, len); + cdp->path[len] = '\0'; + TAILQ_INSERT_TAIL(&exp->cdq, cdp, q); + t = p + 1; + } + if (*p == '\0') + break; + } + return (0); +} + /* Free previous queue. */ +/* + * ex_cdfree -- + * Free the cd path list. + */ +int +ex_cdfree(sp) + SCR *sp; +{ + EX_PRIVATE *exp; + CDPATH *cdp; + + /* Free up cd path information. */ + exp = EXP(sp); + while ((cdp = exp->cdq.tqh_first) != NULL) + FREE_CDPATH(cdp); + return (0); +} diff --git a/usr.bin/vi/ex/ex_delete.c b/usr.bin/vi/ex/ex_delete.c new file mode 100644 index 0000000..08c4250 --- /dev/null +++ b/usr.bin/vi/ex/ex_delete.c @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_delete.c 8.12 (Berkeley) 8/5/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_delete: [line [,line]] d[elete] [buffer] [count] [flags] + * + * Delete lines from the file. + */ +int +ex_delete(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + recno_t lno; + + /* + * !!! + * Historically, lines deleted in ex were not placed in the numeric + * buffers. We follow historic practice so that we don't overwrite + * vi buffers accidentally. + */ + if (cut(sp, ep, + F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL, + &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)) + return (1); + + /* Delete the lines. */ + if (delete(sp, ep, &cmdp->addr1, &cmdp->addr2, 1)) + return (1); + + /* Set the cursor to the line after the last line deleted. */ + sp->lno = cmdp->addr1.lno; + + /* Or the last line in the file if deleted to the end of the file. */ + if (file_lline(sp, ep, &lno)) + return (1); + if (sp->lno > lno) + sp->lno = lno; + return (0); +} diff --git a/usr.bin/vi/ex/ex_digraph.c b/usr.bin/vi/ex/ex_digraph.c new file mode 100644 index 0000000..0739923 --- /dev/null +++ b/usr.bin/vi/ex/ex_digraph.c @@ -0,0 +1,324 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_digraph.c 8.6 (Berkeley) 3/25/94"; +#endif /* not lint */ + +#ifndef NO_DIGRAPH +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +static void do_digraph __P((SCR *, EXF *, int, u_char *)); + +/* This stuff is used to build the default digraphs table. */ +static u_char digtable[][4] = { +# ifdef CS_IBMPC + "C,\200", "u\"\1", "e'\2", "a^\3", + "a\"\4", "a`\5", "a@\6", "c,\7", + "e^\10", "e\"\211", "e`\12", "i\"\13", + "i^\14", "i`\15", "A\"\16", "A@\17", + "E'\20", "ae\21", "AE\22", "o^\23", + "o\"\24", "o`\25", "u^\26", "u`\27", + "y\"\30", "O\"\31", "U\"\32", "a'\240", + "i'!", "o'\"", "u'#", "n~$", + "N~%", "a-&", "o-'", "~?(", + "~!-", "\"<.", "\">/", +# ifdef CS_SPECIAL + "2/+", "4/,", "^+;", "^q<", + "^c=", "^r>", "^t?", "pp]", + "^^^", "oo_", "*a`", "*ba", + "*pc", "*Sd", "*se", "*uf", + "*tg", "*Ph", "*Ti", "*Oj", + "*dk", "*Hl", "*hm", "*En", + "*No", "eqp", "pmq", "ger", + "les", "*It", "*iu", "*/v", + "*=w", "sq{", "^n|", "^2}", + "^3~", "^_\377", +# endif /* CS_SPECIAL */ +# endif /* CS_IBMPC */ +# ifdef CS_LATIN1 + "~!!", "a-*", "\">+", "o-:", + "\"<>", "~??", + + "A`@", "A'A", "A^B", "A~C", + "A\"D", "A@E", "AEF", "C,G", + "E`H", "E'I", "E^J", "E\"K", + "I`L", "I'M", "I^N", "I\"O", + "-DP", "N~Q", "O`R", "O'S", + "O^T", "O~U", "O\"V", "O/X", + "U`Y", "U'Z", "U^[", "U\"\\", + "Y'_", + + "a``", "a'a", "a^b", "a~c", + "a\"d", "a@e", "aef", "c,g", + "e`h", "e'i", "e^j", "e\"k", + "i`l", "i'm", "i^n", "i\"o", + "-dp", "n~q", "o`r", "o's", + "o^t", "o~u", "o\"v", "o/x", + "u`y", "u'z", "u^{", "u\"|", + "y'~", +# endif /* CS_LATIN1 */ + "" +}; + +int +digraph_init(sp) + SCR *sp; +{ + int i; + + for (i = 0; *digtable[i]; i++) + do_digraph(sp, NULL, 0, digtable[i]); + do_digraph(sp, NULL, 0, NULL); + return (0); +} + +int +ex_digraph(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + do_digraph(sp, ep, F_ISSET(cmdp, E_FORCE), cmdp->argv[0]->bp); + return (0); +} + +static struct _DIG +{ + struct _DIG *next; + char key1; + char key2; + char dig; + char save; +} *digs; + +int +digraph(sp, key1, key2) + SCR *sp; + char key1; /* the underlying character */ + char key2; /* the second character */ +{ + int new_key; + register struct _DIG *dp; + + /* if digraphs are disabled, then just return the new char */ + if (O_ISSET(sp, O_DIGRAPH)) + { + return key2; + } + + /* remember the new key, so we can return it if this isn't a digraph */ + new_key = key2; + + /* sort key1 and key2, so that their original order won't matter */ + if (key1 > key2) + { + key2 = key1; + key1 = new_key; + } + + /* scan through the digraph chart */ + for (dp = digs; + dp && (dp->key1 != key1 || dp->key2 != key2); + dp = dp->next) + { + } + + /* if this combination isn't in there, just use the new key */ + if (!dp) + { + return new_key; + } + + /* else use the digraph key */ + return dp->dig; +} + +/* this function lists or defines digraphs */ +static void +do_digraph(sp, ep, bang, extra) + SCR *sp; + EXF *ep; + int bang; + u_char *extra; +{ + int dig; + register struct _DIG *dp; + struct _DIG *prev; + static int user_defined = 0; /* boolean: are all later digraphs user-defined? */ + char listbuf[8]; + + /* if "extra" is NULL, then we've reached the end of the built-ins */ + if (!extra) + { + user_defined = 1; + return; + } + + /* if no args, then display the existing digraphs */ + if (*extra < ' ') + { + listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' '; + listbuf[7] = '\0'; + for (dig = 0, dp = digs; dp; dp = dp->next) + { + if (dp->save || bang) + { + dig += 7; + if (dig >= sp->cno) + { + addch('\n'); + refresh(); + dig = 7; + } + listbuf[3] = dp->key1; + listbuf[4] = dp->key2; + listbuf[6] = dp->dig; + addstr(listbuf); + } + } + addch('\n'); + refresh(); + return; + } + + /* make sure we have at least two characters */ + if (!extra[1]) + { + msgq(sp, M_ERR, + "Digraphs must be composed of two characters"); + return; + } + + /* sort key1 and key2, so that their original order won't matter */ + if (extra[0] > extra[1]) + { + dig = extra[0]; + extra[0] = extra[1]; + extra[1] = dig; + } + + /* locate the new digraph character */ + for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++) + { + } + dig = extra[dig]; + if (!bang && dig) + { + dig |= 0x80; + } + + /* search for the digraph */ + for (prev = (struct _DIG *)0, dp = digs; + dp && (dp->key1 != extra[0] || dp->key2 != extra[1]); + prev = dp, dp = dp->next) + { + } + + /* deleting the digraph? */ + if (!dig) + { + if (!dp) + { +#ifndef CRUNCH + msgq(sp, M_ERR, + "%c%c not a digraph", extra[0], extra[1]); +#endif + return; + } + if (prev) + prev->next = dp->next; + else + digs = dp->next; + free(dp); + return; + } + + /* if necessary, create a new digraph struct for the new digraph */ + if (dig && !dp) + { + MALLOC(sp, dp, struct _DIG *, sizeof(struct _DIG)); + if (dp == NULL) + return; + if (prev) + prev->next = dp; + else + digs = dp; + dp->next = (struct _DIG *)0; + } + + /* assign it the new digraph value */ + dp->key1 = extra[0]; + dp->key2 = extra[1]; + dp->dig = dig; + dp->save = user_defined; +} + +void +digraph_save(sp, fd) + SCR *sp; + int fd; +{ + static char buf[] = "digraph! XX Y\n"; + register struct _DIG *dp; + + for (dp = digs; dp; dp = dp->next) + { + if (dp->save) + { + buf[9] = dp->key1; + buf[10] = dp->key2; + buf[12] = dp->dig; + write(fd, buf, (unsigned)14); + } + } +} +#endif diff --git a/usr.bin/vi/ex/ex_display.c b/usr.bin/vi/ex/ex_display.c new file mode 100644 index 0000000..139127e --- /dev/null +++ b/usr.bin/vi/ex/ex_display.c @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_display.c 8.21 (Berkeley) 8/3/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "tag.h" +#include "excmd.h" + +static int bdisplay __P((SCR *, EXF *)); +static void db __P((SCR *, CB *, CHAR_T *)); + +/* + * ex_display -- :display b[uffers] | s[creens] | t[ags] + * + * Display buffers, tags or screens. + */ +int +ex_display(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + switch (cmdp->argv[0]->bp[0]) { + case 'b': +#undef ARG +#define ARG "buffers" + if (cmdp->argv[0]->len >= sizeof(ARG) || + memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len)) + break; + return (bdisplay(sp, ep)); + case 's': +#undef ARG +#define ARG "screens" + if (cmdp->argv[0]->len >= sizeof(ARG) || + memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len)) + break; + return (ex_sdisplay(sp, ep)); + case 't': +#undef ARG +#define ARG "tags" + if (cmdp->argv[0]->len >= sizeof(ARG) || + memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len)) + break; + return (ex_tagdisplay(sp, ep)); + } + msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); +} + +/* + * bdisplay -- + * + * Display buffers. + */ +static int +bdisplay(sp, ep) + SCR *sp; + EXF *ep; +{ + CB *cbp; + + if (sp->gp->cutq.lh_first == NULL && sp->gp->dcbp == NULL) { + (void)ex_printf(EXCOOKIE, "No cut buffers to display.\n"); + return (0); + } + + /* Buffers can be infinitely long, make it interruptible. */ + F_SET(sp, S_INTERRUPTIBLE); + + /* Display regular cut buffers. */ + for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) { + if (isdigit(cbp->name)) + continue; + if (cbp->textq.cqh_first != (void *)&cbp->textq) + db(sp, cbp, NULL); + if (INTERRUPTED(sp)) + return (0); + } + /* Display numbered buffers. */ + for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) { + if (!isdigit(cbp->name)) + continue; + if (cbp->textq.cqh_first != (void *)&cbp->textq) + db(sp, cbp, NULL); + if (INTERRUPTED(sp)) + return (0); + } + /* Display default buffer. */ + if ((cbp = sp->gp->dcbp) != NULL) + db(sp, cbp, "default buffer"); + return (0); +} + +/* + * db -- + * Display a buffer. + */ +static void +db(sp, cbp, name) + SCR *sp; + CB *cbp; + CHAR_T *name; +{ + CHAR_T *p; + TEXT *tp; + size_t len; + + (void)ex_printf(EXCOOKIE, "********** %s%s\n", + name == NULL ? KEY_NAME(sp, cbp->name) : name, + F_ISSET(cbp, CB_LMODE) ? " (line mode)" : " (character mode)"); + for (tp = cbp->textq.cqh_first; + tp != (void *)&cbp->textq; tp = tp->q.cqe_next) { + for (len = tp->len, p = tp->lb; len--; ++p) { + (void)ex_printf(EXCOOKIE, "%s", KEY_NAME(sp, *p)); + if (INTERRUPTED(sp)) + return; + } + (void)ex_printf(EXCOOKIE, "\n"); + } +} diff --git a/usr.bin/vi/ex/ex_edit.c b/usr.bin/vi/ex/ex_edit.c new file mode 100644 index 0000000..bfe0a2a --- /dev/null +++ b/usr.bin/vi/ex/ex_edit.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_edit.c 8.18 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_edit -- :e[dit][!] [+cmd] [file] + * :vi[sual][!] [+cmd] [file] + * + * Edit a file; if none specified, re-edit the current file. The second + * form of the command can only be executed while in vi mode. See the + * hack in ex.c:ex_cmd(). + * + * !!! + * Historic vi didn't permit the '+' command form without specifying + * a file name as well. + */ +int +ex_edit(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + ARGS *ap; + FREF *frp; + + frp = sp->frp; + switch (cmdp->argc) { + case 0: + /* + * If the name has been changed, we edit that file, not the + * original name. If the user was editing a temporary file, + * create another one. The reason for this is that we do + * special exit processing of temporary files, and reusing + * them is tricky. + */ + if (F_ISSET(frp, FR_TMPFILE)) { + if ((frp = file_add(sp, NULL)) == NULL) + return (1); + } else { + if ((frp = file_add(sp, frp->name)) == NULL) + return (1); + set_alt_name(sp, sp->frp->name); + } + break; + case 1: + ap = cmdp->argv[0]; + if ((frp = file_add(sp, ap->bp)) == NULL) + return (1); + set_alt_name(sp, ap->bp); + break; + default: + abort(); + } + + /* + * Check for modifications. + * + * !!! + * Contrary to POSIX 1003.2-1992, autowrite did not affect :edit. + */ + if (file_m2(sp, ep, F_ISSET(cmdp, E_FORCE))) + return (1); + + /* Switch files. */ + if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE))) + return (1); + F_SET(sp, S_FSWITCH); + return (0); +} diff --git a/usr.bin/vi/ex/ex_equal.c b/usr.bin/vi/ex/ex_equal.c new file mode 100644 index 0000000..a80d723 --- /dev/null +++ b/usr.bin/vi/ex/ex_equal.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_equal.c 8.6 (Berkeley) 4/26/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_equal -- :address = + */ +int +ex_equal(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + recno_t lno; + + /* + * Print out the line number matching the specified address, + * or the number of the last line in the file if no address + * specified. + * + * !!! + * Historically, ":0=" displayed 0, and ":=" or ":1=" in an + * empty file displayed 1. Until somebody complains loudly, + * we're going to do it right. The tables in excmd.c permit + * lno to get away with any address from 0 to the end of the + * file, which, in an empty file, is 0. + */ + if (F_ISSET(cmdp, E_ADDRDEF)) { + if (file_lline(sp, ep, &lno)) + return (1); + } else + lno = cmdp->addr1.lno; + + (void)ex_printf(EXCOOKIE, "%ld\n", lno); + return (0); +} diff --git a/usr.bin/vi/ex/ex_exit.c b/usr.bin/vi/ex/ex_exit.c new file mode 100644 index 0000000..3f0a362 --- /dev/null +++ b/usr.bin/vi/ex/ex_exit.c @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_exit.c 8.13 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_quit -- :quit[!] + * Quit. + */ +int +ex_quit(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + int force; + + force = F_ISSET(cmdp, E_FORCE); + + /* Check for modifications. */ + if (file_m2(sp, ep, force)) + return (1); + + /* Check for more files to edit. */ + if (ex_ncheck(sp, force)) + return (1); + + F_SET(sp, force ? S_EXIT_FORCE : S_EXIT); + return (0); +} diff --git a/usr.bin/vi/ex/ex_file.c b/usr.bin/vi/ex/ex_file.c new file mode 100644 index 0000000..b2c68e7 --- /dev/null +++ b/usr.bin/vi/ex/ex_file.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_file.c 8.10 (Berkeley) 8/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_file -- :f[ile] [name] + * Change the file's name and display the status line. + */ +int +ex_file(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + CHAR_T *p; + FREF *frp; + + switch (cmdp->argc) { + case 0: + break; + case 1: + frp = sp->frp; + + /* Make sure can allocate enough space. */ + if ((p = v_strdup(sp, + cmdp->argv[0]->bp, cmdp->argv[0]->len)) == NULL) + return (1); + + /* If already have a file name, it becomes the alternate. */ + if (!F_ISSET(frp, FR_TMPFILE)) + set_alt_name(sp, frp->name); + + /* Free the previous name. */ + free(frp->name); + frp->name = p; + + /* + * The read-only bit follows the file name; clear it. + * The file has a real name, it's no longer a temporary. + */ + F_CLR(frp, FR_RDONLY | FR_TMPFILE); + + /* Have to force a write if the file exists, next time. */ + F_SET(frp, FR_NAMECHANGE); + break; + default: + abort(); + } + return (msg_status(sp, ep, sp->lno, 1)); +} diff --git a/usr.bin/vi/ex/ex_global.c b/usr.bin/vi/ex/ex_global.c new file mode 100644 index 0000000..624bf8e --- /dev/null +++ b/usr.bin/vi/ex/ex_global.c @@ -0,0 +1,400 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_global.c 8.41 (Berkeley) 8/9/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +enum which {GLOBAL, VGLOBAL}; + +static int global __P((SCR *, EXF *, EXCMDARG *, enum which)); + +/* + * ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands] + * Exec on lines matching a pattern. + */ +int +ex_global(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (global(sp, ep, + cmdp, F_ISSET(cmdp, E_FORCE) ? VGLOBAL : GLOBAL)); +} + +/* + * ex_vglobal -- [line [,line]] v[global] /pattern/ [commands] + * Exec on lines not matching a pattern. + */ +int +ex_vglobal(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (global(sp, ep, cmdp, VGLOBAL)); +} + +static int +global(sp, ep, cmdp, cmd) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; + enum which cmd; +{ + MARK abs; + RANGE *rp; + EX_PRIVATE *exp; + recno_t elno, lno; + regmatch_t match[1]; + regex_t *re, lre; + size_t clen, len; + int delim, eval, reflags, replaced, rval; + char *cb, *ptrn, *p, *t; + + /* + * Skip leading white space. Historic vi allowed any non- + * alphanumeric to serve as the global command delimiter. + */ + for (p = cmdp->argv[0]->bp; isblank(*p); ++p); + if (*p == '\0' || isalnum(*p)) { + msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); + } + delim = *p++; + + /* + * Get the pattern string, toss escaped characters. + * + * QUOTING NOTE: + * Only toss an escaped character if it escapes a delimiter. + */ + for (ptrn = t = p;;) { + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + /* + * !!! + * Nul terminate the pattern string -- it's passed + * to regcomp which doesn't understand anything else. + */ + *t = '\0'; + break; + } + if (p[0] == '\\' && p[1] == delim) + ++p; + *t++ = *p++; + } + + /* If the pattern string is empty, use the last one. */ + if (*ptrn == '\0') { + if (!F_ISSET(sp, S_SRE_SET)) { + msgq(sp, M_ERR, "No previous regular expression"); + return (1); + } + re = &sp->sre; + } else { + /* Set RE flags. */ + reflags = 0; + if (O_ISSET(sp, O_EXTENDED)) + reflags |= REG_EXTENDED; + if (O_ISSET(sp, O_IGNORECASE)) + reflags |= REG_ICASE; + + /* Convert vi-style RE's to POSIX 1003.2 RE's. */ + if (re_conv(sp, &ptrn, &replaced)) + return (1); + + /* Compile the RE. */ + re = &lre; + eval = regcomp(re, ptrn, reflags); + + /* Free up any allocated memory. */ + if (replaced) + FREE_SPACE(sp, ptrn, 0); + + if (eval) { + re_error(sp, eval, re); + return (1); + } + + /* + * Set saved RE. Historic practice is that + * globals set direction as well as the RE. + */ + sp->sre = lre; + sp->searchdir = FORWARD; + F_SET(sp, S_SRE_SET); + } + + /* + * Get a copy of the command string; the default command is print. + * Don't worry about a set of <blank>s with no command, that will + * default to print in the ex parser. + */ + if ((clen = strlen(p)) == 0) { + p = "p"; + clen = 1; + } + MALLOC_RET(sp, cb, char *, clen); + memmove(cb, p, clen); + + /* + * The global commands sets the substitute RE as well as + * the everything-else RE. + */ + sp->subre = sp->sre; + F_SET(sp, S_SUBRE_SET); + + /* Set the global flag. */ + F_SET(sp, S_GLOBAL); + + /* The global commands always set the previous context mark. */ + abs.lno = sp->lno; + abs.cno = sp->cno; + if (mark_set(sp, ep, ABSMARK1, &abs, 1)) + goto err; + + /* + * For each line... The semantics of global matching are that we first + * have to decide which lines are going to get passed to the command, + * and then pass them to the command, ignoring other changes. There's + * really no way to do this in a single pass, since arbitrary line + * creation, deletion and movement can be done in the ex command. For + * example, a good vi clone test is ":g/X/mo.-3", or "g/X/.,.+1d". + * What we do is create linked list of lines that are tracked through + * each ex command. There's a callback routine which the DB interface + * routines call when a line is created or deleted. This doesn't help + * the layering much. + */ + exp = EXP(sp); + for (rval = 0, lno = cmdp->addr1.lno, + elno = cmdp->addr2.lno; lno <= elno; ++lno) { + /* Someone's unhappy, time to stop. */ + if (INTERRUPTED(sp)) + goto interrupted; + + /* Get the line and search for a match. */ + if ((t = file_gline(sp, ep, lno, &len)) == NULL) { + GETLINE_ERR(sp, lno); + goto err; + } + match[0].rm_so = 0; + match[0].rm_eo = len; + switch(eval = regexec(re, t, 1, match, REG_STARTEND)) { + case 0: + if (cmd == VGLOBAL) + continue; + break; + case REG_NOMATCH: + if (cmd == GLOBAL) + continue; + break; + default: + re_error(sp, eval, re); + goto err; + } + + /* If follows the last entry, extend the last entry's range. */ + if ((rp = exp->rangeq.cqh_last) != (void *)&exp->rangeq && + rp->stop == lno - 1) { + ++rp->stop; + continue; + } + + /* Allocate a new range, and append it to the list. */ + CALLOC(sp, rp, RANGE *, 1, sizeof(RANGE)); + if (rp == NULL) + goto err; + rp->start = rp->stop = lno; + CIRCLEQ_INSERT_TAIL(&exp->rangeq, rp, q); + } + + exp = EXP(sp); + exp->range_lno = OOBLNO; + for (;;) { + /* + * Start at the beginning of the range each time, it may have + * been changed (or exhausted) if lines were inserted/deleted. + */ + if ((rp = exp->rangeq.cqh_first) == (void *)&exp->rangeq) + break; + if (rp->start > rp->stop) { + CIRCLEQ_REMOVE(&exp->rangeq, exp->rangeq.cqh_first, q); + free(rp); + continue; + } + + /* + * Execute the command, setting the cursor to the line so that + * relative addressing works. This means that the cursor moves + * to the last line sent to the command, by default, even if + * the command fails. + */ + exp->range_lno = sp->lno = rp->start++; + if (ex_cmd(sp, ep, cb, clen, 0)) + goto err; + + /* Someone's unhappy, time to stop. */ + if (INTERRUPTED(sp)) { +interrupted: msgq(sp, M_INFO, "Interrupted"); + break; + } + } + + /* Set the cursor to the new value, making sure it exists. */ + if (exp->range_lno != OOBLNO) { + if (file_lline(sp, ep, &lno)) + return (1); + sp->lno = + lno < exp->range_lno ? (lno ? lno : 1) : exp->range_lno; + } + if (0) { +err: rval = 1; + } + + /* Command we ran may have set the autoprint flag, clear it. */ + F_CLR(exp, EX_AUTOPRINT); + + /* Clear the global flag. */ + F_CLR(sp, S_GLOBAL); + + /* Free any remaining ranges and the command buffer. */ + while ((rp = exp->rangeq.cqh_first) != (void *)&exp->rangeq) { + CIRCLEQ_REMOVE(&exp->rangeq, exp->rangeq.cqh_first, q); + free(rp); + } + free(cb); + return (rval); +} + +/* + * global_insdel -- + * Update the ranges based on an insertion or deletion. + */ +void +global_insdel(sp, ep, op, lno) + SCR *sp; + EXF *ep; + enum operation op; + recno_t lno; +{ + EX_PRIVATE *exp; + RANGE *nrp, *rp; + + exp = EXP(sp); + + switch (op) { + case LINE_APPEND: + return; + case LINE_DELETE: + for (rp = exp->rangeq.cqh_first; + rp != (void *)&exp->rangeq; rp = nrp) { + nrp = rp->q.cqe_next; + /* If range less than the line, ignore it. */ + if (rp->stop < lno) + continue; + /* If range greater than the line, decrement range. */ + if (rp->start > lno) { + --rp->start; + --rp->stop; + continue; + } + /* Lno is inside the range, decrement the end point. */ + if (rp->start > --rp->stop) { + CIRCLEQ_REMOVE(&exp->rangeq, rp, q); + free(rp); + } + } + break; + case LINE_INSERT: + for (rp = exp->rangeq.cqh_first; + rp != (void *)&exp->rangeq; rp = rp->q.cqe_next) { + /* If range less than the line, ignore it. */ + if (rp->stop < lno) + continue; + /* If range greater than the line, increment range. */ + if (rp->start >= lno) { + ++rp->start; + ++rp->stop; + continue; + } + /* + * Lno is inside the range, so the range must be split. + * Since we're inserting a new element, neither range + * can be exhausted. + */ + CALLOC(sp, nrp, RANGE *, 1, sizeof(RANGE)); + if (nrp == NULL) { + F_SET(sp, S_INTERRUPTED); + return; + } + nrp->start = lno + 1; + nrp->stop = rp->stop + 1; + rp->stop = lno - 1; + CIRCLEQ_INSERT_AFTER(&exp->rangeq, rp, nrp, q); + rp = nrp; + } + break; + case LINE_RESET: + return; + } + /* + * If the command deleted/inserted lines, the cursor moves to + * the line after the deleted/inserted line. + */ + exp->range_lno = lno; +} diff --git a/usr.bin/vi/ex/ex_init.c b/usr.bin/vi/ex/ex_init.c new file mode 100644 index 0000000..79b0e4b --- /dev/null +++ b/usr.bin/vi/ex/ex_init.c @@ -0,0 +1,202 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_init.c 8.16 (Berkeley) 8/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "tag.h" + +/* + * ex_screen_copy -- + * Copy ex screen. + */ +int +ex_screen_copy(orig, sp) + SCR *orig, *sp; +{ + EX_PRIVATE *oexp, *nexp; + + /* Create the private ex structure. */ + CALLOC_RET(orig, nexp, EX_PRIVATE *, 1, sizeof(EX_PRIVATE)); + sp->ex_private = nexp; + + /* Initialize queues. */ + TAILQ_INIT(&nexp->tagq); + TAILQ_INIT(&nexp->tagfq); + TAILQ_INIT(&nexp->cdq); + CIRCLEQ_INIT(&nexp->rangeq); + + if (orig == NULL) { + nexp->at_lbuf_set = 0; + } else { + oexp = EXP(orig); + + nexp->at_lbuf = oexp->at_lbuf; + nexp->at_lbuf_set = oexp->at_lbuf_set; + + if (oexp->lastbcomm != NULL && + (nexp->lastbcomm = strdup(oexp->lastbcomm)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return(1); + } + + if (ex_tagcopy(orig, sp)) + return (1); + } + return (0); +} + +/* + * ex_screen_end -- + * End a vi screen. + */ +int +ex_screen_end(sp) + SCR *sp; +{ + EX_PRIVATE *exp; + int rval; + + rval = 0; + exp = EXP(sp); + + if (argv_free(sp)) + rval = 1; + + if (exp->ibp != NULL) + FREE(exp->ibp, exp->ibp_len); + + if (exp->lastbcomm != NULL) + FREE(exp->lastbcomm, strlen(exp->lastbcomm) + 1); + + if (ex_tagfree(sp)) + rval = 1; + + if (ex_cdfree(sp)) + rval = 1; + + /* Free private memory. */ + FREE(exp, sizeof(EX_PRIVATE)); + sp->ex_private = NULL; + + return (rval); +} + +/* + * ex_init -- + * Initialize ex. + */ +int +ex_init(sp, ep) + SCR *sp; + EXF *ep; +{ + size_t len; + + /* + * The default address is the last line of the file. If the address + * set bit is on for this file, load the address, ensuring that it + * exists. + */ + if (F_ISSET(sp->frp, FR_CURSORSET)) { + sp->lno = sp->frp->lno; + sp->cno = sp->frp->cno; + + if (file_gline(sp, ep, sp->lno, &len) == NULL) { + if (file_lline(sp, ep, &sp->lno)) + return (1); + if (sp->lno == 0) + sp->lno = 1; + sp->cno = 0; + } else if (sp->cno >= len) + sp->cno = 0; + } else { + if (file_lline(sp, ep, &sp->lno)) + return (1); + if (sp->lno == 0) + sp->lno = 1; + sp->cno = 0; + } + + /* Display the status line. */ + return (msg_status(sp, ep, sp->lno, 0)); +} + +/* + * ex_end -- + * End ex session. + */ +int +ex_end(sp) + SCR *sp; +{ + return (0); +} + +/* + * ex_optchange -- + * Handle change of options for vi. + */ +int +ex_optchange(sp, opt) + SCR *sp; + int opt; +{ + switch (opt) { + case O_CDPATH: + return (ex_cdalloc(sp, O_STR(sp, O_CDPATH))); + case O_TAGS: + return (ex_tagalloc(sp, O_STR(sp, O_TAGS))); + } + return (0); +} diff --git a/usr.bin/vi/ex/ex_join.c b/usr.bin/vi/ex/ex_join.c new file mode 100644 index 0000000..d561f0a --- /dev/null +++ b/usr.bin/vi/ex/ex_join.c @@ -0,0 +1,200 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_join.c 8.12 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_join -- :[line [,line]] j[oin][!] [count] [flags] + * Join lines. + */ +int +ex_join(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + recno_t from, to; + size_t blen, clen, len, tlen; + int echar, extra, first; + char *bp, *p, *tbp; + + from = cmdp->addr1.lno; + to = cmdp->addr2.lno; + + /* Check for no lines to join. */ + if ((p = file_gline(sp, ep, from + 1, &len)) == NULL) { + msgq(sp, M_ERR, "No following lines to join"); + return (1); + } + + GET_SPACE_RET(sp, bp, blen, 256); + + /* + * The count for the join command was off-by-one, + * historically, to other counts for other commands. + */ + if (F_ISSET(cmdp, E_COUNT)) + ++cmdp->addr2.lno; + + /* + * If only a single address specified, or, the same address + * specified twice, the from/two addresses will be the same. + */ + if (cmdp->addr1.lno == cmdp->addr2.lno) + ++cmdp->addr2.lno; + + clen = tlen = 0; + for (first = 1, + from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) { + /* + * Get next line. Historic versions of vi allowed "10J" while + * less than 10 lines from the end-of-file, so we do too. + */ + if ((p = file_gline(sp, ep, from, &len)) == NULL) { + cmdp->addr2.lno = from - 1; + break; + } + + /* Empty lines just go away. */ + if (len == 0) + continue; + + /* + * Get more space if necessary. Note, tlen isn't the length + * of the new line, it's roughly the amount of space needed. + * tbp - bp is the length of the new line. + */ + tlen += len + 2; + ADD_SPACE_RET(sp, bp, blen, tlen); + tbp = bp + clen; + + /* + * Historic practice: + * + * If force specified, join without modification. + * If the current line ends with whitespace, strip leading + * whitespace from the joined line. + * If the next line starts with a ), do nothing. + * If the current line ends with ., ? or !, insert two spaces. + * Else, insert one space. + * + * Echar is the last character in the last line joined. + */ + extra = 0; + if (!first && !F_ISSET(cmdp, E_FORCE)) { + if (isblank(echar)) + for (; len && isblank(*p); --len, ++p); + else if (p[0] != ')') { + if (strchr(".?!", echar)) { + *tbp++ = ' '; + ++clen; + extra = 1; + } + *tbp++ = ' '; + ++clen; + for (; len && isblank(*p); --len, ++p); + } + } + + if (len != 0) { + memmove(tbp, p, len); + tbp += len; + clen += len; + echar = p[len - 1]; + } else + echar = ' '; + + /* + * Historic practice for vi was to put the cursor at the first + * inserted whitespace character, if there was one, or the + * first character of the joined line, if there wasn't, or the + * last character of the line if joined to an empty line. If + * a count was specified, the cursor was moved as described + * for the first line joined, ignoring subsequent lines. If + * the join was a ':' command, the cursor was placed at the + * first non-blank character of the line unless the cursor was + * "attracted" to the end of line when the command was executed + * in which case it moved to the new end of line. There are + * probably several more special cases, but frankly, my dear, + * I don't give a damn. This implementation puts the cursor + * on the first inserted whitespace character, the first + * character of the joined line, or the last character of the + * line regardless. Note, if the cursor isn't on the joined + * line (possible with : commands), it is reset to the starting + * line. + */ + if (first) { + sp->cno = (tbp - bp) - (1 + extra); + first = 0; + } else + sp->cno = (tbp - bp) - len - (1 + extra); + } + sp->lno = cmdp->addr1.lno; + + /* Delete the joined lines. */ + for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to) + if (file_dline(sp, ep, to)) + goto err; + + /* If the original line changed, reset it. */ + if (!first && file_sline(sp, ep, from, bp, tbp - bp)) { +err: FREE_SPACE(sp, bp, blen); + return (1); + } + FREE_SPACE(sp, bp, blen); + + sp->rptlines[L_JOINED] += (cmdp->addr2.lno - cmdp->addr1.lno) + 1; + return (0); +} diff --git a/usr.bin/vi/ex/ex_map.c b/usr.bin/vi/ex/ex_map.c new file mode 100644 index 0000000..a1f1915 --- /dev/null +++ b/usr.bin/vi/ex/ex_map.c @@ -0,0 +1,160 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_map.c 8.17 (Berkeley) 7/16/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_map -- :map[!] [input] [replacement] + * Map a key/string or display mapped keys. + * + * Historical note: + * Historic vi maps were fairly bizarre, and likely to differ in + * very subtle and strange ways from this implementation. Two + * things worth noting are that vi would often hang or drop core + * if the map was strange enough (ex: map X "xy$@x^V), or, simply + * not work. One trick worth remembering is that if you put a + * mark at the start of the map, e.g. map X mx"xy ...), or if you + * put the map in a .exrc file, things would often work much better. + * No clue why. + */ +int +ex_map(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + enum seqtype stype; + CHAR_T *input, *p; + + stype = F_ISSET(cmdp, E_FORCE) ? SEQ_INPUT : SEQ_COMMAND; + + switch (cmdp->argc) { + case 0: + if (seq_dump(sp, stype, 1) == 0) + msgq(sp, M_INFO, "No %s map entries", + stype == SEQ_INPUT ? "input" : "command"); + return (0); + case 2: + input = cmdp->argv[0]->bp; + break; + default: + abort(); + } + + /* + * If the mapped string is #[0-9]* (and wasn't quoted) then store + * the function key mapping, and call the screen specific routine. + * Note, if the screen specific routine is able to create the + * mapping, the SEQ_FUNCMAP type stays around, maybe the next screen + * type can get it right. + */ + if (input[0] == '#') { + for (p = input + 1; isdigit(*p); ++p); + if (p[0] != '\0') + goto nofunc; + + if (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len, + cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, SEQ_FUNCMAP)) + return (1); + return (sp->s_fmap(sp, stype, input, cmdp->argv[0]->len, + cmdp->argv[1]->bp, cmdp->argv[1]->len)); + } + + /* Some single keys may not be remapped in command mode. */ +nofunc: if (stype == SEQ_COMMAND && input[1] == '\0') + switch (KEY_VAL(sp, input[0])) { + case K_COLON: + case K_ESCAPE: + case K_NL: + msgq(sp, M_ERR, "The %s character may not be remapped", + KEY_NAME(sp, input[0])); + return (1); + } + return (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len, + cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, SEQ_USERDEF)); +} + +/* + * ex_unmap -- (:unmap[!] key) + * Unmap a key. + */ +int +ex_unmap(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + if (seq_delete(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len, + F_ISSET(cmdp, E_FORCE) ? SEQ_INPUT : SEQ_COMMAND)) { + msgq(sp, M_INFO, "\"%s\" isn't mapped", cmdp->argv[0]->bp); + return (1); + } + return (0); +} + +/* + * map_save -- + * Save the mapped sequences to a file. + */ +int +map_save(sp, fp) + SCR *sp; + FILE *fp; +{ + if (seq_save(sp, fp, "map ", SEQ_COMMAND)) + return (1); + return (seq_save(sp, fp, "map! ", SEQ_INPUT)); +} diff --git a/usr.bin/vi/ex/ex_mark.c b/usr.bin/vi/ex/ex_mark.c new file mode 100644 index 0000000..bd1e0fd --- /dev/null +++ b/usr.bin/vi/ex/ex_mark.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_mark.c 8.6 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +int +ex_mark(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + if (cmdp->argv[0]->len != 1) { + msgq(sp, M_ERR, "Mark names must be a single character"); + return (1); + } + return (mark_set(sp, ep, cmdp->argv[0]->bp[0], &cmdp->addr1, 1)); +} diff --git a/usr.bin/vi/ex/ex_mkexrc.c b/usr.bin/vi/ex/ex_mkexrc.c new file mode 100644 index 0000000..095d51e --- /dev/null +++ b/usr.bin/vi/ex/ex_mkexrc.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_mkexrc.c 8.12 (Berkeley) 7/15/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> +#include <pathnames.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_mkexrc -- :mkexrc[!] [file] + * + * Create (or overwrite) a .exrc file with the current info. + */ +int +ex_mkexrc(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + struct stat sb; + FILE *fp; + int fd, sverrno; + char *fname; + + switch (cmdp->argc) { + case 0: + fname = _PATH_EXRC; + break; + case 1: + fname = cmdp->argv[0]->bp; + set_alt_name(sp, fname); + break; + default: + abort(); + } + + if (!F_ISSET(cmdp, E_FORCE) && !stat(fname, &sb)) { + msgq(sp, M_ERR, + "%s exists, not written; use ! to override", fname); + return (1); + } + + /* Create with max permissions of rw-r--r--. */ + if ((fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { + msgq(sp, M_SYSERR, fname); + return (1); + } + + if ((fp = fdopen(fd, "w")) == NULL) { + sverrno = errno; + (void)close(fd); + errno = sverrno; + goto e2; + } + + if (abbr_save(sp, fp) || ferror(fp)) + goto e1; + if (map_save(sp, fp) || ferror(fp)) + goto e1; + if (opts_save(sp, fp) || ferror(fp)) + goto e1; +#ifndef NO_DIGRAPH + digraph_save(sp, fd); +#endif + if (fclose(fp)) + goto e2; + + msgq(sp, M_INFO, "New .exrc file: %s. ", fname); + return (0); + +e1: sverrno = errno; + (void)fclose(fp); + errno = sverrno; +e2: msgq(sp, M_ERR, "%s: incomplete: %s", fname, strerror(errno)); + return (1); +} diff --git a/usr.bin/vi/ex/ex_move.c b/usr.bin/vi/ex/ex_move.c new file mode 100644 index 0000000..9822508 --- /dev/null +++ b/usr.bin/vi/ex/ex_move.c @@ -0,0 +1,222 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_move.c 8.17 (Berkeley) 8/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_copy -- :[line [,line]] co[py] line [flags] + * Copy selected lines. + */ +int +ex_copy(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + CB cb; + MARK fm1, fm2, m, tm; + recno_t cnt; + int rval; + + rval = 0; + + /* + * It's possible to copy things into the area that's being + * copied, e.g. "2,5copy3" is legitimate. Save the text to + * a cut buffer. + */ + fm1 = cmdp->addr1; + fm2 = cmdp->addr2; + memset(&cb, 0, sizeof(cb)); + CIRCLEQ_INIT(&cb.textq); + for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt) + if (cut_line(sp, ep, cnt, 0, 0, &cb)) { + rval = 1; + goto err; + } + cb.flags |= CB_LMODE; + + /* Put the text into place. */ + tm.lno = cmdp->lineno; + tm.cno = 0; + if (put(sp, ep, &cb, NULL, &tm, &m, 1)) + rval = 1; + else { + /* + * Copy puts the cursor on the last line copied. The cursor + * returned by the put routine is the first line put, not the + * last, because that's the historic semantic of vi. + */ + cnt = (fm2.lno - fm1.lno) + 1; + sp->lno = m.lno + (cnt - 1); + sp->cno = 0; + } +err: text_lfree(&cb.textq); + return (rval); +} + +/* + * ex_move -- :[line [,line]] mo[ve] line + * Move selected lines. + */ +int +ex_move(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + LMARK *lmp; + MARK fm1, fm2; + recno_t cnt, diff, fl, tl, mfl, mtl; + size_t blen, len; + int mark_reset; + char *bp, *p; + + /* + * It's not possible to move things into the area that's being + * moved. + */ + fm1 = cmdp->addr1; + fm2 = cmdp->addr2; + if (cmdp->lineno >= fm1.lno && cmdp->lineno <= fm2.lno) { + msgq(sp, M_ERR, "Destination line is inside move range"); + return (1); + } + + /* + * Log the positions of any marks in the to-be-deleted lines. This + * has to work with the logging code. What happens is that we log + * the old mark positions, make the changes, then log the new mark + * positions. Then the marks end up in the right positions no matter + * which way the log is traversed. + * + * XXX + * Reset the MARK_USERSET flag so that the log can undo the mark. + * This isn't very clean, and should probably be fixed. + */ + fl = fm1.lno; + tl = cmdp->lineno; + + /* Log the old positions of the marks. */ + mark_reset = 0; + for (lmp = ep->marks.lh_first; lmp != NULL; lmp = lmp->q.le_next) + if (lmp->name != ABSMARK1 && + lmp->lno >= fl && lmp->lno <= tl) { + mark_reset = 1; + F_CLR(lmp, MARK_USERSET); + (void)log_mark(sp, ep, lmp); + } + + /* Get memory for the copy. */ + GET_SPACE_RET(sp, bp, blen, 256); + + /* Move the lines. */ + diff = (fm2.lno - fm1.lno) + 1; + if (tl > fl) { /* Destination > source. */ + mfl = tl - diff; + mtl = tl; + for (cnt = diff; cnt--;) { + if ((p = file_gline(sp, ep, fl, &len)) == NULL) + return (1); + BINC_RET(sp, bp, blen, len); + memmove(bp, p, len); + if (file_aline(sp, ep, 1, tl, bp, len)) + return (1); + if (mark_reset) + for (lmp = ep->marks.lh_first; + lmp != NULL; lmp = lmp->q.le_next) + if (lmp->name != ABSMARK1 && + lmp->lno == fl) + lmp->lno = tl + 1; + if (file_dline(sp, ep, fl)) + return (1); + } + } else { /* Destination < source. */ + mfl = tl; + mtl = tl + diff; + for (cnt = diff; cnt--;) { + if ((p = file_gline(sp, ep, fl, &len)) == NULL) + return (1); + BINC_RET(sp, bp, blen, len); + memmove(bp, p, len); + if (file_aline(sp, ep, 1, tl++, bp, len)) + return (1); + if (mark_reset) + for (lmp = ep->marks.lh_first; + lmp != NULL; lmp = lmp->q.le_next) + if (lmp->name != ABSMARK1 && + lmp->lno == fl) + lmp->lno = tl; + ++fl; + if (file_dline(sp, ep, fl)) + return (1); + } + } + FREE_SPACE(sp, bp, blen); + + sp->lno = tl; /* Last line moved. */ + sp->cno = 0; + + /* Log the new positions of the marks. */ + if (mark_reset) + for (lmp = ep->marks.lh_first; + lmp != NULL; lmp = lmp->q.le_next) + if (lmp->name != ABSMARK1 && + lmp->lno >= mfl && lmp->lno <= mtl) + (void)log_mark(sp, ep, lmp); + + + sp->rptlines[L_MOVED] += diff; + return (0); +} diff --git a/usr.bin/vi/ex/ex_open.c b/usr.bin/vi/ex/ex_open.c new file mode 100644 index 0000000..385fdd3 --- /dev/null +++ b/usr.bin/vi/ex/ex_open.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_open.c 8.4 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_open -- :[line] o[pen] [/pattern/] [flags] + * + * Switch to single line "open" mode. + */ +int +ex_open(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + /* If open option off, disallow open command. */ + if (!O_ISSET(sp, O_OPEN)) { + msgq(sp, M_ERR, + "The open command requires that the open option be set"); + return (1); + } + + msgq(sp, M_ERR, "The open command is not yet implemented"); + return (1); +} diff --git a/usr.bin/vi/ex/ex_preserve.c b/usr.bin/vi/ex/ex_preserve.c new file mode 100644 index 0000000..8960f98 --- /dev/null +++ b/usr.bin/vi/ex/ex_preserve.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_preserve.c 8.12 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_preserve -- :pre[serve] + * Push the file to recovery. + */ +int +ex_preserve(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + recno_t lno; + + if (!F_ISSET(ep, F_RCV_ON)) { + msgq(sp, M_ERR, "Preservation of this file not possible"); + return (1); + } + + /* If recovery not initialized, do so. */ + if (F_ISSET(ep, F_FIRSTMODIFY) && rcv_init(sp, ep)) + return (1); + + /* Force the file to be read in, in case it hasn't yet. */ + if (file_lline(sp, ep, &lno)) + return (1); + + /* Sync to disk. */ + if (rcv_sync(sp, ep, RCV_SNAPSHOT)) + return (1); + + msgq(sp, M_INFO, "File preserved"); + return (0); +} + +/* + * ex_recover -- :rec[over][!] file + * + * Recover the file. + */ +int +ex_recover(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + ARGS *ap; + FREF *frp; + + ap = cmdp->argv[0]; + + /* Set the alternate file name. */ + set_alt_name(sp, ap->bp); + + /* + * Check for modifications. Autowrite did not historically + * affect :recover. + */ + if (file_m2(sp, ep, F_ISSET(cmdp, E_FORCE))) + return (1); + + /* Get a file structure for the file. */ + if ((frp = file_add(sp, ap->bp)) == NULL) + return (1); + + /* Set the recover bit. */ + F_SET(frp, FR_RECOVER); + + /* Switch files. */ + if (file_init(sp, frp, NULL, F_ISSET(cmdp, E_FORCE))) + return (1); + F_SET(sp, S_FSWITCH); + return (0); +} diff --git a/usr.bin/vi/ex/ex_print.c b/usr.bin/vi/ex/ex_print.c new file mode 100644 index 0000000..c3aa22f --- /dev/null +++ b/usr.bin/vi/ex/ex_print.c @@ -0,0 +1,212 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_print.c 8.14 (Berkeley) 8/7/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_list -- :[line [,line]] l[ist] [count] [flags] + * + * Display the addressed lines such that the output is unambiguous. + */ +int +ex_list(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + if (ex_print(sp, ep, + &cmdp->addr1, &cmdp->addr2, cmdp->flags | E_F_LIST)) + return (1); + sp->lno = cmdp->addr2.lno; + sp->cno = cmdp->addr2.cno; + return (0); +} + +/* + * ex_number -- :[line [,line]] nu[mber] [count] [flags] + * + * Display the addressed lines with a leading line number. + */ +int +ex_number(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + if (ex_print(sp, ep, + &cmdp->addr1, &cmdp->addr2, cmdp->flags | E_F_HASH)) + return (1); + sp->lno = cmdp->addr2.lno; + sp->cno = cmdp->addr2.cno; + return (0); +} + +/* + * ex_pr -- :[line [,line]] p[rint] [count] [flags] + * + * Display the addressed lines. + */ +int +ex_pr(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + if (ex_print(sp, ep, &cmdp->addr1, &cmdp->addr2, cmdp->flags)) + return (1); + sp->lno = cmdp->addr2.lno; + sp->cno = cmdp->addr2.cno; + return (0); +} + +/* + * ex_print -- + * Print the selected lines. + */ +int +ex_print(sp, ep, fp, tp, flags) + SCR *sp; + EXF *ep; + MARK *fp, *tp; + register int flags; +{ + recno_t from, to; + size_t col, len; + char *p; + + F_SET(sp, S_INTERRUPTIBLE); + for (from = fp->lno, to = tp->lno; from <= to; ++from) { + /* + * Display the line number. The %6 format is specified + * by POSIX 1003.2, and is almost certainly large enough. + * Check, though, just in case. + */ + if (LF_ISSET(E_F_HASH)) + if (from <= 999999) + col = ex_printf(EXCOOKIE, "%6ld ", from); + else + col = ex_printf(EXCOOKIE, "TOOBIG "); + else + col = 0; + + /* + * Display the line. The format for E_F_PRINT isn't very good, + * especially in handling end-of-line tabs, but they're almost + * backward compatible. + */ + if ((p = file_gline(sp, ep, from, &len)) == NULL) { + GETLINE_ERR(sp, from); + return (1); + } + + if (len == 0 && !LF_ISSET(E_F_LIST)) + (void)ex_printf(EXCOOKIE, "\n"); + else if (ex_ldisplay(sp, p, len, col, flags)) + return (1); + + if (INTERRUPTED(sp)) + break; + } + + return (0); +} + +/* + * ex_ldisplay -- + * Display a line. + */ +int +ex_ldisplay(sp, lp, len, col, flags) + SCR *sp; + CHAR_T *lp; + size_t len, col; + u_int flags; +{ + CHAR_T ch, *kp; + u_long ts; + size_t tlen; + + ts = O_VAL(sp, O_TABSTOP); + for (;; --len) { + if (len > 0) + ch = *lp++; + else if (LF_ISSET(E_F_LIST)) + ch = '$'; + else + break; + if (ch == '\t' && !LF_ISSET(E_F_LIST)) + for (tlen = ts - col % ts; + col < sp->cols && tlen--; ++col) + (void)ex_printf(EXCOOKIE, " "); + else { + kp = KEY_NAME(sp, ch); + tlen = KEY_LEN(sp, ch); + if (col + tlen < sp->cols) { + (void)ex_printf(EXCOOKIE, "%s", kp); + col += tlen; + } else + for (; tlen--; ++kp, ++col) { + if (col == sp->cols) { + col = 0; + (void)ex_printf(EXCOOKIE, "\n"); + } + (void)ex_printf(EXCOOKIE, "%c", *kp); + } + } + if (len == 0) + break; + } + (void)ex_printf(EXCOOKIE, "\n"); + return (0); +} diff --git a/usr.bin/vi/ex/ex_put.c b/usr.bin/vi/ex/ex_put.c new file mode 100644 index 0000000..ce44b5f --- /dev/null +++ b/usr.bin/vi/ex/ex_put.c @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_put.c 8.6 (Berkeley) 7/23/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_put -- [line] pu[t] [buffer] + * + * Append a cut buffer into the file. + */ +int +ex_put(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + MARK m; + + m.lno = sp->lno; + m.cno = sp->cno; + if (put(sp, ep, NULL, F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL, + &cmdp->addr1, &m, 1)) + return (1); + sp->lno = m.lno; + sp->cno = m.cno; + return (0); +} diff --git a/usr.bin/vi/ex/ex_read.c b/usr.bin/vi/ex/ex_read.c new file mode 100644 index 0000000..dafc4ad --- /dev/null +++ b/usr.bin/vi/ex/ex_read.c @@ -0,0 +1,300 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_read.c 8.39 (Berkeley) 8/9/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_read -- :read [file] + * :read [!cmd] + * Read from a file or utility. + * + * !!! + * Historical vi wouldn't undo a filter read, for no apparent reason. + */ +int +ex_read(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + struct stat sb; + CHAR_T *arg, *name; + EX_PRIVATE *exp; + FILE *fp; + MARK rm; + recno_t nlines; + size_t arglen, blen, len; + int btear, farg, rval; + char *p; + + /* + * 0 args: we're done. + * 1 args: check for "read !arg". + * 2 args: check for "read ! arg". + * >2 args: object, too many args. + */ + farg = 0; + switch (cmdp->argc) { + case 0: + break; + case 1: + arg = cmdp->argv[0]->bp; + arglen = cmdp->argv[0]->len; + if (*arg == '!') { + ++arg; + --arglen; + farg = 1; + } + break; + case 2: + if (cmdp->argv[0]->len == 1 && cmdp->argv[0]->bp[0] == '!') { + arg = cmdp->argv[1]->bp; + arglen = cmdp->argv[1]->len; + farg = 2; + break; + } + /* FALLTHROUGH */ + default: + goto badarg; + } + + if (farg != 0) { + /* File name and bang expand the user's argument. */ + if (argv_exp1(sp, ep, cmdp, arg, arglen, 1)) + return (1); + + /* If argc unchanged, there wasn't anything to expand. */ + if (cmdp->argc == farg) + goto usage; + + /* Set the last bang command. */ + exp = EXP(sp); + if (exp->lastbcomm != NULL) + free(exp->lastbcomm); + if ((exp->lastbcomm = strdup(cmdp->argv[farg]->bp)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + /* Redisplay the user's argument if it's changed. */ + if (F_ISSET(cmdp, E_MODIFY) && IN_VI_MODE(sp)) { + len = cmdp->argv[farg]->len; + GET_SPACE_RET(sp, p, blen, len + 2); + p[0] = '!'; + memmove(p + 1, + cmdp->argv[farg]->bp, cmdp->argv[farg]->len + 1); + (void)sp->s_busy(sp, p); + FREE_SPACE(sp, p, blen); + } + + if (filtercmd(sp, ep, &cmdp->addr1, + NULL, &rm, cmdp->argv[farg]->bp, FILTER_READ)) + return (1); + + /* The filter version of read set the autoprint flag. */ + F_SET(EXP(sp), EX_AUTOPRINT); + + /* If in vi mode, move to the first nonblank. */ + sp->lno = rm.lno; + if (IN_VI_MODE(sp)) { + sp->cno = 0; + (void)nonblank(sp, ep, sp->lno, &sp->cno); + } + return (0); + } + + /* Shell and file name expand the user's argument. */ + if (argv_exp2(sp, ep, cmdp, arg, arglen, 0)) + return (1); + + /* + * 0 args: no arguments, read the current file, don't set the + * alternate file name. + * 1 args: read it, switching to it or settgin the alternate file + * name. + * >1 args: object, too many args. + */ + switch (cmdp->argc) { + case 1: + name = sp->frp->name; + break; + case 2: + name = cmdp->argv[1]->bp; + /* + * !!! + * Historically, if you had an "unnamed" file, the read command + * renamed the file. + */ + if (F_ISSET(sp->frp, FR_TMPFILE) && + !F_ISSET(sp->frp, FR_READNAMED)) { + if ((p = v_strdup(sp, + cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) { + free(sp->frp->name); + sp->frp->name = p; + } + F_SET(sp->frp, FR_NAMECHANGE | FR_READNAMED); + } else + set_alt_name(sp, name); + break; + default: +badarg: msgq(sp, M_ERR, + "%s expanded into too many file names", cmdp->argv[0]->bp); +usage: msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); + } + + /* + * !!! + * Historically, vi did not permit reads from non-regular files, + * nor did it distinguish between "read !" and "read!", so there + * was no way to "force" it. + */ + if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) { + msgq(sp, M_SYSERR, "%s", name); + return (1); + } + if (!S_ISREG(sb.st_mode)) { + (void)fclose(fp); + msgq(sp, M_ERR, "Only regular files may be read"); + return (1); + } + + /* Turn on busy message. */ + btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Reading..."); + rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1); + if (btear) + busy_off(sp); + + /* + * Set the cursor to the first line read in, if anything read + * in, otherwise, the address. (Historic vi set it to the + * line after the address regardless, but since that line may + * not exist we don't bother.) + */ + sp->lno = cmdp->addr1.lno; + if (nlines) + ++sp->lno; + + return (rval); +} + +/* + * ex_readfp -- + * Read lines into the file. + */ +int +ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg) + SCR *sp; + EXF *ep; + char *name; + FILE *fp; + MARK *fm; + recno_t *nlinesp; + int success_msg; +{ + EX_PRIVATE *exp; + recno_t lcnt, lno; + size_t len; + u_long ccnt; /* XXX: can't print off_t portably. */ + int rval; + + rval = 0; + exp = EXP(sp); + + /* + * Add in the lines from the output. Insertion starts at the line + * following the address. + */ + ccnt = 0; + lcnt = 0; + for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) { + if (INTERRUPTED(sp)) { + if (!success_msg) + msgq(sp, M_INFO, "Interrupted"); + break; + } + if (file_aline(sp, ep, 1, lno, exp->ibp, len)) { + rval = 1; + break; + } + ccnt += len; + } + + if (ferror(fp)) { + msgq(sp, M_SYSERR, "%s", name); + rval = 1; + } + + if (fclose(fp)) { + msgq(sp, M_SYSERR, "%s", name); + return (1); + } + + if (rval) + return (1); + + /* Return the number of lines read in. */ + if (nlinesp != NULL) + *nlinesp = lcnt; + + if (success_msg) + msgq(sp, M_INFO, "%s%s: %lu line%s, %lu characters", + INTERRUPTED(sp) ? "Interrupted read: " : "", + name, lcnt, lcnt == 1 ? "" : "s", ccnt); + + return (0); +} diff --git a/usr.bin/vi/ex/ex_screen.c b/usr.bin/vi/ex/ex_screen.c new file mode 100644 index 0000000..179ed07 --- /dev/null +++ b/usr.bin/vi/ex/ex_screen.c @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_screen.c 8.13 (Berkeley) 6/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_split -- :s[plit] [file ...] + * Split the screen, optionally setting the file list. + */ +int +ex_split(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (sp->s_split(sp, cmdp->argc ? cmdp->argv : NULL, cmdp->argc)); +} + +/* + * ex_bg -- :bg + * Hide the screen. + */ +int +ex_bg(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (sp->s_bg(sp)); +} + +/* + * ex_fg -- :fg [file] + * Show the screen. + */ +int +ex_fg(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (sp->s_fg(sp, cmdp->argc ? cmdp->argv[0]->bp : NULL)); +} + +/* + * ex_resize -- :resize [+-]rows + * Change the screen size. + */ +int +ex_resize(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + enum adjust adj; + + if (!F_ISSET(cmdp, E_COUNT)) { + msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); + } + if (F_ISSET(cmdp, E_COUNT_NEG)) + adj = A_DECREASE; + else if (F_ISSET(cmdp, E_COUNT_POS)) + adj = A_INCREASE; + else + adj = A_SET; + return (sp->s_rabs(sp, cmdp->count, adj)); +} + +/* + * ex_sdisplay -- + * Display the list of screens. + */ +int +ex_sdisplay(sp, ep) + SCR *sp; + EXF *ep; +{ + SCR *tsp; + int cnt, col, len, sep; + + if ((tsp = sp->gp->hq.cqh_first) == (void *)&sp->gp->hq) { + (void)ex_printf(EXCOOKIE, + "No backgrounded screens to display.\n"); + return (0); + } + + col = len = sep = 0; + for (cnt = 1; tsp != (void *)&sp->gp->hq; tsp = tsp->q.cqe_next) { + col += len = strlen(tsp->frp->name) + sep; + if (col >= sp->cols - 1) { + col = len; + sep = 0; + (void)ex_printf(EXCOOKIE, "\n"); + } else if (cnt != 1) { + sep = 1; + (void)ex_printf(EXCOOKIE, " "); + } + (void)ex_printf(EXCOOKIE, "%s", tsp->frp->name); + ++cnt; + } + (void)ex_printf(EXCOOKIE, "\n"); + return (0); +} diff --git a/usr.bin/vi/ex/ex_script.c b/usr.bin/vi/ex/ex_script.c new file mode 100644 index 0000000..59586f1 --- /dev/null +++ b/usr.bin/vi/ex/ex_script.c @@ -0,0 +1,582 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_script.c 8.17 (Berkeley) 7/23/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/queue.h> +#include <sys/time.h> +#include <sys/wait.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "script.h" + +/* + * XXX + */ +int openpty __P((int *, int *, char *, struct termios *, struct winsize *)); + +static int sscr_getprompt __P((SCR *, EXF *)); +static int sscr_init __P((SCR *, EXF *)); +static int sscr_matchprompt __P((SCR *, char *, size_t, size_t *)); +static int sscr_setprompt __P((SCR *, char *, size_t)); + +/* + * ex_script -- : sc[ript][!] [file] + * + * Switch to script mode. + */ +int +ex_script(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + /* Vi only command. */ + if (!IN_VI_MODE(sp)) { + msgq(sp, M_ERR, + "The script command is only available in vi mode"); + return (1); + } + + /* Switch to the new file. */ + if (cmdp->argc != 0 && ex_edit(sp, ep, cmdp)) + return (1); + + /* + * Create the shell, figure out the prompt. + * + * !!! + * The files just switched, use sp->ep. + */ + if (sscr_init(sp, sp->ep)) + return (1); + + return (0); +} + +/* + * sscr_init -- + * Create a pty setup for a shell. + */ +static int +sscr_init(sp, ep) + SCR *sp; + EXF *ep; +{ + SCRIPT *sc; + char *sh, *sh_path; + + MALLOC_RET(sp, sc, SCRIPT *, sizeof(SCRIPT)); + sp->script = sc; + sc->sh_prompt = NULL; + sc->sh_prompt_len = 0; + + /* + * There are two different processes running through this code. + * They are the shell and the parent. + */ + sc->sh_master = sc->sh_slave = -1; + + if (tcgetattr(STDIN_FILENO, &sc->sh_term) == -1) { + msgq(sp, M_SYSERR, "tcgetattr"); + goto err; + } + + /* + * Turn off output postprocessing and echo. + */ + sc->sh_term.c_oflag &= ~OPOST; + sc->sh_term.c_cflag &= ~(ECHO|ECHOE|ECHONL|ECHOK); + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &sc->sh_win) == -1) { + msgq(sp, M_SYSERR, "tcgetattr"); + goto err; + } + + if (openpty(&sc->sh_master, + &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) { + msgq(sp, M_SYSERR, "openpty"); + goto err; + } + + /* + * Don't use vfork() here, because the signal semantics differ from + * implementation to implementation. + */ + SIGBLOCK(sp->gp); + switch (sc->sh_pid = fork()) { + case -1: /* Error. */ + SIGUNBLOCK(sp->gp); + + msgq(sp, M_SYSERR, "fork"); +err: if (sc->sh_master != -1) + (void)close(sc->sh_master); + if (sc->sh_slave != -1) + (void)close(sc->sh_slave); + return (1); + case 0: /* Utility. */ + /* The utility has default signal behavior. */ + sig_end(); + + /* + * XXX + * So that shells that do command line editing turn it off. + */ + (void)putenv("TERM=emacs"); + (void)putenv("TERMCAP=emacs:"); + (void)putenv("EMACS=t"); + + (void)setsid(); +#ifdef TIOCSCTTY + /* + * 4.4BSD allocates a controlling terminal using the TIOCSCTTY + * ioctl, not by opening a terminal device file. POSIX 1003.1 + * doesn't define a portable way to do this. If TIOCSCTTY is + * not available, hope that the open does it. + */ + (void)ioctl(sc->sh_slave, TIOCSCTTY, 0); +#endif + (void)close(sc->sh_master); + (void)dup2(sc->sh_slave, STDIN_FILENO); + (void)dup2(sc->sh_slave, STDOUT_FILENO); + (void)dup2(sc->sh_slave, STDERR_FILENO); + (void)close(sc->sh_slave); + + /* Assumes that all shells have -i. */ + sh_path = O_STR(sp, O_SHELL); + if ((sh = strrchr(sh_path, '/')) == NULL) + sh = sh_path; + else + ++sh; + execl(sh_path, sh, "-i", NULL); + msgq(sp, M_ERR, + "Error: execl: %s: %s", sh_path, strerror(errno)); + _exit(127); + default: /* Parent. */ + SIGUNBLOCK(sp->gp); + break; + } + + if (sscr_getprompt(sp, ep)) + return (1); + + F_SET(sp, S_REDRAW | S_SCRIPT); + return (0); + +} + +/* + * sscr_getprompt -- + * Eat lines printed by the shell until a line with no trailing + * carriage return comes; set the prompt from that line. + */ +static int +sscr_getprompt(sp, ep) + SCR *sp; + EXF *ep; +{ + struct timeval tv; + CHAR_T *endp, *p, *t, buf[1024]; + SCRIPT *sc; + fd_set fdset; + recno_t lline; + size_t llen, len; + u_int value; + int nr; + + FD_ZERO(&fdset); + endp = buf; + len = sizeof(buf); + + /* Wait up to a second for characters to read. */ + tv.tv_sec = 5; + tv.tv_usec = 0; + sc = sp->script; + FD_SET(sc->sh_master, &fdset); + switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { + case -1: /* Error or interrupt. */ + msgq(sp, M_SYSERR, "select"); + goto prompterr; + case 0: /* Timeout */ + msgq(sp, M_ERR, "Error: timed out"); + goto prompterr; + case 1: /* Characters to read. */ + break; + } + + /* Read the characters. */ +more: len = sizeof(buf) - (endp - buf); + switch (nr = read(sc->sh_master, endp, len)) { + case 0: /* EOF. */ + msgq(sp, M_ERR, "Error: shell: EOF"); + goto prompterr; + case -1: /* Error or interrupt. */ + msgq(sp, M_SYSERR, "shell"); + goto prompterr; + default: + endp += nr; + break; + } + + /* If any complete lines, push them into the file. */ + for (p = t = buf; p < endp; ++p) { + value = KEY_VAL(sp, *p); + if (value == K_CR || value == K_NL) { + if (file_lline(sp, ep, &lline) || + file_aline(sp, ep, 0, lline, t, p - t)) + goto prompterr; + t = p + 1; + } + } + if (p > buf) { + memmove(buf, t, endp - t); + endp = buf + (endp - t); + } + if (endp == buf) + goto more; + + /* Wait up 1/10 of a second to make sure that we got it all. */ + tv.tv_sec = 0; + tv.tv_usec = 100000; + switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { + case -1: /* Error or interrupt. */ + msgq(sp, M_SYSERR, "select"); + goto prompterr; + case 0: /* Timeout */ + break; + case 1: /* Characters to read. */ + goto more; + } + + /* Timed out, so theoretically we have a prompt. */ + llen = endp - buf; + endp = buf; + + /* Append the line into the file. */ + if (file_lline(sp, ep, &lline) || + file_aline(sp, ep, 0, lline, buf, llen)) { +prompterr: sscr_end(sp); + return (1); + } + + return (sscr_setprompt(sp, buf, llen)); +} + +/* + * sscr_exec -- + * Take a line and hand it off to the shell. + */ +int +sscr_exec(sp, ep, lno) + SCR *sp; + EXF *ep; + recno_t lno; +{ + SCRIPT *sc; + recno_t last_lno; + size_t blen, len, last_len, tlen; + int matchprompt, nw, rval; + char *bp, *p; + + /* If there's a prompt on the last line, append the command. */ + if (file_lline(sp, ep, &last_lno)) + return (1); + if ((p = file_gline(sp, ep, last_lno, &last_len)) == NULL) { + GETLINE_ERR(sp, last_lno); + return (1); + } + if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) { + matchprompt = 1; + GET_SPACE_RET(sp, bp, blen, last_len + 128); + memmove(bp, p, last_len); + } else + matchprompt = 0; + + /* Get something to execute. */ + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + goto err1; + if (lno == 0) + goto empty; + else + GETLINE_ERR(sp, lno); + goto err1; + } + + /* Empty lines aren't interesting. */ + if (len == 0) + goto empty; + + /* Delete any prompt. */ + if (sscr_matchprompt(sp, p, len, &tlen)) { + if (tlen == len) { +empty: msgq(sp, M_BERR, "Nothing to execute"); + goto err1; + } + p += (len - tlen); + len = tlen; + } + + /* Push the line to the shell. */ + sc = sp->script; + if ((nw = write(sc->sh_master, p, len)) != len) + goto err2; + rval = 0; + if (write(sc->sh_master, "\n", 1) != 1) { +err2: if (nw == 0) + errno = EIO; + msgq(sp, M_SYSERR, "shell"); + goto err1; + } + + if (matchprompt) { + ADD_SPACE_RET(sp, bp, blen, last_len + len); + memmove(bp + last_len, p, len); + if (file_sline(sp, ep, last_lno, bp, last_len + len)) +err1: rval = 1; + } + if (matchprompt) + FREE_SPACE(sp, bp, blen); + return (rval); +} + +/* + * sscr_input -- + * Take a line from the shell and insert it into the file. + */ +int +sscr_input(sp) + SCR *sp; +{ + struct timeval tv; + CHAR_T *endp, *p, *t; + EXF *ep; + SCRIPT *sc; + recno_t lno; + size_t blen, len, tlen; + u_int value; + int nr, rval; + char *bp; + + /* Find out where the end of the file is. */ + ep = sp->ep; + if (file_lline(sp, ep, &lno)) + return (1); + +#define MINREAD 1024 + GET_SPACE_RET(sp, bp, blen, MINREAD); + endp = bp; + + /* Read the characters. */ + rval = 1; + sc = sp->script; +more: switch (nr = read(sc->sh_master, endp, MINREAD)) { + case 0: /* EOF; shell just exited. */ + sscr_end(sp); + F_CLR(sp, S_SCRIPT); + rval = 0; + goto ret; + case -1: /* Error or interrupt. */ + msgq(sp, M_SYSERR, "shell"); + goto ret; + default: + endp += nr; + break; + } + + /* Append the lines into the file. */ + for (p = t = bp; p < endp; ++p) { + value = KEY_VAL(sp, *p); + if (value == K_CR || value == K_NL) { + len = p - t; + if (file_aline(sp, ep, 1, lno++, t, len)) + goto ret; + t = p + 1; + } + } + if (p > t) { + len = p - t; + /* + * If the last thing from the shell isn't another prompt, wait + * up to 1/10 of a second for more stuff to show up, so that + * we don't break the output into two separate lines. Don't + * want to hang indefinitely because some program is hanging, + * confused the shell, or whatever. + */ + if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) { + tv.tv_sec = 0; + tv.tv_usec = 100000; + FD_SET(sc->sh_master, &sp->rdfd); + FD_CLR(STDIN_FILENO, &sp->rdfd); + if (select(sc->sh_master + 1, + &sp->rdfd, NULL, NULL, &tv) == 1) { + memmove(bp, t, len); + endp = bp + len; + goto more; + } + } + if (sscr_setprompt(sp, t, len)) + return (1); + if (file_aline(sp, ep, 1, lno++, t, len)) + goto ret; + } + + /* The cursor moves to EOF. */ + sp->lno = lno; + sp->cno = len ? len - 1 : 0; + rval = sp->s_refresh(sp, ep); + +ret: FREE_SPACE(sp, bp, blen); + return (rval); +} + +/* + * sscr_setprompt -- + * + * Set the prompt to the last line we got from the shell. + * + */ +static int +sscr_setprompt(sp, buf, len) + SCR *sp; + char* buf; + size_t len; +{ + SCRIPT *sc; + + sc = sp->script; + if (sc->sh_prompt) + FREE(sc->sh_prompt, sc->sh_prompt_len); + MALLOC(sp, sc->sh_prompt, char *, len + 1); + if (sc->sh_prompt == NULL) { + sscr_end(sp); + return (1); + } + memmove(sc->sh_prompt, buf, len); + sc->sh_prompt_len = len; + sc->sh_prompt[len] = '\0'; + return (0); +} + +/* + * sscr_matchprompt -- + * Check to see if a line matches the prompt. Nul's indicate + * parts that can change, in both content and size. + */ +static int +sscr_matchprompt(sp, lp, line_len, lenp) + SCR *sp; + char *lp; + size_t line_len, *lenp; +{ + SCRIPT *sc; + size_t prompt_len; + char *pp; + + sc = sp->script; + if (line_len < (prompt_len = sc->sh_prompt_len)) + return (0); + + for (pp = sc->sh_prompt; + prompt_len && line_len; --prompt_len, --line_len) { + if (*pp == '\0') { + for (; prompt_len && *pp == '\0'; --prompt_len, ++pp); + if (!prompt_len) + return (0); + for (; line_len && *lp != *pp; --line_len, ++lp); + if (!line_len) + return (0); + } + if (*pp++ != *lp++) + break; + } + + if (prompt_len) + return (0); + if (lenp != NULL) + *lenp = line_len; + return (1); +} + +/* + * sscr_end -- + * End the pipe to a shell. + */ +int +sscr_end(sp) + SCR *sp; +{ + SCRIPT *sc; + int rval; + + if ((sc = sp->script) == NULL) + return (0); + + /* Turn off the script flag. */ + F_CLR(sp, S_SCRIPT); + + /* Close down the parent's file descriptors. */ + if (sc->sh_master != -1) + (void)close(sc->sh_master); + if (sc->sh_slave != -1) + (void)close(sc->sh_slave); + + /* This should have killed the child. */ + rval = proc_wait(sp, (long)sc->sh_pid, "script-shell", 0); + + /* Free memory. */ + FREE(sc->sh_prompt, sc->sh_prompt_len); + FREE(sc, sizeof(SCRIPT)); + sp->script = NULL; + + return (rval); +} diff --git a/usr.bin/vi/ex/ex_set.c b/usr.bin/vi/ex/ex_set.c new file mode 100644 index 0000000..1ad19f7 --- /dev/null +++ b/usr.bin/vi/ex/ex_set.c @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_set.c 8.4 (Berkeley) 7/22/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +int +ex_set(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + switch(cmdp->argc) { + case 0: + opts_dump(sp, CHANGED_DISPLAY); + break; + default: + opts_set(sp, cmdp->cmd->usage, cmdp->argv); + break; + } + return (0); +} diff --git a/usr.bin/vi/ex/ex_shell.c b/usr.bin/vi/ex/ex_shell.c new file mode 100644 index 0000000..bcbb97d --- /dev/null +++ b/usr.bin/vi/ex/ex_shell.c @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_shell.c 8.24 (Berkeley) 8/5/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "../svi/svi_screen.h" + +/* + * ex_shell -- :sh[ell] + * Invoke the program named in the SHELL environment variable + * with the argument -i. + */ +int +ex_shell(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + char buf[MAXPATHLEN]; + + (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL)); + return (ex_exec_proc(sp, buf, "\n", NULL)); +} + +/* + * ex_exec_proc -- + * Run a separate process. + */ +int +ex_exec_proc(sp, cmd, p1, p2) + SCR *sp; + char *cmd, *p1, *p2; +{ + const char *name; + pid_t pid; + int rval, teardown; + + /* Clear the rest of the screen. */ + if (sp->s_clear(sp)) + return (1); + + /* Save ex/vi terminal settings, and restore the original ones. */ + teardown = !ex_sleave(sp); + + /* + * Flush waiting messages (autowrite, for example) so the output + * matches historic practice. + */ + (void)sex_refresh(sp, sp->ep); + + /* Put out various messages. */ + if (p1 != NULL) + (void)write(STDOUT_FILENO, p1, strlen(p1)); + if (p2 != NULL) + (void)write(STDOUT_FILENO, p2, strlen(p2)); + + SIGBLOCK(sp->gp); + switch (pid = vfork()) { + case -1: /* Error. */ + SIGUNBLOCK(sp->gp); + + msgq(sp, M_SYSERR, "vfork"); + rval = 1; + break; + case 0: /* Utility. */ + /* The utility has default signal behavior. */ + sig_end(); + + if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL) + name = O_STR(sp, O_SHELL); + else + ++name; + execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL); + msgq(sp, M_ERR, "Error: execl: %s: %s", + O_STR(sp, O_SHELL), strerror(errno)); + _exit(127); + /* NOTREACHED */ + default: /* Parent. */ + SIGUNBLOCK(sp->gp); + + rval = proc_wait(sp, (long)pid, cmd, 0); + break; + } + + /* Restore ex/vi terminal settings. */ + if (teardown) + ex_rleave(sp); + + /* + * XXX + * Stat of the tty structures (see ex_sleave, ex_rleave) only give + * us 1-second resolution on the tty changes. A fast '!' command, + * e.g. ":!pwd" can beat us to the refresh. When there's better + * resolution from the stat(2) timers, this can go away. + */ + F_SET(sp, S_REFRESH); + + return (rval); +} diff --git a/usr.bin/vi/ex/ex_shift.c b/usr.bin/vi/ex/ex_shift.c new file mode 100644 index 0000000..41cb557 --- /dev/null +++ b/usr.bin/vi/ex/ex_shift.c @@ -0,0 +1,204 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_shift.c 8.14 (Berkeley) 3/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +enum which {LEFT, RIGHT}; +static int shift __P((SCR *, EXF *, EXCMDARG *, enum which)); + +int +ex_shiftl(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (shift(sp, ep, cmdp, LEFT)); +} + +int +ex_shiftr(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (shift(sp, ep, cmdp, RIGHT)); +} + +static int +shift(sp, ep, cmdp, rl) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; + enum which rl; +{ + recno_t from, to; + size_t blen, len, newcol, newidx, oldcol, oldidx, sw; + int curset; + char *p, *bp, *tbp; + + if (O_VAL(sp, O_SHIFTWIDTH) == 0) { + msgq(sp, M_INFO, "shiftwidth option set to 0"); + return (0); + } + + /* + * The historic version of vi permitted the user to string any number + * of '>' or '<' characters together, resulting in an indent of the + * appropriate levels. There's a special hack in ex_cmd() so that + * cmdp->argv[0] points to the string of '>' or '<' characters. + * + * Q: What's the difference between the people adding features + * to vi and the Girl Scouts? + * A: The Girl Scouts have mint cookies and adult supervision. + */ + for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p) + sw += O_VAL(sp, O_SHIFTWIDTH); + + GET_SPACE_RET(sp, bp, blen, 256); + + curset = 0; + for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) { + if ((p = file_gline(sp, ep, from, &len)) == NULL) + goto err; + if (!len) { + if (sp->lno == from) + curset = 1; + continue; + } + + /* + * Calculate the old indent amount and the number of + * characters it used. + */ + for (oldidx = 0, oldcol = 0; oldidx < len; ++oldidx) + if (p[oldidx] == ' ') + ++oldcol; + else if (p[oldidx] == '\t') + oldcol += O_VAL(sp, O_TABSTOP) - + oldcol % O_VAL(sp, O_TABSTOP); + else + break; + + /* Calculate the new indent amount. */ + if (rl == RIGHT) + newcol = oldcol + sw; + else { + newcol = oldcol < sw ? 0 : oldcol - sw; + if (newcol == oldcol) { + if (sp->lno == from) + curset = 1; + continue; + } + } + + /* Get a buffer that will hold the new line. */ + ADD_SPACE_RET(sp, bp, blen, newcol + len); + + /* + * Build a new indent string and count the number of + * characters it uses. + */ + for (tbp = bp, newidx = 0; + newcol >= O_VAL(sp, O_TABSTOP); ++newidx) { + *tbp++ = '\t'; + newcol -= O_VAL(sp, O_TABSTOP); + } + for (; newcol > 0; --newcol, ++newidx) + *tbp++ = ' '; + + /* Add the original line. */ + memmove(tbp, p + oldidx, len - oldidx); + + /* Set the replacement line. */ + if (file_sline(sp, ep, from, bp, (tbp + (len - oldidx)) - bp)) { +err: FREE_SPACE(sp, bp, blen); + return (1); + } + + /* + * !!! + * The shift command in historic vi had the usual bizarre + * collection of cursor semantics. If called from vi, the + * cursor was repositioned to the first non-blank character + * of the lowest numbered line shifted. If called from ex, + * the cursor was repositioned to the first non-blank of the + * highest numbered line shifted. Here, if the cursor isn't + * part of the set of lines that are moved, move it to the + * first non-blank of the last line shifted. (This makes + * ":3>>" in vi work reasonably.) If the cursor is part of + * the shifted lines, it doesn't get moved at all. This + * permits shifting of marked areas, i.e. ">'a." shifts the + * marked area twice, something that couldn't be done with + * historic vi. + */ + if (sp->lno == from) { + curset = 1; + if (newidx > oldidx) + sp->cno += newidx - oldidx; + else if (sp->cno >= oldidx - newidx) + sp->cno -= oldidx - newidx; + } + } + if (!curset) { + sp->lno = to; + sp->cno = 0; + (void)nonblank(sp, ep, to, &sp->cno); + } + + FREE_SPACE(sp, bp, blen); + + sp->rptlines[rl == RIGHT ? L_RSHIFT : L_LSHIFT] += + cmdp->addr2.lno - cmdp->addr1.lno + 1; + return (0); +} diff --git a/usr.bin/vi/ex/ex_source.c b/usr.bin/vi/ex/ex_source.c new file mode 100644 index 0000000..70b85b9 --- /dev/null +++ b/usr.bin/vi/ex/ex_source.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_source.c 8.5 (Berkeley) 8/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_source -- :source file + * Execute ex commands from a file. + */ +int +ex_source(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (ex_cfile(sp, ep, cmdp->argv[0]->bp, 0)); +} diff --git a/usr.bin/vi/ex/ex_stop.c b/usr.bin/vi/ex/ex_stop.c new file mode 100644 index 0000000..3487bbb --- /dev/null +++ b/usr.bin/vi/ex/ex_stop.c @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_stop.c 8.7 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "../sex/sex_screen.h" + +/* + * ex_stop -- :stop[!] + * :suspend[!] + * Suspend execution. + */ +int +ex_stop(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + /* For some strange reason, the force flag turns off autowrite. */ + if (!F_ISSET(cmdp, E_FORCE) && + F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE) && + file_write(sp, ep, NULL, NULL, NULL, FS_ALL)) + return (1); + return (sp->s_suspend(sp)); +} diff --git a/usr.bin/vi/ex/ex_subst.c b/usr.bin/vi/ex/ex_subst.c new file mode 100644 index 0000000..54b6ee8 --- /dev/null +++ b/usr.bin/vi/ex/ex_subst.c @@ -0,0 +1,1001 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_subst.c 8.57 (Berkeley) 8/7/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +#define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */ +#define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */ + +static __inline int regsub __P((SCR *, char *, + char **, size_t *, size_t *, regmatch_t [10])); +static int substitute __P((SCR *, EXF *, + EXCMDARG *, char *, regex_t *, u_int)); + +/* + * ex_substitute -- + * [line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]] + * + * Substitute on lines matching a pattern. + */ +int +ex_substitute(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + regex_t *re, lre; + size_t blen, len; + u_int flags; + int delim, eval, reflags, replaced; + char *bp, *ptrn, *rep, *p, *t; + + /* + * Skip leading white space. + * + * !!! + * Historic vi allowed any non-alphanumeric to serve as the + * substitution command delimiter. + * + * !!! + * If the arguments are empty, it's the same as &, i.e. we + * repeat the last substitution. + */ + for (p = cmdp->argv[0]->bp, + len = cmdp->argv[0]->len; len > 0; --len, ++p) { + if (!isblank(*p)) + break; + } + if (len == 0) + return (ex_subagain(sp, ep, cmdp)); + delim = *p++; + if (isalnum(delim)) + return (substitute(sp, ep, + cmdp, p, &sp->subre, SUB_MUSTSETR)); + + /* + * !!! + * The full-blown substitute command reset the remembered + * state of the 'c' and 'g' suffices. + */ + sp->c_suffix = sp->g_suffix = 0; + + /* + * Get the pattern string, toss escaped characters. + * + * !!! + * Historic vi accepted any of the following forms: + * + * :s/abc/def/ change "abc" to "def" + * :s/abc/def change "abc" to "def" + * :s/abc/ delete "abc" + * :s/abc delete "abc" + * + * QUOTING NOTE: + * + * Only toss an escape character if it escapes a delimiter. + * This means that "s/A/\\\\f" replaces "A" with "\\f". It + * would be nice to be more regular, i.e. for each layer of + * escaping a single escape character is removed, but that's + * not how the historic vi worked. + */ + for (ptrn = t = p;;) { + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + /* + * !!! + * Nul terminate the pattern string -- it's passed + * to regcomp which doesn't understand anything else. + */ + *t = '\0'; + break; + } + if (p[0] == '\\') + if (p[1] == delim) + ++p; + else if (p[1] == '\\') + *t++ = *p++; + *t++ = *p++; + } + + /* + * If the pattern string is empty, use the last RE (not just the + * last substitution RE). + */ + if (*ptrn == '\0') { + if (!F_ISSET(sp, S_SRE_SET)) { + msgq(sp, M_ERR, "No previous regular expression"); + return (1); + } + re = &sp->sre; + flags = 0; + } else { + /* Set RE flags. */ + reflags = 0; + if (O_ISSET(sp, O_EXTENDED)) + reflags |= REG_EXTENDED; + if (O_ISSET(sp, O_IGNORECASE)) + reflags |= REG_ICASE; + + /* Convert vi-style RE's to POSIX 1003.2 RE's. */ + if (re_conv(sp, &ptrn, &replaced)) + return (1); + + /* Compile the RE. */ + eval = regcomp(&lre, (char *)ptrn, reflags); + + /* Free up any allocated memory. */ + if (replaced) + FREE_SPACE(sp, ptrn, 0); + + if (eval) { + re_error(sp, eval, &lre); + return (1); + } + + /* + * Set saved RE. + * + * !!! + * Historic practice is that substitutes set the search + * direction as well as both substitute and search RE's. + */ + sp->searchdir = FORWARD; + sp->sre = lre; + F_SET(sp, S_SRE_SET); + sp->subre = lre; + F_SET(sp, S_SUBRE_SET); + + re = &lre; + flags = SUB_FIRST; + } + + /* + * Get the replacement string. + * + * The special character & (\& if O_MAGIC not set) matches the + * entire RE. No handling of & is required here, it's done by + * regsub(). + * + * The special character ~ (\~ if O_MAGIC not set) inserts the + * previous replacement string into this replacement string. + * Count ~'s to figure out how much space we need. We could + * special case nonexistent last patterns or whether or not + * O_MAGIC is set, but it's probably not worth the effort. + * + * QUOTING NOTE: + * + * Only toss an escape character if it escapes a delimiter or + * if O_MAGIC is set and it escapes a tilde. + * + * !!! + * If the entire replacement pattern is "%", then use the last + * replacement pattern. This semantic was added to vi in System + * V and then percolated elsewhere, presumably around the time + * that it was added to their version of ed(1). + */ + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + if (sp->repl != NULL) + FREE(sp->repl, sp->repl_len); + sp->repl = NULL; + sp->repl_len = 0; + } else if (p[0] == '%' && (p[1] == '\0' || p[1] == delim)) + p += p[1] == delim ? 2 : 1; + else { + for (rep = p, len = 0; + p[0] != '\0' && p[0] != delim; ++p, ++len) + if (p[0] == '~') + len += sp->repl_len; + GET_SPACE_RET(sp, bp, blen, len); + for (t = bp, len = 0, p = rep;;) { + if (p[0] == '\0' || p[0] == delim) { + if (p[0] == delim) + ++p; + break; + } + if (p[0] == '\\') { + if (p[1] == delim) + ++p; + else if (p[1] == '\\') { + *t++ = *p++; + ++len; + } else if (p[1] == '~') { + ++p; + if (!O_ISSET(sp, O_MAGIC)) + goto tilde; + } + } else if (p[0] == '~' && O_ISSET(sp, O_MAGIC)) { +tilde: ++p; + memmove(t, sp->repl, sp->repl_len); + t += sp->repl_len; + len += sp->repl_len; + continue; + } + *t++ = *p++; + ++len; + } + if ((sp->repl_len = len) != 0) { + if (sp->repl != NULL) + free(sp->repl); + if ((sp->repl = malloc(len)) == NULL) { + msgq(sp, M_SYSERR, NULL); + FREE_SPACE(sp, bp, blen); + return (1); + } + memmove(sp->repl, bp, len); + } + FREE_SPACE(sp, bp, blen); + } + return (substitute(sp, ep, cmdp, p, re, flags)); +} + +/* + * ex_subagain -- + * [line [,line]] & [cgr] [count] [#lp]] + * + * Substitute using the last substitute RE and replacement pattern. + */ +int +ex_subagain(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + if (!F_ISSET(sp, S_SUBRE_SET)) { + msgq(sp, M_ERR, "No previous regular expression"); + return (1); + } + return (substitute(sp, ep, cmdp, cmdp->argv[0]->bp, &sp->subre, 0)); +} + +/* + * ex_subtilde -- + * [line [,line]] ~ [cgr] [count] [#lp]] + * + * Substitute using the last RE and last substitute replacement pattern. + */ +int +ex_subtilde(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + if (!F_ISSET(sp, S_SRE_SET)) { + msgq(sp, M_ERR, "No previous regular expression"); + return (1); + } + return (substitute(sp, ep, cmdp, cmdp->argv[0]->bp, &sp->sre, 0)); +} + +/* + * The nasty part of the substitution is what happens when the replacement + * string contains newlines. It's a bit tricky -- consider the information + * that has to be retained for "s/f\(o\)o/^M\1^M\1/". The solution here is + * to build a set of newline offsets which we use to break the line up later, + * when the replacement is done. Don't change it unless you're pretty damned + * confident. + */ +#define NEEDNEWLINE(sp) { \ + if (sp->newl_len == sp->newl_cnt) { \ + sp->newl_len += 25; \ + REALLOC(sp, sp->newl, size_t *, \ + sp->newl_len * sizeof(size_t)); \ + if (sp->newl == NULL) { \ + sp->newl_len = 0; \ + return (1); \ + } \ + } \ +} + +#define BUILD(sp, l, len) { \ + if (lbclen + (len) > lblen) { \ + lblen += MAX(lbclen + (len), 256); \ + REALLOC(sp, lb, char *, lblen); \ + if (lb == NULL) { \ + lbclen = 0; \ + return (1); \ + } \ + } \ + memmove(lb + lbclen, l, len); \ + lbclen += len; \ +} + +#define NEEDSP(sp, len, pnt) { \ + if (lbclen + (len) > lblen) { \ + lblen += MAX(lbclen + (len), 256); \ + REALLOC(sp, lb, char *, lblen); \ + if (lb == NULL) { \ + lbclen = 0; \ + return (1); \ + } \ + pnt = lb + lbclen; \ + } \ +} + +/* + * substitute -- + * Do the substitution. This stuff is *really* tricky. There are + * lots of special cases, and general nastiness. Don't mess with it + * unless you're pretty confident. + */ +static int +substitute(sp, ep, cmdp, s, re, flags) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; + char *s; + regex_t *re; + u_int flags; +{ + MARK from, to; + recno_t elno, lno; + regmatch_t match[10]; + size_t blen, cnt, last, lbclen, lblen, len, llen, offset, saved_offset; + int cflag, lflag, nflag, pflag, rflag; + int didsub, do_eol_match, eflags, empty_ok, eval; + int linechanged, matched, quit, rval; + char *bp, *lb; + + /* + * !!! + * Historically, the 'g' and 'c' suffices were always toggled as flags, + * so ":s/A/B/" was the same as ":s/A/B/ccgg". If O_EDCOMPATIBLE was + * not set, they were initialized to 0 for all substitute commands. If + * O_EDCOMPATIBLE was set, they were initialized to 0 only if the user + * specified substitute/replacement patterns (see ex_substitute()). + */ + if (!O_ISSET(sp, O_EDCOMPATIBLE)) + sp->c_suffix = sp->g_suffix = 0; + + /* + * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but + * it only displayed the last change. I'd disallow them, but they are + * useful in combination with the [v]global commands. In the current + * model the problem is combining them with the 'c' flag -- the screen + * would have to flip back and forth between the confirm screen and the + * ex print screen, which would be pretty awful. We do display all + * changes, though, for what that's worth. + * + * !!! + * Historic vi was fairly strict about the order of "options", the + * count, and "flags". I'm somewhat fuzzy on the difference between + * options and flags, anyway, so this is a simpler approach, and we + * just take it them in whatever order the user gives them. (The ex + * usage statement doesn't reflect this.) + */ + cflag = lflag = nflag = pflag = rflag = 0; + for (lno = OOBLNO; *s != '\0'; ++s) + switch (*s) { + case ' ': + case '\t': + continue; + case '+': + ++cmdp->flagoff; + break; + case '-': + --cmdp->flagoff; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (lno != OOBLNO) + goto usage; + errno = 0; + lno = strtoul(s, &s, 10); + if (*s == '\0') /* Loop increment correction. */ + --s; + if (errno == ERANGE) { + if (lno == LONG_MAX) + msgq(sp, M_ERR, "Count overflow"); + else if (lno == LONG_MIN) + msgq(sp, M_ERR, "Count underflow"); + else + msgq(sp, M_SYSERR, NULL); + return (1); + } + /* + * In historic vi, the count was inclusive from the + * second address. + */ + cmdp->addr1.lno = cmdp->addr2.lno; + cmdp->addr2.lno += lno - 1; + break; + case '#': + nflag = 1; + break; + case 'c': + sp->c_suffix = !sp->c_suffix; + break; + case 'g': + sp->g_suffix = !sp->g_suffix; + break; + case 'l': + lflag = 1; + break; + case 'p': + pflag = 1; + break; + case 'r': + if (LF_ISSET(SUB_FIRST)) { + msgq(sp, M_ERR, + "Regular expression specified; r flag meaningless"); + return (1); + } + if (!F_ISSET(sp, S_SRE_SET)) { + msgq(sp, M_ERR, + "No previous regular expression"); + return (1); + } + rflag = 1; + re = &sp->sre; + break; + default: + goto usage; + } + + if (*s != '\0' || !rflag && LF_ISSET(SUB_MUSTSETR)) { +usage: msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); + } + + if (IN_VI_MODE(sp) && sp->c_suffix && (lflag || nflag || pflag)) { + msgq(sp, M_ERR, + "The #, l and p flags may not be combined with the c flag in vi mode"); + return (1); + } + + /* + * bp: if interactive, line cache + * blen: if interactive, line cache length + * lb: build buffer pointer. + * lbclen: current length of built buffer. + * lblen; length of build buffer. + */ + bp = lb = NULL; + blen = lbclen = lblen = 0; + + /* For each line... */ + for (matched = quit = 0, lno = cmdp->addr1.lno, + elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) { + + /* Someone's unhappy, time to stop. */ + if (INTERRUPTED(sp)) { + if (!F_ISSET(sp, S_GLOBAL)) + msgq(sp, M_INFO, "Interrupted"); + break; + } + + /* Get the line. */ + if ((s = file_gline(sp, ep, lno, &llen)) == NULL) { + GETLINE_ERR(sp, lno); + goto ret1; + } + + /* + * Make a local copy if doing confirmation -- when calling + * the confirm routine we're likely to lose the cached copy. + */ + if (sp->c_suffix) { + if (bp == NULL) { + GET_SPACE_RET(sp, bp, blen, llen); + } else + ADD_SPACE_RET(sp, bp, blen, llen); + memmove(bp, s, llen); + s = bp; + } + + /* Start searching from the beginning. */ + offset = 0; + len = llen; + + /* Reset the build buffer offset. */ + lbclen = 0; + + /* Reset empty match flag. */ + empty_ok = 1; + + /* + * We don't want to have to do a setline if the line didn't + * change -- keep track of whether or not this line changed. + * If doing confirmations, don't want to keep setting the + * line if change is refused -- keep track of substitutions. + */ + didsub = linechanged = 0; + + /* New line, do an EOL match. */ + do_eol_match = 1; + + /* It's not nul terminated, but we pretend it is. */ + eflags = REG_STARTEND; + + /* + * The search area is from s + offset to the EOL. + * + * Generally, match[0].rm_so is the offset of the start + * of the match from the start of the search, and offset + * is the offset of the start of the last search. + */ +nextmatch: match[0].rm_so = 0; + match[0].rm_eo = len; + + /* Get the next match. */ + eval = regexec(re, (char *)s + offset, 10, match, eflags); + + /* + * There wasn't a match or if there was an error, deal with + * it. If there was a previous match in this line, resolve + * the changes into the database. Otherwise, just move on. + */ + if (eval == REG_NOMATCH) + goto endmatch; + if (eval != 0) { + re_error(sp, eval, re); + goto ret1; + } + matched = 1; + + /* Only the first search can match an anchored expression. */ + eflags |= REG_NOTBOL; + + /* + * !!! + * It's possible to match 0-length strings -- for example, the + * command s;a*;X;, when matched against the string "aabb" will + * result in "XbXbX", i.e. the matches are "aa", the space + * between the b's and the space between the b's and the end of + * the string. There is a similar space between the beginning + * of the string and the a's. The rule that we use (because vi + * historically used it) is that any 0-length match, occurring + * immediately after a match, is ignored. Otherwise, the above + * example would have resulted in "XXbXbX". Another example is + * incorrectly using " *" to replace groups of spaces with one + * space. + * + * The way we do this is that if we just had a successful match, + * the starting offset does not skip characters, and the match + * is empty, ignore the match and move forward. If there's no + * more characters in the string, we were attempting to match + * after the last character, so quit. + */ + if (!empty_ok && match[0].rm_so == 0 && match[0].rm_eo == 0) { + empty_ok = 1; + if (len == 0) + goto endmatch; + BUILD(sp, s + offset, 1) + ++offset; + --len; + goto nextmatch; + } + + /* Confirm change. */ + if (sp->c_suffix) { + /* + * Set the cursor position for confirmation. Note, + * if we matched on a '$', the cursor may be past + * the end of line. + * + * XXX + * We may want to "fix" this in the confirm routine, + * if the confirm routine should be able to display + * a cursor past EOL. + */ + from.lno = to.lno = lno; + from.cno = match[0].rm_so + offset; + to.cno = match[0].rm_eo; + if (llen == 0) + from.cno = to.cno = 0; + else { + if (to.cno >= llen) + to.cno = llen - 1; + if (from.cno >= llen) + from.cno = llen - 1; + } + switch (sp->s_confirm(sp, ep, &from, &to)) { + case CONF_YES: + break; + case CONF_NO: + didsub = 0; + BUILD(sp, s +offset, match[0].rm_eo); + goto skip; + case CONF_QUIT: + /* Set the quit flag. */ + quit = 1; + + /* If interruptible, pass the info back. */ + if (F_ISSET(sp, S_INTERRUPTIBLE)) + F_SET(sp, S_INTERRUPTED); + + /* + * If any changes, resolve them, otherwise + * return to the main loop. + */ + goto endmatch; + } + } + + /* Copy the bytes before the match into the build buffer. */ + BUILD(sp, s + offset, match[0].rm_so); + + /* Substitute the matching bytes. */ + didsub = 1; + if (regsub(sp, s + offset, &lb, &lbclen, &lblen, match)) + goto ret1; + + /* Set the change flag so we know this line was modified. */ + linechanged = 1; + + /* Move past the matched bytes. */ +skip: offset += match[0].rm_eo; + len -= match[0].rm_eo; + + /* A match cannot be followed by an empty pattern. */ + empty_ok = 0; + + /* + * If doing a global change with confirmation, we have to + * update the screen. The basic idea is to store the line + * so the screen update routines can find it, and restart. + */ + if (didsub && sp->c_suffix && sp->g_suffix) { + /* + * The new search offset will be the end of the + * modified line. + */ + saved_offset = lbclen; + + /* Copy the rest of the line. */ + if (len) + BUILD(sp, s + offset, len) + + /* Set the new offset. */ + offset = saved_offset; + + /* Store inserted lines, adjusting the build buffer. */ + last = 0; + if (sp->newl_cnt) { + for (cnt = 0; + cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) { + if (file_iline(sp, ep, lno, + lb + last, sp->newl[cnt] - last)) + goto ret1; + last = sp->newl[cnt] + 1; + ++sp->rptlines[L_ADDED]; + } + lbclen -= last; + offset -= last; + sp->newl_cnt = 0; + } + + /* Store and retrieve the line. */ + if (file_sline(sp, ep, lno, lb + last, lbclen)) + goto ret1; + if ((s = file_gline(sp, ep, lno, &llen)) == NULL) { + GETLINE_ERR(sp, lno); + goto ret1; + } + ADD_SPACE_RET(sp, bp, blen, llen) + memmove(bp, s, llen); + s = bp; + len = llen - offset; + + /* Restart the build. */ + lbclen = 0; + BUILD(sp, s, offset); + + /* + * If we haven't already done the after-the-string + * match, do one. Set REG_NOTEOL so the '$' pattern + * only matches once. + */ + if (!do_eol_match) + goto endmatch; + if (offset == len) { + do_eol_match = 0; + eflags |= REG_NOTEOL; + } + goto nextmatch; + } + + /* + * If it's a global: + * + * If at the end of the string, do a test for the after + * the string match. Set REG_NOTEOL so the '$' pattern + * only matches once. + */ + if (sp->g_suffix && do_eol_match) { + if (len == 0) { + do_eol_match = 0; + eflags |= REG_NOTEOL; + } + goto nextmatch; + } + +endmatch: if (!linechanged) + continue; + + /* Copy any remaining bytes into the build buffer. */ + if (len) + BUILD(sp, s + offset, len) + + /* Store inserted lines, adjusting the build buffer. */ + last = 0; + if (sp->newl_cnt) { + for (cnt = 0; + cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) { + if (file_iline(sp, ep, + lno, lb + last, sp->newl[cnt] - last)) + goto ret1; + last = sp->newl[cnt] + 1; + ++sp->rptlines[L_ADDED]; + } + lbclen -= last; + sp->newl_cnt = 0; + } + + /* Store the changed line. */ + if (file_sline(sp, ep, lno, lb + last, lbclen)) + goto ret1; + + /* Update changed line counter. */ + if (sp->rptlchange != lno) { + sp->rptlchange = lno; + ++sp->rptlines[L_CHANGED]; + } + + /* + * !!! + * Display as necessary. Historic practice is to only + * display the last line of a line split into multiple + * lines. + */ + if (lflag || nflag || pflag) { + from.lno = to.lno = lno; + from.cno = to.cno = 0; + if (lflag) + ex_print(sp, ep, &from, &to, E_F_LIST); + if (nflag) + ex_print(sp, ep, &from, &to, E_F_HASH); + if (pflag) + ex_print(sp, ep, &from, &to, E_F_PRINT); + } + + if (!sp->c_suffix) + sp->lno = lno; + + /* + * !!! + * Move the cursor to the last line changed. + */ + if (!sp->c_suffix) + sp->lno = lno; + } + + /* + * !!! + * Move the cursor to the first non-blank of the last line change. + * + * XXX + * This is NOT backward compatible with historic vi, which always + * moved to the last line actually changed. + */ + if (!sp->c_suffix) { + sp->cno = 0; + (void)nonblank(sp, ep, sp->lno, &sp->cno); + } + + /* + * If not in a global command, and nothing matched, say so. + * Else, if none of the lines displayed, put something up. + */ + if (!matched) { + if (!F_ISSET(sp, S_GLOBAL)) + msgq(sp, M_INFO, "No match found"); + } else if (!lflag && !nflag && !pflag) + F_SET(EXP(sp), EX_AUTOPRINT); + + rval = 0; + if (0) { +ret1: rval = 1; + } + + if (bp != NULL) + FREE_SPACE(sp, bp, blen); + if (lb != NULL) + free(lb); + return (rval); +} + +/* + * regsub -- + * Do the substitution for a regular expression. + */ +static __inline int +regsub(sp, ip, lbp, lbclenp, lblenp, match) + SCR *sp; + char *ip; /* Input line. */ + char **lbp; + size_t *lbclenp, *lblenp; + regmatch_t match[10]; +{ + enum { C_NOTSET, C_LOWER, C_ONELOWER, C_ONEUPPER, C_UPPER } conv; + size_t lbclen, lblen; /* Local copies. */ + size_t mlen; /* Match length. */ + size_t rpl; /* Remaining replacement length. */ + char *rp; /* Replacement pointer. */ + int ch; + int no; /* Match replacement offset. */ + char *p, *t; /* Buffer pointers. */ + char *lb; /* Local copies. */ + + lb = *lbp; /* Get local copies. */ + lbclen = *lbclenp; + lblen = *lblenp; + + /* + * QUOTING NOTE: + * + * There are some special sequences that vi provides in the + * replacement patterns. + * & string the RE matched (\& if nomagic set) + * \# n-th regular subexpression + * \E end \U, \L conversion + * \e end \U, \L conversion + * \l convert the next character to lower-case + * \L convert to lower-case, until \E, \e, or end of replacement + * \u convert the next character to upper-case + * \U convert to upper-case, until \E, \e, or end of replacement + * + * Otherwise, since this is the lowest level of replacement, discard + * all escape characters. This (hopefully) follows historic practice. + */ +#define ADDCH(ch) { \ + CHAR_T __ch = (ch); \ + u_int __value = KEY_VAL(sp, __ch); \ + if (__value == K_CR || __value == K_NL) { \ + NEEDNEWLINE(sp); \ + sp->newl[sp->newl_cnt++] = lbclen; \ + } else if (conv != C_NOTSET) { \ + switch (conv) { \ + case C_ONELOWER: \ + conv = C_NOTSET; \ + /* FALLTHROUGH */ \ + case C_LOWER: \ + if (isupper(__ch)) \ + __ch = tolower(__ch); \ + break; \ + case C_ONEUPPER: \ + conv = C_NOTSET; \ + /* FALLTHROUGH */ \ + case C_UPPER: \ + if (islower(__ch)) \ + __ch = toupper(__ch); \ + break; \ + default: \ + abort(); \ + } \ + } \ + NEEDSP(sp, 1, p); \ + *p++ = __ch; \ + ++lbclen; \ +} + conv = C_NOTSET; + for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) { + switch (ch = *rp++) { + case '&': + if (O_ISSET(sp, O_MAGIC)) { + no = 0; + goto subzero; + } + break; + case '\\': + if (rpl == 0) + break; + --rpl; + switch (ch = *rp) { + case '&': + ++rp; + if (!O_ISSET(sp, O_MAGIC)) { + no = 0; + goto subzero; + } + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + no = *rp++ - '0'; +subzero: if (match[no].rm_so == -1 || + match[no].rm_eo == -1) + break; + mlen = match[no].rm_eo - match[no].rm_so; + for (t = ip + match[no].rm_so; mlen--; ++t) + ADDCH(*t); + continue; + case 'e': + case 'E': + ++rp; + conv = C_NOTSET; + continue; + case 'l': + ++rp; + conv = C_ONELOWER; + continue; + case 'L': + ++rp; + conv = C_LOWER; + continue; + case 'u': + ++rp; + conv = C_ONEUPPER; + continue; + case 'U': + ++rp; + conv = C_UPPER; + continue; + default: + ++rp; + break; + } + } + ADDCH(ch); + } + + *lbp = lb; /* Update caller's information. */ + *lbclenp = lbclen; + *lblenp = lblen; + return (0); +} diff --git a/usr.bin/vi/ex/ex_tag.c b/usr.bin/vi/ex/ex_tag.c new file mode 100644 index 0000000..0bb8c3e --- /dev/null +++ b/usr.bin/vi/ex/ex_tag.c @@ -0,0 +1,905 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David Hitz of Auspex Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_tag.c 8.43 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "tag.h" + +static char *binary_search __P((char *, char *, char *)); +static int compare __P((char *, char *, char *)); +static char *linear_search __P((char *, char *, char *)); +static int search __P((SCR *, char *, char *, char **)); +static int tag_get __P((SCR *, char *, char **, char **, char **)); + +/* + * ex_tagfirst -- + * The tag code can be entered from main, i.e. "vi -t tag". + */ +int +ex_tagfirst(sp, tagarg) + SCR *sp; + char *tagarg; +{ + FREF *frp; + MARK m; + long tl; + u_int flags; + int sval; + char *p, *tag, *name, *search; + + /* Taglength may limit the number of characters. */ + if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(tagarg) > tl) + tagarg[tl] = '\0'; + + /* Get the tag information. */ + if (tag_get(sp, tagarg, &tag, &name, &search)) + return (1); + + /* Create the file entry. */ + if ((frp = file_add(sp, name)) == NULL) + return (1); + if (file_init(sp, frp, NULL, 0)) + return (1); + + /* + * !!! + * The historic tags file format (from a long, long time ago...) + * used a line number, not a search string. I got complaints, so + * people are still using the format. + */ + if (isdigit(search[0])) { + m.lno = atoi(search); + m.cno = 0; + } else { + /* + * Search for the tag; cheap fallback for C functions if + * the name is the same but the arguments have changed. + */ + m.lno = 1; + m.cno = 0; + flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM; + sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags); + if (sval && (p = strrchr(search, '(')) != NULL) { + p[1] = '\0'; + sval = f_search(sp, sp->ep, + &m, &m, search, NULL, &flags); + } + if (sval) + msgq(sp, M_ERR, "%s: search pattern not found", tag); + } + + /* Set up the screen. */ + frp->lno = m.lno; + frp->cno = m.cno; + F_SET(frp, FR_CURSORSET); + + /* Might as well make this the default tag. */ + if ((EXP(sp)->tlast = strdup(tagarg)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + return (0); +} + +/* Free a tag or tagf structure from a queue. */ +#define FREETAG(tp) { \ + TAILQ_REMOVE(&exp->tagq, (tp), q); \ + if ((tp)->search != NULL) \ + free((tp)->search); \ + FREE((tp), sizeof(TAGF)); \ +} +#define FREETAGF(tfp) { \ + TAILQ_REMOVE(&exp->tagfq, (tfp), q); \ + free((tfp)->name); \ + FREE((tfp), sizeof(TAGF)); \ +} + +/* + * ex_tagpush -- :tag [file] + * Move to a new tag. + * + * The tags stacks in nvi are a bit tricky. Each tag contains a file name, + * search string, and line/column numbers. The search string is only used + * for the first access and for user display. The first record on the stack + * is the place where we first did a tag, so it has no search string. The + * second record is the first tag, and so on. Note, this means that the + * "current" tag is always on the stack. Each tag has a line/column which is + * the location from which the user tagged the following TAG entry, and which + * is used as the return location. + */ +int +ex_tagpush(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + enum {TC_CHANGE, TC_CURRENT} which; + EX_PRIVATE *exp; + FREF *frp; + MARK m; + TAG *tp; + u_int flags; + int sval; + long tl; + char *name, *p, *search, *tag; + + exp = EXP(sp); + switch (cmdp->argc) { + case 1: + if (exp->tlast != NULL) + FREE(exp->tlast, strlen(exp->tlast) + 1); + if ((exp->tlast = strdup(cmdp->argv[0]->bp)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + break; + case 0: + if (exp->tlast == NULL) { + msgq(sp, M_ERR, "No previous tag entered"); + return (1); + } + break; + default: + abort(); + } + + /* Taglength may limit the number of characters. */ + if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(exp->tlast) > tl) + exp->tlast[tl] = '\0'; + + /* Get the tag information. */ + if (tag_get(sp, exp->tlast, &tag, &name, &search)) + return (1); + + /* Get the (possibly new) FREF structure. */ + if ((frp = file_add(sp, name)) == NULL) + goto err; + + if (sp->frp == frp) + which = TC_CURRENT; + else { + if (file_m1(sp, sp->ep, + F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE)) + goto err; + which = TC_CHANGE; + } + + /* + * Get a tag structure -- if this is the first tag, push it on the + * stack as a placeholder and get another tag structure. Set the + * line/column of the most recent element on the stack to be the + * current values, including the file pointer. Then push the new + * TAG onto the stack with the new file and search string for user + * display. + */ + CALLOC(sp, tp, TAG *, 1, sizeof(TAG)); + if (tp != NULL && exp->tagq.tqh_first == NULL) { + TAILQ_INSERT_HEAD(&exp->tagq, tp, q); + CALLOC(sp, tp, TAG *, 1, sizeof(TAG)); + } + if (exp->tagq.tqh_first != NULL) { + exp->tagq.tqh_first->frp = sp->frp; + exp->tagq.tqh_first->lno = sp->lno; + exp->tagq.tqh_first->cno = sp->cno; + } + if (tp != NULL) { + if ((tp->search = strdup(search)) == NULL) + msgq(sp, M_SYSERR, NULL); + else + tp->slen = strlen(search); + tp->frp = frp; + TAILQ_INSERT_HEAD(&exp->tagq, tp, q); + } + + /* Switch files. */ + if (which == TC_CHANGE && file_init(sp, frp, NULL, 0)) { + if (tp != NULL) + FREETAG(tp); + /* Handle special, first-tag case. */ + if (exp->tagq.tqh_first->q.tqe_next == NULL) + TAILQ_REMOVE(&exp->tagq, exp->tagq.tqh_first, q); +err: free(tag); + return (1); + } + + /* + * !!! + * Historic vi accepted a line number as well as a search + * string, and people are apparently still using the format. + */ + if (isdigit(search[0])) { + m.lno = atoi(search); + m.cno = 0; + sval = 0; + } else { + /* + * Search for the tag; cheap fallback for C functions + * if the name is the same but the arguments have changed. + */ + m.lno = 1; + m.cno = 0; + flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM; + sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags); + if (sval && (p = strrchr(search, '(')) != NULL) { + p[1] = '\0'; + sval = f_search(sp, sp->ep, + &m, &m, search, NULL, &flags); + p[1] = '('; + } + if (sval) + msgq(sp, M_ERR, "%s: search pattern not found", tag); + } + free(tag); + + switch (which) { + case TC_CHANGE: + frp->lno = m.lno; + frp->cno = m.cno; + F_SET(frp, FR_CURSORSET); + F_SET(sp, S_FSWITCH); + break; + case TC_CURRENT: + if (sval) + return (1); + sp->lno = m.lno; + sp->cno = m.cno; + break; + } + return (0); +} + +/* + * ex_tagpop -- :tagp[op][!] [number | file] + * Pop the tag stack. + */ +int +ex_tagpop(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + EX_PRIVATE *exp; + TAG *ntp, *tp; + long off; + size_t arglen; + char *arg, *p, *t; + + /* Check for an empty stack. */ + exp = EXP(sp); + if (exp->tagq.tqh_first == NULL) { + msgq(sp, M_INFO, "The tags stack is empty"); + return (1); + } + + switch (cmdp->argc) { + case 0: /* Pop one tag. */ + ntp = exp->tagq.tqh_first; + break; + case 1: /* Name or number. */ + arg = cmdp->argv[0]->bp; + off = strtol(arg, &p, 10); + if (*p == '\0') { + if (off < 1) + return (0); + for (tp = exp->tagq.tqh_first; + tp != NULL && --off > 1; tp = tp->q.tqe_next); + if (tp == NULL) { + msgq(sp, M_ERR, +"Less than %s entries on the tags stack; use :display to see the tags stack", + arg); + return (1); + } + ntp = tp; + } else { + arglen = strlen(arg); + for (tp = exp->tagq.tqh_first; + tp != NULL; ntp = tp, tp = tp->q.tqe_next) { + /* Use the user's original file name. */ + p = tp->frp->name; + if ((t = strrchr(p, '/')) == NULL) + t = p; + else + ++t; + if (!strncmp(arg, t, arglen)) + break; + } + if (tp == NULL) { + msgq(sp, M_ERR, +"No file named %s on the tags stack; use :display to see the tags stack", + arg); + return (1); + } + } + break; + default: + abort(); + } + + /* Update the cursor from the saved TAG information. */ + tp = ntp->q.tqe_next; + if (tp->frp == sp->frp) { + sp->lno = tp->lno; + sp->cno = tp->cno; + } else { + if (file_m1(sp, ep, + F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE)) + return (1); + if (file_init(sp, tp->frp, NULL, 0)) + return (1); + + tp->frp->lno = tp->lno; + tp->frp->cno = tp->cno; + F_SET(sp->frp, FR_CURSORSET); + + F_SET(sp, S_FSWITCH); + } + + /* Pop entries off the queue up to ntp. */ + for (;;) { + tp = exp->tagq.tqh_first; + FREETAG(tp); + if (tp == ntp) + break; + } + + /* If returning to the first tag, the stack is now empty. */ + if (exp->tagq.tqh_first->q.tqe_next == NULL) + TAILQ_REMOVE(&exp->tagq, exp->tagq.tqh_first, q); + return (0); +} + +/* + * ex_tagtop -- :tagt[op][!] + * Clear the tag stack. + */ +int +ex_tagtop(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + EX_PRIVATE *exp; + TAG *tp; + + /* Find oldest saved information. */ + exp = EXP(sp); + for (tp = exp->tagq.tqh_first; + tp != NULL && tp->q.tqe_next != NULL; tp = tp->q.tqe_next); + if (tp == NULL) { + msgq(sp, M_INFO, "The tags stack is empty"); + return (1); + } + + /* If not switching files, it's easy; else do the work. */ + if (tp->frp == sp->frp) { + sp->lno = tp->lno; + sp->cno = tp->cno; + } else { + if (file_m1(sp, sp->ep, + F_ISSET(cmdp, E_FORCE), FS_ALL | FS_POSSIBLE)) + return (1); + if (file_init(sp, tp->frp, NULL, 0)) + return (1); + + tp->frp->lno = tp->lno; + tp->frp->cno = tp->cno; + + F_SET(sp->frp, FR_CURSORSET); + F_SET(sp, S_FSWITCH); + } + + /* Empty out the queue. */ + while ((tp = exp->tagq.tqh_first) != NULL) + FREETAG(tp); + return (0); +} + +/* + * ex_tagdisplay -- + * Display the list of tags. + */ +int +ex_tagdisplay(sp, ep) + SCR *sp; + EXF *ep; +{ + EX_PRIVATE *exp; + TAG *tp; + size_t len, maxlen; + int cnt; + char *name; + + exp = EXP(sp); + if ((tp = exp->tagq.tqh_first) == NULL) { + (void)ex_printf(EXCOOKIE, "No tags to display.\n"); + return (0); + } + + /* + * Figure out the formatting. MNOC is the maximum + * number of file name columns before we split the line. + */ +#define MNOC 15 + for (maxlen = 0, + tp = exp->tagq.tqh_first; tp != NULL; tp = tp->q.tqe_next) { + len = strlen(name = tp->frp->name); /* The original name. */ + if (maxlen < len && len < MNOC) + maxlen = len; + } + + for (cnt = 1, tp = exp->tagq.tqh_first; tp != NULL; + ++cnt, tp = tp->q.tqe_next) { + len = strlen(name = tp->frp->name); /* The original name. */ + if (len > maxlen || len + tp->slen > sp->cols) + if (tp == NULL || tp->search == NULL) + (void)ex_printf(EXCOOKIE, + "%2d %s\n", cnt, name); + else + (void)ex_printf(EXCOOKIE, + "%2d %s\n** %*.*s %s\n", cnt, name, + (int)maxlen, (int)maxlen, "", tp->search); + else + if (tp == NULL || tp->search == NULL) + (void)ex_printf(EXCOOKIE, "%2d %*.*s\n", + cnt, (int)maxlen, (int)len, name); + else + (void)ex_printf(EXCOOKIE, "%2d %*.*s %s\n", + cnt, (int)maxlen, (int)len, name, + tp->search); + } + return (0); +} + +/* + * ex_tagalloc -- + * Create a new list of tag files. + */ +int +ex_tagalloc(sp, str) + SCR *sp; + char *str; +{ + EX_PRIVATE *exp; + TAGF *tp; + size_t len; + char *p, *t; + + /* Free current queue. */ + exp = EXP(sp); + while ((tp = exp->tagfq.tqh_first) != NULL) + FREETAGF(tp); + + /* Create new queue. */ + for (p = t = str;; ++p) { + if (*p == '\0' || isblank(*p)) { + if ((len = p - t) > 1) { + MALLOC_RET(sp, tp, TAGF *, sizeof(TAGF)); + MALLOC(sp, tp->name, char *, len + 1); + if (tp->name == NULL) { + FREE(tp, sizeof(TAGF)); + return (1); + } + memmove(tp->name, t, len); + tp->name[len] = '\0'; + tp->flags = 0; + TAILQ_INSERT_TAIL(&exp->tagfq, tp, q); + } + t = p + 1; + } + if (*p == '\0') + break; + } + return (0); +} + /* Free previous queue. */ +/* + * ex_tagfree -- + * Free the tags file list. + */ +int +ex_tagfree(sp) + SCR *sp; +{ + EX_PRIVATE *exp; + TAG *tp; + TAGF *tfp; + + /* Free up tag information. */ + exp = EXP(sp); + while ((tp = exp->tagq.tqh_first) != NULL) + FREETAG(tp); + while ((tfp = exp->tagfq.tqh_first) != NULL) + FREETAGF(tfp); + if (exp->tlast != NULL) + free(exp->tlast); + return (0); +} + +/* + * ex_tagcopy -- + * Copy a screen's tag structures. + */ +int +ex_tagcopy(orig, sp) + SCR *orig, *sp; +{ + EX_PRIVATE *oexp, *nexp; + TAG *ap, *tp; + TAGF *atfp, *tfp; + + /* Copy tag stack. */ + oexp = EXP(orig); + nexp = EXP(sp); + for (ap = oexp->tagq.tqh_first; ap != NULL; ap = ap->q.tqe_next) { + MALLOC(sp, tp, TAG *, sizeof(TAG)); + if (tp == NULL) + goto nomem; + *tp = *ap; + if (ap->search != NULL && + (tp->search = strdup(ap->search)) == NULL) + goto nomem; + TAILQ_INSERT_TAIL(&nexp->tagq, tp, q); + } + + /* Copy list of tag files. */ + for (atfp = oexp->tagfq.tqh_first; + atfp != NULL; atfp = atfp->q.tqe_next) { + MALLOC(sp, tfp, TAGF *, sizeof(TAGF)); + if (tfp == NULL) + goto nomem; + *tfp = *atfp; + if ((tfp->name = strdup(atfp->name)) == NULL) + goto nomem; + TAILQ_INSERT_TAIL(&nexp->tagfq, tfp, q); + } + + /* Copy the last tag. */ + if (oexp->tlast != NULL && + (nexp->tlast = strdup(oexp->tlast)) == NULL) { +nomem: msgq(sp, M_SYSERR, NULL); + return (1); + } + return (0); +} + +/* + * tag_get -- + * Get a tag from the tags files. + */ +static int +tag_get(sp, tag, tagp, filep, searchp) + SCR *sp; + char *tag, **tagp, **filep, **searchp; +{ + struct stat sb; + EX_PRIVATE *exp; + TAGF *tfp; + size_t plen, slen, tlen; + int dne; + char *p, pbuf[MAXPATHLEN]; + + /* + * Find the tag, only display missing file messages once, and + * then only if we didn't find the tag. + */ + dne = 0; + exp = EXP(sp); + for (p = NULL, tfp = exp->tagfq.tqh_first; + tfp != NULL && p == NULL; tfp = tfp->q.tqe_next) { + errno = 0; + F_CLR(tfp, TAGF_DNE); + if (search(sp, tfp->name, tag, &p)) + if (errno == ENOENT) { + if (!F_ISSET(tfp, TAGF_DNE_WARN)) { + dne = 1; + F_SET(tfp, TAGF_DNE); + } + } else + msgq(sp, M_SYSERR, tfp->name); + else + if (p != NULL) + break; + } + + if (p == NULL) { + msgq(sp, M_ERR, "%s: tag not found", tag); + if (dne) + for (tfp = exp->tagfq.tqh_first; + tfp != NULL; tfp = tfp->q.tqe_next) + if (F_ISSET(tfp, TAGF_DNE)) { + errno = ENOENT; + msgq(sp, M_SYSERR, tfp->name); + F_SET(tfp, TAGF_DNE_WARN); + } + return (1); + } + + /* + * Set the return pointers; tagp points to the tag, and, incidentally + * the allocated string, filep points to the file name, and searchp + * points to the search string. All three are nul-terminated. + */ + for (*tagp = p; *p && !isblank(*p); ++p); + if (*p == '\0') + goto malformed; + for (*p++ = '\0'; isblank(*p); ++p); + for (*filep = p; *p && !isblank(*p); ++p); + if (*p == '\0') + goto malformed; + for (*p++ = '\0'; isblank(*p); ++p); + *searchp = p; + if (*p == '\0') { +malformed: free(*tagp); + msgq(sp, M_ERR, "%s: corrupted tag in %s", tag, tfp->name); + return (1); + } + + /* + * !!! + * If the tag file path is a relative path, see if it exists. If it + * doesn't, look relative to the tags file path. It's okay for a tag + * file to not exist, and, historically, vi simply displayed a "new" + * file. However, if the path exists relative to the tag file, it's + * pretty clear what's happening, so we may as well do it right. + */ + if ((*filep)[0] != '/' + && stat(*filep, &sb) && (p = strrchr(tfp->name, '/')) != NULL) { + *p = '\0'; + plen = snprintf(pbuf, sizeof(pbuf), "%s/%s", tfp->name, *filep); + *p = '/'; + if (stat(pbuf, &sb) == 0) { + slen = strlen(*searchp); + tlen = strlen(*tagp); + MALLOC(sp, p, char *, plen + slen + tlen + 5); + if (p != NULL) { + memmove(p, *tagp, tlen); + free(*tagp); + *tagp = p; + *(p += tlen) = '\0'; + memmove(++p, pbuf, plen); + *filep = p; + *(p += plen) = '\0'; + memmove(++p, *searchp, slen); + *searchp = p; + *(p += slen) = '\0'; + } + } + } + return (0); +} + +#define EQUAL 0 +#define GREATER 1 +#define LESS (-1) + +/* + * search -- + * Search a file for a tag. + */ +static int +search(sp, name, tname, tag) + SCR *sp; + char *name, *tname, **tag; +{ + struct stat sb; + int fd, len; + char *endp, *back, *front, *map, *p; + + if ((fd = open(name, O_RDONLY, 0)) < 0) + return (1); + + /* + * XXX + * We'd like to test if the file is too big to mmap. Since we don't + * know what size or type off_t's or size_t's are, what the largest + * unsigned integral type is, or what random insanity the local C + * compiler will perpetrate, doing the comparison in a portable way + * is flatly impossible. Hope that malloc fails if the file is too + * large. + */ + if (fstat(fd, &sb) || (map = mmap(NULL, (size_t)sb.st_size, + PROT_READ, MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) { + (void)close(fd); + return (1); + } + front = map; + back = front + sb.st_size; + + front = binary_search(tname, front, back); + front = linear_search(tname, front, back); + + if (front == NULL || (endp = strchr(front, '\n')) == NULL) { + *tag = NULL; + goto done; + } + + len = endp - front; + MALLOC(sp, p, char *, len + 1); + if (p == NULL) { + *tag = NULL; + goto done; + } + memmove(p, front, len); + p[len] = '\0'; + *tag = p; + +done: if (munmap(map, (size_t)sb.st_size)) + msgq(sp, M_SYSERR, "munmap"); + if (close(fd)) + msgq(sp, M_SYSERR, "close"); + return (0); +} + +/* + * Binary search for "string" in memory between "front" and "back". + * + * This routine is expected to return a pointer to the start of a line at + * *or before* the first word matching "string". Relaxing the constraint + * this way simplifies the algorithm. + * + * Invariants: + * front points to the beginning of a line at or before the first + * matching string. + * + * back points to the beginning of a line at or after the first + * matching line. + * + * Base of the Invariants. + * front = NULL; + * back = EOF; + * + * Advancing the Invariants: + * + * p = first newline after halfway point from front to back. + * + * If the string at "p" is not greater than the string to match, + * p is the new front. Otherwise it is the new back. + * + * Termination: + * + * The definition of the routine allows it return at any point, + * since front is always at or before the line to print. + * + * In fact, it returns when the chosen "p" equals "back". This + * implies that there exists a string is least half as long as + * (back - front), which in turn implies that a linear search will + * be no more expensive than the cost of simply printing a string or two. + * + * Trying to continue with binary search at this point would be + * more trouble than it's worth. + */ +#define SKIP_PAST_NEWLINE(p, back) while (p < back && *p++ != '\n'); + +static char * +binary_search(string, front, back) + register char *string, *front, *back; +{ + register char *p; + + p = front + (back - front) / 2; + SKIP_PAST_NEWLINE(p, back); + + while (p != back) { + if (compare(string, p, back) == GREATER) + front = p; + else + back = p; + p = front + (back - front) / 2; + SKIP_PAST_NEWLINE(p, back); + } + return (front); +} + +/* + * Find the first line that starts with string, linearly searching from front + * to back. + * + * Return NULL for no such line. + * + * This routine assumes: + * + * o front points at the first character in a line. + * o front is before or at the first line to be printed. + */ +static char * +linear_search(string, front, back) + char *string, *front, *back; +{ + while (front < back) { + switch (compare(string, front, back)) { + case EQUAL: /* Found it. */ + return (front); + case LESS: /* No such string. */ + return (NULL); + case GREATER: /* Keep going. */ + break; + } + SKIP_PAST_NEWLINE(front, back); + } + return (NULL); +} + +/* + * Return LESS, GREATER, or EQUAL depending on how the string1 compares + * with string2 (s1 ??? s2). + * + * o Matches up to len(s1) are EQUAL. + * o Matches up to len(s2) are GREATER. + * + * The string "s1" is null terminated. The string s2 is '\t', space, (or + * "back") terminated. + * + * !!! + * Reasonably modern ctags programs use tabs as separators, not spaces. + * However, historic programs did use spaces, and, I got complaints. + */ +static int +compare(s1, s2, back) + register char *s1, *s2, *back; +{ + for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2) + if (*s1 != *s2) + return (*s1 < *s2 ? LESS : GREATER); + return (*s1 ? GREATER : s2 < back && + (*s2 != '\t' && *s2 != ' ') ? LESS : EQUAL); +} diff --git a/usr.bin/vi/ex/ex_undo.c b/usr.bin/vi/ex/ex_undo.c new file mode 100644 index 0000000..4331696 --- /dev/null +++ b/usr.bin/vi/ex/ex_undo.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_undo.c 8.7 (Berkeley) 8/9/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_undo -- u + * Undo the last change. + */ +int +ex_undo(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + MARK m; + + /* + * !!! + * Historic undo always set the previous context mark. + */ + m.lno = sp->lno; + m.cno = sp->cno; + if (mark_set(sp, ep, ABSMARK1, &m, 1)) + return (1); + + /* + * !!! + * Multiple undo isn't available in ex, as there's no '.' command. + * Whether 'u' is undo or redo is toggled each time, unless there + * was a change since the last undo, in which case it's an undo. + */ + if (!F_ISSET(ep, F_UNDO)) { + F_SET(ep, F_UNDO); + ep->lundo = FORWARD; + } + switch (ep->lundo) { + case BACKWARD: + if (log_forward(sp, ep, &m)) + return (1); + ep->lundo = FORWARD; + break; + case FORWARD: + if (log_backward(sp, ep, &m)) + return (1); + ep->lundo = BACKWARD; + break; + case NOTSET: + abort(); + } + sp->lno = m.lno; + sp->cno = m.cno; + return (0); +} diff --git a/usr.bin/vi/ex/ex_usage.c b/usr.bin/vi/ex/ex_usage.c new file mode 100644 index 0000000..b6031b5 --- /dev/null +++ b/usr.bin/vi/ex/ex_usage.c @@ -0,0 +1,197 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_usage.c 8.19 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "../vi/vcmd.h" + +/* + * ex_help -- :help + * Display help message. + */ +int +ex_help(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + (void)ex_printf(EXCOOKIE, + "To see the list of vi commands, enter \":viusage<CR>\"\n"); + (void)ex_printf(EXCOOKIE, + "To see the list of ex commands, enter \":exusage<CR>\"\n"); + (void)ex_printf(EXCOOKIE, + "For an ex command usage statement enter \":exusage [cmd]<CR>\"\n"); + (void)ex_printf(EXCOOKIE, + "For a vi key usage statement enter \":viusage [key]<CR>\"\n"); + (void)ex_printf(EXCOOKIE, "To exit, enter \":q!\"\n"); + return (0); +} + +/* + * ex_usage -- :exusage [cmd] + * Display ex usage strings. + */ +int +ex_usage(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + ARGS *ap; + EXCMDLIST const *cp; + char *name; + + switch (cmdp->argc) { + case 1: + ap = cmdp->argv[0]; + for (cp = cmds; cp->name != NULL && + memcmp(ap->bp, cp->name, ap->len); ++cp); + if (cp->name == NULL) + (void)ex_printf(EXCOOKIE, + "The %.*s command is unknown", + (int)ap->len, ap->bp); + else { + (void)ex_printf(EXCOOKIE, + "Command: %s\n Usage: %s\n", cp->help, cp->usage); + /* + * !!! + * The "visual" command has two modes, one from ex, + * one from the vi colon line. Don't ask. + */ + if (cp != &cmds[C_VISUAL_EX] && + cp != &cmds[C_VISUAL_VI]) + break; + if (cp == &cmds[C_VISUAL_EX]) + cp = &cmds[C_VISUAL_VI]; + else + cp = &cmds[C_VISUAL_EX]; + (void)ex_printf(EXCOOKIE, + "Command: %s\n Usage: %s\n", cp->help, cp->usage); + } + break; + case 0: + F_SET(sp, S_INTERRUPTIBLE); + for (cp = cmds; cp->name != NULL; ++cp) { + /* The ^D command has an unprintable name. */ + if (cp == &cmds[C_SCROLL]) + name = "^D"; + else + name = cp->name; + (void)ex_printf(EXCOOKIE, + "%*s: %s\n", MAXCMDNAMELEN, name, cp->help); + } + break; + default: + abort(); + } + return (0); +} + +/* + * ex_viusage -- :viusage [key] + * Display vi usage strings. + */ +int +ex_viusage(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + VIKEYS const *kp; + int key; + + switch (cmdp->argc) { + case 1: + if (cmdp->argv[0]->len != 1) { + msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); + } + key = cmdp->argv[0]->bp[0]; + if (key > MAXVIKEY) + goto nokey; + + /* Special case: '[' and ']' commands. */ + if ((key == '[' || key == ']') && cmdp->argv[0]->bp[1] != key) + goto nokey; + + /* Special case: ~ command. */ + if (key == '~' && O_ISSET(sp, O_TILDEOP)) + kp = &tmotion; + else + kp = &vikeys[key]; + + if (kp->func == NULL) +nokey: (void)ex_printf(EXCOOKIE, + "The %s key has no current meaning", + KEY_NAME(sp, key)); + else + (void)ex_printf(EXCOOKIE, + " Key:%s%s\nUsage: %s\n", + isblank(*kp->help) ? "" : " ", kp->help, kp->usage); + break; + case 0: + F_SET(sp, S_INTERRUPTIBLE); + for (key = 0; key <= MAXVIKEY; ++key) { + /* Special case: ~ command. */ + if (key == '~' && O_ISSET(sp, O_TILDEOP)) + kp = &tmotion; + else + kp = &vikeys[key]; + if (kp->help != NULL) + (void)ex_printf(EXCOOKIE, "%s\n", kp->help); + } + break; + default: + abort(); + } + return (0); +} diff --git a/usr.bin/vi/ex/ex_util.c b/usr.bin/vi/ex/ex_util.c new file mode 100644 index 0000000..e88c28f --- /dev/null +++ b/usr.bin/vi/ex/ex_util.c @@ -0,0 +1,189 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_util.c 8.12 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_getline -- + * Return a line from the terminal. + */ +int +ex_getline(sp, fp, lenp) + SCR *sp; + FILE *fp; + size_t *lenp; +{ + EX_PRIVATE *exp; + size_t off; + int ch; + char *p; + + exp = EXP(sp); + for (errno = 0, off = 0, p = exp->ibp;;) { + if (off >= exp->ibp_len) { + BINC_RET(sp, exp->ibp, exp->ibp_len, off + 1); + p = exp->ibp + off; + } + if ((ch = getc(fp)) == EOF && !feof(fp)) { + if (errno == EINTR) { + errno = 0; + clearerr(fp); + continue; + } + return (1); + } + if (ch == EOF || ch == '\n') { + if (ch == EOF && !off) + return (1); + *lenp = off; + return (0); + } + *p++ = ch; + ++off; + } + /* NOTREACHED */ +} + +/* + * ex_sleave -- + * Save the terminal/signal state, screen modification time. + * Specific to ex/filter.c and ex/ex_shell.c. + */ +int +ex_sleave(sp) + SCR *sp; +{ + struct stat sb; + EX_PRIVATE *exp; + + /* Ignore sessions not using tty's. */ + if (!F_ISSET(sp->gp, G_STDIN_TTY)) + return (1); + + exp = EXP(sp); + if (tcgetattr(STDIN_FILENO, &exp->leave_term)) { + msgq(sp, M_SYSERR, "tcgetattr"); + return (1); + } + if (tcsetattr(STDIN_FILENO, + TCSANOW | TCSASOFT, &sp->gp->original_termios)) { + msgq(sp, M_SYSERR, "tcsetattr"); + return (1); + } + /* + * The process may write to the terminal. Save the access time + * (read) and modification time (write) of the tty; if they have + * changed when we restore the modes, will have to refresh the + * screen. + */ + if (fstat(STDIN_FILENO, &sb)) { + msgq(sp, M_SYSERR, "stat: stdin"); + exp->leave_atime = exp->leave_mtime = 0; + } else { + exp->leave_atime = sb.st_atime; + exp->leave_mtime = sb.st_mtime; + } + return (0); +} + +/* + * ex_rleave -- + * Return the terminal/signal state, not screen modification time. + * Specific to ex/filter.c and ex/ex_shell.c. + */ +void +ex_rleave(sp) + SCR *sp; +{ + EX_PRIVATE *exp; + struct stat sb; + + exp = EXP(sp); + + /* Restore the terminal modes. */ + if (tcsetattr(STDIN_FILENO, TCSANOW | TCSASOFT, &exp->leave_term)) + msgq(sp, M_SYSERR, "tcsetattr"); + + /* If the terminal was used, refresh the screen. */ + if (fstat(STDIN_FILENO, &sb) || exp->leave_atime == 0 || + exp->leave_atime != sb.st_atime || exp->leave_mtime != sb.st_mtime) + F_SET(sp, S_REFRESH); +} + +/* + * ex_ncheck -- + * Check for more files to edit. + */ +int +ex_ncheck(sp, force) + SCR *sp; + int force; +{ + /* + * !!! + * Historic practice: quit! or two quit's done in succession + * (where ZZ counts as a quit) didn't check for other files. + */ + if (!force && sp->ccnt != sp->q_ccnt + 1 && + sp->cargv != NULL && sp->cargv[1] != NULL) { + sp->q_ccnt = sp->ccnt; + msgq(sp, M_ERR, + "More files to edit; use n[ext] to go to the next file, q[uit]! to quit"); + return (1); + } + return (0); +} diff --git a/usr.bin/vi/ex/ex_version.c b/usr.bin/vi/ex/ex_version.c new file mode 100644 index 0000000..31c2cb7 --- /dev/null +++ b/usr.bin/vi/ex/ex_version.c @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_version.c 8.62 (Berkeley) 8/15/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_version -- :version + * Display the program version. + */ +int +ex_version(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + static time_t then = 776975285; + + (void)ex_printf(EXCOOKIE, +"Version 1.32, %sThe CSRG, University of California, Berkeley.\n", + ctime(&then)); + return (0); +} diff --git a/usr.bin/vi/ex/ex_visual.c b/usr.bin/vi/ex/ex_visual.c new file mode 100644 index 0000000..cfb0c13 --- /dev/null +++ b/usr.bin/vi/ex/ex_visual.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_visual.c 8.13 (Berkeley) 7/18/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags] + * + * Switch to visual mode. + */ +int +ex_visual(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + size_t len; + int pos; + char buf[256]; + + /* If open option off, disallow visual command. */ + if (!O_ISSET(sp, O_OPEN)) { + msgq(sp, M_ERR, + "The visual command requires that the open option be set"); + return (1); + } + + /* If a line specified, move to that line. */ + if (cmdp->addrcnt) + sp->lno = cmdp->addr1.lno; + + /* + * Push a command based on the line position flags. If no + * flag specified, the line goes at the top of the screen. + */ + switch (F_ISSET(cmdp, E_F_CARAT | E_F_DASH | E_F_DOT | E_F_PLUS)) { + case E_F_CARAT: + pos = '^'; + break; + case E_F_DASH: + pos = '-'; + break; + case E_F_DOT: + pos = '.'; + break; + case E_F_PLUS: + pos = '+'; + break; + default: + sp->frp->lno = sp->lno; + sp->frp->cno = 0; + F_SET(sp->frp, FR_CURSORSET | FR_FNONBLANK); + goto nopush; + } + + if (F_ISSET(cmdp, E_COUNT)) + len = snprintf(buf, sizeof(buf), + "%luz%c%lu", sp->lno, pos, cmdp->count); + else + len = snprintf(buf, sizeof(buf), "%luz%c", sp->lno, pos); + (void)term_push(sp, buf, len, CH_NOMAP | CH_QUOTED); + + /* + * !!! + * Historically, if no line address was specified, the [p#l] flags + * caused the cursor to be moved to the last line of the file, which + * was then positioned as described above. This seems useless, so + * I haven't implemented it. + */ + switch (F_ISSET(cmdp, E_F_HASH | E_F_LIST | E_F_PRINT)) { + case E_F_HASH: + O_SET(sp, O_NUMBER); + break; + case E_F_LIST: + O_SET(sp, O_LIST); + break; + case E_F_PRINT: + break; + } + + /* Switch modes. */ +nopush: F_CLR(sp, S_SCREENS); + F_SET(sp, sp->saved_vi_mode); + + return (0); +} diff --git a/usr.bin/vi/ex/ex_write.c b/usr.bin/vi/ex/ex_write.c new file mode 100644 index 0000000..3dbb6e8 --- /dev/null +++ b/usr.bin/vi/ex/ex_write.c @@ -0,0 +1,327 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_write.c 8.36 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +enum which {WN, WQ, WRITE, XIT}; + +static int exwr __P((SCR *, EXF *, EXCMDARG *, enum which)); + +/* + * ex_wn -- :wn[!] [>>] [file] + * Write to a file and switch to the next one. + */ +int +ex_wn(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + if (exwr(sp, ep, cmdp, WN)) + return (1); + if (file_m3(sp, ep, 0)) + return (1); + + /* The file name isn't a new file to edit. */ + cmdp->argc = 0; + + return (ex_next(sp, ep, cmdp)); +} + +/* + * ex_wq -- :wq[!] [>>] [file] + * Write to a file and quit. + */ +int +ex_wq(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + int force; + + if (exwr(sp, ep, cmdp, WQ)) + return (1); + if (file_m3(sp, ep, 0)) + return (1); + + force = F_ISSET(cmdp, E_FORCE); + + if (ex_ncheck(sp, force)) + return (1); + + F_SET(sp, force ? S_EXIT_FORCE : S_EXIT); + return (0); +} + +/* + * ex_write -- :write[!] [>>] [file] + * :write [!] [cmd] + * Write to a file. + */ +int +ex_write(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (exwr(sp, ep, cmdp, WRITE)); +} + + +/* + * ex_xit -- :x[it]! [file] + * + * Write out any modifications and quit. + */ +int +ex_xit(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + int force; + + if (F_ISSET((ep), F_MODIFIED) && exwr(sp, ep, cmdp, XIT)) + return (1); + if (file_m3(sp, ep, 0)) + return (1); + + force = F_ISSET(cmdp, E_FORCE); + + if (ex_ncheck(sp, force)) + return (1); + + F_SET(sp, force ? S_EXIT_FORCE : S_EXIT); + return (0); +} + +/* + * exwr -- + * The guts of the ex write commands. + */ +static int +exwr(sp, ep, cmdp, cmd) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; + enum which cmd; +{ + EX_PRIVATE *exp; + MARK rm; + int flags; + char *name, *p; + + /* All write commands can have an associated '!'. */ + LF_INIT(FS_POSSIBLE); + if (F_ISSET(cmdp, E_FORCE)) + LF_SET(FS_FORCE); + + /* Skip any leading whitespace. */ + if (cmdp->argc != 0) + for (p = cmdp->argv[0]->bp; *p && isblank(*p); ++p); + + /* If no arguments, just write the file back. */ + if (cmdp->argc == 0 || *p == '\0') { + if (F_ISSET(cmdp, E_ADDR2_ALL)) + LF_SET(FS_ALL); + return (file_write(sp, ep, + &cmdp->addr1, &cmdp->addr2, NULL, flags)); + } + + /* If "write !" it's a pipe to a utility. */ + exp = EXP(sp); + if (cmd == WRITE && *p == '!') { + for (++p; *p && isblank(*p); ++p); + if (*p == '\0') { + msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); + } + /* Expand the argument. */ + if (argv_exp1(sp, ep, cmdp, p, strlen(p), 0)) + return (1); + if (filtercmd(sp, ep, &cmdp->addr1, &cmdp->addr2, + &rm, cmdp->argv[1]->bp, FILTER_WRITE)) + return (1); + sp->lno = rm.lno; + return (0); + } + + /* If "write >>" it's an append to a file. */ + if (cmd != XIT && p[0] == '>' && p[1] == '>') { + LF_SET(FS_APPEND); + + /* Skip ">>" and whitespace. */ + for (p += 2; *p && isblank(*p); ++p); + } + + /* Build an argv so we get an argument count and file expansion. */ + if (argv_exp2(sp, ep, cmdp, p, strlen(p), 0)) + return (1); + + switch (cmdp->argc) { + case 1: + /* + * Nothing to expand, write the current file. + * XXX + * Should never happen, already checked this case. + */ + name = NULL; + break; + case 2: + /* One new argument, write it. */ + name = cmdp->argv[exp->argsoff - 1]->bp; + set_alt_name(sp, name); + break; + default: + /* If expanded to more than one argument, object. */ + msgq(sp, M_ERR, "%s expanded into too many file names", + cmdp->argv[0]->bp); + msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage); + return (1); + } + + if (F_ISSET(cmdp, E_ADDR2_ALL)) + LF_SET(FS_ALL); + return (file_write(sp, ep, &cmdp->addr1, &cmdp->addr2, name, flags)); +} + +/* + * ex_writefp -- + * Write a range of lines to a FILE *. + */ +int +ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch) + SCR *sp; + EXF *ep; + char *name; + FILE *fp; + MARK *fm, *tm; + u_long *nlno, *nch; +{ + struct stat sb; + u_long ccnt; /* XXX: can't print off_t portably. */ + recno_t fline, tline, lcnt; + size_t len; + int sv_errno; + char *p; + + fline = fm->lno; + tline = tm->lno; + + if (nlno != NULL) { + *nch = 0; + *nlno = 0; + } + + /* + * The vi filter code has multiple processes running simultaneously, + * and one of them calls ex_writefp(). The "unsafe" function calls + * in this code are to file_gline() and msgq(). File_gline() is safe, + * see the comment in filter.c:filtercmd() for details. We don't call + * msgq if the multiple process bit in the EXF is set. + * + * !!! + * Historic vi permitted files of 0 length to be written. However, + * since the way vi got around dealing with "empty" files was to + * always have a line in the file no matter what, it wrote them as + * files of a single, empty line. We write empty files. + * + * "Alex, I'll take vi trivia for $1000." + */ + ccnt = 0; + lcnt = 0; + if (tline != 0) { + for (; fline <= tline; ++fline, ++lcnt) { + /* Caller has to provide any interrupt message. */ + if (INTERRUPTED(sp)) + break; + if ((p = file_gline(sp, ep, fline, &len)) == NULL) + break; + if (fwrite(p, 1, len, fp) != len) { + msgq(sp, M_SYSERR, name); + (void)fclose(fp); + return (1); + } + ccnt += len; + if (putc('\n', fp) != '\n') + break; + ++ccnt; + } + } + + /* If it's a regular file, sync it so that NFS is forced to flush. */ + if (!fstat(fileno(fp), &sb) && + S_ISREG(sb.st_mode) && fsync(fileno(fp))) { + sv_errno = errno; + (void)fclose(fp); + errno = sv_errno; + goto err; + } + if (fclose(fp)) + goto err; + if (nlno != NULL) { + *nch = ccnt; + *nlno = lcnt; + } + return (0); + +err: if (!F_ISSET(ep, F_MULTILOCK)) + msgq(sp, M_SYSERR, name); + return (1); +} diff --git a/usr.bin/vi/ex/ex_yank.c b/usr.bin/vi/ex/ex_yank.c new file mode 100644 index 0000000..7f5d280 --- /dev/null +++ b/usr.bin/vi/ex/ex_yank.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_yank.c 8.5 (Berkeley) 5/17/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_yank -- :[line [,line]] ya[nk] [buffer] [count] + * + * Yank the lines into a buffer. + */ +int +ex_yank(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + return (cut(sp, ep, + F_ISSET(cmdp, E_BUFFER) ? &cmdp->buffer : NULL, + &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)); +} diff --git a/usr.bin/vi/ex/ex_z.c b/usr.bin/vi/ex/ex_z.c new file mode 100644 index 0000000..a5917b3 --- /dev/null +++ b/usr.bin/vi/ex/ex_z.c @@ -0,0 +1,180 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)ex_z.c 8.6 (Berkeley) 7/23/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * ex_z -- :[line] z [^-.+=] [count] [flags] + * + * Adjust window. + */ +int +ex_z(sp, ep, cmdp) + SCR *sp; + EXF *ep; + EXCMDARG *cmdp; +{ + MARK abs; + recno_t cnt, equals, lno; + int eofcheck; + + /* + * !!! + * If no count specified, use either two times the size of the + * scrolling region, or the size of the window option. POSIX + * 1003.2 claims that the latter is correct, but historic ex/vi + * documentation and practice appear to use the scrolling region. + * I'm using the window size as it means that the entire screen + * is used instead of losing a line to roundoff. Note, we drop + * a line from the cnt if using the window size to leave room for + * the next ex prompt. + */ + if (F_ISSET(cmdp, E_COUNT)) + cnt = cmdp->count; + else +#ifdef HISTORIC_PRACTICE + cnt = O_VAL(sp, O_SCROLL) * 2; +#else + cnt = O_VAL(sp, O_WINDOW) - 1; +#endif + + equals = 0; + eofcheck = 0; + lno = cmdp->addr1.lno; + + switch (F_ISSET(cmdp, + E_F_CARAT | E_F_DASH | E_F_DOT | E_F_EQUAL | E_F_PLUS)) { + case E_F_CARAT: /* Display cnt * 2 before the line. */ + eofcheck = 1; + if (lno > cnt * 2) + cmdp->addr1.lno = (lno - cnt * 2) + 1; + else + cmdp->addr1.lno = 1; + cmdp->addr2.lno = (cmdp->addr1.lno + cnt) - 1; + break; + case E_F_DASH: /* Line goes at the bottom of the screen. */ + cmdp->addr1.lno = lno > cnt ? (lno - cnt) + 1 : 1; + cmdp->addr2.lno = lno; + break; + case E_F_DOT: /* Line goes in the middle of the screen. */ + /* + * !!! + * Historically, the "middleness" of the line overrode the + * count, so that "3z.19" or "3z.20" would display the first + * 12 lines of the file, i.e. (N - 1) / 2 lines before and + * after the specified line. + */ + eofcheck = 1; + cnt = (cnt - 1) / 2; + cmdp->addr1.lno = lno > cnt ? lno - cnt : 1; + cmdp->addr2.lno = lno + cnt; + + /* + * !!! + * Historically, z. set the absolute cursor mark. + */ + abs.lno = sp->lno; + abs.cno = sp->cno; + (void)mark_set(sp, ep, ABSMARK1, &abs, 1); + break; + case E_F_EQUAL: /* Center with hyphens. */ + /* + * !!! + * Strangeness. The '=' flag is like the '.' flag (see the + * above comment, it applies here as well) but with a special + * little hack. Print out lines of hyphens before and after + * the specified line. Additionally, the cursor remains set + * on that line. + */ + eofcheck = 1; + cnt = (cnt - 1) / 2; + cmdp->addr1.lno = lno > cnt ? lno - cnt : 1; + cmdp->addr2.lno = lno - 1; + if (ex_pr(sp, ep, cmdp)) + return (1); + (void)ex_printf(EXCOOKIE, + "%s", "----------------------------------------\n"); + cmdp->addr2.lno = cmdp->addr1.lno = equals = lno; + if (ex_pr(sp, ep, cmdp)) + return (1); + (void)ex_printf(EXCOOKIE, + "%s", "----------------------------------------\n"); + cmdp->addr1.lno = lno + 1; + cmdp->addr2.lno = (lno + cnt) - 1; + break; + default: + /* If no line specified, move to the next one. */ + if (F_ISSET(cmdp, E_ADDRDEF)) + ++lno; + /* FALLTHROUGH */ + case E_F_PLUS: /* Line goes at the top of the screen. */ + eofcheck = 1; + cmdp->addr1.lno = lno; + cmdp->addr2.lno = (lno + cnt) - 1; + break; + } + + if (eofcheck) { + if (file_lline(sp, ep, &lno)) + return (1); + if (cmdp->addr2.lno > lno) + cmdp->addr2.lno = lno; + } + + if (ex_pr(sp, ep, cmdp)) + return (1); + if (equals) + sp->lno = equals; + return (0); +} diff --git a/usr.bin/vi/ex/excmd.awk b/usr.bin/vi/ex/excmd.awk new file mode 100644 index 0000000..2890220 --- /dev/null +++ b/usr.bin/vi/ex/excmd.awk @@ -0,0 +1,6 @@ +# @(#)excmd.awk 8.1 (Berkeley) 4/17/94 + +/^\/\* C_[0-9A-Z_]* \*\/$/ { + printf("#define %s %d\n", $2, cnt++); + next; +} diff --git a/usr.bin/vi/ex/excmd.c b/usr.bin/vi/ex/excmd.c new file mode 100644 index 0000000..3845768 --- /dev/null +++ b/usr.bin/vi/ex/excmd.c @@ -0,0 +1,458 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)excmd.c 8.58 (Berkeley) 8/9/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" + +/* + * This array maps ex command names to command functions. + * + * The order in which command names are listed below is important -- + * ambiguous abbreviations are resolved to be the first possible match, + * e.g. "r" means "read", not "rewind", because "read" is listed before + * "rewind". + * + * The syntax of the ex commands is unbelievably irregular, and a special + * case from beginning to end. Each command has an associated "syntax + * script" which describes the "arguments" that are possible. The script + * syntax is as follows: + * + * ! -- ! flag + * 1 -- flags: [+-]*[pl#][+-]* + * 2 -- flags: [-.+^] + * 3 -- flags: [-.+^=] + * b -- buffer + * c[01+a] -- count (0-N, 1-N, signed 1-N, address offset) + * f[N#][or] -- file (a number or N, optional or required) + * l -- line + * S -- string with file name expansion + * s -- string + * W -- word string + * w[N#][or] -- word (a number or N, optional or required) + */ +EXCMDLIST const cmds[] = { +/* C_SCROLL */ + {"\004", ex_pr, E_ADDR2|E_NORC, + "", + "^D", + "scroll lines"}, +/* C_BANG */ + {"!", ex_bang, E_ADDR2_NONE|E_NORC, + "S", + "[line [,line]] ! command", + "filter lines through commands or run commands"}, +/* C_HASH */ + {"#", ex_number, E_ADDR2|E_F_PRCLEAR|E_NORC, + "ca1", + "[line [,line]] # [count] [l]", + "display numbered lines"}, +/* C_SUBAGAIN */ + {"&", ex_subagain, E_ADDR2|E_NORC, + "s", + "[line [,line]] & [cgr] [count] [#lp]", + "repeat the last subsitution"}, +/* C_STAR */ + {"*", ex_at, 0, + "b", + "* [buffer]", + "execute a buffer"}, +/* C_SHIFTL */ + {"<", ex_shiftl, E_ADDR2|E_AUTOPRINT|E_NORC, + "ca1", + "[line [,line]] <[<...] [count] [flags]", + "shift lines left"}, +/* C_EQUAL */ + {"=", ex_equal, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF, + "1", + "[line] = [flags]", + "display line number"}, +/* C_SHIFTR */ + {">", ex_shiftr, E_ADDR2|E_AUTOPRINT|E_NORC, + "ca1", + "[line [,line]] >[>...] [count] [flags]", + "shift lines right"}, +/* C_AT */ + {"@", ex_at, 0, + "b", + "@ [buffer]", + "execute a buffer"}, +/* C_APPEND */ + {"append", ex_append, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF, + "!", + "[line] a[ppend][!]", + "append input to a line"}, +/* C_ABBR */ + {"abbreviate", ex_abbr, E_NOGLOBAL, + "W", + "ab[brev] [word replace]", + "specify an input abbreviation"}, +/* C_ARGS */ + {"args", ex_args, E_NOGLOBAL|E_NORC, + "", + "ar[gs]", + "display file argument list"}, +/* C_BG */ + {"bg", ex_bg, E_NOGLOBAL|E_NORC, + "", + "bg", + "background the current screen"}, +/* C_CHANGE */ + {"change", ex_change, E_ADDR2|E_NORC|E_ZERODEF, + "!ca", + "[line [,line]] c[hange][!] [count]", + "change lines to input"}, +/* C_CD */ + {"cd", ex_cd, E_NOGLOBAL, + "!f1o", + "cd[!] [directory]", + "change the current directory"}, +/* C_CHDIR */ + {"chdir", ex_cd, E_NOGLOBAL, + "!f1o", + "chd[ir][!] [directory]", + "change the current directory"}, +/* C_COPY */ + {"copy", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC, + "l1", + "[line [,line]] co[py] line [flags]", + "copy lines elsewhere in the file"}, +/* + * !!! + * Adding new commands starting with 'd' may break the delete command code + * in ex_cmd() (the ex parser). Read through the comments there, first. + */ +/* C_DELETE */ + {"delete", ex_delete, E_ADDR2|E_AUTOPRINT|E_NORC, + "bca1", + "[line [,line]] d[elete][flags] [buffer] [count] [flags]", + "delete lines from the file"}, +/* C_DISPLAY */ + {"display", ex_display, E_NOGLOBAL|E_NORC, + "w1r", + "display b[uffers] | s[creens] | t[ags]", + "display buffers, screens or tags"}, +/* C_DIGRAPH */ + {"digraph", ex_digraph, E_NOGLOBAL|E_NOPERM|E_NORC, + "", + "digraph", + "specify digraphs (not implemented)"}, +/* C_EDIT */ + {"edit", ex_edit, E_NOGLOBAL|E_NORC, + "f1o", + "e[dit][!] [+cmd] [file]", + "begin editing another file"}, +/* C_EX */ + {"ex", ex_edit, E_NOGLOBAL|E_NORC, + "f1o", + "ex[!] [+cmd] [file]", + "begin editing another file"}, +/* C_EXUSAGE */ + {"exusage", ex_usage, E_NOGLOBAL|E_NORC, + "w1o", + "[exu]sage [command]", + "display ex command usage statement"}, +/* C_FILE */ + {"file", ex_file, E_NOGLOBAL|E_NORC, + "f1o", + "f[ile] [name]", + "display (and optionally set) file name"}, +/* C_FG */ + {"fg", ex_fg, E_NOGLOBAL|E_NORC, + "f1o", + "fg [file]", + "switch the current screen and a backgrounded screen"}, +/* C_GLOBAL */ + {"global", ex_global, E_ADDR2_ALL|E_NOGLOBAL|E_NORC, + "!s", + "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]", + "execute a global command on lines matching an RE"}, +/* C_HELP */ + {"help", ex_help, E_NOGLOBAL|E_NORC, + "", + "he[lp]", + "display help statement"}, +/* C_INSERT */ + {"insert", ex_insert, E_ADDR1|E_NORC, + "!", + "[line] i[nsert][!]", + "insert input before a line"}, +/* C_JOIN */ + {"join", ex_join, E_ADDR2|E_AUTOPRINT|E_NORC, + "!ca1", + "[line [,line]] j[oin][!] [count] [flags]", + "join lines into a single line"}, +/* C_K */ + {"k", ex_mark, E_ADDR1|E_NORC, + "w1r", + "[line] k key", + "mark a line position"}, +/* C_LIST */ + {"list", ex_list, E_ADDR2|E_F_PRCLEAR|E_NORC, + "ca1", + "[line [,line]] l[ist] [count] [#]", + "display lines in an unambiguous form"}, +/* C_MOVE */ + {"move", ex_move, E_ADDR2|E_AUTOPRINT|E_NORC, + "l", + "[line [,line]] m[ove] line", + "move lines elsewhere in the file"}, +/* C_MARK */ + {"mark", ex_mark, E_ADDR1|E_NORC, + "w1r", + "[line] ma[rk] key", + "mark a line position"}, +/* C_MAP */ + {"map", ex_map, 0, + "!W", + "map[!] [keys replace]", + "map input or commands to one or more keys"}, +/* C_MKEXRC */ + {"mkexrc", ex_mkexrc, E_NOGLOBAL|E_NORC, + "!f1r", + "mkexrc[!] file", + "write a .exrc file"}, +/* C_NEXT */ + {"next", ex_next, E_NOGLOBAL|E_NORC, + "!fN", + "n[ext][!] [+cmd] [file ...]", + "edit (and optionally specify) the next file"}, +/* C_NUMBER */ + {"number", ex_number, E_ADDR2|E_F_PRCLEAR|E_NORC, + "ca1", + "[line [,line]] nu[mber] [count] [l]", + "change display to number lines"}, +/* C_OPEN */ + {"open", ex_open, E_ADDR1, + "s", + "[line] o[pen] [/RE/] [flags]", + "enter \"open\" mode (not implemented)"}, +/* C_PRINT */ + {"print", ex_pr, E_ADDR2|E_F_PRCLEAR|E_NORC, + "ca1", + "[line [,line]] p[rint] [count] [#l]", + "display lines"}, +/* C_PRESERVE */ + {"preserve", ex_preserve, E_NOGLOBAL|E_NORC, + "", + "pre[serve]", + "preserve an edit session for recovery"}, +/* C_PREVIOUS */ + {"previous", ex_prev, E_NOGLOBAL|E_NORC, + "!", + "prev[ious][!]", + "edit the previous file in the file argument list"}, +/* C_PUT */ + {"put", ex_put, E_ADDR1|E_AUTOPRINT|E_NORC|E_ZERO, + "b", + "[line] pu[t] [buffer]", + "append a cut buffer to the line"}, +/* C_QUIT */ + {"quit", ex_quit, E_NOGLOBAL|E_NORC, + "!", + "q[uit][!]", + "exit ex/vi"}, +/* C_READ */ + {"read", ex_read, E_ADDR1|E_NORC|E_ZERO|E_ZERODEF, + "s", + "[line] r[ead] [!cmd | [file]]", + "append input from a command or file to the line"}, +/* C_RECOVER */ + {"recover", ex_recover, E_NOGLOBAL|E_NORC, + "!f1r", + "recover[!] file", + "recover a saved file"}, +/* C_RESIZE */ + {"resize", ex_resize, E_NOGLOBAL|E_NORC, + "c+", + "resize [+-]rows", + "grow or shrink the current screen"}, +/* C_REWIND */ + {"rewind", ex_rew, E_NOGLOBAL|E_NORC, + "!", + "rew[ind][!]", + "re-edit all the files in the file argument list"}, +/* C_SUBSTITUTE */ + {"substitute", ex_substitute, E_ADDR2|E_NORC, + "s", +"[line [,line]] s[ubstitute] [[/;]RE[/;]/repl[/;] [cgr] [count] [#lp]]", + "substitute on lines matching an RE"}, +/* C_SCRIPT */ + {"script", ex_script, E_NOGLOBAL|E_NORC, + "!f1o", + "sc[ript][!] [file]", + "run a shell in a screen"}, +/* C_SET */ + {"set", ex_set, E_NOGLOBAL, + "wN", + "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]", + "set options (use \":set all\" to see all options)"}, +/* C_SHELL */ + {"shell", ex_shell, E_NOGLOBAL|E_NORC, + "", + "sh[ell]", + "suspend editing and run a shell"}, +/* C_SOURCE */ + {"source", ex_source, E_NOGLOBAL, + "f1r", + "so[urce] file", + "read a file of ex commands"}, +/* C_SPLIT */ + {"split", ex_split, E_NOGLOBAL|E_NORC, + "fNo", + "sp[lit] [file ...]", + "split the current screen into two screens"}, +/* C_STOP */ + {"stop", ex_stop, E_NOGLOBAL|E_NORC, + "!", + "st[op][!]", + "suspend the edit session"}, +/* C_SUSPEND */ + {"suspend", ex_stop, E_NOGLOBAL|E_NORC, + "!", + "su[spend][!]", + "suspend the edit session"}, +/* C_T */ + {"t", ex_copy, E_ADDR2|E_AUTOPRINT|E_NORC, + "l1", + "[line [,line]] t line [flags]", + "copy lines elsewhere in the file"}, +/* C_TAG */ + {"tag", ex_tagpush, E_NOGLOBAL, + "!w1o", + "ta[g][!] [string]", + "edit the file containing the tag"}, +/* C_TAGPOP */ + {"tagpop", ex_tagpop, E_NOGLOBAL|E_NORC, + "!w1o", + "tagp[op][!] [number | file]", + "return to a previous tag"}, +/* C_TAGTOP */ + {"tagtop", ex_tagtop, E_NOGLOBAL|E_NORC, + "!", + "tagt[op][!]", + "return to the first tag"}, +/* C_UNDO */ + {"undo", ex_undo, E_AUTOPRINT|E_NOGLOBAL|E_NORC, + "", + "u[ndo]", + "undo the most recent change"}, +/* C_UNABBREVIATE */ + {"unabbreviate",ex_unabbr, E_NOGLOBAL, + "w1r", + "una[bbrev] word", + "delete an abbreviation"}, +/* C_UNMAP */ + {"unmap", ex_unmap, E_NOGLOBAL, + "!w1r", + "unm[ap][!] word", + "delete an input or command map"}, +/* C_VGLOBAL */ + {"vglobal", ex_vglobal, E_ADDR2_ALL|E_NOGLOBAL|E_NORC, + "s", + "[line [,line]] v[global] [;/]RE[;/] [commands]", + "execute a global command on lines NOT matching an RE"}, +/* C_VERSION */ + {"version", ex_version, E_NOGLOBAL|E_NORC, + "", + "version", + "display the program version information"}, +/* C_VISUAL_EX */ + {"visual", ex_visual, E_ADDR1|E_NOGLOBAL|E_NORC|E_ZERODEF, + "2c11", + "[line] vi[sual] [-|.|+|^] [window_size] [flags]", + "enter visual (vi) mode from ex mode"}, +/* C_VISUAL_VI */ + {"visual", ex_edit, E_NOGLOBAL|E_NORC, + "f1o", + "vi[sual][!] [+cmd] [file]", + "edit another file (from vi mode only)"}, +/* C_VIUSAGE */ + {"viusage", ex_viusage, E_NOGLOBAL|E_NORC, + "w1o", + "[viu]sage [key]", + "display vi key usage statement"}, +/* C_WRITE */ + {"write", ex_write, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF, + "!s", + "[line [,line]] w[rite][!] [!cmd | [>>] [file]]", + "write the file"}, +/* C_WN */ + {"wn", ex_wn, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF, + "!s", + "[line [,line]] wn[!] [>>] [file]", + "write the file and switch to the next file"}, +/* C_WQ */ + {"wq", ex_wq, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF, + "!s", + "[line [,line]] wq[!] [>>] [file]", + "write the file and exit"}, +/* C_XIT */ + {"xit", ex_xit, E_ADDR2_ALL|E_NOGLOBAL|E_NORC|E_ZERODEF, + "!f1o", + "[line [,line]] x[it][!] [file]", + "exit"}, +/* C_YANK */ + {"yank", ex_yank, E_ADDR2|E_NORC, + "bca", + "[line [,line]] ya[nk] [buffer] [count]", + "copy lines to a cut buffer"}, +/* C_Z */ + {"z", ex_z, E_ADDR1|E_NOGLOBAL|E_NORC, + "3c01", + "[line] z [-|.|+|^|=] [count] [flags]", + "display different screens of the file"}, +/* C_SUBTILDE */ + {"~", ex_subtilde, E_ADDR2|E_NORC, + "s", + "[line [,line]] ~ [cgr] [count] [#lp]", + "replace previous RE with previous replacement string,"}, + {NULL}, +}; diff --git a/usr.bin/vi/ex/excmd.h.stub b/usr.bin/vi/ex/excmd.h.stub new file mode 100644 index 0000000..3b4051b --- /dev/null +++ b/usr.bin/vi/ex/excmd.h.stub @@ -0,0 +1,285 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)excmd.h.stub 8.73 (Berkeley) 8/9/94 + */ + +#define PROMPTCHAR ':' /* Prompt character. */ + +/* Ex command structure. */ +typedef struct _excmdlist { + char *name; /* Command name. */ + /* Underlying function. */ + int (*fn) __P((SCR *, EXF *, EXCMDARG *)); + +#define E_ADDR1 0x0000001 /* One address. */ +#define E_ADDR2 0x0000002 /* Two address. */ +#define E_ADDR2_ALL 0x0000004 /* Zero/two addresses; zero == all. */ +#define E_ADDR2_NONE 0x0000008 /* Zero/two addresses; zero == none. */ +#define E_ADDRDEF 0x0000010 /* Default addresses used. */ +#define E_AUTOPRINT 0x0000020 /* Command always sets autoprint. */ +#define E_BUFFER 0x0000040 /* Buffer name supplied. */ +#define E_COUNT 0x0000080 /* Count supplied. */ +#define E_COUNT_NEG 0x0000100 /* Count was signed negative. */ +#define E_COUNT_POS 0x0000200 /* Count was signed positive. */ +#define E_FORCE 0x0000400 /* ! */ + +#define E_F_CARAT 0x0000800 /* ^ flag. */ +#define E_F_DASH 0x0001000 /* - flag. */ +#define E_F_DOT 0x0002000 /* . flag. */ +#define E_F_EQUAL 0x0004000 /* = flag. */ +#define E_F_HASH 0x0008000 /* # flag. */ +#define E_F_LIST 0x0010000 /* l flag. */ +#define E_F_PLUS 0x0020000 /* + flag. */ +#define E_F_PRINT 0x0040000 /* p flag. */ + +#define E_F_PRCLEAR 0x0080000 /* Clear the print (#, l, p) flags. */ +#define E_MODIFY 0x0100000 /* File name expansion modified arg. */ +#define E_NOGLOBAL 0x0200000 /* Not in a global. */ +#define E_NOPERM 0x0400000 /* Permission denied for now. */ +#define E_NORC 0x0800000 /* Not from a .exrc or EXINIT. */ +#define E_ZERO 0x1000000 /* 0 is a legal addr1. */ +#define E_ZERODEF 0x2000000 /* 0 is default addr1 of empty files. */ + u_int32_t flags; + char *syntax; /* Syntax script. */ + char *usage; /* Usage line. */ + char *help; /* Help line. */ +} EXCMDLIST; +#define MAXCMDNAMELEN 12 /* Longest command name. */ +extern EXCMDLIST const cmds[]; /* List of ex commands. */ + +/* + * Structure passed around to functions implementing ex commands. + * There are several commands in vi that build one of these and + * call ex directly. See vi/v_ex.c for details. + */ +struct _excmdarg { + EXCMDLIST const *cmd; /* Command entry in command table. */ + CHAR_T buffer; /* Named buffer. */ + recno_t lineno; /* Line number. */ + long count; /* Signed, specified count. */ + long flagoff; /* Signed, flag offset parsed by command. */ + int addrcnt; /* Number of addresses (0, 1 or 2). */ + MARK addr1; /* 1st address. */ + MARK addr2; /* 2nd address. */ + ARGS **argv; /* Array of arguments. */ + int argc; /* Count of arguments. */ + u_int32_t flags; /* Selected flags from EXCMDLIST. */ +}; + +/* Global ranges. */ +typedef struct _range RANGE; +struct _range { + CIRCLEQ_ENTRY(_range) q; /* Linked list of ranges. */ + recno_t start, stop; /* Start/stop of the range. */ +}; + +/* Cd paths. */ +typedef struct _cdpath CDPATH; +struct _cdpath { + TAILQ_ENTRY(_cdpath) q; /* Linked list of cd paths. */ + char *path; /* Path. */ +}; + +/* Ex private, per-screen memory. */ +typedef struct _ex_private { + ARGS **args; /* Arguments. */ + int argscnt; /* Argument count. */ + int argsoff; /* Offset into arguments. */ + + CHAR_T at_lbuf; /* Last executed at buffer's name. */ + int at_lbuf_set; /* If at_lbuf is set. */ + + char *ibp; /* Line input buffer. */ + size_t ibp_len; /* Line input buffer length. */ + + u_int32_t fdef; /* Default command flags. */ + + CHAR_T *lastbcomm; /* Last bang command. */ + + struct termios leave_term; /* ex_[sr]leave tty state. */ + /* XXX: Should be struct timespec's, but time_t is more portable. */ + time_t leave_atime; /* ex_[sr]leave old access time. */ + time_t leave_mtime; /* ex_[sr]leave old mod time. */ + + TAILQ_HEAD(_tagh, _tag) tagq; /* Tag list (stack). */ + TAILQ_HEAD(_tagfh, _tagf) tagfq;/* Tag file list. */ + char *tlast; /* Saved last tag. */ + + TAILQ_HEAD(_cdh, _cdpath) cdq; /* Cd path list. */ + + /* Linked list of ranges. */ + CIRCLEQ_HEAD(_rangeh, _range) rangeq; + recno_t range_lno; /* Range set line number. */ + +#define EX_ABSMARK 0x01 /* Set the absolute mark. */ +#define EX_AUTOPRINT 0x02 /* Autoprint flag. */ + u_int8_t flags; +} EX_PRIVATE; +#define EXP(sp) ((EX_PRIVATE *)((sp)->ex_private)) + +/* + * !!! + * Historically, .exrc files and EXINIT variables could only use ^V + * as an escape character, neither ^Q or a user specified character + * worked. We enforce that here, just in case someone depends on it. + */ +#define IS_ESCAPE(sp, ch) \ + (F_ISSET(sp, S_VLITONLY) ? \ + (ch) == CH_LITERAL : KEY_VAL(sp, ch) == K_VLNEXT) + +/* + * Filter actions: + * + * FILTER Filter text through the utility. + * FILTER_READ Read from the utility into the file. + * FILTER_WRITE Write to the utility, display its output. + */ +enum filtertype { FILTER, FILTER_READ, FILTER_WRITE }; +int filtercmd __P((SCR *, EXF *, + MARK *, MARK *, MARK *, char *, enum filtertype)); + +/* Argument expansion routines. */ +int argv_init __P((SCR *, EXF *, EXCMDARG *)); +int argv_exp0 __P((SCR *, EXF *, EXCMDARG *, char *, size_t)); +int argv_exp1 __P((SCR *, EXF *, EXCMDARG *, char *, size_t, int)); +int argv_exp2 __P((SCR *, EXF *, EXCMDARG *, char *, size_t, int)); +int argv_exp3 __P((SCR *, EXF *, EXCMDARG *, char *, size_t)); +int argv_free __P((SCR *)); + +/* Ex function prototypes. */ +int ex __P((SCR *, EXF *)); +int ex_cfile __P((SCR *, EXF *, char *, int)); +int ex_cmd __P((SCR *, EXF *, char *, size_t, int)); +int ex_cdalloc __P((SCR *, char *)); +int ex_cdfree __P((SCR *)); +int ex_end __P((SCR *)); +int ex_exec_proc __P((SCR *, char *, char *, char *)); +int ex_gb __P((SCR *, EXF *, TEXTH *, int, u_int)); +int ex_getline __P((SCR *, FILE *, size_t *)); +int ex_icmd __P((SCR *, EXF *, char *, size_t, int)); +int ex_init __P((SCR *, EXF *)); +int ex_is_abbrev __P((char *, size_t)); +int ex_is_unmap __P((char *, size_t)); +int ex_ldisplay __P((SCR *, CHAR_T *, size_t, size_t, u_int)); +int ex_ncheck __P((SCR *, int)); +int ex_optchange __P((SCR *, int)); +int ex_print __P((SCR *, EXF *, MARK *, MARK *, int)); +int ex_readfp __P((SCR *, EXF *, char *, FILE *, MARK *, recno_t *, int)); +void ex_refresh __P((SCR *, EXF *)); +void ex_rleave __P((SCR *)); +int ex_screen_copy __P((SCR *, SCR *)); +int ex_screen_end __P((SCR *)); +int ex_sdisplay __P((SCR *, EXF *)); +int ex_sleave __P((SCR *)); +int ex_suspend __P((SCR *)); +int ex_tdisplay __P((SCR *, EXF *)); +int ex_writefp __P((SCR *, EXF *, + char *, FILE *, MARK *, MARK *, u_long *, u_long *)); +void global_insdel __P((SCR *, EXF *, enum operation, recno_t)); +int proc_wait __P((SCR *, long, const char *, int)); +int sscr_end __P((SCR *)); +int sscr_exec __P((SCR *, EXF *, recno_t)); +int sscr_input __P((SCR *)); + +int abbr_save __P((SCR *, FILE *)); +int map_save __P((SCR *, FILE *)); + +#define EXPROTO(name) int name __P((SCR *, EXF *, EXCMDARG *)) +EXPROTO(ex_abbr); +EXPROTO(ex_append); +EXPROTO(ex_args); +EXPROTO(ex_at); +EXPROTO(ex_bang); +EXPROTO(ex_bg); +EXPROTO(ex_cd); +EXPROTO(ex_change); +EXPROTO(ex_color); +EXPROTO(ex_copy); +EXPROTO(ex_debug); +EXPROTO(ex_delete); +EXPROTO(ex_digraph); +EXPROTO(ex_display); +EXPROTO(ex_edit); +EXPROTO(ex_equal); +EXPROTO(ex_fg); +EXPROTO(ex_file); +EXPROTO(ex_global); +EXPROTO(ex_help); +EXPROTO(ex_insert); +EXPROTO(ex_join); +EXPROTO(ex_list); +EXPROTO(ex_map); +EXPROTO(ex_mark); +EXPROTO(ex_mkexrc); +EXPROTO(ex_move); +EXPROTO(ex_next); +EXPROTO(ex_number); +EXPROTO(ex_open); +EXPROTO(ex_pr); +EXPROTO(ex_preserve); +EXPROTO(ex_prev); +EXPROTO(ex_put); +EXPROTO(ex_quit); +EXPROTO(ex_read); +EXPROTO(ex_recover); +EXPROTO(ex_resize); +EXPROTO(ex_rew); +EXPROTO(ex_script); +EXPROTO(ex_set); +EXPROTO(ex_shell); +EXPROTO(ex_shiftl); +EXPROTO(ex_shiftr); +EXPROTO(ex_source); +EXPROTO(ex_split); +EXPROTO(ex_stop); +EXPROTO(ex_subagain); +EXPROTO(ex_substitute); +EXPROTO(ex_subtilde); +EXPROTO(ex_tagpop); +EXPROTO(ex_tagpush); +EXPROTO(ex_tagtop); +EXPROTO(ex_unabbr); +EXPROTO(ex_undo); +EXPROTO(ex_unmap); +EXPROTO(ex_usage); +EXPROTO(ex_validate); +EXPROTO(ex_version); +EXPROTO(ex_vglobal); +EXPROTO(ex_visual); +EXPROTO(ex_viusage); +EXPROTO(ex_wn); +EXPROTO(ex_wq); +EXPROTO(ex_write); +EXPROTO(ex_xit); +EXPROTO(ex_yank); +EXPROTO(ex_z); diff --git a/usr.bin/vi/ex/filter.c b/usr.bin/vi/ex/filter.c new file mode 100644 index 0000000..59a221c --- /dev/null +++ b/usr.bin/vi/ex/filter.c @@ -0,0 +1,414 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)filter.c 8.43 (Berkeley) 8/7/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> +#include <sys/wait.h> + +#include <bitstring.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> +#include <pathnames.h> + +#include "vi.h" +#include "excmd.h" + +static int filter_ldisplay __P((SCR *, FILE *)); + +/* + * filtercmd -- + * Run a range of lines through a filter utility and optionally + * replace the original text with the stdout/stderr output of + * the utility. + */ +int +filtercmd(sp, ep, fm, tm, rp, cmd, ftype) + SCR *sp; + EXF *ep; + MARK *fm, *tm, *rp; + char *cmd; + enum filtertype ftype; +{ + FILE *ifp, *ofp; + pid_t parent_writer_pid, utility_pid; + recno_t nread; + int input[2], output[2], rval, teardown; + char *name; + + /* Set return cursor position; guard against a line number of zero. */ + *rp = *fm; + if (fm->lno == 0) + rp->lno = 1; + + /* + * There are three different processes running through this code. + * They are the utility, the parent-writer and the parent-reader. + * The parent-writer is the process that writes from the file to + * the utility, the parent reader is the process that reads from + * the utility. + * + * Input and output are named from the utility's point of view. + * The utility reads from input[0] and the parent(s) write to + * input[1]. The parent(s) read from output[0] and the utility + * writes to output[1]. + * + * In the FILTER_READ case, the utility isn't expected to want + * input. Redirect its input from /dev/null. Otherwise open + * up utility input pipe. + */ + teardown = 0; + ofp = NULL; + input[0] = input[1] = output[0] = output[1] = -1; + if (ftype == FILTER_READ) { + if ((input[0] = open(_PATH_DEVNULL, O_RDONLY, 0)) < 0) { + msgq(sp, M_ERR, + "filter: %s: %s", _PATH_DEVNULL, strerror(errno)); + return (1); + } + } else + if (pipe(input) < 0) { + msgq(sp, M_SYSERR, "pipe"); + goto err; + } + + /* Open up utility output pipe. */ + if (pipe(output) < 0) { + msgq(sp, M_SYSERR, "pipe"); + goto err; + } + if ((ofp = fdopen(output[0], "r")) == NULL) { + msgq(sp, M_SYSERR, "fdopen"); + goto err; + } + + /* + * Save ex/vi terminal settings, and restore the original ones. + * Restoration so that users can do things like ":r! cat /dev/tty". + */ + teardown = ftype != FILTER_WRITE && !ex_sleave(sp); + + /* Fork off the utility process. */ + SIGBLOCK(sp->gp); + switch (utility_pid = vfork()) { + case -1: /* Error. */ + SIGUNBLOCK(sp->gp); + + msgq(sp, M_SYSERR, "vfork"); +err: if (input[0] != -1) + (void)close(input[0]); + if (input[1] != -1) + (void)close(input[1]); + if (ofp != NULL) + (void)fclose(ofp); + else if (output[0] != -1) + (void)close(output[0]); + if (output[1] != -1) + (void)close(output[1]); + rval = 1; + goto ret; + case 0: /* Utility. */ + /* The utility has default signal behavior. */ + sig_end(); + + /* + * Redirect stdin from the read end of the input pipe, and + * redirect stdout/stderr to the write end of the output pipe. + * + * !!! + * Historically, ex only directed stdout into the input pipe, + * letting stderr come out on the terminal as usual. Vi did + * not, directing both stdout and stderr into the input pipe. + * We match that practice for both ex and vi for consistency. + */ + (void)dup2(input[0], STDIN_FILENO); + (void)dup2(output[1], STDOUT_FILENO); + (void)dup2(output[1], STDERR_FILENO); + + /* Close the utility's file descriptors. */ + (void)close(input[0]); + (void)close(input[1]); + (void)close(output[0]); + (void)close(output[1]); + + if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL) + name = O_STR(sp, O_SHELL); + else + ++name; + + execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL); + msgq(sp, M_ERR, "Error: execl: %s: %s", + O_STR(sp, O_SHELL), strerror(errno)); + _exit (127); + /* NOTREACHED */ + default: /* Parent-reader, parent-writer. */ + SIGUNBLOCK(sp->gp); + + /* Close the pipe ends neither parent will use. */ + (void)close(input[0]); + (void)close(output[1]); + break; + } + + /* + * FILTER_READ: + * + * Reading is the simple case -- we don't need a parent writer, + * so the parent reads the output from the read end of the output + * pipe until it finishes, then waits for the child. Ex_readfp + * appends to the MARK, and closes ofp. + * + * !!! + * Set the return cursor to the last line read in. Historically, + * this behaves differently from ":r file" command, which leaves + * the cursor at the first line read in. Check to make sure that + * it's not past EOF because we were reading into an empty file. + */ + if (ftype == FILTER_READ) { + rval = ex_readfp(sp, ep, "filter", ofp, fm, &nread, 0); + sp->rptlines[L_ADDED] += nread; + if (fm->lno == 0) + rp->lno = nread; + else + rp->lno += nread; + goto uwait; + } + + /* + * FILTER, FILTER_WRITE + * + * Here we need both a reader and a writer. Temporary files are + * expensive and we'd like to avoid disk I/O. Using pipes has the + * obvious starvation conditions. It's done as follows: + * + * fork + * child + * write lines out + * exit + * parent + * FILTER: + * read lines into the file + * delete old lines + * FILTER_WRITE + * read and display lines + * wait for child + * + * XXX + * We get away without locking the underlying database because we know + * that none of the records that we're reading will be modified until + * after we've read them. This depends on the fact that the current + * B+tree implementation doesn't balance pages or similar things when + * it inserts new records. When the DB code has locking, we should + * treat vi as if it were multiple applications sharing a database, and + * do the required locking. If necessary a work-around would be to do + * explicit locking in the line.c:file_gline() code, based on the flag + * set here. + */ + rval = 0; + F_SET(ep, F_MULTILOCK); + + SIGBLOCK(sp->gp); + switch (parent_writer_pid = fork()) { + case -1: /* Error. */ + SIGUNBLOCK(sp->gp); + + msgq(sp, M_SYSERR, "fork"); + (void)close(input[1]); + (void)close(output[0]); + rval = 1; + break; + case 0: /* Parent-writer. */ + /* + * Write the selected lines to the write end of the input + * pipe. This instance of ifp is closed by ex_writefp. + */ + (void)close(output[0]); + if ((ifp = fdopen(input[1], "w")) == NULL) + _exit (1); + _exit(ex_writefp(sp, ep, "filter", ifp, fm, tm, NULL, NULL)); + + /* NOTREACHED */ + default: /* Parent-reader. */ + SIGUNBLOCK(sp->gp); + + (void)close(input[1]); + if (ftype == FILTER_WRITE) + /* + * Read the output from the read end of the output + * pipe and display it. Filter_ldisplay closes ofp. + */ + rval = filter_ldisplay(sp, ofp); + else { + /* + * Read the output from the read end of the output + * pipe. Ex_readfp appends to the MARK and closes + * ofp. + */ + rval = ex_readfp(sp, ep, "filter", ofp, tm, &nread, 0); + sp->rptlines[L_ADDED] += nread; + } + + /* Wait for the parent-writer. */ + rval |= proc_wait(sp, + (long)parent_writer_pid, "parent-writer", 1); + + /* Delete any lines written to the utility. */ + if (rval == 0 && ftype == FILTER && + (cut(sp, ep, NULL, fm, tm, CUT_LINEMODE) || + delete(sp, ep, fm, tm, 1))) { + rval = 1; + break; + } + + /* + * If the filter had no output, we may have just deleted + * the cursor. Don't do any real error correction, we'll + * try and recover later. + */ + if (rp->lno > 1 && file_gline(sp, ep, rp->lno, NULL) == NULL) + --rp->lno; + break; + } + F_CLR(ep, F_MULTILOCK); + +uwait: rval |= proc_wait(sp, (long)utility_pid, cmd, 0); + + /* Restore ex/vi terminal settings. */ +ret: if (teardown) + ex_rleave(sp); + return (rval); +} + +/* + * proc_wait -- + * Wait for one of the processes. + * + * !!! + * The pid_t type varies in size from a short to a long depending on the + * system. It has to be cast into something or the standard promotion + * rules get you. I'm using a long based on the belief that nobody is + * going to make it unsigned and it's unlikely to be a quad. + */ +int +proc_wait(sp, pid, cmd, okpipe) + SCR *sp; + long pid; + const char *cmd; + int okpipe; +{ + extern const char *const sys_siglist[]; + size_t len; + int pstat; + + /* + * Wait for the utility to finish. We can get interrupted + * by SIGALRM, just ignore it. + */ + for (;;) { + errno = 0; + if (waitpid((pid_t)pid, &pstat, 0) != -1) + break; + if (errno != EINTR) { + msgq(sp, M_SYSERR, "wait error"); + return (1); + } + } + + /* + * Display the utility's exit status. Ignore SIGPIPE from the + * parent-writer, as that only means that the utility chose to + * exit before reading all of its input. + */ + if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) { + for (; isblank(*cmd); ++cmd); + len = strlen(cmd); + msgq(sp, M_ERR, "%.*s%s: received signal: %s%s", + MIN(len, 20), cmd, len > 20 ? "..." : "", + sys_siglist[WTERMSIG(pstat)], + WCOREDUMP(pstat) ? "; core dumped" : ""); + return (1); + } + if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) { + for (; isblank(*cmd); ++cmd); + len = strlen(cmd); + msgq(sp, M_ERR, "%.*s%s: exited with status %d", + MIN(len, 20), cmd, len > 20 ? "..." : "", + WEXITSTATUS(pstat)); + return (1); + } + return (0); +} + +/* + * filter_ldisplay -- + * Display output from a utility. + * + * !!! + * Historically, the characters were passed unmodified to the terminal. + * We use the ex print routines to make sure they're printable. + */ +static int +filter_ldisplay(sp, fp) + SCR *sp; + FILE *fp; +{ + size_t len; + + EX_PRIVATE *exp; + + F_SET(sp, S_INTERRUPTIBLE); + for (exp = EXP(sp); !ex_getline(sp, fp, &len);) { + if (ex_ldisplay(sp, exp->ibp, len, 0, 0)) + break; + if (INTERRUPTED(sp)) + break; + } + if (ferror(fp)) + msgq(sp, M_SYSERR, "filter input"); + (void)fclose(fp); + return (0); +} diff --git a/usr.bin/vi/ex/script.h b/usr.bin/vi/ex/script.h new file mode 100644 index 0000000..b21c63a --- /dev/null +++ b/usr.bin/vi/ex/script.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)script.h 8.2 (Berkeley) 4/17/94 + */ + +struct _script { + pid_t sh_pid; /* Shell pid. */ + int sh_master; /* Master pty fd. */ + int sh_slave; /* Slave pty fd. */ + char *sh_prompt; /* Prompt. */ + size_t sh_prompt_len; /* Prompt length. */ + char sh_name[64]; /* Pty name */ + struct winsize sh_win; /* Window size. */ + struct termios sh_term; /* Terminal information. */ +}; diff --git a/usr.bin/vi/ex/tag.h b/usr.bin/vi/ex/tag.h new file mode 100644 index 0000000..a9fd59d --- /dev/null +++ b/usr.bin/vi/ex/tag.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tag.h 8.13 (Berkeley) 7/17/94 + */ + +struct _tagf { /* Tag file. */ + TAILQ_ENTRY(_tagf) q; /* Linked list of tag files. */ + char *name; /* Tag file name. */ + +#define TAGF_DNE 0x01 /* Didn't exist. */ +#define TAGF_DNE_WARN 0x02 /* DNE error reported. */ + u_int8_t flags; +}; + +struct _tag { /* Tag stack. */ + TAILQ_ENTRY(_tag) q; /* Linked list of tags. */ + FREF *frp; /* Saved file name. */ + recno_t lno; /* Saved line number. */ + size_t cno; /* Saved column number. */ + char *search; /* Search string. */ + size_t slen; /* Search string length. */ +}; + +int ex_tagalloc __P((SCR *, char *)); +int ex_tagcopy __P((SCR *, SCR *)); +int ex_tagdisplay __P((SCR *, EXF *)); +int ex_tagfirst __P((SCR *, char *)); +int ex_tagfree __P((SCR *)); diff --git a/usr.bin/vi/install/recover.script b/usr.bin/vi/install/recover.script new file mode 100644 index 0000000..9f91e4e --- /dev/null +++ b/usr.bin/vi/install/recover.script @@ -0,0 +1,32 @@ +# @(#)recover.script 8.4 (Berkeley) 8/13/94 +# +# Recover nvi editor files: +RECDIR=/var/tmp/vi.recover +SENDMAIL=/usr/lib/sendmail +echo 'Recovering nvi editor sessions.' + +# Unmodified nvi editor backup files are either zero length or +# have the execute bit set. Delete both cases. +vibackup=`echo $RECDIR/vi.*` +if [ "$vibackup" != "$RECDIR/vi.*" ]; then + for i in $vibackup; do + if test -x $i -o ! -s $i; then + rm $i + fi + done +fi + +# It is possible to get incomplete recovery files, if the editor +# crashes at the right time. Delete any recovery files without +# corresponding backup files, otherwise send mail to the user. +virecovery=`echo $RECDIR/recover.*` +if [ "$virecovery" != "$RECDIR/recover.*" ]; then + for i in $virecovery; do + recfile=`awk '/^X-vi-recover-path:/{print $2}' < $i` + if test ! -n $recfile -a -s $recfile; then + $SENDMAIL -t < $i + else + rm $i + fi + done +fi diff --git a/usr.bin/vi/sex/sex_confirm.c b/usr.bin/vi/sex/sex_confirm.c new file mode 100644 index 0000000..2900928 --- /dev/null +++ b/usr.bin/vi/sex/sex_confirm.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)sex_confirm.c 8.7 (Berkeley) 4/13/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "sex_screen.h" + +enum confirm +sex_confirm(sp, ep, fp, tp) + SCR *sp; + EXF *ep; + MARK *fp, *tp; +{ + CH ikey; + recno_t cnt; + + if (ex_print(sp, ep, fp, tp, 0)) + return (CONF_QUIT); + + for (cnt = fp->cno; cnt; --cnt) + (void)putc(' ', stdout); + for (cnt = tp->cno; cnt; --cnt) + (void)putc('^', stdout); + (void)fprintf(stdout, "[ynq]"); + + if (term_key(sp, &ikey, 0) != INP_OK) + return (CONF_QUIT); + switch (ikey.ch) { + case CH_YES: + return (CONF_YES); + case CH_QUIT: + return (CONF_QUIT); + default: + case CH_NO: + return (CONF_NO); + } + /* NOTREACHED */ +} diff --git a/usr.bin/vi/sex/sex_get.c b/usr.bin/vi/sex/sex_get.c new file mode 100644 index 0000000..a29be5c --- /dev/null +++ b/usr.bin/vi/sex/sex_get.c @@ -0,0 +1,514 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)sex_get.c 8.37 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "../vi/vcmd.h" +#include "sex_screen.h" + +/* + * !!! + * The ex input didn't have escape characters like ^V. The only special + * character was the backslash character, and that only when it preceded + * a newline as part of a substitution replacement pattern. For example, + * the command input ":a\<cr>" failed immediately with an error, as the + * <cr> wasn't part of a substitution replacement pattern. This implies + * a frightening integration of the editor and the RE engine. There's no + * way we're going to reproduce those semantics. So, if backslashes are + * special, this code inserts the backslash and the next character into the + * string, without regard for the character or the command being entered. + * Since "\<cr>" was illegal historically (except for the one special case), + * and the command will fail eventually, historical scripts shouldn't break + * (presuming they didn't depend on the failure mode itself or the characters + * remaining when failure occurred. + */ +static void txt_display __P((SCR *, TEXT *, size_t, size_t *)); +static int txt_outdent __P((SCR *, TEXT *)); + +#define ERASECH { \ + for (cnt = tp->wd[tp->len]; cnt-- > 0; --col) \ + (void)printf("\b \b"); \ +} + +/* + * sex_get -- + * Get lines from the terminal for ex. + */ +enum input +sex_get(sp, ep, tiqh, prompt, flags) + SCR *sp; + EXF *ep; + TEXTH *tiqh; + ARG_CHAR_T prompt; + u_int flags; +{ + /* State of the "[^0]^D" sequences. */ + enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st; + TEXT *ntp, *tp, ait; /* Input and autoindent text structures. */ + CH ikey; /* Input character. */ + size_t col; /* 0-N: screen column. */ + size_t cnt; + int rval, istty; + + /* + * !!! + * Most of the special capabilities (like autoindent, erase, + * etc.) are turned off if ex isn't talking to a terminal. + */ + istty = F_ISSET(sp->gp, G_STDIN_TTY); + + /* + * Get a TEXT structure with some initial buffer space, reusing + * the last one if it's big enough. (All TEXT bookkeeping fields + * default to 0 -- text_init() handles this.) + */ + if (tiqh->cqh_first != (void *)tiqh) { + tp = tiqh->cqh_first; + if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < 32) { + text_lfree(tiqh); + goto newtp; + } + tp->len = 0; + } else { +newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL) + return (INP_ERR); + CIRCLEQ_INSERT_HEAD(tiqh, tp, q); + } + + if (istty) { + /* Display the prompt. */ + if (LF_ISSET(TXT_PROMPT)) { + col = KEY_LEN(sp, prompt); + (void)printf("%s", KEY_NAME(sp, prompt)); + } + + /* Initialize autoindent value and print it out. */ + if (LF_ISSET(TXT_AUTOINDENT)) { + if (txt_auto(sp, ep, sp->lno, NULL, 0, tp)) + return (INP_ERR); + BINC_GOTO(sp, tp->wd, tp->wd_len, tp->len + 1); + for (cnt = 0; cnt < tp->ai; ++cnt) + txt_display(sp, tp, cnt, &col); + } + } else { + col = 0; + + /* Turn off autoindent here, less special casing below. */ + LF_CLR(TXT_AUTOINDENT); + } + + for (carat_st = C_NOTSET;;) { + if (istty) + (void)fflush(stdout); + /* + * !!! + * Historically, ex never mapped commands or keys. + */ + if (rval = term_key(sp, &ikey, 0)) + return (rval); + + if (INTERRUPTED(sp)) + return (INP_INTR); + + BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1); + BINC_GOTO(sp, tp->wd, tp->wd_len, tp->len + 1); + + switch (ikey.value) { + case K_CR: + case K_NL: + /* '\' can escape <carriage-return>/<newline>. */ + if (LF_ISSET(TXT_BACKSLASH) && + tp->len != 0 && tp->lb[tp->len - 1] == '\\') + goto ins_ch; + + /* Echo the newline if requested. */ + if (istty && LF_ISSET(TXT_NLECHO)) { + (void)putc('\r', stdout); + (void)putc('\n', stdout); + (void)fflush(stdout); + } + + /* + * CR returns from the ex command line, interrupt + * always returns. + */ + if (LF_ISSET(TXT_CR)) { + /* Terminate with a nul, needed by filter. */ + tp->lb[tp->len] = '\0'; + return (INP_OK); + } + + /* '.' terminates ex input modes. */ + if (LF_ISSET(TXT_DOTTERM) && + tp->len == tp->ai + 1 && + tp->lb[tp->len - 1] == '.') { + /* Release the current TEXT. */ + ntp = tp->q.cqe_prev; + CIRCLEQ_REMOVE(tiqh, tp, q); + text_free(tp); + tp = ntp; + return (INP_OK); + } + + /* + * If we echoed the newline, display any accumulated + * error messages. + */ + if (LF_ISSET(TXT_NLECHO) && sex_refresh(sp, ep)) + return (INP_ERR); + + /* Set up bookkeeping for the new line. */ + if ((ntp = text_init(sp, NULL, 0, 32)) == NULL) + return (INP_ERR); + ntp->lno = tp->lno + 1; + + /* + * Reset the autoindent line value. 0^D keeps the ai + * line from changing, ^D changes the level, even if + * there are no characters in the old line. Note, + * if using the current tp structure, use the cursor + * as the length, the user may have erased autoindent + * characters. + */ + col = 0; + if (LF_ISSET(TXT_AUTOINDENT)) { + if (carat_st == C_NOCHANGE) { + if (txt_auto(sp, ep, + OOBLNO, &ait, ait.ai, ntp)) + return (INP_ERR); + FREE_SPACE(sp, ait.lb, ait.lb_len); + } else + if (txt_auto(sp, ep, + OOBLNO, tp, tp->len, ntp)) + return (INP_ERR); + carat_st = C_NOTSET; + + if (ntp->ai) { + BINC_GOTO(sp, + ntp->wd, ntp->wd_len, ntp->len + 1); + for (cnt = 0; cnt < ntp->ai; ++cnt) + txt_display(sp, ntp, cnt, &col); + } + } + /* + * Swap old and new TEXT's, and insert the new TEXT + * into the queue. + */ + tp = ntp; + CIRCLEQ_INSERT_TAIL(tiqh, tp, q); + break; + case K_CARAT: /* Delete autoindent chars. */ + if (LF_ISSET(TXT_AUTOINDENT) && tp->len <= tp->ai) + carat_st = C_CARATSET; + goto ins_ch; + case K_ZERO: /* Delete autoindent chars. */ + if (LF_ISSET(TXT_AUTOINDENT) && tp->len <= tp->ai) + carat_st = C_ZEROSET; + goto ins_ch; + case K_CNTRLD: /* Delete autoindent char. */ + /* + * !!! + * Historically, the ^D command took (but then ignored) + * a count. For simplicity, we don't return it unless + * it's the first character entered. The check for len + * equal to 0 is okay, TXT_AUTOINDENT won't be set. + */ + if (LF_ISSET(TXT_CNTRLD)) { + for (cnt = 0; cnt < tp->len; ++cnt) + if (!isblank(tp->lb[cnt])) + break; + if (cnt == tp->len) { + tp->len = 1; + tp->lb[0] = '\004'; + tp->lb[1] = '\0'; + return (INP_OK); + } + } + + /* + * If in the first column or no characters to erase, + * ignore the ^D (this matches historic practice). If + * not doing autoindent or already inserted non-ai + * characters, it's a literal. The latter test is done + * in the switch, as the CARAT forms are N + 1, not N. + */ + if (!LF_ISSET(TXT_AUTOINDENT)) + goto ins_ch; + if (tp->len == 0) + break; + switch (carat_st) { + case C_CARATSET: /* ^^D */ + if (tp->len > tp->ai + 1) + goto ins_ch; + /* Save the ai string for later. */ + ait.lb = NULL; + ait.lb_len = 0; + BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai); + memmove(ait.lb, tp->lb, tp->ai); + ait.ai = ait.len = tp->ai; + + carat_st = C_NOCHANGE; + goto leftmargin; + case C_ZEROSET: /* 0^D */ + if (tp->len > tp->ai + 1) + goto ins_ch; + carat_st = C_NOTSET; +leftmargin: (void)printf("\b \r"); + tp->ai = tp->len = 0; + break; + case C_NOTSET: /* ^D */ + if (tp->len > tp->ai) + goto ins_ch; + if (txt_outdent(sp, tp)) + return (INP_ERR); + break; + default: + abort(); + } + break; + case K_VERASE: + if (!istty) + goto ins_ch; + if (tp->len) { + --tp->len; + if (tp->lb[tp->len] == '\n' || + tp->lb[tp->len] == '\r') + goto repaint; + ERASECH; + } + break; + case K_VWERASE: + if (!istty) + goto ins_ch; + + /* Move to the last non-space character. */ + while (tp->len) { + --tp->len; + if (tp->lb[tp->len] == '\n' || + tp->lb[tp->len] == '\r') + goto repaint; + if (!isblank(tp->lb[tp->len])) { + ++tp->len; + break; + } else + ERASECH; + } + + /* Move to the last space character. */ + while (tp->len) { + --tp->len; + if (tp->lb[tp->len] == '\n' || + tp->lb[tp->len] == '\r') + goto repaint; + if (isblank(tp->lb[tp->len])) { + ++tp->len; + break; + } else + ERASECH; + } + break; + case K_VKILL: + if (!istty) + goto ins_ch; + while (tp->len) { + --tp->len; + if (tp->lb[tp->len] == '\n' || + tp->lb[tp->len] == '\r') { + tp->len = 0; + goto repaint; + } + ERASECH; + } + break; + /* + * XXX + * Historic practice is that ^Z suspended command mode, and + * that it was unaffected by the autowrite option. ^Z ended + * insert mode, retaining all but the current line of input, + * which was discarded. When ex was foregrounded, it was in + * command mode. I don't want to discard input because a user + * tried to enter a ^Z, and I'd like to be consistent with vi. + * So, nex matches vi's historic practice, and doesn't permit + * ^Z in input mode. + */ + case K_CNTRLZ: + if (!istty || !LF_ISSET(TXT_EXSUSPEND)) + goto ins_ch; + sex_suspend(sp); + goto repaint; + case K_CNTRLR: + if (!istty) + goto ins_ch; +repaint: if (LF_ISSET(TXT_PROMPT)) { + col = KEY_LEN(sp, prompt); + (void)printf("\r%s", KEY_NAME(sp, prompt)); + } else { + col = 0; + (void)putc('\r', stdout); + } + for (cnt = 0; cnt < tp->len; ++cnt) + txt_display(sp, tp, cnt, &col); + break; + default: + /* + * See the TXT_BEAUTIFY comment in vi/v_ntext.c. + * + * Silently eliminate any iscntrl() character that + * wasn't already handled specially, except for <tab> + * and <ff>. + */ +ins_ch: if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ikey.ch) && + ikey.value != K_FORMFEED && ikey.value != K_TAB) + break; + tp->lb[tp->len] = ikey.ch; + if (istty) + txt_display(sp, tp, tp->len, &col); + ++tp->len; + break; + } + } + /* NOTREACHED */ + +binc_err: + return (INP_ERR); +} + +/* + * txt_display -- + * Display the character. + */ +static void +txt_display(sp, tp, off, colp) + SCR *sp; + TEXT *tp; + size_t off, *colp; +{ + CHAR_T ch; + size_t width; + + switch (ch = tp->lb[off]) { + case '\t': + *colp += tp->wd[off] = width = + O_VAL(sp, O_TABSTOP) - *colp % O_VAL(sp, O_TABSTOP); + while (width--) + putc(' ', stdout); + break; + case '\n': + case '\r': + (void)putc('\r', stdout); + (void)putc('\n', stdout); + break; + default: + *colp += tp->wd[off] = KEY_LEN(sp, ch); + (void)printf("%s", KEY_NAME(sp, ch)); + } +} + +/* + * txt_outdent -- + * Handle ^D outdents. + * + * Ex version of vi/v_ntext.c:txt_outdent(). See that code for the + * usual ranting and raving. + */ +static int +txt_outdent(sp, tp) + SCR *sp; + TEXT *tp; +{ + u_long sw, ts; + size_t cno, cnt, off, scno, spaces; + + ts = O_VAL(sp, O_TABSTOP); + sw = O_VAL(sp, O_SHIFTWIDTH); + + /* Get the current screen column. */ + for (off = scno = 0; off < tp->len; ++off) + if (tp->lb[off] == '\t') + scno += STOP_OFF(scno, ts); + else + ++scno; + + /* Get the previous shiftwidth column. */ + for (cno = scno; --scno % sw != 0;); + + /* Decrement characters until less than or equal to that slot. */ + for (; cno > scno; --tp->ai) { + for (cnt = tp->wd[--tp->len]; cnt-- > 0;) + (void)printf("\b \b"); + if (tp->lb[--off] == '\t') + cno -= STOP_OFF(cno, ts); + else + --cno; + } + + /* Spaces needed to get to the target. */ + spaces = scno - cno; + + /* Maybe just a delete. */ + if (spaces == 0) + return (0); + + /* Make sure there's enough room. */ + BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces); + + /* Maybe that was enough. */ + if (spaces == 0) + return (0); + + /* Add new space characters. */ + for (; spaces--; ++tp->ai) + tp->lb[tp->len++] = ' '; + return (0); +} diff --git a/usr.bin/vi/sex/sex_refresh.c b/usr.bin/vi/sex/sex_refresh.c new file mode 100644 index 0000000..c1be816 --- /dev/null +++ b/usr.bin/vi/sex/sex_refresh.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)sex_refresh.c 8.14 (Berkeley) 7/15/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "sex_screen.h" + +#ifndef SYSV_CURSES +#define A_NORMAL 1 +#define A_STANDOUT 2 +#define vidattr(attr) Xvidattr(sp, attr) + +static int Xvidattr __P((SCR *, int)); +#endif + +/* + * sex_refresh -- + * In ex, just display any messages. + */ +int +sex_refresh(sp, ep) + SCR *sp; + EXF *ep; +{ + MSG *mp; + + /* Check for screen resize. */ + if (F_ISSET(sp, S_RESIZE)) { + sp->rows = O_VAL(sp, O_LINES); + sp->cols = O_VAL(sp, O_COLUMNS); + F_CLR(sp, S_RESIZE); + } + + /* Ring the bell. */ + if (F_ISSET(sp, S_BELLSCHED)) { + sex_bell(sp); + F_CLR(sp, S_BELLSCHED); + } + + /* Display messages. */ + for (mp = sp->msgq.lh_first; + mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next) { + if (F_ISSET(mp, M_INV_VIDEO) && + vidattr(A_STANDOUT) == ERR && O_ISSET(sp, O_ERRORBELLS)) + (void)printf("\07"); + (void)printf("%.*s.\n", (int)mp->len, mp->mbuf); + F_SET(mp, M_EMPTY); + + if (F_ISSET(mp, M_INV_VIDEO)) + vidattr(A_NORMAL); + (void)fflush(stdout); + } + return (0); +} + +#ifndef SYSV_CURSES +/* + * Xvidattr -- + * Set the video attributes to a value. + * + * XXX + * Just enough to make the above code work when using non-System V + * curses. + */ +static int +Xvidattr(sp, attr) + SCR *sp; + int attr; +{ + SEX_PRIVATE *sxp; + + sxp = SXP(sp); + + /* Check to see if standout isn't available. */ + if (sxp->SO == NULL) + return (ERR); + + switch (attr) { + case A_NORMAL: + (void)tputs(SXP(sp)->SE, 1, vi_putchar); + break; + case A_STANDOUT: + (void)tputs(SXP(sp)->SO, 1, vi_putchar); + break; + default: + abort(); + } + return (0); +} +#endif diff --git a/usr.bin/vi/sex/sex_screen.c b/usr.bin/vi/sex/sex_screen.c new file mode 100644 index 0000000..4338998 --- /dev/null +++ b/usr.bin/vi/sex/sex_screen.c @@ -0,0 +1,340 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)sex_screen.c 8.47 (Berkeley) 7/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "sex_screen.h" +#include "../svi/svi_screen.h" + +static void sex_abort __P((void)); +static int sex_noop __P((void)); +static int sex_nope __P((SCR *)); +static int sex_term_init __P((SCR *)); +static void so_se_init __P((SCR *)); + +/* + * sex_screen_init -- + * Initialize the ex screen. + */ +int +sex_screen_init(sp) + SCR *sp; +{ + /* Initialize support routines. */ + sp->s_bell = sex_bell; + sp->s_bg = (int (*)())sex_nope; + sp->s_busy = (int (*)())sex_busy; + sp->s_change = (int (*)())sex_noop; + sp->s_clear = (int (*)())sex_noop; + sp->s_colpos = (size_t (*)())sex_abort; + sp->s_column = (int (*)())sex_abort; + sp->s_confirm = sex_confirm; + sp->s_crel = (int (*)())sex_nope; + sp->s_edit = sex_screen_edit; + sp->s_end = (int (*)())sex_noop; + sp->s_ex_cmd = (int (*)())sex_abort; + sp->s_ex_run = (int (*)())sex_abort; + sp->s_ex_write = (int (*)())sex_abort; + sp->s_fg = (int (*)())sex_nope; + sp->s_fill = (int (*)())sex_abort; + sp->s_get = sex_get; + sp->s_key_read = sex_key_read; + sp->s_optchange = sex_optchange; + sp->s_fmap = (int (*)())sex_noop; + sp->s_position = (int (*)())sex_abort; + sp->s_rabs = (int (*)())sex_nope; + sp->s_rcm = (size_t (*)())sex_abort; + sp->s_refresh = sex_refresh; + sp->s_scroll = (int (*)())sex_abort; + sp->s_split = (int (*)())sex_nope; + sp->s_suspend = sex_suspend; + sp->s_window = sex_window; + + return (0); +} + +/* + * sex_screen_copy -- + * Copy to a new screen. + */ +int +sex_screen_copy(orig, sp) + SCR *orig, *sp; +{ + SEX_PRIVATE *osex, *nsex; + + /* Create the private screen structure. */ + CALLOC_RET(orig, nsex, SEX_PRIVATE *, 1, sizeof(SEX_PRIVATE)); + sp->sex_private = nsex; + +/* INITIALIZED AT SCREEN CREATE. */ + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ + if (orig == NULL) { + } else { + osex = SXP(orig); +#ifndef SYSV_CURSES + if (osex->SE != NULL && (nsex->SE = strdup(osex->SE)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + if (osex->SO != NULL && (nsex->SO = strdup(osex->SO)) == NULL) { + msgq(sp, M_SYSERR, NULL); + free(osex->SE); + return (1); + } +#endif + } + + return (0); +} + +/* + * sex_screen_end -- + * End a screen. + */ +int +sex_screen_end(sp) + SCR *sp; +{ +#ifndef SYSV_CURSES + /* Free inverse video strings. */ + if (SXP(sp)->SE != NULL) + free(SXP(sp)->SE); + if (SXP(sp)->SO != NULL) + free(SXP(sp)->SO); +#endif + + /* Free private memory. */ + FREE(SXP(sp), sizeof(SEX_PRIVATE)); + sp->sex_private = NULL; + + return (0); +} + +/* + * sex_screen_edit -- + * Main ex screen loop. The ex screen is relatively uncomplicated. + * As long as it has a stdio FILE pointer for output, it's happy. + */ +int +sex_screen_edit(sp, ep) + SCR *sp; + EXF *ep; +{ + struct termios t; + GS *gp; + int force, rval; + + /* Initialize the terminal state. */ + gp = sp->gp; + if (F_ISSET(gp, G_STDIN_TTY)) + SEX_RAW(t); + + /* Write to the terminal. */ + sp->stdfp = stdout; + + /* + * The resize bit is probably set, but clear it, we're + * going to initialize the screen right now. + */ + F_CLR(sp, S_RESIZE); + + /* Initialize the termcap buffer. */ + if (sex_term_init(sp)) + return (1); + + for (;;) { + /* + * Run ex. If ex fails, sex data structures + * may be corrupted, be careful what you do. + */ + if (rval = ex(sp, sp->ep)) { + (void)rcv_sync(sp, sp->ep, + RCV_EMAIL | RCV_ENDSESSION | RCV_PRESERVE); + (void)screen_end(sp); /* General SCR info. */ + break; + } + + force = 0; + switch (F_ISSET(sp, S_MAJOR_CHANGE)) { + case S_EXIT_FORCE: + force = 1; + /* FALLTHROUGH */ + case S_EXIT: + F_CLR(sp, S_EXIT_FORCE | S_EXIT); + if (file_end(sp, sp->ep, force)) + break; + (void)screen_end(sp); /* General SCR info. */ + goto ret; + case 0: /* Changing from ex mode. */ + goto ret; + case S_FSWITCH: + F_CLR(sp, S_FSWITCH); + break; + case S_SSWITCH: + default: + abort(); + } + } + + /* Reset the terminal state. */ +ret: if (F_ISSET(gp, G_STDIN_TTY) && SEX_NORAW(t)) + rval = 1; + return (rval); +} + +/* + * sex_term_init -- + * Initialize ex's relationship with the termcap/terminfo entry. + */ +static int +sex_term_init(sp) + SCR *sp; +{ + +#ifndef SYSV_CURSES + /* Initialize standout information. */ + so_se_init(sp); +#endif + + sp->rows = O_VAL(sp, O_LINES); + sp->cols = O_VAL(sp, O_COLUMNS); + return (0); +} + +#ifndef SYSV_CURSES +/* + * so_se_init -- + * Initialize the inverse video strings. + */ +static void +so_se_init(sp) + SCR *sp; +{ + SEX_PRIVATE *sxp; + size_t len; + char *s, *t, buf[128], tbuf[2048]; + + if (tgetent(tbuf, O_STR(sp, O_TERM)) != 1) + return; + + sxp = SXP(sp); + + /* Get SE. */ + t = buf; + if ((t = tgetstr("se", &t)) == NULL) + return; + if ((len = strlen(t)) == 0) + return; + MALLOC_NOMSG(sp, s, char *, len + 1); + if (s == NULL) + return; + memmove(s, buf, len); + s[len] = '\0'; + sxp->SE = s; + + /* Get SO. */ + t = buf; + if ((t = tgetstr("so", &t)) == NULL) + goto err; + if ((len = strlen(t)) == 0) + goto err; + MALLOC_NOMSG(sp, s, char *, len + 1); + if (s == NULL) + goto err; + memmove(s, buf, len); + s[len] = '\0'; + sxp->SO = s; + + return; + +err: free(sxp->SE); + sxp->SE = NULL; + return; +} +#endif + +/* + * sex_abort -- + * Fake function. Die. + */ +static void +sex_abort() +{ + abort(); +} + +/* + * sex_noop -- + * Fake function. Do nothing. + */ +static int +sex_noop() +{ + return (0); +} + +/* + * sex_nope -- + * Fake function. Not in ex, you don't. + */ +static int +sex_nope(sp) + SCR *sp; +{ + msgq(sp, M_ERR, "Command not applicable to ex mode"); + return (1); +} diff --git a/usr.bin/vi/sex/sex_screen.h b/usr.bin/vi/sex/sex_screen.h new file mode 100644 index 0000000..150e38f --- /dev/null +++ b/usr.bin/vi/sex/sex_screen.h @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)sex_screen.h 8.20 (Berkeley) 8/8/94 + */ + +#define SEX_NORAW(t) \ + tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &(t)) + +#define SEX_RAW(t) { \ + struct termios __rawt; \ + if (tcgetattr(STDIN_FILENO, &(t))) \ + return (1); \ + __rawt = (t); \ + __rawt.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INLCR|IGNCR|ICRNL); \ + __rawt.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); \ + __rawt.c_oflag |= OPOST | ONLCR; \ + __rawt.c_cc[VMIN] = 1; \ + __rawt.c_cc[VTIME] = 0; \ + if (tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &__rawt)) \ + return (1); \ +} + +typedef struct _sex_private { +/* INITIALIZED AT SCREEN CREATE. */ + int __unused; /* Make sure it's not empty. */ + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ +#ifndef SYSV_CURSES + char *SE, *SO; /* Inverse video termcap strings. */ +#endif +} SEX_PRIVATE; + +#define SXP(sp) ((SEX_PRIVATE *)((sp)->sex_private)) + +void sex_bell __P((SCR *)); +void sex_busy __P((SCR *, char const *)); +enum confirm + sex_confirm __P((SCR *, EXF *, MARK *, MARK *)); +enum input + sex_get __P((SCR *, EXF *, TEXTH *, ARG_CHAR_T, u_int)); +enum input + sex_key_read __P((SCR *, int *, struct timeval *)); +int sex_optchange __P((SCR *, int)); +int sex_refresh __P((SCR *, EXF *)); +int sex_screen_copy __P((SCR *, SCR *)); +int sex_screen_edit __P((SCR *, EXF *)); +int sex_screen_end __P((SCR *)); +int sex_suspend __P((SCR *)); +int sex_window __P((SCR *, int)); diff --git a/usr.bin/vi/sex/sex_term.c b/usr.bin/vi/sex/sex_term.c new file mode 100644 index 0000000..93ca048 --- /dev/null +++ b/usr.bin/vi/sex/sex_term.c @@ -0,0 +1,217 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)sex_term.c 8.38 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "../ex/script.h" + +/* + * sex_key_read -- + * Read characters from the input. + */ +enum input +sex_key_read(sp, nrp, timeout) + SCR *sp; + int *nrp; + struct timeval *timeout; +{ + struct timeval t, *tp; + GS *gp; + IBUF *tty; + int maxfd, nr; + + *nrp = 0; + gp = sp->gp; + tty = gp->tty; + + /* + * We're about to block; check for signals. If a signal received, + * clear it immediately, so that if it's reset while being serviced + * we won't miss it. + * + * These signal recipients set global flags. None of this has + * anything to do with input keys, but it's something that can't + * be done asynchronously without adding locking to handle race + * conditions, and which needs to be done periodically. + */ +sigchk: while (F_ISSET(gp, G_SIGINT | G_SIGWINCH)) { + if (F_ISSET(gp, G_SIGINT)) + return (INP_INTR); + if (F_ISSET(gp, G_SIGWINCH)) { + F_CLR(gp, G_SIGWINCH); + if (!sp->s_window(sp, 1)) + (void)sp->s_refresh(sp, sp->ep); + } + } + + /* + * There are three cases here: + * + * 1: A read from a file or a pipe. In this case, the reads + * never timeout regardless. This means that we can hang + * when trying to complete a map, but we're going to hang + * on the next read anyway. + */ + if (!F_ISSET(gp, G_STDIN_TTY)) { + if ((nr = read(STDIN_FILENO, + tty->ch + tty->next + tty->cnt, + tty->nelem - (tty->next + tty->cnt))) > 0) + goto success; + return (INP_EOF); + } + + /* + * 2: A read with an associated timeout. In this case, we are trying + * to complete a map sequence. Ignore script windows and timeout + * as specified. If input arrives, we fall into #3, but because + * timeout isn't NULL, don't read anything but command input. + * + * If interrupted, go back and check to see what it was. + */ + if (timeout != NULL) { + if (F_ISSET(sp, S_SCRIPT)) + FD_CLR(sp->script->sh_master, &sp->rdfd); + FD_SET(STDIN_FILENO, &sp->rdfd); + for (;;) { + switch (select(STDIN_FILENO + 1, + &sp->rdfd, NULL, NULL, timeout)) { + case -1: /* Error or interrupt. */ + if (errno == EINTR) + goto sigchk; + goto err; + case 1: /* Characters ready. */ + break; + case 0: /* Timeout. */ + return (INP_OK); + } + break; + } + } + + /* + * 3: At this point, we'll take anything that comes. Select on the + * command file descriptor and the file descriptor for the script + * window if there is one. Poll the fd's, increasing the timeout + * each time each time we don't get anything until we're blocked + * on I/O. + * + * If interrupted, go back and check to see what it was. + */ + for (t.tv_sec = t.tv_usec = 0;;) { + /* + * Reset each time -- sscr_input() may call other + * routines which could reset bits. + */ + if (timeout == NULL && F_ISSET(sp, S_SCRIPT)) { + tp = &t; + + FD_SET(STDIN_FILENO, &sp->rdfd); + if (F_ISSET(sp, S_SCRIPT)) { + FD_SET(sp->script->sh_master, &sp->rdfd); + maxfd = + MAX(STDIN_FILENO, sp->script->sh_master); + } else + maxfd = STDIN_FILENO; + } else { + tp = NULL; + + FD_SET(STDIN_FILENO, &sp->rdfd); + if (F_ISSET(sp, S_SCRIPT)) + FD_CLR(sp->script->sh_master, &sp->rdfd); + maxfd = STDIN_FILENO; + } + + switch (select(maxfd + 1, &sp->rdfd, NULL, NULL, tp)) { + case -1: /* Error or interrupt. */ + if (errno == EINTR) + goto sigchk; +err: msgq(sp, M_SYSERR, "select"); + return (INP_ERR); + case 0: /* Timeout. */ + if (t.tv_usec) { + ++t.tv_sec; + t.tv_usec = 0; + } else + t.tv_usec += 500000; + continue; + } + + if (timeout == NULL && F_ISSET(sp, S_SCRIPT) && + FD_ISSET(sp->script->sh_master, &sp->rdfd)) { + sscr_input(sp); + continue; + } + + switch (nr = read(STDIN_FILENO, + tty->ch + tty->next + tty->cnt, + tty->nelem - (tty->next + tty->cnt))) { + case 0: /* EOF. */ + return (INP_EOF); + case -1: /* Error or interrupt. */ + if (errno == EINTR) + goto sigchk; + msgq(sp, M_SYSERR, "read"); + return (INP_ERR); + default: + goto success; + } + /* NOTREACHED */ + } + +success: + MEMSET(tty->chf + tty->next + tty->cnt, 0, nr); + tty->cnt += *nrp = nr; + return (INP_OK); +} diff --git a/usr.bin/vi/sex/sex_util.c b/usr.bin/vi/sex/sex_util.c new file mode 100644 index 0000000..5acd788 --- /dev/null +++ b/usr.bin/vi/sex/sex_util.c @@ -0,0 +1,148 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)sex_util.c 8.15 (Berkeley) 7/16/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "sex_screen.h" + +/* + * sex_bell -- + * Ring the bell. + */ +void +sex_bell(sp) + SCR *sp; +{ + (void)write(STDOUT_FILENO, "\07", 1); /* \a */ +} + +void +sex_busy(sp, msg) + SCR *sp; + char const *msg; +{ + (void)fprintf(stdout, "%s\n", msg); + (void)fflush(stdout); +} + +/* + * sex_optchange -- + * Screen specific "option changed" routine. + */ +int +sex_optchange(sp, opt) + SCR *sp; + int opt; +{ + switch (opt) { + case O_TERM: + /* Reset the screen size. */ + if (sp->s_window(sp, 0)) + return (1); + F_SET(sp, S_RESIZE); + break; + } + + (void)ex_optchange(sp, opt); + + return (0); +} + +/* + * sex_suspend -- + * Suspend an ex screen. + */ +int +sex_suspend(sp) + SCR *sp; +{ + struct termios t; + GS *gp; + int rval; + + rval = 0; + + /* Save current terminal settings, and restore the original ones. */ + gp = sp->gp; + if (F_ISSET(gp, G_STDIN_TTY)) { + if (tcgetattr(STDIN_FILENO, &t)) { + msgq(sp, M_SYSERR, "suspend: tcgetattr"); + return (1); + } + if (F_ISSET(gp, G_TERMIOS_SET) && tcsetattr(STDIN_FILENO, + TCSASOFT | TCSADRAIN, &gp->original_termios)) { + msgq(sp, M_SYSERR, "suspend: tcsetattr original"); + return (1); + } + } + + /* Push out any waiting messages. */ + (void)sex_refresh(sp, sp->ep); + + /* Stop the process group. */ + if (kill(0, SIGTSTP)) { + msgq(sp, M_SYSERR, "suspend: kill"); + rval = 1; + } + + /* Time passes ... */ + + /* Restore current terminal settings. */ + if (F_ISSET(gp, G_STDIN_TTY) && + tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t)) { + msgq(sp, M_SYSERR, "suspend: tcsetattr current"); + rval = 1; + } + return (rval); +} diff --git a/usr.bin/vi/sex/sex_window.c b/usr.bin/vi/sex/sex_window.c new file mode 100644 index 0000000..37fc8ed --- /dev/null +++ b/usr.bin/vi/sex/sex_window.c @@ -0,0 +1,194 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)sex_window.c 8.6 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" + +/* + * sex_window -- + * Set the window size. + */ +int +sex_window(sp, sigwinch) + SCR *sp; + int sigwinch; +{ + struct winsize win; + size_t col, row; + int rval, user_set; + ARGS *argv[2], a, b; + char *s, buf[2048]; + + /* + * Get the screen rows and columns. If the values are wrong, it's + * not a big deal -- as soon as the user sets them explicitly the + * environment will be set and the screen package will use the new + * values. + * + * Try TIOCGWINSZ. + */ + row = col = 0; +#ifdef TIOCGWINSZ + if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1) { + row = win.ws_row; + col = win.ws_col; + } +#endif + /* If here because of a signal, TIOCGWINSZ is all we trust. */ + if (sigwinch) { + if (row == 0 || col == 0) { + msgq(sp, M_SYSERR, "TIOCGWINSZ"); + return (1); + } + + /* + * !!! + * SunOS systems deliver SIGWINCH when windows are uncovered + * as well as when they change size. In addition, we call + * here when continuing after being suspended since the window + * may have changed size. Since we don't want to background + * all of the screens just because the window was uncovered, + * ignore the signal if there's no change. + */ + if (row == O_VAL(sp, O_LINES) && col == O_VAL(sp, O_COLUMNS)) + return (1); + + goto sigw; + } + + /* + * !!! + * If TIOCGWINSZ failed, or had entries of 0, try termcap. This + * routine is called before any termcap or terminal information + * has been set up. If there's no TERM environmental variable set, + * let it go, at least ex can run. + */ + if (row == 0 || col == 0) { + if ((s = getenv("TERM")) == NULL) + goto noterm; +#ifdef SYSV_CURSES + if (row == 0) + if ((rval = tigetnum("lines")) < 0) + msgq(sp, M_SYSERR, "tigetnum: lines"); + else + row = rval; + if (col == 0) + if ((rval = tigetnum("cols")) < 0) + msgq(sp, M_SYSERR, "tigetnum: cols"); + else + col = rval; +#else + switch (tgetent(buf, s)) { + case -1: + msgq(sp, M_SYSERR, "tgetent: %s", s); + return (1); + case 0: + msgq(sp, M_ERR, "%s: unknown terminal type", s); + return (1); + } + if (row == 0) + if ((rval = tgetnum("li")) < 0) + msgq(sp, M_ERR, + "no \"li\" capability for %s", s); + else + row = rval; + if (col == 0) + if ((rval = tgetnum("co")) < 0) + msgq(sp, M_ERR, + "no \"co\" capability for %s", s); + else + col = rval; +#endif + } + + /* If nothing else, well, it's probably a VT100. */ +noterm: if (row == 0) + row = 24; + if (col == 0) + col = 80; + + /* POSIX 1003.2 requires the environment to override. */ + if ((s = getenv("LINES")) != NULL) + row = strtol(s, NULL, 10); + if ((s = getenv("COLUMNS")) != NULL) + col = strtol(s, NULL, 10); + +sigw: a.bp = buf; + b.bp = NULL; + b.len = 0; + argv[0] = &a; + argv[1] = &b;; + + /* + * Tell the options code that the screen size has changed. + * Since the user didn't do the set, clear the set bits. + */ + user_set = F_ISSET(&sp->opts[O_LINES], OPT_SET); + a.len = snprintf(buf, sizeof(buf), "lines=%u", row); + if (opts_set(sp, NULL, argv)) + return (1); + if (user_set) + F_CLR(&sp->opts[O_LINES], OPT_SET); + + user_set = F_ISSET(&sp->opts[O_COLUMNS], OPT_SET); + a.len = snprintf(buf, sizeof(buf), "columns=%u", col); + if (opts_set(sp, NULL, argv)) + return (1); + if (user_set) + F_CLR(&sp->opts[O_COLUMNS], OPT_SET); + + F_SET(sp, S_RESIZE); + return (0); +} diff --git a/usr.bin/vi/svi/svi_confirm.c b/usr.bin/vi/svi/svi_confirm.c new file mode 100644 index 0000000..06ef25c --- /dev/null +++ b/usr.bin/vi/svi/svi_confirm.c @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_confirm.c 8.8 (Berkeley) 4/13/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "svi_screen.h" + +enum confirm +svi_confirm(sp, ep, fp, tp) + SCR *sp; + EXF *ep; + MARK *fp, *tp; +{ + CH ikey; + size_t oldy, oldx; + + /* + * Refresh the cursor first -- this means that we won't have to + * set S_UPDATE_MODE to keep refresh from erasing the mode line + * or SVI_CUR_INVALID because we sneaked the cursor off somewhere + * else. + */ + sp->lno = fp->lno; + sp->cno = fp->cno; + if (svi_paint(sp, ep)) + return (CONF_QUIT); + + getyx(stdscr, oldy, oldx); + MOVE(sp, INFOLINE(sp), 0); + clrtoeol(); + ADDNSTR(STR_CONFIRM, sizeof(STR_CONFIRM) - 1); + MOVEA(sp, oldy, oldx); + refresh(); + + if (term_key(sp, &ikey, 0) != INP_OK) + return (CONF_QUIT); + switch (ikey.ch) { + case CH_YES: + return (CONF_YES); + case CH_QUIT: + return (CONF_QUIT); + default: + case CH_NO: + return (CONF_NO); + } + /* NOTREACHED */ +} diff --git a/usr.bin/vi/svi/svi_curses.c b/usr.bin/vi/svi/svi_curses.c new file mode 100644 index 0000000..523fff9 --- /dev/null +++ b/usr.bin/vi/svi/svi_curses.c @@ -0,0 +1,252 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_curses.c 8.3 (Berkeley) 8/7/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "svi_screen.h" + +/* + * svi_curses_init -- + * Initialize curses. + */ +int +svi_curses_init(sp) + SCR *sp; +{ + struct termios t; + char *p; + +#ifdef SYSV_CURSES + /* + * The SunOS/System V initscr() isn't reentrant. Don't even think + * about trying to use it. It fails in subtle ways (e.g. select(2) + * on fileno(stdin) stops working). We don't care about the SCREEN + * reference returned by newterm, we never have more than one SCREEN + * at a time. + */ + errno = 0; + if (newterm(O_STR(sp, O_TERM), stdout, stdin) == NULL) { + msgq(sp, errno ? M_SYSERR : M_ERR, "newterm failed"); + return (1); + } +#else + /* + * Initscr() doesn't provide useful error values or messages. The + * reasonable guess is that either malloc failed or the terminal was + * unknown or lacking some essential feature. Try and guess so the + * user isn't even more pissed off because of the error message. + */ + errno = 0; + if (initscr() == NULL) { + char kbuf[2048]; + msgq(sp, errno ? M_SYSERR : M_ERR, "initscr failed"); + if ((p = getenv("TERM")) == NULL || !strcmp(p, "unknown")) + msgq(sp, M_ERR, + "No TERM environment variable set, or TERM set to \"unknown\""); + else if (tgetent(kbuf, p) != 1) + msgq(sp, M_ERR, +"%s: unknown terminal type, or terminal lacks necessary features", p); + else + msgq(sp, M_ERR, + "%s: terminal type lacks necessary features", p); + return (1); + } +#endif + /* + * We use raw mode. What we want is 8-bit clean, however, signals + * and flow control should continue to work. Admittedly, it sounds + * like cbreak, but it isn't. Using cbreak() can get you additional + * things like IEXTEN, which turns on things like DISCARD and LNEXT. + * + * !!! + * If raw isn't turning off echo and newlines, something's wrong. + * However, it doesn't hurt. + */ + noecho(); /* No character echo. */ + nonl(); /* No CR/NL translation. */ + raw(); /* 8-bit clean. */ + idlok(stdscr, 1); /* Use hardware insert/delete line. */ + + /* + * XXX + * Historic implementations of curses handled SIGTSTP signals + * in one of three ways. They either: + * + * 1: Set their own handler, regardless. + * 2: Did not set a handler if a handler was already installed. + * 3: Set their own handler, but then called any previously set + * handler after completing their own cleanup. + * + * We don't try and figure out which behavior is in place, we + * just set it to SIG_DFL after initializing the curses interface. + */ + (void)signal(SIGTSTP, SIG_DFL); + + /* + * If flow control was on, turn it back on. Turn signals on. ISIG + * turns on VINTR, VQUIT, VDSUSP and VSUSP. See signal.c:sig_init() + * for a discussion of what's going on here. To sum up, sig_init() + * already installed a handler for VINTR. We're going to disable the + * other three. + * + * XXX + * We want to use ^Y as a vi scrolling command. If the user has the + * DSUSP character set to ^Y (common practice) clean it up. As it's + * equally possible that the user has VDSUSP set to 'a', we disable + * it regardless. It doesn't make much sense to suspend vi at read, + * so I don't think anyone will care. Alternatively, we could look + * it up in the table of legal command characters and turn it off if + * it matches one. VDSUSP wasn't in POSIX 1003.1-1990, so we test for + * it. + * + * XXX + * We don't check to see if the user had signals enabled to start with. + * If they didn't, it's unclear what we're supposed to do here, but it + * is also pretty unlikely. + */ + if (!tcgetattr(STDIN_FILENO, &t)) { + if (sp->gp->original_termios.c_iflag & IXON) + t.c_iflag |= IXON; + if (sp->gp->original_termios.c_iflag & IXOFF) + t.c_iflag |= IXOFF; + + t.c_lflag |= ISIG; +#ifdef VDSUSP + t.c_cc[VDSUSP] = _POSIX_VDISABLE; +#endif + t.c_cc[VQUIT] = _POSIX_VDISABLE; + t.c_cc[VSUSP] = _POSIX_VDISABLE; + + (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); + } + + /* Put the cursor keys into application mode. */ + svi_keypad(sp, 1); + + /* + * The first screen in the list gets it all. All other screens + * are hidden and lose their maps. + */ + svi_dtoh(sp, "Window resize"); + + /* Initialize terminal values. */ + SVP(sp)->srows = O_VAL(sp, O_LINES); + + /* + * Initialize screen values. + * + * Small windows: see svi/svi_refresh.c:svi_refresh, section 3b. + * + * Setup: + * t_minrows is the minimum rows to display + * t_maxrows is the maximum rows to display (rows - 1) + * t_rows is the rows currently being displayed + */ + sp->rows = SVP(sp)->srows; + sp->cols = O_VAL(sp, O_COLUMNS); + sp->woff = 0; + sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW); + if (sp->t_rows > sp->rows - 1) { + sp->t_minrows = sp->t_rows = sp->rows - 1; + msgq(sp, M_INFO, + "Windows option value is too large, max is %u", sp->t_rows); + } + sp->t_maxrows = sp->rows - 1; + + /* Create the screen map. */ + CALLOC(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP)); + if (HMAP == NULL) { + if (endwin() == ERR) + msgq(sp, M_SYSERR, "endwin"); + return (1); + } + TMAP = HMAP + (sp->t_rows - 1); + + F_SET(SVP(sp), SVI_CUR_INVALID); /* Cursor is invalid. */ + F_SET(SVP(sp), SVI_CURSES_INIT); /* It's initialized. */ + + return (0); +} + +/* + * svi_curses_end -- + * Move to the bottom of the screen, end curses. + */ +int +svi_curses_end(sp) + SCR *sp; +{ + /* + * XXX + * By the time we get here, the screen private area (SVI_PRIVATE) + * is probably gone. Don't use it, and don't call any routines + * that do. + * + * Restore the cursor keys to normal mode. + */ + svi_keypad(sp, 0); + + /* Move to the bottom of the screen. */ + if (move(INFOLINE(sp), 0) == OK) { + clrtoeol(); + refresh(); + } + + /* End curses window. */ + if (endwin() == ERR) + msgq(sp, M_SYSERR, "endwin"); + + return (0); +} diff --git a/usr.bin/vi/svi/svi_ex.c b/usr.bin/vi/svi/svi_ex.c new file mode 100644 index 0000000..9b81080b --- /dev/null +++ b/usr.bin/vi/svi/svi_ex.c @@ -0,0 +1,650 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_ex.c 8.54 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "../vi/vcmd.h" +#include "excmd.h" +#include "svi_screen.h" +#include "../sex/sex_screen.h" + +static int svi_ex_divider __P((SCR *)); +static int svi_ex_done __P((SCR *, EXF *, MARK *)); +static int svi_ex_inv __P((SCR *)); +static int svi_ex_scroll __P((SCR *, int, CH *)); + +#define MSGS_WAITING(sp) \ + ((sp)->msgq.lh_first != NULL && \ + !F_ISSET((sp)->msgq.lh_first, M_EMPTY)) + +/* + * svi_ex_cmd -- + * Execute an ex command. + */ +int +svi_ex_cmd(sp, ep, exp, rp) + SCR *sp; + EXF *ep; + EXCMDARG *exp; + MARK *rp; +{ + SVI_PRIVATE *svp; + int rval; + + svp = SVP(sp); + svp->exlcontinue = svp->exlinecount = svp->extotalcount = 0; + + (void)svi_busy(sp, NULL); + rval = exp->cmd->fn(sp, ep, exp); + + (void)msg_rpt(sp, 0); + (void)ex_fflush(EXCOOKIE); + + /* + * If displayed anything, figure out if we have to wait. If the + * screen wasn't trashed, only one line output and there are no + * waiting messages, don't wait, but don't overwrite it with mode + * information either. + */ + if (svp->extotalcount > 0) + if (!F_ISSET(sp, S_REFRESH) && + svp->extotalcount == 1 && !MSGS_WAITING(sp)) { + F_SET(sp, S_UPDATE_MODE); + if (sp->q.cqe_next != (void *)&sp->gp->dq) + (void)svi_ex_inv(sp); + } else { + /* This message isn't interruptible. */ + F_CLR(sp, S_INTERRUPTIBLE); + (void)svi_ex_scroll(sp, 1, NULL); + } + return (svi_ex_done(sp, ep, rp) || rval); +} + +/* + * svi_ex_run -- + * Execute strings of ex commands. + */ +int +svi_ex_run(sp, ep, rp) + SCR *sp; + EXF *ep; + MARK *rp; +{ + enum input (*get) __P((SCR *, EXF *, TEXTH *, ARG_CHAR_T, u_int)); + struct termios t; + CH ikey; + SVI_PRIVATE *svp; + TEXT *tp; + int flags, in_exmode, rval; + + svp = SVP(sp); + svp->exlcontinue = svp->exlinecount = svp->extotalcount = 0; + + /* + * There's some tricky stuff going on here to handle when a user has + * mapped a key to multiple ex commands. Historic practice was that + * vi ran without any special actions, as if the user were entering + * the characters, until ex trashed the screen, e.g. something like a + * '!' command. At that point, we no longer know what the screen + * looks like, so we can't afford to overwrite anything. The solution + * is to go into real ex mode until we get to the end of the command + * strings. + */ + get = svi_get; + flags = TXT_BS | TXT_PROMPT; + for (in_exmode = rval = 0;;) { + /* + * Get the next command. Interrupt flag manipulation is safe + * because ex_icmd clears them all. + */ + F_SET(sp, S_INTERRUPTIBLE); + if (get(sp, ep, sp->tiqp, ':', flags) != INP_OK) { + rval = 1; + break; + } + if (INTERRUPTED(sp)) + break; + + /* + * Len is 0 if the user backspaced over the prompt, + * 1 if only a CR was entered. + */ + tp = sp->tiqp->cqh_first; + if (tp->len == 0) + break; + + if (!in_exmode) + (void)svi_busy(sp, NULL); + + /* Ignore return, presumably an error message was displayed. */ + (void)ex_icmd(sp, ep, tp->lb, tp->len, 0); + (void)ex_fflush(EXCOOKIE); + + /* + * The file or screen may have changed, in which case, the + * main editor loop takes care of it. + */ + if (F_ISSET(sp, S_MAJOR_CHANGE)) + break; + + /* + * If continue not required, and one or no lines, and there + * are no waiting messages, don't wait, but don't overwrite + * it with mode information either. + */ + if (!F_ISSET(sp, S_CONTINUE) && (svp->extotalcount == 0 || + svp->extotalcount == 1 && !MSGS_WAITING(sp))) { + if (svp->extotalcount == 1) { + F_SET(sp, S_UPDATE_MODE); + if (sp->q.cqe_next != (void *)&sp->gp->dq) + svi_ex_inv(sp); + } + break; + } + + if (INTERRUPTED(sp)) + break; + + /* + * If the screen is trashed, or there are messages waiting, + * go into ex mode. + */ + if (!in_exmode && + (F_ISSET(sp, S_REFRESH) || MSGS_WAITING(sp))) { + /* Initialize the terminal state. */ + if (F_ISSET(sp->gp, G_STDIN_TTY)) + SEX_RAW(t); + get = sex_get; + flags = TXT_CR | TXT_NLECHO | TXT_PROMPT; + in_exmode = 1; + } + + /* Display any waiting messages. */ + if (MSGS_WAITING(sp)) + (void)sex_refresh(sp, ep); + + /* + * Get a continue character; users may continue in ex mode by + * entering a ':'. + * + * !!! + * Historic practice is that any key can be used to continue. + * Nvi used to require that the user enter a <carriage-return> + * or <newline>, but this broke historic users. + */ + if (in_exmode) { + (void)write(STDOUT_FILENO, + STR_CMSG, sizeof(STR_CMSG) - 1); + if (term_key(sp, &ikey, 0) != INP_OK) { + rval = 1; + goto ret; + } + } else { + /* This message isn't interruptible. */ + F_CLR(sp, S_INTERRUPTIBLE); + (void)svi_ex_scroll(sp, 1, &ikey); + } + if (ikey.ch != ':') + break; + + if (in_exmode) + (void)write(STDOUT_FILENO, "\n", 1); + else { + ++svp->extotalcount; + ++svp->exlinecount; + } + } + +ret: if (in_exmode) { + /* Reset the terminal state. */ + if (F_ISSET(sp->gp, G_STDIN_TTY) && SEX_NORAW(t)) + rval = 1; + F_SET(sp, S_REFRESH); + } else + if (svi_ex_done(sp, ep, rp)) + rval = 1; + + F_CLR(sp, S_CONTINUE); + return (rval); +} + +/* + * svi_msgflush -- + * Flush any accumulated messages. + */ +int +svi_msgflush(sp) + SCR *sp; +{ + enum {INVERSE, NORMAL} inverse; + SVI_PRIVATE *svp; + MSG *mp; + int rval; + + svp = SVP(sp); + svp->exlcontinue = svp->exlinecount = svp->extotalcount = 0; + + /* + * XXX + * S_IVIDEO is a bit of a kluge. We can only pass a single magic + * cookie into the svi_ex_write routine, and it has to be the SCR + * structure. So, the inverse video bit has to be there. + */ + inverse = NORMAL; + for (mp = sp->msgq.lh_first; + mp != NULL && !F_ISSET(mp, M_EMPTY); mp = mp->q.le_next) { + /* + * If the second and subsequent messages fit on the current + * line, write a separator. Otherwise, put out a newline + * and break the line. + */ + if (mp != sp->msgq.lh_first) + if (mp->len + svp->exlcontinue + 3 >= sp->cols) { + if (inverse == INVERSE) + F_SET(sp, S_IVIDEO); + (void)svi_ex_write(sp, ".\n", 2); + F_CLR(sp, S_IVIDEO); + } else { + if (inverse == INVERSE) + F_SET(sp, S_IVIDEO); + (void)svi_ex_write(sp, ";", 1); + F_CLR(sp, S_IVIDEO); + (void)svi_ex_write(sp, " ", 2); + } + + inverse = F_ISSET(mp, M_INV_VIDEO) ? INVERSE : NORMAL; + if (inverse == INVERSE) + F_SET(sp, S_IVIDEO); + (void)svi_ex_write(sp, mp->mbuf, mp->len); + F_CLR(sp, S_IVIDEO); + + F_SET(mp, M_EMPTY); + } + + /* + * None of the messages end with periods, we do it in the message + * flush routine, which makes it possible to join messages. + */ + if (inverse == INVERSE) + F_SET(sp, S_IVIDEO); + (void)svi_ex_write(sp, ".", 1); + F_CLR(sp, S_IVIDEO); + + /* + * Figure out if we have to wait. Don't wait for only one line, + * but don't overwrite it with mode information either. + */ + if (svp->extotalcount == 1) { + F_SET(sp, S_UPDATE_MODE); + if (sp->q.cqe_next != (void *)&sp->gp->dq) + svi_ex_inv(sp); + return (0); + } + + rval = svi_ex_scroll(sp, 1, NULL); + if (svi_ex_done(sp, sp->ep, NULL)) + rval = 1; + MOVE(sp, INFOLINE(sp), 0); + clrtoeol(); + return (rval); +} + +/* + * svi_ex_done -- + * Cleanup from dipping into ex. + */ +static int +svi_ex_done(sp, ep, rp) + SCR *sp; + EXF *ep; + MARK *rp; +{ + SMAP *smp; + SVI_PRIVATE *svp; + recno_t lno; + size_t cnt, len; + + /* + * The file or screen may have changed, in which case, + * the main editor loop takes care of it. + */ + if (F_ISSET(sp, S_MAJOR_CHANGE)) + return (0); + + /* + * Otherwise, the only cursor modifications will be real, however, the + * underlying line may have changed; don't trust anything. This code + * has been a remarkably fertile place for bugs. + * + * Repaint the entire screen if at least half the screen is trashed. + * Else, repaint only over the overwritten lines. The "-2" comes + * from one for the mode line and one for the fact that it's an offset. + * Note the check for small screens. + * + * Don't trust ANYTHING. + */ + svp = SVP(sp); + if (svp->extotalcount >= HALFTEXT(sp)) + F_SET(sp, S_REDRAW); + else + for (cnt = sp->rows - 2; svp->extotalcount--; --cnt) + if (cnt > sp->t_rows) { + MOVE(sp, cnt, 0); + clrtoeol(); + } else { + smp = HMAP + cnt; + SMAP_FLUSH(smp); + if (svi_line(sp, ep, smp, NULL, NULL)) + return (1); + } + + /* Ignore the cursor if the caller doesn't care. */ + if (rp == NULL) + return (0); + + /* + * Do a reality check on a cursor value, and make sure it's okay. + * If necessary, change it. Ex keeps track of the line number, + * but it doesn't care about the column and it may have disappeared. + */ + if (file_gline(sp, ep, sp->lno, &len) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) + GETLINE_ERR(sp, sp->lno); + sp->lno = 1; + sp->cno = 0; + } else if (sp->cno >= len) + sp->cno = len ? len - 1 : 0; + + rp->lno = sp->lno; + rp->cno = sp->cno; + return (0); +} + +/* + * svi_ex_write -- + * Write out the ex messages. + */ +int +svi_ex_write(cookie, line, llen) + void *cookie; + const char *line; + int llen; +{ + SCR *sp; + SVI_PRIVATE *svp; + size_t oldy, oldx; + int len, rlen, tlen; + const char *p, *t; + + /* + * XXX + * If it's a 4.4BSD system, we could just use fpurge(3). + * This shouldn't be too expensive, though. + */ + sp = cookie; + svp = SVP(sp); + if (INTERRUPTED(sp)) + return (llen); + + p = line; /* In case of a write of 0. */ + for (rlen = llen; llen;) { + /* Get the next line. */ + if ((p = memchr(line, '\n', llen)) == NULL) + len = llen; + else + len = p - line; + + /* + * The max is sp->cols characters, and we may + * have already written part of the line. + */ + if (len + svp->exlcontinue > sp->cols) + len = sp->cols - svp->exlcontinue; + + /* + * If the first line output, do nothing. + * If the second line output, draw the divider line. + * If drew a full screen, remove the divider line. + * If it's a continuation line, move to the continuation + * point, else, move the screen up. + */ + if (svp->exlcontinue == 0) { + if (svp->extotalcount == 1) { + MOVE(sp, INFOLINE(sp) - 1, 0); + clrtoeol(); + if (svi_ex_divider(sp)) + return (-1); + F_SET(svp, SVI_DIVIDER); + ++svp->extotalcount; + ++svp->exlinecount; + } + if (svp->extotalcount == sp->t_maxrows && + F_ISSET(svp, SVI_DIVIDER)) { + --svp->extotalcount; + --svp->exlinecount; + F_CLR(svp, SVI_DIVIDER); + } + if (svp->extotalcount != 0 && + svi_ex_scroll(sp, 0, NULL)) + return (-1); + MOVE(sp, INFOLINE(sp), 0); + ++svp->extotalcount; + ++svp->exlinecount; + if (F_ISSET(sp, S_INTERRUPTIBLE) && INTERRUPTED(sp)) + break; + } else + MOVE(sp, INFOLINE(sp), svp->exlcontinue); + + /* Display the line, doing character translation. */ + if (F_ISSET(sp, S_IVIDEO)) + standout(); + for (t = line, tlen = len; tlen--; ++t) + ADDCH(*t); + if (F_ISSET(sp, S_IVIDEO)) + standend(); + + /* Clear to EOL. */ + getyx(stdscr, oldy, oldx); + if (oldx < sp->cols) + clrtoeol(); + + /* If we loop, it's a new line. */ + svp->exlcontinue = 0; + + /* Reset for the next line. */ + line += len; + llen -= len; + if (p != NULL) { + ++line; + --llen; + } + } + /* Refresh the screen, even if it's a partial. */ + refresh(); + + /* Set up next continuation line. */ + if (p == NULL) + getyx(stdscr, oldy, svp->exlcontinue); + return (rlen); +} + +/* + * svi_ex_scroll -- + * Scroll the screen for ex output. + */ +static int +svi_ex_scroll(sp, mustwait, chp) + SCR *sp; + int mustwait; + CH *chp; +{ + CH ikey; + SVI_PRIVATE *svp; + + /* + * Scroll the screen. Instead of scrolling the entire screen, delete + * the line above the first line output so preserve the maximum amount + * of the screen. + */ + svp = SVP(sp); + if (svp->extotalcount >= sp->rows) { + MOVE(sp, 0, 0); + } else + MOVE(sp, INFOLINE(sp) - svp->extotalcount, 0); + + deleteln(); + + /* If there are screens below us, push them back into place. */ + if (sp->q.cqe_next != (void *)&sp->gp->dq) { + MOVE(sp, INFOLINE(sp), 0); + insertln(); + } + + /* If just displayed a full screen, wait. */ + if (mustwait || svp->exlinecount == sp->t_maxrows) { + MOVE(sp, INFOLINE(sp), 0); + if (F_ISSET(sp, S_INTERRUPTIBLE)) { + ADDNSTR(STR_QMSG, (int)sizeof(STR_QMSG) - 1); + } else { + ADDNSTR(STR_CMSG, (int)sizeof(STR_CMSG) - 1); + } + clrtoeol(); + refresh(); + /* + * !!! + * Historic practice is that any key can be used to continue. + * Nvi used to require that the user enter a <carriage-return> + * or <newline>, but this broke historic users. + */ + if (term_key(sp, &ikey, 0) != INP_OK) + return (-1); + if (ikey.ch == CH_QUIT && F_ISSET(sp, S_INTERRUPTIBLE)) + F_SET(sp, S_INTERRUPTED); + if (chp != NULL) + *chp = ikey; + svp->exlinecount = 0; + } + return (0); +} + +/* + * svi_ex_inv -- + * Change whatever is on the info line to inverse video so we have + * a divider line between split screens. + */ +static int +svi_ex_inv(sp) + SCR *sp; +{ + CHAR_T ch; + size_t spcnt, col, row; + + row = INFOLINE(sp); + + /* + * Walk through the line, retrieving each character and writing + * it back out in inverse video. Since curses doesn't have an + * EOL marker, only put out trailing spaces if we find another + * character. + * + * XXX + * This is a major kluge -- curses should have an interface + * that allows us to change attributes on a per line basis. + */ + MOVE(sp, row, 0); + standout(); + for (spcnt = col = 0;;) { + ch = winch(stdscr); + if (isspace(ch)) { + ++spcnt; + if (++col >= sp->cols) + break; + MOVE(sp, row, col); + } else { + if (spcnt) { + MOVE(sp, row, col - spcnt); + for (; spcnt > 0; --spcnt) + ADDCH(' '); + } + ADDCH(ch); + if (++col >= sp->cols) + break; + } + } + standend(); + return (0); +} + +/* + * svi_ex_divider -- + * Draw a dividing line between the screens. + */ +static int +svi_ex_divider(sp) + SCR *sp; +{ + size_t len; + +#define DIVIDESTR "+=+=+=+=+=+=+=+" + len = sizeof(DIVIDESTR) - 1 > sp->cols ? + sp->cols : sizeof(DIVIDESTR) - 1; + standout(); + ADDNSTR(DIVIDESTR, len); + standend(); + return (0); +} diff --git a/usr.bin/vi/svi/svi_get.c b/usr.bin/vi/svi/svi_get.c new file mode 100644 index 0000000..db790a9 --- /dev/null +++ b/usr.bin/vi/svi/svi_get.c @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_get.c 8.25 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "../vi/vcmd.h" +#include "svi_screen.h" + +/* + * svi_get -- + * Fill a buffer from the terminal for vi. + */ +enum input +svi_get(sp, ep, tiqh, prompt, flags) + SCR *sp; + EXF *ep; + TEXTH *tiqh; + ARG_CHAR_T prompt; + u_int flags; +{ + MARK save; + SMAP *esmp; + recno_t bot_lno; + size_t bot_off, cnt; + int eval; + + /* + * The approach used is to fake like the user is doing input on + * the last line of the screen. This makes all of the scrolling + * work correctly, and allows us the use of the vi text editing + * routines, not to mention practically infinite length ex commands. + * + * Save the current location. + */ + bot_lno = TMAP->lno; + bot_off = TMAP->off; + save.lno = sp->lno; + save.cno = sp->cno; + + /* + * If it's a small screen, TMAP may be small for the screen. + * Fix it, filling in fake lines as we go. + */ + if (ISSMALLSCREEN(sp)) + for (esmp = HMAP + (sp->t_maxrows - 1); TMAP < esmp; ++TMAP) { + TMAP[1].lno = TMAP[0].lno + 1; + TMAP[1].off = 1; + } + + /* Build the fake entry. */ + TMAP[1].lno = TMAP[0].lno + 1; + TMAP[1].off = 1; + SMAP_FLUSH(&TMAP[1]); + ++TMAP; + + /* Move to it. */ + sp->lno = TMAP[0].lno; + sp->cno = 0; + + if (O_ISSET(sp, O_ALTWERASE)) + LF_SET(TXT_ALTWERASE); + if (O_ISSET(sp, O_TTYWERASE)) + LF_SET(TXT_TTYWERASE); + LF_SET(TXT_APPENDEOL | + TXT_CR | TXT_ESCAPE | TXT_INFOLINE | TXT_MAPINPUT); + + /* Don't update the modeline for now. */ + F_SET(SVP(sp), SVI_INFOLINE); + + eval = v_ntext(sp, ep, tiqh, NULL, NULL, 0, NULL, prompt, 0, flags); + + F_CLR(SVP(sp), SVI_INFOLINE); + + /* Put it all back. */ + --TMAP; + sp->lno = save.lno; + sp->cno = save.cno; + + /* + * If it's a small screen, TMAP may be wrong. Clear any + * lines that might have been overwritten. + */ + if (ISSMALLSCREEN(sp)) { + for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) { + MOVE(sp, cnt, 0); + clrtoeol(); + } + TMAP = HMAP + (sp->t_rows - 1); + } + + /* + * The map may be wrong if the user entered more than one + * (logical) line. Fix it. If the user entered a whole + * screen, this will be slow, but it's not worth caring. + */ + while (bot_lno != TMAP->lno || bot_off != TMAP->off) + if (svi_sm_1down(sp, ep)) + return (INP_ERR); + + /* + * Invalidate the cursor and the line size cache, the line never + * really existed. This fixes bugs where the user searches for + * the last line on the screen + 1 and the refresh routine thinks + * that's where we just were. + */ + F_SET(SVP(sp), SVI_CUR_INVALID); + SVI_SCR_CFLUSH(SVP(sp)); + + return (eval ? INP_ERR : INP_OK); +} diff --git a/usr.bin/vi/svi/svi_line.c b/usr.bin/vi/svi/svi_line.c new file mode 100644 index 0000000..8b437e5 --- /dev/null +++ b/usr.bin/vi/svi/svi_line.c @@ -0,0 +1,441 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_line.c 8.25 (Berkeley) 5/16/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "svi_screen.h" + +#if defined(DEBUG) && 0 +#define TABCH '-' +#define TABSTR "--------------------" +#else +#define TABSTR " " +#define TABCH ' ' +#endif + +/* + * svi_line -- + * Update one line on the screen. + */ +int +svi_line(sp, ep, smp, yp, xp) + SCR *sp; + EXF *ep; + SMAP *smp; + size_t *xp, *yp; +{ + SMAP *tsmp; + size_t chlen, cols_per_screen, cno_cnt, len, scno, skip_screens; + size_t offset_in_char, offset_in_line; + size_t oldy, oldx; + int ch, is_cached, is_infoline, is_partial, is_tab; + int list_tab, list_dollar; + char *p, nbuf[10]; + +#if defined(DEBUG) && 0 + TRACE(sp, "svi_line: row %u: line: %u off: %u\n", + smp - HMAP, smp->lno, smp->off); +#endif + + /* + * Assume that, if the cache entry for the line is filled in, the + * line is already on the screen, and all we need to do is return + * the cursor position. If the calling routine doesn't need the + * cursor position, we can just return. + */ + is_cached = SMAP_CACHE(smp); + if (yp == NULL && is_cached) + return (0); + + /* + * A nasty side effect of this routine is that it returns the screen + * position for the "current" character. Not pretty, but this is the + * only routine that really knows what's out there. + * + * Move to the line. This routine can be called by svi_sm_position(), + * which uses it to fill in the cache entry so it can figure out what + * the real contents of the screen are. Because of this, we have to + * return to whereever we started from. + */ + getyx(stdscr, oldy, oldx); + MOVE(sp, smp - HMAP, 0); + + /* Get a copy of the line. */ + p = file_gline(sp, ep, smp->lno, &len); + + /* + * Special case if we're printing the info/mode line. Skip printing + * the leading number, as well as other minor setup. If painting the + * line between two screens, it's always in reverse video. The only + * time this code paints the mode line is when the user is entering + * text for a ":" command, so we can put the code here instead of + * dealing with the empty line logic below. This is a kludge, but it's + * pretty much confined to this module. + * + * Set the number of screens to skip until a character is displayed. + * Left-right screens are special, because we don't bother building + * a buffer to be skipped over. + * + * Set the number of columns for this screen. + */ + cols_per_screen = sp->cols; + list_tab = O_ISSET(sp, O_LIST); + if (is_infoline = ISINFOLINE(sp, smp)) { + list_dollar = 0; + if (O_ISSET(sp, O_LEFTRIGHT)) + skip_screens = 0; + else + skip_screens = smp->off - 1; + } else { + list_dollar = list_tab; + skip_screens = smp->off - 1; + + /* + * If O_NUMBER is set and it's line number 1 or the line exists + * and this is the first screen of a folding line or any left- + * right line, display the line number. + */ + if (O_ISSET(sp, O_NUMBER)) { + cols_per_screen -= O_NUMBER_LENGTH; + if ((smp->lno == 1 || p != NULL) && skip_screens == 0) { + (void)snprintf(nbuf, + sizeof(nbuf), O_NUMBER_FMT, smp->lno); + ADDSTR(nbuf); + } + } + } + + /* + * Special case non-existent lines and the first line of an empty + * file. In both cases, the cursor position is 0, but corrected + * for the O_NUMBER field if it was displayed. + */ + if (p == NULL || len == 0) { + /* Fill in the cursor. */ + if (yp != NULL && smp->lno == sp->lno) { + *yp = smp - HMAP; + *xp = sp->cols - cols_per_screen; + } + + /* If the line is on the screen, quit. */ + if (is_cached) + goto ret; + + /* Set line cacheing information. */ + smp->c_sboff = smp->c_eboff = 0; + smp->c_scoff = smp->c_eclen = 0; + + /* Lots of special cases for empty lines. */ + if (skip_screens == 0) + if (p == NULL) { + if (smp->lno == 1) { + if (list_dollar) { + ch = '$'; + goto empty; + } + } else { + ch = '~'; + goto empty; + } + } else + if (list_dollar) { + ch = '$'; +empty: ADDCH(ch); + } + + clrtoeol(); + MOVEA(sp, oldy, oldx); + return (0); + } + + /* + * If we wrote a line that's this or a previous one, we can do this + * much more quickly -- we cached the starting and ending positions + * of that line. The way it works is we keep information about the + * lines displayed in the SMAP. If we're painting the screen in + * the forward, this saves us from reformatting the physical line for + * every line on the screen. This wins big on binary files with 10K + * lines. + * + * Test for the first screen of the line, then the current screen line, + * then the line behind us, then do the hard work. Note, it doesn't + * do us any good to have a line in front of us -- it would be really + * hard to try and figure out tabs in the reverse direction, i.e. how + * many spaces a tab takes up in the reverse direction depends on + * what characters preceded it. + */ + if (smp->off == 1) { + smp->c_sboff = offset_in_line = 0; + smp->c_scoff = offset_in_char = 0; + p = &p[offset_in_line]; + } else if (is_cached) { + offset_in_line = smp->c_sboff; + offset_in_char = smp->c_scoff; + p = &p[offset_in_line]; + if (skip_screens != 0) + cols_per_screen = sp->cols; + } else if (smp != HMAP && + SMAP_CACHE(tsmp = smp - 1) && tsmp->lno == smp->lno) { + if (tsmp->c_eclen != tsmp->c_ecsize) { + offset_in_line = tsmp->c_eboff; + offset_in_char = tsmp->c_eclen; + } else { + offset_in_line = tsmp->c_eboff + 1; + offset_in_char = 0; + } + + /* Put starting info for this line in the cache. */ + smp->c_sboff = offset_in_line; + smp->c_scoff = offset_in_char; + p = &p[offset_in_line]; + if (skip_screens != 0) + cols_per_screen = sp->cols; + } else { + offset_in_line = 0; + offset_in_char = 0; + + /* This is the loop that skips through screens. */ + if (skip_screens == 0) { + smp->c_sboff = offset_in_line; + smp->c_scoff = offset_in_char; + } else for (scno = 0; offset_in_line < len; ++offset_in_line) { + scno += chlen = + (ch = *(u_char *)p++) == '\t' && !list_tab ? + TAB_OFF(sp, scno) : KEY_LEN(sp, ch); + if (scno < cols_per_screen) + continue; + /* + * Reset cols_per_screen to second and subsequent line + * length. + */ + scno -= cols_per_screen; + cols_per_screen = sp->cols; + + /* + * If crossed the last skipped screen boundary, start + * displaying the characters. + */ + if (--skip_screens) + continue; + + /* Put starting info for this line in the cache. */ + if (scno) { + smp->c_sboff = offset_in_line; + smp->c_scoff = offset_in_char = chlen - scno; + --p; + } else { + smp->c_sboff = ++offset_in_line; + smp->c_scoff = 0; + } + break; + } + } + + /* + * Set the number of characters to skip before reaching the cursor + * character. Offset by 1 and use 0 as a flag value. Svi_line is + * called repeatedly with a valid pointer to a cursor position. + * Don't fill anything in unless it's the right line and the right + * character, and the right part of the character... + */ + if (yp == NULL || + smp->lno != sp->lno || sp->cno < offset_in_line || + offset_in_line + cols_per_screen < sp->cno) { + cno_cnt = 0; + /* If the line is on the screen, quit. */ + if (is_cached) + goto ret; + } else + cno_cnt = (sp->cno - offset_in_line) + 1; + + /* This is the loop that actually displays characters. */ + for (is_partial = 0, scno = 0; + offset_in_line < len; ++offset_in_line, offset_in_char = 0) { + if ((ch = *(u_char *)p++) == '\t' && !list_tab) { + scno += chlen = TAB_OFF(sp, scno) - offset_in_char; + is_tab = 1; + } else { + scno += chlen = KEY_LEN(sp, ch) - offset_in_char; + is_tab = 0; + } + + /* + * Only display up to the right-hand column. Set a flag if + * the entire character wasn't displayed for use in setting + * the cursor. If reached the end of the line, set the cache + * info for the screen. Don't worry about there not being + * characters to display on the next screen, its lno/off won't + * match up in that case. + */ + if (scno >= cols_per_screen) { + smp->c_ecsize = chlen; + chlen -= scno - cols_per_screen; + smp->c_eclen = chlen; + smp->c_eboff = offset_in_line; + if (scno > cols_per_screen) + is_partial = 1; + + /* Terminate the loop. */ + offset_in_line = len; + } + + /* + * If the caller wants the cursor value, and this was the + * cursor character, set the value. There are two ways to + * put the cursor on a character -- if it's normal display + * mode, it goes on the last column of the character. If + * it's input mode, it goes on the first. In normal mode, + * set the cursor only if the entire character was displayed. + */ + if (cno_cnt && + --cno_cnt == 0 && (F_ISSET(sp, S_INPUT) || !is_partial)) { + *yp = smp - HMAP; + if (F_ISSET(sp, S_INPUT)) + *xp = scno - chlen; + else + *xp = scno - 1; + if (O_ISSET(sp, O_NUMBER) && + !is_infoline && smp->off == 1) + *xp += O_NUMBER_LENGTH; + + /* If the line is on the screen, quit. */ + if (is_cached) + goto ret; + } + + /* If the line is on the screen, don't display anything. */ + if (is_cached) + continue; + + /* + * Display the character. If it's a tab and tabs aren't some + * ridiculous length, do it fast. (We do tab expansion here + * because curses doesn't have a way to set the tab length.) + */ + if (is_tab) { + if (chlen <= sizeof(TABSTR) - 1) { + ADDNSTR(TABSTR, chlen); + } else + while (chlen--) + ADDCH(TABCH); + } else + ADDNSTR(KEY_NAME(sp, ch) + offset_in_char, chlen); + } + + if (scno < cols_per_screen) { + /* If didn't paint the whole line, update the cache. */ + smp->c_ecsize = smp->c_eclen = KEY_LEN(sp, ch); + smp->c_eboff = len - 1; + + /* + * If not the info/mode line, and O_LIST set, and at the + * end of the line, and the line ended on this screen, + * add a trailing $. + */ + if (list_dollar) { + ++scno; + ADDCH('$'); + } + + /* If still didn't paint the whole line, clear the rest. */ + if (scno < cols_per_screen) + clrtoeol(); + } + +ret: MOVEA(sp, oldy, oldx); + return (0); +} + +/* + * svi_number -- + * Repaint the numbers on all the lines. + */ +int +svi_number(sp, ep) + SCR *sp; + EXF *ep; +{ + SMAP *smp; + size_t oldy, oldx; + char *lp, nbuf[10]; + + /* + * Try and avoid getting the last line in the file, by getting the + * line after the last line in the screen -- if it exists, we know + * we have to to number all the lines in the screen. Get the one + * after the last instead of the last, so that the info line doesn't + * fool us. + * + * If that test fails, we have to check each line for existence. + * + * XXX + * The problem is that file_lline will lie, and tell us that the + * info line is the last line in the file. + */ + lp = file_gline(sp, ep, TMAP->lno + 1, NULL); + + getyx(stdscr, oldy, oldx); + for (smp = HMAP; smp <= TMAP; ++smp) { + if (smp->off != 1) + continue; + if (ISINFOLINE(sp, smp)) + break; + if (smp->lno != 1 && lp == NULL && + file_gline(sp, ep, smp->lno, NULL) == NULL) + break; + MOVE(sp, smp - HMAP, 0); + (void)snprintf(nbuf, sizeof(nbuf), O_NUMBER_FMT, smp->lno); + ADDSTR(nbuf); + } + MOVEA(sp, oldy, oldx); + return (0); +} diff --git a/usr.bin/vi/svi/svi_refresh.c b/usr.bin/vi/svi/svi_refresh.c new file mode 100644 index 0000000..bc8bd92 --- /dev/null +++ b/usr.bin/vi/svi/svi_refresh.c @@ -0,0 +1,818 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_refresh.c 8.60 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "svi_screen.h" +#include "../sex/sex_screen.h" + +static int svi_modeline __P((SCR *, EXF *)); + +int +svi_refresh(sp, ep) + SCR *sp; + EXF *ep; +{ + SCR *tsp; + u_int paintbits; + + /* + * 1: Resize the screen. + * + * Notice that a resize is requested, and set up everything so that + * the file gets reinitialized. Done here, instead of in the vi loop + * because there may be other initialization that other screens need + * to do. The actual changing of the row/column values was done by + * calling the ex options code which put them into the environment, + * which is used by curses. Stupid, but ugly. + */ + if (F_ISSET(sp, S_RESIZE)) { + /* Reinitialize curses. */ + if (svi_curses_end(sp) || svi_curses_init(sp)) + return (1); + + /* Invalidate the line size cache. */ + SVI_SCR_CFLUSH(SVP(sp)); + + /* + * Fill the map, incidentally losing any svi_line() + * cached information. + */ + if (svi_sm_fill(sp, ep, sp->lno, P_FILL)) + return (1); + F_CLR(sp, S_RESIZE | S_REFORMAT); + F_SET(sp, S_REDRAW); + } + + /* + * 2: S_REFRESH + * + * If S_REFRESH is set in the current screen, repaint everything + * that we can find. + */ + if (F_ISSET(sp, S_REFRESH)) + for (tsp = sp->gp->dq.cqh_first; + tsp != (void *)&sp->gp->dq; tsp = tsp->q.cqe_next) + if (tsp != sp) + F_SET(tsp, S_REDRAW); + /* + * 3: Related or dirtied screens, or screens with messages. + * + * If related screens share a view into a file, they may have been + * modified as well. Refresh any screens with paint or dirty bits + * set, or where messages are waiting. Finally, if we refresh any + * screens other than the current one, the cursor will be trashed. + */ + paintbits = S_REDRAW | S_REFORMAT | S_REFRESH; + if (O_ISSET(sp, O_NUMBER)) + paintbits |= S_RENUMBER; + for (tsp = sp->gp->dq.cqh_first; + tsp != (void *)&sp->gp->dq; tsp = tsp->q.cqe_next) + if (tsp != sp && + (F_ISSET(tsp, paintbits) || + F_ISSET(SVP(tsp), SVI_SCREENDIRTY) || + tsp->msgq.lh_first != NULL && + !F_ISSET(tsp->msgq.lh_first, M_EMPTY))) { + (void)svi_paint(tsp, tsp->ep); + F_CLR(SVP(tsp), SVI_SCREENDIRTY); + F_SET(SVP(sp), SVI_CUR_INVALID); + } + + /* + * 4: Refresh the current screen. + * + * Always refresh the current screen, it may be a cursor movement. + * Also, always do it last -- that way, S_REFRESH can be set in + * the current screen only, and the screen won't flash. + */ + F_CLR(sp, SVI_SCREENDIRTY); + return (svi_paint(sp, ep)); +} + +/* + * svi_paint -- + * This is the guts of the vi curses screen code. The idea is that + * the SCR structure passed in contains the new coordinates of the + * screen. What makes this hard is that we don't know how big + * characters are, doing input can put the cursor in illegal places, + * and we're frantically trying to avoid repainting unless it's + * absolutely necessary. If you change this code, you'd better know + * what you're doing. It's subtle and quick to anger. + */ +int +svi_paint(sp, ep) + SCR *sp; + EXF *ep; +{ + SMAP *smp, tmp; + SVI_PRIVATE *svp; + recno_t lastline, lcnt; + size_t cwtotal, cnt, len, x, y; + int ch, didpaint, leftright_warp; + char *p; + +#define LNO sp->lno +#define OLNO svp->olno +#define CNO sp->cno +#define OCNO svp->ocno +#define SCNO svp->sc_col + + didpaint = leftright_warp = 0; + svp = SVP(sp); + + /* + * 1: Reformat the lines. + * + * If the lines themselves have changed (:set list, for example), + * fill in the map from scratch. Adjust the screen that's being + * displayed if the leftright flag is set. + */ + if (F_ISSET(sp, S_REFORMAT)) { + /* Invalidate the line size cache. */ + SVI_SCR_CFLUSH(SVP(sp)); + + /* Toss svi_line() cached information. */ + if (svi_sm_fill(sp, ep, HMAP->lno, P_TOP)) + return (1); + if (O_ISSET(sp, O_LEFTRIGHT) && + (cnt = svi_opt_screens(sp, ep, LNO, &CNO)) != 1) + for (smp = HMAP; smp <= TMAP; ++smp) + smp->off = cnt; + F_CLR(sp, S_REFORMAT); + F_SET(sp, S_REDRAW); + } + + /* + * 2: Line movement. + * + * Line changes can cause the top line to change as well. As + * before, if the movement is large, the screen is repainted. + * + * 2a: Tiny screens. + * + * Tiny screens cannot be permitted into the "scrolling" parts of + * the smap code for two reasons. If the screen size is 1 line, + * HMAP == TMAP and the code will quickly drop core. If the screen + * size is 2, none of the divisions by 2 will work, and scrolling + * won't work. In fact, because no line change will be less than + * HALFTEXT(sp), we always ending up "filling" the map, with a + * P_MIDDLE flag, which isn't what the user wanted. Tiny screens + * can go into the "fill" portions of the smap code, however. + */ + if (sp->t_rows <= 2) { + if (LNO < HMAP->lno) { + if (svi_sm_fill(sp, ep, LNO, P_TOP)) + return (1); + } else if (LNO > TMAP->lno) + if (svi_sm_fill(sp, ep, LNO, P_BOTTOM)) + return (1); + if (sp->t_rows == 1) { + HMAP->off = svi_opt_screens(sp, ep, LNO, &CNO); + goto paint; + } + F_SET(sp, S_REDRAW); + goto adjust; + } + + /* + * 2b: Small screens. + * + * Users can use the window, w300, w1200 and w9600 options to make + * the screen artificially small. The behavior of these options + * in the historic vi wasn't all that consistent, and, in fact, it + * was never documented how various screen movements affected the + * screen size. Generally, one of three things would happen: + * 1: The screen would expand in size, showing the line + * 2: The screen would scroll, showing the line + * 3: The screen would compress to its smallest size and + * repaint. + * In general, scrolling didn't cause compression (200^D was handled + * the same as ^D), movement to a specific line would (:N where N + * was 1 line below the screen caused a screen compress), and cursor + * movement would scroll if it was 11 lines or less, and compress if + * it was more than 11 lines. (And, no, I have no idea where the 11 + * comes from.) + * + * What we do is try and figure out if the line is less than half of + * a full screen away. If it is, we expand the screen if there's + * room, and then scroll as necessary. The alternative is to compress + * and repaint. + * + * !!! + * This code is a special case from beginning to end. Unfortunately, + * home modems are still slow enough that it's worth having. + * + * XXX + * If the line a really long one, i.e. part of the line is on the + * screen but the column offset is not, we'll end up in the adjust + * code, when we should probably have compressed the screen. + */ + if (ISSMALLSCREEN(sp)) + if (LNO < HMAP->lno) { + lcnt = svi_sm_nlines(sp, ep, HMAP, LNO, sp->t_maxrows); + if (lcnt <= HALFSCREEN(sp)) + for (; lcnt && sp->t_rows != sp->t_maxrows; + --lcnt, ++sp->t_rows) { + ++TMAP; + if (svi_sm_1down(sp, ep)) + return (1); + } + else + goto small_fill; + } else if (LNO > TMAP->lno) { + lcnt = svi_sm_nlines(sp, ep, TMAP, LNO, sp->t_maxrows); + if (lcnt <= HALFSCREEN(sp)) + for (; lcnt && sp->t_rows != sp->t_maxrows; + --lcnt, ++sp->t_rows) { + if (svi_sm_next(sp, ep, TMAP, TMAP + 1)) + return (1); + ++TMAP; + if (svi_line(sp, ep, TMAP, NULL, NULL)) + return (1); + } + else { +small_fill: MOVE(sp, INFOLINE(sp), 0); + clrtoeol(); + for (; sp->t_rows > sp->t_minrows; + --sp->t_rows, --TMAP) { + MOVE(sp, TMAP - HMAP, 0); + clrtoeol(); + } + if (svi_sm_fill(sp, ep, LNO, P_FILL)) + return (1); + F_SET(sp, S_REDRAW); + goto adjust; + } + } + + /* + * 3a: Line down, or current screen. + */ + if (LNO >= HMAP->lno) { + /* Current screen. */ + if (LNO <= TMAP->lno) + goto adjust; + + /* + * If less than half a screen above the line, scroll down + * until the line is on the screen. + */ + lcnt = svi_sm_nlines(sp, ep, TMAP, LNO, HALFTEXT(sp)); + if (lcnt < HALFTEXT(sp)) { + while (lcnt--) + if (svi_sm_1up(sp, ep)) + return (1); + goto adjust; + } + goto bottom; + } + + /* + * 3b: Line up. + */ + lcnt = svi_sm_nlines(sp, ep, HMAP, LNO, HALFTEXT(sp)); + if (lcnt < HALFTEXT(sp)) { + /* + * If less than half a screen below the line, scroll up until + * the line is the first line on the screen. Special check so + * that if the screen has been emptied, we refill it. + */ + if (file_gline(sp, ep, HMAP->lno, &len) != NULL) { + while (lcnt--) + if (svi_sm_1down(sp, ep)) + return (1); + goto adjust; + } + + /* + * If less than a full screen from the bottom of the file, + * put the last line of the file on the bottom of the screen. + */ +bottom: if (file_lline(sp, ep, &lastline)) + return (1); + tmp.lno = LNO; + tmp.off = 1; + lcnt = svi_sm_nlines(sp, ep, &tmp, lastline, sp->t_rows); + if (lcnt < sp->t_rows) { + if (svi_sm_fill(sp, ep, lastline, P_BOTTOM)) + return (1); + F_SET(sp, S_REDRAW); + goto adjust; + } + /* It's not close, just put the line in the middle. */ + goto middle; + } + + /* + * If less than half a screen from the top of the file, put the first + * line of the file at the top of the screen. Otherwise, put the line + * in the middle of the screen. + */ + tmp.lno = 1; + tmp.off = 1; + lcnt = svi_sm_nlines(sp, ep, &tmp, LNO, HALFTEXT(sp)); + if (lcnt < HALFTEXT(sp)) { + if (svi_sm_fill(sp, ep, 1, P_TOP)) + return (1); + } else +middle: if (svi_sm_fill(sp, ep, LNO, P_MIDDLE)) + return (1); + F_SET(sp, S_REDRAW); + + /* + * At this point we know part of the line is on the screen. Since + * scrolling is done using logical lines, not physical, all of the + * line may not be on the screen. While that's not necessarily bad, + * if the part the cursor is on isn't there, we're going to lose. + * This can be tricky; if the line covers the entire screen, lno + * may be the same as both ends of the map, that's why we test BOTH + * the top and the bottom of the map. This isn't a problem for + * left-right scrolling, the cursor movement code handles the problem. + * + * There's a performance issue here if editing *really* long lines. + * This gets to the right spot by scrolling, and, in a binary, by + * scrolling hundreds of lines. If the adjustment looks like it's + * going to be a serious problem, refill the screen and repaint. + */ +adjust: if (!O_ISSET(sp, O_LEFTRIGHT) && + (LNO == HMAP->lno || LNO == TMAP->lno)) { + cnt = svi_opt_screens(sp, ep, LNO, &CNO); + if (LNO == HMAP->lno && cnt < HMAP->off) + if ((HMAP->off - cnt) > HALFTEXT(sp)) { + HMAP->off = cnt; + svi_sm_fill(sp, ep, OOBLNO, P_TOP); + F_SET(sp, S_REDRAW); + } else + while (cnt < HMAP->off) + if (svi_sm_1down(sp, ep)) + return (1); + if (LNO == TMAP->lno && cnt > TMAP->off) + if ((cnt - TMAP->off) > HALFTEXT(sp)) { + TMAP->off = cnt; + svi_sm_fill(sp, ep, OOBLNO, P_BOTTOM); + F_SET(sp, S_REDRAW); + } else + while (cnt > TMAP->off) + if (svi_sm_1up(sp, ep)) + return (1); + } + + /* + * If the screen needs to be repainted, skip cursor optimization. + * However, in the code above we skipped leftright scrolling on + * the grounds that the cursor code would handle it. Make sure + * the right screen is up. + */ + if (F_ISSET(sp, S_REDRAW)) { + if (O_ISSET(sp, O_LEFTRIGHT)) { + cnt = svi_opt_screens(sp, ep, LNO, &CNO); + if (HMAP->off != cnt) + for (smp = HMAP; smp <= TMAP; ++smp) + smp->off = cnt; + } + goto paint; + } + + /* + * 4: Cursor movements. + * + * Decide cursor position. If the line has changed, the cursor has + * moved over a tab, or don't know where the cursor was, reparse the + * line. Otherwise, we've just moved over fixed-width characters, + * and can calculate the left/right scrolling and cursor movement + * without reparsing the line. Note that we don't know which (if any) + * of the characters between the old and new cursor positions changed. + * + * XXX + * With some work, it should be possible to handle tabs quickly, at + * least in obvious situations, like moving right and encountering + * a tab, without reparsing the whole line. + */ + + /* If the line we're working with has changed, reparse. */ + if (F_ISSET(SVP(sp), SVI_CUR_INVALID) || LNO != OLNO) { + F_CLR(SVP(sp), SVI_CUR_INVALID); + goto slow; + } + + /* Otherwise, if nothing's changed, go fast. */ + if (CNO == OCNO) + goto fast; + + /* + * Get the current line. If this fails, we either have an empty + * file and can just repaint, or there's a real problem. This + * isn't a performance issue because there aren't any ways to get + * here repeatedly. + */ + if ((p = file_gline(sp, ep, LNO, &len)) == NULL) { + if (file_lline(sp, ep, &lastline)) + return (1); + if (lastline == 0) + goto slow; + GETLINE_ERR(sp, LNO); + return (1); + } + +#ifdef DEBUG + /* This is just a test. */ + if (CNO >= len && len != 0) { + msgq(sp, M_ERR, "Error: %s/%d: cno (%u) >= len (%u)", + tail(__FILE__), __LINE__, CNO, len); + return (1); + } +#endif + /* + * The basic scheme here is to look at the characters in between + * the old and new positions and decide how big they are on the + * screen, and therefore, how many screen positions to move. + */ + if (CNO < OCNO) { + /* + * 4a: Cursor moved left. + * + * Point to the old character. The old cursor position can + * be past EOL if, for example, we just deleted the rest of + * the line. In this case, since we don't know the width of + * the characters we traversed, we have to do it slowly. + */ + p += OCNO; + cnt = (OCNO - CNO) + 1; + if (OCNO >= len) + goto slow; + + /* + * Quick sanity check -- it's hard to figure out exactly when + * we cross a screen boundary as we do in the cursor right + * movement. If cnt is so large that we're going to cross the + * boundary no matter what, stop now. + */ + if (SCNO + 1 + MAX_CHARACTER_COLUMNS < cnt) + goto lscreen; + + /* + * Count up the widths of the characters. If it's a tab + * character, go do it the the slow way. + */ + for (cwtotal = 0; cnt--; cwtotal += KEY_LEN(sp, ch)) + if ((ch = *(u_char *)p--) == '\t') + goto slow; + + /* + * Decrement the screen cursor by the total width of the + * characters minus 1. + */ + cwtotal -= 1; + + /* + * If we're moving left, and there's a wide character in the + * current position, go to the end of the character. + */ + if (KEY_LEN(sp, ch) > 1) + cwtotal -= KEY_LEN(sp, ch) - 1; + + /* + * If the new column moved us off of the current logical line, + * calculate a new one. If doing leftright scrolling, we've + * moved off of the current screen, as well. Since most files + * don't have more than two screens, we optimize moving from + * screen 2 to screen 1. + */ + if (SCNO < cwtotal) { +lscreen: if (O_ISSET(sp, O_LEFTRIGHT)) { + cnt = HMAP->off == 2 ? 1 : + svi_opt_screens(sp, ep, LNO, &CNO); + for (smp = HMAP; smp <= TMAP; ++smp) + smp->off = cnt; + leftright_warp = 1; + goto paint; + } + goto slow; + } + SCNO -= cwtotal; + } else { + /* + * 4b: Cursor moved right. + * + * Point to the first character to the right. + */ + p += OCNO + 1; + cnt = CNO - OCNO; + + /* + * Count up the widths of the characters. If it's a tab + * character, go do it the the slow way. If we cross a + * screen boundary, we can quit. + */ + for (cwtotal = SCNO; cnt--;) { + if ((ch = *(u_char *)p++) == '\t') + goto slow; + if ((cwtotal += KEY_LEN(sp, ch)) >= SCREEN_COLS(sp)) + break; + } + + /* + * Increment the screen cursor by the total width of the + * characters. + */ + SCNO = cwtotal; + + /* See screen change comment in section 4a. */ + if (SCNO >= SCREEN_COLS(sp)) { + if (O_ISSET(sp, O_LEFTRIGHT)) { + cnt = svi_opt_screens(sp, ep, LNO, &CNO); + for (smp = HMAP; smp <= TMAP; ++smp) + smp->off = cnt; + leftright_warp = 1; + goto paint; + } + goto slow; + } + } + + /* + * 4c: Fast cursor update. + * + * Retrieve the current cursor position, and correct it + * for split screens. + */ +fast: getyx(stdscr, y, x); + y -= sp->woff; + goto number; + + /* + * 4d: Slow cursor update. + * + * Walk through the map and find the current line. If doing left-right + * scrolling and the cursor movement has changed the screen displayed, + * scroll the screen left or right, unless we're updating the info line + * in which case we just scroll that one line. Then update the screen + * lines for this file line until we have a new screen cursor position. + */ +slow: for (smp = HMAP; smp->lno != LNO; ++smp); + if (O_ISSET(sp, O_LEFTRIGHT)) { + cnt = svi_opt_screens(sp, ep, LNO, &CNO) % SCREEN_COLS(sp); + if (cnt != HMAP->off) { + if (ISINFOLINE(sp, smp)) + smp->off = cnt; + else { + for (smp = HMAP; smp <= TMAP; ++smp) + smp->off = cnt; + leftright_warp = 1; + } + goto paint; + } + } + for (y = -1; smp <= TMAP && smp->lno == LNO; ++smp) { + if (svi_line(sp, ep, smp, &y, &SCNO)) + return (1); + if (y != -1) + break; + } + goto number; + + /* + * 5: Repaint the entire screen. + * + * Lost big, do what you have to do. We flush the cache as S_REDRAW + * gets set when the screen isn't worth fixing, and it's simpler to + * repaint. So, don't trust anything that we think we know about it. + */ +paint: for (smp = HMAP; smp <= TMAP; ++smp) + SMAP_FLUSH(smp); + for (smp = HMAP; smp <= TMAP; ++smp) + if (svi_line(sp, ep, smp, &y, &SCNO)) + return (1); + /* + * If it's a small screen and we're redrawing, clear the unused lines, + * ex may have overwritten them. + */ + if (F_ISSET(sp, S_REDRAW)) { + if (ISSMALLSCREEN(sp)) + for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) { + MOVE(sp, cnt, 0); + clrtoeol(); + } + F_CLR(sp, S_REDRAW); + } + + didpaint = 1; + + /* + * 6: Repaint the line numbers. + * + * If O_NUMBER is set and the S_RENUMBER bit is set, and we didn't + * repaint the screen, repaint all of the line numbers, they've + * changed. + */ +number: if (O_ISSET(sp, O_NUMBER) && F_ISSET(sp, S_RENUMBER) && !didpaint) { + if (svi_number(sp, ep)) + return (1); + F_CLR(sp, S_RENUMBER); + } + + /* + * 7: Refresh the screen. + * + * If the screen was corrupted, refresh it. + */ + if (F_ISSET(sp, S_REFRESH)) { + wrefresh(curscr); + F_CLR(sp, S_REFRESH); + } + + if (F_ISSET(sp, S_BELLSCHED)) + svi_bell(sp); + /* + * If the bottom line isn't in use by the colon command, and + * we're not in the middle of a map: + * + * Display any messages. Don't test S_UPDATE_MODE. The + * message printing routine set it to avoid anyone else + * destroying the message we're about to display. + * + * If the bottom line isn't in use by anyone, put out the + * standard status line. + */ + if (!F_ISSET(SVP(sp), SVI_INFOLINE) && !KEYS_WAITING(sp)) + if (sp->msgq.lh_first != NULL && + !F_ISSET(sp->msgq.lh_first, M_EMPTY)) + svi_msgflush(sp); + else if (!F_ISSET(sp, S_UPDATE_MODE)) + svi_modeline(sp, ep); + + /* Update saved information. */ + OCNO = CNO; + OLNO = LNO; + + /* Place the cursor. */ + MOVE(sp, y, SCNO); + + /* Flush it all out. */ + refresh(); + + /* + * XXX + * Recalculate the "most favorite" cursor position. Vi doesn't know + * that we've warped the screen and it's going to have a completely + * wrong idea about where the cursor should be. This is vi's problem, + * and fixing it here is a gross violation of layering. + */ + if (leftright_warp) + (void)svi_column(sp, ep, &sp->rcm); + + return (0); +} + +/* + * svi_modeline -- + * Update the mode line. + */ +static int +svi_modeline(sp, ep) + SCR *sp; + EXF *ep; +{ + size_t cols, curlen, endpoint, len, midpoint; + char *p, buf[20]; + + /* Clear the mode line. */ + MOVE(sp, INFOLINE(sp), 0); + clrtoeol(); + + /* + * We put down the file name, the ruler, the mode and the dirty flag. + * If there's not enough room, there's not enough room, we don't play + * any special games. We try to put the ruler in the middle and the + * mode and dirty flag at the end. + * + * !!! + * Leave the last character blank, in case it's a really dumb terminal + * with hardware scroll. Second, don't paint the last character in the + * screen, SunOS 4.1.1 and Ultrix 4.2 curses won't let you. + */ + cols = sp->cols - 1; + + curlen = 0; + if (sp->q.cqe_next != (void *)&sp->gp->dq) { + for (p = sp->frp->name; *p != '\0'; ++p); + while (--p > sp->frp->name) { + if (*p == '/') { + ++p; + break; + } + if ((curlen += KEY_LEN(sp, *p)) > cols) { + curlen -= KEY_LEN(sp, *p); + ++p; + break; + } + } + + MOVE(sp, INFOLINE(sp), 0); + standout(); + for (; *p != '\0'; ++p) + ADDCH(*p); + standend(); + } + + /* + * Display the ruler. If we're not at the midpoint yet, move there. + * Otherwise, just add in two extra spaces. + * + * XXX + * Assume that numbers, commas, and spaces only take up a single + * column on the screen. + */ + if (O_ISSET(sp, O_RULER)) { + len = snprintf(buf, + sizeof(buf), "%lu,%lu", sp->lno, sp->cno + 1); + midpoint = (cols - ((len + 1) / 2)) / 2; + if (curlen < midpoint) { + MOVE(sp, INFOLINE(sp), midpoint); + ADDSTR(buf); + curlen += len; + } else if (curlen + 2 + len < cols) { + ADDSTR(" "); + ADDSTR(buf); + curlen += 2 + len; + } + } + + /* + * Display the mode and the modified flag, as close to the end of the + * line as possible, but guaranteeing at least two spaces between the + * ruler and the modified flag. + * + * XXX + * Assume that mode name characters, asterisks, and spaces only take + * up a single column on the screen. + */ + endpoint = cols; + if (O_ISSET(sp, O_SHOWDIRTY) && F_ISSET(ep, F_MODIFIED)) + --endpoint; + +#define MODESIZE 9 + if (O_ISSET(sp, O_SHOWMODE)) + endpoint -= MAX_MODE_NAME; + + if (endpoint < curlen + 2) + return (0); + + MOVE(sp, INFOLINE(sp), endpoint); + if (O_ISSET(sp, O_SHOWDIRTY) && F_ISSET(ep, F_MODIFIED)) + ADDSTR("*"); + if (O_ISSET(sp, O_SHOWMODE)) + ADDSTR(sp->showmode); + return (0); +} diff --git a/usr.bin/vi/svi/svi_relative.c b/usr.bin/vi/svi/svi_relative.c new file mode 100644 index 0000000..a1af33f --- /dev/null +++ b/usr.bin/vi/svi/svi_relative.c @@ -0,0 +1,334 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_relative.c 8.16 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "svi_screen.h" + +static size_t svi_screens + __P((SCR *, EXF *, char *, size_t, recno_t, size_t *)); + +/* + * svi_column -- + * Return the logical column of the cursor. + */ +int +svi_column(sp, ep, cp) + SCR *sp; + EXF *ep; + size_t *cp; +{ + size_t col; + + col = SVP(sp)->sc_col; + if (O_ISSET(sp, O_NUMBER)) + col -= O_NUMBER_LENGTH; + *cp = col; + return (0); +} + +/* + * svi_opt_screens -- + * Return the screen columns necessary to display the line, or + * if specified, the physical character column within the line, + * including space required for the O_NUMBER and O_LIST options. + */ +size_t +svi_opt_screens(sp, ep, lno, cnop) + SCR *sp; + EXF *ep; + recno_t lno; + size_t *cnop; +{ + size_t cols, screens; + + /* + * Check for a cached value. We maintain a cache because, if the + * line is large, this routine gets called repeatedly. One other + * hack, lots of time the cursor is on column one, which is an easy + * one. + */ + if (cnop == NULL) { + if (SVP(sp)->ss_lno == lno) + return (SVP(sp)->ss_screens); + } else if (*cnop == 0) + return (1); + + /* Figure out how many columns the line/column needs. */ + cols = svi_screens(sp, ep, NULL, 0, lno, cnop); + + /* Leading number if O_NUMBER option set. */ + if (O_ISSET(sp, O_NUMBER)) + cols += O_NUMBER_LENGTH; + + /* Trailing '$' if O_LIST option set. */ + if (O_ISSET(sp, O_LIST) && cnop == NULL) + cols += KEY_LEN(sp, '$'); + + screens = (cols / sp->cols + (cols % sp->cols ? 1 : 0)); + if (screens == 0) + screens = 1; + + /* Cache the value. */ + if (cnop == NULL) { + SVP(sp)->ss_lno = lno; + SVP(sp)->ss_screens = screens; + } + return (screens); +} + +/* + * svi_screens -- + * Return the screen columns necessary to display the line, or, + * if specified, the physical character column within the line. + */ +static size_t +svi_screens(sp, ep, lp, llen, lno, cnop) + SCR *sp; + EXF *ep; + char *lp; + size_t llen; + recno_t lno; + size_t *cnop; +{ + size_t chlen, cno, len, scno, tab_off; + int ch, listset; + char *p; + + /* Need the line to go any further. */ + if (lp == NULL) + lp = file_gline(sp, ep, lno, &llen); + + /* Missing or empty lines are easy. */ + if (lp == NULL || llen == 0) + return (0); + + listset = O_ISSET(sp, O_LIST); + +#define SET_CHLEN { \ + chlen = (ch = *(u_char *)p++) == '\t' && \ + !listset ? TAB_OFF(sp, tab_off) : KEY_LEN(sp, ch); \ +} +#define TAB_RESET { \ + /* \ + * If past the end of the screen, and the character was a tab, \ + * reset the screen column to 0. Otherwise, display the rest \ + * of the character on the next line. \ + */ \ + if ((tab_off += chlen) >= sp->cols) \ + if (ch == '\t') { \ + tab_off = 0; \ + scno -= scno % sp->cols; \ + } else \ + tab_off -= sp->cols; \ +} + p = lp; + len = llen; + scno = tab_off = 0; + if (cnop == NULL) + while (len--) { + SET_CHLEN; + scno += chlen; + TAB_RESET; + } + else + for (cno = *cnop; len--; --cno) { + SET_CHLEN; + scno += chlen; + TAB_RESET; + if (cno == 0) + break; + } + return (scno); +} + +/* + * svi_rcm -- + * Return the physical column from the line that will display a + * character closest to the currently most attractive character + * position (which is stored as a screen column). + */ +size_t +svi_rcm(sp, ep, lno) + SCR *sp; + EXF *ep; + recno_t lno; +{ + size_t len; + + /* Last character is easy, and common. */ + if (sp->rcm_last) + return (file_gline(sp, + ep, lno, &len) == NULL || len == 0 ? 0 : len - 1); + + /* First character is easy, and common. */ + if (HMAP->off == 1 && sp->rcm == 0) + return (0); + + /* + * Get svi_cm_private() to do the hard work. If doing leftright + * scrolling, we use the current screen offset, otherwise, use + * the first screen, i.e. an offset of 1. + * + * XXX + * I'm not sure that an offset of 1 is right. What happens is that + * the vi main loop calls us for the VM_RCM case. By using an offset + * of 1, we're assuming that every VM_RCM command changes lines, and + * that we want to position on the first screen for that line. This + * is currently the way it works, but it's not clean. I'd prefer it if + * we could find the SMAP entry the cursor references, and use that + * screen offset. Unfortunately, that's not going to be easy, as we + * don't keep that information around and it may be expensive to get. + */ + return (svi_cm_private(sp, ep, lno, + O_ISSET(sp, O_LEFTRIGHT) ? HMAP->off : 1, sp->rcm)); +} + +/* + * svi_cm_public -- + * Return the physical column from the line that will display a + * character closest to the specified screen column. + * + * The extra interface is because it's called by vi, which doesn't + * have a handle on the SMAP structure. + */ +size_t +svi_cm_public(sp, ep, lno, cno) + SCR *sp; + EXF *ep; + recno_t lno; + size_t cno; +{ + return (svi_cm_private(sp, ep, lno, HMAP->off, cno)); +} + +/* + * svi_cm_private -- + * Return the physical column from the line that will display a + * character closest to the specified screen column, taking into + * account the screen offset. + * + * The offset is for the commands that move logical distances, i.e. + * if it's a logical scroll the closest physical distance is based + * on the logical line, not the physical line. + */ +size_t +svi_cm_private(sp, ep, lno, off, cno) + SCR *sp; + EXF *ep; + recno_t lno; + size_t off, cno; +{ + size_t chlen, len, llen, scno, tab_off; + int ch, listset; + char *lp, *p; + + /* Need the line to go any further. */ + lp = file_gline(sp, ep, lno, &llen); + + /* Missing or empty lines are easy. */ + if (lp == NULL || llen == 0) + return (0); + + listset = O_ISSET(sp, O_LIST); + + /* Discard screen (logical) lines. */ + for (scno = 0, p = lp, len = llen; --off;) { + for (; len && scno < sp->cols; --len) + scno += (ch = *(u_char *)p++) == '\t' && + !listset ? TAB_OFF(sp, scno) : KEY_LEN(sp, ch); + + /* + * If reached the end of the physical line, return + * the last physical character in the line. + */ + if (len == 0) + return (llen - 1); + + /* + * If the character was a tab, reset the screen column to 0. + * Otherwise, the rest of the character is displayed on the + * next line. + */ + if (ch == '\t') + scno = 0; + else + scno -= sp->cols; + } + + /* Step through the line until reach the right character or EOL. */ + for (tab_off = scno; len--;) { + SET_CHLEN; + + /* + * If we've reached the specific character, there are three + * cases. + * + * 1: scno == cno, i.e. the current character ends at the + * screen character we care about. + * a: off < llen - 1, i.e. not the last character in + * the line, return the offset of the next character. + * b: else return the offset of the last character. + * 2: scno != cno, i.e. this character overruns the character + * we care about, return the offset of this character. + */ + if ((scno += chlen) >= cno) { + off = p - lp; + return (scno == cno ? + (off < llen - 1 ? off : llen - 1) : off - 1); + } + + TAB_RESET; + } + + /* No such character; return the start of the last character. */ + return (llen - 1); +} diff --git a/usr.bin/vi/svi/svi_screen.c b/usr.bin/vi/svi/svi_screen.c new file mode 100644 index 0000000..05e07ea --- /dev/null +++ b/usr.bin/vi/svi/svi_screen.c @@ -0,0 +1,332 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_screen.c 8.91 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "../vi/vcmd.h" +#include "svi_screen.h" +#include "../sex/sex_screen.h" + +/* + * svi_screen_init -- + * Initialize a screen. + */ +int +svi_screen_init(sp) + SCR *sp; +{ + /* Initialize support routines. */ + sp->s_bell = svi_bell; + sp->s_bg = svi_bg; + sp->s_busy = svi_busy; + sp->s_change = svi_change; + sp->s_clear = svi_clear; + sp->s_colpos = svi_cm_public; + sp->s_column = svi_column; + sp->s_confirm = svi_confirm; + sp->s_crel = svi_crel; + sp->s_edit = svi_screen_edit; + sp->s_end = svi_screen_end; + sp->s_ex_cmd = svi_ex_cmd; + sp->s_ex_run = svi_ex_run; + sp->s_ex_write = svi_ex_write; + sp->s_fg = svi_fg; + sp->s_fill = svi_sm_fill; + sp->s_get = svi_get; + sp->s_key_read = sex_key_read; + sp->s_optchange = svi_optchange; + sp->s_fmap = svi_fmap; + sp->s_position = svi_sm_position; + sp->s_rabs = svi_rabs; + sp->s_rcm = svi_rcm; + sp->s_refresh = svi_refresh; + sp->s_scroll = svi_sm_scroll; + sp->s_split = svi_split; + sp->s_suspend = svi_suspend; + sp->s_window = sex_window; + + return (0); +} + +/* + * svi_screen_copy -- + * Copy to a new screen. + */ +int +svi_screen_copy(orig, sp) + SCR *orig, *sp; +{ + SVI_PRIVATE *osvi, *nsvi; + + /* Create the private screen structure. */ + CALLOC_RET(orig, nsvi, SVI_PRIVATE *, 1, sizeof(SVI_PRIVATE)); + sp->svi_private = nsvi; + +/* INITIALIZED AT SCREEN CREATE. */ + /* Invalidate the line size cache. */ + SVI_SCR_CFLUSH(nsvi); + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ + if (orig == NULL) { + } else { + osvi = SVP(orig); + nsvi->srows = osvi->srows; + if (osvi->VB != NULL && (nsvi->VB = strdup(osvi->VB)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + F_SET(nsvi, F_ISSET(osvi, SVI_CURSES_INIT)); + } + return (0); +} + +/* + * svi_screen_end -- + * End a screen. + */ +int +svi_screen_end(sp) + SCR *sp; +{ + SVI_PRIVATE *svp; + + svp = SVP(sp); + + /* Free the screen map. */ + if (HMAP != NULL) + FREE(HMAP, SIZE_HMAP(sp) * sizeof(SMAP)); + + /* Free the visual bell string. */ + if (svp->VB != NULL) + free(svp->VB); + + /* Free private memory. */ + FREE(svp, sizeof(SVI_PRIVATE)); + sp->svi_private = NULL; + + return (0); +} + +/* + * We use a single curses "window" for each vi screen. The model would be + * simpler with two windows (one for the text, and one for the modeline) + * because scrolling the text window down would work correctly then, not + * affecting the mode line. As it is we have to play games to make it look + * right. The reason for this choice is that it would be difficult for + * curses to optimize the movement, i.e. detect that the downward scroll + * isn't going to change the modeline, set the scrolling region on the + * terminal and only scroll the first part of the text window. (Even if + * curses did detect it, the set-scrolling-region terminal commands can't + * be used by curses because it's indeterminate where the cursor ends up + * after they are sent.) + */ +/* + * svi_screen_edit -- + * Main vi curses screen loop. + */ +int +svi_screen_edit(sp, ep) + SCR *sp; + EXF *ep; +{ + SCR *tsp; + int ecurses, escreen, force, rval; + + escreen = ecurses = rval = 0; + + /* Initialize curses. */ + if (svi_curses_init(sp)) { + escreen = 1; + goto err; + } + ecurses = 1; + + /* + * The resize bit is probably set, as a result of the terminal being + * set. We clear it as we just finished initializing the screen. + * However, we will want to fill in the map from scratch, so provide + * a line number just in case, and set the reformat flag. + */ + HMAP->lno = 1; + F_CLR(sp, S_RESIZE); + F_SET(sp, S_REFORMAT); + + /* + * The historic 4BSD curses had an uneasy relationship with termcap. + * Termcap used a static buffer to hold the terminal information, + * which was was then used by the curses functions. We want to use + * it too, for lots of random things, but we've put it off until after + * svi_curses_init:initscr() was called. Do it now. + */ + if (svi_term_init(sp)) + goto err; + + for (;;) { + /* Reset the cursor. */ + F_SET(SVP(sp), SVI_CUR_INVALID); + + /* + * Run vi. If vi fails, svi data structures may be + * corrupted, be extremely careful what you free up. + */ + if (vi(sp, sp->ep)) { + (void)rcv_sync(sp, sp->ep, + RCV_EMAIL | RCV_ENDSESSION | RCV_PRESERVE); + escreen = 1; + goto err; + } + + force = 0; + switch (F_ISSET(sp, S_MAJOR_CHANGE)) { + case S_EXIT_FORCE: + force = 1; + /* FALLTHROUGH */ + case S_EXIT: + F_CLR(sp, S_EXIT_FORCE | S_EXIT); + if (file_end(sp, sp->ep, force))/* File end. */ + break; + /* + * !!! + * NB: sp->frp may now be NULL, if it was a tmp file. + */ + (void)svi_join(sp, &tsp); /* Find a new screen. */ + if (tsp == NULL) + (void)svi_swap(sp, &tsp, NULL); + if (tsp == NULL) { + escreen = 1; + goto ret; + } + (void)screen_end(sp); /* Screen end. */ + sp = tsp; + break; + case 0: /* Exit vi mode. */ + svi_dtoh(sp, "Exit from vi"); + goto ret; + case S_FSWITCH: /* File switch. */ + F_CLR(sp, S_FSWITCH); + F_SET(sp, S_REFORMAT); + break; + case S_SSWITCH: /* Screen switch. */ + F_CLR(sp, S_SSWITCH); + sp = sp->nextdisp; + break; + default: + abort(); + } + } + + if (0) { +err: rval = 1; + } + +ret: if (svi_term_end(sp)) /* Terminal end (uses sp). */ + rval = 1; + if (ecurses && svi_curses_end(sp)) /* Curses end (uses sp). */ + rval = 1; + if (escreen && screen_end(sp)) /* Screen end. */ + rval = 1; + return (rval); +} + +/* + * svi_crel -- + * Change the relative size of the current screen. + */ +int +svi_crel(sp, count) + SCR *sp; + long count; +{ + /* Can't grow beyond the size of the window. */ + if (count > O_VAL(sp, O_WINDOW)) + count = O_VAL(sp, O_WINDOW); + + sp->t_minrows = sp->t_rows = count; + if (sp->t_rows > sp->rows - 1) + sp->t_minrows = sp->t_rows = sp->rows - 1; + TMAP = HMAP + (sp->t_rows - 1); + F_SET(sp, S_REDRAW); + return (0); +} + +/* + * svi_dtoh -- + * Move all but the current screen to the hidden queue. + */ +void +svi_dtoh(sp, emsg) + SCR *sp; + char *emsg; +{ + SCR *tsp; + int hidden; + + for (hidden = 0; + (tsp = sp->gp->dq.cqh_first) != (void *)&sp->gp->dq; ++hidden) { + if (_HMAP(tsp) != NULL) { + FREE(_HMAP(tsp), SIZE_HMAP(tsp) * sizeof(SMAP)); + _HMAP(tsp) = NULL; + } + CIRCLEQ_REMOVE(&sp->gp->dq, tsp, q); + CIRCLEQ_INSERT_TAIL(&sp->gp->hq, tsp, q); + } + CIRCLEQ_REMOVE(&sp->gp->hq, sp, q); + CIRCLEQ_INSERT_TAIL(&sp->gp->dq, sp, q); + if (hidden > 1) + msgq(sp, M_INFO, + "%s backgrounded %d screens; use :display to list the screens", + emsg, hidden - 1); +} diff --git a/usr.bin/vi/svi/svi_screen.h b/usr.bin/vi/svi/svi_screen.h new file mode 100644 index 0000000..3b4643d --- /dev/null +++ b/usr.bin/vi/svi/svi_screen.h @@ -0,0 +1,262 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)svi_screen.h 8.52 (Berkeley) 7/20/94 + */ + +/* + * Structure for mapping lines to the screen. An SMAP is an array, with one + * structure element per screen line, which holds information describing the + * physical line which is displayed in the screen line. The first two fields + * (lno and off) are all that are necessary to describe a line. The rest of + * the information is useful to keep information from being re-calculated. + * + * Lno is the line number. Off is the screen offset into the line. For + * example, the pair 2:1 would be the first screen of line 2, and 2:2 would + * be the second. If doing left-right scrolling, all of the offsets will be + * the same, i.e. for the second screen, 1:2, 2:2, 3:2, etc. If doing the + * standard vi scrolling, it will be staggered, i.e. 1:1, 1:2, 1:3, 2:1, 3:1, + * etc. + * + * The SMAP is always as large as the physical screen, plus a slot for the + * info line, so that there is room to add any screen into another one at + * screen exit. + */ +typedef struct _smap { + recno_t lno; /* 1-N: Physical file line number. */ + size_t off; /* 1-N: Screen offset in the line. */ + + /* svi_line() cache information. */ + size_t c_sboff; /* 0-N: offset of first character byte. */ + size_t c_eboff; /* 0-N: offset of last character byte. */ + u_char c_scoff; /* 0-N: offset into the first character. */ + u_char c_eclen; /* 1-N: columns from the last character. */ + u_char c_ecsize; /* 1-N: size of the last character. */ +} SMAP; + + /* Macros to flush/test cached information. */ +#define SMAP_CACHE(smp) ((smp)->c_ecsize != 0) +#define SMAP_FLUSH(smp) ((smp)->c_ecsize = 0) + +typedef struct _svi_private { +/* INITIALIZED AT SCREEN CREATE. */ + SMAP *h_smap; /* First slot of the line map. */ + SMAP *t_smap; /* Last slot of the line map. */ + + size_t exlinecount; /* Ex overwrite count. */ + size_t extotalcount; /* Ex overwrite count. */ + size_t exlcontinue; /* Ex line continue value. */ + + /* svi_opt_screens() cache information. */ +#define SVI_SCR_CFLUSH(svp) svp->ss_lno = OOBLNO + recno_t ss_lno; /* 1-N: Line number. */ + size_t ss_screens; /* Return value. */ + + recno_t olno; /* 1-N: old cursor file line. */ + size_t ocno; /* 0-N: old file cursor column. */ + size_t sc_col; /* 0-N: LOGICAL screen column. */ + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ + size_t srows; /* 1-N: Rows in the terminal/window. */ + + char *VB; /* Visual bell termcap string. */ + +#define SVI_CURSES_INIT 0x001 /* Curses/termcap initialized. */ +#define SVI_CUR_INVALID 0x002 /* Cursor position is unknown. */ +#define SVI_DIVIDER 0x004 /* Screen divider is displayed. */ +#define SVI_INFOLINE 0x008 /* The infoline is being used by v_ntext(). */ +#define SVI_SCREENDIRTY 0x010 /* Screen needs refreshing. */ + u_int8_t flags; +} SVI_PRIVATE; + +#define SVP(sp) ((SVI_PRIVATE *)((sp)->svi_private)) +#define HMAP (SVP(sp)->h_smap) +#define TMAP (SVP(sp)->t_smap) +#define _HMAP(sp) (SVP(sp)->h_smap) +#define _TMAP(sp) (SVP(sp)->t_smap) + +/* + * One extra slot is always allocated for the map so that we can use + * it to do vi :colon command input; see svi_get(). + */ +#define SIZE_HMAP(sp) (SVP(sp)->srows + 1) + +#define O_NUMBER_FMT "%7lu " /* O_NUMBER format, length. */ +#define O_NUMBER_LENGTH 8 + /* Columns on a screen. */ +#define SCREEN_COLS(sp) \ + ((O_ISSET(sp, O_NUMBER) ? (sp)->cols - O_NUMBER_LENGTH : (sp)->cols)) + +#define HALFSCREEN(sp) ((sp)->t_maxrows / 2) /* Half the screen. */ +#define HALFTEXT(sp) ((sp)->t_rows / 2) /* Half the text. */ + +#define INFOLINE(sp) ((sp)->t_maxrows) /* Info line test, offset. */ +#define ISINFOLINE(sp, smp) (((smp) - HMAP) == INFOLINE(sp)) + + /* Small screen test. */ +#define ISSMALLSCREEN(sp) ((sp)->t_minrows != (sp)->t_maxrows) + +/* + * Next tab offset. + * + * !!! + * There are problems with how the historical vi handled tabs. For example, + * by doing "set ts=3" and building lines that fold, you can get it to step + * through tabs as if they were spaces and move inserted characters to new + * positions when <esc> is entered. I think that nvi does tabs correctly, + * but there may be some historical incompatibilities. + */ +#define TAB_OFF(sp, c) (O_VAL(sp, O_TABSTOP) - (c) % O_VAL(sp, O_TABSTOP)) + +/* Move in a screen (absolute), and fail if it doesn't work. */ +#ifdef DEBUG +#define MOVEA(sp, lno, cno) { \ + if (move(lno, cno) == ERR) { \ + msgq(sp, M_ERR, \ + "Error: %s/%d: move:l(%u), c(%u), abs", \ + tail(__FILE__), __LINE__, lno, cno); \ + return (1); \ + } \ +} +#else +#define MOVEA(sp, lno, cno) (void)move(lno, cno) +#endif + +/* Move in a window, and fail if it doesn't work. */ +#ifdef DEBUG +#define MOVE(sp, lno, cno) { \ + size_t __lno = (sp)->woff + (lno); \ + if (move(__lno, cno) == ERR) { \ + msgq(sp, M_ERR, \ + "Error: %s/%d: move:l(%u), c(%u), o(%u)", \ + tail(__FILE__), __LINE__, lno, cno, sp->woff); \ + return (1); \ + } \ +} +#else +#define MOVE(sp, lno, cno) (void)move((sp)->woff + (lno), cno) +#endif + +/* Add a character. */ +#define ADDCH(ch) { \ + CHAR_T __ch = ch; \ + ADDNSTR(KEY_NAME(sp, __ch), KEY_LEN(sp, __ch)); \ +} + +/* Add a string len bytes long. */ +#ifdef DEBUG +#define ADDNSTR(str, len) { \ + if (addnstr(str, len) == ERR) { \ + int __x, __y; \ + getyx(stdscr, __y, __x); \ + msgq(sp, M_ERR, "Error: %s/%d: addnstr: (%d/%u)", \ + tail(__FILE__), __LINE__, __y, __x); \ + return (1); \ + } \ +} +#else +#define ADDNSTR(str, len) (void)addnstr(str, len) +#endif + +/* Add a string. */ +#ifdef DEBUG +#define ADDSTR(str) { \ + if (addstr(str) == ERR) { \ + int __x, __y; \ + getyx(stdscr, __y, __x); \ + msgq(sp, M_ERR, "Error: %s/%d: addstr: (%d/%u)", \ + tail(__FILE__), __LINE__, __y, __x); \ + return (1); \ + } \ +} +#else +#define ADDSTR(str) (void)addstr(str); +#endif + +/* Public routines. */ +void svi_bell __P((SCR *)); +int svi_bg __P((SCR *)); +int svi_busy __P((SCR *, char const *)); +int svi_change __P((SCR *, EXF *, recno_t, enum operation)); +size_t svi_cm_public __P((SCR *, EXF *, recno_t, size_t)); +int svi_column __P((SCR *, EXF *, size_t *)); +enum confirm + svi_confirm __P((SCR *, EXF *, MARK *, MARK *)); +int svi_clear __P((SCR *)); +int svi_crel __P((SCR *, long)); +int svi_ex_cmd __P((SCR *, EXF *, struct _excmdarg *, MARK *)); +int svi_ex_run __P((SCR *, EXF *, MARK *)); +int svi_ex_write __P((void *, const char *, int)); +int svi_fg __P((SCR *, CHAR_T *)); +int svi_fmap __P((SCR *, enum seqtype, CHAR_T *, size_t, CHAR_T *, size_t)); +enum input + svi_get __P((SCR *, EXF *, TEXTH *, ARG_CHAR_T, u_int)); +int svi_optchange __P((SCR *, int)); +int svi_rabs __P((SCR *, long, enum adjust)); +size_t svi_rcm __P((SCR *, EXF *, recno_t)); +int svi_refresh __P((SCR *, EXF *)); +int svi_screen_copy __P((SCR *, SCR *)); +int svi_screen_edit __P((SCR *, EXF *)); +int svi_screen_end __P((SCR *)); +int svi_sm_fill __P((SCR *, EXF *, recno_t, enum position)); +int svi_sm_position __P((SCR *, EXF *, MARK *, u_long, enum position)); +int svi_sm_scroll __P((SCR *, EXF *, MARK *, recno_t, enum sctype)); +int svi_split __P((SCR *, ARGS *[], int)); +int svi_suspend __P((SCR *)); +int svi_swap __P((SCR *, SCR **, char *)); + +/* Private routines. */ +size_t svi_cm_private __P((SCR *, EXF *, recno_t, size_t, size_t)); +int svi_curses_end __P((SCR *)); +int svi_curses_init __P((SCR *)); +void svi_dtoh __P((SCR *, char *)); +int svi_init __P((SCR *)); +int svi_join __P((SCR *, SCR **)); +void svi_keypad __P((SCR *, int)); +int svi_line __P((SCR *, EXF *, SMAP *, size_t *, size_t *)); +int svi_msgflush __P((SCR *)); +int svi_number __P((SCR *, EXF *)); +size_t svi_opt_screens __P((SCR *, EXF *, recno_t, size_t *)); +int svi_paint __P((SCR *, EXF *)); +int svi_sm_1down __P((SCR *, EXF *)); +int svi_sm_1up __P((SCR *, EXF *)); +int svi_sm_cursor __P((SCR *, EXF *, SMAP **)); +int svi_sm_next __P((SCR *, EXF *, SMAP *, SMAP *)); +recno_t svi_sm_nlines __P((SCR *, EXF *, SMAP *, recno_t, size_t)); +int svi_sm_prev __P((SCR *, EXF *, SMAP *, SMAP *)); +int svi_term_end __P((SCR *sp)); +int svi_term_init __P((SCR *sp)); + +/* Private debugging routines. */ +#ifdef DEBUG +int svi_gdbrefresh __P((void)); +#endif diff --git a/usr.bin/vi/svi/svi_smap.c b/usr.bin/vi/svi/svi_smap.c new file mode 100644 index 0000000..6d06d8e --- /dev/null +++ b/usr.bin/vi/svi/svi_smap.c @@ -0,0 +1,1216 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_smap.c 8.46 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "../vi/vcmd.h" +#include "svi_screen.h" + +static int svi_deleteln __P((SCR *, int)); +static int svi_insertln __P((SCR *, int)); +static int svi_sm_delete __P((SCR *, EXF *, recno_t)); +static int svi_sm_down __P((SCR *, EXF *, + MARK *, recno_t, enum sctype, SMAP *)); +static int svi_sm_erase __P((SCR *)); +static int svi_sm_insert __P((SCR *, EXF *, recno_t)); +static int svi_sm_reset __P((SCR *, EXF *, recno_t)); +static int svi_sm_up __P((SCR *, EXF *, + MARK *, recno_t, enum sctype, SMAP *)); + +/* + * svi_change -- + * Make a change to the screen. + */ +int +svi_change(sp, ep, lno, op) + SCR *sp; + EXF *ep; + recno_t lno; + enum operation op; +{ + SMAP *p; + size_t oldy, oldx; + + /* Appending is the same as inserting, if the line is incremented. */ + if (op == LINE_APPEND) { + ++lno; + op = LINE_INSERT; + } + + /* Ignore the change if the line is after the map. */ + if (lno > TMAP->lno) + return (0); + + /* + * If the line is before the map, and it's a decrement, decrement + * the map. If it's an increment, increment the map. Otherwise, + * ignore it. + */ + if (lno < HMAP->lno) { + switch (op) { + case LINE_APPEND: + abort(); + /* NOTREACHED */ + case LINE_DELETE: + for (p = HMAP; p <= TMAP; ++p) + --p->lno; + if (sp->lno >= lno) + --sp->lno; + F_SET(sp, S_RENUMBER); + break; + case LINE_INSERT: + for (p = HMAP; p <= TMAP; ++p) + ++p->lno; + if (sp->lno >= lno) + ++sp->lno; + F_SET(sp, S_RENUMBER); + break; + case LINE_RESET: + break; + } + return (0); + } + + F_SET(SVP(sp), SVI_SCREENDIRTY); + + /* Invalidate the cursor, if it's on this line. */ + if (sp->lno == lno) + F_SET(SVP(sp), SVI_CUR_INVALID); + + /* Invalidate the line size cache. */ + SVI_SCR_CFLUSH(SVP(sp)); + + getyx(stdscr, oldy, oldx); + + switch (op) { + case LINE_DELETE: + if (svi_sm_delete(sp, ep, lno)) + return (1); + F_SET(sp, S_RENUMBER); + break; + case LINE_INSERT: + if (svi_sm_insert(sp, ep, lno)) + return (1); + F_SET(sp, S_RENUMBER); + break; + case LINE_RESET: + if (svi_sm_reset(sp, ep, lno)) + return (1); + break; + default: + abort(); + } + + MOVEA(sp, oldy, oldx); + + return (0); +} + +/* + * svi_sm_fill -- + * Fill in the screen map, placing the specified line at the + * right position. There isn't any way to tell if an SMAP + * entry has been filled in, so this routine had better be + * called with P_FILL set before anything else is done. + * + * !!! + * Unexported interface: if lno is OOBLNO, P_TOP means that the HMAP + * slot is already filled in, P_BOTTOM means that the TMAP slot is + * already filled in, and we just finish up the job. + */ +int +svi_sm_fill(sp, ep, lno, pos) + SCR *sp; + EXF *ep; + recno_t lno; + enum position pos; +{ + SMAP *p, tmp; + + /* Flush all cached information from the SMAP. */ + for (p = HMAP; p <= TMAP; ++p) + SMAP_FLUSH(p); + + /* If the map is filled, the screen must be redrawn. */ + F_SET(sp, S_REDRAW); + + switch (pos) { + case P_FILL: + tmp.lno = 1; + tmp.off = 1; + + /* See if less than half a screen from the top. */ + if (svi_sm_nlines(sp, ep, + &tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) { + lno = 1; + goto top; + } + + /* See if less than half a screen from the bottom. */ + if (file_lline(sp, ep, &tmp.lno)) + return (1); + if (!O_ISSET(sp, O_LEFTRIGHT)) + tmp.off = svi_opt_screens(sp, ep, tmp.lno, NULL); + if (svi_sm_nlines(sp, ep, + &tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) { + TMAP->lno = tmp.lno; + if (!O_ISSET(sp, O_LEFTRIGHT)) + TMAP->off = tmp.off; + goto bottom; + } + goto middle; + case P_TOP: + if (lno != OOBLNO) { +top: HMAP->lno = lno; + HMAP->off = 1; + } + /* If we fail, just punt. */ + for (p = HMAP; p < TMAP; ++p) + if (svi_sm_next(sp, ep, p, p + 1)) + goto err; + break; + case P_MIDDLE: + /* If we fail, guess that the file is too small. */ +middle: p = HMAP + (TMAP - HMAP) / 2; + for (p->lno = lno, p->off = 1; p > HMAP; --p) + if (svi_sm_prev(sp, ep, p, p - 1)) { + lno = 1; + goto top; + } + + /* If we fail, just punt. */ + p = HMAP + (TMAP - HMAP) / 2; + for (; p < TMAP; ++p) + if (svi_sm_next(sp, ep, p, p + 1)) + goto err; + break; + case P_BOTTOM: + if (lno != OOBLNO) { + TMAP->lno = lno; + if (!O_ISSET(sp, O_LEFTRIGHT)) + TMAP->off = svi_opt_screens(sp, ep, lno, NULL); + } + /* If we fail, guess that the file is too small. */ +bottom: for (p = TMAP; p > HMAP; --p) + if (svi_sm_prev(sp, ep, p, p - 1)) { + lno = 1; + goto top; + } + break; + default: + abort(); + } + return (0); + + /* + * Try and put *something* on the screen. If this fails, + * we have a serious hard error. + */ +err: HMAP->lno = 1; + HMAP->off = 1; + for (p = HMAP; p < TMAP; ++p) + if (svi_sm_next(sp, ep, p, p + 1)) + return (1); + return (0); +} + +/* + * For the routines svi_sm_reset, svi_sm_delete and svi_sm_insert: if the + * screen only contains one line, or, if the line is the entire screen, this + * gets fairly exciting. Skip the fun and simply return if there's only one + * line in the screen, or just call fill. Fill may not be entirely accurate, + * i.e. we may be painting the screen with something not even close to the + * cursor, but it's not like we're into serious performance issues here, and + * the refresh routine will fix it for us. + */ +#define TOO_WEIRD { \ + if (cnt_orig >= sp->t_rows) { \ + if (cnt_orig == 1) \ + return (0); \ + if (file_gline(sp, ep, lno, NULL) == NULL) \ + if (file_lline(sp, ep, &lno)) \ + return (1); \ + F_SET(sp, S_REDRAW); \ + return (svi_sm_fill(sp, ep, lno, P_TOP)); \ + } \ +} + +/* + * svi_sm_delete -- + * Delete a line out of the SMAP. + */ +static int +svi_sm_delete(sp, ep, lno) + SCR *sp; + EXF *ep; + recno_t lno; +{ + SMAP *p, *t; + size_t cnt_orig; + + /* + * Find the line in the map, and count the number of screen lines + * which display any part of the deleted line. + */ + for (p = HMAP; p->lno != lno; ++p); + if (O_ISSET(sp, O_LEFTRIGHT)) + cnt_orig = 1; + else + for (cnt_orig = 1, t = p + 1; + t <= TMAP && t->lno == lno; ++cnt_orig, ++t); + + TOO_WEIRD; + + /* Delete that many lines from the screen. */ + MOVE(sp, p - HMAP, 0); + if (svi_deleteln(sp, cnt_orig)) + return (1); + + /* Shift the screen map up. */ + memmove(p, p + cnt_orig, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP)); + + /* Decrement the line numbers for the rest of the map. */ + for (t = TMAP - cnt_orig; p <= t; ++p) + --p->lno; + + /* Display the new lines. */ + for (p = TMAP - cnt_orig;;) { + if (p < TMAP && svi_sm_next(sp, ep, p, p + 1)) + return (1); + /* svi_sm_next() flushed the cache. */ + if (svi_line(sp, ep, ++p, NULL, NULL)) + return (1); + if (p == TMAP) + break; + } + return (0); +} + +/* + * svi_sm_insert -- + * Insert a line into the SMAP. + */ +static int +svi_sm_insert(sp, ep, lno) + SCR *sp; + EXF *ep; + recno_t lno; +{ + SMAP *p, *t; + size_t cnt_orig, cnt; + + /* + * Find the line in the map, find out how many screen lines + * needed to display the line. + */ + for (p = HMAP; p->lno != lno; ++p); + if (O_ISSET(sp, O_LEFTRIGHT)) + cnt_orig = 1; + else + cnt_orig = svi_opt_screens(sp, ep, lno, NULL); + + TOO_WEIRD; + + /* + * The lines left in the screen override the number of screen + * lines in the inserted line. + */ + cnt = (TMAP - p) + 1; + if (cnt_orig > cnt) + cnt_orig = cnt; + + /* Push down that many lines. */ + MOVE(sp, p - HMAP, 0); + if (svi_insertln(sp, cnt_orig)) + return (1); + + /* Shift the screen map down. */ + memmove(p + cnt_orig, p, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP)); + + /* Increment the line numbers for the rest of the map. */ + for (t = p + cnt_orig; t <= TMAP; ++t) + ++t->lno; + + /* Fill in the SMAP for the new lines, and display. */ + for (cnt = 1, t = p; cnt <= cnt_orig; ++t, ++cnt) { + t->lno = lno; + t->off = cnt; + SMAP_FLUSH(t); + if (svi_line(sp, ep, t, NULL, NULL)) + return (1); + } + return (0); +} + +/* + * svi_sm_reset -- + * Reset a line in the SMAP. + */ +static int +svi_sm_reset(sp, ep, lno) + SCR *sp; + EXF *ep; + recno_t lno; +{ + SMAP *p, *t; + size_t cnt_orig, cnt_new, cnt, diff; + + /* + * See if the number of on-screen rows taken up by the old display + * for the line is the same as the number needed for the new one. + * If so, repaint, otherwise do it the hard way. + */ + for (p = HMAP; p->lno != lno; ++p); + if (O_ISSET(sp, O_LEFTRIGHT)) { + t = p; + cnt_orig = cnt_new = 1; + } else { + for (cnt_orig = 0, + t = p; t <= TMAP && t->lno == lno; ++cnt_orig, ++t); + cnt_new = svi_opt_screens(sp, ep, lno, NULL); + } + + TOO_WEIRD; + + if (cnt_orig == cnt_new) { + do { + SMAP_FLUSH(p); + if (svi_line(sp, ep, p, NULL, NULL)) + return (1); + } while (++p < t); + return (0); + } + + if (cnt_orig < cnt_new) { + /* Get the difference. */ + diff = cnt_new - cnt_orig; + + /* + * The lines left in the screen override the number of screen + * lines in the inserted line. + */ + cnt = (TMAP - p) + 1; + if (diff > cnt) + diff = cnt; + + /* Push down the extra lines. */ + MOVE(sp, p - HMAP, 0); + if (svi_insertln(sp, diff)) + return (1); + + /* Shift the screen map down. */ + memmove(p + diff, p, (((TMAP - p) - diff) + 1) * sizeof(SMAP)); + + /* Fill in the SMAP for the replaced line, and display. */ + for (cnt = 1, t = p; cnt_new-- && t <= TMAP; ++t, ++cnt) { + t->lno = lno; + t->off = cnt; + SMAP_FLUSH(t); + if (svi_line(sp, ep, t, NULL, NULL)) + return (1); + } + } else { + /* Get the difference. */ + diff = cnt_orig - cnt_new; + + /* Delete that many lines from the screen. */ + MOVE(sp, p - HMAP, 0); + if (svi_deleteln(sp, diff)) + return (1); + + /* Shift the screen map up. */ + memmove(p, p + diff, (((TMAP - p) - diff) + 1) * sizeof(SMAP)); + + /* Fill in the SMAP for the replaced line, and display. */ + for (cnt = 1, t = p; cnt_new--; ++t, ++cnt) { + t->lno = lno; + t->off = cnt; + SMAP_FLUSH(t); + if (svi_line(sp, ep, t, NULL, NULL)) + return (1); + } + + /* Display the new lines at the bottom of the screen. */ + for (t = TMAP - diff;;) { + if (t < TMAP && svi_sm_next(sp, ep, t, t + 1)) + return (1); + /* svi_sm_next() flushed the cache. */ + if (svi_line(sp, ep, ++t, NULL, NULL)) + return (1); + if (t == TMAP) + break; + } + } + return (0); +} + +/* + * svi_sm_scroll + * Scroll the SMAP up/down count logical lines. Different + * semantics based on the vi command, *sigh*. + */ +int +svi_sm_scroll(sp, ep, rp, count, scmd) + SCR *sp; + EXF *ep; + MARK *rp; + recno_t count; + enum sctype scmd; +{ + SMAP *smp; + + /* + * Invalidate the cursor. The line is probably going to change, + * (although for ^E and ^Y it may not). In any case, the scroll + * routines move the cursor to draw things. + */ + F_SET(SVP(sp), SVI_CUR_INVALID); + + /* Find the cursor in the screen. */ + if (svi_sm_cursor(sp, ep, &smp)) + return (1); + + switch (scmd) { + case CNTRL_B: + case CNTRL_U: + case CNTRL_Y: + case Z_CARAT: + if (svi_sm_down(sp, ep, rp, count, scmd, smp)) + return (1); + break; + case CNTRL_D: + case CNTRL_E: + case CNTRL_F: + case Z_PLUS: + if (svi_sm_up(sp, ep, rp, count, scmd, smp)) + return (1); + break; + default: + abort(); + } + + /* + * !!! + * If we're at the start of a line, go for the first non-blank. + * This makes it look like the old vi, even though we're moving + * around by logical lines, not physical ones. + * + * XXX + * In the presence of a long line, which has more than a screen + * width of leading spaces, this code can cause a cursor warp. + * Live with it. + */ + if (scmd != CNTRL_E && scmd != CNTRL_Y && + rp->cno == 0 && nonblank(sp, ep, rp->lno, &rp->cno)) + return (1); + + return (0); +} + +/* + * svi_sm_up -- + * Scroll the SMAP up count logical lines. + */ +static int +svi_sm_up(sp, ep, rp, count, scmd, smp) + SCR *sp; + EXF *ep; + MARK *rp; + enum sctype scmd; + recno_t count; + SMAP *smp; +{ + int cursor_set, echanged, zset; + SMAP s1, s2; + + /* + * Check to see if movement is possible. + * + * Get the line after the map. If that line is a new one (and if + * O_LEFTRIGHT option is set, this has to be true), and the next + * line doesn't exist, and the cursor doesn't move, or the cursor + * isn't even on the screen, or the cursor is already at the last + * line in the map, it's an error. If that test succeeded because + * the cursor wasn't at the end of the map, test to see if the map + * is mostly empty. + */ + if (svi_sm_next(sp, ep, TMAP, &s1)) + return (1); + if (s1.lno > TMAP->lno && !file_gline(sp, ep, s1.lno, NULL)) { + if (scmd == CNTRL_E || scmd == Z_PLUS || smp == TMAP) { + v_eof(sp, ep, NULL); + return (1); + } + if (svi_sm_next(sp, ep, smp, &s1)) + return (1); + if (s1.lno > smp->lno && !file_gline(sp, ep, s1.lno, NULL)) { + v_eof(sp, ep, NULL); + return (1); + } + } + + /* + * Small screens: see svi/svi_refresh.c:svi_refresh, section 2b. + * + * If it's a small screen, and the movement isn't larger than a + * screen, i.e some context will remain, open up the screen and + * display by scrolling. In this case, the cursor moves to the + * first line displayed. Otherwise, erase/compress and repaint, + * and move the cursor to the first line in the screen. Note, + * the ^F command is always in the latter case, for historical + * reasons. + */ + cursor_set = 0; + if (ISSMALLSCREEN(sp)) { + if (count >= sp->t_maxrows || scmd == CNTRL_F) { + s1 = TMAP[0]; + if (svi_sm_erase(sp)) + return (1); + for (; count--; s1 = s2) { + if (svi_sm_next(sp, ep, &s1, &s2)) + return (1); + if (s2.lno != s1.lno && + !file_gline(sp, ep, s2.lno, NULL)) + break; + } + TMAP[0] = s2; + if (svi_sm_fill(sp, ep, OOBLNO, P_BOTTOM)) + return (1); + return (svi_sm_position(sp, ep, rp, 0, P_TOP)); + } + for (; count && + sp->t_rows != sp->t_maxrows; --count, ++sp->t_rows) { + if (svi_sm_next(sp, ep, TMAP, &s1)) + return (1); + if (TMAP->lno != s1.lno && + !file_gline(sp, ep, s1.lno, NULL)) + break; + *++TMAP = s1; + /* svi_sm_next() flushed the cache. */ + if (svi_line(sp, ep, TMAP, NULL, NULL)) + return (1); + + if (scmd != CNTRL_E && !cursor_set) { + cursor_set = 1; + rp->lno = TMAP->lno; + rp->cno = TMAP->c_sboff; + } + } + if (count == 0) + return (0); + } + + for (echanged = zset = 0; count; --count) { + /* Decide what would show up on the screen. */ + if (svi_sm_next(sp, ep, TMAP, &s1)) + return (1); + + /* If the line doesn't exist, we're done. */ + if (TMAP->lno != s1.lno && !file_gline(sp, ep, s1.lno, NULL)) + break; + + /* Scroll the screen cursor up one logical line. */ + if (svi_sm_1up(sp, ep)) + return (1); + switch (scmd) { + case CNTRL_E: + if (smp > HMAP) + --smp; + else + echanged = 1; + break; + case Z_PLUS: + if (zset) { + if (smp > HMAP) + --smp; + } else { + smp = TMAP; + zset = 1; + } + /* FALLTHROUGH */ + default: + break; + } + } + + if (cursor_set) + return(0); + + switch (scmd) { + case CNTRL_E: + /* + * On a ^E that was forced to change lines, try and keep the + * cursor as close as possible to the last position, but also + * set it up so that the next "real" movement will return the + * cursor to the closest position to the last real movement. + */ + if (echanged) { + rp->lno = smp->lno; + rp->cno = + svi_cm_private(sp, ep, smp->lno, smp->off, sp->rcm); + } + return (0); + case CNTRL_F: + /* + * If there are more lines, the ^F command is always + * positioned at the first line of the screen. + */ + if (!count) { + smp = HMAP; + break; + } + /* FALLTHROUGH */ + case CNTRL_D: + /* + * The ^D and ^F commands move the cursor towards EOF + * if there are more lines to move. Check to be sure + * the lines actually exist. (They may not if the + * file is smaller than the screen.) + */ + for (; count; --count, ++smp) + if (smp == TMAP || + !file_gline(sp, ep, smp[1].lno, NULL)) + break; + break; + case Z_PLUS: + /* The z+ command moves the cursor to the first new line. */ + break; + default: + abort(); + } + + if (!SMAP_CACHE(smp) && svi_line(sp, ep, smp, NULL, NULL)) + return (1); + rp->lno = smp->lno; + rp->cno = smp->c_sboff; + return (0); +} + +/* + * svi_sm_1up -- + * Scroll the SMAP up one. + */ +int +svi_sm_1up(sp, ep) + SCR *sp; + EXF *ep; +{ + /* + * Delete the top line of the screen. Shift the screen map up. + * Display a new line at the bottom of the screen. + */ + MOVE(sp, 0, 0); + if (svi_deleteln(sp, 1)) + return (1); + + /* One-line screens can fail. */ + if (HMAP == TMAP) { + if (svi_sm_next(sp, ep, TMAP, TMAP)) + return (1); + } else { + memmove(HMAP, HMAP + 1, (sp->rows - 1) * sizeof(SMAP)); + if (svi_sm_next(sp, ep, TMAP - 1, TMAP)) + return (1); + } + /* svi_sm_next() flushed the cache. */ + if (svi_line(sp, ep, TMAP, NULL, NULL)) + return (1); + return (0); +} + +/* + * svi_deleteln -- + * Delete a line a la curses, make sure to put the information + * line and other screens back. + */ +static int +svi_deleteln(sp, cnt) + SCR *sp; + int cnt; +{ + size_t oldy, oldx; + + getyx(stdscr, oldy, oldx); + while (cnt--) { + deleteln(); + MOVE(sp, INFOLINE(sp) - 1, 0); + insertln(); + MOVEA(sp, oldy, oldx); + } + return (0); +} + +/* + * svi_sm_down -- + * Scroll the SMAP down count logical lines. + */ +static int +svi_sm_down(sp, ep, rp, count, scmd, smp) + SCR *sp; + EXF *ep; + MARK *rp; + recno_t count; + SMAP *smp; + enum sctype scmd; +{ + SMAP s1, s2; + int cursor_set, ychanged, zset; + + /* Check to see if movement is possible. */ + if (HMAP->lno == 1 && HMAP->off == 1 && + (scmd == CNTRL_Y || scmd == Z_CARAT || smp == HMAP)) { + v_sof(sp, NULL); + return (1); + } + + /* + * Small screens: see svi/svi_refresh.c:svi_refresh, section 2b. + * + * If it's a small screen, and the movement isn't larger than a + * screen, i.e some context will remain, open up the screen and + * display by scrolling. In this case, the cursor moves to the + * first line displayed. Otherwise, erase/compress and repaint, + * and move the cursor to the first line in the screen. Note, + * the ^B command is always in the latter case, for historical + * reasons. + */ + cursor_set = scmd == CNTRL_Y; + if (ISSMALLSCREEN(sp)) { + if (count >= sp->t_maxrows || scmd == CNTRL_B) { + s1 = HMAP[0]; + if (svi_sm_erase(sp)) + return (1); + for (; count--; s1 = s2) { + if (svi_sm_prev(sp, ep, &s1, &s2)) + return (1); + if (s2.lno == 1 && s2.off == 1) + break; + } + HMAP[0] = s2; + if (svi_sm_fill(sp, ep, OOBLNO, P_TOP)) + return (1); + return (svi_sm_position(sp, ep, rp, 0, P_BOTTOM)); + } + for (; count && + sp->t_rows != sp->t_maxrows; --count, ++sp->t_rows) { + if (HMAP->lno == 1 || HMAP->off == 1) + break; + ++TMAP; + if (svi_sm_1down(sp, ep)) + return (1); + if (scmd != CNTRL_Y && !cursor_set) { + cursor_set = 1; + if (svi_sm_position(sp, ep, rp, 0, P_BOTTOM)) + return (1); + } + } + if (count == 0) + return (0); + } + + for (ychanged = zset = 0; count; --count) { + /* If the line doesn't exist, we're done. */ + if (HMAP->lno == 1 && HMAP->off == 1) + break; + + /* Scroll the screen and cursor down one logical line. */ + if (svi_sm_1down(sp, ep)) + return (1); + switch (scmd) { + case CNTRL_Y: + if (smp < TMAP) + ++smp; + else + ychanged = 1; + break; + case Z_CARAT: + if (zset) { + if (smp < TMAP) + ++smp; + } else { + smp = HMAP; + zset = 1; + } + /* FALLTHROUGH */ + default: + break; + } + } + + if (scmd != CNTRL_Y && cursor_set) + return(0); + + switch (scmd) { + case CNTRL_B: + /* + * If there are more lines, the ^B command is always + * positioned at the last line of the screen. + */ + if (!count) { + smp = TMAP; + break; + } + /* FALLTHROUGH */ + case CNTRL_U: + /* + * The ^B and ^U commands move the cursor towards SOF + * if there are more lines to move. + */ + if (count < smp - HMAP) + smp -= count; + else + smp = HMAP; + break; + case CNTRL_Y: + /* + * On a ^Y that was forced to change lines, try and keep the + * cursor as close as possible to the last position, but also + * set it up so that the next "real" movement will return the + * cursor to the closest position to the last real movement. + */ + if (ychanged) { + rp->lno = smp->lno; + rp->cno = + svi_cm_private(sp, ep, smp->lno, smp->off, sp->rcm); + } + return (0); + case Z_CARAT: + /* The z^ command moves the cursor to the first new line. */ + break; + default: + abort(); + } + + if (!SMAP_CACHE(smp) && svi_line(sp, ep, smp, NULL, NULL)) + return (1); + rp->lno = smp->lno; + rp->cno = smp->c_sboff; + return (0); +} + +/* + * svi_sm_erase -- + * Erase the small screen area for the scrolling functions. + */ +static int +svi_sm_erase(sp) + SCR *sp; +{ + MOVE(sp, INFOLINE(sp), 0); + clrtoeol(); + for (; sp->t_rows > sp->t_minrows; --sp->t_rows, --TMAP) { + MOVE(sp, TMAP - HMAP, 0); + clrtoeol(); + } + return (0); +} + +/* + * svi_sm_1down -- + * Scroll the SMAP down one. + */ +int +svi_sm_1down(sp, ep) + SCR *sp; + EXF *ep; +{ + /* + * Clear the bottom line of the screen, insert a line at the top + * of the screen. Shift the screen map down, display a new line + * at the top of the screen. + */ + MOVE(sp, sp->t_rows, 0); + clrtoeol(); + MOVE(sp, 0, 0); + if (svi_insertln(sp, 1)) + return (1); + memmove(HMAP + 1, HMAP, (sp->rows - 1) * sizeof(SMAP)); + if (svi_sm_prev(sp, ep, HMAP + 1, HMAP)) + return (1); + /* svi_sm_prev() flushed the cache. */ + if (svi_line(sp, ep, HMAP, NULL, NULL)) + return (1); + return (0); +} + +/* + * svi_insertln -- + * Insert a line a la curses, make sure to put the information + * line and other screens back. + */ +static int +svi_insertln(sp, cnt) + SCR *sp; + int cnt; +{ + size_t oldy, oldx; + + getyx(stdscr, oldy, oldx); + while (cnt--) { + MOVE(sp, INFOLINE(sp) - 1, 0); + deleteln(); + MOVEA(sp, oldy, oldx); + insertln(); + } + return (0); +} + +/* + * svi_sm_next -- + * Fill in the next entry in the SMAP. + */ +int +svi_sm_next(sp, ep, p, t) + SCR *sp; + EXF *ep; + SMAP *p, *t; +{ + size_t lcnt; + + SMAP_FLUSH(t); + if (O_ISSET(sp, O_LEFTRIGHT)) { + t->lno = p->lno + 1; + t->off = p->off; + } else { + lcnt = svi_opt_screens(sp, ep, p->lno, NULL); + if (lcnt == p->off) { + t->lno = p->lno + 1; + t->off = 1; + } else { + t->lno = p->lno; + t->off = p->off + 1; + } + } + return (0); +} + +/* + * svi_sm_prev -- + * Fill in the previous entry in the SMAP. + */ +int +svi_sm_prev(sp, ep, p, t) + SCR *sp; + EXF *ep; + SMAP *p, *t; +{ + SMAP_FLUSH(t); + if (O_ISSET(sp, O_LEFTRIGHT)) { + t->lno = p->lno - 1; + t->off = p->off; + } else if (p->off != 1) { + t->lno = p->lno; + t->off = p->off - 1; + } else { + t->lno = p->lno - 1; + t->off = svi_opt_screens(sp, ep, t->lno, NULL); + } + return (t->lno == 0); +} + +/* + * svi_sm_cursor -- + * Return the SMAP entry referenced by the cursor. + */ +int +svi_sm_cursor(sp, ep, smpp) + SCR *sp; + EXF *ep; + SMAP **smpp; +{ + SMAP *p; + + /* See if the cursor is not in the map. */ + if (sp->lno < HMAP->lno || sp->lno > TMAP->lno) + return (1); + + /* Find the first occurence of the line. */ + for (p = HMAP; p->lno != sp->lno; ++p); + + /* Fill in the map information until we find the right line. */ + for (; p <= TMAP; ++p) { + /* Short lines are common and easy to detect. */ + if (p != TMAP && (p + 1)->lno != p->lno) { + *smpp = p; + return (0); + } + if (!SMAP_CACHE(p) && svi_line(sp, ep, p, NULL, NULL)) + return (1); + if (p->c_eboff >= sp->cno) { + *smpp = p; + return (0); + } + } + + /* It was past the end of the map after all. */ + return (1); +} + +/* + * svi_sm_position -- + * Return the line/column of the top, middle or last line on the screen. + * (The vi H, M and L commands.) Here because only the screen routines + * know what's really out there. + */ +int +svi_sm_position(sp, ep, rp, cnt, pos) + SCR *sp; + EXF *ep; + MARK *rp; + u_long cnt; + enum position pos; +{ + SMAP *smp; + recno_t last; + + switch (pos) { + case P_TOP: + /* + * !!! + * Historically, an invalid count to the H command failed. + * We do nothing special here, just making sure that H in + * an empty screen works. + */ + if (cnt > TMAP - HMAP) + goto sof; + smp = HMAP + cnt; + if (cnt && file_gline(sp, ep, smp->lno, NULL) == NULL) { +sof: msgq(sp, M_BERR, "Movement past the end-of-screen"); + return (1); + } + break; + case P_MIDDLE: + /* + * !!! + * Historically, a count to the M command was ignored. + * If the screen isn't filled, find the middle of what's + * real and move there. + */ + if (file_gline(sp, ep, TMAP->lno, NULL) == NULL) { + if (file_lline(sp, ep, &last)) + return (1); + for (smp = TMAP; smp->lno > last && smp > HMAP; --smp); + if (smp > HMAP) + smp -= (smp - HMAP) / 2; + } else + smp = (HMAP + (TMAP - HMAP) / 2) + cnt; + break; + case P_BOTTOM: + /* + * !!! + * Historically, an invalid count to the L command failed. + * If the screen isn't filled, find the bottom of what's + * real and try to offset from there. + */ + if (cnt > TMAP - HMAP) + goto eof; + smp = TMAP - cnt; + if (file_gline(sp, ep, smp->lno, NULL) == NULL) { + if (file_lline(sp, ep, &last)) + return (1); + for (; smp->lno > last && smp > HMAP; --smp); + if (cnt > smp - HMAP) { +eof: msgq(sp, M_BERR, + "Movement past the beginning-of-screen"); + return (1); + } + smp -= cnt; + } + break; + default: + abort(); + } + + /* Make sure that the cached information is valid. */ + if (!SMAP_CACHE(smp) && svi_line(sp, ep, smp, NULL, NULL)) + return (1); + rp->lno = smp->lno; + rp->cno = smp->c_sboff; + + return (0); +} + +/* + * svi_sm_nlines -- + * Return the number of screen lines from an SMAP entry to the + * start of some file line, less than a maximum value. + */ +recno_t +svi_sm_nlines(sp, ep, from_sp, to_lno, max) + SCR *sp; + EXF *ep; + SMAP *from_sp; + recno_t to_lno; + size_t max; +{ + recno_t lno, lcnt; + + if (O_ISSET(sp, O_LEFTRIGHT)) + return (from_sp->lno > to_lno ? + from_sp->lno - to_lno : to_lno - from_sp->lno); + + if (from_sp->lno == to_lno) + return (from_sp->off - 1); + + if (from_sp->lno > to_lno) { + lcnt = from_sp->off - 1; /* Correct for off-by-one. */ + for (lno = from_sp->lno; --lno >= to_lno && lcnt <= max;) + lcnt += svi_opt_screens(sp, ep, lno, NULL); + } else { + lno = from_sp->lno; + lcnt = (svi_opt_screens(sp, ep, lno, NULL) - from_sp->off) + 1; + for (; ++lno < to_lno && lcnt <= max;) + lcnt += svi_opt_screens(sp, ep, lno, NULL); + } + return (lcnt); +} diff --git a/usr.bin/vi/svi/svi_split.c b/usr.bin/vi/svi/svi_split.c new file mode 100644 index 0000000..160f495 --- /dev/null +++ b/usr.bin/vi/svi/svi_split.c @@ -0,0 +1,627 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_split.c 8.46 (Berkeley) 8/9/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "svi_screen.h" + +/* + * svi_split -- + * Split the screen. + */ +int +svi_split(sp, argv, argc) + SCR *sp; + ARGS *argv[]; + int argc; +{ + MSG *mp, *next; + SCR *tsp, saved_sp; + SVI_PRIVATE saved_svp; + SMAP *smp; + size_t cnt, half; + int issmallscreen, splitup; + char **ap; + + /* Check to see if it's possible. */ + half = sp->rows / 2; + if (half < MINIMUM_SCREEN_ROWS) { + msgq(sp, M_ERR, "Screen must be larger than %d to split", + MINIMUM_SCREEN_ROWS); + return (1); + } + + /* Get a new screen. */ + if (screen_init(sp, &tsp, 0)) + return (1); + CALLOC(sp, _HMAP(tsp), SMAP *, SIZE_HMAP(sp), sizeof(SMAP)); + if (_HMAP(tsp) == NULL) + return (1); + + /* + * We're about to modify the current screen. Save the contents + * in case something goes horribly, senselessly wrong. + */ + saved_sp = *sp; + saved_svp = *SVP(sp); + +/* INITIALIZED AT SCREEN CREATE. */ + +/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ + /* + * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b. + * Set a flag so we know to fix the screen up later. + */ + issmallscreen = ISSMALLSCREEN(sp); + + /* + * Split the screen, and link the screens together. If the cursor + * is in the top half of the current screen, the new screen goes + * under the current screen. Else, it goes above the current screen. + * + * The columns in the screen don't change. + */ + tsp->cols = sp->cols; + + cnt = svi_sm_cursor(sp, sp->ep, &smp) ? 0 : smp - HMAP; + if (cnt <= half) { /* Parent is top half. */ + /* Child. */ + tsp->rows = sp->rows - half; + tsp->woff = sp->woff + half; + tsp->t_maxrows = tsp->rows - 1; + + /* Parent. */ + sp->rows = half; + sp->t_maxrows = sp->rows - 1; + + splitup = 0; + } else { /* Parent is bottom half. */ + /* Child. */ + tsp->rows = sp->rows - half; + tsp->woff = sp->woff; + tsp->t_maxrows = tsp->rows - 1; + + /* Parent. */ + sp->rows = half; + sp->woff += tsp->rows; + sp->t_maxrows = sp->rows - 1; + + /* Shift the parent's map down. */ + memmove(_HMAP(sp), + _HMAP(sp) + tsp->rows, sp->t_maxrows * sizeof(SMAP)); + + splitup = 1; + } + + /* + * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b. + * + * The child may have different screen options sizes than the + * parent, so use them. Make sure that the text counts aren't + * larger than the new screen sizes. + */ + if (issmallscreen) { + /* Fix the text line count for the parent. */ + if (splitup) + sp->t_rows -= tsp->rows; + + /* Fix the parent screen. */ + if (sp->t_rows > sp->t_maxrows) + sp->t_rows = sp->t_maxrows; + if (sp->t_minrows > sp->t_maxrows) + sp->t_minrows = sp->t_maxrows; + + /* Fix the child screen. */ + tsp->t_minrows = tsp->t_rows = O_VAL(sp, O_WINDOW); + if (tsp->t_rows > tsp->t_maxrows) + tsp->t_rows = tsp->t_maxrows; + if (tsp->t_minrows > tsp->t_maxrows) + tsp->t_minrows = tsp->t_maxrows; + + /* + * If we split up, i.e. the child is on top, lines that + * were painted in the parent may not be painted in the + * child. Clear any lines not being used in the child + * screen. + * + */ + if (splitup) + for (cnt = tsp->t_rows; ++cnt <= tsp->t_maxrows;) { + MOVE(tsp, cnt, 0); + clrtoeol(); + } + } else { + sp->t_minrows = sp->t_rows = sp->rows - 1; + + /* + * The new screen may be a small screen, even though the + * parent was not. Don't complain if O_WINDOW is too large, + * we're splitting the screen so the screen is much smaller + * than normal. Clear any lines not being used in the child + * screen. + */ + tsp->t_minrows = tsp->t_rows = O_VAL(sp, O_WINDOW); + if (tsp->t_rows > tsp->rows - 1) + tsp->t_minrows = tsp->t_rows = tsp->rows - 1; + else + for (cnt = tsp->t_rows; ++cnt <= tsp->t_maxrows;) { + MOVE(tsp, cnt, 0); + clrtoeol(); + } + } + + /* Adjust the ends of both maps. */ + _TMAP(sp) = _HMAP(sp) + (sp->t_rows - 1); + _TMAP(tsp) = _HMAP(tsp) + (tsp->t_rows - 1); + + /* Reset the length of the default scroll. */ + sp->defscroll = sp->t_maxrows / 2; + tsp->defscroll = tsp->t_maxrows / 2; + + /* + * If files specified, build the file list, else, link to the + * current file. + */ + if (argv == NULL) { + if ((tsp->frp = file_add(tsp, sp->frp->name)) == NULL) + goto err; + } else { + /* Create a new argument list. */ + CALLOC(sp, tsp->argv, char **, argc + 1, sizeof(char *)); + if (tsp->argv == NULL) + goto err; + for (ap = tsp->argv, argv; argv[0]->len != 0; ++ap, ++argv) + if ((*ap = + v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL) + goto err; + *ap = NULL; + + /* Switch to the first one. */ + tsp->cargv = tsp->argv; + if ((tsp->frp = file_add(tsp, *tsp->cargv)) == NULL) + goto err; + } + + /* + * Copy the file state flags, start the file. Fill the child's + * screen map. If the file is unchanged, keep the screen and + * cursor the same. + */ + if (argv == NULL) { + tsp->ep = sp->ep; + ++sp->ep->refcnt; + + tsp->frp->flags = sp->frp->flags; + tsp->frp->lno = sp->lno; + tsp->frp->cno = sp->cno; + F_SET(tsp->frp, FR_CURSORSET); + + /* Copy the parent's map into the child's map. */ + memmove(_HMAP(tsp), _HMAP(sp), tsp->t_rows * sizeof(SMAP)); + } else { + if (file_init(tsp, tsp->frp, NULL, 0)) + goto err; + (void)svi_sm_fill(tsp, tsp->ep, 1, P_TOP); + } + + /* Everything's initialized, put the screen on the displayed queue.*/ + if (splitup) { + /* Link in before the parent. */ + CIRCLEQ_INSERT_BEFORE(&sp->gp->dq, sp, tsp, q); + } else { + /* Link in after the parent. */ + CIRCLEQ_INSERT_AFTER(&sp->gp->dq, sp, tsp, q); + } + + /* Clear the current information lines in both screens. */ + MOVE(sp, INFOLINE(sp), 0); + clrtoeol(); + MOVE(tsp, INFOLINE(tsp), 0); + clrtoeol(); + + /* Redraw the status line for the parent screen. */ + (void)msg_status(sp, sp->ep, sp->lno, 0); + + /* Save the parent screen's cursor information. */ + sp->frp->lno = sp->lno; + sp->frp->cno = sp->cno; + F_SET(sp->frp, FR_CURSORSET); + + /* Completely redraw the child screen. */ + F_SET(tsp, S_REDRAW); + + /* Switch screens. */ + sp->nextdisp = tsp; + F_SET(sp, S_SSWITCH); + return (0); + + /* Recover the original screen. */ +err: *sp = saved_sp; + *SVP(sp) = saved_svp; + + /* Copy any (probably error) messages in the new screen. */ + for (mp = tsp->msgq.lh_first; mp != NULL; mp = next) { + if (!F_ISSET(mp, M_EMPTY)) + msg_app(sp->gp, sp, + mp->flags & M_INV_VIDEO, mp->mbuf, mp->len); + next = mp->q.le_next; + if (mp->mbuf != NULL) + free(mp->mbuf); + free(mp); + } + + /* Free the new screen. */ + if (tsp->argv != NULL) { + for (ap = tsp->argv; *ap != NULL; ++ap) + free(*ap); + free(tsp->argv); + } + free(_HMAP(tsp)); + free(SVP(tsp)); + FREE(tsp, sizeof(SCR)); + return (1); +} + +/* + * svi_bg -- + * Background the screen, and switch to the next one. + */ +int +svi_bg(csp) + SCR *csp; +{ + SCR *sp; + + /* Try and join with another screen. */ + if ((svi_join(csp, &sp))) + return (1); + if (sp == NULL) { + msgq(csp, M_ERR, + "You may not background your only displayed screen"); + return (1); + } + + /* Move the old screen to the hidden queue. */ + CIRCLEQ_REMOVE(&csp->gp->dq, csp, q); + CIRCLEQ_INSERT_TAIL(&csp->gp->hq, csp, q); + + /* Switch screens. */ + csp->nextdisp = sp; + F_SET(csp, S_SSWITCH); + + return (0); +} + +/* + * svi_join -- + * Join the screen into a related screen, if one exists, + * and return that screen. + */ +int +svi_join(csp, nsp) + SCR *csp, **nsp; +{ + SCR *sp; + size_t cnt; + + /* + * If a split screen, add space to parent/child. Make no effort + * to clean up the screen's values. If it's not exiting, we'll + * get it when the user asks to show it again. + */ + if ((sp = csp->q.cqe_prev) == (void *)&csp->gp->dq) { + if ((sp = csp->q.cqe_next) == (void *)&csp->gp->dq) { + *nsp = NULL; + return (0); + } + sp->woff = csp->woff; + } + sp->rows += csp->rows; + if (ISSMALLSCREEN(sp)) { + sp->t_maxrows += csp->rows; + for (cnt = sp->t_rows; ++cnt <= sp->t_maxrows;) { + MOVE(sp, cnt, 0); + clrtoeol(); + } + TMAP = HMAP + (sp->t_rows - 1); + } else { + sp->t_maxrows += csp->rows; + sp->t_rows = sp->t_minrows = sp->t_maxrows; + TMAP = HMAP + (sp->t_rows - 1); + if (svi_sm_fill(sp, sp->ep, sp->lno, P_FILL)) + return (1); + F_SET(sp, S_REDRAW); + } + + /* Reset the length of the default scroll. */ + sp->defscroll = sp->t_maxrows / 2; + + /* + * Save the old screen's cursor information. + * + * XXX + * If called after file_end(), if the underlying file was a tmp + * file it may have gone away. + */ + if (csp->frp != NULL) { + csp->frp->lno = csp->lno; + csp->frp->cno = csp->cno; + F_SET(csp->frp, FR_CURSORSET); + } + + *nsp = sp; + return (0); +} + +/* + * svi_fg -- + * Background the current screen, and foreground a new one. + */ +int +svi_fg(csp, name) + SCR *csp; + CHAR_T *name; +{ + SCR *sp; + + if (svi_swap(csp, &sp, name)) + return (1); + if (sp == NULL) { + if (name == NULL) + msgq(csp, M_ERR, "There are no background screens"); + else + msgq(csp, M_ERR, + "There's no background screen editing a file named %s", + name); + return (1); + } + + /* Move the old screen to the hidden queue. */ + CIRCLEQ_REMOVE(&csp->gp->dq, csp, q); + CIRCLEQ_INSERT_TAIL(&csp->gp->hq, csp, q); + + return (0); +} + +/* + * svi_swap -- + * Swap the current screen with a hidden one. + */ +int +svi_swap(csp, nsp, name) + SCR *csp, **nsp; + char *name; +{ + SCR *sp; + int issmallscreen; + + /* Find the screen, or, if name is NULL, the first screen. */ + for (sp = csp->gp->hq.cqh_first; + sp != (void *)&csp->gp->hq; sp = sp->q.cqe_next) + if (name == NULL || !strcmp(sp->frp->name, name)) + break; + if (sp == (void *)&csp->gp->hq) { + *nsp = NULL; + return (0); + } + *nsp = sp; + + /* + * Save the old screen's cursor information. + * + * XXX + * If called after file_end(), if the underlying file was a tmp + * file it may have gone away. + */ + if (csp->frp != NULL) { + csp->frp->lno = csp->lno; + csp->frp->cno = csp->cno; + F_SET(csp->frp, FR_CURSORSET); + } + + /* Switch screens. */ + csp->nextdisp = sp; + F_SET(csp, S_SSWITCH); + + /* Initialize terminal information. */ + SVP(sp)->srows = SVP(csp)->srows; + + issmallscreen = ISSMALLSCREEN(sp); + + /* Initialize screen information. */ + sp->rows = csp->rows; + sp->cols = csp->cols; + sp->woff = csp->woff; + + /* + * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b. + * + * The new screens may have different screen options sizes than the + * old one, so use them. Make sure that text counts aren't larger + * than the new screen sizes. + */ + if (issmallscreen) { + sp->t_minrows = sp->t_rows = O_VAL(sp, O_WINDOW); + if (sp->t_rows > csp->t_maxrows) + sp->t_rows = sp->t_maxrows; + if (sp->t_minrows > csp->t_maxrows) + sp->t_minrows = sp->t_maxrows; + } else + sp->t_rows = sp->t_maxrows = sp->t_minrows = sp->rows - 1; + + /* Reset the length of the default scroll. */ + sp->defscroll = sp->t_maxrows / 2; + + /* + * Don't change the screen's cursor information other than to + * note that the cursor is wrong. + */ + F_SET(SVP(sp), SVI_CUR_INVALID); + + /* + * The HMAP may be NULL, if the screen got resized and + * a bunch of screens had to be hidden. + */ + if (HMAP == NULL) + CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP)); + TMAP = HMAP + (sp->t_rows - 1); + + /* Fill the map. */ + if (svi_sm_fill(sp, sp->ep, sp->lno, P_FILL)) + return (1); + + /* + * The new screen replaces the old screen in the parent/child list. + * We insert the new screen after the old one. If we're exiting, + * the exit will delete the old one, if we're foregrounding, the fg + * code will move the old one to the hidden queue. + */ + CIRCLEQ_REMOVE(&sp->gp->hq, sp, q); + CIRCLEQ_INSERT_AFTER(&csp->gp->dq, csp, sp, q); + + F_SET(sp, S_REDRAW); + return (0); +} + +/* + * svi_rabs -- + * Change the absolute size of the current screen. + */ +int +svi_rabs(sp, count, adj) + SCR *sp; + long count; + enum adjust adj; +{ + SCR *g, *s; + + /* + * Figure out which screens will grow, which will shrink, and + * make sure it's possible. + */ + if (count == 0) + return (0); + if (adj == A_SET) { + if (sp->t_maxrows == count) + return (0); + if (sp->t_maxrows > count) { + adj = A_DECREASE; + count = sp->t_maxrows - count; + } else { + adj = A_INCREASE; + count = count - sp->t_maxrows; + } + } + if (adj == A_DECREASE) { + if (count < 0) + count = -count; + s = sp; + if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) + goto toosmall; + if ((g = sp->q.cqe_prev) == (void *)&sp->gp->dq) { + if ((g = sp->q.cqe_next) == (void *)&sp->gp->dq) + goto toobig; + g->woff -= count; + } else + s->woff += count; + } else { + g = sp; + if ((s = sp->q.cqe_next) != (void *)&sp->gp->dq) + if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) + s = NULL; + else + s->woff += count; + else + s = NULL; + if (s == NULL) { + if ((s = sp->q.cqe_prev) == (void *)&sp->gp->dq) { +toobig: msgq(sp, M_BERR, "The screen cannot %s", + adj == A_DECREASE ? "shrink" : "grow"); + return (1); + } + if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) { +toosmall: msgq(sp, M_BERR, + "The screen can only shrink to %d rows", + MINIMUM_SCREEN_ROWS); + return (1); + } + g->woff -= count; + } + } + + /* + * Update the screens; we could optimize the reformatting of the + * screen, but this isn't likely to be a common enough operation + * to make it worthwhile. + */ + g->rows += count; + g->t_rows += count; + if (g->t_minrows == g->t_maxrows) + g->t_minrows += count; + g->t_maxrows += count; + _TMAP(g) += count; + (void)msg_status(g, g->ep, g->lno, 0); + F_SET(g, S_REFORMAT); + + s->rows -= count; + s->t_rows -= count; + s->t_maxrows -= count; + if (s->t_minrows > s->t_maxrows) + s->t_minrows = s->t_maxrows; + _TMAP(s) -= count; + (void)msg_status(s, s->ep, s->lno, 0); + F_SET(s, S_REFORMAT); + + return (0); +} diff --git a/usr.bin/vi/svi/svi_term.c b/usr.bin/vi/svi/svi_term.c new file mode 100644 index 0000000..baedfa7 --- /dev/null +++ b/usr.bin/vi/svi/svi_term.c @@ -0,0 +1,310 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_term.c 8.5 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "../vi/vcmd.h" +#include "excmd.h" +#include "svi_screen.h" + +/* + * XXX + * THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE. + */ +typedef struct _tklist { + char *ts; /* Key's termcap string. */ + char *output; /* Corresponding vi command. */ + char *name; /* Name. */ + u_char value; /* Special value (for lookup). */ +} TKLIST; +static TKLIST const c_tklist[] = { /* Command mappings. */ +#ifdef SYSV_CURSES + {"kil1", "O", "insert line"}, + {"kdch1", "x", "delete character"}, + {"kcud1", "j", "cursor down"}, + {"kel", "D", "delete to eol"}, + {"kind", "\004", "scroll down"}, + {"kll", "$", "go to eol"}, + {"khome", "^", "go to sol"}, + {"kich1", "i", "insert at cursor"}, + {"kdl1", "dd", "delete line"}, + {"kcub1", "h", "cursor left"}, + {"knp", "\006", "page down"}, + {"kpp", "\002", "page up"}, + {"kri", "\025", "scroll up"}, + {"ked", "dG", "delete to end of screen"}, + {"kcuf1", "l", "cursor right"}, + {"kcuu1", "k", "cursor up"}, +#else + {"kA", "O", "insert line"}, + {"kD", "x", "delete character"}, + {"kd", "j", "cursor down"}, + {"kE", "D", "delete to eol"}, + {"kF", "\004", "scroll down"}, + {"kH", "$", "go to eol"}, + {"kh", "^", "go to sol"}, + {"kI", "i", "insert at cursor"}, + {"kL", "dd", "delete line"}, + {"kl", "h", "cursor left"}, + {"kN", "\006", "page down"}, + {"kP", "\002", "page up"}, + {"kR", "\025", "scroll up"}, + {"kS", "dG", "delete to end of screen"}, + {"kr", "l", "cursor right"}, + {"ku", "k", "cursor up"}, +#endif + {NULL}, +}; +static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */ + {NULL}, +}; +static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */ +#ifdef SYSV_CURSES + {"kcud1", "\033ja", "cursor down"}, + {"kcub1", "\033ha", "cursor left"}, + {"kcuu1", "\033ka", "cursor up"}, + {"kcuf1", "\033la", "cursor right"}, +#else + {"kd", "\033ja", "cursor down"}, + {"kl", "\033ha", "cursor left"}, + {"ku", "\033ka", "cursor up"}, + {"kr", "\033la", "cursor right"}, +#endif + {NULL}, +}; + +/* + * svi_term_init -- + * Initialize the special keys defined by the termcap/terminfo entry. + */ +int +svi_term_init(sp) + SCR *sp; +{ + KEYLIST *kp; + SEQ *qp; + TKLIST const *tkp; + size_t len; + char *sbp, *s, *t, sbuf[1024]; + + /* Command mappings. */ + for (tkp = c_tklist; tkp->name != NULL; ++tkp) { +#ifdef SYSV_CURSES + if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) + continue; +#else + sbp = sbuf; + if ((t = tgetstr(tkp->ts, &sbp)) == NULL) + continue; +#endif + if (seq_set(sp, tkp->name, strlen(tkp->name), t, strlen(t), + tkp->output, strlen(tkp->output), SEQ_COMMAND, SEQ_SCREEN)) + return (1); + } + + /* Input mappings needing to be looked up. */ + for (tkp = m1_tklist; tkp->name != NULL; ++tkp) { +#ifdef SYSV_CURSES + if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) + continue; +#else + sbp = sbuf; + if ((t = tgetstr(tkp->ts, &sbp)) == NULL) + continue; +#endif + for (kp = keylist;; ++kp) + if (kp->value == tkp->value) + break; + if (kp == NULL) + continue; + if (seq_set(sp, tkp->name, strlen(tkp->name), + t, strlen(t), &kp->ch, 1, SEQ_INPUT, SEQ_SCREEN)) + return (1); + } + + /* Input mappings that are already set or are text deletions. */ + for (tkp = m2_tklist; tkp->name != NULL; ++tkp) { +#ifdef SYSV_CURSES + if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) + continue; +#else + sbp = sbuf; + if ((t = tgetstr(tkp->ts, &sbp)) == NULL) + continue; +#endif + /* + * !!! + * Some terminals' <cursor_left> keys send single <backspace> + * characters. This is okay in command mapping, but not okay + * in input mapping. That combination is the only one we'll + * ever see, hopefully, so kluge it here for now. + */ + if (!strcmp(t, "\b")) + continue; + if (tkp->output == NULL) { + if (seq_set(sp, tkp->name, strlen(tkp->name), + t, strlen(t), NULL, 0, SEQ_INPUT, SEQ_SCREEN)) + return (1); + } else + if (seq_set(sp, tkp->name, strlen(tkp->name), + t, strlen(t), tkp->output, strlen(tkp->output), + SEQ_INPUT, SEQ_SCREEN)) + return (1); + } + + /* Rework any function key mappings. */ + for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) { + if (!F_ISSET(qp, SEQ_FUNCMAP)) + continue; + (void)svi_fmap(sp, qp->stype, + qp->input, qp->ilen, qp->output, qp->olen); + } + + /* Set up the visual bell information. */ + t = sbuf; + if (tgetstr("vb", &t) != NULL && (len = t - sbuf) != 0) { + MALLOC_RET(sp, s, char *, len); + memmove(s, sbuf, len); + if (SVP(sp)->VB != NULL) + free(SVP(sp)->VB); + SVP(sp)->VB = s; + return (0); + } + + return (0); +} + +/* + * svi_term_end -- + * End the special keys defined by the termcap/terminfo entry. + */ +int +svi_term_end(sp) + SCR *sp; +{ + SEQ *qp, *nqp; + + /* Delete screen specific mappings. */ + for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = nqp) { + nqp = qp->q.le_next; + if (!F_ISSET(qp, SEQ_SCREEN)) + continue; + (void)seq_mdel(qp); + } + return (0); +} + +/* + * svi_fmap -- + * Map a function key. + */ +int +svi_fmap(sp, stype, from, flen, to, tlen) + SCR *sp; + enum seqtype stype; + CHAR_T *from, *to; + size_t flen, tlen; +{ + char *t, keyname[64]; + size_t nlen; + + /* If the terminal isn't initialized, there's nothing to do. */ + if (!F_ISSET(SVP(sp), SVI_CURSES_INIT)) + return (0); + +#ifdef SYSV_CURSES + (void)snprintf(keyname, sizeof(keyname), "kf%d", atoi(from + 1)); + if ((t = tigetstr(keyname)) == NULL || t == (char *)-1) + t = NULL; +#else + /* + * !!! + * Historically, the 4BSD termcap code didn't support functions keys + * greater than 9. This was silently enforced -- asking for key k12 + * returned the value for k1. We try and get around this by using + * the tables specified in the terminfo(TI_ENV) man page from the 3rd + * Edition SVID. This assumes that the implementors of any System V + * compatibility code or an extended termcap used those codes. + */ + { int n; char *sbp, sbuf[1024]; + static const char codes[] = { +/* 0-10 */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';', +/* 11-19 */ '1', '2', '3', '4', '5', '6', '7', '8', '9', +/* 20-63 */ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + }; + if ((n = atoi(from + 1)) > 63) { + msgq(sp, M_ERR, + "Termcap has no code for the %s function key", + from); + return (1); + } + (void)snprintf(keyname, sizeof(keyname), + "%c%c", n <= 10 ? 'k' : 'F', codes[n]); + sbp = sbuf; + t = tgetstr(keyname, &sbp); + } +#endif + if (t == NULL) { + msgq(sp, M_ERR, "This terminal has no %s key", from); + return (1); + } + nlen = snprintf(keyname, + sizeof(keyname), "function key %d", atoi(from + 1)); + return (seq_set(sp, keyname, nlen, t, strlen(t), + to, tlen, stype, SEQ_SCREEN | SEQ_USERDEF)); +} diff --git a/usr.bin/vi/svi/svi_util.c b/usr.bin/vi/svi/svi_util.c new file mode 100644 index 0000000..5ba8b1e --- /dev/null +++ b/usr.bin/vi/svi/svi_util.c @@ -0,0 +1,347 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)svi_util.c 8.53 (Berkeley) 8/12/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <curses.h> +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "../vi/vcmd.h" +#include "excmd.h" +#include "svi_screen.h" +#include "../sex/sex_screen.h" + +/* + * svi_bell -- + * Ring the bell. + */ +void +svi_bell(sp) + SCR *sp; +{ +#ifdef SYSV_CURSES + if (O_ISSET(sp, O_FLASH)) + flash(); + else + beep(); +#else + if (O_ISSET(sp, O_FLASH) && SVP(sp)->VB != NULL) { + (void)tputs(SVP(sp)->VB, 1, vi_putchar); + (void)fflush(stdout); + } else + (void)write(STDOUT_FILENO, "\007", 1); /* '\a' */ +#endif + F_CLR(sp, S_BELLSCHED); +} + +/* + * svi_optchange -- + * Screen specific "option changed" routine. + */ +int +svi_optchange(sp, opt) + SCR *sp; + int opt; +{ + switch (opt) { + case O_TERM: + /* Toss any saved visual bell information. */ + if (SVP(sp)->VB != NULL) { + FREE(SVP(sp)->VB, strlen(SVP(sp)->VB) + 1); + SVP(sp)->VB = NULL; + } + + /* Reset the screen size. */ + if (sp->s_window(sp, 0)) + return (1); + F_SET(sp, S_RESIZE); + break; + case O_WINDOW: + if (svi_crel(sp, O_VAL(sp, O_WINDOW))) + return (1); + break; + } + + (void)v_optchange(sp, opt); + (void)ex_optchange(sp, opt); + + return (0); +} + +/* + * svi_busy -- + * Put the cursor somewhere so the user will think we're busy. + */ +int +svi_busy(sp, msg) + SCR *sp; + char const *msg; +{ + /* + * search.c:f_search() is called from ex/ex_tag.c:ex_tagfirst(), + * which runs before the screen really exists. Make sure we don't + * step on anything. + * + * If the terminal isn't initialized, there's nothing to do. + */ + if (!F_ISSET(SVP(sp), SVI_CURSES_INIT)) + return (0); + + MOVE(sp, INFOLINE(sp), 0); + if (msg) { + ADDSTR(msg); + clrtoeol(); + } + refresh(); + F_SET(SVP(sp), SVI_CUR_INVALID); + return (0); +} + +/* + * svi_keypad -- + * Put the keypad/cursor arrows into or out of application mode. + */ +void +svi_keypad(sp, on) + SCR *sp; + int on; +{ +#ifdef SYSV_CURSES + keypad(stdscr, on ? TRUE : FALSE); +#else + char *sbp, *t, sbuf[128]; + + sbp = sbuf; + if ((t = tgetstr(on ? "ks" : "ke", &sbp)) == NULL) + return; + (void)tputs(t, 0, vi_putchar); + (void)fflush(stdout); +#endif +} + +/* + * svi_clear -- + * Clear from the row down to the end of the screen. + */ +int +svi_clear(sp) + SCR *sp; +{ + size_t oldy, oldx, row; + + getyx(stdscr, oldy, oldx); + for (row = SVP(sp)->srows - 1; row >= oldy; --row) { + MOVEA(sp, row, 0); + clrtoeol(); + } + MOVEA(sp, oldy, oldx); + refresh(); + return (0); +} + +/* + * svi_suspend -- + * Suspend an svi screen. + * + * See signal.c for a long discussion of what's going on here. Let + * me put it this way, it's NOT my fault. + */ +int +svi_suspend(sp) + SCR *sp; +{ + struct termios sv_term; + sigset_t set; + int oldx, oldy, rval; + char *sbp, *t, sbuf[128]; + + rval = 0; + + /* + * Block SIGALRM, because vi uses timers to decide when to paint + * busy messages on the screen. + */ + (void)sigemptyset(&set); + (void)sigaddset(&set, SIGALRM); + if (sigprocmask(SIG_BLOCK, &set, NULL)) { + msgq(sp, M_SYSERR, "suspend: sigblock"); + return (1); + } + + /* Save the current cursor position. */ + getyx(stdscr, oldy, oldx); + + /* + * Move the cursor to the bottom of the screen. + * + * XXX + * Some curses implementations don't turn off inverse video when + * standend() is called, waiting to see what the next character is + * going to be, instead. Write a character to force inverse video + * off, and then clear the line. + */ + MOVE(sp, INFOLINE(sp), 0); + ADDCH('.'); + refresh(); + MOVE(sp, INFOLINE(sp), 0); + clrtoeol(); + refresh(); + + /* Restore the cursor keys to normal mode. */ + svi_keypad(sp, 0); + + /* Send VE/TE. */ +#ifdef SYSV_CURSES + if ((t = tigetstr("cnorm")) != NULL && t != (char *)-1) + (void)tputs(t, 0, vi_putchar); + if ((t = tigetstr("rmcup")) != NULL && t != (char *)-1) + (void)tputs(t, 0, vi_putchar); +#else + sbp = sbuf; + if ((t = tgetstr("ve", &sbp)) != NULL) + (void)tputs(t, 0, vi_putchar); + sbp = sbuf; + if ((t = tgetstr("te", &sbp)) != NULL) + (void)tputs(t, 0, vi_putchar); +#endif + (void)fflush(stdout); + + /* Save current terminal settings, and restore the original ones. */ + if (tcgetattr(STDIN_FILENO, &sv_term)) { + msgq(sp, M_SYSERR, "suspend: tcgetattr"); + return (1); + } + if (tcsetattr(STDIN_FILENO, + TCSASOFT | TCSADRAIN, &sp->gp->original_termios)) { + msgq(sp, M_SYSERR, "suspend: tcsetattr original"); + return (1); + } + + /* Push out any waiting messages. */ + (void)write(STDOUT_FILENO, "\n", 1); + (void)sex_refresh(sp, sp->ep); + + /* Stop the process group. */ + if (kill(0, SIGTSTP)) { + msgq(sp, M_SYSERR, "suspend: kill"); + rval = 1; + } + + /* Time passes ... */ + + /* Restore current terminal settings. */ + if (tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &sv_term)) { + msgq(sp, M_SYSERR, "suspend: tcsetattr current"); + rval = 1; + } + + /* Send TI/VS. */ +#ifdef SYSV_CURSES + if ((t = tigetstr("smcup")) != NULL && t != (char *)-1) + (void)tputs(t, 0, vi_putchar); + if ((t = tigetstr("cvvis")) != NULL && t != (char *)-1) + (void)tputs(t, 0, vi_putchar); +#else + sbp = sbuf; + if ((t = tgetstr("ti", &sbp)) != NULL) + (void)tputs(t, 0, vi_putchar); + sbp = sbuf; + if ((t = tgetstr("vs", &sbp)) != NULL) + (void)tputs(t, 0, vi_putchar); +#endif + (void)fflush(stdout); + + /* Put the cursor keys into application mode. */ + svi_keypad(sp, 1); + + /* + * If the screen changed size, do a full refresh. Otherwise, + * System V has curses repaint it. 4BSD curses will repaint + * it in the wrefresh() call below. + */ + if (!sp->s_window(sp, 1)) + (void)sp->s_refresh(sp, sp->ep); +#ifdef SYSV_CURSES + else + redrawwin(stdscr); +#endif + + /* + * Restore the cursor. + * + * !!! + * Don't use MOVE/MOVEA, we don't want to return without resetting + * the signals, regardless. + */ + (void)move(oldy, oldx); + (void)wrefresh(curscr); + + /* Reset the signals. */ + if (sigprocmask(SIG_UNBLOCK, &set, NULL)) { + msgq(sp, M_SYSERR, "suspend: sigblock"); + rval = 1; + } + return (rval); +} + +/* + * svi_gdbrefresh -- + * Stub routine so can flush out screen changes using gdb. + */ +#ifdef DEBUG +int +svi_gdbrefresh() +{ + refresh(); + return (0); +} +#endif diff --git a/usr.bin/vi/vi/getc.c b/usr.bin/vi/vi/getc.c new file mode 100644 index 0000000..14c8423 --- /dev/null +++ b/usr.bin/vi/vi/getc.c @@ -0,0 +1,268 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)getc.c 8.9 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * Character stream routines -- + * These routines return the file a character at a time. There are two + * special cases. First, the end of a line, end of a file, start of a + * file and empty lines are returned as special cases, and no character + * is returned. Second, empty lines include lines that have only white + * space in them, because the vi search functions don't care about white + * space, and this makes it easier for them to be consistent. + */ + +/* + * cs_init -- + * Initialize character stream routines. + */ +int +cs_init(sp, ep, csp) + SCR *sp; + EXF *ep; + VCS *csp; +{ + recno_t lno; + + if ((csp->cs_bp = + file_gline(sp, ep, csp->cs_lno, &csp->cs_len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) + msgq(sp, M_BERR, "Empty file"); + else + GETLINE_ERR(sp, csp->cs_lno); + return (1); + } + if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) { + csp->cs_cno = 0; + csp->cs_flags = CS_EMP; + } else { + csp->cs_flags = 0; + csp->cs_ch = csp->cs_bp[csp->cs_cno]; + } + return (0); +} + +/* + * cs_next -- + * Retrieve the next character. + */ +int +cs_next(sp, ep, csp) + SCR *sp; + EXF *ep; + VCS *csp; +{ + recno_t slno; + + switch (csp->cs_flags) { + case CS_EMP: /* EMP; get next line. */ + case CS_EOL: /* EOL; get next line. */ + slno = csp->cs_lno; /* Save current line. */ + if ((csp->cs_bp = + file_gline(sp, ep, ++csp->cs_lno, &csp->cs_len)) == NULL) { + csp->cs_lno = slno; + if (file_lline(sp, ep, &slno)) + return (1); + if (slno > csp->cs_lno) { + GETLINE_ERR(sp, csp->cs_lno); + return (1); + } + csp->cs_flags = CS_EOF; + } else if (csp->cs_len == 0 || + v_isempty(csp->cs_bp, csp->cs_len)) { + csp->cs_cno = 0; + csp->cs_flags = CS_EMP; + } else { + csp->cs_flags = 0; + csp->cs_ch = csp->cs_bp[csp->cs_cno = 0]; + } + break; + case 0: + if (csp->cs_cno == csp->cs_len - 1) + csp->cs_flags = CS_EOL; + else + csp->cs_ch = csp->cs_bp[++csp->cs_cno]; + break; + case CS_EOF: /* EOF. */ + break; + default: + abort(); + /* NOTREACHED */ + } + return (0); +} + +/* + * cs_fspace -- + * If on a space, eat forward until something other than a + * whitespace character. + * + * XXX + * Semantics of checking the current character were coded for the fword() + * function -- once the other word routines are converted, they may have + * to change. + */ +int +cs_fspace(sp, ep, csp) + SCR *sp; + EXF *ep; + VCS *csp; +{ + if (csp->cs_flags != 0 || !isblank(csp->cs_ch)) + return (0); + for (;;) { + if (cs_next(sp, ep, csp)) + return (1); + if (csp->cs_flags != 0 || !isblank(csp->cs_ch)) + break; + } + return (0); +} + +/* + * cs_fblank -- + * Eat forward to the next non-whitespace character. + */ +int +cs_fblank(sp, ep, csp) + SCR *sp; + EXF *ep; + VCS *csp; +{ + for (;;) { + if (cs_next(sp, ep, csp)) + return (1); + if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP || + csp->cs_flags == 0 && isblank(csp->cs_ch)) + continue; + break; + } + return (0); +} + +/* + * cs_prev -- + * Retrieve the previous character. + */ +int +cs_prev(sp, ep, csp) + SCR *sp; + EXF *ep; + VCS *csp; +{ + recno_t slno; + + switch (csp->cs_flags) { + case CS_EMP: /* EMP; get previous line. */ + case CS_EOL: /* EOL; get previous line. */ + if (csp->cs_lno == 1) { /* SOF. */ + csp->cs_flags = CS_SOF; + break; + } + slno = csp->cs_lno; /* Save current line. */ + if ((csp->cs_bp = /* Line should exist. */ + file_gline(sp, ep, --csp->cs_lno, &csp->cs_len)) == NULL) { + GETLINE_ERR(sp, csp->cs_lno); + csp->cs_lno = slno; + return (1); + } + if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) { + csp->cs_cno = 0; + csp->cs_flags = CS_EMP; + } else { + csp->cs_flags = 0; + csp->cs_cno = csp->cs_len - 1; + csp->cs_ch = csp->cs_bp[csp->cs_cno]; + } + break; + case 0: + if (csp->cs_cno == 0) + if (csp->cs_lno == 1) + csp->cs_flags = CS_SOF; + else + csp->cs_flags = CS_EOL; + else + csp->cs_ch = csp->cs_bp[--csp->cs_cno]; + break; + case CS_SOF: /* SOF. */ + break; + default: + abort(); + /* NOTREACHED */ + } + return (0); +} + +/* + * cs_bblank -- + * Eat backward to the next non-whitespace character. + */ +int +cs_bblank(sp, ep, csp) + SCR *sp; + EXF *ep; + VCS *csp; +{ + for (;;) { + if (cs_prev(sp, ep, csp)) + return (1); + if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP || + csp->cs_flags == 0 && isblank(csp->cs_ch)) + continue; + break; + } + return (0); +} diff --git a/usr.bin/vi/vi/v_ch.c b/usr.bin/vi/vi/v_ch.c new file mode 100644 index 0000000..1e59460 --- /dev/null +++ b/usr.bin/vi/vi/v_ch.c @@ -0,0 +1,340 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_ch.c 8.13 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +static void notfound __P((SCR *, ARG_CHAR_T)); +static void noprev __P((SCR *)); + +/* + * v_chrepeat -- [count]; + * Repeat the last F, f, T or t search. + */ +int +v_chrepeat(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + vp->character = VIP(sp)->lastckey; + + switch (VIP(sp)->csearchdir) { + case CNOTSET: + noprev(sp); + return (1); + case FSEARCH: + return (v_chF(sp, ep, vp)); + case fSEARCH: + return (v_chf(sp, ep, vp)); + case TSEARCH: + return (v_chT(sp, ep, vp)); + case tSEARCH: + return (v_cht(sp, ep, vp)); + default: + abort(); + } + /* NOTREACHED */ +} + +/* + * v_chrrepeat -- [count], + * Repeat the last F, f, T or t search in the reverse direction. + */ +int +v_chrrepeat(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + enum cdirection savedir; + int rval; + + vp->character = VIP(sp)->lastckey; + savedir = VIP(sp)->csearchdir; + + switch (VIP(sp)->csearchdir) { + case CNOTSET: + noprev(sp); + return (1); + case FSEARCH: + rval = v_chf(sp, ep, vp); + break; + case fSEARCH: + rval = v_chF(sp, ep, vp); + break; + case TSEARCH: + rval = v_cht(sp, ep, vp); + break; + case tSEARCH: + rval = v_chT(sp, ep, vp); + break; + default: + abort(); + } + VIP(sp)->csearchdir = savedir; + return (rval); +} + +/* + * v_cht -- [count]tc + * Search forward in the line for the character before the next + * occurrence of the specified character. + */ +int +v_cht(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + if (v_chf(sp, ep, vp)) + return (1); + + /* + * v_chf places the cursor on the character, where the 't' + * command wants it to its left. We know this is safe since + * we had to move right for v_chf() to have succeeded. + */ + --vp->m_stop.cno; + + /* + * Make any necessary correction to the motion decision made + * by the v_chf routine. + */ + if (!ISMOTION(vp)) + vp->m_final = vp->m_stop; + + VIP(sp)->csearchdir = tSEARCH; + return (0); +} + +/* + * v_chf -- [count]fc + * Search forward in the line for the next occurrence of the + * specified character. + */ +int +v_chf(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + size_t len; + recno_t lno; + u_long cnt; + int key; + char *endp, *p, *startp; + + /* + * !!! + * If it's a dot command, it doesn't reset the key for which we're + * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'. + */ + key = vp->character; + if (!F_ISSET(vp, VC_ISDOT)) + VIP(sp)->lastckey = key; + VIP(sp)->csearchdir = fSEARCH; + + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) { + notfound(sp, key); + return (1); + } + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + + if (len == 0) { + notfound(sp, key); + return (1); + } + + endp = (startp = p) + len; + p += vp->m_start.cno; + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + while (++p < endp && *p != key); + if (p == endp) { + notfound(sp, key); + return (1); + } + } + + vp->m_stop.cno = p - startp; + + /* + * Non-motion commands move to the end of the range. VC_D + * and VC_Y stay at the start. Ignore VC_C and VC_DEF. + */ + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_chT -- [count]Tc + * Search backward in the line for the character after the next + * occurrence of the specified character. + */ +int +v_chT(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + if (v_chF(sp, ep, vp)) + return (1); + + /* + * v_chF places the cursor on the character, where the 'T' + * command wants it to its right. We know this is safe since + * we had to move left for v_chF() to have succeeded. + */ + ++vp->m_stop.cno; + + /* + * Make any necessary correction to the motion decision made + * by the v_chF routine. + * + * XXX + * If you change this, notice that v_chF changes vp->m_start + * AFTER setting vp->m_final. + */ + if (!F_ISSET(vp, VC_Y)) + vp->m_final = vp->m_stop; + + VIP(sp)->csearchdir = TSEARCH; + return (0); +} + +/* + * v_chF -- [count]Fc + * Search backward in the line for the next occurrence of the + * specified character. + */ +int +v_chF(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + size_t len; + u_long cnt; + int key; + char *endp, *p; + + /* + * !!! + * If it's a dot command, it doesn't reset the key for which + * we're searching, e.g. in "df1|f2|.|;", the ';' searches + * for a '2'. + */ + key = vp->character; + if (!F_ISSET(vp, VC_ISDOT)) + VIP(sp)->lastckey = key; + VIP(sp)->csearchdir = FSEARCH; + + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) { + notfound(sp, key); + return (1); + } + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + + if (len == 0) { + notfound(sp, key); + return (1); + } + + endp = p - 1; + p += vp->m_start.cno; + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + while (--p > endp && *p != key); + if (p == endp) { + notfound(sp, key); + return (1); + } + } + + vp->m_stop.cno = (p - endp) - 1; + + /* + * VC_D and non-motion commands move to the end of the range, + * VC_Y stays at the start. Ignore VC_C and VC_DEF. Motion + * commands adjust the starting point to the character before + * the current one. + */ + vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop; + if (ISMOTION(vp)) + --vp->m_start.cno; + return (0); +} + +static void +noprev(sp) + SCR *sp; +{ + msgq(sp, M_BERR, "No previous F, f, T or t search"); +} + +static void +notfound(sp, ch) + SCR *sp; + ARG_CHAR_T ch; +{ + msgq(sp, M_BERR, "%s not found", KEY_NAME(sp, ch)); +} diff --git a/usr.bin/vi/vi/v_delete.c b/usr.bin/vi/vi/v_delete.c new file mode 100644 index 0000000..aa2af98 --- /dev/null +++ b/usr.bin/vi/vi/v_delete.c @@ -0,0 +1,160 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_delete.c 8.14 (Berkeley) 7/28/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_Delete -- [buffer][count]D + * Delete line command. + */ +int +v_Delete(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + size_t len; + + if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) + return (0); + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + + if (len == 0) + return (0); + + vp->m_stop.lno = vp->m_start.lno; + vp->m_stop.cno = len - 1; + + /* Yank the lines. */ + if (cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, CUT_NUMOPT)) + return (1); + if (delete(sp, ep, &vp->m_start, &vp->m_stop, 0)) + return (1); + + vp->m_final.lno = vp->m_start.lno; + vp->m_final.cno = vp->m_start.cno ? vp->m_start.cno - 1 : 0; + return (0); +} + +/* + * v_delete -- [buffer][count]d[count]motion + * Delete a range of text. + */ +int +v_delete(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t nlines; + size_t len; + int lmode; + + lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0; + + /* Yank the lines. */ + if (cut(sp, ep, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, + lmode | (F_ISSET(vp, VM_CUTREQ) ? CUT_NUMREQ : CUT_NUMOPT))) + return (1); + + /* Delete the lines. */ + if (delete(sp, ep, &vp->m_start, &vp->m_stop, lmode)) + return (1); + + /* + * Check for deletion of the entire file. Try to check a close + * by line so we don't go to the end of the file unnecessarily. + */ + if (file_gline(sp, ep, vp->m_final.lno + 1, &len) == NULL) { + if (file_lline(sp, ep, &nlines)) + return (1); + if (nlines == 0) { + vp->m_final.lno = 1; + vp->m_final.cno = 0; + return (0); + } + } + + /* + * One special correction, in case we've deleted the current line or + * character. We check it here instead of checking in every command + * that can be a motion component. + */ + if (file_gline(sp, ep, vp->m_final.lno, &len) == NULL) { + if (file_gline(sp, ep, nlines, &len) == NULL) { + GETLINE_ERR(sp, nlines); + return (1); + } + vp->m_final.lno = nlines; + } + if (vp->m_final.cno >= len) + vp->m_final.cno = len ? len - 1 : 0; + + /* + * !!! + * The "dd" command moved to the first non-blank; "d<motion>" didn't. + */ + if (F_ISSET(vp, VM_LDOUBLE)) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + } + return (0); +} diff --git a/usr.bin/vi/vi/v_ex.c b/usr.bin/vi/vi/v_ex.c new file mode 100644 index 0000000..6481b407 --- /dev/null +++ b/usr.bin/vi/vi/v_ex.c @@ -0,0 +1,352 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_ex.c 8.10 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "vcmd.h" + +static void excmd __P((EXCMDARG *, + int, int, recno_t, recno_t, int, ARGS *[], ARGS *, char *)); + +/* + * v_again -- & + * Repeat the previous substitution. + */ +int +v_again(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + + excmd(&cmd, C_SUBAGAIN, + 2, vp->m_start.lno, vp->m_start.lno, 1, ap, &a, ""); + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * v_at -- @ + * Execute a buffer. + */ +int +v_at(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + + excmd(&cmd, C_AT, 0, OOBLNO, OOBLNO, 0, ap, &a, NULL); + if (F_ISSET(vp, VC_BUFFER)) { + F_SET(&cmd, E_BUFFER); + cmd.buffer = vp->buffer; + } + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * v_ex -- : + * Execute a colon command line. + */ +int +v_ex(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (sp->s_ex_run(sp, ep, &vp->m_final)); +} + +/* + * v_exmode -- Q + * Switch the editor into EX mode. + */ +int +v_exmode(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* Save the current line/column number. */ + sp->frp->lno = sp->lno; + sp->frp->cno = sp->cno; + F_SET(sp->frp, FR_CURSORSET); + + /* Switch to ex mode. */ + sp->saved_vi_mode = F_ISSET(sp, S_VI_CURSES | S_VI_XAW); + F_CLR(sp, S_SCREENS); + F_SET(sp, S_EX); + return (0); +} + +/* + * v_filter -- [count]!motion command(s) + * Run range through shell commands, replacing text. + */ +int +v_filter(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + TEXT *tp; + + /* + * !!! + * Historical vi permitted "!!" in an empty file, and it's handled + * as a special case in the ex_bang routine. Don't modify this setup + * without understanding that one. In particular, note that we're + * manipulating the ex argument structures behind ex's back. + * + * !!! + * Historical vi did not permit the '!' command to be associated with + * a non-line oriented motion command, in general, although it did + * with search commands. So, !f; and !w would fail, but !/;<CR> + * would succeed, even if they all moved to the same location in the + * current line. I don't see any reason to disallow '!' using any of + * the possible motion commands. + */ + excmd(&cmd, C_BANG, + 2, vp->m_start.lno, vp->m_stop.lno, 0, ap, &a, NULL); + EXP(sp)->argsoff = 0; /* XXX */ + if (F_ISSET(vp, VC_ISDOT)) { + if (argv_exp1(sp, ep, &cmd, "!", 1, 1)) + return (1); + } else { + /* Get the command from the user. */ + if (sp->s_get(sp, ep, sp->tiqp, + '!', TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK) + return (1); + /* + * Len is 0 if backspaced over the prompt, + * 1 if only CR entered. + */ + tp = sp->tiqp->cqh_first; + if (tp->len <= 1) + return (0); + + if (argv_exp1(sp, ep, &cmd, tp->lb + 1, tp->len - 1, 1)) + return (1); + } + cmd.argc = EXP(sp)->argsoff; /* XXX */ + cmd.argv = EXP(sp)->args; /* XXX */ + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * v_join -- [count]J + * Join lines together. + */ +int +v_join(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + int lno; + + /* + * YASC. + * The general rule is that '#J' joins # lines, counting the current + * line. However, 'J' and '1J' are the same as '2J', i.e. join the + * current and next lines. This doesn't map well into the ex command + * (which takes two line numbers), so we handle it here. Note that + * we never test for EOF -- historically going past the end of file + * worked just fine. + */ + lno = vp->m_start.lno + 1; + if (F_ISSET(vp, VC_C1SET) && vp->count > 2) + lno = vp->m_start.lno + (vp->count - 1); + + excmd(&cmd, C_JOIN, 2, vp->m_start.lno, lno, 0, ap, &a, NULL); + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * v_shiftl -- [count]<motion + * Shift lines left. + */ +int +v_shiftl(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + + excmd(&cmd, C_SHIFTL, + 2, vp->m_start.lno, vp->m_stop.lno, 0, ap, &a, "<"); + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * v_shiftr -- [count]>motion + * Shift lines right. + */ +int +v_shiftr(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + + excmd(&cmd, C_SHIFTR, + 2, vp->m_start.lno, vp->m_stop.lno, 0, ap, &a, ">"); + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * v_switch -- ^^ + * Switch to the previous file. + */ +int +v_switch(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + char *name; + + /* + * Try the alternate file name, then the previous file + * name. Use the real name, not the user's current name. + */ + if ((name = sp->alt_name) == NULL) { + msgq(sp, M_ERR, "No previous file to edit"); + return (1); + } + + /* If autowrite is set, write out the file. */ + if (file_m1(sp, ep, 0, FS_ALL)) + return (1); + + excmd(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, ap, &a, name); + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * v_tagpush -- ^[ + * Do a tag search on a the cursor keyword. + */ +int +v_tagpush(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + + excmd(&cmd, C_TAG, 0, OOBLNO, 0, 0, ap, &a, vp->keyword); + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * v_tagpop -- ^T + * Pop the tags stack. + */ +int +v_tagpop(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + ARGS *ap[2], a; + EXCMDARG cmd; + + excmd(&cmd, C_TAGPOP, 0, OOBLNO, 0, 0, ap, &a, NULL); + return (sp->s_ex_cmd(sp, ep, &cmd, &vp->m_final)); +} + +/* + * excmd -- + * Build an EX command structure. + */ +static void +excmd(cmdp, cmd_id, naddr, lno1, lno2, force, ap, a, arg) + EXCMDARG *cmdp; + int cmd_id, force, naddr; + recno_t lno1, lno2; + ARGS *ap[2], *a; + char *arg; +{ + memset(cmdp, 0, sizeof(EXCMDARG)); + cmdp->cmd = &cmds[cmd_id]; + cmdp->addrcnt = naddr; + cmdp->addr1.lno = lno1; + cmdp->addr2.lno = lno2; + cmdp->addr1.cno = cmdp->addr2.cno = 1; + if (force) + cmdp->flags |= E_FORCE; + if ((a->bp = arg) == NULL) { + cmdp->argc = 0; + a->len = 0; + } else { + cmdp->argc = 1; + a->len = strlen(arg); + } + ap[0] = a; + ap[1] = NULL; + cmdp->argv = ap; +} diff --git a/usr.bin/vi/vi/v_increment.c b/usr.bin/vi/vi/v_increment.c new file mode 100644 index 0000000..6961953 --- /dev/null +++ b/usr.bin/vi/vi/v_increment.c @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_increment.c 8.9 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +static char * const fmt[] = { +#define DEC 0 + "%ld", +#define SDEC 1 + "%+ld", +#define HEXC 2 + "%#0.*lX", +#define HEXL 3 + "%#0.*lx", +#define OCTAL 4 + "%#0.*lo", +}; + +/* + * v_increment -- [count]#[#+-] + * Increment/decrement a keyword number. + */ +int +v_increment(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + VI_PRIVATE *vip; + u_long ulval; + long lval; + size_t blen, len, nlen; + int rval; + char *bp, *ntype, *p, nbuf[100]; + + vip = VIP(sp); + + /* Do repeat operations. */ + if (vp->character == '#') + vp->character = vip->inc_lastch; + + /* Get new value. */ + if (F_ISSET(vp, VC_C1SET)) + vip->inc_lastval = vp->count; + + if (vp->character != '+' && vp->character != '-') { + msgq(sp, M_ERR, "usage: %s", vp->kp->usage); + return (1); + } + vip->inc_lastch = vp->character; + + /* Figure out the resulting type and number. */ + p = vp->keyword; + len = vp->klen; + if (len > 1 && p[0] == '0') { + if (vp->character == '+') { + ulval = strtoul(vp->keyword, NULL, 0); + if (ULONG_MAX - ulval < vip->inc_lastval) + goto overflow; + ulval += vip->inc_lastval; + } else { + ulval = strtoul(vp->keyword, NULL, 0); + if (ulval < vip->inc_lastval) + goto underflow; + ulval -= vip->inc_lastval; + } + ntype = fmt[OCTAL]; + if (len > 2) + if (p[1] == 'X') + ntype = fmt[HEXC]; + else if (p[1] == 'x') + ntype = fmt[HEXL]; + nlen = snprintf(nbuf, sizeof(nbuf), ntype, len, ulval); + } else { + if (vp->character == '+') { + lval = strtol(vp->keyword, NULL, 0); + if (lval > 0 && LONG_MAX - lval < vip->inc_lastval) { +overflow: msgq(sp, M_ERR, "Resulting number too large"); + return (1); + } + lval += vip->inc_lastval; + } else { + lval = strtol(vp->keyword, NULL, 0); + if (lval < 0 && -(LONG_MIN - lval) < vip->inc_lastval) { +underflow: msgq(sp, M_ERR, "Resulting number too small"); + return (1); + } + lval -= vip->inc_lastval; + } + ntype = lval != 0 && + (*vp->keyword == '+' || *vp->keyword == '-') ? + fmt[SDEC] : fmt[DEC]; + nlen = snprintf(nbuf, sizeof(nbuf), ntype, lval); + } + + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + + GET_SPACE_RET(sp, bp, blen, len + nlen); + memmove(bp, p, vp->m_start.cno); + memmove(bp + vp->m_start.cno, nbuf, nlen); + memmove(bp + vp->m_start.cno + nlen, + p + vp->m_start.cno + vp->klen, len - vp->m_start.cno - vp->klen); + len = len - vp->klen + nlen; + + rval = file_sline(sp, ep, vp->m_start.lno, bp, len); + FREE_SPACE(sp, bp, blen); + return (rval); +} diff --git a/usr.bin/vi/vi/v_init.c b/usr.bin/vi/vi/v_init.c new file mode 100644 index 0000000..069733c --- /dev/null +++ b/usr.bin/vi/vi/v_init.c @@ -0,0 +1,256 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_init.c 8.26 (Berkeley) 8/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" +#include "excmd.h" + +static int v_comment __P((SCR *, EXF *)); + +/* + * v_screen_copy -- + * Copy vi screen. + */ +int +v_screen_copy(orig, sp) + SCR *orig, *sp; +{ + VI_PRIVATE *ovip, *nvip; + + /* Create the private vi structure. */ + CALLOC_RET(orig, nvip, VI_PRIVATE *, 1, sizeof(VI_PRIVATE)); + sp->vi_private = nvip; + + if (orig == NULL) { + nvip->inc_lastch = '+'; + nvip->inc_lastval = 1; + nvip->csearchdir = CNOTSET; + } else { + ovip = VIP(orig); + + /* User can replay the last input, but nothing else. */ + if (ovip->rep_len != 0) { + MALLOC(orig, nvip->rep, char *, ovip->rep_len); + if (nvip->rep != NULL) { + memmove(nvip->rep, ovip->rep, ovip->rep_len); + nvip->rep_len = ovip->rep_len; + } + } + + nvip->inc_lastch = ovip->inc_lastch; + nvip->inc_lastval = ovip->inc_lastval; + + if (ovip->ps != NULL && + (nvip->ps = strdup(ovip->ps)) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + + nvip->lastckey = ovip->lastckey; + nvip->csearchdir = ovip->csearchdir; + } + return (0); +} + +/* + * v_screen_end -- + * End a vi screen. + */ +int +v_screen_end(sp) + SCR *sp; +{ + VI_PRIVATE *vip; + + vip = VIP(sp); + + if (vip->rep != NULL) + free(vip->rep); + + if (vip->ps != NULL) + free(vip->ps); + + /* Free private memory. */ + FREE(vip, sizeof(VI_PRIVATE)); + sp->vi_private = NULL; + + return (0); +} + +/* + * v_init -- + * Initialize vi. + */ +int +v_init(sp, ep) + SCR *sp; + EXF *ep; +{ + size_t len; + + /* + * The default address is line 1, column 0. If the address set + * bit is on for this file, load the address, ensuring that it + * exists. + */ + if (F_ISSET(sp->frp, FR_CURSORSET)) { + sp->lno = sp->frp->lno; + sp->cno = sp->frp->cno; + + if (file_gline(sp, ep, sp->lno, &len) == NULL) { + if (sp->lno != 1 || sp->cno != 0) { + if (file_lline(sp, ep, &sp->lno)) + return (1); + if (sp->lno == 0) + sp->lno = 1; + sp->cno = 0; + } + } else if (sp->cno >= len) + sp->cno = 0; + + if (F_ISSET(sp->frp, FR_FNONBLANK)) { + sp->cno = 0; + if (nonblank(sp, ep, sp->lno, &sp->cno)) + return (1); + + /* Reset strange attraction. */ + sp->rcm = 0; + sp->rcm_last = 0; + } + } else { + sp->lno = 1; + sp->cno = 0; + + if (O_ISSET(sp, O_COMMENT) && v_comment(sp, ep)) + return (1); + + /* Vi always starts up on the first non-<blank>. */ + if (nonblank(sp, ep, sp->lno, &sp->cno)) + return (1); + + /* Reset strange attraction. */ + sp->rcm = 0; + sp->rcm_last = 0; + } + + /* Make ex display to a special function. */ + if ((sp->stdfp = fwopen(sp, sp->s_ex_write)) == NULL) { + msgq(sp, M_SYSERR, "ex output"); + return (1); + } +#ifdef MAKE_EX_OUTPUT_LINE_BUFFERED + (void)setvbuf(sp->stdfp, NULL, _IOLBF, 0); +#endif + + /* Display the status line. */ + return (msg_status(sp, ep, sp->lno, 0)); +} + +/* + * v_end -- + * End vi session. + */ +int +v_end(sp) + SCR *sp; +{ + /* Close down ex output file descriptor. */ + (void)fclose(sp->stdfp); + + return (0); +} + +/* + * v_optchange -- + * Handle change of options for vi. + */ +int +v_optchange(sp, opt) + SCR *sp; + int opt; +{ + switch (opt) { + case O_PARAGRAPHS: + case O_SECTIONS: + return (v_buildps(sp)); + } + return (0); +} + +/* + * v_comment -- + * Skip the first comment. + */ +static int +v_comment(sp, ep) + SCR *sp; + EXF *ep; +{ + recno_t lno; + size_t len; + char *p; + + for (lno = 1; + (p = file_gline(sp, ep, lno, &len)) != NULL && len == 0; ++lno); + if (p == NULL || len <= 1 || memcmp(p, "/*", 2)) + return (0); + do { + for (; len; --len, ++p) + if (p[0] == '*' && len > 1 && p[1] == '/') { + sp->lno = lno; + return (0); + } + } while ((p = file_gline(sp, ep, ++lno, &len)) != NULL); + return (0); +} diff --git a/usr.bin/vi/vi/v_left.c b/usr.bin/vi/vi/v_left.c new file mode 100644 index 0000000..ec57d91 --- /dev/null +++ b/usr.bin/vi/vi/v_left.c @@ -0,0 +1,287 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_left.c 8.9 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_left -- [count]^H, [count]h + * Move left by columns. + */ +int +v_left(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t cnt; + + /* + * !!! + * The ^H and h commands always failed in the first column. + */ + if (vp->m_start.cno == 0) { + v_sol(sp); + return (1); + } + + /* Find the end of the range. */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (vp->m_start.cno > cnt) + vp->m_stop.cno = vp->m_start.cno - cnt; + else + vp->m_stop.cno = 0; + + /* + * VC_D and non-motion commands move to the end of the range, + * VC_Y stays at the start. Ignore VC_C and VC_DEF. Motion + * commands adjust the starting point to the character before + * the current one. + */ + vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop; + if (ISMOTION(vp)) + --vp->m_start.cno; + return (0); +} + +/* + * v_cfirst -- [count]_ + * Move to the first non-blank character in a line. + */ +int +v_cfirst(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t cnt; + + /* + * !!! + * If the _ is a motion component, it makes the command a line motion + * e.g. "d_" deletes the line. It also means that the cursor doesn't + * move. + * + * The _ command never failed in the first column. + */ + if (ISMOTION(vp)) + F_SET(vp, VM_LMODE); + /* + * !!! + * Historically a specified count makes _ move down count - 1 + * rows, so, "3_" is the same as "2j_". + */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (cnt != 1) { + --vp->count; + return (v_down(sp, ep, vp)); + } + + /* + * Move to the first non-blank. + * + * Can't just use RCM_SET_FNB, in case _ is used as the motion + * component of another command. + */ + vp->m_stop.cno = 0; + if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + + /* + * VC_D and non-motion commands move to the end of the range, + * VC_Y stays at the start. Ignore VC_C and VC_DEF. + */ + vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_first -- ^ + * Move to the first non-blank character in this line. + */ +int +v_first(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * !!! + * Yielding to none in our quest for compatibility with every + * historical blemish of vi, no matter how strange it might be, + * we permit the user to enter a count and then ignore it. + */ + + /* + * Move to the first non-blank. + * + * Can't just use RCM_SET_FNB, in case ^ is used as the motion + * component of another command. + */ + vp->m_stop.cno = 0; + if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + + /* + * !!! + * The ^ command succeeded if used as a command without a whitespace + * character preceding the cursor in the line, but failed if used as + * a motion component in the same situation. + */ + if (ISMOTION(vp) && vp->m_start.cno <= vp->m_stop.cno) { + v_sol(sp); + return (1); + } + + /* + * VC_D and non-motion commands move to the end of the range, + * VC_Y stays at the start. Ignore VC_C and VC_DEF. Motion + * commands adjust the starting point to the character before + * the current one. + */ + vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop; + if (ISMOTION(vp)) + --vp->m_start.cno; + return (0); +} + +/* + * v_ncol -- [count]| + * Move to column count or the first column on this line. If the + * requested column is past EOL, move to EOL. The nasty part is + * that we have to know character column widths to make this work. + */ +int +v_ncol(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + if (F_ISSET(vp, VC_C1SET) && vp->count > 1) { + --vp->count; + vp->m_stop.cno = + sp->s_colpos(sp, ep, vp->m_start.lno, (size_t)vp->count); + /* + * !!! + * The | command succeeded if used as a command and the cursor + * didn't move, but failed if used as a motion component in the + * same situation. + */ + if (ISMOTION(vp) && vp->m_stop.cno == vp->m_start.cno) { + v_nomove(sp); + return (1); + } + } else { + /* + * !!! + * The | command succeeded if used as a command in column 0 + * without a count, but failed if used as a motion component + * in the same situation. + */ + if (ISMOTION(vp) && vp->m_start.cno == 0) { + v_sol(sp); + return (1); + } + vp->m_stop.cno = 0; + } + + /* + * If moving right, non-motion commands move to the end of the range. + * VC_D and VC_Y stay at the start. If moving left, non-motion and + * VC_D commands move to the end of the range. VC_Y remains at the + * start. Ignore VC_C and VC_DEF. Motion left commands adjust the + * starting point to the character before the current one. + */ + if (vp->m_start.cno < vp->m_stop.cno) + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + else { + vp->m_final = vp->m_stop; + if (ISMOTION(vp)) { + if (F_ISSET(vp, VC_Y)) + vp->m_final = vp->m_start; + --vp->m_start.cno; + } + } + return (0); +} + +/* + * v_zero -- 0 + * Move to the first column on this line. + */ +int +v_zero(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * !!! + * The 0 command succeeded if used as a command in the first column + * but failed if used as a motion component in the same situation. + */ + if (ISMOTION(vp) && vp->m_start.cno == 0) { + v_sol(sp); + return (1); + } + + /* + * VC_D and non-motion commands move to the end of the range, + * VC_Y stays at the start. Ignore VC_C and VC_DEF. Motion + * commands adjust the starting point to the character before + * the current one. + */ + vp->m_stop.cno = 0; + vp->m_final = F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop; + if (ISMOTION(vp)) + --vp->m_start.cno; + return (0); +} diff --git a/usr.bin/vi/vi/v_mark.c b/usr.bin/vi/vi/v_mark.c new file mode 100644 index 0000000..66dda1a --- /dev/null +++ b/usr.bin/vi/vi/v_mark.c @@ -0,0 +1,210 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_mark.c 8.8 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_mark -- m[a-z] + * Set a mark. + */ +int +v_mark(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (mark_set(sp, ep, vp->character, &vp->m_start, 1)); +} + +enum which {BMARK, FMARK}; +static int mark __P((SCR *, EXF *, VICMDARG *, enum which)); + + +/* + * v_bmark -- `['`a-z] + * Move to a mark. + * + * Moves to a mark, setting both row and column. + * + * !!! + * Although not commonly known, the "'`" and "'`" forms are historically + * valid. The behavior is determined by the first character, so "`'" is + * the same as "``". Remember this fact -- you'll be amazed at how many + * people don't know it and will be delighted that you are able to tell + * them. + */ +int +v_bmark(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (mark(sp, ep, vp, BMARK)); +} + +/* + * v_fmark -- '['`a-z] + * Move to a mark. + * + * Move to the first nonblank character of the line containing the mark. + */ +int +v_fmark(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (mark(sp, ep, vp, FMARK)); +} + +static int +mark(sp, ep, vp, cmd) + SCR *sp; + EXF *ep; + VICMDARG *vp; + enum which cmd; +{ + MARK m; + size_t len; + enum direction dir; + + if (mark_get(sp, ep, vp->character, &vp->m_stop)) + return (1); + + /* Forward marks move to the first non-blank. */ + if (cmd == FMARK) { + vp->m_stop.cno = 0; + if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + } + + /* Non-motion commands move to the end of the range. */ + if (!ISMOTION(vp)) { + vp->m_final = vp->m_stop; + return (0); + } + + /* + * !!! + * If a motion component, the cursor has to move. + */ + if (vp->m_stop.lno == vp->m_start.lno && + vp->m_stop.cno == vp->m_start.cno) { + v_nomove(sp); + return (1); + } + + /* + * If the motion is in the reverse direction, switch the start and + * stop MARK's so that it's in a forward direction. (There's no + * reason for this other than to make the tests below easier. The + * code in vi.c:vi() would have done the switch.) Both forward + * and backward motions can happen for either kind of mark command. + */ + if (vp->m_start.lno > vp->m_stop.lno || + vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno > vp->m_stop.cno) { + dir = BACKWARD; + m = vp->m_start; + vp->m_start = vp->m_stop; + vp->m_stop = m; + } else + dir = FORWARD; + + /* + * BACKWARD: + * VC_D commands move to the end of the range. VC_Y stays at + * the start unless the end of the range is on a different line, + * when it moves to the end of the range. Ignore VC_C and + * VC_DEF. + * + * FORWARD: + * VC_D and VC_Y commands don't move. Ignore VC_C and VC_DEF. + */ + if (dir == BACKWARD) + if (F_ISSET(vp, VC_D) || + F_ISSET(vp, VC_Y) && vp->m_start.lno != vp->m_stop.lno) + vp->m_final = vp->m_start; + else + vp->m_final = vp->m_stop; + else + vp->m_final = vp->m_start; + + if (cmd == FMARK) + return (0); + + /* + * Forward marks are always line oriented, and it's set in the + * vcmd.c table. Backward marks that start and stop at column + * 0 of the line are also line mode commands. + */ + if (vp->m_start.cno == 0 && vp->m_stop.cno == 0) + F_SET(vp, VM_LMODE); + + /* + * BMARK'S that move backward and start at column 0, or move forward + * and end at column 0 are corrected to the last column of the previous + * line. Else, adjust the starting/ending point to the character + * before the current one (this is safe because we know the command had + * to move to succeed). + */ + if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) { + if (file_gline(sp, ep, --vp->m_stop.lno, &len) == NULL) { + GETLINE_ERR(sp, vp->m_stop.lno); + return (1); + } + vp->m_stop.cno = len ? len - 1 : 0; + } else + --vp->m_stop.cno; + + return (0); +} diff --git a/usr.bin/vi/vi/v_match.c b/usr.bin/vi/vi/v_match.c new file mode 100644 index 0000000..b047a44 --- /dev/null +++ b/usr.bin/vi/vi/v_match.c @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_match.c 8.14 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_match -- % + * Search to matching character. + */ +int +v_match(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + VCS cs; + MARK *mp; + recno_t lno; + size_t cno, len, off; + int cnt, matchc, startc, (*gc)__P((SCR *, EXF *, VCS *)); + char *p; + + /* + * !!! + * Historic practice; ignore the count. + */ + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) + goto nomatch; + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + + /* + * !!! + * Historical practice was to search for the initial character + * in the forward direction only. + */ + for (off = vp->m_start.cno;; ++off) { + if (off >= len) { +nomatch: msgq(sp, M_BERR, "No match character on this line"); + return (1); + } + switch (startc = p[off]) { + case '(': + matchc = ')'; + gc = cs_next; + break; + case ')': + matchc = '('; + gc = cs_prev; + break; + case '[': + matchc = ']'; + gc = cs_next; + break; + case ']': + matchc = '['; + gc = cs_prev; + break; + case '{': + matchc = '}'; + gc = cs_next; + break; + case '}': + matchc = '{'; + gc = cs_prev; + break; + default: + continue; + } + break; + } + + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = off; + if (cs_init(sp, ep, &cs)) + return (1); + for (cnt = 1;;) { + if (gc(sp, ep, &cs)) + return (1); + if (cs.cs_flags != 0) { + if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) + break; + continue; + } + if (cs.cs_ch == startc) + ++cnt; + else if (cs.cs_ch == matchc && --cnt == 0) + break; + } + if (cnt) { + msgq(sp, M_BERR, "Matching character not found"); + return (1); + } + + vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * If moving right, non-motion commands move to the end of the range. + * VC_D and VC_Y stay at the start. If moving left, non-motion and + * VC_D commands move to the end of the range. VC_Y remains at the + * start. Ignore VC_C and VC_DEF. + * + * !!! + * Don't correct for leftward movement -- historic vi deleted the + * starting cursor position when deleting to a match. + */ + if (vp->m_start.lno < vp->m_stop.lno || + vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno < vp->m_stop.cno) + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + else + vp->m_final = ISMOTION(vp) && + F_ISSET(vp, VC_Y) ? vp->m_start : vp->m_stop; + + /* + * !!! + * If the motion is across lines, and the earliest cursor position + * is at or before any non-blank characters in the line, i.e. the + * movement is cutting all of the line's text, and the later cursor + * position has nothing other than whitespace characters between it + * and the end of its line, the buffer is in line mode. + */ + if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno) + return (0); + mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop; + if (mp->cno != 0) { + cno = 0; + if (nonblank(sp, ep, mp->lno, &cno)) + return (1); + if (cno < mp->cno) + return (0); + } + mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start; + if ((p = file_gline(sp, ep, mp->lno, &len)) == NULL) { + GETLINE_ERR(sp, mp->lno); + return (1); + } + for (p += mp->cno + 1, len -= mp->cno; --len; ++p) + if (!isblank(*p)) + return (0); + F_SET(vp, VM_LMODE); + return (0); +} diff --git a/usr.bin/vi/vi/v_ntext.c b/usr.bin/vi/vi/v_ntext.c new file mode 100644 index 0000000..5dcba3b --- /dev/null +++ b/usr.bin/vi/vi/v_ntext.c @@ -0,0 +1,1899 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_ntext.c 8.120 (Berkeley) 8/15/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" +#include "excmd.h" + +static int txt_abbrev __P((SCR *, TEXT *, CHAR_T *, int, int *, int *)); +static void txt_ai_resolve __P((SCR *, TEXT *)); +static TEXT *txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int *)); +static void txt_err __P((SCR *, EXF *, TEXTH *)); +static int txt_hex __P((SCR *, TEXT *)); +static int txt_indent __P((SCR *, TEXT *)); +static int txt_margin __P((SCR *, + TEXT *, CHAR_T *, TEXT *, u_int, int *)); +static int txt_outdent __P((SCR *, TEXT *)); +static void txt_Rcleanup __P((SCR *, + TEXTH *, TEXT *, const char *, const size_t)); +static int txt_resolve __P((SCR *, EXF *, TEXTH *, u_int)); +static void txt_showmatch __P((SCR *, EXF *)); +static void txt_unmap __P((SCR *, TEXT *, u_int *)); + +/* Cursor character (space is hard to track on the screen). */ +#if defined(DEBUG) && 0 +#undef CH_CURSOR +#define CH_CURSOR '+' +#endif + +/* + * v_ntext -- + * Read in text from the user. + * + * !!! + * Historic vi did a special screen optimization for tab characters. For + * the keystrokes "iabcd<esc>0C<tab>", the tab would overwrite the rest of + * the string when it was displayed. Because this implementation redisplays + * the entire line on each keystroke, the "bcd" gets pushed to the right as + * we ignore that the user has "promised" to change the rest of the characters. + * Users have noticed, but this isn't worth fixing, and, the way that the + * historic vi did it results in an even worse bug. Given the keystrokes + * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears + * on the second <esc> key. + */ +int +v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags) + SCR *sp; + EXF *ep; + TEXTH *tiqh; + MARK *tm; /* To MARK. */ + const char *lp; /* Input line. */ + const size_t len; /* Input line length. */ + MARK *rp; /* Return MARK. */ + ARG_CHAR_T prompt; /* Prompt to display. */ + recno_t ai_line; /* Line number to use for autoindent count. */ + u_int flags; /* TXT_ flags. */ +{ + /* State of abbreviation checks. */ + enum { A_NOTSET, A_NOTWORD, A_INWORD } abb; + /* State of the "[^0]^D" sequences. */ + enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st; + /* State of the hex input character. */ + enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex; + /* State of quotation. */ + enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted; + enum input tval; + struct termios t; /* Terminal characteristics. */ + CH ikey; /* Input character structure. */ + CHAR_T ch; /* Input character. */ + TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */ + TEXT wmt; /* Wrapmargin text structure. */ + size_t owrite, insert; /* Temporary copies of TEXT fields. */ + size_t rcol; /* 0-N: insert offset in the replay buffer. */ + size_t col; /* Current column. */ + u_long margin; /* Wrapmargin value. */ + u_int iflags; /* Input flags. */ + int ab_cnt, ab_turnoff; /* Abbreviation count, if turned off. */ + int eval; /* Routine return value. */ + int replay; /* If replaying a set of input. */ + int showmatch; /* Showmatch set on this character. */ + int sig_ix, sig_reset; /* Signal information. */ + int testnr; /* Test first character for nul replay. */ + int max, tmp; + int unmap_tst; /* Input map needs testing. */ + int wmset, wmskip; /* Wrapmargin happened, blank skip flags. */ + char *p; + + /* + * Set the input flag, so tabs get displayed correctly + * and everyone knows that the text buffer is in use. + */ + F_SET(sp, S_INPUT); + + /* Local initialization. */ + eval = 0; + + /* + * Get one TEXT structure with some initial buffer space, reusing + * the last one if it's big enough. (All TEXT bookkeeping fields + * default to 0 -- text_init() handles this.) If changing a line, + * copy it into the TEXT buffer. + */ + if (tiqh->cqh_first != (void *)tiqh) { + tp = tiqh->cqh_first; + if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) { + text_lfree(tiqh); + goto newtp; + } + tp->ai = tp->insert = tp->offset = tp->owrite = 0; + if (lp != NULL) { + tp->len = len; + memmove(tp->lb, lp, len); + } else + tp->len = 0; + } else { +newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL) + return (1); + CIRCLEQ_INSERT_HEAD(tiqh, tp, q); + } + + /* Set the starting line number. */ + tp->lno = sp->lno; + + /* + * Set the insert and overwrite counts. If overwriting characters, + * do insertion afterward. If not overwriting characters, assume + * doing insertion. If change is to a mark, emphasize it with an + * CH_ENDMARK + */ + if (len) { + if (LF_ISSET(TXT_OVERWRITE)) { + tp->owrite = (tm->cno - sp->cno) + 1; + tp->insert = (len - tm->cno) - 1; + } else + tp->insert = len - sp->cno; + + if (LF_ISSET(TXT_EMARK)) + tp->lb[tm->cno] = CH_ENDMARK; + } + + /* + * Many of the special cases in this routine are to handle autoindent + * support. Somebody decided that it would be a good idea if "^^D" + * and "0^D" deleted all of the autoindented characters. In an editor + * that takes single character input from the user, this beggars the + * imagination. Note also, "^^D" resets the next lines' autoindent, + * but "0^D" doesn't. + * + * We assume that autoindent only happens on empty lines, so insert + * and overwrite will be zero. If doing autoindent, figure out how + * much indentation we need and fill it in. Update input column and + * screen cursor as necessary. + */ + if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) { + if (txt_auto(sp, ep, ai_line, NULL, 0, tp)) + return (1); + sp->cno = tp->ai; + } else { + /* + * The cc and S commands have a special feature -- leading + * <blank> characters are handled as autoindent characters. + * Beauty! + */ + if (LF_ISSET(TXT_AICHARS)) { + tp->offset = 0; + tp->ai = sp->cno; + } else + tp->offset = sp->cno; + } + + /* If getting a command buffer from the user, there may be a prompt. */ + if (LF_ISSET(TXT_PROMPT)) { + tp->lb[sp->cno++] = prompt; + ++tp->len; + ++tp->offset; + } + + /* + * If appending after the end-of-line, add a space into the buffer + * and move the cursor right. This space is inserted, i.e. pushed + * along, and then deleted when the line is resolved. Assumes that + * the cursor is already positioned at the end of the line. This + * avoids the nastiness of having the cursor reside on a magical + * column, i.e. a column that doesn't really exist. The only down + * side is that we may wrap lines or scroll the screen before it's + * strictly necessary. Not a big deal. + */ + if (LF_ISSET(TXT_APPENDEOL)) { + tp->lb[sp->cno] = CH_CURSOR; + ++tp->len; + ++tp->insert; + } + + /* + * Historic practice is that the wrapmargin value was a distance + * from the RIGHT-HAND column, not the left. It's more useful to + * us as a distance from the left-hand column. + * + * !!!/XXX + * Replay commands were not affected by the wrapmargin option in the + * historic 4BSD vi. What I found surprising was that people depend + * on it, as in this gem of a macro which centers lines: + * + * map #c $mq81a ^V^[81^V|D`qld0:s/ / /g^V^M$p + * + * Other historic versions of vi, notably Sun's, applied wrapmargin + * to replay lines as well. + * + * XXX + * Setting margin causes a significant performance hit. Normally + * we don't update the screen if there are keys waiting, but we + * have to if margin is set, otherwise the screen routines don't + * know where the cursor is. + * + * !!! + * One more special case. If an inserted <blank> character causes + * wrapmargin to split the line, the next user entered character is + * discarded if it's a <space> character. + */ + if (LF_ISSET(TXT_REPLAY) || !LF_ISSET(TXT_WRAPMARGIN)) + margin = 0; + else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0) + margin = sp->cols - margin; + wmset = wmskip = 0; + + /* Initialize abbreviations checks. */ + if (F_ISSET(sp->gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) { + abb = A_INWORD; + ab_cnt = ab_turnoff = 0; + } else + abb = A_NOTSET; + + /* + * Set up the dot command. Dot commands are done by saving the + * actual characters and replaying the input. We have to push + * the characters onto the key stack and then handle them normally, + * otherwise things like wrapmargin will fail. + * + * XXX + * It would be nice if we could swallow backspaces and such, but + * it's not all that easy to do. Another possibility would be to + * recognize full line insertions, which could be performed quickly, + * without replay. + */ +nullreplay: + rcol = 0; + if (replay = LF_ISSET(TXT_REPLAY)) { + /* + * !!! + * Historically, it wasn't an error to replay non-existent + * input. This test is necessary, we get here by the user + * doing an input command followed by a nul. + * + * !!! + * Historically, vi did not remap or reabbreviate replayed + * input. It did, however, beep at you if you changed an + * abbreviation and then replayed the input. We're not that + * compatible. + */ + if (VIP(sp)->rep == NULL) + return (0); + if (term_push(sp, VIP(sp)->rep, VIP(sp)->rep_cnt, CH_NOMAP)) + return (1); + testnr = 0; + abb = A_NOTSET; + LF_CLR(TXT_RECORD); + } else + testnr = 1; + + unmap_tst = LF_ISSET(TXT_MAPINPUT) && LF_ISSET(TXT_INFOLINE); + iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT); + for (showmatch = 0, sig_reset = 0, + carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) { + /* + * Reset the line and update the screen. (The txt_showmatch() + * code refreshes the screen for us.) Don't refresh unless + * we're about to wait on a character or we need to know where + * the cursor really is. + */ + if (showmatch || margin || !KEYS_WAITING(sp)) { + if (sp->s_change(sp, ep, tp->lno, LINE_RESET)) + goto err; + if (showmatch) { + showmatch = 0; + txt_showmatch(sp, ep); + } else if (sp->s_refresh(sp, ep)) + goto err; + } + + /* Get the next character. */ +next_ch: tval = term_key(sp, &ikey, quoted == Q_THISCHAR ? + iflags & ~(TXT_MAPCOMMAND | TXT_MAPINPUT) : iflags); + ch = ikey.ch; + + /* Restore the terminal state if it was modified. */ + if (sig_reset && !tcgetattr(STDIN_FILENO, &t)) { + t.c_lflag |= ISIG; + t.c_iflag |= sig_ix; + sig_reset = 0; + (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); + } + + /* + * !!! + * Historically, <interrupt> exited the user from text input + * mode or cancelled a colon command, and returned to command + * mode. It also beeped the terminal, but that seems a bit + * excessive. + */ + if (tval != INP_OK) { + if (tval == INP_INTR) + goto k_escape; + goto err; + } + + /* Abbreviation check. See comment in txt_abbrev(). */ +#define MAX_ABBREVIATION_EXPANSION 256 + if (ikey.flags & CH_ABBREVIATED) { + if (++ab_cnt > MAX_ABBREVIATION_EXPANSION) { + term_flush(sp, + "Abbreviation exceeded maximum number of characters", + CH_ABBREVIATED); + ab_cnt = 0; + continue; + } + } else + ab_cnt = 0; + + /* Wrapmargin check. */ + if (wmskip) { + wmskip = 0; + if (ch == ' ') + goto next_ch; + } + + /* + * !!! + * Historic feature. If the first character of the input is + * a nul, replay the previous input. This isn't documented + * anywhere, and is a great test of vi clones. + */ + if (ch == '\0' && testnr) { + LF_SET(TXT_REPLAY); + goto nullreplay; + } + testnr = 0; + + /* + * Check to see if the character fits into the input (and + * replay, if necessary) buffers. It isn't necessary to + * have tp->len bytes, since it doesn't consider overwrite + * characters, but not worth fixing. + */ + if (LF_ISSET(TXT_RECORD)) { + BINC_GOTO(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1); + VIP(sp)->rep[rcol++] = ch; + } + BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1); + + /* + * If the character was quoted, replace the last character + * (the literal mark) with the new character. If quoted + * by someone else, simply insert the character. + */ + if (ikey.flags & CH_QUOTED) + goto insq_ch; + if (quoted == Q_THISCHAR) { + --sp->cno; + ++tp->owrite; + quoted = Q_NOTSET; + goto insq_ch; + } + /* + * !!! + * Extension. If the user enters "<CH_HEX>[isxdigit()]*" we + * will try to use the value as a character. Anything else + * inserts the <CH_HEX> character, and resets hex mode. + */ + if (hex == H_INHEX && !isxdigit(ch)) { + if (txt_hex(sp, tp)) + goto err; + hex = H_NOTSET; + } + + switch (ikey.value) { + case K_CR: /* Carriage return. */ + case K_NL: /* New line. */ + /* Return in script windows and the command line. */ +k_cr: if (LF_ISSET(TXT_CR)) { + /* + * If this was a map, we may have not displayed + * the line. Display it, just in case. + * + * If a script window and not the colon line, + * push a <cr> so it gets executed. + */ + if (LF_ISSET(TXT_INFOLINE)) { + if (sp->s_change(sp, + ep, tp->lno, LINE_RESET)) + goto err; + } else if (F_ISSET(sp, S_SCRIPT)) + (void)term_push(sp, "\r", 1, CH_NOMAP); + goto k_escape; + } + +#define LINE_RESOLVE { \ + /* \ + * Handle abbreviations. If there was one, \ + * discard the replay characters. \ + */ \ + if (abb == A_INWORD && !replay) { \ + if (txt_abbrev(sp, tp, &ch, \ + LF_ISSET(TXT_INFOLINE), &tmp, \ + &ab_turnoff)) \ + goto err; \ + if (tmp) { \ + if (LF_ISSET(TXT_RECORD)) \ + rcol -= tmp; \ + goto next_ch; \ + } \ + } \ + if (abb != A_NOTSET) \ + abb = A_NOTWORD; \ + if (unmap_tst) \ + txt_unmap(sp, tp, &iflags); \ + /* Delete any appended cursor. */ \ + if (LF_ISSET(TXT_APPENDEOL)) { \ + --tp->len; \ + --tp->insert; \ + } \ +} + LINE_RESOLVE; + + /* + * Save the current line information for restoration + * in txt_backup(). Set the new line length. + */ + tp->sv_len = tp->len; + tp->sv_cno = sp->cno; + tp->len = sp->cno; + + /* Update the old line. */ + if (sp->s_change(sp, ep, tp->lno, LINE_RESET)) + goto err; + + /* + * Historic practice was to delete <blank> characters + * following the inserted newline. This affected the + * 'R', 'c', and 's' commands; 'c' and 's' retained + * the insert characters only, 'R' moved overwrite and + * insert characters into the next TEXT structure. + * All other commands simply deleted the overwrite + * characters. We have to keep track of the number of + * characters erased for the 'R' command so that we + * can get the final resolution of the line correct. + */ + tp->R_erase = 0; + owrite = tp->owrite; + insert = tp->insert; + if (LF_ISSET(TXT_REPLACE) && owrite != 0) { + for (p = tp->lb + sp->cno; + owrite > 0 && isblank(*p); + ++p, --owrite, ++tp->R_erase); + if (owrite == 0) + for (; insert > 0 && isblank(*p); + ++p, ++tp->R_erase, --insert); + } else { + for (p = tp->lb + sp->cno + owrite; + insert > 0 && isblank(*p); ++p, --insert); + owrite = 0; + } + + /* Set up bookkeeping for the new line. */ + if ((ntp = text_init(sp, p, + insert + owrite, insert + owrite + 32)) == NULL) + goto err; + ntp->insert = insert; + ntp->owrite = owrite; + ntp->lno = tp->lno + 1; + + /* + * Reset the autoindent line value. 0^D keeps the ai + * line from changing, ^D changes the level, even if + * there are no characters in the old line. Note, + * if using the current tp structure, use the cursor + * as the length, the user may have erased autoindent + * characters. + */ + if (LF_ISSET(TXT_AUTOINDENT)) { + if (carat_st == C_NOCHANGE) { + if (txt_auto(sp, ep, + OOBLNO, &ait, ait.ai, ntp)) + goto err; + FREE_SPACE(sp, ait.lb, ait.lb_len); + } else + if (txt_auto(sp, ep, + OOBLNO, tp, sp->cno, ntp)) + goto err; + carat_st = C_NOTSET; + } + + /* Reset the cursor. */ + sp->lno = ntp->lno; + sp->cno = ntp->ai; + + /* + * If we're here because wrapmargin was set and we've + * broken a line, there may be additional information + * (i.e. the start of a line) in the wmt structure. + */ + if (wmset) { + if (wmt.len != 0 || + wmt.insert != 0 || wmt.owrite != 0) { + BINC_GOTO(sp, ntp->lb, ntp->lb_len, + ntp->len + wmt.len + 32); + memmove(ntp->lb + sp->cno, wmt.lb, + wmt.len + wmt.insert + wmt.owrite); + ntp->len += + wmt.len + wmt.insert + wmt.owrite; + ntp->insert = wmt.insert; + ntp->owrite = wmt.owrite; + sp->cno += wmt.len; + } + wmset = 0; + } + + /* New lines are TXT_APPENDEOL. */ + if (ntp->owrite == 0 && ntp->insert == 0) { + BINC_GOTO(sp, + ntp->lb, ntp->lb_len, ntp->len + 1); + LF_SET(TXT_APPENDEOL); + ntp->lb[sp->cno] = CH_CURSOR; + ++ntp->insert; + ++ntp->len; + } + + /* + * Swap old and new TEXT's, and insert the new TEXT + * into the queue. + * + * !!! + * DON'T insert until the old line has been updated, + * or the inserted line count in line.c:file_gline() + * will be wrong. + */ + tp = ntp; + CIRCLEQ_INSERT_TAIL(tiqh, tp, q); + + /* Update the new line. */ + if (sp->s_change(sp, ep, tp->lno, LINE_INSERT)) + goto err; + + /* Set the renumber bit. */ + F_SET(sp, S_RENUMBER); + + /* Refresh if nothing waiting. */ + if (margin || !KEYS_WAITING(sp)) + if (sp->s_refresh(sp, ep)) + goto err; + goto next_ch; + case K_ESCAPE: /* Escape. */ + if (!LF_ISSET(TXT_ESCAPE)) + goto ins_ch; +k_escape: LINE_RESOLVE; + + /* + * Clean up for the 'R' command, restoring overwrite + * characters, and making them into insert characters. + */ + if (LF_ISSET(TXT_REPLACE)) + txt_Rcleanup(sp, tiqh, tp, lp, len); + + /* + * If there are any overwrite characters, copy down + * any insert characters, and decrement the length. + */ + if (tp->owrite) { + if (tp->insert) + memmove(tp->lb + sp->cno, + tp->lb + sp->cno + tp->owrite, + tp->insert); + tp->len -= tp->owrite; + } + + /* + * Optionally resolve the lines into the file. Clear + * the input flag, the look-aside buffer is no longer + * valid. If not resolving the lines into the file, + * end it with a nul. + * + * XXX + * This is wrong, should pass back a length. + */ + if (LF_ISSET(TXT_RESOLVE)) { + if (txt_resolve(sp, ep, tiqh, flags)) + goto err; + F_CLR(sp, S_INPUT); + } else { + BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1); + tp->lb[tp->len] = '\0'; + } + + /* + * Set the return cursor position to rest on the last + * inserted character. + */ + if (rp != NULL) { + rp->lno = tp->lno; + rp->cno = sp->cno ? sp->cno - 1 : 0; + if (sp->s_change(sp, ep, rp->lno, LINE_RESET)) + goto err; + } + goto ret; + case K_CARAT: /* Delete autoindent chars. */ + if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai) + carat_st = C_CARATSET; + goto ins_ch; + case K_ZERO: /* Delete autoindent chars. */ + if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai) + carat_st = C_ZEROSET; + goto ins_ch; + case K_CNTRLD: /* Delete autoindent char. */ + /* + * If in the first column or no characters to erase, + * ignore the ^D (this matches historic practice). If + * not doing autoindent or already inserted non-ai + * characters, it's a literal. The latter test is done + * in the switch, as the CARAT forms are N + 1, not N. + */ + if (!LF_ISSET(TXT_AUTOINDENT)) + goto ins_ch; + if (sp->cno == 0) + break; + switch (carat_st) { + case C_CARATSET: /* ^^D */ + if (sp->cno > tp->ai + tp->offset + 1) + goto ins_ch; + /* Save the ai string for later. */ + ait.lb = NULL; + ait.lb_len = 0; + BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai); + memmove(ait.lb, tp->lb, tp->ai); + ait.ai = ait.len = tp->ai; + + carat_st = C_NOCHANGE; + goto leftmargin; + case C_ZEROSET: /* 0^D */ + if (sp->cno > tp->ai + tp->offset + 1) + goto ins_ch; + carat_st = C_NOTSET; +leftmargin: tp->lb[sp->cno - 1] = ' '; + tp->owrite += sp->cno - tp->offset; + tp->ai = 0; + sp->cno = tp->offset; + break; + case C_NOTSET: /* ^D */ + if (sp->cno > tp->ai + tp->offset) + goto ins_ch; + (void)txt_outdent(sp, tp); + break; + default: + abort(); + } + break; + case K_VERASE: /* Erase the last character. */ + /* + * If can erase over the prompt, return. Len is 0 + * if backspaced over the prompt, 1 if only CR entered. + */ + if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) { + tp->len = 0; + goto ret; + } + + /* + * If at the beginning of the line, try and drop back + * to a previously inserted line. + */ + if (sp->cno == 0) { + if ((ntp = txt_backup(sp, + ep, tiqh, tp, &flags)) == NULL) + goto err; + tp = ntp; + break; + } + + /* If nothing to erase, bell the user. */ + if (sp->cno <= tp->offset) { + msgq(sp, M_BERR, + "No more characters to erase"); + break; + } + + /* Drop back one character. */ + --sp->cno; + + /* + * Increment overwrite, decrement ai if deleted. + * + * !!! + * Historic vi did not permit users to use erase + * characters to delete autoindent characters. + */ + ++tp->owrite; + if (sp->cno < tp->ai) + --tp->ai; + break; + case K_VWERASE: /* Skip back one word. */ + /* + * If at the beginning of the line, try and drop back + * to a previously inserted line. + */ + if (sp->cno == 0) { + if ((ntp = txt_backup(sp, + ep, tiqh, tp, &flags)) == NULL) + goto err; + tp = ntp; + } + + /* + * If at offset, nothing to erase so bell the user. + */ + if (sp->cno <= tp->offset) { + msgq(sp, M_BERR, + "No more characters to erase"); + break; + } + + /* + * First werase goes back to any autoindent + * and second werase goes back to the offset. + * + * !!! + * Historic vi did not permit users to use erase + * characters to delete autoindent characters. + */ + if (tp->ai && sp->cno > tp->ai) + max = tp->ai; + else { + tp->ai = 0; + max = tp->offset; + } + + /* Skip over trailing space characters. */ + while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) { + --sp->cno; + ++tp->owrite; + } + if (sp->cno == max) + break; + /* + * There are three types of word erase found on UNIX + * systems. They can be identified by how the string + * /a/b/c is treated -- as 1, 3, or 6 words. Historic + * vi had two classes of characters, and strings were + * delimited by them and <blank>'s, so, 6 words. The + * historic tty interface used <blank>'s to delimit + * strings, so, 1 word. The algorithm offered in the + * 4.4BSD tty interface (as stty altwerase) treats it + * as 3 words -- there are two classes of characters, + * and strings are delimited by them and <blank>'s. + * The difference is that the type of the first erased + * character erased is ignored, which is exactly right + * when erasing pathname components. Here, the options + * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD + * tty interface and the historic tty driver behavior, + * respectively, and the default is the same as the + * historic vi behavior. + */ + if (LF_ISSET(TXT_TTYWERASE)) + while (sp->cno > max) { + --sp->cno; + ++tp->owrite; + if (isblank(tp->lb[sp->cno - 1])) + break; + } + else { + if (LF_ISSET(TXT_ALTWERASE)) { + --sp->cno; + ++tp->owrite; + if (isblank(tp->lb[sp->cno - 1])) + break; + } + if (sp->cno > max) + tmp = inword(tp->lb[sp->cno - 1]); + while (sp->cno > max) { + --sp->cno; + ++tp->owrite; + if (tmp != inword(tp->lb[sp->cno - 1]) + || isblank(tp->lb[sp->cno - 1])) + break; + } + } + break; + case K_VKILL: /* Restart this line. */ + /* + * If at the beginning of the line, try and drop back + * to a previously inserted line. + */ + if (sp->cno == 0) { + if ((ntp = txt_backup(sp, + ep, tiqh, tp, &flags)) == NULL) + goto err; + tp = ntp; + } + + /* If at offset, nothing to erase so bell the user. */ + if (sp->cno <= tp->offset) { + msgq(sp, M_BERR, + "No more characters to erase"); + break; + } + + /* + * First kill goes back to any autoindent + * and second kill goes back to the offset. + * + * !!! + * Historic vi did not permit users to use erase + * characters to delete autoindent characters. + */ + if (tp->ai && sp->cno > tp->ai) + max = tp->ai; + else { + tp->ai = 0; + max = tp->offset; + } + tp->owrite += sp->cno - max; + sp->cno = max; + break; + case K_CNTRLT: /* Add autoindent char. */ + if (!LF_ISSET(TXT_CNTRLT)) + goto ins_ch; + if (txt_indent(sp, tp)) + goto err; + goto ebuf_chk; +#ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_SUSPEND + case K_CNTRLZ: + /* + * XXX + * Note, historically suspend triggered an autowrite. + * That needs to be done to make this work correctly. + */ + (void)sp->s_suspend(sp); + break; +#endif +#ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT + case K_FORMFEED: + F_SET(sp, S_REFRESH); + break; +#endif + case K_RIGHTBRACE: + case K_RIGHTPAREN: + showmatch = LF_ISSET(TXT_SHOWMATCH); + goto ins_ch; + case K_VLNEXT: /* Quote the next character. */ + ch = '^'; + quoted = Q_NEXTCHAR; + /* + * If there are no keys in the queue, reset the tty + * so that the user can enter a ^C, ^Q, ^S. There's + * an obvious race here, if the user entered the ^C + * already. There's nothing that we can do to fix + * that problem. + */ + if (!KEYS_WAITING(sp) && !tcgetattr(STDIN_FILENO, &t)) { + t.c_lflag &= ~ISIG; + sig_ix = t.c_iflag & (IXON | IXOFF); + t.c_iflag &= ~(IXON | IXOFF); + sig_reset = 1; + (void)tcsetattr(STDIN_FILENO, + TCSASOFT | TCSADRAIN, &t); + } + /* + * XXX + * Pass the tests for abbreviations, so ":ab xa XA", + * "ixa^V<space>" works. Historic vi did something + * weird here: ":ab x y", "ix\<space>" resulted in + * "<space>x\", for some unknown reason. Had to be + * a bug. + */ + goto insl_ch; + case K_HEXCHAR: + hex = H_NEXTCHAR; + goto insq_ch; + default: /* Insert the character. */ +ins_ch: /* + * Historically, vi eliminated nul's out of hand. If + * the beautify option was set, it also deleted any + * unknown ASCII value less than space (040) and the + * del character (0177), except for tabs. Unknown is + * a key word here. Most vi documentation claims that + * it deleted everything but <tab>, <nl> and <ff>, as + * that's what the original 4BSD documentation said. + * This is obviously wrong, however, as <esc> would be + * included in that list. What we do is eliminate any + * unquoted, iscntrl() character that wasn't a replay + * and wasn't handled specially, except <tab> or <ff>. + */ + if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ch) && + ikey.value != K_FORMFEED && ikey.value != K_TAB) { + msgq(sp, M_BERR, + "Illegal character; quote to enter"); + break; + } +insq_ch: /* + * If entering a non-word character after a word, check + * for abbreviations. If there was one, discard the + * replay characters. If entering a blank character, + * check for unmap commands, as well. + */ + if (!inword(ch)) { + if (abb == A_INWORD && !replay) { + if (txt_abbrev(sp, tp, &ch, + LF_ISSET(TXT_INFOLINE), + &tmp, &ab_turnoff)) + goto err; + if (tmp) { + if (LF_ISSET(TXT_RECORD)) + rcol -= tmp; + goto next_ch; + } + } + if (isblank(ch) && unmap_tst) + txt_unmap(sp, tp, &iflags); + } + if (abb != A_NOTSET) + abb = inword(ch) ? A_INWORD : A_NOTWORD; + +insl_ch: if (tp->owrite) /* Overwrite a character. */ + --tp->owrite; + else if (tp->insert) { /* Insert a character. */ + ++tp->len; + if (tp->insert == 1) + tp->lb[sp->cno + 1] = tp->lb[sp->cno]; + else + memmove(tp->lb + sp->cno + 1, + tp->lb + sp->cno, tp->insert); + } + + tp->lb[sp->cno++] = ch; + + /* Check to see if we've crossed the margin. */ + if (margin) { + if (sp->s_column(sp, ep, &col)) + goto err; + if (col >= margin) { + if (txt_margin(sp, + tp, &ch, &wmt, flags, &tmp)) + goto err; + if (tmp) { + if (isblank(ch)) + wmskip = 1; + wmset = 1; + goto k_cr; + } + } + } + + /* + * If we've reached the end of the buffer, then we + * need to switch into insert mode. This happens + * when there's a change to a mark and the user puts + * in more characters than the length of the motion. + */ +ebuf_chk: if (sp->cno >= tp->len) { + BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1); + LF_SET(TXT_APPENDEOL); + tp->lb[sp->cno] = CH_CURSOR; + ++tp->insert; + ++tp->len; + } + + if (hex == H_NEXTCHAR) + hex = H_INHEX; + if (quoted == Q_NEXTCHAR) + quoted = Q_THISCHAR; + break; + } +#if defined(DEBUG) && 1 + if (sp->cno + tp->insert + tp->owrite != tp->len) + msgq(sp, M_ERR, + "len %u != cno: %u ai: %u insert %u overwrite %u", + tp->len, sp->cno, tp->ai, tp->insert, tp->owrite); + tp->len = sp->cno + tp->insert + tp->owrite; +#endif + } + + /* Clear input flag. */ +ret: F_CLR(sp, S_INPUT); + + if (LF_ISSET(TXT_RECORD)) + VIP(sp)->rep_cnt = rcol; + return (eval); + +err: /* Error jumps. */ +binc_err: + eval = 1; + txt_err(sp, ep, tiqh); + goto ret; +} + +/* + * txt_abbrev -- + * Handle abbreviations. + */ +static int +txt_abbrev(sp, tp, pushcp, isinfoline, didsubp, turnoffp) + SCR *sp; + TEXT *tp; + CHAR_T *pushcp; + int isinfoline, *didsubp, *turnoffp; +{ + CHAR_T ch; + SEQ *qp; + size_t len, off; + char *p; + + /* + * Find the start of the "word". Historically, abbreviations + * could be preceded by any non-word character or the beginning + * of the entry, .e.g inserting an abbreviated string in the + * middle of another string triggered the replacement. + */ + for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) { + if (!inword(*p)) { + ++p; + break; + } + ++len; + if (off == tp->ai || off == tp->offset) + break; + } + + /* + * !!! + * Historic vi exploded abbreviations on the command line. This has + * obvious problems in that unabbreviating the string can be extremely + * tricky, particularly if the string has, say, an embedded escape + * character. Personally, I think it's a stunningly bad idea. Other + * examples of problems this caused in historic vi are: + * :ab foo bar + * :ab foo baz + * results in "bar" being abbreviated to "baz", which wasn't what the + * user had in mind at all. Also, the commands: + * :ab foo bar + * :unab foo<space> + * resulted in an error message that "bar" wasn't mapped. Finally, + * since the string was already exploded by the time the unabbreviate + * command got it, all it knew was that an abbreviation had occurred. + * Cleverly, it checked the replacement string for its unabbreviation + * match, which meant that the commands: + * :ab foo1 bar + * :ab foo2 bar + * :unab foo2 + * unabbreviate "foo1", and the commands: + * :ab foo bar + * :ab bar baz + * unabbreviate "foo"! + * + * Anyway, people neglected to first ask my opinion before they wrote + * macros that depend on this stuff, so, we make this work as follows. + * When checking for an abbreviation on the command line, if we get a + * string which is <blank> terminated and which starts at the beginning + * of the line, we check to see it is the abbreviate or unabbreviate + * commands. If it is, turn abbreviations off and return as if no + * abbreviation was found. Note also, minor trickiness, so that if + * the user erases the line and starts another command, we turn the + * abbreviations back on. + * + * This makes the layering look like a Nachos Supreme. + */ + *didsubp = 0; + if (isinfoline) + if (off == tp->ai || off == tp->offset) + if (ex_is_abbrev(p, len)) { + *turnoffp = 1; + return (0); + } else + *turnoffp = 0; + else + if (*turnoffp) + return (0); + + /* Check for any abbreviations. */ + if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL) + return (0); + + /* + * Push the abbreviation onto the tty stack. Historically, characters + * resulting from an abbreviation expansion were themselves subject to + * map expansions, O_SHOWMATCH matching etc. This means the expanded + * characters will be re-tested for abbreviations. It's difficult to + * know what historic practice in this case was, since abbreviations + * were applied to :colon command lines, so entering abbreviations that + * looped was tricky, although possible. In addition, obvious loops + * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will + * silently only implement and/or display the last abbreviation.) + * + * This implementation doesn't recover well from such abbreviations. + * The main input loop counts abbreviated characters, and, when it + * reaches a limit, discards any abbreviated characters on the queue. + * It's difficult to back up to the original position, as the replay + * queue would have to be adjusted, and the line state when an initial + * abbreviated character was received would have to be saved. + */ + ch = *pushcp; + if (term_push(sp, &ch, 1, CH_ABBREVIATED)) + return (1); + if (term_push(sp, qp->output, qp->olen, CH_ABBREVIATED)) + return (1); + + /* Move to the start of the abbreviation, adjust the length. */ + sp->cno -= len; + tp->len -= len; + + /* Copy any insert characters back. */ + if (tp->insert) + memmove(tp->lb + sp->cno + tp->owrite, + tp->lb + sp->cno + tp->owrite + len, tp->insert); + + /* + * We return the length of the abbreviated characters. This is so + * the calling routine can replace the replay characters with the + * abbreviation. This means that subsequent '.' commands will produce + * the same text, regardless of intervening :[un]abbreviate commands. + * This is historic practice. + */ + *didsubp = len; + return (0); +} + +/* + * txt_unmap -- + * Handle the unmap command. + */ +static void +txt_unmap(sp, tp, iflagsp) + SCR *sp; + TEXT *tp; + u_int *iflagsp; +{ + size_t len, off; + char *p; + + /* Find the beginning of this "word". */ + for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) { + if (isblank(*p)) { + ++p; + break; + } + ++len; + if (off == tp->ai || off == tp->offset) + break; + } + + /* + * !!! + * Historic vi exploded input mappings on the command line. See the + * txt_abbrev() routine for an explanation of the problems inherent + * in this. + * + * We make this work as follows. If we get a string which is <blank> + * terminated and which starts at the beginning of the line, we check + * to see it is the unmap command. If it is, we return that the input + * mapping should be turned off. Note also, minor trickiness, so that + * if the user erases the line and starts another command, we go ahead + * an turn mapping back on. + */ + if ((off == tp->ai || off == tp->offset) && ex_is_unmap(p, len)) + *iflagsp &= ~TXT_MAPINPUT; + else + *iflagsp |= TXT_MAPINPUT; +} + +/* + * txt_ai_resolve -- + * When a line is resolved by <esc> or <cr>, review autoindent + * characters. + */ +static void +txt_ai_resolve(sp, tp) + SCR *sp; + TEXT *tp; +{ + u_long ts; + int del; + size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs; + char *p; + + /* + * If the line is empty, has an offset, or no autoindent + * characters, we're done. + */ + if (!tp->len || tp->offset || !tp->ai) + return; + + /* + * If the length is less than or equal to the autoindent + * characters, delete them. + */ + if (tp->len <= tp->ai) { + tp->len = tp->ai = 0; + if (tp->lno == sp->lno) + sp->cno = 0; + return; + } + + /* + * The autoindent characters plus any leading <blank> characters + * in the line are resolved into the minimum number of characters. + * Historic practice. + */ + ts = O_VAL(sp, O_TABSTOP); + + /* Figure out the last <blank> screen column. */ + for (p = tp->lb, scno = 0, len = tp->len, + spaces = tab_after_sp = 0; len-- && isblank(*p); ++p) + if (*p == '\t') { + if (spaces) + tab_after_sp = 1; + scno += STOP_OFF(scno, ts); + } else { + ++spaces; + ++scno; + } + + /* + * If there are no spaces, or no tabs after spaces and less than + * ts spaces, it's already minimal. + */ + if (!spaces || !tab_after_sp && spaces < ts) + return; + + /* Count up spaces/tabs needed to get to the target. */ + for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs) + cno += STOP_OFF(cno, ts); + spaces = scno - cno; + + /* + * Figure out how many characters we're dropping -- if we're not + * dropping any, it's already minimal, we're done. + */ + old = p - tp->lb; + new = spaces + tabs; + if (old == new) + return; + + /* Shift the rest of the characters down, adjust the counts. */ + del = old - new; + memmove(p - del, p, tp->len - old); + tp->len -= del; + + /* If the cursor was on this line, adjust it as well. */ + if (sp->lno == tp->lno) + sp->cno -= del; + + /* Fill in space/tab characters. */ + for (p = tp->lb; tabs--;) + *p++ = '\t'; + while (spaces--) + *p++ = ' '; +} + +/* + * txt_auto -- + * Handle autoindent. If aitp isn't NULL, use it, otherwise, + * retrieve the line. + */ +int +txt_auto(sp, ep, lno, aitp, len, tp) + SCR *sp; + EXF *ep; + recno_t lno; + size_t len; + TEXT *aitp, *tp; +{ + size_t nlen; + char *p, *t; + + if (aitp == NULL) { + /* + * If the ex append command is executed with an address of 0, + * it's possible to get here with a line number of 0. Return + * an indent of 0. + */ + if (lno == 0) { + tp->ai = 0; + return (0); + } + if ((t = file_gline(sp, ep, lno, &len)) == NULL) + return (1); + } else + t = aitp->lb; + + /* Count whitespace characters. */ + for (p = t; len > 0; ++p, --len) + if (!isblank(*p)) + break; + + /* Set count, check for no indentation. */ + if ((nlen = (p - t)) == 0) + return (0); + + /* Make sure the buffer's big enough. */ + BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen); + + /* Copy the buffer's current contents up. */ + if (tp->len != 0) + memmove(tp->lb + nlen, tp->lb, tp->len); + tp->len += nlen; + + /* Copy the indentation into the new buffer. */ + memmove(tp->lb, t, nlen); + + /* Set the autoindent count. */ + tp->ai = nlen; + return (0); +} + +/* + * txt_backup -- + * Back up to the previously edited line. + */ +static TEXT * +txt_backup(sp, ep, tiqh, tp, flagsp) + SCR *sp; + EXF *ep; + TEXTH *tiqh; + TEXT *tp; + u_int *flagsp; +{ + TEXT *ntp; + u_int flags; + + /* Get a handle on the previous TEXT structure. */ + if ((ntp = tp->q.cqe_prev) == (void *)tiqh) { + msgq(sp, M_BERR, "Already at the beginning of the insert"); + return (tp); + } + + /* Reset the cursor, bookkeeping. */ + sp->lno = ntp->lno; + sp->cno = ntp->sv_cno; + ntp->len = ntp->sv_len; + + /* Handle appending to the line. */ + flags = *flagsp; + if (ntp->owrite == 0 && ntp->insert == 0) { + ntp->lb[ntp->len] = CH_CURSOR; + ++ntp->insert; + ++ntp->len; + LF_SET(TXT_APPENDEOL); + } else + LF_CLR(TXT_APPENDEOL); + *flagsp = flags; + + /* Release the current TEXT. */ + CIRCLEQ_REMOVE(tiqh, tp, q); + text_free(tp); + + /* Update the old line on the screen. */ + if (sp->s_change(sp, ep, ntp->lno + 1, LINE_DELETE)) + return (NULL); + + /* Return the new/current TEXT. */ + return (ntp); +} + +/* + * txt_err -- + * Handle an error during input processing. + */ +static void +txt_err(sp, ep, tiqh) + SCR *sp; + EXF *ep; + TEXTH *tiqh; +{ + recno_t lno; + size_t len; + + /* + * The problem with input processing is that the cursor is at an + * indeterminate position since some input may have been lost due + * to a malloc error. So, try to go back to the place from which + * the cursor started, knowing that it may no longer be available. + * + * We depend on at least one line number being set in the text + * chain. + */ + for (lno = tiqh->cqh_first->lno; + file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno); + + sp->lno = lno == 0 ? 1 : lno; + sp->cno = 0; + + /* Redraw the screen, just in case. */ + F_SET(sp, S_REDRAW); +} + +/* + * txt_hex -- + * Let the user insert any character value they want. + * + * !!! + * This is an extension. The pattern "^X[0-9a-fA-F]*" is a way + * for the user to specify a character value which their keyboard + * may not be able to enter. + */ +static int +txt_hex(sp, tp) + SCR *sp; + TEXT *tp; +{ + CHAR_T savec; + size_t len, off; + u_long value; + char *p, *wp; + + /* + * Null-terminate the string. Since nul isn't a legal hex value, + * this should be okay, and lets us use a local routine, which + * presumably understands the character set, to convert the value. + */ + savec = tp->lb[sp->cno]; + tp->lb[sp->cno] = 0; + + /* Find the previous CH_HEX character. */ + for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off, ++len) { + if (*p == CH_HEX) { + wp = p + 1; + break; + } + /* Not on this line? Shouldn't happen. */ + if (off == tp->ai || off == tp->offset) + goto nothex; + } + + /* If length of 0, then it wasn't a hex value. */ + if (len == 0) + goto nothex; + + /* Get the value. */ + errno = 0; + value = strtol(wp, NULL, 16); + if (errno || value > MAX_CHAR_T) { +nothex: tp->lb[sp->cno] = savec; + return (0); + } + + /* Restore the original character. */ + tp->lb[sp->cno] = savec; + + /* Adjust the bookkeeping. */ + sp->cno -= len; + tp->len -= len; + tp->lb[sp->cno - 1] = value; + + /* Copy down any overwrite characters. */ + if (tp->owrite) + memmove(tp->lb + sp->cno, + tp->lb + sp->cno + len, tp->owrite); + + /* Copy down any insert characters. */ + if (tp->insert) + memmove(tp->lb + sp->cno + tp->owrite, + tp->lb + sp->cno + tp->owrite + len, tp->insert); + + return (0); +} + +/* + * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements + * to the next or previous shiftwidth value, i.e. for a 1-based numbering, + * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to + * the 10th column, and ^D moves it back. + * + * !!! + * The ^T and ^D characters in historical vi only had special meaning when + * they were the first characters typed after entering text input mode. + * Since normal erase characters couldn't erase autoindent (in this case + * ^T) characters, this meant that inserting text into previously existing + * text was quite strange, ^T only worked if it was the first keystroke, + * and then it could only be erased by using ^D. This implementation treats + * ^T specially anywhere it occurs in the input, and permits the standard + * erase characters to erase characters inserted using it. + * + * XXX + * Technically, txt_indent, txt_outdent should part of the screen interface, + * as they require knowledge of the size of a space character on the screen. + * (Not the size of tabs, because tabs are logically composed of spaces.) + * They're left in the text code because they're complicated, not to mention + * the gruesome awareness that if spaces aren't a single column on the screen + * for any language, we're into some serious, ah, for lack of a better word, + * "issues". + */ + +/* + * txt_indent -- + * Handle ^T indents. + */ +static int +txt_indent(sp, tp) + SCR *sp; + TEXT *tp; +{ + u_long sw, ts; + size_t cno, off, scno, spaces, tabs; + + ts = O_VAL(sp, O_TABSTOP); + sw = O_VAL(sp, O_SHIFTWIDTH); + + /* Get the current screen column. */ + for (off = scno = 0; off < sp->cno; ++off) + if (tp->lb[off] == '\t') + scno += STOP_OFF(scno, ts); + else + ++scno; + + /* Count up spaces/tabs needed to get to the target. */ + for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0; + cno + STOP_OFF(cno, ts) <= scno; ++tabs) + cno += STOP_OFF(cno, ts); + spaces = scno - cno; + + /* Put space/tab characters in place of any overwrite characters. */ + for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai) + tp->lb[sp->cno++] = '\t'; + for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai) + tp->lb[sp->cno++] = ' '; + + if (!tabs && !spaces) + return (0); + + /* Make sure there's enough room. */ + BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs); + + /* Move the insert characters out of the way. */ + if (tp->insert) + memmove(tp->lb + sp->cno + spaces + tabs, + tp->lb + sp->cno, tp->insert); + + /* Add new space/tab characters. */ + for (; tabs--; ++tp->len, ++tp->ai) + tp->lb[sp->cno++] = '\t'; + for (; spaces--; ++tp->len, ++tp->ai) + tp->lb[sp->cno++] = ' '; + return (0); +} + +/* + * txt_outdent -- + * Handle ^D outdents. + * + */ +static int +txt_outdent(sp, tp) + SCR *sp; + TEXT *tp; +{ + u_long sw, ts; + size_t cno, off, scno, spaces; + + ts = O_VAL(sp, O_TABSTOP); + sw = O_VAL(sp, O_SHIFTWIDTH); + + /* Get the current screen column. */ + for (off = scno = 0; off < sp->cno; ++off) + if (tp->lb[off] == '\t') + scno += STOP_OFF(scno, ts); + else + ++scno; + + /* Get the previous shiftwidth column. */ + for (cno = scno; --scno % sw != 0;); + + /* Decrement characters until less than or equal to that slot. */ + for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite) + if (tp->lb[--off] == '\t') + cno -= STOP_OFF(cno, ts); + else + --cno; + + /* Spaces needed to get to the target. */ + spaces = scno - cno; + + /* Maybe just a delete. */ + if (spaces == 0) + return (0); + + /* Make sure there's enough room. */ + BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces); + + /* Use up any overwrite characters. */ + for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite) + tp->lb[sp->cno++] = ' '; + + /* Maybe that was enough. */ + if (spaces == 0) + return (0); + + /* Move the insert characters out of the way. */ + if (tp->insert) + memmove(tp->lb + sp->cno + spaces, + tp->lb + sp->cno, tp->insert); + + /* Add new space characters. */ + for (; spaces--; ++tp->len, ++tp->ai) + tp->lb[sp->cno++] = ' '; + return (0); +} + +/* + * txt_resolve -- + * Resolve the input text chain into the file. + */ +static int +txt_resolve(sp, ep, tiqh, flags) + SCR *sp; + EXF *ep; + TEXTH *tiqh; + u_int flags; +{ + TEXT *tp; + recno_t lno; + + /* + * The first line replaces a current line, and all subsequent lines + * are appended into the file. Resolve autoindented characters for + * each line before committing it. + */ + tp = tiqh->cqh_first; + if (LF_ISSET(TXT_AUTOINDENT)) + txt_ai_resolve(sp, tp); + if (file_sline(sp, ep, tp->lno, tp->lb, tp->len)) + return (1); + + for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)sp->tiqp; ++lno) { + if (LF_ISSET(TXT_AUTOINDENT)) + txt_ai_resolve(sp, tp); + if (file_aline(sp, ep, 0, lno, tp->lb, tp->len)) + return (1); + } + return (0); +} + +/* + * txt_showmatch -- + * Show a character match. + * + * !!! + * Historic vi tried to display matches even in the :colon command line. + * I think not. + */ +static void +txt_showmatch(sp, ep) + SCR *sp; + EXF *ep; +{ + struct timeval second; + VCS cs; + MARK m; + fd_set zero; + int cnt, endc, startc; + + /* + * Do a refresh first, in case the v_ntext() code hasn't done + * one in awhile, so the user can see what we're complaining + * about. + */ + if (sp->s_refresh(sp, ep)) + return; + /* + * We don't display the match if it's not on the screen. Find + * out what the first character on the screen is. + */ + if (sp->s_position(sp, ep, &m, 0, P_TOP)) + return; + + /* Initialize the getc() interface. */ + cs.cs_lno = sp->lno; + cs.cs_cno = sp->cno - 1; + if (cs_init(sp, ep, &cs)) + return; + startc = (endc = cs.cs_ch) == ')' ? '(' : '{'; + + /* Search for the match. */ + for (cnt = 1;;) { + if (cs_prev(sp, ep, &cs)) + return; + if (cs.cs_lno < m.lno || + cs.cs_lno == m.lno && cs.cs_cno < m.cno) + return; + if (cs.cs_flags != 0) { + if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) { + (void)sp->s_bell(sp); + return; + } + continue; + } + if (cs.cs_ch == endc) + ++cnt; + else if (cs.cs_ch == startc && --cnt == 0) + break; + } + + /* Move to the match. */ + m.lno = sp->lno; + m.cno = sp->cno; + sp->lno = cs.cs_lno; + sp->cno = cs.cs_cno; + (void)sp->s_refresh(sp, ep); + + /* + * Sleep(3) is eight system calls. Do it fast -- besides, + * I don't want to wait an entire second. + */ + FD_ZERO(&zero); + second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10; + second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L; + (void)select(0, &zero, &zero, &zero, &second); + + /* Return to the current location. */ + sp->lno = m.lno; + sp->cno = m.cno; + (void)sp->s_refresh(sp, ep); +} + +/* + * txt_margin -- + * Handle margin wrap. + */ +static int +txt_margin(sp, tp, chp, wmtp, flags, didbreak) + SCR *sp; + TEXT *tp, *wmtp; + CHAR_T *chp; + int *didbreak; + u_int flags; +{ + size_t len, off; + char *p, *wp; + + /* Find the nearest previous blank. */ + for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --off, --p, ++len) { + if (isblank(*p)) { + wp = p + 1; + break; + } + + /* + * If reach the start of the line, there's nowhere to break. + * + * !!! + * Historic vi belled each time a character was entered after + * crossing the margin until a space was entered which could + * be used to break the line. I don't as it tends to wake the + * cats. + */ + if (off == tp->ai || off == tp->offset) { + *didbreak = 0; + return (0); + } + } + + /* + * Store saved information about the rest of the line in the + * wrapmargin TEXT structure. + */ + wmtp->lb = p + 1; + wmtp->len = len; + wmtp->insert = LF_ISSET(TXT_APPENDEOL) ? tp->insert - 1 : tp->insert; + wmtp->owrite = tp->owrite; + + /* Correct current bookkeeping information. */ + sp->cno -= len; + if (LF_ISSET(TXT_APPENDEOL)) { + tp->len -= len + tp->owrite + (tp->insert - 1); + tp->insert = 1; + } else { + tp->len -= len + tp->owrite + tp->insert; + tp->insert = 0; + } + tp->owrite = 0; + + /* + * !!! + * Delete any trailing whitespace from the current line. + */ + for (;; --p, --off) { + if (!isblank(*p)) + break; + --sp->cno; + --tp->len; + if (off == tp->ai || off == tp->offset) + break; + } + *didbreak = 1; + return (0); +} + +/* + * txt_Rcleanup -- + * Resolve the input line for the 'R' command. + */ +static void +txt_Rcleanup(sp, tiqh, tp, lp, olen) + SCR *sp; + TEXTH *tiqh; + TEXT *tp; + const char *lp; + const size_t olen; +{ + TEXT *ttp; + size_t ilen, tmp; + + /* + * Check to make sure that the cursor hasn't moved beyond + * the end of the line. + */ + if (tp->owrite == 0) + return; + + /* + * Calculate how many characters the user has entered, + * plus the blanks erased by <carriage-return>/<newline>s. + */ + for (ttp = tiqh->cqh_first, ilen = 0;;) { + ilen += ttp == tp ? sp->cno : ttp->len + ttp->R_erase; + if ((ttp = ttp->q.cqe_next) == (void *)sp->tiqp) + break; + } + + /* + * If the user has entered less characters than the original line + * was long, restore any overwriteable characters to the original + * characters, and make them insert characters. We don't copy them + * anywhere, because the 'R' command doesn't have insert characters. + */ + if (ilen < olen) { + tmp = MIN(tp->owrite, olen - ilen); + memmove(tp->lb + sp->cno, lp + ilen, tmp); + tp->owrite -= tmp; + tp->insert += tmp; + } +} diff --git a/usr.bin/vi/vi/v_paragraph.c b/usr.bin/vi/vi/v_paragraph.c new file mode 100644 index 0000000..590718d --- /dev/null +++ b/usr.bin/vi/vi/v_paragraph.c @@ -0,0 +1,370 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_paragraph.c 8.18 (Berkeley) 7/29/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +#define INTEXT_CHECK { \ + if (len == 0 || v_isempty(p, len)) { \ + if (!--cnt) \ + goto found; \ + pstate = P_INBLANK; \ + } \ + /* \ + * !!! \ + * Historic documentation (USD:15-11, 4.2) said that formfeed \ + * characters (^L) in the first column delimited paragraphs. \ + * The historic vi code mentions formfeed characters, but never \ + * implements them. It seems reasonable, do it. \ + */ \ + if (p[0] == '\014') { \ + if (!--cnt) \ + goto found; \ + continue; \ + } \ + if (p[0] != '.' || len < 2) \ + continue; \ + for (lp = VIP(sp)->ps; *lp != '\0'; lp += 2) \ + if (lp[0] == p[1] && \ + (lp[1] == ' ' && len == 2 || lp[1] == p[2]) && \ + !--cnt) \ + goto found; \ +} + +/* + * v_paragraphf -- [count]} + * Move forward count paragraphs. + * + * Paragraphs are empty lines after text, formfeed characters, or values + * from the paragraph or section options. + */ +int +v_paragraphf(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + enum { P_INTEXT, P_INBLANK } pstate; + size_t lastlen, len; + recno_t cnt, lastlno, lno; + char *p, *lp; + + /* + * !!! + * If the starting cursor position is at or before any non-blank + * characters in the line, i.e. the movement is cutting all of the + * line's text, the buffer is in line mode. It's a lot easier to + * check here, because we know that the end is going to be the start + * or end of a line. + * + * This was historical practice in vi, with a single exception. If + * the paragraph movement was from the start of the last line to EOF, + * then all the characters were deleted from the last line, but the + * line itself remained. If somebody complains, don't pause, don't + * hesitate, just hit them. + */ + if (ISMOTION(vp)) + if (vp->m_start.cno == 0) + F_SET(vp, VM_LMODE); + else { + vp->m_stop = vp->m_start; + vp->m_stop.cno = 0; + if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + if (vp->m_start.cno <= vp->m_stop.cno) + F_SET(vp, VM_LMODE); + } + + /* Figure out what state we're currently in. */ + lno = vp->m_start.lno; + if ((p = file_gline(sp, ep, lno, &len)) == NULL) + goto eof; + + /* + * If we start in text, we want to switch states + * (2 * N - 1) times, in non-text, (2 * N) times. + */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cnt *= 2; + if (len == 0 || v_isempty(p, len)) + pstate = P_INBLANK; + else { + --cnt; + pstate = P_INTEXT; + } + + for (;;) { + lastlno = lno; + lastlen = len; + if ((p = file_gline(sp, ep, ++lno, &len)) == NULL) + goto eof; + switch (pstate) { + case P_INTEXT: + INTEXT_CHECK; + break; + case P_INBLANK: + if (len == 0 || v_isempty(p, len)) + break; + if (--cnt) { + pstate = P_INTEXT; + break; + } + /* + * !!! + * Non-motion commands move to the end of the range, + * VC_D and VC_Y stay at the start. Ignore VC_C and + * VC_DEF. Adjust the end of the range for motion + * commands; historically, a motion component was to + * the end of the previous line, whereas the movement + * command was to the start of the new "paragraph". + */ +found: if (ISMOTION(vp)) { + vp->m_stop.lno = lastlno; + vp->m_stop.cno = lastlen ? lastlen - 1 : 0; + vp->m_final = vp->m_start; + } else { + vp->m_stop.lno = lno; + vp->m_stop.cno = 0; + vp->m_final = vp->m_stop; + } + return (0); + default: + abort(); + } + } + + /* + * !!! + * Adjust end of the range for motion commands; EOF is a movement + * sink. The } command historically moved to the end of the last + * line, not the beginning, from any position before the end of the + * last line. It also historically worked on empty files, so we + * have to make it okay. + */ +eof: if (vp->m_start.lno == lno || vp->m_start.lno == lno - 1) { + if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (vp->m_start.lno != 1 || lno != 0) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + vp->m_start.cno = 0; + return (0); + } + if (vp->m_start.cno == (len ? len - 1 : 0)) { + v_eof(sp, ep, NULL); + return (1); + } + } + /* + * !!! + * Non-motion commands move to the end of the range, VC_D + * and VC_Y stay at the start. Ignore VC_C and VC_DEF. + * + * If deleting the line (which happens if deleting to EOF), then + * cursor movement is to the first nonblank. + */ + if (F_ISSET(vp, VC_D)) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + } + vp->m_stop.lno = lno - 1; + vp->m_stop.cno = len ? len - 1 : 0; + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_paragraphb -- [count]{ + * Move backward count paragraphs. + */ +int +v_paragraphb(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + enum { P_INTEXT, P_INBLANK } pstate; + size_t len; + recno_t cnt, lno; + char *p, *lp; + + /* + * !!! + * Check for SOF. The historic vi didn't complain if users hit SOF + * repeatedly, unless it was part of a motion command. There is no + * question but that Emerson's editor of choice was vi. + * + * The { command historically moved to the beginning of the first + * line if invoked on the first line. + * + * !!! + * If the starting cursor position is in the first column (backward + * paragraph movements did NOT historically pay attention to non-blank + * characters) i.e. the movement is cutting the entire line, the buffer + * is in line mode. Cuts from the beginning of the line also did not + * cut the current line, but started at the previous EOL. + * + * Correct for a left motion component while we're thinking about it. + */ + lno = vp->m_start.lno; + + if (ISMOTION(vp)) + if (vp->m_start.cno == 0) { + if (vp->m_start.lno == 1) { + v_sof(sp, &vp->m_start); + return (1); + } else + --vp->m_start.lno; + F_SET(vp, VM_LMODE); + } else + --vp->m_start.cno; + + if (vp->m_start.lno <= 1) + goto sof; + + /* Figure out what state we're currently in. */ + if ((p = file_gline(sp, ep, lno, &len)) == NULL) + goto sof; + + /* + * If we start in text, we want to switch states + * (2 * N - 1) times, in non-text, (2 * N) times. + */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cnt *= 2; + if (len == 0 || v_isempty(p, len)) + pstate = P_INBLANK; + else { + --cnt; + pstate = P_INTEXT; + + /* + * !!! + * If the starting cursor is past the first column, + * the current line is checked for a paragraph. + */ + if (vp->m_start.cno > 0) + ++lno; + } + + for (;;) { + if ((p = file_gline(sp, ep, --lno, &len)) == NULL) + goto sof; + switch (pstate) { + case P_INTEXT: + INTEXT_CHECK; + break; + case P_INBLANK: + if (len != 0 && !v_isempty(p, len)) { + if (!--cnt) + goto found; + pstate = P_INTEXT; + } + break; + default: + abort(); + } + } + + /* SOF is a movement sink. */ +sof: lno = 1; + +found: vp->m_stop.lno = lno; + vp->m_stop.cno = 0; + + /* + * All commands move to the end of the range. (We already + * adjusted the start of the range for motion commands). + */ + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_buildps -- + * Build the paragraph command search pattern. + */ +int +v_buildps(sp) + SCR *sp; +{ + VI_PRIVATE *vip; + size_t p_len, s_len; + char *p, *p_p, *s_p; + + /* + * The vi paragraph command searches for either a paragraph or + * section option macro. + */ + p_len = (p_p = O_STR(sp, O_PARAGRAPHS)) == NULL ? 0 : strlen(p_p); + s_len = (s_p = O_STR(sp, O_SECTIONS)) == NULL ? 0 : strlen(s_p); + + if (p_len == 0 && s_len == 0) + return (0); + + MALLOC_RET(sp, p, char *, p_len + s_len + 1); + + vip = VIP(sp); + if (vip->ps != NULL) + free(vip->ps); + + if (p_p != NULL) + memmove(p, p_p, p_len + 1); + if (s_p != NULL) + memmove(p + p_len, s_p, s_len + 1); + vip->ps = p; + return (0); +} diff --git a/usr.bin/vi/vi/v_put.c b/usr.bin/vi/vi/v_put.c new file mode 100644 index 0000000..8206d16 --- /dev/null +++ b/usr.bin/vi/vi/v_put.c @@ -0,0 +1,168 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_put.c 8.9 (Berkeley) 5/2/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +static void inc_buf __P((SCR *, VICMDARG *)); + +/* + * v_Put -- [buffer]P + * Insert the contents of the buffer before the cursor. + */ +int +v_Put(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + u_long cnt; + + if (F_ISSET(vp, VC_ISDOT)) + inc_buf(sp, vp); + + /* + * !!! + * Historic vi did not support a count with the 'p' and 'P' + * commands. It's useful, so we do. + */ + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + if (put(sp, ep, NULL, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_final, 0)) + return (1); + vp->m_start = vp->m_final; + } + return (0); +} + +/* + * v_put -- [buffer]p + * Insert the contents of the buffer after the cursor. + */ +int +v_put(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + u_long cnt; + + if (F_ISSET(vp, VC_ISDOT)) + inc_buf(sp, vp); + + /* + * !!! + * Historic vi did not support a count with the 'p' and 'P' + * commands. It's useful, so we do. + */ + for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + if (put(sp, ep, NULL, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_final, 1)) + return (1); + vp->m_start = vp->m_final; + } + return (0); +} + +/* + * !!! + * Historical whackadoo. The dot command `puts' the numbered buffer + * after the last one put. For example, `"4p.' would put buffer #4 + * and buffer #5. If the user continued to enter '.', the #9 buffer + * would be repeatedly output. This was not documented, and is a bit + * tricky to reconstruct. Historical versions of vi also dropped the + * contents of the default buffer after each put, so after `"4p' the + * default buffer would be empty. This makes no sense to me, so we + * don't bother. Don't assume sequential order of numeric characters. + * + * And, if that weren't exciting enough, failed commands don't normally + * set the dot command. Well, boys and girls, an exception is that + * the buffer increment gets done regardless of the success of the put. + */ +static void +inc_buf(sp, vp) + SCR *sp; + VICMDARG *vp; +{ + CHAR_T v; + + switch (vp->buffer) { + case '1': + v = '2'; + break; + case '2': + v = '3'; + break; + case '3': + v = '4'; + break; + case '4': + v = '5'; + break; + case '5': + v = '6'; + break; + case '6': + v = '7'; + break; + case '7': + v = '8'; + break; + case '8': + v = '9'; + break; + default: + return; + } + VIP(sp)->sdot.buffer = vp->buffer = v; +} diff --git a/usr.bin/vi/vi/v_redraw.c b/usr.bin/vi/vi/v_redraw.c new file mode 100644 index 0000000..8f7054c --- /dev/null +++ b/usr.bin/vi/vi/v_redraw.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_redraw.c 8.4 (Berkeley) 3/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_redraw -- ^R + * Redraw the screen. + */ +int +v_redraw(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + F_SET(sp, S_REFRESH); + return (0); +} diff --git a/usr.bin/vi/vi/v_replace.c b/usr.bin/vi/vi/v_replace.c new file mode 100644 index 0000000..9254024 --- /dev/null +++ b/usr.bin/vi/vi/v_replace.c @@ -0,0 +1,194 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_replace.c 8.18 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_replace -- [count]rc + * + * !!! + * The r command in historic vi was almost beautiful in its badness. For + * example, "r<erase>" and "r<word erase>" beeped the terminal and deleted + * a single character. "Nr<carriage return>", where N was greater than 1, + * inserted a single carriage return. This may not be right, but at least + * it's not insane. + */ +int +v_replace(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + CH ikey; + TEXT *tp; + recno_t lno; + size_t blen, len; + u_long cnt; + int rval; + char *bp, *p; + + /* + * If the line doesn't exist, or it's empty, replacement isn't + * allowed. It's not hard to implement, but: + * + * 1: It's historic practice. + * 2: For consistency, this change would require that the more + * general case, "Nr", when the user is < N characters from + * the end of the line, also work. + * 3: Replacing a newline has somewhat odd semantics. + */ + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + goto nochar; + } + if (len == 0) { +nochar: msgq(sp, M_BERR, "No characters to replace"); + return (1); + } + + /* + * Figure out how many characters to be replace. For no particular + * reason (other than that the semantics of replacing the newline + * are confusing) only permit the replacement of the characters in + * the current line. I suppose we could append replacement characters + * to the line, but I see no compelling reason to do so. + */ + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + vp->m_stop.lno = vp->m_start.lno; + vp->m_stop.cno = vp->m_start.cno + cnt - 1; + if (vp->m_stop.cno > len - 1) { + v_eol(sp, ep, &vp->m_start); + return (1); + } + + /* + * Get the character. Literal escapes escape any character, + * single escapes return. + */ + if (F_ISSET(vp, VC_ISDOT)) { + ikey.ch = VIP(sp)->rlast; + ikey.value = KEY_VAL(sp, ikey.ch); + } else { + sp->showmode = "Replace char"; + (void)sp->s_refresh(sp, ep); + + if (term_key(sp, &ikey, 0) != INP_OK) + return (1); + switch (ikey.value) { + case K_ESCAPE: + return (0); + case K_VLNEXT: + if (term_key(sp, &ikey, 0) != INP_OK) + return (1); + break; + } + VIP(sp)->rlast = ikey.ch; + } + + /* Copy the line. */ + GET_SPACE_RET(sp, bp, blen, len); + memmove(bp, p, len); + p = bp; + + if (ikey.value == K_CR || ikey.value == K_NL) { + /* Set return line. */ + vp->m_stop.lno = vp->m_start.lno + cnt; + vp->m_stop.cno = 0; + + /* The first part of the current line. */ + if (file_sline(sp, ep, vp->m_start.lno, p, vp->m_start.cno)) + goto err_ret; + + /* + * The rest of the current line. And, of course, now it gets + * tricky. Any white space after the replaced character is + * stripped, and autoindent is applied. Put the cursor on the + * last indent character as did historic vi. + */ + for (p += vp->m_start.cno + cnt, len -= vp->m_start.cno + cnt; + len && isblank(*p); --len, ++p); + + if ((tp = text_init(sp, p, len, len)) == NULL) + goto err_ret; + if (txt_auto(sp, ep, vp->m_start.lno, NULL, 0, tp)) + goto err_ret; + vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0; + if (file_aline(sp, ep, 1, vp->m_start.lno, tp->lb, tp->len)) + goto err_ret; + text_free(tp); + + rval = 0; + + /* All of the middle lines. */ + while (--cnt) + if (file_aline(sp, ep, 1, vp->m_start.lno, "", 0)) { +err_ret: rval = 1; + break; + } + } else { + memset(bp + vp->m_start.cno, ikey.ch, cnt); + rval = file_sline(sp, ep, vp->m_start.lno, bp, len); + } + FREE_SPACE(sp, bp, blen); + + vp->m_final = vp->m_stop; + return (rval); +} diff --git a/usr.bin/vi/vi/v_right.c b/usr.bin/vi/vi/v_right.c new file mode 100644 index 0000000..df7c85c --- /dev/null +++ b/usr.bin/vi/vi/v_right.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_right.c 8.8 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_right -- [count]' ', [count]l + * Move right by columns. + */ +int +v_right(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + size_t len; + + if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) + v_eol(sp, ep, NULL); + else + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + + /* It's always illegal to move right on empty lines. */ + if (len == 0) { + v_eol(sp, ep, NULL); + return (1); + } + + /* + * Non-motion commands move to the end of the range. VC_D and + * VC_Y stay at the start. Ignore VC_C and VC_DEF. Adjust the + * end of the range for motion commands. + * + * !!! + * Historically, "[cdsy]l" worked at the end of a line. Also, + * EOL is a count sink. + */ + vp->m_stop.cno = vp->m_start.cno + + (F_ISSET(vp, VC_C1SET) ? vp->count : 1); + if (vp->m_start.cno == len - 1 && !ISMOTION(vp)) { + v_eol(sp, ep, NULL); + return (1); + } + if (vp->m_stop.cno >= len) { + vp->m_stop.cno = len - 1; + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + } else if (ISMOTION(vp)) { + --vp->m_stop.cno; + vp->m_final = vp->m_start; + } else + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_dollar -- [count]$ + * Move to the last column. + */ +int +v_dollar(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + size_t len; + + /* + * !!! + * A count moves down count - 1 rows, so, "3$" is the same as "2j$". + */ + if ((F_ISSET(vp, VC_C1SET) ? vp->count : 1) != 1) { + /* + * !!! + * Historically, if the $ is a motion, and deleting from + * at or before the first non-blank of the line, it's a + * line motion, and the line motion flag is set. + */ + vp->m_stop.cno = 0; + if (nonblank(sp, ep, vp->m_start.lno, &vp->m_stop.cno)) + return (1); + if (ISMOTION(vp) && vp->m_start.cno <= vp->m_stop.cno) + F_SET(vp, VM_LMODE); + + --vp->count; + if (v_down(sp, ep, vp)) + return (1); + } + + if (file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) + v_eol(sp, ep, NULL); + else + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + + /* + * Non-motion commands move to the end of the range. VC_D + * and VC_Y stay at the start. Ignore VC_C and VC_DEF. + */ + vp->m_stop.cno = len ? len - 1 : 0; + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} diff --git a/usr.bin/vi/vi/v_screen.c b/usr.bin/vi/vi/v_screen.c new file mode 100644 index 0000000..20ca6ba --- /dev/null +++ b/usr.bin/vi/vi/v_screen.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_screen.c 8.12 (Berkeley) 8/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_screen -- ^W + * Switch screens. + */ +int +v_screen(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * Try for the next lower screen, or, go back to the first + * screen on the stack. + */ + if (sp->q.cqe_next != (void *)&sp->gp->dq) + sp->nextdisp = sp->q.cqe_next; + else if (sp->gp->dq.cqh_first == sp) { + msgq(sp, M_ERR, "No other screen to switch to"); + return (1); + } else + sp->nextdisp = sp->gp->dq.cqh_first; + + /* + * Display the old screen's status line so the user can + * find the screen they want. + */ + (void)msg_status(sp, ep, vp->m_start.lno, 0); + + /* Save the old screen's cursor information. */ + sp->frp->lno = sp->lno; + sp->frp->cno = sp->cno; + F_SET(sp->frp, FR_CURSORSET); + + F_SET(sp, S_SSWITCH); + return (0); +} diff --git a/usr.bin/vi/vi/v_scroll.c b/usr.bin/vi/vi/v_scroll.c new file mode 100644 index 0000000..b381dc5 --- /dev/null +++ b/usr.bin/vi/vi/v_scroll.c @@ -0,0 +1,486 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_scroll.c 8.20 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "vcmd.h" + +static void goto_adjust __P((VICMDARG *)); + +/* + * The historic vi had a problem in that all movements were by physical + * lines, not by logical, or screen lines. Arguments can be made that this + * is the right thing to do. For example, single line movements, such as + * 'j' or 'k', should probably work on physical lines. Commands like "dj", + * or "j.", where '.' is a change command, make more sense for physical lines + * than they do for logical lines. + * + * These arguments, however, don't apply to scrolling commands like ^D and + * ^F -- if the window is fairly small, using physical lines can result in + * a half-page scroll repainting the entire screen, which is not what the + * user wanted. Second, if the line is larger than the screen, using physical + * lines can make it impossible to display parts of the line -- there aren't + * any commands that don't display the beginning of the line in historic vi, + * and if both the beginning and end of the line can't be on the screen at + * the same time, you lose. This is even worse in the case of the H, L, and + * M commands -- for large lines, they may all refer to the same line and + * will result in no movement at all. + * + * Another issue is that page and half-page scrolling commands historically + * moved to the first non-blank character in the new line. If the line is + * approximately the same size as the screen, this loses because the cursor + * before and after a ^D, may refer to the same location on the screen. In + * this implementation, scrolling commands set the cursor to the first non- + * blank character if the line changes because of the scroll. Otherwise, + * the cursor is left alone. + * + * This implementation does the scrolling (^B, ^D, ^F, ^U, ^Y, ^E), and the + * cursor positioning commands (H, L, M) commands using logical lines, not + * physical. + */ + +/* + * v_lgoto -- [count]G + * Go to first non-blank character of the line count, the last line + * of the file by default. + */ +int +v_lgoto(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t nlines; + + if (F_ISSET(vp, VC_C1SET)) { + if (file_gline(sp, ep, vp->count, NULL) == NULL) { + v_eof(sp, ep, &vp->m_start); + return (1); + } + vp->m_stop.lno = vp->count; + } else { + if (file_lline(sp, ep, &nlines)) + return (1); + vp->m_stop.lno = nlines ? nlines : 1; + } + goto_adjust(vp); + return (0); +} + +/* + * v_home -- [count]H + * Move to the first non-blank character of the logical line + * count - 1 from the top of the screen, 0 by default. + */ +int +v_home(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + if (sp->s_position(sp, ep, &vp->m_stop, + F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_TOP)) + return (1); + goto_adjust(vp); + return (0); +} + +/* + * v_middle -- M + * Move to the first non-blank character of the logical line + * in the middle of the screen. + */ +int +v_middle(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * Yielding to none in our quest for compatibility with every + * historical blemish of vi, no matter how strange it might be, + * we permit the user to enter a count and then ignore it. + */ + if (sp->s_position(sp, ep, &vp->m_stop, 0, P_MIDDLE)) + return (1); + goto_adjust(vp); + return (0); +} + +/* + * v_bottom -- [count]L + * Move to the first non-blank character of the logical line + * count - 1 from the bottom of the screen, 0 by default. + */ +int +v_bottom(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + if (sp->s_position(sp, ep, &vp->m_stop, + F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_BOTTOM)) + return (1); + goto_adjust(vp); + return (0); +} + +static void +goto_adjust(vp) + VICMDARG *vp; +{ + /* Guess that it's the end of the range. */ + vp->m_final = vp->m_stop; + + /* + * Non-motion commands move the cursor to the end of the range, and + * then to the NEXT nonblank of the line. Historic vi always moved + * to the first nonblank in the line; since the H, M, and L commands + * are logical motions in this implementation, we do the next nonblank + * so that it looks approximately the same to the user. To make this + * happen, the VM_RCM_SETNNB flag is set in the vcmd.c command table. + * + * If it's a motion, it's more complicated. The best possible solution + * is probably to display the first nonblank of the line the cursor + * will eventually rest on. This is tricky, particularly given that if + * the associated command is a delete, we don't yet know what line that + * will be. So, we clear the VM_RCM_SETNNB flag, and set the first + * nonblank flag (VM_RCM_SETFNB). Note, if the lines are sufficiently + * long, this can cause the cursor to warp out of the screen. It's too + * hard to fix. + * + * XXX + * The G command is always first nonblank, so it's okay to reset it. + */ + if (ISMOTION(vp)) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + } else + return; + + /* + * If moving backward in the file, VC_D and VC_Y move to the end + * of the range, unless the line didn't change, in which case VC_Y + * doesn't move. If moving forward in the file, VC_D and VC_Y stay + * at the start of the range. Ignore VC_C and VC_DEF. + */ + if (vp->m_stop.lno < vp->m_start.lno || + vp->m_stop.lno == vp->m_start.lno && + vp->m_stop.cno < vp->m_start.cno) { + if (F_ISSET(vp, VC_Y) && vp->m_stop.lno == vp->m_start.lno) + vp->m_final = vp->m_start; + } else + vp->m_final = vp->m_start; +} + +/* + * v_up -- [count]^P, [count]k, [count]- + * Move up by lines. + */ +int +v_up(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + + lno = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (vp->m_start.lno <= lno) { + v_sof(sp, &vp->m_start); + return (1); + } + vp->m_stop.lno = vp->m_start.lno - lno; + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_cr -- [count]^M + * In a script window, send the line to the shell. + * In a regular window, move down by lines. + */ +int +v_cr(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * If it's a script window, exec the line, + * otherwise it's the same as v_down(). + */ + return (F_ISSET(sp, S_SCRIPT) ? + sscr_exec(sp, ep, vp->m_start.lno) : v_down(sp, ep, vp)); +} + +/* + * v_down -- [count]^J, [count]^N, [count]j, [count]^M, [count]+ + * Move down by lines. + */ +int +v_down(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + + lno = vp->m_start.lno + (F_ISSET(vp, VC_C1SET) ? vp->count : 1); + if (file_gline(sp, ep, lno, NULL) == NULL) { + v_eof(sp, ep, &vp->m_start); + return (1); + } + vp->m_stop.lno = lno; + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_hpageup -- [count]^U + * Page up half screens. + */ +int +v_hpageup(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * Half screens always succeed unless already at SOF. + * + * !!! + * Half screens set the scroll value, even if the command + * ultimately failed, in historic vi. Probably a don't care. + */ + if (F_ISSET(vp, VC_C1SET)) + sp->defscroll = vp->count; + if (sp->s_scroll(sp, ep, &vp->m_stop, sp->defscroll, CNTRL_U)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_hpagedown -- [count]^D + * Page down half screens. + */ +int +v_hpagedown(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * Half screens always succeed unless already at EOF. + * + * !!! + * Half screens set the scroll value, even if the command + * ultimately failed, in historic vi. Probably a don't care. + */ + if (F_ISSET(vp, VC_C1SET)) + sp->defscroll = vp->count; + if (sp->s_scroll(sp, ep, &vp->m_stop, sp->defscroll, CNTRL_D)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_pagedown -- [count]^F + * Page down full screens. + * !!! + * Historic vi did not move to the EOF if the screen couldn't move, i.e. + * if EOF was already displayed on the screen. This implementation does + * move to EOF in that case, making ^F more like the the historic ^D. + */ +int +v_pagedown(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t offset; + + /* + * !!! + * The calculation in IEEE Std 1003.2-1992 (POSIX) is: + * + * top_line = top_line + count * (window - 2); + * + * which was historically wrong. The correct one is: + * + * top_line = top_line + count * window - 2; + * + * i.e. the two line "overlap" was only subtracted once. Which + * makes no sense, but then again, an overlap makes no sense for + * any screen but the "next" one anyway. We do it the historical + * was as there's no good reason to change it. + * + * If the screen has been split, use the smaller of the current + * window size and the window option value. + * + * Given a one-line screen with the cursor on line 1, it would be + * possible for this to fail, i.e. "1 + 1 * 1 - 2 = 0". Move at + * least one line. + */ +#define IS_SPLIT_SCREEN(sp) \ + ((sp)->q.cqe_prev != (void *)&(sp)->gp->dq || \ + (sp)->q.cqe_next != (void *)&(sp)->gp->dq) + + offset = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * + (IS_SPLIT_SCREEN(sp) ? + MIN(sp->t_maxrows, O_VAL(sp, O_WINDOW)) : O_VAL(sp, O_WINDOW)) - 2; + if (offset == 0) + offset = 1; + if (sp->s_scroll(sp, ep, &vp->m_stop, offset, CNTRL_F)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_pageup -- [count]^B + * Page up full screens. + * + * !!! + * Historic vi did not move to the SOF if the screen couldn't move, i.e. + * if SOF was already displayed on the screen. This implementation does + * move to SOF in that case, making ^B more like the the historic ^U. + */ +int +v_pageup(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t offset; + + /* + * !!! + * The calculation in IEEE Std 1003.2-1992 (POSIX) is: + * + * top_line = top_line - count * (window - 2); + * + * which was historically wrong. The correct one is: + * + * top_line = (top_line - count * window) + 2; + * + * A simpler expression is that, as with ^F, we scroll exactly: + * + * count * window - 2 + * + * lines. + * + * Bizarre. As with ^F, an overlap makes no sense for anything + * but the first screen. We do it the historical way as there's + * no good reason to change it. + * + * If the screen has been split, use the smaller of the current + * window size and the window option value. + * + * Given a one-line screen with the cursor on line 1, it would be + * possible for this to fail, i.e. "1 + 1 * 1 - 2 = 0". Move at + * least one line. + */ + offset = (F_ISSET(vp, VC_C1SET) ? vp->count : 1) * + (IS_SPLIT_SCREEN(sp) ? + MIN(sp->t_maxrows, O_VAL(sp, O_WINDOW)) : O_VAL(sp, O_WINDOW)) - 2; + if (offset == 0) + offset = 1; + if (sp->s_scroll(sp, ep, &vp->m_stop, offset, CNTRL_B)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_lineup -- [count]^Y + * Page up by lines. + */ +int +v_lineup(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * The cursor moves down, staying with its original line, unless it + * reaches the bottom of the screen. + */ + if (sp->s_scroll(sp, ep, + &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, CNTRL_Y)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_linedown -- [count]^E + * Page down by lines. + */ +int +v_linedown(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * The cursor moves up, staying with its original line, unless it + * reaches the top of the screen. + */ + if (sp->s_scroll(sp, ep, + &vp->m_stop, F_ISSET(vp, VC_C1SET) ? vp->count : 1, CNTRL_E)) + return (1); + vp->m_final = vp->m_stop; + return (0); +} diff --git a/usr.bin/vi/vi/v_search.c b/usr.bin/vi/vi/v_search.c new file mode 100644 index 0000000..2ba013a --- /dev/null +++ b/usr.bin/vi/vi/v_search.c @@ -0,0 +1,414 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_search.c 8.32 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +static int correct __P((SCR *, EXF *, VICMDARG *, u_int)); +static int getptrn __P((SCR *, EXF *, ARG_CHAR_T, char **, size_t *)); +static int search __P((SCR *, + EXF *, VICMDARG *, char *, size_t, u_int, enum direction)); + +/* + * v_searchn -- n + * Repeat last search. + */ +int +v_searchn(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (search(sp, ep, vp, NULL, 0, SEARCH_MSG, sp->searchdir)); +} + +/* + * v_searchN -- N + * Reverse last search. + */ +int +v_searchN(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + enum direction dir; + + switch (sp->searchdir) { + case BACKWARD: + dir = FORWARD; + break; + case FORWARD: + dir = BACKWARD; + break; + default: /* NOTSET handled in search(). */ + dir = sp->searchdir; + break; + } + return (search(sp, ep, vp, NULL, 0, SEARCH_MSG, dir)); +} + +/* + * v_searchb -- [count]?RE[? offset] + * Search backward. + */ +int +v_searchb(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + size_t len; + char *ptrn; + + if (F_ISSET(vp, VC_ISDOT)) + ptrn = NULL; + else { + if (getptrn(sp, ep, CH_BSEARCH, &ptrn, &len)) + return (1); + if (len == 0) { + F_SET(vp, VM_NOMOTION); + return (0); + } + } + return (search(sp, ep, vp, ptrn, len, + SEARCH_MSG | SEARCH_PARSE | SEARCH_SET, BACKWARD)); +} + +/* + * v_searchf -- [count]/RE[/ offset] + * Search forward. + */ +int +v_searchf(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + size_t len; + char *ptrn; + + if (F_ISSET(vp, VC_ISDOT)) + ptrn = NULL; + else { + if (getptrn(sp, ep, CH_FSEARCH, &ptrn, &len)) + return (1); + if (len == 0) { + F_SET(vp, VM_NOMOTION); + return (0); + } + } + return (search(sp, ep, vp, ptrn, len, + SEARCH_MSG | SEARCH_PARSE | SEARCH_SET, FORWARD)); +} + +/* + * v_searchw -- [count]^A + * Search for the word under the cursor. + */ +int +v_searchw(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + size_t blen, len; + int rval; + char *bp; + + len = vp->kbuflen + sizeof(RE_WSTART) + sizeof(RE_WSTOP); + GET_SPACE_RET(sp, bp, blen, len); + (void)snprintf(bp, blen, "%s%s%s", RE_WSTART, vp->keyword, RE_WSTOP); + + rval = search(sp, ep, vp, bp, 0, SEARCH_MSG | SEARCH_TERM, FORWARD); + + FREE_SPACE(sp, bp, blen); + return (rval); +} + +static int +search(sp, ep, vp, ptrn, len, flags, dir) + SCR *sp; + EXF *ep; + VICMDARG *vp; + u_int flags; + char *ptrn; + size_t len; + enum direction dir; +{ + char *eptrn; + + if (ISMOTION(vp)) + flags |= SEARCH_EOL; + + for (;;) { + switch (dir) { + case BACKWARD: + if (b_search(sp, ep, + &vp->m_start, &vp->m_stop, ptrn, &eptrn, &flags)) + return (1); + break; + case FORWARD: + if (f_search(sp, ep, + &vp->m_start, &vp->m_stop, ptrn, &eptrn, &flags)) + return (1); + break; + case NOTSET: + msgq(sp, M_ERR, "No previous search pattern"); + return (1); + default: + abort(); + } + + /* + * !!! + * Historically, vi permitted trailing <blank>'s, multiple + * search strings (separated by semi-colons) and full-blown + * z commands after / and ? search strings. In the case of + * multiple search strings, leading <blank>'s on the second + * and subsequent strings was eaten as well. + * + * !!! + * However, the command "/STRING/; " failed, apparently it + * confused the parser. We're not *that* compatible. + * + * The N, n, and ^A commands also get to here, but they've + * set ptrn to NULL, len to 0, or the SEARCH_TERM flag, or + * some combination thereof. + */ + if (ptrn == NULL || len == 0) + break; + len -= eptrn - ptrn; + for (; len > 0 && isblank(*eptrn); ++eptrn, --len); + if (len == 0) + break; + + switch (*eptrn) { + case ';': + for (++eptrn; --len > 0 && isblank(*eptrn); ++eptrn); + ptrn = eptrn; + switch (*eptrn) { + case '/': + dir = FORWARD; + break; + case '?': + dir = BACKWARD; + break; + default: + goto usage; + } + ptrn = eptrn; + vp->m_start = vp->m_stop; + continue; + case 'z': + if (term_push(sp, eptrn, len, CH_NOMAP | CH_QUOTED)) + return (1); + goto ret; + default: +usage: msgq(sp, M_ERR, + "Characters after search string and/or delta"); + return (1); + } + } + + /* Non-motion commands move to the end of the range. */ +ret: if (ISMOTION(vp)) { + if (correct(sp, ep, vp, flags)) + return (1); + } else + vp->m_final = vp->m_stop; + return (0); +} + +/* + * getptrn -- + * Get the search pattern. + */ +static int +getptrn(sp, ep, prompt, ptrnp, lenp) + SCR *sp; + EXF *ep; + ARG_CHAR_T prompt; + char **ptrnp; + size_t *lenp; +{ + TEXT *tp; + + if (sp->s_get(sp, ep, sp->tiqp, prompt, + TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK) + return (1); + + /* Len is 0 if backspaced over the prompt, 1 if only CR entered. */ + tp = sp->tiqp->cqh_first; + *ptrnp = tp->lb; + *lenp = tp->len; + return (0); +} + +/* + * correct -- + * Handle command with a search as the motion. + * + * !!! + * Historically, commands didn't affect the line searched to/from if the + * motion command was a search and the final position was the start/end + * of the line. There were some special cases and vi was not consistent; + * it was fairly easy to confuse it. For example, given the two lines: + * + * abcdefghi + * ABCDEFGHI + * + * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h' + * 'k' and put would no longer work correctly. In any case, we try to do + * the right thing, but it's not going to exactly match historic practice. + */ +static int +correct(sp, ep, vp, flags) + SCR *sp; + EXF *ep; + VICMDARG *vp; + u_int flags; +{ + enum direction dir; + MARK m; + size_t len; + + /* + * !!! + * We may have wrapped if wrapscan was set, and we may have returned + * to the position where the cursor started. Historic vi didn't cope + * with this well. Yank wouldn't beep, but the first put after the + * yank would move the cursor right one column (without adding any + * text) and the second would put a copy of the current line. The + * change and delete commands would beep, but would leave the cursor + * on the colon command line. I believe that there are macros that + * depend on delete, at least, failing. For now, commands that use + * search as a motion component fail when the search returns to the + * original cursor position. + */ + if (vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno == vp->m_stop.cno) { + msgq(sp, M_BERR, "Search wrapped to original position"); + return (1); + } + + /* + * !!! + * Searches become line mode operations if there was a delta + * specified to the search pattern. + */ + if (LF_ISSET(SEARCH_DELTA)) + F_SET(vp, VM_LMODE); + + /* + * If the motion is in the reverse direction, switch the start and + * stop MARK's so that it's in a forward direction. (There's no + * reason for this other than to make the tests below easier. The + * code in vi.c:vi() would have done the switch.) Both forward + * and backward motions can happen for any kind of search command + * because of the wrapscan option. + */ + if (vp->m_start.lno > vp->m_stop.lno || + vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno > vp->m_stop.cno) { + dir = BACKWARD; + m = vp->m_start; + vp->m_start = vp->m_stop; + vp->m_stop = m; + } else + dir = FORWARD; + + /* + * BACKWARD: + * VC_D commands move to the end of the range. VC_Y stays at + * the start unless the end of the range is on a different line, + * when it moves to the end of the range. Ignore VC_C and + * VC_DEF. + * + * FORWARD: + * VC_D and VC_Y commands don't move. Ignore VC_C and VC_DEF. + */ + if (dir == BACKWARD) + if (F_ISSET(vp, VC_D) || + F_ISSET(vp, VC_Y) && vp->m_start.lno != vp->m_stop.lno) + vp->m_final = vp->m_start; + else + vp->m_final = vp->m_stop; + else + vp->m_final = vp->m_start; + + /* + * !!! + * Backward searches starting at column 0, and forward searches ending + * at column 0 are corrected to the last column of the previous line. + * Otherwise, adjust the starting/ending point to the character before + * the current one (this is safe because we know the search had to move + * to succeed). + * + * Searches become line mode operations if they start at column 0 and + * end at column 0 of another line. + */ + if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) { + if (file_gline(sp, ep, --vp->m_stop.lno, &len) == NULL) { + GETLINE_ERR(sp, vp->m_stop.lno); + return (1); + } + if (vp->m_start.cno == 0) + F_SET(vp, VM_LMODE); + vp->m_stop.cno = len ? len - 1 : 0; + } else + --vp->m_stop.cno; + + return (0); +} diff --git a/usr.bin/vi/vi/v_section.c b/usr.bin/vi/vi/v_section.c new file mode 100644 index 0000000..9bc06b6 --- /dev/null +++ b/usr.bin/vi/vi/v_section.c @@ -0,0 +1,280 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_section.c 8.10 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * !!! + * In historic vi, the section commands ignored empty lines, unlike the + * paragraph commands, which was probably okay. However, they also moved + * to the start of the last line when there where no more sections instead + * of the end of the last line like the paragraph commands. I've changed + * the latter behavior to match the paragraph commands. + * + * In historic vi, a section was defined as the first character(s) of the + * line matching, which could be followed by anything. This implementation + * follows that historic practice. + * + * !!! + * The historic vi documentation (USD:15-10) claimed: + * The section commands interpret a preceding count as a different + * window size in which to redraw the screen at the new location, + * and this window size is the base size for newly drawn windows + * until another size is specified. This is very useful if you are + * on a slow terminal ... + * + * I can't get the 4BSD vi to do this, it just beeps at me. For now, a + * count to the section commands simply repeats the command. + */ + +/* + * v_sectionf -- [count]]] + * Move forward count sections/functions. + * + * !!! + * Using ]] as a motion command was a bit special, historically. It could + * match } as well as the usual { and section values. If it matched a { or + * a section, it did NOT include the matched line. If it matched a }, it + * did include the line. No clue why. + */ +int +v_sectionf(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t cnt, lno; + size_t len; + char *p, *list, *lp; + + /* Get the macro list. */ + if ((list = O_STR(sp, O_SECTIONS)) == NULL) + return (1); + + /* + * !!! + * If the starting cursor position is at or before any non-blank + * characters in the line, i.e. the movement is cutting all of the + * line's text, the buffer is in line mode. It's a lot easier to + * check here, because we know that the end is going to be the start + * or end of a line. + */ + if (ISMOTION(vp)) + if (vp->m_start.cno == 0) + F_SET(vp, VM_LMODE); + else { + vp->m_stop = vp->m_start; + vp->m_stop.cno = 0; + if (nonblank(sp, ep, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + if (vp->m_start.cno <= vp->m_stop.cno) + F_SET(vp, VM_LMODE); + } + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + for (lno = vp->m_start.lno; + (p = file_gline(sp, ep, ++lno, &len)) != NULL;) { + if (len == 0) + continue; + if (p[0] == '{' || ISMOTION(vp) && p[0] == '}') { + if (!--cnt) { + if (p[0] == '{') + goto adjust1; + goto adjust2; + } + continue; + } + /* + * !!! + * Historic documentation (USD:15-11, 4.2) said that formfeed + * characters (^L) in the first column delimited sections. + * The historic code mentions formfeed characters, but never + * implements them. Seems reasonable, do it. + */ + if (p[0] == '\014') { + if (!--cnt) + goto adjust1; + continue; + } + if (p[0] != '.' || len < 2) + continue; + for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp)) + if (lp[0] == p[1] && + (lp[1] == ' ' && len == 2 || lp[1] == p[2]) && + !--cnt) { + /* + * !!! + * If not cutting this line, adjust to the end + * of the previous one. Otherwise, position to + * column 0. + */ +adjust1: if (ISMOTION(vp)) + goto ret1; + +adjust2: vp->m_stop.lno = lno; + vp->m_stop.cno = 0; + goto ret2; + } + } + + /* If moving forward, reached EOF, check to see if we started there. */ + if (vp->m_start.lno == lno - 1) { + v_eof(sp, ep, NULL); + return (1); + } + +ret1: if (file_gline(sp, ep, --lno, &len) == NULL) + return (1); + vp->m_stop.lno = lno; + vp->m_stop.cno = len ? len - 1 : 0; + + /* + * Non-motion commands go to the end of the range. VC_D and + * VC_Y stay at the start of the range. Ignore VC_C and VC_DEF. + */ +ret2: if (ISMOTION(vp)) { + vp->m_final = vp->m_start; + if (F_ISSET(vp, VM_LMODE)) + vp->m_final.cno = 0; + } else + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_sectionb -- [count][[ + * Move backward count sections/functions. + */ +int +v_sectionb(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + size_t len; + recno_t cnt, lno; + char *p, *list, *lp; + + /* An empty file or starting from line 1 is always illegal. */ + if (vp->m_start.lno <= 1) { + v_sof(sp, NULL); + return (1); + } + + /* Get the macro list. */ + if ((list = O_STR(sp, O_SECTIONS)) == NULL) + return (1); + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + for (lno = vp->m_start.lno; + (p = file_gline(sp, ep, --lno, &len)) != NULL;) { + if (len == 0) + continue; + if (p[0] == '{') { + if (!--cnt) + goto adjust1; + continue; + } + /* + * !!! + * Historic documentation (USD:15-11, 4.2) said that formfeed + * characters (^L) in the first column delimited sections. + * The historic code mentions formfeed characters, but never + * implements them. Seems reasonable, do it. + */ + if (p[0] == '\014') { + if (!--cnt) + goto adjust1; + continue; + } + if (p[0] != '.' || len < 2) + continue; + for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp)) + if (lp[0] == p[1] && + (lp[1] == ' ' && len == 2 || lp[1] == p[2]) && + !--cnt) { +adjust1: vp->m_stop.lno = lno; + vp->m_stop.cno = 0; + goto ret1; + } + } + + /* + * If moving backward, reached SOF, which is a movement sink. + * We already checked for starting there. + */ + vp->m_stop.lno = 1; + vp->m_stop.cno = 0; + + /* + * All commands move to the end of the range. + * + * !!! + * Historic practice is the section cut was in line mode if it started + * from column 0 and was in the backward direction. Otherwise, left + * motion commands adjust the starting point to the character before + * the current one. What makes this worse is that if it cut to line + * mode it also went to the first non-<blank>. + */ +ret1: if (vp->m_start.cno == 0) { + F_CLR(vp, VM_RCM_MASK); + F_SET(vp, VM_RCM_SETFNB); + + --vp->m_start.lno; + F_SET(vp, VM_LMODE); + } else + --vp->m_start.cno; + + vp->m_final = vp->m_stop; + return (0); +} diff --git a/usr.bin/vi/vi/v_sentence.c b/usr.bin/vi/vi/v_sentence.c new file mode 100644 index 0000000..87c6039 --- /dev/null +++ b/usr.bin/vi/vi/v_sentence.c @@ -0,0 +1,386 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_sentence.c 8.15 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * !!! + * In historic vi, a sentence was delimited by a '.', '?' or '!' character + * followed by TWO spaces or a newline. One or more empty lines was also + * treated as a separate sentence. The Berkeley documentation for historical + * vi states that any number of ')', ']', '"' and '\'' characters can be + * between the delimiter character and the spaces or end of line, however, + * the historical implementation did not handle additional '"' characters. + * We follow the documentation here, not the implementation. + * + * Once again, historical vi didn't do sentence movements associated with + * counts consistently, mostly in the presence of lines containing only + * white-space characters. + * + * This implementation also permits a single tab to delimit sentences, and + * treats lines containing only white-space characters as empty lines. + * Finally, tabs are eaten (along with spaces) when skipping to the start + * of the text following a "sentence". + */ + +/* + * v_sentencef -- [count]) + * Move forward count sentences. + */ +int +v_sentencef(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + enum { BLANK, NONE, PERIOD } state; + VCS cs; + size_t len; + u_long cnt; + + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, ep, &cs)) + return (1); + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + + /* + * !!! + * If in white-space, the next start of sentence counts as one. + * This may not handle " . " correctly, but it's real unclear + * what correctly means in that case. + */ + if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) { + if (cs_fblank(sp, ep, &cs)) + return (1); + if (--cnt == 0) { + if (vp->m_start.lno != cs.cs_lno || + vp->m_start.cno != cs.cs_cno) + goto okret; + return (1); + } + } + + for (state = NONE;;) { + if (cs_next(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + break; + if (cs.cs_flags == CS_EOL) { + if ((state == PERIOD || state == BLANK) && --cnt == 0) { + if (cs_next(sp, ep, &cs)) + return (1); + if (cs.cs_flags == 0 && + isblank(cs.cs_ch) && cs_fblank(sp, ep, &cs)) + return (1); + goto okret; + } + state = NONE; + continue; + } + if (cs.cs_flags == CS_EMP) { /* An EMP is two sentences. */ + if (--cnt == 0) + goto okret; + if (cs_fblank(sp, ep, &cs)) + return (1); + if (--cnt == 0) + goto okret; + state = NONE; + continue; + } + switch (cs.cs_ch) { + case '.': + case '?': + case '!': + state = PERIOD; + break; + case ')': + case ']': + case '"': + case '\'': + if (state != PERIOD) + state = NONE; + break; + case '\t': + if (state == PERIOD) + state = BLANK; + /* FALLTHROUGH */ + case ' ': + if (state == PERIOD) { + state = BLANK; + break; + } + if (state == BLANK && --cnt == 0) { + if (cs_fblank(sp, ep, &cs)) + return (1); + goto okret; + } + /* FALLTHROUGH */ + default: + state = NONE; + break; + } + } + + /* EOF is a movement sink, but it's an error not to have moved. */ + if (vp->m_start.lno == cs.cs_lno && vp->m_start.cno == cs.cs_cno) { + v_eof(sp, ep, NULL); + return (1); + } + +okret: vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * !!! + * Historic, uh, features, yeah, that's right, call 'em features. + * If the ending cursor position is at the first column in the + * line, i.e. the movement is cutting an entire line, the buffer + * is in line mode, and the ending position is the last character + * of the previous line. + * + * Non-motion commands move to the end of the range. VC_D and + * VC_Y stay at the start. Ignore VC_C and VC_DEF. Adjust the + * end of the range for motion commands. + */ + if (ISMOTION(vp)) { + if (vp->m_start.cno == 0 && + (cs.cs_flags != 0 || vp->m_stop.cno == 0)) { + if (file_gline(sp, ep, + --vp->m_stop.lno, &len) == NULL) { + GETLINE_ERR(sp, vp->m_stop.lno); + return (1); + } + vp->m_stop.cno = len ? len - 1 : 0; + F_SET(vp, VM_LMODE); + } else + --vp->m_stop.cno; + vp->m_final = vp->m_start; + } else + vp->m_final = vp->m_stop; + return (0); +} + +/* + * v_sentenceb -- [count]( + * Move backward count sentences. + */ +int +v_sentenceb(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + VCS cs; + recno_t slno; + size_t len, scno; + u_long cnt; + int last; + + /* + * !!! + * Historic vi permitted the user to hit SOF repeatedly. + */ + if (vp->m_start.lno == 1 && vp->m_start.cno == 0) + return (0); + + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, ep, &cs)) + return (1); + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + + /* + * !!! + * In empty lines, skip to the previous non-white-space character. + * If in text, skip to the prevous white-space character. Believe + * it or not, in the paragraph: + * ab cd. + * AB CD. + * if the cursor is on the 'A' or 'B', ( moves to the 'a'. If it + * is on the ' ', 'C' or 'D', it moves to the 'A'. Yes, Virginia, + * Berkeley was once a major center of drug activity. + */ + if (cs.cs_flags == CS_EMP) { + if (cs_bblank(sp, ep, &cs)) + return (1); + for (;;) { + if (cs_prev(sp, ep, &cs)) + return (1); + if (cs.cs_flags != CS_EOL) + break; + } + } else if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) + for (;;) { + if (cs_prev(sp, ep, &cs)) + return (1); + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + break; + } + + for (last = 0;;) { + if (cs_prev(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) /* SOF is a movement sink. */ + break; + if (cs.cs_flags == CS_EOL) { + last = 1; + continue; + } + if (cs.cs_flags == CS_EMP) { + if (--cnt == 0) + goto ret; + if (cs_bblank(sp, ep, &cs)) + return (1); + last = 0; + continue; + } + switch (cs.cs_ch) { + case '.': + case '?': + case '!': + if (!last || --cnt != 0) { + last = 0; + continue; + } + +ret: slno = cs.cs_lno; + scno = cs.cs_cno; + + /* + * Move to the start of the sentence, skipping blanks + * and special characters. + */ + do { + if (cs_next(sp, ep, &cs)) + return (1); + } while (!cs.cs_flags && + (cs.cs_ch == ')' || cs.cs_ch == ']' || + cs.cs_ch == '"' || cs.cs_ch == '\'')); + if ((cs.cs_flags || isblank(cs.cs_ch)) && + cs_fblank(sp, ep, &cs)) + return (1); + + /* + * If it was ". xyz", with the cursor on the 'x', or + * "end. ", with the cursor in the spaces, or the + * beginning of a sentence preceded by an empty line, + * we can end up where we started. Fix it. + */ + if (vp->m_start.lno != cs.cs_lno || + vp->m_start.cno != cs.cs_cno) + goto okret; + + /* + * Well, if an empty line preceded possible blanks + * and the sentence, it could be a real sentence. + */ + for (;;) { + if (cs_prev(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOL) + continue; + if (cs.cs_flags == 0 && isblank(cs.cs_ch)) + continue; + break; + } + if (cs.cs_flags == CS_EMP) + goto okret; + + /* But it wasn't; try again. */ + ++cnt; + cs.cs_lno = slno; + cs.cs_cno = scno; + last = 0; + break; + case '\t': + last = 1; + break; + default: + last = + cs.cs_flags == CS_EOL || isblank(cs.cs_ch) || + cs.cs_ch == ')' || cs.cs_ch == ']' || + cs.cs_ch == '"' || cs.cs_ch == '\'' ? 1 : 0; + } + } + +okret: vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * !!! + * If the starting and stopping cursor positions are at the first + * columns in the line, i.e. the movement is cutting an entire line, + * the buffer is in line mode, and the starting position is the last + * character of the previous line. + * + * All commands move to the end of the range. Adjust the start of + * the range for motion commands. + */ + if (ISMOTION(vp)) + if (vp->m_start.cno == 0 && + (cs.cs_flags != 0 || vp->m_stop.cno == 0)) { + if (file_gline(sp, ep, + --vp->m_start.lno, &len) == NULL) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + vp->m_start.cno = len ? len - 1 : 0; + F_SET(vp, VM_LMODE); + } else + --vp->m_start.cno; + vp->m_final = vp->m_stop; + return (0); +} diff --git a/usr.bin/vi/vi/v_status.c b/usr.bin/vi/vi/v_status.c new file mode 100644 index 0000000..5ea544c --- /dev/null +++ b/usr.bin/vi/vi/v_status.c @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_status.c 8.16 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_status -- ^G + * Show the file status. + */ +int +v_status(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + + /* + * ^G in historic vi reset the cursor column to the first + * non-blank character in the line. This doesn't seem of + * any usefulness whatsoever, so I don't bother. + */ + return (msg_status(sp, ep, vp->m_start.lno, 1)); +} diff --git a/usr.bin/vi/vi/v_stop.c b/usr.bin/vi/vi/v_stop.c new file mode 100644 index 0000000..1e865d9 --- /dev/null +++ b/usr.bin/vi/vi/v_stop.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_stop.c 8.7 (Berkeley) 3/8/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_stop -- ^Z + * Suspend vi. + */ +int +v_stop(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* If autowrite is set, write out the file. */ + if (F_ISSET(ep, F_MODIFIED) && O_ISSET(sp, O_AUTOWRITE)) { + if (file_write(sp, ep, NULL, NULL, NULL, FS_ALL)) + return (1); + if (sp->s_refresh(sp, ep)) + return (1); + } + return (sp->s_suspend(sp)); +} diff --git a/usr.bin/vi/vi/v_text.c b/usr.bin/vi/vi/v_text.c new file mode 100644 index 0000000..e6c940a --- /dev/null +++ b/usr.bin/vi/vi/v_text.c @@ -0,0 +1,883 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_text.c 8.40 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * !!! + * Repeated input in the historic vi is mostly wrong and this isn't very + * backward compatible. For example, if the user entered "3Aab\ncd" in + * the historic vi, the "ab" was repeated 3 times, and the "\ncd" was then + * appended to the result. There was also a hack which I don't remember + * right now, where "3o" would open 3 lines and then let the user fill them + * in, to make screen movements on 300 baud modems more tolerable. I don't + * think it's going to be missed. + * + * !!! + * There's a problem with the way that we do logging for change commands with + * implied motions (e.g. A, I, O, cc, etc.). Since the main vi loop logs the + * starting cursor position before the change command "moves" the cursor, the + * cursor position to which we return on undo will be where the user entered + * the change command, not the start of the change. Several of the following + * routines re-log the cursor to make this work correctly. Historic vi tried + * to do the same thing, and mostly got it right. (The only spectacular way + * it fails is if the user entered 'o' from anywhere but the last character of + * the line, the undo returned the cursor to the start of the line. If the + * user was on the last character of the line, the cursor returned to that + * position.) We also check for mapped keys waiting, i.e. if we're in the + * middle of a map, don't bother logging the cursor. + */ +#define LOG_CORRECT { \ + if (!MAPPED_KEYS_WAITING(sp)) \ + (void)log_cursor(sp, ep); \ +} +#define LOG_CORRECT_FIRST { \ + if (first == 1) { \ + LOG_CORRECT; \ + first = 0; \ + } \ +} + +static u_int set_txt_std __P((SCR *, VICMDARG *, u_int)); +static int v_CS __P((SCR *, EXF *, VICMDARG *, u_int)); + +/* + * v_iA -- [count]A + * Append text to the end of the line. + */ +int +v_iA(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + u_long cnt; + size_t len; + u_int flags; + int first; + char *p; + + sp->showmode = "Append"; + flags = set_txt_std(sp, vp, TXT_APPENDEOL); + for (first = 1, lno = vp->m_start.lno, + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + /* Move the cursor to the end of the line + 1. */ + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, lno); + return (1); + } + lno = 1; + len = 0; + } else { + /* Correct logging for implied cursor motion. */ + if (first == 1) { + sp->cno = len == 0 ? 0 : len - 1; + LOG_CORRECT; + first = 0; + } + + /* Start the change after the line. */ + sp->cno = len; + } + + if (v_ntext(sp, ep, + sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags)) + return (1); + + flags = set_txt_std(sp, vp, TXT_APPENDEOL | TXT_REPLAY); + sp->lno = lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + } + return (0); +} + +/* + * v_ia -- [count]a + * Append text to the cursor position. + */ +int +v_ia(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + u_long cnt; + u_int flags; + size_t len; + char *p; + + sp->showmode = "Append"; + flags = set_txt_std(sp, vp, 0); + for (lno = vp->m_start.lno, + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + /* + * Move the cursor one column to the right and + * repaint the screen. + */ + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, lno); + return (1); + } + lno = 1; + len = 0; + LF_SET(TXT_APPENDEOL); + } else if (len) { + if (len == sp->cno + 1) { + sp->cno = len; + LF_SET(TXT_APPENDEOL); + } else + ++sp->cno; + } else + LF_SET(TXT_APPENDEOL); + + if (v_ntext(sp, ep, + sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags)) + return (1); + + flags = set_txt_std(sp, vp, TXT_REPLAY); + sp->lno = lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + } + return (0); +} + +/* + * v_iI -- [count]I + * Insert text at the first non-blank character in the line. + */ +int +v_iI(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + u_long cnt; + size_t len; + u_int flags; + int first; + char *p; + + sp->showmode = "Insert"; + flags = set_txt_std(sp, vp, 0); + for (first = 1, lno = vp->m_start.lno, + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + /* + * Move the cursor to the start of the line and repaint + * the screen. + */ + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, lno); + return (1); + } + lno = 1; + len = 0; + } else { + sp->cno = 0; + if (nonblank(sp, ep, lno, &sp->cno)) + return (1); + + /* Correct logging for implied cursor motion. */ + LOG_CORRECT_FIRST; + } + if (len == 0) + LF_SET(TXT_APPENDEOL); + + if (v_ntext(sp, ep, + sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags)) + return (1); + + flags = set_txt_std(sp, vp, TXT_REPLAY); + sp->lno = lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + } + return (0); +} + +/* + * v_ii -- [count]i + * Insert text at the cursor position. + */ +int +v_ii(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + u_long cnt; + size_t len; + u_int flags; + char *p; + + sp->showmode = "Insert"; + flags = set_txt_std(sp, vp, 0); + for (lno = vp->m_start.lno, + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + lno = 1; + len = 0; + } + /* If len == sp->cno, it's a replay caused by a count. */ + if (len == 0 || len == sp->cno) + LF_SET(TXT_APPENDEOL); + + if (v_ntext(sp, ep, + sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags)) + return (1); + + /* + * On replay, if the line isn't empty, advance the insert + * by one (make it an append). + */ + flags = set_txt_std(sp, vp, TXT_REPLAY); + sp->lno = lno = vp->m_final.lno; + if ((sp->cno = vp->m_final.cno) != 0) + ++sp->cno; + } + return (0); +} + +/* + * v_iO -- [count]O + * Insert text above this line. + */ +int +v_iO(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t ai_line, lno; + size_t len; + u_long cnt; + u_int flags; + int first; + char *p; + + sp->showmode = "Insert"; + flags = set_txt_std(sp, vp, TXT_APPENDEOL); + for (first = 1, cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + if (sp->lno == 1) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) + goto insert; + p = NULL; + len = 0; + ai_line = OOBLNO; + } else { +insert: p = ""; + sp->cno = 0; + + /* Correct logging for implied cursor motion. */ + LOG_CORRECT_FIRST; + + if (file_iline(sp, ep, sp->lno, p, 0)) + return (1); + if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) { + GETLINE_ERR(sp, sp->lno); + return (1); + } + ai_line = sp->lno + 1; + } + + if (v_ntext(sp, ep, + sp->tiqp, NULL, p, len, &vp->m_final, 0, ai_line, flags)) + return (1); + + flags = set_txt_std(sp, vp, TXT_APPENDEOL | TXT_REPLAY); + sp->lno = lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + } + return (0); +} + +/* + * v_io -- [count]o + * Insert text after this line. + */ +int +v_io(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t ai_line, lno; + size_t len; + u_long cnt; + u_int flags; + int first; + char *p; + + sp->showmode = "Insert"; + flags = set_txt_std(sp, vp, TXT_APPENDEOL); + for (first = 1, + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { + if (sp->lno == 1) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) + goto insert; + p = NULL; + len = 0; + ai_line = OOBLNO; + } else { +insert: p = ""; + sp->cno = 0; + + /* Correct logging for implied cursor motion. */ + LOG_CORRECT_FIRST; + + len = 0; + if (file_aline(sp, ep, 1, sp->lno, p, len)) + return (1); + if ((p = file_gline(sp, ep, ++sp->lno, &len)) == NULL) { + GETLINE_ERR(sp, sp->lno); + return (1); + } + ai_line = sp->lno - 1; + } + + if (v_ntext(sp, ep, + sp->tiqp, NULL, p, len, &vp->m_final, 0, ai_line, flags)) + return (1); + + flags = set_txt_std(sp, vp, TXT_APPENDEOL | TXT_REPLAY); + sp->lno = lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + } + return (0); +} + +/* + * v_Change -- [buffer][count]C + * Change line command. + */ +int +v_Change(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (v_CS(sp, ep, vp, 0)); +} + +/* + * v_Subst -- [buffer][count]S + * Line substitute command. + */ +int +v_Subst(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + u_int flags; + + /* + * The S command is the same as a 'C' command from the beginning + * of the line. This is hard to do in the parser, so do it here. + * + * If autoindent is on, the change is from the first *non-blank* + * character of the line, not the first character. And, to make + * it just a bit more exciting, the initial space is handled as + * auto-indent characters. + */ + LF_INIT(0); + if (O_ISSET(sp, O_AUTOINDENT)) { + vp->m_start.cno = 0; + if (nonblank(sp, ep, vp->m_start.lno, &vp->m_start.cno)) + return (1); + LF_SET(TXT_AICHARS); + } else + vp->m_start.cno = 0; + sp->cno = vp->m_start.cno; + return (v_CS(sp, ep, vp, flags)); +} + +/* + * v_CS -- + * C and S commands. + */ +static int +v_CS(sp, ep, vp, iflags) + SCR *sp; + EXF *ep; + VICMDARG *vp; + u_int iflags; +{ + MARK *tm; + recno_t lno; + size_t len; + char *p; + u_int flags; + + sp->showmode = "Change"; + flags = set_txt_std(sp, vp, iflags); + + /* + * There are two cases -- if a count is supplied, we do a line + * mode change where we delete the lines and then insert text + * into a new line. Otherwise, we replace the current line. + */ + vp->m_stop.lno = + vp->m_start.lno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0); + if (vp->m_start.lno != vp->m_stop.lno) { + /* Make sure that the to line is real. */ + if (file_gline(sp, ep, + vp->m_stop.lno, &vp->m_stop.cno) == NULL) { + v_eof(sp, ep, &vp->m_start); + return (1); + } + if (vp->m_stop.cno != 0) + --vp->m_stop.cno; + + /* + * Cut the lines. + * + * !!! + * Historic practice, C and S did not cut into the numeric + * buffers, only the unnamed one. + */ + if (cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, CUT_LINEMODE)) + return (1); + + /* Insert a line while we still can... */ + if (file_iline(sp, ep, vp->m_start.lno, "", 0)) + return (1); + ++vp->m_start.lno; + ++vp->m_stop.lno; + + /* Delete the lines. */ + if (delete(sp, ep, &vp->m_start, &vp->m_stop, 1)) + return (1); + + /* Get the inserted line. */ + if ((p = file_gline(sp, ep, --vp->m_start.lno, &len)) == NULL) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + tm = NULL; + sp->lno = vp->m_start.lno; + sp->cno = 0; + LF_SET(TXT_APPENDEOL); + } else { + /* The line may be empty, but that's okay. */ + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + vp->m_stop.cno = len = 0; + LF_SET(TXT_APPENDEOL); + } else { + if (len == 0) { + vp->m_stop.cno = 0; + LF_SET(TXT_APPENDEOL); + } else + vp->m_stop.cno = len - 1; + /* + * !!! + * Historic practice, C and S did not cut into the + * numeric buffers, only the unnamed one. + */ + if (cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, CUT_LINEMODE)) + return (1); + LF_SET(TXT_EMARK | TXT_OVERWRITE); + } + tm = &vp->m_stop; + } + + /* Correct logging for implied cursor motion. */ + LOG_CORRECT; + + return (v_ntext(sp, ep, + sp->tiqp, tm, p, len, &vp->m_final, 0, OOBLNO, flags)); +} + +/* + * v_change -- [buffer][count]c[count]motion + * Change command. + */ +int +v_change(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + size_t blen, len; + u_int flags; + int lmode, rval; + char *bp, *p; + + sp->showmode = "Change"; + flags = set_txt_std(sp, vp, 0); + + /* + * Move the cursor to the start of the change. Note, if autoindent + * is turned on, the cc command in line mode changes from the first + * *non-blank* character of the line, not the first character. And, + * to make it just a bit more exciting, the initial space is handled + * as auto-indent characters. + */ + lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0; + if (lmode) { + vp->m_start.cno = 0; + if (O_ISSET(sp, O_AUTOINDENT)) { + if (nonblank(sp, ep, vp->m_start.lno, &vp->m_start.cno)) + return (1); + LF_SET(TXT_AICHARS); + } + } + sp->lno = vp->m_start.lno; + sp->cno = vp->m_start.cno; + + /* Correct logging for implied cursor motion. */ + LOG_CORRECT; + + /* + * Turn off the VM_RCM flags, inserting text has its own rules for + * cursor positioning. + */ + F_CLR(vp, VM_RCM_MASK); + + /* + * If not in line mode and changing within a single line, the line + * either currently has text or it doesn't. If it doesn't, insert + * some. Otherwise, copy it and overwrite it. + */ + if (!lmode && vp->m_start.lno == vp->m_stop.lno) { + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (p == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + } + vp->m_stop.cno = len = 0; + LF_SET(TXT_APPENDEOL); + } else { + /* + * !!! + * Historic practice, c cut into the numeric buffers, + * as well as the unnamed one. + */ + if (cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, lmode | CUT_NUMOPT)) + return (1); + if (len == 0) + LF_SET(TXT_APPENDEOL); + LF_SET(TXT_EMARK | TXT_OVERWRITE); + } + return (v_ntext(sp, ep, sp->tiqp, + &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags)); + } + + /* + * It's trickier if changing over multiple lines. If we're in + * line mode we delete all of the lines and insert a replacement + * line which the user edits. If there was leading whitespace + * in the first line being changed, we copy it and use it as the + * replacement. If we're not in line mode, we just delete the + * text and start inserting. + * + * !!! + * Historic practice, c cut into the numeric buffers, as well as the + * unnamed one. + * + * Copy the text. + */ + if (cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, lmode | CUT_NUMOPT)) + return (1); + + /* If replacing entire lines and there's leading text. */ + if (lmode && vp->m_start.cno) { + /* Get a copy of the first line changed. */ + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + /* Copy the leading text elsewhere. */ + GET_SPACE_RET(sp, bp, blen, vp->m_start.cno); + memmove(bp, p, vp->m_start.cno); + } else + bp = NULL; + + /* Delete the text. */ + if (delete(sp, ep, &vp->m_start, &vp->m_stop, lmode)) + return (1); + + /* If replacing entire lines, insert a replacement line. */ + if (lmode) { + if (file_iline(sp, ep, vp->m_start.lno, bp, vp->m_start.cno)) + return (1); + sp->lno = vp->m_start.lno; + len = sp->cno = vp->m_start.cno; + } + + /* Get the line we're editing. */ + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + len = 0; + } + + /* Check to see if we're appending to the line. */ + if (vp->m_start.cno >= len) + LF_SET(TXT_APPENDEOL); + + rval = v_ntext(sp, ep, + sp->tiqp, NULL, p, len, &vp->m_final, 0, OOBLNO, flags); + + if (bp != NULL) + FREE_SPACE(sp, bp, blen); + return (rval); +} + +/* + * v_Replace -- [count]R + * Overwrite multiple characters. + */ +int +v_Replace(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + u_long cnt; + size_t len; + u_int flags; + char *p; + + sp->showmode = "Replace"; + flags = set_txt_std(sp, vp, 0); + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + len = 0; + LF_SET(TXT_APPENDEOL); + } else { + if (len == 0) + LF_SET(TXT_APPENDEOL); + LF_SET(TXT_OVERWRITE | TXT_REPLACE); + } + vp->m_stop.lno = vp->m_start.lno; + vp->m_stop.cno = len ? len - 1 : 0; + if (v_ntext(sp, ep, sp->tiqp, + &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags)) + return (1); + + /* + * Special case. The historic vi handled [count]R badly, in that R + * would replace some number of characters, and then the count would + * append count-1 copies of the replacing chars to the replaced space. + * This seems wrong, so this version counts R commands. There is some + * trickiness in moving back to where the user stopped replacing after + * each R command. Basically, if the user ended with a newline, we + * want to use vp->m_final.cno (which will be 0). Otherwise, use the + * column after the returned cursor, unless it would be past the end of + * the line, in which case we append to the line. + */ + while (--cnt) { + if ((p = file_gline(sp, ep, vp->m_final.lno, &len)) == NULL) + GETLINE_ERR(sp, vp->m_final.lno); + flags = set_txt_std(sp, vp, TXT_REPLAY); + + sp->lno = vp->m_final.lno; + + if (len == 0 || vp->m_final.cno == len - 1) { + sp->cno = len; + LF_SET(TXT_APPENDEOL); + } else { + sp->cno = vp->m_final.cno; + if (vp->m_final.cno != 0) + ++sp->cno; + LF_SET(TXT_OVERWRITE | TXT_REPLACE); + } + + vp->m_stop.lno = sp->lno; + vp->m_stop.cno = sp->cno; + if (v_ntext(sp, ep, sp->tiqp, + &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags)) + return (1); + } + return (0); +} + +/* + * v_subst -- [buffer][count]s + * Substitute characters. + */ +int +v_subst(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + size_t len; + u_int flags; + char *p; + + sp->showmode = "Change"; + flags = set_txt_std(sp, vp, 0); + if ((p = file_gline(sp, ep, vp->m_start.lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno != 0) { + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + len = 0; + LF_SET(TXT_APPENDEOL); + } else { + if (len == 0) + LF_SET(TXT_APPENDEOL); + LF_SET(TXT_EMARK | TXT_OVERWRITE); + } + + vp->m_stop.lno = vp->m_start.lno; + vp->m_stop.cno = + vp->m_start.cno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0); + if (vp->m_stop.cno > len - 1) + vp->m_stop.cno = len - 1; + + if (p != NULL && cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, 0)) + return (1); + + return (v_ntext(sp, ep, sp->tiqp, + &vp->m_stop, p, len, &vp->m_final, 0, OOBLNO, flags)); +} + +/* + * set_txt_std -- + * Initialize text processing flags. + */ +static u_int +set_txt_std(sp, vp, init) + SCR *sp; + VICMDARG *vp; + u_int init; +{ + u_int flags; + + /* Text operations are all interruptible. */ + F_SET(sp, S_INTERRUPTIBLE); + + LF_INIT(init); + LF_SET(TXT_CNTRLT | + TXT_ESCAPE | TXT_MAPINPUT | TXT_RECORD | TXT_RESOLVE); + if (O_ISSET(sp, O_ALTWERASE)) + LF_SET(TXT_ALTWERASE); + if (O_ISSET(sp, O_AUTOINDENT)) + LF_SET(TXT_AUTOINDENT); + if (O_ISSET(sp, O_BEAUTIFY)) + LF_SET(TXT_BEAUTIFY); + if (O_ISSET(sp, O_SHOWMATCH)) + LF_SET(TXT_SHOWMATCH); + if (O_ISSET(sp, O_WRAPMARGIN)) + LF_SET(TXT_WRAPMARGIN); + if (F_ISSET(sp, S_SCRIPT)) + LF_SET(TXT_CR); + if (O_ISSET(sp, O_TTYWERASE)) + LF_SET(TXT_TTYWERASE); + if (F_ISSET(vp, VC_ISDOT)) + LF_SET(TXT_REPLAY); + return (flags); +} diff --git a/usr.bin/vi/vi/v_ulcase.c b/usr.bin/vi/vi/v_ulcase.c new file mode 100644 index 0000000..9bf150f --- /dev/null +++ b/usr.bin/vi/vi/v_ulcase.c @@ -0,0 +1,208 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_ulcase.c 8.8 (Berkeley) 7/15/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +static int ulcase __P((SCR *, EXF *, + recno_t, CHAR_T *, size_t, size_t, size_t)); + +/* + * v_ulcase -- [count]~ + * Toggle upper & lower case letters. + * + * !!! + * Historic vi didn't permit ~ to cross newline boundaries. I can + * think of no reason why it shouldn't, which at least lets the user + * auto-repeat through a paragraph. + * + * !!! + * In historic vi, the count was ignored. It would have been better + * if there had been an associated motion, but it's too late to make + * that the default now. + */ +int +v_ulcase(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + size_t cno, lcnt, len; + u_long cnt; + char *p; + + lno = vp->m_start.lno; + cno = vp->m_start.cno; + + /* EOF is an infinite count sink. */ + for (cnt = + F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt > 0; cno = 0, ++lno) { + if ((p = file_gline(sp, ep, lno, &len)) == NULL) + break; + + /* Empty lines decrement the count by one. */ + if (len == 0) { + --cnt; + vp->m_final.lno = lno + 1; + vp->m_final.cno = 0; + } else { + if (cno + cnt >= len) { + lcnt = len - 1; + cnt -= len - cno; + + vp->m_final.lno = lno + 1; + vp->m_final.cno = 0; + } else { + lcnt = cno + cnt - 1; + cnt = 0; + + vp->m_final.lno = lno; + vp->m_final.cno = lcnt + 1; + } + + if (ulcase(sp, ep, lno, p, len, cno, lcnt)) + return (1); + } + } + + /* Check to see if we tried to move past EOF. */ + if (file_gline(sp, ep, vp->m_final.lno, &len) == NULL) { + (void)file_gline(sp, ep, --vp->m_final.lno, &len); + vp->m_final.cno = len == 0 ? 0 : len - 1; + } + return (0); +} + +/* + * v_mulcase -- [count]~[count]motion + * Toggle upper & lower case letters over a range. + */ +int +v_mulcase(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + CHAR_T *p; + size_t len; + recno_t lno; + + for (lno = vp->m_start.lno;;) { + if ((p = file_gline(sp, ep, lno, &len)) == NULL) { + GETLINE_ERR(sp, lno); + return (1); + } + if (len != 0 && + ulcase(sp, ep, lno, p, len, + lno == vp->m_start.lno ? vp->m_start.cno : 0, + !F_ISSET(vp, VM_LMODE) && + lno == vp->m_stop.lno ? vp->m_stop.cno : len)) + return (1); + + if (++lno > vp->m_stop.lno) + break; + } + + /* + * XXX + * I didn't create a new motion command when I added motion semantics + * for ~. While that's the correct way to do it, that choice would + * have required changes all over the vi directory for little gain. + * Instead, we pretend it's a yank command. Note, this means that we + * follow the cursor motion rules for yank commands, but that seems + * reasonable to me. + */ + return (0); +} + +/* + * ulcase -- + * Change part of a line's case. + */ +static int +ulcase(sp, ep, lno, lp, len, scno, ecno) + SCR *sp; + EXF *ep; + recno_t lno; + CHAR_T *lp; + size_t len, scno, ecno; +{ + size_t blen; + int change, rval; + CHAR_T ch, *p, *t; + char *bp; + + GET_SPACE_RET(sp, bp, blen, len); + memmove(bp, lp, len); + + change = rval = 0; + for (p = bp + scno, t = bp + ecno + 1; p < t; ++p) { + ch = *(u_char *)p; + if (islower(ch)) { + *p = toupper(ch); + change = 1; + } else if (isupper(ch)) { + *p = tolower(ch); + change = 1; + } + } + + if (change && file_sline(sp, ep, lno, bp, len)) + rval = 1; + + FREE_SPACE(sp, bp, blen); + return (rval); +} diff --git a/usr.bin/vi/vi/v_undo.c b/usr.bin/vi/vi/v_undo.c new file mode 100644 index 0000000..65dc715 --- /dev/null +++ b/usr.bin/vi/vi/v_undo.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_undo.c 8.10 (Berkeley) 5/7/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_Undo -- U + * Undo changes to this line. + */ +int +v_Undo(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* + * Historically, U reset the cursor to the first column in the line + * (not the first non-blank). This seems a bit non-intuitive, but, + * considering that we may have undone multiple changes, anything + * else (including the cursor position stored in the logging records) + * is going to appear random. + */ + vp->m_final.cno = 0; + + /* + * !!! + * Set up the flags so that an immediately subsequent 'u' will roll + * forward, instead of backward. In historic vi, a 'u' following a + * 'U' redid all of the changes to the line. Given that the user has + * explicitly discarded those changes by entering 'U', it seems likely + * that the user wants something between the original and end forms of + * the line, so starting to replay the changes seems the best way to + * get to there. + */ + F_SET(ep, F_UNDO); + ep->lundo = BACKWARD; + + return (log_setline(sp, ep)); +} + +/* + * v_undo -- u + * Undo the last change. + */ +int +v_undo(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* Set the command count. */ + VIP(sp)->u_ccnt = sp->ccnt; + + /* + * !!! + * In historic vi, 'u' toggled between "undo" and "redo", i.e. 'u' + * undid the last undo. However, if there has been a change since + * the last undo/redo, we always do an undo. To make this work when + * the user can undo multiple operations, we leave the old semantic + * unchanged, but make '.' after a 'u' do another undo/redo operation. + * This has two problems. + * + * The first is that 'u' didn't set '.' in historic vi. So, if a + * user made a change, realized it was in the wrong place, does a + * 'u' to undo it, moves to the right place and then does '.', the + * change was reapplied. To make this work, we only apply the '.' + * to the undo command if it's the command immediately following an + * undo command. See vi/vi.c:getcmd() for the details. + * + * The second is that the traditional way to view the numbered cut + * buffers in vi was to enter the commands "1pu.u.u.u. which will + * no longer work because the '.' immediately follows the 'u' command. + * Since we provide a much better method of viewing buffers, and + * nobody can think of a better way of adding in multiple undo, this + * remains broken. + * + * !!! + * There is change to historic practice for the final cursor position + * in this implementation. In historic vi, if an undo was isolated to + * a single line, the cursor moved to the start of the change, and + * then, subsequent 'u' commands would not move it again. (It has been + * pointed out that users used multiple undo commands to get the cursor + * to the start of the changed text.) Nvi toggles between the cursor + * position before and after the change was made. One final issue is + * that historic vi only did this if the user had not moved off of the + * line before entering the undo command; otherwise, vi would move the + * cursor to the most attractive position on the changed line. + * + * It would be difficult to match historic practice in this area. You + * not only have to know that the changes were isolated to one line, + * but whether it was the first or second undo command as well. And, + * to completely match historic practice, we'd have to track users line + * changes, too. This isn't worth the effort. + */ + if (!F_ISSET(ep, F_UNDO)) { + F_SET(ep, F_UNDO); + ep->lundo = BACKWARD; + } else if (!F_ISSET(vp, VC_ISDOT)) + ep->lundo = ep->lundo == BACKWARD ? FORWARD : BACKWARD; + + switch (ep->lundo) { + case BACKWARD: + return (log_backward(sp, ep, &vp->m_final)); + case FORWARD: + return (log_forward(sp, ep, &vp->m_final)); + default: + abort(); + } + /* NOTREACHED */ +} diff --git a/usr.bin/vi/vi/v_util.c b/usr.bin/vi/vi/v_util.c new file mode 100644 index 0000000..d7defa8 --- /dev/null +++ b/usr.bin/vi/vi/v_util.c @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_util.c 8.10 (Berkeley) 7/18/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_eof -- + * Vi end-of-file error. + */ +void +v_eof(sp, ep, mp) + SCR *sp; + EXF *ep; + MARK *mp; +{ + recno_t lno; + + if (mp == NULL) + msgq(sp, M_BERR, "Already at end-of-file"); + else { + if (file_lline(sp, ep, &lno)) + return; + if (mp->lno >= lno) + msgq(sp, M_BERR, "Already at end-of-file"); + else + msgq(sp, M_BERR, "Movement past the end-of-file"); + } +} + +/* + * v_eol -- + * Vi end-of-line error. + */ +void +v_eol(sp, ep, mp) + SCR *sp; + EXF *ep; + MARK *mp; +{ + size_t len; + + if (mp == NULL) + msgq(sp, M_BERR, "Already at end-of-line"); + else { + if (file_gline(sp, ep, mp->lno, &len) == NULL) { + GETLINE_ERR(sp, mp->lno); + return; + } + if (mp->cno == len - 1) + msgq(sp, M_BERR, "Already at end-of-line"); + else + msgq(sp, M_BERR, "Movement past the end-of-line"); + } +} + +/* + * v_nomove -- + * Vi no cursor movement error. + */ +void +v_nomove(sp) + SCR *sp; +{ + msgq(sp, M_BERR, "No cursor movement made"); +} + +/* + * v_sof -- + * Vi start-of-file error. + */ +void +v_sof(sp, mp) + SCR *sp; + MARK *mp; +{ + if (mp == NULL || mp->lno == 1) + msgq(sp, M_BERR, "Already at the beginning of the file"); + else + msgq(sp, M_BERR, "Movement past the beginning of the file"); +} + +/* + * v_sol -- + * Vi start-of-line error. + */ +void +v_sol(sp) + SCR *sp; +{ + msgq(sp, M_BERR, "Already in the first column"); +} + +/* + * v_isempty -- + * Return if the line contains nothing but white-space characters. + */ +int +v_isempty(p, len) + char *p; + size_t len; +{ + for (; len--; ++p) + if (!isblank(*p)) + return (0); + return (1); +} diff --git a/usr.bin/vi/vi/v_word.c b/usr.bin/vi/vi/v_word.c new file mode 100644 index 0000000..7c53fe9 --- /dev/null +++ b/usr.bin/vi/vi/v_word.c @@ -0,0 +1,570 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_word.c 8.21 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * There are two types of "words". Bigwords are easy -- groups of anything + * delimited by whitespace. Normal words are trickier. They are either a + * group of characters, numbers and underscores, or a group of anything but, + * delimited by whitespace. When for a word, if you're in whitespace, it's + * easy, just remove the whitespace and go to the beginning or end of the + * word. Otherwise, figure out if the next character is in a different group. + * If it is, go to the beginning or end of that group, otherwise, go to the + * beginning or end of the current group. The historic version of vi didn't + * get this right, so, for example, there were cases where "4e" was not the + * same as "eeee" -- in particular, single character words, and commands that + * began in whitespace were almost always handled incorrectly. To get it right + * you have to resolve the cursor after each search so that the look-ahead to + * figure out what type of "word" the cursor is in will be correct. + * + * Empty lines, and lines that consist of only white-space characters count + * as a single word, and the beginning and end of the file counts as an + * infinite number of words. + * + * Movements associated with commands are different than movement commands. + * For example, in "abc def", with the cursor on the 'a', "cw" is from + * 'a' to 'c', while "w" is from 'a' to 'd'. In general, trailing white + * space is discarded from the change movement. Another example is that, + * in the same string, a "cw" on any white space character replaces that + * single character, and nothing else. Ain't nothin' in here that's easy. + * + * One historic note -- in the original vi, the 'w', 'W' and 'B' commands + * would treat groups of empty lines as individual words, i.e. the command + * would move the cursor to each new empty line. The 'e' and 'E' commands + * would treat groups of empty lines as a single word, i.e. the first use + * would move past the group of lines. The 'b' command would just beep at + * you, or, if you did it from the start of the line as part of a motion + * command, go absolutely nuts. If the lines contained only white-space + * characters, the 'w' and 'W' commands would just beep at you, and the 'B', + * 'b', 'E' and 'e' commands would treat the group as a single word, and + * the 'B' and 'b' commands will treat the lines as individual words. This + * implementation treats all of these cases as a single white-space word. + */ + +enum which {BIGWORD, LITTLEWORD}; + +static int bword __P((SCR *, EXF *, VICMDARG *, enum which)); +static int eword __P((SCR *, EXF *, VICMDARG *, enum which)); +static int fword __P((SCR *, EXF *, VICMDARG *, enum which)); + +/* + * v_wordW -- [count]W + * Move forward a bigword at a time. + */ +int +v_wordW(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (fword(sp, ep, vp, BIGWORD)); +} + +/* + * v_wordw -- [count]w + * Move forward a word at a time. + */ +int +v_wordw(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (fword(sp, ep, vp, LITTLEWORD)); +} + +/* + * fword -- + * Move forward by words. + */ +static int +fword(sp, ep, vp, type) + SCR *sp; + EXF *ep; + VICMDARG *vp; + enum which type; +{ + enum { INWORD, NOTWORD } state; + VCS cs; + u_long cnt; + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, ep, &cs)) + return (1); + + /* + * If in white-space: + * If the count is 1, and it's a change command, we're done. + * Else, move to the first non-white-space character, which + * counts as a single word move. If it's a motion command, + * don't move off the end of the line. + */ + if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) { + if (cs.cs_flags != CS_EMP && cnt == 1) { + if (F_ISSET(vp, VC_C)) + return (0); + if (F_ISSET(vp, VC_D | VC_Y)) { + if (cs_fspace(sp, ep, &cs)) + return (1); + goto ret; + } + } + if (cs_fblank(sp, ep, &cs)) + return (1); + --cnt; + } + + /* + * Cyclically move to the next word -- this involves skipping + * over word characters and then any trailing non-word characters. + * Note, for the 'w' command, the definition of a word keeps + * switching. + */ + if (type == BIGWORD) + while (cnt--) { + for (;;) { + if (cs_next(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + break; + } + /* + * If a motion command and we're at the end of the + * last word, we're done. Delete and yank eat any + * trailing blanks, but we don't move off the end + * of the line regardless. + */ + if (cnt == 0 && ISMOTION(vp)) { + if (F_ISSET(vp, VC_D | VC_Y) && + cs_fspace(sp, ep, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs_fblank(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + } + else + while (cnt--) { + state = cs.cs_flags == 0 && + inword(cs.cs_ch) ? INWORD : NOTWORD; + for (;;) { + if (cs_next(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + break; + if (state == INWORD) { + if (!inword(cs.cs_ch)) + break; + } else + if (inword(cs.cs_ch)) + break; + } + /* See comment above. */ + if (cnt == 0 && ISMOTION(vp)) { + if (F_ISSET(vp, VC_D | VC_Y) && + cs_fspace(sp, ep, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + if (cs_fblank(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + } + + /* + * If we didn't move, we must be at EOF. + * + * !!! + * That's okay for motion commands, however. + */ +ret: if (!ISMOTION(vp) && + cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) { + v_eof(sp, ep, &vp->m_start); + return (1); + } + + /* Adjust the end of the range for motion commands. */ + vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + if (ISMOTION(vp) && cs.cs_flags == 0) + --vp->m_stop.cno; + + /* + * Non-motion commands move to the end of the range. VC_D + * and VC_Y stay at the start. Ignore VC_C and VC_DEF. + */ + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_wordE -- [count]E + * Move forward to the end of the bigword. + */ +int +v_wordE(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (eword(sp, ep, vp, BIGWORD)); +} + +/* + * v_worde -- [count]e + * Move forward to the end of the word. + */ +int +v_worde(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (eword(sp, ep, vp, LITTLEWORD)); +} + +/* + * eword -- + * Move forward to the end of the word. + */ +static int +eword(sp, ep, vp, type) + SCR *sp; + EXF *ep; + VICMDARG *vp; + enum which type; +{ + enum { INWORD, NOTWORD } state; + VCS cs; + u_long cnt; + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, ep, &cs)) + return (1); + + /* + * !!! + * If in whitespace, or the next character is whitespace, move past + * it. (This doesn't count as a word move.) Stay at the character + * past the current one, it sets word "state" for the 'e' command. + */ + if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) { + if (cs_next(sp, ep, &cs)) + return (1); + if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) + goto start; + } + if (cs_fblank(sp, ep, &cs)) + return (1); + + /* + * Cyclically move to the next word -- this involves skipping + * over word characters and then any trailing non-word characters. + * Note, for the 'e' command, the definition of a word keeps + * switching. + */ +start: if (type == BIGWORD) + while (cnt--) { + for (;;) { + if (cs_next(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + break; + } + /* + * When we reach the start of the word after the last + * word, we're done. If we changed state, back up one + * to the end of the previous word. + */ + if (cnt == 0) { + if (cs.cs_flags == 0 && cs_prev(sp, ep, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs_fblank(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + } + else + while (cnt--) { + state = cs.cs_flags == 0 && + inword(cs.cs_ch) ? INWORD : NOTWORD; + for (;;) { + if (cs_next(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + break; + if (state == INWORD) { + if (!inword(cs.cs_ch)) + break; + } else + if (inword(cs.cs_ch)) + break; + } + /* See comment above. */ + if (cnt == 0) { + if (cs.cs_flags == 0 && cs_prev(sp, ep, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + if (cs_fblank(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_EOF) + goto ret; + } + + /* + * If we didn't move, we must be at EOF. + * + * !!! + * That's okay for motion commands, however. + */ +ret: if (!ISMOTION(vp) && + cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) { + v_eof(sp, ep, &vp->m_start); + return (1); + } + + /* Set the end of the range for motion commands. */ + vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * Non-motion commands move to the end of the range. VC_D + * and VC_Y stay at the start. Ignore VC_C and VC_DEF. + */ + vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; + return (0); +} + +/* + * v_WordB -- [count]B + * Move backward a bigword at a time. + */ +int +v_wordB(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (bword(sp, ep, vp, BIGWORD)); +} + +/* + * v_wordb -- [count]b + * Move backward a word at a time. + */ +int +v_wordb(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + return (bword(sp, ep, vp, LITTLEWORD)); +} + +/* + * bword -- + * Move backward by words. + */ +static int +bword(sp, ep, vp, type) + SCR *sp; + EXF *ep; + VICMDARG *vp; + enum which type; +{ + enum { INWORD, NOTWORD } state; + VCS cs; + u_long cnt; + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + cs.cs_lno = vp->m_start.lno; + cs.cs_cno = vp->m_start.cno; + if (cs_init(sp, ep, &cs)) + return (1); + + /* + * !!! + * If in whitespace, or the previous character is whitespace, move + * past it. (This doesn't count as a word move.) Stay at the + * character before the current one, it sets word "state" for the + * 'b' command. + */ + if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) { + if (cs_prev(sp, ep, &cs)) + return (1); + if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) + goto start; + } + if (cs_bblank(sp, ep, &cs)) + return (1); + + /* + * Cyclically move to the beginning of the previous word -- this + * involves skipping over word characters and then any trailing + * non-word characters. Note, for the 'b' command, the definition + * of a word keeps switching. + */ +start: if (type == BIGWORD) + while (cnt--) { + for (;;) { + if (cs_prev(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) + goto ret; + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + break; + } + /* + * When we reach the end of the word before the last + * word, we're done. If we changed state, move forward + * one to the end of the next word. + */ + if (cnt == 0) { + if (cs.cs_flags == 0 && cs_next(sp, ep, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs_bblank(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) + goto ret; + } + else + while (cnt--) { + state = cs.cs_flags == 0 && + inword(cs.cs_ch) ? INWORD : NOTWORD; + for (;;) { + if (cs_prev(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) + goto ret; + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + break; + if (state == INWORD) { + if (!inword(cs.cs_ch)) + break; + } else + if (inword(cs.cs_ch)) + break; + } + /* See comment above. */ + if (cnt == 0) { + if (cs.cs_flags == 0 && cs_next(sp, ep, &cs)) + return (1); + break; + } + + /* Eat whitespace characters. */ + if (cs.cs_flags != 0 || isblank(cs.cs_ch)) + if (cs_bblank(sp, ep, &cs)) + return (1); + if (cs.cs_flags == CS_SOF) + goto ret; + } + + /* If we didn't move, we must be at SOF. */ +ret: if (cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) { + v_sof(sp, &vp->m_start); + return (1); + } + + /* Set the end of the range for motion commands. */ + vp->m_stop.lno = cs.cs_lno; + vp->m_stop.cno = cs.cs_cno; + + /* + * All commands move to the end of the range. Motion commands + * adjust the starting point to the character before the current + * one. + * + * !!! + * The historic vi didn't get this right -- the `yb' command yanked + * the right stuff and even updated the cursor value, but the cursor + * was not actually updated on the screen. + */ + vp->m_final = vp->m_stop; + if (ISMOTION(vp)) + --vp->m_start.cno; + return (0); +} diff --git a/usr.bin/vi/vi/v_xchar.c b/usr.bin/vi/vi/v_xchar.c new file mode 100644 index 0000000..6bb317c --- /dev/null +++ b/usr.bin/vi/vi/v_xchar.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_xchar.c 8.8 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_xchar -- [count]x + * Deletes the character(s) on which the cursor sits. + */ +int +v_xchar(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t lno; + size_t len; + + if (file_gline(sp, ep, vp->m_start.lno, &len) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) + goto nodel; + GETLINE_ERR(sp, vp->m_start.lno); + return (1); + } + if (len == 0) { +nodel: msgq(sp, M_BERR, "No characters to delete"); + return (1); + } + + /* + * Delete from the cursor toward the end of line, w/o moving the + * cursor. + * + * !!! + * Note, "2x" at EOL isn't the same as "xx" because the left movement + * of the cursor as part of the 'x' command isn't taken into account. + * Historically correct. + */ + if (F_ISSET(vp, VC_C1SET)) + vp->m_stop.cno += vp->count - 1; + if (vp->m_stop.cno >= len - 1) { + vp->m_stop.cno = len - 1; + vp->m_final.cno = vp->m_start.cno ? vp->m_start.cno - 1 : 0; + } else + vp->m_final.cno = vp->m_start.cno; + + if (cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, 0)) + return (1); + return (delete(sp, ep, &vp->m_start, &vp->m_stop, 0)); +} + +/* + * v_Xchar -- [count]X + * Deletes the character(s) immediately before the current cursor + * position. + */ +int +v_Xchar(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + u_long cnt; + + if (vp->m_start.cno == 0) { + v_sol(sp); + return (1); + } + + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (cnt >= vp->m_start.cno) + vp->m_start.cno = 0; + else + vp->m_start.cno -= cnt; + --vp->m_stop.cno; + vp->m_final.cno = vp->m_start.cno; + + if (cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, 0)) + return (1); + return (delete(sp, ep, &vp->m_start, &vp->m_stop, 0)); +} diff --git a/usr.bin/vi/vi/v_yank.c b/usr.bin/vi/vi/v_yank.c new file mode 100644 index 0000000..14f99f5 --- /dev/null +++ b/usr.bin/vi/vi/v_yank.c @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_yank.c 8.14 (Berkeley) 5/17/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_yank -- [buffer][count]Y + * [buffer][count]y[count][motion] + * Yank text (or lines of text) into a cut buffer. + * + * !!! + * Historic vi moved the cursor to the from MARK if it was before the current + * cursor and on a different line, e.g., "yj" moves the cursor but "yk" and + * "yh" do not. Unfortunately, it's too late to change this now. Matching + * the historic semantics isn't easy. The line number was always changed and + * column movement was usually relative. However, "y'a" moved the cursor to + * the first non-blank of the line marked by a, while "y`a" moved the cursor + * to the line and column marked by a. Hopefully, the motion component code + * got it right... Unlike delete, we make no adjustments here. + */ +int +v_yank(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + int lmode; + + /* The line may not exist in line mode cuts, check to be sure. */ + if (F_ISSET(vp, VM_LMODE)) { + if (file_gline(sp, ep, vp->m_stop.lno, NULL) == NULL) { + v_eof(sp, ep, &vp->m_start); + return (1); + } + lmode = CUT_LINEMODE; + } else + lmode = 0; + if (cut(sp, ep, + F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_stop, lmode)) + return (1); + + sp->rptlines[L_YANKED] += (vp->m_stop.lno - vp->m_start.lno) + 1; + return (0); +} diff --git a/usr.bin/vi/vi/v_z.c b/usr.bin/vi/vi/v_z.c new file mode 100644 index 0000000..ca780f4 --- /dev/null +++ b/usr.bin/vi/vi/v_z.c @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_z.c 8.16 (Berkeley) 7/17/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * v_z -- [count]z[count][-.+^<CR>] + * Move the screen. + */ +int +v_z(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + recno_t last, lno; + u_int value; + + /* + * The first count is the line to use. If the value doesn't + * exist, use the last line. + */ + if (F_ISSET(vp, VC_C1SET)) { + lno = vp->count; + if (file_lline(sp, ep, &last)) + return (1); + if (lno > last) + lno = last; + } else + lno = vp->m_start.lno; + + /* Set default return cursor values. */ + vp->m_final.lno = lno; + vp->m_final.cno = vp->m_start.cno; + + /* + * The second count is the displayed window size, i.e. the 'z' + * command is another way to get artificially small windows. + * + * !!! + * A window size of 0 was historically allowed, and simply ignored. + * Also, this could be much more simply done by modifying the value + * of the O_WINDOW option, but that's not how it worked historically. + */ + if (F_ISSET(vp, VC_C2SET) && + vp->count2 != 0 && sp->s_crel(sp, vp->count2)) + return (1); + + switch (vp->character) { + case '-': /* Put the line at the bottom. */ + if (sp->s_fill(sp, ep, lno, P_BOTTOM)) + return (1); + break; + case '.': /* Put the line in the middle. */ + if (sp->s_fill(sp, ep, lno, P_MIDDLE)) + return (1); + break; + case '+': + /* + * If the user specified a line number, put that line at the + * top and move the cursor to it. Otherwise, scroll forward + * a screen from the current screen. + */ + if (F_ISSET(vp, VC_C1SET)) { + if (sp->s_fill(sp, ep, lno, P_TOP)) + return (1); + if (sp->s_position(sp, ep, &vp->m_final, 0, P_TOP)) + return (1); + } else + if (sp->s_scroll(sp, ep, + &vp->m_final, sp->t_rows, Z_PLUS)) + return (1); + break; + case '^': + /* + * If the user specified a line number, put that line at the + * bottom, move the cursor to it, and then display the screen + * before that one. Otherwise, scroll backward a screen from + * the current screen. + * + * !!! + * Note, we match the off-by-one characteristics of historic + * vi, here. + */ + if (F_ISSET(vp, VC_C1SET)) { + if (sp->s_fill(sp, ep, lno, P_BOTTOM)) + return (1); + if (sp->s_position(sp, ep, &vp->m_final, 0, P_TOP)) + return (1); + if (sp->s_fill(sp, ep, vp->m_final.lno, P_BOTTOM)) + return (1); + } else + if (sp->s_scroll(sp, ep, + &vp->m_final, sp->t_rows, Z_CARAT)) + return (1); + break; + default: /* Put the line at the top for <cr>. */ + value = KEY_VAL(sp, vp->character); + if (value != K_CR && value != K_NL) { + msgq(sp, M_ERR, "usage: %s", vp->kp->usage); + return (1); + } + if (sp->s_fill(sp, ep, lno, P_TOP)) + return (1); + break; + } + + + return (0); +} diff --git a/usr.bin/vi/vi/v_zexit.c b/usr.bin/vi/vi/v_zexit.c new file mode 100644 index 0000000..cd4aac7 --- /dev/null +++ b/usr.bin/vi/vi/v_zexit.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v_zexit.c 8.11 (Berkeley) 8/4/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "excmd.h" +#include "vcmd.h" + +/* + * v_zexit -- ZZ + * Save the file and exit. + */ +int +v_zexit(sp, ep, vp) + SCR *sp; + EXF *ep; + VICMDARG *vp; +{ + /* Write back any modifications. */ + if (F_ISSET(ep, F_MODIFIED) && + file_write(sp, ep, NULL, NULL, NULL, FS_ALL)) + return (1); + + /* Check to make sure it's not a temporary file. */ + if (file_m3(sp, ep, 0)) + return (1); + + /* Check for more files to edit. */ + if (ex_ncheck(sp, 0)) + return (1); + + F_SET(sp, S_EXIT); + return (0); +} diff --git a/usr.bin/vi/vi/vcmd.c b/usr.bin/vi/vi/vcmd.c new file mode 100644 index 0000000..59b6e8b --- /dev/null +++ b/usr.bin/vi/vi/vcmd.c @@ -0,0 +1,533 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)vcmd.c 8.39 (Berkeley) 7/28/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +/* + * This array maps keystrokes to vi command functions. It is known + * in ex/ex_usage.c that it takes four columns to name a vi character. + */ +VIKEYS const vikeys [MAXVIKEY + 1] = { +/* 000 NUL -- The code in vi.c expects key 0 to be undefined. */ + {NULL}, +/* 001 ^A */ + {v_searchw, V_ABS|V_CNT|V_MOVE|V_KEYW|VM_CUTREQ|VM_RCM_SET, + "[count]^A", + "^A search forward for cursor word"}, +/* 002 ^B */ + {v_pageup, V_CNT|VM_RCM_SET, + "[count]^B", + "^B scroll up by screens"}, +/* 003 ^C */ + {NULL, 0, + "^C", + "^C interrupt an operation (e.g. read, write, search)"}, +/* 004 ^D */ + {v_hpagedown, V_CNT|VM_RCM_SET, + "[count]^D", + "^D scroll down by half screens (setting count)"}, +/* 005 ^E */ + {v_linedown, V_CNT, + "[count]^E", + "^E scroll down by lines"}, +/* 006 ^F */ + {v_pagedown, V_CNT|VM_RCM_SET, + "[count]^F", + "^F scroll down by screens"}, +/* 007 ^G */ + {v_status, 0, + "^G", + "^G file status"}, +/* 010 ^H */ + {v_left, V_CNT|V_MOVE|VM_RCM_SET, + "[count]^H", + "^H move left by characters"}, +/* 011 ^I */ + {NULL}, +/* 012 ^J */ + {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]^J", + "^J move down by lines"}, +/* 013 ^K */ + {NULL}, +/* 014 ^L */ + {v_redraw, 0, + "^L", + "^L redraw screen"}, +/* 015 ^M */ + {v_cr, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, + "[count]^M", + "^M move down by lines (to first non-blank)"}, +/* 016 ^N */ + {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]^N", + "^N move down by lines"}, +/* 017 ^O */ + {NULL}, +/* 020 ^P */ + {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]^P", + "^P move up by lines"}, +/* 021 ^Q -- not available, used for hardware flow control. */ + {NULL}, +/* 022 ^R */ + {v_redraw, 0, + "^R", + "^R redraw screen"}, +/* 023 ^S -- not available, used for hardware flow control. */ + {NULL}, +/* 024 ^T */ + {v_tagpop, V_ABS|VM_RCM_SET, + "^T", + "^T tag pop"}, +/* 025 ^U */ + {v_hpageup, V_CNT|VM_RCM_SET, + "[count]^U", + "^U half page up (set count)"}, +/* 026 ^V */ + {NULL, 0, + "^V", + "^V input a literal character"}, +/* 027 ^W */ + {v_screen, 0, + "^W", + "^W move to next screen"}, +/* 030 ^X */ + {NULL}, +/* 031 ^Y */ + {v_lineup, V_CNT, + "[count]^Y", + "^Y page up by lines"}, +/* 032 ^Z */ + {v_stop, 0, + "^Z", + "^Z suspend editor"}, +/* 033 ^[ */ + {NULL, 0, + "^[ <escape>", + "^[ <escape> leave input mode, return to command mode"}, +/* 034 ^\ */ + {v_exmode, 0, + "^\\", + " ^\\ switch to ex mode"}, +/* 035 ^] */ + {v_tagpush, V_ABS|V_KEYW|VM_RCM_SET, + "^]", + "^] tag push cursor word"}, +/* 036 ^^ */ + {v_switch, 0, + "^^", + "^^ switch to previous file"}, +/* 037 ^_ */ + {NULL}, +/* 040 ' ' */ + {v_right, V_CNT|V_MOVE|VM_RCM_SET, + "[count]' '", + " <space> move right by columns"}, +/* 041 ! */ + {v_filter, V_CNT|V_DOT|V_MOTION|VC_DEF|VM_RCM_SET, + "[count]![count]motion command(s)", + " ! filter through command(s) to motion"}, +/* 042 " */ + {NULL}, +/* 043 # */ + {v_increment, V_CHAR|V_CNT|V_DOT|V_KEYNUM|VM_RCM_SET, + "[count]#[#+-]", + " # number increment/decrement"}, +/* 044 $ */ + {v_dollar, V_CNT|V_MOVE|VM_RCM_SETLAST, + " [count]$", + " $ move to last column"}, +/* 045 % */ + {v_match, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "%", + " % move to match"}, +/* 046 & */ + {v_again, 0, + "&", + " & repeat substitution"}, +/* 047 ' */ + {v_fmark, V_ABS_L|V_CHAR|V_MOVE|VM_LMODE, + "'['a-z]", + " ' move to mark (to first non-blank)"}, +/* 050 ( */ + {v_sentenceb, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "[count](", + " ( move back sentence"}, +/* 051 ) */ + {v_sentencef, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "[count])", + " ) move forward sentence"}, +/* 052 * */ + {NULL}, +/* 053 + */ + {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, + "[count]+", + " + move down by lines (to first non-blank)"}, +/* 054 , */ + {v_chrrepeat, V_CNT|V_MOVE|VM_RCM_SET, + "[count],", + " , reverse last F, f, T or t search"}, +/* 055 - */ + {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, + "[count]-", + " - move up by lines (to first non-blank)"}, +/* 056 . */ + {NULL, 0, + ".", + " . repeat the last command"}, +/* 057 / */ + {v_searchf, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "/RE[/ offset]", + " / search forward"}, +/* 060 0 */ + {v_zero, V_MOVE|VM_RCM_SET, + "0", + " 0 move to first character"}, +/* 061 1 */ + {NULL}, +/* 062 2 */ + {NULL}, +/* 063 3 */ + {NULL}, +/* 064 4 */ + {NULL}, +/* 065 5 */ + {NULL}, +/* 066 6 */ + {NULL}, +/* 067 7 */ + {NULL}, +/* 070 8 */ + {NULL}, +/* 071 9 */ + {NULL}, +/* 072 : */ + {v_ex, 0, + ":command [| command] ...", + " : ex command"}, +/* 073 ; */ + {v_chrepeat, V_CNT|V_MOVE|VM_RCM_SET, + "[count];", + " ; repeat last F, f, T or t search"}, +/* 074 < */ + {v_shiftl, V_CNT|V_DOT|V_MOTION|VC_DEF|VM_RCM_SET, + "[count]<[count]motion", + " < shift lines left to motion"}, +/* 075 = */ + {NULL}, +/* 076 > */ + {v_shiftr, V_CNT|V_DOT|V_MOTION|VC_DEF|VM_RCM_SET, + "[count]>[count]motion", + " > shift lines right to motion"}, +/* 077 ? */ + {v_searchb, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "?RE[? offset]", + " ? search backward"}, +/* 100 @ */ + {v_at, V_RBUF|VM_RCM_SET, + "@buffer", + " @ execute buffer"}, +/* 101 A */ + {v_iA, V_CNT|V_DOT|VM_RCM_SET, + "[count]A", + " A append to the line"}, +/* 102 B */ + {v_wordB, V_CNT|V_MOVE|VM_RCM_SET, + "[count]B", + " B move back bigword"}, +/* 103 C */ + {v_Change, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer][count]C", + " C change to end-of-line"}, +/* 104 D */ + {v_Delete, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer][count]D", + " D delete to end-of-line"}, +/* 105 E */ + {v_wordE, V_CNT|V_MOVE|VM_RCM_SET, + "[count]E", + " E move to end of bigword"}, +/* 106 F */ + {v_chF, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, + "[count]F character", + " F character in line backward search"}, +/* 107 G */ + {v_lgoto, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, + "[count]G", + " G move to line"}, +/* 110 H */ + {v_home, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, + "[count]H", + " H move to count lines from screen top"}, +/* 111 I */ + {v_iI, V_CNT|V_DOT|VM_RCM_SET, + "[count]I", + " I insert at line beginning"}, +/* 112 J */ + {v_join, V_CNT|V_DOT|VM_RCM_SET, + "[count]J", + " J join lines"}, +/* 113 K */ + {NULL}, +/* 114 L */ + {v_bottom, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, + "[count]L", + " L move to screen bottom"}, +/* 115 M */ + {v_middle, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, + "M", + " M move to screen middle"}, +/* 116 N */ + {v_searchN, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "n", + " N reverse last search"}, +/* 117 O */ + {v_iO, V_CNT|V_DOT|VM_RCM_SET, + "[count]O", + " O insert above line"}, +/* 120 P */ + {v_Put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer]P", + " P insert before cursor from buffer"}, +/* 121 Q */ + {v_exmode, 0, + "Q", + " Q switch to ex mode"}, +/* 122 R */ + {v_Replace, V_CNT|V_DOT|VM_RCM_SET, + "[count]R", + " R replace characters"}, +/* 123 S */ + {v_Subst, V_CNT|V_DOT|V_OBUF|VM_LMODE|VM_RCM_SET, + "[buffer][count]S", + " S substitute for the line(s)"}, +/* 124 T */ + {v_chT, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, + "[count]T character", + " T before character in line backward search"}, +/* 125 U */ + {v_Undo, VM_RCM_SET, + "U", + " U Restore the current line"}, +/* 126 V */ + {NULL}, +/* 127 W */ + {v_wordW, V_CNT|V_MOVE|VM_RCM_SET, + "[count]W", + " W move to next bigword"}, +/* 130 X */ + {v_Xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer][count]X", + " X delete character before cursor"}, +/* 131 Y */ + {v_yank, V_CNT|VM_LMODE|V_OBUF, + "[buffer][count]Y", + " Y copy line"}, +/* 132 Z */ + {v_zexit, 0, + "ZZ", + "ZZ save file and exit"}, +/* 133 [ */ + {v_sectionb, V_ABS|V_CNT|V_MOVE|VM_RCM_SET, + "[[", + "[[ move back section"}, +/* 134 \ */ + {NULL}, +/* 135 ] */ + {v_sectionf, V_ABS|V_CNT|V_MOVE|VM_RCM_SET, + "]]", + "]] move forward section"}, +/* 136 ^ */ + /* + * DON'T set the VM_RCM_SETFNB flag, the function has to do the work + * anyway, in case it's a motion component. DO set VM_RCM_SET, so + * that any motion that's part of a command is preserved. + */ + {v_first, V_CNT|V_MOVE|VM_RCM_SET, + "^", + " ^ move to first non-blank"}, +/* 137 _ */ + /* + * Needs both to set the VM_RCM_SETFNB flag, and to do the work + * in the function, in case it's a delete. + */ + {v_cfirst, V_CNT|V_MOVE|VM_RCM_SETFNB, + "_", + " _ move to first non-blank"}, +/* 140 ` */ + {v_bmark, V_ABS_C|V_CHAR|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "`[`a-z]", + " ` move to mark"}, +/* 141 a */ + {v_ia, V_CNT|V_DOT|VM_RCM_SET, + "[count]a", + " a append after cursor"}, +/* 142 b */ + {v_wordb, V_CNT|V_MOVE|VM_RCM_SET, + "[count]b", + " b move back word"}, +/* 143 c */ + {v_change, V_CNT|V_DOT|V_MOTION|V_OBUF|VC_C|VM_RCM_SET, + "[buffer][count]c[count]motion", + " c change to motion"}, +/* 144 d */ + {v_delete, V_CNT|V_DOT|V_MOTION|V_OBUF|VC_D|VM_RCM_SET, + "[buffer][count]d[count]motion", + " d delete to motion"}, +/* 145 e */ + {v_worde, V_CNT|V_MOVE|VM_RCM_SET, + "[count]e", + " e move to end of word"}, +/* 146 f */ + {v_chf, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, + "[count]f character", + " f character in line forward search"}, +/* 147 g */ + {NULL}, +/* 150 h */ + {v_left, V_CNT|V_MOVE|VM_RCM_SET, + "[count]h", + " h move left by columns"}, +/* 151 i */ + {v_ii, V_CNT|V_DOT|VM_RCM_SET, + "[count]i", + " i insert before cursor"}, +/* 152 j */ + {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]j", + " j move down by lines"}, +/* 153 k */ + {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM, + "[count]k", + " k move up by lines"}, +/* 154 l */ + {v_right, V_CNT|V_MOVE|VM_RCM_SET, + "[count]l", + " l move right by columns"}, +/* 155 m */ + {v_mark, V_CHAR, + "m[a-z]", + " m set mark"}, +/* 156 n */ + {v_searchn, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "n", + " n repeat last search"}, +/* 157 o */ + {v_io, V_CNT|V_DOT|VM_RCM_SET, + "[count]o", + " o append after line"}, +/* 160 p */ + {v_put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer]p", + " p insert after cursor from buffer"}, +/* 161 q */ + {NULL}, +/* 162 r */ + {v_replace, V_CNT|V_DOT|VM_RCM_SET, + "[count]r character", + " r replace character"}, +/* 163 s */ + {v_subst, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer][count]s", + " s substitute character"}, +/* 164 t */ + {v_cht, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, + "[count]t character", + " t before character in line forward search"}, +/* 165 u */ + /* + * DON'T set the V_DOT flag, it' more complicated than that. + * See vi/vi.c for details. + */ + {v_undo, VM_RCM_SET, + "u", + " u undo last change"}, +/* 166 v */ + {NULL}, +/* 167 w */ + {v_wordw, V_CNT|V_MOVE|VM_RCM_SET, + "[count]w", + " w move to next word"}, +/* 170 x */ + {v_xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, + "[buffer][count]x", + " x delete character"}, +/* 171 y */ + {v_yank, V_CNT|V_MOTION|V_OBUF|VC_Y|VM_RCM_SET, + "[buffer][count]y[count]motion", + " y copy text to motion into a cut buffer"}, +/* 172 z */ + /* + * DON'T set the V_CHAR flag, the char isn't required, + * so it's handled specially in getcmd(). + */ + {v_z, V_ABS_L|V_CNT|VM_RCM_SET, + "[line]z[window_size][-|.|+|^|<CR>]", + " z redraw window"}, +/* 173 { */ + {v_paragraphb, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "[count]{", + " { move back paragraph"}, +/* 174 | */ + {v_ncol, V_CNT|V_MOVE|VM_RCM_SET, + "[count]|", + " | move to column"}, +/* 175 } */ + {v_paragraphf, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, + "[count]}", + " } move forward paragraph"}, +/* 176 ~ */ + {v_ulcase, V_CNT|V_DOT|VM_RCM_SET, + "[count]~", + " ~ reverse case"}, +}; diff --git a/usr.bin/vi/vi/vcmd.h b/usr.bin/vi/vi/vcmd.h new file mode 100644 index 0000000..4c13076 --- /dev/null +++ b/usr.bin/vi/vi/vcmd.h @@ -0,0 +1,346 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vcmd.h 8.40 (Berkeley) 8/5/94 + */ + +typedef struct _vikeys VIKEYS; + +/* Structure passed around to functions implementing vi commands. */ +typedef struct _vicmdarg { +#define vp_startzero buffer /* START ZERO OUT. */ + CHAR_T key; /* Command key. */ + CHAR_T buffer; /* Buffer. */ + CHAR_T character; /* Character. */ + u_long count; /* Count. */ + u_long count2; /* Second count (only used by z). */ + VIKEYS const *kp; /* VIKEYS key. */ + size_t klen; /* Keyword length. */ + + /* + * Historic vi allowed "dl" when the cursor was on the last column, + * deleting the last character, and similarly allowed "dw" when + * the cursor was on the last column of the file. It didn't allow + * "dh" when the cursor was on column 1, although these cases are + * not strictly analogous. The point is that some movements would + * succeed if they were associated with a motion command, and fail + * otherwise. This is part of the off-by-1 schizophrenia that + * plagued vi. Other examples are that "dfb" deleted everything + * up to and including the next 'b' character, while "d/b" deleted + * everything up to the next 'b' character. While this implementation + * regularizes the interface to the extent possible, there are many + * special cases that can't be fixed. The special cases are handled + * by setting flags per command so that the underlying command and + * motion routines know what's really going on. + * + * The VC_* and VM_* flags are set in the vikeys array, and the VM_* + * flags may be set by the underlying functions (motion component or + * command) as well. For this reason, the flags in the VICMDARG and + * VIKEYS structures live in the same name space. + */ +#define VC_C 0x00000001 /* The 'c' command. */ +#define VC_D 0x00000002 /* The 'd' command. */ +#define VC_DEF 0x00000004 /* The '<', '>' and '!' commands. */ +#define VC_Y 0x00000008 /* The 'y' command. */ +#define VC_COMMASK 0x0000000f /* Mask for VC flags. */ +#define ISMOTION(vp) F_ISSET(vp, VC_COMMASK) + +#define VM_CUTREQ 0x00000010 /* Always cut into numeric buffers. */ +#define VM_LDOUBLE 0x00000020 /* Doubled command for line mode. */ +#define VM_LMODE 0x00000040 /* Motion is line oriented. */ +#define VM_NOMOTION 0x00000080 /* Motion command not entered. */ +#define VM_COMMASK 0x000000f0 /* Mask for VM flags. */ + + /* + * The VM_RCM_* flags are single usage, i.e. if you set one, you have + * to clear the others. + */ +#define VM_RCM 0x00000100 /* Use relative cursor movment (RCM). */ +#define VM_RCM_SET 0x00000200 /* RCM: set to current position. */ +#define VM_RCM_SETFNB 0x00000400 /* RCM: set to first non-blank (FNB). */ +#define VM_RCM_SETLAST 0x00000800 /* RCM: set to last character. */ +#define VM_RCM_SETNNB 0x00001000 /* RCM: set to next non-blank. */ +#define VM_RCM_MASK 0x00001f00 /* Mask for RCM flags. */ + + /* Flags for the underlying function. */ +#define VC_BUFFER 0x00002000 /* The buffer was set. */ +#define VC_C1RESET 0x00004000 /* Reset C1SET flag for dot commands. */ +#define VC_C1SET 0x00008000 /* Count 1 was set. */ +#define VC_C2SET 0x00010000 /* Count 2 was set. */ +#define VC_ISDOT 0x00020000 /* Command was the dot command. */ + u_int32_t flags; + +#define vp_endzero keyword /* END ZERO OUT. */ + char *keyword; /* Keyword. */ + size_t kbuflen; /* Keyword buffer length. */ + /* + * There are four cursor locations that we worry about: the initial + * cursor position, the start of the range, the end of the range, + * and the final cursor position. The initial cursor position and + * the start of the range are both m_start, and are always the same. + * All locations are initialized to the starting cursor position by + * the main vi routines, and the underlying functions depend on this. + * + * Commands that can be motion components set the end of the range + * cursor position, m_stop. All commands must set the ending cursor + * position, m_final. The reason that m_stop isn't the same as m_final + * is that there are situations where the final position of the cursor + * is outside of the cut/delete range (e.g. 'd[[' from the first column + * of a line). The final cursor position often varies based on the + * direction of the movement, as well as the command. The only special + * case that the delete code handles is that it will make adjustments + * if the final cursor position is deleted. + * + * The reason for all of this is that the historic vi semantics were + * defined command-by-command. Every function has to roll its own + * starting and stopping positions, and adjust them if it's being used + * as a motion component. The general rules are as follows: + * 1: If not a motion component, the final cursor is at the end + * of the range. + * 2: If moving backward in the file: + * a: VC_D moves to the end of the range. + * b: If the line hasn't changed, VC_Y doesn't move, else it + * moves to the end of the range. + * 3: If moving forward in the file, VC_D and VC_Y stay at the + * start of the range. + * + * Usually, if moving backward in the file and it's a motion component, + * the starting cursor is decremented by a single character (or, in a + * few cases, to the end of the previous line) so that the starting + * cursor character isn't cut or deleted. No cursor adjustment is + * needed for moving forward, because the cut/delete routines handle + * m_stop inclusively, i.e. the last character in the range is cut or + * deleted. This makes cutting to the EOF/EOL reasonable. + * + * The 'c', '<', '>', and '!' commands are special cases. We ignore + * the final cursor position for all of them: for 'c', the text input + * routines set the cursor to the last character inserted; for '<', + * '>' and '!', the underlying ex commands that do the operation will + * set the cursor for us. We still need a VC_C flag because there are + * special motion semantics that are associated with the 'c' command. + * We don't need VC_ flags for the others, because, as far as I know, + * there are no special semantics associated with their motions. So, + * we group them under a single VC_ flag so that the standard motion + * adjustments get done. + */ + MARK m_start; /* mark: initial cursor, range start. */ + MARK m_stop; /* mark: range end. */ + MARK m_final; /* mark: final cursor position. */ +} VICMDARG; + +/* Vi command structure. */ +struct _vikeys { /* Underlying function. */ + int (*func) __P((SCR *, EXF *, VICMDARG *)); +#define V_ABS 0x00040000 /* Absolute movement, set '' mark. */ +#define V_ABS_C 0x00080000 /* V_ABS: if the line/column changed. */ +#define V_ABS_L 0x00100000 /* V_ABS: if the line changed. */ +#define V_CHAR 0x00200000 /* Character (required, trailing). */ +#define V_CNT 0x00400000 /* Count (optional, leading). */ +#define V_DOT 0x00800000 /* On success, sets dot command. */ +#define V_KEYNUM 0x01000000 /* Cursor referenced number. */ +#define V_KEYW 0x02000000 /* Cursor referenced word. */ +#define V_MOTION 0x04000000 /* Motion (required, trailing). */ +#define V_MOVE 0x08000000 /* Command defines movement. */ +#define V_OBUF 0x10000000 /* Buffer (optional, leading). */ +#define V_RBUF 0x20000000 /* Buffer (required, trailing). */ + u_int32_t flags; + char *usage; /* Usage line. */ + char *help; /* Help line. */ +}; +#define MAXVIKEY 126 /* List of vi commands. */ +extern VIKEYS const vikeys[MAXVIKEY + 1]; +extern VIKEYS const tmotion; /* XXX Hacked ~ command. */ + +/* Definition of a vi "word". */ +#define inword(ch) (isalnum(ch) || (ch) == '_') + +/* Offset to next column of stop size. */ +#define STOP_OFF(c, stop) (stop - (c) % stop) + +/* Character stream structure, prototypes. */ +typedef struct _vcs { + recno_t cs_lno; /* Line. */ + size_t cs_cno; /* Column. */ + CHAR_T *cs_bp; /* Buffer. */ + size_t cs_len; /* Length. */ + CHAR_T cs_ch; /* Character. */ +#define CS_EMP 1 /* Empty line. */ +#define CS_EOF 2 /* End-of-file. */ +#define CS_EOL 3 /* End-of-line. */ +#define CS_SOF 4 /* Start-of-file. */ + int cs_flags; /* Return flags. */ +} VCS; + +int cs_bblank __P((SCR *, EXF *, VCS *)); +int cs_fblank __P((SCR *, EXF *, VCS *)); +int cs_fspace __P((SCR *, EXF *, VCS *)); +int cs_init __P((SCR *, EXF *, VCS *)); +int cs_next __P((SCR *, EXF *, VCS *)); +int cs_prev __P((SCR *, EXF *, VCS *)); + + /* Character search information. */ +enum cdirection { CNOTSET, FSEARCH, fSEARCH, TSEARCH, tSEARCH }; + +/* Vi private, per-screen memory. */ +typedef struct _vi_private { + VICMDARG sdot; /* Saved dot, motion command. */ + VICMDARG sdotmotion; + + CHAR_T rlast; /* Last 'r' command character. */ + + char *rep; /* Input replay buffer. */ + size_t rep_len; /* Input replay buffer length. */ + size_t rep_cnt; /* Input replay buffer characters. */ + + CHAR_T inc_lastch; /* Last increment character. */ + long inc_lastval; /* Last increment value. */ + + char *ps; /* Paragraph plus section list. */ + + u_long u_ccnt; /* Undo command count. */ + + CHAR_T lastckey; /* Last search character. */ + enum cdirection csearchdir; /* Character search direction. */ +} VI_PRIVATE; + +#define VIP(sp) ((VI_PRIVATE *)((sp)->vi_private)) + +/* Vi function prototypes. */ +int txt_auto __P((SCR *, EXF *, recno_t, TEXT *, size_t, TEXT *)); +int v_buildps __P((SCR *)); +int v_end __P((SCR *)); +void v_eof __P((SCR *, EXF *, MARK *)); +void v_eol __P((SCR *, EXF *, MARK *)); +int v_exwrite __P((void *, const char *, int)); +int v_init __P((SCR *, EXF *)); +int v_isempty __P((char *, size_t)); +int v_msgflush __P((SCR *)); +void v_nomove __P((SCR *)); +int v_ntext __P((SCR *, EXF *, TEXTH *, MARK *, + const char *, const size_t, MARK *, ARG_CHAR_T, recno_t, u_int)); +int v_optchange __P((SCR *, int)); +int v_screen_copy __P((SCR *, SCR *)); +int v_screen_end __P((SCR *)); +void v_sof __P((SCR *, MARK *)); +void v_sol __P((SCR *)); +int vi __P((SCR *, EXF *)); + +#define VIPROTO(name) int name __P((SCR *, EXF *, VICMDARG *)) +VIPROTO(v_again); +VIPROTO(v_at); +VIPROTO(v_bmark); +VIPROTO(v_bottom); +VIPROTO(v_cfirst); +VIPROTO(v_Change); +VIPROTO(v_change); +VIPROTO(v_chF); +VIPROTO(v_chf); +VIPROTO(v_chrepeat); +VIPROTO(v_chrrepeat); +VIPROTO(v_chT); +VIPROTO(v_cht); +VIPROTO(v_cr); +VIPROTO(v_Delete); +VIPROTO(v_delete); +VIPROTO(v_dollar); +VIPROTO(v_down); +VIPROTO(v_ex); +VIPROTO(v_exmode); +VIPROTO(v_filter); +VIPROTO(v_first); +VIPROTO(v_fmark); +VIPROTO(v_home); +VIPROTO(v_hpagedown); +VIPROTO(v_hpageup); +VIPROTO(v_iA); +VIPROTO(v_ia); +VIPROTO(v_iI); +VIPROTO(v_ii); +VIPROTO(v_increment); +VIPROTO(v_iO); +VIPROTO(v_io); +VIPROTO(v_join); +VIPROTO(v_left); +VIPROTO(v_lgoto); +VIPROTO(v_linedown); +VIPROTO(v_lineup); +VIPROTO(v_mark); +VIPROTO(v_match); +VIPROTO(v_middle); +VIPROTO(v_mulcase); +VIPROTO(v_ncol); +VIPROTO(v_pagedown); +VIPROTO(v_pageup); +VIPROTO(v_paragraphb); +VIPROTO(v_paragraphf); +VIPROTO(v_Put); +VIPROTO(v_put); +VIPROTO(v_redraw); +VIPROTO(v_Replace); +VIPROTO(v_replace); +VIPROTO(v_right); +VIPROTO(v_screen); +VIPROTO(v_searchb); +VIPROTO(v_searchf); +VIPROTO(v_searchN); +VIPROTO(v_searchn); +VIPROTO(v_searchw); +VIPROTO(v_sectionb); +VIPROTO(v_sectionf); +VIPROTO(v_sentenceb); +VIPROTO(v_sentencef); +VIPROTO(v_shiftl); +VIPROTO(v_shiftr); +VIPROTO(v_status); +VIPROTO(v_stop); +VIPROTO(v_Subst); +VIPROTO(v_subst); +VIPROTO(v_switch); +VIPROTO(v_tagpop); +VIPROTO(v_tagpush); +VIPROTO(v_ulcase); +VIPROTO(v_Undo); +VIPROTO(v_undo); +VIPROTO(v_up); +VIPROTO(v_wordB); +VIPROTO(v_wordb); +VIPROTO(v_wordE); +VIPROTO(v_worde); +VIPROTO(v_wordW); +VIPROTO(v_wordw); +VIPROTO(v_Xchar); +VIPROTO(v_xchar); +VIPROTO(v_Yank); +VIPROTO(v_yank); +VIPROTO(v_z); +VIPROTO(v_zero); +VIPROTO(v_zexit); diff --git a/usr.bin/vi/vi/vi.c b/usr.bin/vi/vi/vi.c new file mode 100644 index 0000000..9e52eb1 --- /dev/null +++ b/usr.bin/vi/vi/vi.c @@ -0,0 +1,937 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)vi.c 8.89 (Berkeley) 8/14/94"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" +#include "vcmd.h" + +static int getcmd __P((SCR *, EXF *, + VICMDARG *, VICMDARG *, VICMDARG *, int *, int *)); +static __inline int + getcount __P((SCR *, ARG_CHAR_T, u_long *)); +static __inline int + getkey __P((SCR *, CH *, u_int)); +static int getkeyword __P((SCR *, EXF *, VICMDARG *, u_int)); +static int getmotion __P((SCR *, EXF *, VICMDARG *, VICMDARG *, int *)); + +/* + * Side-effect: + * The dot structure can be set by the underlying vi functions, + * see v_Put() and v_put(). + */ +#define DOT (&VIP(sp)->sdot) +#define DOTMOTION (&VIP(sp)->sdotmotion) + +/* + * vi -- + * Main vi command loop. + */ +int +vi(sp, ep) + SCR *sp; + EXF *ep; +{ + MARK abs; + VICMDARG cmd, *vp; + u_int flags, saved_mode; + int comcount, eval, mapped; + + /* Start vi and paint the screen. */ + if (v_init(sp, ep)) + return (1); + + /* Command initialization. */ + memset(&cmd, 0, sizeof(VICMDARG)); + + for (eval = 0, vp = &cmd;;) { + /* Refresh the screen. */ + sp->showmode = "Command"; + if (sp->s_refresh(sp, ep)) { + eval = 1; + break; + } + + /* Set the new favorite position. */ + if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) { + sp->rcm_last = 0; + (void)sp->s_column(sp, ep, &sp->rcm); + } + + /* + * If not currently in a map, log the cursor position, + * and set a flag so that this command can become the + * DOT command. + */ + if (MAPPED_KEYS_WAITING(sp)) + mapped = 1; + else { + if (log_cursor(sp, ep)) + goto err; + mapped = 0; + } + + /* + * We get a command, which may or may not have an associated + * motion. If it does, we get it too, calling its underlying + * function to get the resulting mark. We then call the + * command setting the cursor to the resulting mark. + */ + if (getcmd(sp, ep, DOT, vp, NULL, &comcount, &mapped)) + goto err; + + /* + * Historical practice: if a dot command gets a new count, + * any motion component goes away, i.e. "d3w2." deletes a + * total of 5 words. + */ + if (F_ISSET(vp, VC_ISDOT) && comcount) + DOTMOTION->count = 1; + + /* Copy the key flags into the local structure. */ + F_SET(vp, vp->kp->flags); + + /* Get any associated keyword. */ + if (F_ISSET(vp, V_KEYNUM | V_KEYW) && + getkeyword(sp, ep, vp, vp->flags)) + goto err; + + /* Prepare to set the previous context. */ + if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) { + abs.lno = sp->lno; + abs.cno = sp->cno; + } + + /* + * Set the three cursor locations to the current cursor. The + * underlying routines don't bother if the cursor doesn't move. + * This also handles line commands (e.g. Y) defaulting to the + * current line. + */ + vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno; + vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno; + + /* + * Do any required motion; getmotion sets the from MARK and the + * line mode flag. We save off the RCM mask and only restore + * it if it no RCM flags are set by the motion command. This + * means that the motion command is expected to determine where + * the cursor ends up! + */ + if (F_ISSET(vp, V_MOTION)) { + flags = F_ISSET(vp, VM_RCM_MASK); + F_CLR(vp, VM_RCM_MASK); + if (getmotion(sp, ep, DOTMOTION, vp, &mapped)) + goto err; + if (F_ISSET(vp, VM_NOMOTION)) + goto err; + if (!F_ISSET(vp, VM_RCM_MASK)) + F_SET(vp, flags); + } + + /* + * If a count is set and the command is line oriented, set the + * to MARK here relative to the cursor/from MARK. This is for + * commands that take both counts and motions, i.e. "4yy" and + * "y%". As there's no way the command can know which the user + * did, we have to do it here. (There are commands that are + * line oriented and that take counts ("#G", "#H"), for which + * this calculation is either completely meaningless or wrong. + * Each command must validate the value for itself. + */ + if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE)) + vp->m_stop.lno += vp->count - 1; + + /* Increment the command count. */ + ++sp->ccnt; + + /* Save the mode and call the function. */ + saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE); + if ((vp->kp->func)(sp, ep, vp)) + goto err; +#ifdef DEBUG + /* Make sure no function left the temporary space locked. */ + if (F_ISSET(sp->gp, G_TMP_INUSE)) { + msgq(sp, M_ERR, + "Error: vi: temporary buffer not released"); + return (1); + } +#endif + /* + * If that command took us out of vi or changed the screen, + * then exit the loop without further action. + */ + if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE)) + break; + + /* + * Set the dot command structure. + * + * !!! + * Historically, no command which used any mapped keys became + * the dot command. + */ + if (F_ISSET(vp, V_DOT) && !mapped) { + *DOT = cmd; + F_SET(DOT, VC_ISDOT); + + /* + * If a count was supplied for both the command and + * its motion, the count was used only for the motion. + * Turn the count back on for the dot structure. + */ + if (F_ISSET(vp, VC_C1RESET)) + F_SET(DOT, VC_C1SET); + + /* VM flags aren't retained. */ + F_CLR(DOT, VM_COMMASK | VM_RCM_MASK); + } + + /* + * Some vi row movements are "attracted" to the last position + * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET + * commands' candle. It's broken into two parts. Here we deal + * with the command flags. In sp->relative(), we deal with the + * screen flags. If the movement is to the EOL the vi command + * handles it. If it's to the beginning, we handle it here. + * + * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB + * flag, but do the work themselves. The reason is that they + * have to modify the column in case they're being used as a + * motion component. Other similar commands (e.g. +, -) don't + * have to modify the column because they are always line mode + * operations when used as motions, so the column number isn't + * of any interest. + * + * Does this totally violate the screen and editor layering? + * You betcha. As they say, if you think you understand it, + * you don't. + */ + switch (F_ISSET(vp, VM_RCM_MASK)) { + case 0: + case VM_RCM_SET: + break; + case VM_RCM: + vp->m_final.cno = sp->s_rcm(sp, ep, vp->m_final.lno); + break; + case VM_RCM_SETLAST: + sp->rcm_last = 1; + break; + case VM_RCM_SETFNB: + vp->m_final.cno = 0; + /* FALLTHROUGH */ + case VM_RCM_SETNNB: + if (nonblank(sp, ep, vp->m_final.lno, &vp->m_final.cno)) + goto err; + break; + default: + abort(); + } + + /* Update the cursor. */ + sp->lno = vp->m_final.lno; + sp->cno = vp->m_final.cno; + + /* + * Set the absolute mark -- set even if a tags or similar + * command, since the tag may be moving to the same file. + */ + if ((F_ISSET(vp, V_ABS) || + F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno || + F_ISSET(vp, V_ABS_C) && + (sp->lno != abs.lno || sp->cno != abs.cno)) && + mark_set(sp, ep, ABSMARK1, &abs, 1)) + goto err; + + if (!MAPPED_KEYS_WAITING(sp)) + (void)msg_rpt(sp, 1); + + /* + * Check and clear the interrupts. There's an obvious race, + * but it's not worth cleaning up. This is done after the + * err: lable, so that if the "error" was an interupt it gets + * cleaned up. + * + * !!! + * Previous versions of nvi cleared mapped characters on error, + * even if it wasn't an interrupt. This feature was removed as + * users complained that it wasn't historic practice and that + * they used leading (illegal) <escape> characters in the map + * to clean up vi state before the map was interpreted. + */ +err: if (INTERRUPTED(sp)) + term_flush(sp, "Interrupted", CH_MAPPED); + CLR_INTERRUPT(sp); + } + + /* Free allocated keyword memory. */ + if (cmd.keyword != NULL) + free(cmd.keyword); + + return (v_end(sp) || eval); +} + +#define KEY(key, map) { \ + if (getkey(sp, &ikey, map)) \ + return (1); \ + if (ikey.value == K_ESCAPE) \ + goto esc; \ + if (F_ISSET(&ikey, CH_MAPPED)) \ + *mappedp = 1; \ + key = ikey.ch; \ +} + +/* + * The O_TILDEOP option makes the ~ command take a motion instead + * of a straight count. This is the replacement structure we use + * instead of the one currently in the VIKEYS table. + * + * XXX + * Note, I used VC_Y instead of creating a new motion command, it's + * a lot easier. + */ +VIKEYS const tmotion = { + v_mulcase, V_CNT|V_DOT|V_MOTION|VC_Y|VM_RCM_SET, + "[count]~[count]motion", + " ~ change case to motion" +}; + +/* + * getcmd -- + * + * The command structure for vi is less complex than ex (and don't think + * I'm not grateful!) The command syntax is: + * + * [count] [buffer] [count] key [[motion] | [buffer] [character]] + * + * and there are several special cases. The motion value is itself a vi + * command, with the syntax: + * + * [count] key [character] + */ +static int +getcmd(sp, ep, dp, vp, ismotion, comcountp, mappedp) + SCR *sp; + EXF *ep; + VICMDARG *dp, *vp; + VICMDARG *ismotion; /* Previous key if getting motion component. */ + int *comcountp, *mappedp; +{ + enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart; + VIKEYS const *kp; + u_int flags; + CH ikey; + CHAR_T key; + char *s; + + /* Refresh the command structure. */ + memset(&vp->vp_startzero, 0, + (char *)&vp->vp_endzero - (char *)&vp->vp_startzero); + + /* + * Get a key. + * + * <escape> cancels partial commands, i.e. a command where at least + * one non-numeric character has been entered. Otherwise, it beeps + * the terminal. + * + * !!! + * POSIX 1003.2-1992 explicitly disallows cancelling commands where + * all that's been entered is a number, requiring that the terminal + * be alerted. + */ + cpart = ismotion == NULL ? COMMANDMODE : ISPARTIAL; + KEY(key, TXT_MAPCOMMAND); + if (ismotion == NULL) + cpart = NOTPARTIAL; + + /* Pick up optional buffer. */ + if (key == '"') { + cpart = ISPARTIAL; + if (ismotion != NULL) { + msgq(sp, M_BERR, + "Buffers should be specified before the command"); + return (1); + } + KEY(vp->buffer, 0); + F_SET(vp, VC_BUFFER); + + KEY(key, TXT_MAPCOMMAND); + } + + /* + * Pick up optional count, where a leading 0 is not a count, + * it's a command. + */ + if (isdigit(key) && key != '0') { + if (getcount(sp, key, &vp->count)) + return (1); + F_SET(vp, VC_C1SET); + *comcountp = 1; + + KEY(key, TXT_MAPCOMMAND); + } else + *comcountp = 0; + + /* Pick up optional buffer. */ + if (key == '"') { + cpart = ISPARTIAL; + if (F_ISSET(vp, VC_BUFFER)) { + msgq(sp, M_ERR, "Only one buffer can be specified"); + return (1); + } + if (ismotion != NULL) { + msgq(sp, M_BERR, + "Buffers should be specified before the command"); + return (1); + } + KEY(vp->buffer, 0); + F_SET(vp, VC_BUFFER); + + KEY(key, TXT_MAPCOMMAND); + } + + /* Check for an OOB command key. */ + cpart = ISPARTIAL; + if (key > MAXVIKEY) { + msgq(sp, M_BERR, "%s isn't a vi command", KEY_NAME(sp, key)); + return (1); + } + kp = &vikeys[vp->key = key]; + + /* The tildeop option makes the ~ command take a motion. */ + if (key == '~' && O_ISSET(sp, O_TILDEOP)) + kp = &tmotion; + + vp->kp = kp; + + /* + * Find the command. The only legal command with no underlying + * function is dot. It's historic practice that <escape> doesn't + * just erase the preceding number, it beeps the terminal as well. + * It's a common problem, so just beep the terminal unless verbose + * was set. + */ + if (kp->func == NULL) { + if (key != '.') { + msgq(sp, ikey.value == K_ESCAPE ? M_BERR : M_ERR, + "%s isn't a vi command", KEY_NAME(sp, key)); + return (1); + } + + /* If called for a motion command, stop now. */ + if (dp == NULL) + goto usage; + + /* A repeatable command must have been executed. */ + if (!F_ISSET(dp, VC_ISDOT)) { + msgq(sp, M_ERR, "No command to repeat"); + return (1); + } + + /* + * !!! + * If a '.' is immediately entered after an undo command, we + * replay the log instead of redoing the last command. This + * is necessary because 'u' can't set the dot command -- see + * vi/v_undo.c:v_undo for details. + */ + if (VIP(sp)->u_ccnt == sp->ccnt) { + vp->kp = &vikeys['u']; + F_SET(vp, VC_ISDOT); + return (0); + } + + /* Set new count/buffer, if any, and return. */ + if (F_ISSET(vp, VC_C1SET)) { + F_SET(dp, VC_C1SET); + dp->count = vp->count; + } + if (F_ISSET(vp, VC_BUFFER)) + dp->buffer = vp->buffer; + *vp = *dp; + return (0); + } + + /* Set the flags based on the command flags. */ + flags = kp->flags; + + /* Check for illegal count. */ + if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT)) + goto usage; + + /* Illegal motion command. */ + if (ismotion == NULL) { + /* Illegal buffer. */ + if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER)) + goto usage; + + /* Required buffer. */ + if (LF_ISSET(V_RBUF)) { + KEY(vp->buffer, 0); + F_SET(vp, VC_BUFFER); + } + } + + /* + * Special case: '[', ']' and 'Z' commands. Doesn't the fact that + * the *single* characters don't mean anything but the *doubled* + * characters do just frost your shorts? + */ + if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') { + /* + * Historically, half entered [[, ]] or Z commands weren't + * cancelled by <escape>, the terminal was beeped instead. + * POSIX.2-1992 probably didn't notice, and requires that + * they be cancelled instead of beeping. Seems fine to me. + */ + KEY(key, TXT_MAPCOMMAND); + + if (vp->key != key) { +usage: if (ismotion == NULL) + s = kp->usage; + else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP)) + s = tmotion.usage; + else + s = vikeys[ismotion->key].usage; + msgq(sp, M_ERR, "Usage: %s", s); + return (1); + } + } + /* Special case: 'z' command. */ + if (vp->key == 'z') { + KEY(vp->character, 0); + if (isdigit(vp->character)) { + if (getcount(sp, vp->character, &vp->count2)) + return (1); + F_SET(vp, VC_C2SET); + KEY(vp->character, 0); + } + } + + /* + * Commands that have motion components can be doubled to + * imply the current line. + */ + if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) { + msgq(sp, M_ERR, "%s may not be used as a motion command", + KEY_NAME(sp, key)); + return (1); + } + + /* Required character. */ + if (LF_ISSET(V_CHAR)) + KEY(vp->character, 0); + + return (0); + +esc: switch (cpart) { + case COMMANDMODE: + msgq(sp, M_BERR, "Already in command mode"); + break; + case ISPARTIAL: + break; + case NOTPARTIAL: + (void)sp->s_bell(sp); + break; + } + return (1); +} + +/* + * getmotion -- + * + * Get resulting motion mark. + */ +static int +getmotion(sp, ep, dm, vp, mappedp) + SCR *sp; + EXF *ep; + VICMDARG *dm, *vp; + int *mappedp; +{ + MARK m; + VICMDARG motion; + size_t len; + u_long cnt; + int notused; + + /* + * If '.' command, use the dot motion, else get the motion command. + * Clear any line motion flags, the subsequent motion isn't always + * the same, i.e. "/aaa" may or may not be a line motion. + */ + if (F_ISSET(vp, VC_ISDOT)) { + motion = *dm; + F_SET(&motion, VC_ISDOT); + F_CLR(&motion, VM_COMMASK); + } else if (getcmd(sp, ep, NULL, &motion, vp, ¬used, mappedp)) + return (1); + + /* + * A count may be provided both to the command and to the motion, in + * which case the count is multiplicative. For example, "3y4y" is the + * same as "12yy". This count is provided to the motion command and + * not to the regular function. + */ + cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1; + if (F_ISSET(vp, VC_C1SET)) { + motion.count *= vp->count; + F_SET(&motion, VC_C1SET); + + /* + * Set flags to restore the original values of the command + * structure so dot commands can change the count values, + * e.g. "2dw" "3." deletes a total of five words. + */ + F_CLR(vp, VC_C1SET); + F_SET(vp, VC_C1RESET); + } + + /* + * Some commands can be repeated to indicate the current line. In + * this case, or if the command is a "line command", set the flags + * appropriately. If not a doubled command, run the function to get + * the resulting mark. + */ + if (vp->key == motion.key) { + F_SET(vp, VM_LDOUBLE | VM_LMODE); + + /* Set the origin of the command. */ + vp->m_start.lno = sp->lno; + vp->m_start.cno = 0; + + /* + * Set the end of the command. + * + * If the current line is missing, i.e. the file is empty, + * historic vi permitted a "cc" or "!!" command to insert + * text. + */ + vp->m_stop.lno = sp->lno + motion.count - 1; + if (file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) { + if (vp->m_stop.lno != 1 || + vp->key != 'c' && vp->key != '!') { + m.lno = sp->lno; + m.cno = sp->cno; + v_eof(sp, ep, &m); + return (1); + } + vp->m_stop.cno = 0; + } else + vp->m_stop.cno = len ? len - 1 : 0; + } else { + /* + * Motion commands change the underlying movement (*snarl*). + * For example, "l" is illegal at the end of a line, but "dl" + * is not. Set flags so the function knows the situation. + */ + F_SET(&motion, vp->kp->flags & VC_COMMASK); + + /* + * Copy the key flags into the local structure, except for + * the RCM flags, the motion command will set the RCM flags + * in the vp structure as necessary. + */ + F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK); + + /* + * Set the three cursor locations to the current cursor. This + * permits commands like 'j' and 'k', that are line oriented + * motions and have special cursor suck semantics when they are + * used as standalone commands, to ignore column positioning. + */ + motion.m_final.lno = + motion.m_stop.lno = motion.m_start.lno = sp->lno; + motion.m_final.cno = + motion.m_stop.cno = motion.m_start.cno = sp->cno; + + /* Run the function. */ + if ((motion.kp->func)(sp, ep, &motion)) + return (1); + + /* + * Copy cut buffer, line mode and cursor position information + * from the motion command structure, i.e. anything that the + * motion command can set for us. The commands can flag the + * movement as a line motion (see v_sentence) as well as set + * the VM_RCM_* flags explicitly. + */ + F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK)); + + /* + * Motion commands can reset all of the cursor information. + * If the motion is in the reverse direction, switch the + * from and to MARK's so that it's in a forward direction. + * Motions are from the from MARK to the to MARK (inclusive). + */ + if (motion.m_start.lno > motion.m_stop.lno || + motion.m_start.lno == motion.m_stop.lno && + motion.m_start.cno > motion.m_stop.cno) { + vp->m_start = motion.m_stop; + vp->m_stop = motion.m_start; + } else { + vp->m_start = motion.m_start; + vp->m_stop = motion.m_stop; + } + vp->m_final = motion.m_final; + } + + /* + * If the command sets dot, save the motion structure. The motion + * count was changed above and needs to be reset, that's why this + * is done here, and not in the calling routine. + */ + if (F_ISSET(vp->kp, V_DOT)) { + *dm = motion; + dm->count = cnt; + } + return (0); +} + +#define innum(c) (isdigit(c) || strchr("abcdefABCDEF", c)) + +/* + * getkeyword -- + * Get the "word" the cursor is on. + */ +static int +getkeyword(sp, ep, kp, flags) + SCR *sp; + EXF *ep; + VICMDARG *kp; + u_int flags; +{ + recno_t lno; + size_t beg, end, len; + char *p; + + if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) { + if (file_lline(sp, ep, &lno)) + return (1); + if (lno == 0) + v_eof(sp, ep, NULL); + else + GETLINE_ERR(sp, sp->lno); + return (1); + } + + /* + * !!! + * Historically, tag commands skipped over any leading whitespace + * characters. + */ + for (beg = sp->cno; beg < len && isspace(p[beg]); ++beg); + + if (beg >= len || + LF_ISSET(V_KEYW) && !inword(p[beg]) || + LF_ISSET(V_KEYNUM) && !innum(p[beg]) && + p[beg] != '-' && p[beg] != '+') + goto noword; + + /* + * !!! + * Find the beginning/end of the keyword. Keywords (V_KEYW) are + * used for cursor-word searching and for tags. Historical vi + * only used the word in a tag search from the cursor to the end + * of the word, i.e. if the cursor was on the 'b' in " abc ", the + * tag was "bc". For no particular reason, we make the cursor + * word searches follow the same rule. + */ + if (beg != 0) + if (LF_ISSET(V_KEYW)) { +#ifdef MOVE_TO_KEYWORD_BEGINNING + for (;;) { + --beg; + if (!inword(p[beg])) { + ++beg; + break; + } + if (beg == 0) + break; + } +#endif + } else { + for (;;) { + --beg; + if (!innum(p[beg])) { + if (beg > 0 && p[beg - 1] == '0' && + (p[beg] == 'X' || p[beg] == 'x')) + --beg; + else + ++beg; + break; + } + if (beg == 0) + break; + } + + /* Skip possible leading sign. */ + if (beg != 0 && p[beg] != '0' && + (p[beg - 1] == '+' || p[beg - 1] == '-')) + --beg; + } + + if (LF_ISSET(V_KEYW)) { + for (end = beg; ++end < len && inword(p[end]);); + --end; + } else { + for (end = beg; ++end < len;) { + if (p[end] == 'X' || p[end] == 'x') { + if (end != beg + 1 || p[beg] != '0') + break; + continue; + } + if (!innum(p[end])) + break; + } + + /* Just a sign isn't a number. */ + if (end == beg && (p[beg] == '+' || p[beg] == '-')) { +noword: msgq(sp, M_BERR, "Cursor not in a %s", + LF_ISSET(V_KEYW) ? "word" : "number"); + return (1); + } + --end; + } + + /* + * Getting a keyword implies moving the cursor to its beginning. + * Refresh now. + */ + if (beg != sp->cno) { + sp->cno = beg; + sp->s_refresh(sp, ep); + } + + /* + * XXX + * 8-bit clean problem. Numeric keywords are handled using strtol(3) + * and friends. This would have to be fixed in v_increment and here + * to not depend on a trailing NULL. + */ + len = (end - beg) + 2; /* XXX */ + kp->klen = (end - beg) + 1; + BINC_RET(sp, kp->keyword, kp->kbuflen, len); + memmove(kp->keyword, p + beg, kp->klen); + kp->keyword[kp->klen] = '\0'; /* XXX */ + return (0); +} + +/* + * getcount -- + * Return the next count. + */ +static __inline int +getcount(sp, fkey, countp) + SCR *sp; + ARG_CHAR_T fkey; + u_long *countp; +{ + u_long count, tc; + CH ikey; + + ikey.ch = fkey; + count = tc = 0; + do { + /* Assume that overflow results in a smaller number. */ + tc = count * 10 + ikey.ch - '0'; + if (count > tc) { + /* Toss to the next non-digit. */ + do { + if (getkey(sp, &ikey, + TXT_MAPCOMMAND | TXT_MAPNODIGIT)) + return (1); + } while (isdigit(ikey.ch)); + msgq(sp, M_ERR, "Number larger than %lu", ULONG_MAX); + return (1); + } + count = tc; + if (getkey(sp, &ikey, TXT_MAPCOMMAND | TXT_MAPNODIGIT)) + return (1); + } while (isdigit(ikey.ch)); + *countp = count; + return (0); +} + +/* + * getkey -- + * Return the next key. + */ +static __inline int +getkey(sp, ikeyp, map) + SCR *sp; + CH *ikeyp; + u_int map; +{ + switch (term_key(sp, ikeyp, map)) { + case INP_EOF: + case INP_ERR: + F_SET(sp, S_EXIT_FORCE); + return (1); + case INP_INTR: + /* + * !!! + * Historically, vi beeped on command level interrupts. + * + * Historically, vi exited to ex mode if no file was named + * on the command line, and two interrupts were generated + * in a row. (Just figured you might want to know that.) + */ + (void)sp->s_bell(sp); + return (1); + case INP_OK: + return (0); + } + /* NOTREACHED */ +} diff --git a/usr.bin/vi/xaw/xaw_screen.c b/usr.bin/vi/xaw/xaw_screen.c new file mode 100644 index 0000000..14a9674 --- /dev/null +++ b/usr.bin/vi/xaw/xaw_screen.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)xaw_screen.c 8.6 (Berkeley) 5/21/94"; +#endif /* not lint */ + +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <termios.h> + +#include "compat.h" +#include <db.h> +#include <regex.h> + +#include "vi.h" + +/* + * xaw_init -- + * Athena widget screen initialization. + */ +int +xaw_screen_init(sp) + SCR *sp; +{ + msgq(sp, M_ERR, "The Athena widget screen not yet implemented"); + return (1); +} + +/* + * xaw_screen_copy -- + * Copy to a new screen. + */ +int +xaw_screen_copy(orig, sp) + SCR *orig, *sp; +{ + return (0); +} + +/* + * xaw_screen_end -- + * End a screen. + */ +int +xaw_screen_end(sp) + SCR *sp; +{ + return (0); +} + +/* + * xaw -- + * Main vi Athena widget screen loop. + */ +int +xaw(sp, ep, spp) + SCR *sp, **spp; + EXF *ep; +{ + *spp = NULL; + return (0); +} |