Termcap update, replacing elvis by nvi.

Removing elvis, importing nvi, ctags, updating libedit.

Change-Id: I881eb04d2dc64cf112facd992de1114e1a59107f
This commit is contained in:
Lionel Sambuc 2013-01-22 12:03:53 +01:00 committed by Lionel Sambuc
parent f9f6c9251a
commit 3e1db26a5a
491 changed files with 192709 additions and 28905 deletions

View file

@ -8,7 +8,7 @@ SUBDIR= add_route arp ash at backup banner basename btrace cal \
comm compress cp crc cron crontab cut \
dd decomp16 DESCRIBE devmand devsize df dhcpd \
dhrystone diff dirname diskctl dumpcore \
eject elvis env expand factor fbdctl \
eject env expand factor fbdctl \
find finger fingerd fix fold format fortune fsck.mfs \
ftp101 gcore gcov-pull getty grep head hexdump host \
hostaddr id ifconfig ifdef \

View file

@ -1 +0,0 @@
Lightweight vi

File diff suppressed because it is too large Load diff

View file

@ -1,68 +0,0 @@
The following options are missing:
[no]optimize - affects screen redrawing method
[no]redraw - simulate character insertion by redrawing line
[no]slowopen - don't use character insertion
tags="tags" - list of tags, used as TAGPATH
I'd like to improve the versatility of the options whose value is a command:
cc, make, kp, and ep. I'd like to add some notation that allows you to say
where to insert the current filename or current word.
-------------------------------------------------------------------------------
Currently, elvis is configured to look for | only in .exrc files. It doesn't
look for | in any interactively entered command lines, yet.
-------------------------------------------------------------------------------
The 'p', '#', and 'l' flags aren't supported. Also, ex commands don't accept
counts; e.g., ":c5" can't be used to change five lines.
-------------------------------------------------------------------------------
The following have been reported, but have not been verified. If you have
experienced any of the following, and haven't reported it yet, then please
report it now! I need more information about these bugs.
[Bugs that are not in this list should also be reported, of course.]
- Under VMS on an 80-column screen, after scolling sideways to approximately
column 110, a ^L will not redraw the part of the line after the cursor.
- On an Atari ST running under TOS: some ASCII keys seem to send '#' plus
another key. (This is normal for non-ASCII keys like <F1> or <Help>, but
ASCII keys should always send a single ASCII character.)
-------------------------------------------------------------------------------
BIG JOBS:
Desirable extension: merge input mode and visual command mode.
Display long lines by wrapping, like the real vi (if ":set sidescroll=0")
-------------------------------------------------------------------------------
- In the ":w >>filename" command, elvis doesn't allow any whitespace between
the ">>" and "filename".
- Elvis doesn't allow "backslash newline" inside a single EX command.
- VMS intercepts the control-T character, which is normally used to increase
indentation. The <Tab> key works, but it doesn't do quite the same thing.
(":map! ^I ^T" helps.)
- Under VMS, file I/O is very slow. Looking over the vmsio.c file, I get the
impression that it is rather over-done for elvis. Its speed could
probably be inproved.
- The errlist feature doesn't seem to work with the Borland compilers. Perhaps
they write to stderr instead of stdout? This will probably be easy to solve
once I modify the "cc" and "make" options, as described earlier.
- The command ":0" should move the cursor to line 1. Currently, it doesn't
move the cursor at all.
- File preservation is still flakey. On DOS/TOS/VMS systems, it is also more
complex that it should be.
- The act of appending to a cut buffer (as in "Ayy) sets file modification
flag. It shouldn't!
- The .exrc file is limited to BLKSIZE bytes -- 2048 on most systems, but
1024 on Minicx-PC, Coherent, and MS-DOS.
- I *still* haven't quite perfected the screen update code. If you suspect
that the screen doesn't accurately reflect the contents of the edit buffer,
then you should try doing a control-L.
I'll be overhauling the screen update code soon to make it wrap long lines
like the real vi. I expect to fix this bug then.

View file

@ -1,87 +0,0 @@
# This is the Makefile for Elvis' "doc" directory. It makes use of a
# troff-like formatter called mroff. Since you probably don't have mroff,
# you'll need to edit this Makefile before you can fully use it. It can
# also use nroff, though, so you should be able to get something out of it.
#
# make Use nroff to create an ASCII version of the manual.
# make foo.doc Use nroff to create an ASCII version of foo.man or foo.ms
# make manual Use MROFF to print a typeset manual on a laser printer
# make foo.1200 Use MROFF to print a typeset version of foo.man or foo.ms
# make foo.100 Use MROFF to print a draft-quality version of foo.man or foo.ms
# make foo.more Use MROFF to preview foo.man or foo.more on your terminal
#
###############################################################################
# Definitions...
MAN= ctags.man elvis.man elvprsv.man elvrec.man fmt.man ref.man
MS= title.ms index.ms intro.ms visual.ms ex.ms regexp.ms options.ms\
cutbufs.ms differ.ms internal.ms cflags.ms termcap.ms environ.ms\
versions.ms question.ms
ASC= title.doc index.doc intro.doc visual.doc ex.doc regexp.doc options.doc\
cutbufs.doc differ.doc internal.doc cflags.doc termcap.doc environ.doc\
versions.doc question.doc\
ctags.doc elvis.doc elvprsv.doc elvrec.doc fmt.doc ref.doc
MANUAL= title.1200 index.1200 intro.1200 visual.1200 ex.1200 regexp.1200 options.1200\
cutbufs.1200 differ.1200 internal.1200 cflags.1200 termcap.1200 environ.1200\
versions.1200\
ctags.1200 elvis.1200 elvprsv.1200 elvrec.1200 fmt.1200 ref.1200
VER= ver.ms
TROFF= mroff
NROFF= nroff
###############################################################################
# Rules...
.SUFFIXES: .tmp .100 .1200 .more .doc .man .ms .vga .vgas
.ms.tmp:
$(TROFF) -ms $(VER) $< >tmp
.man.tmp:
$(TROFF) -man $< >tmp
.ms.more:
$(TROFF) -ms $(VER) $< | draft | more
.man.more:
$(TROFF) -man $< | draft | more
.ms.1200:
$(TROFF) -ms $(VER) $< | hp2 1200 | lp -og $(PRINTER)
.man.1200:
$(TROFF) -man $< | hp2 1200 | lp -og $(PRINTER)
.ms.100:
$(TROFF) -ms $(VER) $< | hp2 100 | lp -og $(PRINTER)
.man.100:
$(TROFF) -man $< | hp2 100 | lp -og $(PRINTER)
.ms.doc:
$(NROFF) -ms $(VER) $< >$@
.man.doc:
$(NROFF) -man $< >$@
.ms.vga:
$(TROFF) -ms $(VER) $< >/tmp/foo
-vga /tmp/foo
rm /tmp/foo
.ms.vgas:
$(TROFF) -ms $(VER) $< >/tmp/foo
-vgas /tmp/foo
rm /tmp/foo
#############################################################################
# Targets...
asc: $(ASC)
cat $(ASC) >asc
manual: $(MANUAL)
clean:
rm -f *.doc *.sh

View file

@ -1,50 +0,0 @@
# Makefile for elvis
#
# Several groups of Makefile settings are included below. Choose *ONE* group
# of settings for your particular system, and leave the others commented out.
# The meanings of these settings are:
# EXTRA version-specific object files used in elvis
# CC the C compiler command, possibly with "memory model" flags
# CFLAGS compiler flags used to select compile-time options
# PROGS the list of all programs
# SORT if the "tags" file must be sorted, then SORT=-DSORT
PROGS= elvis ctags ref elvrec fmt elvprsv
CPPFLAGS+= -w -DCRUNCH \
-DNO_MKEXRC -DNO_CURSORSHAPE -DNO_CHARATTR -DNO_SHOWMODE \
-DNO_MODELINE -DNO_OPTCOLS -DNO_DIGRAPH -DNO_EXTENSIONS \
-DNO_ERRLIST -DNO_FKEY -DNO_VISIBLE -DNO_COLOR -DNO_POPUP
# LSC Force usage of local getline, this is required here as long as
# we do not fix elvis.
CPPFLAGS+= -D__NBSD_LIBC
###########################################################################
### The rest of this Makefile contains no user-serviceable parts ###
###########################################################################
SRCS.elvis= blk.c cmd1.c cmd2.c ctype.c curses.c cut.c ex.c input.c \
main.c misc.c modify.c move1.c move2.c move3.c move4.c move5.c \
opts.c recycle.c redraw.c regexp.c regsub.c system.c tio.c tmp.c \
unix.c vars.c vcmd.c vi.c
BINDIR= /usr/bin
# Do not overwrite vi and ex if they already exist, only install the links
# as a default fallback in their absence
.if !exists(${DESTDIR}/${BINDIR}/vi)
LINKS+= ${BINDIR}/elvis ${BINDIR}/vi
.endif
.if !exists(${DESTDIR}/${BINDIR}/ex)
LINKS+= ${BINDIR}/elvis ${BINDIR}/ex
.endif
MAN.elvis=
MAN.ctags=
MAN.ref=
MAN.elvrec=
MAN.fmt=
MAN.elvprsv=
.include <bsd.prog.mk>

View file

@ -1,414 +0,0 @@
echo x - ctags.man
sed '/^X/s///' > ctags.man << '/'
X.TH CTAGS 1
X.SH NAME
Xctags - Generates "tags" and (optionally) "refs" files
X.SH SYNOPSIS
X\fBctags\fP [\fB-stvra\fP] \fIfilesnames\fP...
X.SH DESCRIPTION
X\fIctags\fP generates the "tags" and "refs" files
Xfrom a group of C source files.
XThe "tags" file is used by Elvis' ":tag" command,
Xcontrol-] command,
Xand -t option.
XThe "refs" file is sometimes used by the \fIref(1)\fP program.
X.PP
XEach C source file is scanned for #define statements and
Xglobal function definitions.
XThe name of the macro or function becomes the name of a tag.
XFor each tag, a line is added to the "tags" file which contains:
X.RS
X.nf
X - the name of the tag
X - a tab character
X - the name of the file containing the tag
X - a tab character
X - a way to find the particular line within the file.
X.RE
X.fi
X.PP
XThe filenames list will typically be the names of all C source
Xfiles in the current directory, like this:
X.RS
X.nf
X$ ctags -stv *.[ch]
X.RE
X.fi
X.SH OPTIONS
X.IP \fB-t\fR
XInclude typedefs.
XA tag will be generated for each user-defined type.
XAlso tags will be generated for struct and enum names.
XTypes are considered to be global if they are defined in a header file,
Xand static if they are defined in a C source file.
X.IP \fB-v\fR
XInclude variable declarations.
XA tag will be generated for each variable, except for those that are declared
Xinside the body of a function.
X.IP \fB-s\fR
XInclude static tags.
X\fICtags\fR will normally put global tags in the "tags" file, and silently ignore
Xthe static tags.
XThis flag causes both global and static tags to be added.
XThe name of a static tag is generated by prefixing the name of the declared
Xitem with the name of the file where it is defined, with a colon in between.
XFor example, "static foo(){}" in "bar.c" results in a tag named "bar.c:foo".
X.IP \fB-r\fP
XThis causes \fIctags\fP to generate both "tags" and "refs".
XWithout \fB-r\fP, it would only generate "tags".
X.IP \fB-a\fR
XAppend to "tags", and maybe "refs".
XNormally, \fIctags\fR overwrites these files each time it is invoked.
XThis flag is useful when you have to many files in the current directory
Xfor you to list them on a single command-line;
Xit allows you to split the arguments among several invocations.
X.SH FILES
X.IP tags
XA cross-reference that lists each tag name, the name of the source file that
Xcontains it, and a way to locate a particular line in the source file.
X.IP refs
XThe "refs" file contains the definitions for each tag in the "tags" file,
Xand very little else.
XThis file can be useful, for example, when licensing restrictions prevent
Xyou from making the source code to the standard C library readable by everybody,
Xbut you still everybody to know what arguments the library functions need.
X.SH BUGS
X.PP
X\fIctags\fR is sensitive to indenting and line breaks.
XConsequently, it might not discover all of the tags in a file that
Xis formatted in an unusual way.
X.SH "SEE ALSO"
Xelvis(1), refs(1)
X.SH AUTHOR
X.nf
XSteve Kirkendall
Xkirkenda@cs.pdx.edu
X.fi
/
echo x - elvis.man
sed '/^X/s///' > elvis.man << '/'
X.TH ELVIS 1
X.SH NAME
Xelvis, ex, vi, view, input - The editor
X.SH SYNOPSIS
X\fBelvis\fP [\fIflags\fP] [\fB+\fP\fIcmd\fP] [\fIfiles\fP...]
X.SH DESCRIPTION
X\fIElvis\fP is a text editor which emulates \fIvi\fP/\fIex\fP.
X.PP
XOn systems which pass the program name as an argument, such as Unix and Minix,
Xyou may also install \fIelvis\fP under the names "ex", "vi", "view", and "input".
XThese extra names would normally be links to elvis;
Xsee the "ln" shell command.
X.PP
XWhen \fIelvis\fP is invoked as "vi",
Xit behaves exactly as though it was invoked as "elvis".
XHowever, if you invoke \fIelvis\fP as "view",
Xthen the readonly option is set as though you had given it the "-R" flag.
XIf you invoke \fIelvis\fP as "ex",
Xthen \fIelvis\fP will start up in the colon command mode
Xinstead of the visual command mode,
Xas though you had given it the "-e" flag.
XIf you invoke \fIelvis\fP as "input" or "edit",
Xthen \fIelvis\fP will start up in input mode,
Xas though the "-i" flag was given.
X.SH OPTIONS
X.IP \fB-r\fP
XTo the real vi, this flag means that a previous edit should be recovered.
X\fIElvis\fP, though, has a separate program, called \fIelvrec(1)\fP, for recovering
Xfiles.
XWhen you invoke \fIelvis\fP with -r, \fIelvis\fP will tell you to run \fIelvrec\fP.
X.IP \fB-R\fP
XThis sets the "readonly" option,
Xso you won't accidentally overwrite a file.
X.IP "\fB-t\fP \fItag\fP"
XThis causes \fIelvis\fP to start editing at the given tag.
X.IP "\fB-m\fP [\fIfile\fP]"
X\fIElvis\fP will search through \fIfile\fP for something that looks like
Xan error message from a compiler.
XIt will then begin editing the source file that caused the error,
Xwith the cursor sitting on the line where the error was detected.
XIf you don't explicitly name a \fIfile\fP, then "errlist" is assumed.
X.IP \fB-e\fP
X\fIElvis\fP will start up in colon command mode.
X.IP \fB-v\fP
X\fIElvis\fP will start up in visual command mode.
X.IP \fB-i\fP
X\fIElvis\fP will start up in input mode.
X.IP "\fB-w\fR \fIwinsize\fR"
XSets the "window" option's value to \fIwinsize\fR.
X.IP "\fB+\fP\fIcommand\fP or \fB-c\fP \fIcommand\fP"
XIf you use the +\fIcommand\fP parameter,
Xthen after the first file is loaded
X\fIcommand\fP is executed as an EX command.
XA typical example would be "elvis +237 foo",
Xwhich would cause \fIelvis\fP to start editing foo and
Xthen move directly to line 237.
XThe "-c \fIcommand\fP" variant was added for UNIX SysV compatibility.
X.SH FILES
X.IP /tmp/elv*
XDuring editing,
X\fIelvis\fP stores text in a temporary file.
XFor UNIX, this file will usually be stored in the /tmp directory,
Xand the first three characters will be "elv".
XFor other systems, the temporary files may be stored someplace else;
Xsee the version-specific section of the documentation.
X.IP tags
XThis is the database used by the \fI:tags\fP command and the \fB-t\fP option.
XIt is usually created by the \fIctags(1)\fP program.
X.IP ".exrc or elvis.rc"
XOn UNIX-like systems, a file called ".exrc" in your home directory
Xis executed as a series of \fIex\fR commands.
XA file by the same name may be executed in the current directory, too.
XOn non-UNIX systems, ".exrc" is usually an invalid file name;
Xthere, the initialization file is called "elvis.rc" instead.
X.SH "SEE ALSO"
Xctags(1), ref(1), virec(1)
X.PP
X\fIElvis - A Clone of Vi/Ex\fP, the complete \fIelvis\fP documentation.
X.SH BUGS
XThere is no LISP support.
XCertain other features are missing, too.
X.PP
XAuto-indent mode is not quite compatible with the real vi.
XAmong other things, 0^D and ^^D don't do what you might expect.
X.PP
XLong lines are displayed differently.
XThe real vi wraps long lines onto multiple rows of the screen,
Xbut \fIelvis\fP scrolls sideways.
X.SH AUTHOR
X.nf
XSteve Kirkendall
Xkirkenda@cs.pdx.edu
X.fi
X.PP
XMany other people have worked to port \fIelvis\fP to various operating systems.
XTo see who deserves credit, run the \fI:version\fP command from within \fIelvis\fP,
Xor look in the system-specific section of the complete documentation.
/
echo x - elvprsv.man
sed '/^X/s///' > elvprsv.man << '/'
X.TH ELVPRSV 1
X.SH NAME
Xelvprsv - Preserve the the modified version of a file after a crash.
X.SH SYNOPSIS
X.nf
X\fB\fBelvprsv\fP ["-\fIwhy elvis died\fP"] /tmp/\fIfilename\fP...
X\fB\fBelvprsv\fP -R /tmp/\fIfilename\fP...
X.fi
X.SH DESCRIPTION
X.PP
X\fIelvprsv\fP preserves your edited text after \fIelvis\fP dies.
XThe text can be recovered later, via the \fIelvprsv\fP program.
X.PP
XFor UNIX-like systems,
Xyou should never need to run this program from the command line.
XIt is run automatically when \fIelvis\fP is about to die,
Xand it should be run (via /etc/rc) when the computer is booted.
XTHAT'S ALL!
X.PP
XFor non-UNIX systems such as MS-DOS, you can either use \fIelvprsv\fP
Xthe same way as under UNIX systems (by running it from your AUTOEXEC.BAT file),
Xor you can run it separately with the "-R" flag to recover the files
Xin one step.
X.PP
XIf you're editing a file when \fIelvis\fP dies
X(due to a bug, system crash, power failure, etc.)
Xthen \fIelvprsv\fP will preserve the most recent version of your text.
XThe preserved text is stored in a special directory; it does NOT overwrite
Xyour text file automatically.
X.PP
X\fIelvprsv\fP will send mail to any user whose work it preserves,
Xif your operating system normally supports mail.
X.SH FILES
X.IP /tmp/elv*
XThe temporary file that \fIelvis\fP was using when it died.
X.IP /usr/preserve/p*
XThe text that is preserved by \fIelvprsv\fP.
X.IP /usr/preserve/Index
XA text file which lists the names of all preserved files, and the names
Xof the /usr/preserve/p* files which contain their preserved text.
X.SH BUGS
X.PP
XDue to the permissions on the /usr/preserve directory, on UNIX systems
X\fIelvprsv\fP must be run as superuser.
XThis is accomplished by making the \fIelvprsv\fP executable be owned by "root"
Xand turning on its "set user id" bit.
X.PP
XIf you're editing a nameless buffer when \fIelvis\fP dies, then \fIelvprsv\fP will pretend
Xthat the file was named "foo".
X.SH AUTHOR
X.nf
XSteve Kirkendall
Xkirkenda@cs.pdx.edu
X.fi
/
echo x - elvrec.man
sed '/^X/s///' > elvrec.man << '/'
X.TH ELVREC 1
X.SH NAME
Xelvrec - Recover the modified version of a file after a crash
X.SH SYNOPSIS
X.nf
X\fBelvrec\fP [\fIpreservedfile\fP [\fInewfile\fR]]
X.fi
X.SH DESCRIPTION
X.PP
XIf you're editing a file when \fIelvis\fP dies, the system crashes, or power fails,
Xthe most recent version of your text will be preserved.
XThe preserved text is stored in a special directory; it does NOT overwrite
Xyour text file automatically.
X.PP
XThe \fIelvrec\fP program locates the preserved version of a given file,
Xand writes it over the top of your text file -- or to a new file, if you prefer.
XThe recovered file will have nearly all of your changes.
X.PP
XTo see a list of all recoverable files, run \fIelvrec\fP with no arguments.
X.SH FILES
X.IP /usr/preserve/p*
XThe text that was preserved when \fIelvis\fP died.
X.IP /usr/preserve/Index
XA text file which lists the names of all preserved files, and the names
Xof the /usr/preserve/p* files which contain their preserved text.
X.SH BUGS
X.PP
X\fIelvrec\fP is very picky about filenames.
XYou must tell it to recover the file using exactly the same pathname as
Xwhen you were editing it.
XThe simplest way to do this is to go into the same directory that you were
Xediting, and invoke \fIelvrec\fP with the same filename as \fIelvis\fP.
XIf that doesn't work, then try running \fIelvrec\fP with no arguments,
Xto see exactly which pathname it is using for the desired file.
X.PP
XDue to the permissions on the /usr/preserve directory, on UNIX systems
X\fIelvrec\fP must be run as superuser.
XThis is accomplished by making the \fIelvrec\fP executable be owned by "root"
Xand setting its "set user id" bit.
X.PP
XIf you're editing a nameless buffer when \fIelvis\fP dies, then \fIelvrec\fP
Xwill pretend that the file was named "foo".
X.SH AUTHOR
X.nf
XSteve Kirkendall
Xkirkenda@cs.pdx.edu
X.fi
/
echo x - fmt.man
sed '/^X/s///' > fmt.man << '/'
X.TH FMT 1
X.SH NAME
Xfmt - adjust line-length for paragraphs of text
X.SH SYNOPSIS
X\fBfmt\fP [\-\fIwidth\fP] [\fIfiles\fP]...
X.SH DESCRIPTION
X\fIfmt\fR is a simple text formatter.
XIt inserts or deletes newlines, as necessary, to make all lines in a
Xparagraph be approximately the same width.
XIt preserves indentation and word spacing.
X.PP
XThe default line width is 72 characters.
XYou can override this with the \-\fIwidth\fR flag.
XIf you don't name any files on the command line,
Xthen \fIfmt\fR will read from stdin.
X.PP
XIt is typically used from within \fIvi\fR to adjust the line breaks
Xin a single paragraph.
XTo do this, move the cursor to the top of the paragraph,
Xtype "!}fmt", and
Xhit <Return>.
X.SH AUTHOR
X.nf
XSteve Kirkendall
Xkirkenda@cs.pdx.edu
X.fi
/
echo x - ref.man
sed '/^X/s///' > ref.man << '/'
X.TH REF 1
X.SH NAME
Xref - Display a C function header
X.SH SYNOPSIS
X\fBref\fR [-t] [-c \fIclass\fR]... [-f \fIfile\fR]... \fItag\fR
X.SH DESCRIPTION
X\fIref\fP quickly locates and displays the header of a function.
XTo do this, \fIref\fR
Xlooks in the "tags" file for the line that describes the function, and then
Xscans the source file for the function.
XWhen it locates the function, it displays an introductory comment
X(if there is one), the function's declaration, and the declarations of all
Xarguments.
X.SH "SEARCH METHOD"
X.PP
X\fIref\fR uses a fairly sophisticated tag look-up algorithm.
XIf you supply a filename via \fB-f\fR \fIfile\fR, then elvis first scans
Xthe tags file for a static tag from that file.
XThis search is limited to the tags file in the current directory.
X.PP
XIf you supply a classname via \fB-c\fR \fIclass\fR, then elvis searches
Xfor a tag from that class.
XThis search is not limited to the current directory;
XYou can supply a list of directories in the environment variable \fITAGPATH\fR,
Xand \fIref\fR will search through the "tags" file in each directory until it finds
Xa tag in the desired class.
X.PP
XIf that fails, \fIref\fR will then try to look up an ordinary global tag.
XThis search checks all of the directories listed in \fITAGPATH\fR, too.
X.PP
XIf you've given the \fB-t\fR flag, then \fIref\fR will simply output the tag line that
Xit found, and then exit.
XWithout \fB-t\fR, though, \fIref\fR will search for the tag line.
XIt will try to open the source file, which should be in the same directory
Xas the tags file where the tag was discovered.
XIf the source file doesn't exist, or is unreadable, then \fIref\fR will try to open
Xa file called "\fIrefs\fR" in that directory.
XEither way, \fIref\fR will try to locate the tag, and display whatever it finds.
X.SH "INTERACTION WITH ELVIS"
X.PP
X\fIref\fP is used by \fIelvis\fR' shift-K command.
XIf the cursor is located on a word such as "splat", in the file "foo.c",
Xthen \fIelvis\fR will invoke \fIref\fR with the command "ref -f foo.c splat".
X.PP
XIf \fIelvis\fR has been compiled with the -DEXTERNAL_TAGS flag, then \fIelvis\fR will
Xuse \fIref\fR \fB\fRto scan the tags files.
XThis is slower than the built-in tag searching, but it allows \fIelvis\fR to access
Xthe more sophisticated tag lookup provided by \fIref\fR.
XOther than that, external tags should act exactly like internal tags.
X.SH OPTIONS
X.IP \fB-t\fR
XOutput tag info, instead of the function header.
X.IP "\fB-f\fR \fIfile\fR"
XThe tag might be a static function in \fIfile\fR.
XYou can use several -f flags to have \fIref\fR consider static tags from more than one file.
X.IP "\fB-c\fR \fIclass\fR"
XThe tag might be a member of class \fIclass\fR.
XYou can use several -c flags to have \fIref\fR consider tags from more than one class.
X.SH FILES
X.IP \fBtags\fR
XList of function names and their locations, generated by \fIctags\fR.
X.IP \fBrefs\fR
XFunction headers extracted from source files (optional).
X.SH ENVIRONMENT
X.IP \fBTAGPATH\fR
XList of directories to be searched.
XThe elements in the list are separated by either
Xsemicolons (for MS-DOS, Atari TOS, and AmigaDos), or
Xby colons (every other operating system).
XFor each operating system, \fIref\fR has a built-in default which is probably
Xadequate.
X.SH NOTES
X.PP
XYou might want to generate a "tags" file the directory that contains the
Xsource code for standard C library on your system.
XIf licensing restrictions prevent you from making the library source readable
Xby everybody, then you can have \fIctags\fR generate a "refs" file,
Xand make "refs" readable by everybody.
X.PP
XIf your system doesn't come with the library source code, then perhaps you
Xcan produce something workable from the \fIlint\fR libraries.
X.SH "SEE ALSO"
Xelvis(1), ctags(1)
X.SH AUTHOR
X.nf
XSteve Kirkendall
Xkirkenda@cs.pdx.edu
X.fi
/

View file

@ -1,31 +0,0 @@
Elvis is a clone of vi/ex, the standard UNIX editor. Elvis supports
nearly all of the vi/ex commands, in both visual mode and colon mode.
Elvis runs under BSD UNIX, AT&T SysV UNIX, SCO Xenix, Minix, MS-DOS
(Turbo-C or MSC 5.1), Atari TOS, OS9/68000, Coherent, VMS, and AmigaDos.
Ports to other operating systems are in progress; contact me before you
start porting it to some other OS, because somebody else may have
already done it for you.
Elvis is freely redistributable, in either source form or executable
form. There are no restrictions on how you may use it.
The file "elvisman.txt" contains the manual for elvis. It is a plain
ASCII file with nothing more exotic than a newline character. It is
formatted for 66-line, 80-column pages. There may also be an archive of
"*.ms" and "*.man" files, which contain the TROFF source text used to
generate that manual.
The file named "Makefile.mix" is used to compile elvis for all systems
except VMS and possibly MS-DOS. You should copy "Makefile.mix" to
"Makefile", and then edit "Makefile" to select the appropriate group of
settings for your system.
Author: Steve Kirkendall
14407 SW Teal Blvd. #C
Beaverton, OR 97005
E-mail: kirkenda@cs.pdx.edu
Phone: (503) 643-6980

View file

@ -1,469 +0,0 @@
/* blk.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the functions that get/put blocks from the temp file.
* It also contains the "do" and "undo" functions.
*/
#include "config.h"
#include "vi.h"
#ifndef NBUFS
# define NBUFS 5 /* must be at least 3 -- more is better */
#endif
/*------------------------------------------------------------------------*/
BLK hdr; /* buffer for the header block */
static int b4cnt; /* used to count context of beforedo/afterdo */
static struct _blkbuf
{
BLK buf; /* contents of a text block */
unsigned short logical; /* logical block number */
int dirty; /* must the buffer be rewritten? */
}
blk[NBUFS], /* buffers for text[?] blocks */
*toonew, /* buffer which shouldn't be recycled yet */
*newtoo, /* another buffer which should be recycled */
*recycle = blk; /* next block to be recycled */
/* This function wipes out all buffers */
void blkinit()
{
int i;
for (i = 0; i < NBUFS; i++)
{
blk[i].logical = 0;
blk[i].dirty = FALSE;
}
for (i = 0; i < MAXBLKS; i++)
{
hdr.n[i] = 0;
}
}
/* This function allocates a buffer and fills it with a given block's text */
BLK *blkget(logical)
int logical; /* logical block number to fetch */
{
REG struct _blkbuf *this; /* used to step through blk[] */
REG int i;
/* if logical is 0, just return the hdr buffer */
if (logical == 0)
{
return &hdr;
}
/* see if we have that block in mem already */
for (this = blk; this < &blk[NBUFS]; this++)
{
if (this->logical == logical)
{
newtoo = toonew;
toonew = this;
return &this->buf;
}
}
/* choose a block to be recycled */
do
{
this = recycle++;
if (recycle == &blk[NBUFS])
{
recycle = blk;
}
} while (this == toonew || this == newtoo);
/* if it contains a block, flush that block */
blkflush(this);
/* fill this buffer with the desired block */
this->logical = logical;
if (hdr.n[logical])
{
/* it has been used before - fill it from tmp file */
lseek(tmpfd, (long)hdr.n[logical] * (long)BLKSIZE, 0);
if (read(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE)
{
msg("Error reading back from tmp file!");
}
}
else
{
/* it is new - zero it */
for (i = 0; i < BLKSIZE; i++)
{
this->buf.c[i] = 0;
}
}
/* This isn't really a change, but it does potentially invalidate
* the kinds of shortcuts that the "changes" variable is supposed
* to protect us from... so count it as a change.
*/
changes++;
/* mark it as being "not dirty" */
this->dirty = 0;
/* return it */
newtoo = toonew;
toonew = this;
return &this->buf;
}
/* This function writes a block out to the temporary file */
void blkflush(this)
REG struct _blkbuf *this; /* the buffer to flush */
{
long seekpos; /* seek position of the new block */
unsigned short physical; /* physical block number */
/* if its empty (an orphan blkadd() maybe?) then make it dirty */
if (this->logical && !*this->buf.c)
{
blkdirty(&this->buf);
}
/* if it's an empty buffer or a clean version is on disk, quit */
if (!this->logical || hdr.n[this->logical] && !this->dirty)
{
return;
}
/* find a free place in the file */
#ifndef NO_RECYCLE
seekpos = allocate();
lseek(tmpfd, seekpos, 0);
#else
seekpos = lseek(tmpfd, 0L, 2);
#endif
physical = seekpos / BLKSIZE;
/* put the block there */
if (write(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE)
{
msg("Trouble writing to tmp file");
}
this->dirty = FALSE;
/* update the header so it knows we put it there */
hdr.n[this->logical] = physical;
}
/* This function sets a block's "dirty" flag or deletes empty blocks */
void blkdirty(bp)
BLK *bp; /* buffer returned by blkget() */
{
REG int i, j;
REG char *scan;
REG int k;
/* find the buffer */
for (i = 0; i < NBUFS && bp != &blk[i].buf; i++)
{
}
#ifdef DEBUG
if (i >= NBUFS)
{
msg("blkdirty() called with unknown buffer at 0x%lx", bp);
return;
}
if (blk[i].logical == 0)
{
msg("blkdirty called with freed buffer");
return;
}
#endif
/* if this block ends with line# INFINITY, then it must have been
* allocated unnecessarily during tmpstart(). Forget it.
*/
if (lnum[blk[i].logical] == INFINITY)
{
#ifdef DEBUG
if (blk[i].buf.c[0])
{
msg("bkldirty called with non-empty extra BLK");
}
#endif
blk[i].logical = 0;
blk[i].dirty = FALSE;
return;
}
/* count lines in this block */
for (j = 0, scan = bp->c; *scan && scan < bp->c + BLKSIZE; scan++)
{
if (*scan == '\n')
{
j++;
}
}
/* adjust lnum, if necessary */
k = blk[i].logical;
j += (lnum[k - 1] - lnum[k]);
if (j != 0)
{
nlines += j;
while (k < MAXBLKS && lnum[k] != INFINITY)
{
lnum[k++] += j;
}
}
/* if it still has text, mark it as dirty */
if (*bp->c)
{
blk[i].dirty = TRUE;
}
else /* empty block, so delete it */
{
/* adjust the cache */
k = blk[i].logical;
for (j = 0; j < NBUFS; j++)
{
if (blk[j].logical >= k)
{
blk[j].logical--;
}
}
/* delete it from hdr.n[] and lnum[] */
blk[i].logical = 0;
blk[i].dirty = FALSE;
while (k < MAXBLKS - 1)
{
hdr.n[k] = hdr.n[k + 1];
lnum[k] = lnum[k + 1];
k++;
}
hdr.n[MAXBLKS - 1] = 0;
lnum[MAXBLKS - 1] = INFINITY;
}
}
/* insert a new block into hdr, and adjust the cache */
BLK *blkadd(logical)
int logical; /* where to insert the new block */
{
REG int i;
/* adjust hdr and lnum[] */
for (i = MAXBLKS - 1; i > logical; i--)
{
hdr.n[i] = hdr.n[i - 1];
lnum[i] = lnum[i - 1];
}
hdr.n[logical] = 0;
lnum[logical] = lnum[logical - 1];
/* adjust the cache */
for (i = 0; i < NBUFS; i++)
{
if (blk[i].logical >= logical)
{
blk[i].logical++;
}
}
/* return the new block, via blkget() */
return blkget(logical);
}
/* This function forces all dirty blocks out to disk */
void blksync()
{
int i;
for (i = 0; i < NBUFS; i++)
{
/* blk[i].dirty = TRUE; */
blkflush(&blk[i]);
}
if (*o_sync)
{
sync();
}
}
/*------------------------------------------------------------------------*/
static MARK undocurs; /* where the cursor should go if undone */
static long oldnlines;
static long oldlnum[MAXBLKS];
/* This function should be called before each command that changes the text.
* It defines the state that undo() will reset the file to.
*/
void beforedo(forundo)
int forundo; /* boolean: is this for an undo? */
{
REG int i;
REG long l;
/* if this is a nested call to beforedo, quit! Use larger context */
if (b4cnt++ > 0)
{
return;
}
/* force all block buffers to disk */
blksync();
#ifndef NO_RECYCLE
/* perform garbage collection on blocks from tmp file */
garbage();
#endif
/* force the header out to disk */
lseek(tmpfd, 0L, 0);
if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) != BLKSIZE)
{
msg("Trouble writing header to tmp file ");
}
/* copy or swap oldnlines <--> nlines, oldlnum <--> lnum */
if (forundo)
{
for (i = 0; i < MAXBLKS; i++)
{
l = lnum[i];
lnum[i] = oldlnum[i];
oldlnum[i] = l;
}
l = nlines;
nlines = oldnlines;
oldnlines = l;
}
else
{
for (i = 0; i < MAXBLKS; i++)
{
oldlnum[i] = lnum[i];
}
oldnlines = nlines;
}
/* save the cursor position */
undocurs = cursor;
/* upon return, the calling function continues and makes changes... */
}
/* This function marks the end of a (nested?) change to the file */
void afterdo()
{
if (--b4cnt)
{
/* after abortdo(), b4cnt may decribe nested beforedo/afterdo
* pairs incorrectly. If it is decremented to often, then
* keep b4cnt sane but don't do anything else.
*/
if (b4cnt < 0)
b4cnt = 0;
return;
}
/* make sure the cursor wasn't left stranded in deleted text */
if (markline(cursor) > nlines)
{
cursor = MARK_LAST;
}
/* NOTE: it is still possible that markidx(cursor) is after the
* end of a line, so the Vi mode will have to take care of that
* itself */
/* if a significant change has been made to this file, then set the
* MODIFIED flag.
*/
if (significant)
{
setflag(file, MODIFIED);
setflag(file, UNDOABLE);
}
}
/* This function cuts short the current set of changes. It is called after
* a SIGINT.
*/
void abortdo()
{
/* finish the operation immediately. */
if (b4cnt > 0)
{
b4cnt = 1;
afterdo();
}
/* in visual mode, the screen is probably screwed up */
if (mode == MODE_COLON)
{
mode = MODE_VI;
}
if (mode == MODE_VI)
{
redraw(MARK_UNSET, FALSE);
}
}
/* This function discards all changes made since the last call to beforedo() */
int undo()
{
BLK oldhdr;
/* if beforedo() has never been run, fail */
if (!tstflag(file, UNDOABLE))
{
msg("You haven't modified this file yet.");
return FALSE;
}
/* read the old header form the tmp file */
lseek(tmpfd, 0L, 0);
if (read(tmpfd, oldhdr.c, (unsigned)BLKSIZE) != BLKSIZE)
{
msg("Trouble rereading the old header from tmp file");
}
/* "do" the changed version, so we can undo the "undo" */
cursor = undocurs;
beforedo(TRUE);
afterdo();
/* wipe out the block buffers - we can't assume they're correct */
blkinit();
/* use the old header -- and therefore the old text blocks */
hdr = oldhdr;
/* This is a change */
significant = TRUE;
changes++;
return TRUE;
}

File diff suppressed because it is too large Load diff

View file

@ -1,942 +0,0 @@
/* cmd2.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains some of the commands - mostly ones that change text */
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
#if TOS
# include <stat.h>
#else
# if OSK
# include "osk.h"
# else
# if AMIGA
# include "amistat.h"
# else
# include <sys/stat.h>
# endif
# endif
#endif
/*ARGSUSED*/
void cmd_substitute(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra; /* rest of the command line */
{
char *line; /* a line from the file */
regexp *re; /* the compiled search expression */
char *subst; /* the substitution string */
char *opt; /* substitution options */
long l; /* a line number */
char *s, *d; /* used during subtitutions */
char *conf; /* used during confirmation */
long chline; /* # of lines changed */
long chsub; /* # of substitutions made */
static optp; /* boolean option: print when done? */
static optg; /* boolean option: substitute globally in line? */
static optc; /* boolean option: confirm before subst? */
#ifndef CRUNCH
long oldnlines;
#endif
/* for now, assume this will fail */
rptlines = -1L;
if (cmd == CMD_SUBAGAIN)
{
#ifndef NO_MAGIC
if (*o_magic)
subst = "~";
else
#endif
subst = "\\~";
re = regcomp("");
/* if visual "&", then turn off the "p" and "c" options */
if (bang)
{
optp = optc = FALSE;
}
}
else /* CMD_SUBSTITUTE */
{
/* make sure we got a search pattern */
if (*extra != '/' && *extra != '?')
{
msg("Usage: s/regular expression/new text/");
return;
}
/* parse & compile the search pattern */
subst = parseptrn(extra);
re = regcomp(extra + 1);
}
/* abort if RE error -- error message already given by regcomp() */
if (!re)
{
return;
}
if (cmd == CMD_SUBSTITUTE)
{
/* parse the substitution string & find the option string */
for (opt = subst; *opt && *opt != *extra; opt++)
{
if (*opt == '\\' && opt[1])
{
opt++;
}
}
if (*opt)
{
*opt++ = '\0';
}
/* analyse the option string */
if (!*o_edcompatible)
{
optp = optg = optc = FALSE;
}
while (*opt)
{
switch (*opt++)
{
case 'p': optp = !optp; break;
case 'g': optg = !optg; break;
case 'c': optc = !optc; break;
case ' ':
case '\t': break;
default:
msg("Subst options are p, c, and g -- not %c", opt[-1]);
return;
}
}
}
/* if "c" or "p" flag was given, and we're in visual mode, then NEWLINE */
if ((optc || optp) && mode == MODE_VI)
{
addch('\n');
exrefresh();
}
ChangeText
{
/* reset the change counters */
chline = chsub = 0L;
/* for each selected line */
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* fetch the line */
line = fetchline(l);
/* if it contains the search pattern... */
if (regexec(re, line, TRUE))
{
/* increment the line change counter */
chline++;
/* initialize the pointers */
s = line;
d = tmpblk.c;
/* do once or globally ... */
do
{
#ifndef CRUNCH
/* confirm, if necessary */
if (optc)
{
for (conf = line; conf < re->startp[0]; conf++)
addch(*conf);
standout();
for ( ; conf < re->endp[0]; conf++)
addch(*conf);
standend();
for (; *conf; conf++)
addch(*conf);
addch('\n');
exrefresh();
if (getkey(0) != 'y')
{
/* copy accross the original chars */
while (s < re->endp[0])
*d++ = *s++;
/* skip to next match on this line, if any */
goto Continue;
}
}
#endif /* not CRUNCH */
/* increment the substitution change counter */
chsub++;
/* copy stuff from before the match */
while (s < re->startp[0])
{
*d++ = *s++;
}
/* substitute for the matched part */
regsub(re, subst, d);
s = re->endp[0];
d += strlen(d);
Continue:
/* if this regexp could conceivably match
* a zero-length string, then require at
* least 1 unmatched character between
* matches.
*/
if (re->minlen == 0)
{
if (!*s)
break;
*d++ = *s++;
}
} while (optg && regexec(re, s, FALSE));
/* copy stuff from after the match */
while (*d++ = *s++) /* yes, ASSIGNMENT! */
{
}
#ifndef CRUNCH
/* NOTE: since the substitution text is allowed to have ^Ms which are
* translated into newlines, it is possible that the number of lines
* in the file will increase after each line has been substituted.
* we need to adjust for this.
*/
oldnlines = nlines;
#endif
/* replace the old version of the line with the new */
d[-1] = '\n';
d[0] = '\0';
change(MARK_AT_LINE(l), MARK_AT_LINE(l + 1), tmpblk.c);
#ifndef CRUNCH
l += nlines - oldnlines;
tomark += MARK_AT_LINE(nlines - oldnlines);
#endif
/* if supposed to print it, do so */
if (optp)
{
addstr(tmpblk.c);
exrefresh();
}
/* move the cursor to that line */
cursor = MARK_AT_LINE(l);
}
}
}
/* free the regexp */
free(re);
/* if done from within a ":g" command, then finish silently */
if (doingglobal)
{
rptlines = chline;
rptlabel = "changed";
return;
}
/* Reporting */
if (chsub == 0)
{
msg("Substitution failed");
}
else if (chline >= *o_report)
{
msg("%ld substitutions on %ld lines", chsub, chline);
}
rptlines = 0L;
}
/*ARGSUSED*/
void cmd_delete(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
MARK curs2; /* an altered form of the cursor */
/* choose your cut buffer */
if (*extra == '"')
{
extra++;
}
if (*extra)
{
cutname(*extra);
}
/* make sure we're talking about whole lines here */
frommark = frommark & ~(BLKSIZE - 1);
tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
/* yank the lines */
cut(frommark, tomark);
/* if CMD_DELETE then delete the lines */
if (cmd != CMD_YANK)
{
curs2 = cursor;
ChangeText
{
/* delete the lines */
delete(frommark, tomark);
}
if (curs2 > tomark)
{
cursor = curs2 - tomark + frommark;
}
else if (curs2 > frommark)
{
cursor = frommark;
}
}
}
/*ARGSUSED*/
void cmd_append(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l; /* line counter */
#ifndef CRUNCH
/* if '!' then toggle auto-indent */
if (bang)
{
*o_autoindent = !*o_autoindent;
}
#endif
ChangeText
{
/* if we're doing a change, delete the old version */
if (cmd == CMD_CHANGE)
{
/* delete 'em */
cmd_delete(frommark, tomark, cmd, bang, extra);
}
/* new lines start at the frommark line, or after it */
l = markline(frommark);
if (cmd == CMD_APPEND)
{
l++;
}
/* get lines until no more lines, or "." line, and insert them */
while (vgets('\0', tmpblk.c, BLKSIZE) >= 0)
{
addch('\n');
if (!strcmp(tmpblk.c, "."))
{
break;
}
strcat(tmpblk.c, "\n");
add(MARK_AT_LINE(l), tmpblk.c);
l++;
}
}
/* on the odd chance that we're calling this from vi mode ... */
redraw(MARK_UNSET, FALSE);
}
/*ARGSUSED*/
void cmd_put(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
/* choose your cut buffer */
if (*extra == '"')
{
extra++;
}
if (*extra)
{
cutname(*extra);
}
/* paste it */
ChangeText
{
cursor = paste(frommark, TRUE, FALSE);
}
}
/*ARGSUSED*/
void cmd_join(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l;
char *scan;
int len; /* length of the new line */
/* if only one line is specified, assume the following one joins too */
if (markline(frommark) == nlines)
{
msg("Nothing to join with this line");
return;
}
if (markline(frommark) == markline(tomark))
{
tomark += BLKSIZE;
}
/* get the first line */
l = markline(frommark);
strcpy(tmpblk.c, fetchline(l));
len = strlen(tmpblk.c);
/* build the longer line */
while (++l <= markline(tomark))
{
/* get the next line */
scan = fetchline(l);
/* remove any leading whitespace */
while (*scan == '\t' || *scan == ' ')
{
scan++;
}
/* see if the line will fit */
if (strlen(scan) + len + 3 > BLKSIZE)
{
msg("Can't join -- the resulting line would be too long");
return;
}
/* catenate it, with a space (or two) in between */
if (!bang)
{
if (len >= 1)
{
if (tmpblk.c[len - 1] == '.'
|| tmpblk.c[len - 1] == '?'
|| tmpblk.c[len - 1] == '!')
{
tmpblk.c[len++] = ' ';
}
tmpblk.c[len++] = ' ';
}
}
strcpy(tmpblk.c + len, scan);
len += strlen(scan);
}
tmpblk.c[len++] = '\n';
tmpblk.c[len] = '\0';
/* make the change */
ChangeText
{
frommark &= ~(BLKSIZE - 1);
tomark &= ~(BLKSIZE - 1);
tomark += BLKSIZE;
change(frommark, tomark, tmpblk.c);
}
/* Reporting... */
rptlines = markline(tomark) - markline(frommark) - 1L;
rptlabel = "joined";
}
/*ARGSUSED*/
void cmd_shift(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l; /* line number counter */
int oldidx; /* number of chars previously used for indent */
int newidx; /* number of chars in the new indent string */
int oldcol; /* previous indent amount */
int newcol; /* new indent amount */
char *text; /* pointer to the old line's text */
ChangeText
{
/* for each line to shift... */
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* get the line - ignore empty lines unless ! mode */
text = fetchline(l);
if (!*text && !bang)
continue;
/* calc oldidx and oldcol */
for (oldidx = 0, oldcol = 0;
text[oldidx] == ' ' || text[oldidx] == '\t';
oldidx++)
{
if (text[oldidx] == ' ')
{
oldcol += 1;
}
else
{
oldcol += *o_tabstop - (oldcol % *o_tabstop);
}
}
/* calc newcol */
if (cmd == CMD_SHIFTR)
{
newcol = oldcol + (*o_shiftwidth & 0xff);
}
else
{
newcol = oldcol - (*o_shiftwidth & 0xff);
if (newcol < 0)
newcol = 0;
}
/* if no change, then skip to next line */
if (oldcol == newcol)
continue;
/* build a new indent string */
newidx = 0;
if (*o_autotab)
{
while (newcol >= *o_tabstop)
{
tmpblk.c[newidx++] = '\t';
newcol -= *o_tabstop;
}
}
while (newcol > 0)
{
tmpblk.c[newidx++] = ' ';
newcol--;
}
tmpblk.c[newidx] = '\0';
/* change the old indent string into the new */
change(MARK_AT_LINE(l), MARK_AT_LINE(l) + oldidx, tmpblk.c);
}
}
/* Reporting... */
rptlines = markline(tomark) - markline(frommark) + 1L;
if (cmd == CMD_SHIFTR)
{
rptlabel = ">ed";
}
else
{
rptlabel = "<ed";
}
}
/*ARGSUSED*/
void cmd_read(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
int fd, rc; /* used while reading from the file */
char *scan; /* used for finding NUL characters */
int hadnul; /* boolean: any NULs found? */
int addnl; /* boolean: forced to add newlines? */
int len; /* number of chars in current line */
long lines; /* number of lines in current block */
struct stat statb;
/* special case: if ":r !cmd" then let the filter() function do it */
if (extra[0] == '!')
{
filter(frommark, MARK_UNSET, extra + 1, TRUE);
return;
}
/* open the file */
fd = open(extra, O_RDONLY);
if (fd < 0)
{
msg("Can't open \"%s\"", extra);
return;
}
#ifndef CRUNCH
if (stat(extra, &statb) < 0)
{
msg("Can't stat \"%s\"", extra);
}
# if TOS
if (statb.st_mode & S_IJDIR)
# else
# if OSK
if (statb.st_mode & S_IFDIR)
# else
if ((statb.st_mode & S_IFMT) != S_IFREG)
# endif
# endif
{
msg("\"%s\" is not a regular file", extra);
return;
}
#endif /* not CRUNCH */
/* get blocks from the file, and add them */
ChangeText
{
/* insertion starts at the line following frommark */
tomark = frommark = (frommark | (BLKSIZE - 1L)) + 1L;
len = 0;
hadnul = addnl = FALSE;
/* add an extra newline, so partial lines at the end of
* the file don't trip us up
*/
add(tomark, "\n");
/* for each chunk of text... */
while ((rc = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
{
/* count newlines, convert NULs, etc. ... */
for (lines = 0, scan = tmpblk.c; rc > 0; rc--, scan++)
{
/* break up long lines */
if (*scan != '\n' && len + 2 > BLKSIZE)
{
*scan = '\n';
addnl = TRUE;
}
/* protect against NUL chars in file */
if (!*scan)
{
*scan = 0x80;
hadnul = TRUE;
}
/* starting a new line? */
if (*scan == '\n')
{
/* reset length at newline */
len = 0;
lines++;
}
else
{
len++;
}
}
/* add the text */
*scan = '\0';
add(tomark, tmpblk.c);
tomark += MARK_AT_LINE(lines) + len - markidx(tomark);
}
/* if partial last line, then retain that first newline */
if (len > 0)
{
msg("Last line had no newline");
tomark += BLKSIZE; /* <- for the rptlines calc */
}
else /* delete that first newline */
{
delete(tomark, (tomark | (BLKSIZE - 1L)) + 1L);
}
}
/* close the file */
close(fd);
/* Reporting... */
rptlines = markline(tomark) - markline(frommark);
rptlabel = "read";
if (mode == MODE_EX)
{
cursor = (tomark & ~BLKSIZE) - BLKSIZE;
}
else
{
cursor = frommark;
}
if (addnl)
msg("Newlines were added to break up long lines");
if (hadnul)
msg("NULs were converted to 0x80");
}
/*ARGSUSED*/
void cmd_undo(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
undo();
}
/* print the selected lines */
/*ARGSUSED*/
void cmd_print(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
REG char *scan;
REG long l;
REG int col;
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* display a line number, if CMD_NUMBER */
if (cmd == CMD_NUMBER)
{
sprintf(tmpblk.c, "%6ld ", l);
qaddstr(tmpblk.c);
col = 8;
}
else
{
col = 0;
}
/* get the next line & display it */
for (scan = fetchline(l); *scan; scan++)
{
/* expand tabs to the proper width */
if (*scan == '\t' && cmd != CMD_LIST)
{
do
{
qaddch(' ');
col++;
} while (col % *o_tabstop != 0);
}
else if (*scan > 0 && *scan < ' ' || *scan == '\177')
{
qaddch('^');
qaddch(*scan ^ 0x40);
col += 2;
}
else if ((*scan & 0x80) && cmd == CMD_LIST)
{
sprintf(tmpblk.c, "\\%03o", UCHAR(*scan));
qaddstr(tmpblk.c);
col += 4;
}
else
{
qaddch(*scan);
col++;
}
/* wrap at the edge of the screen */
if (!has_AM && col >= COLS)
{
addch('\n');
col -= COLS;
}
}
if (cmd == CMD_LIST)
{
qaddch('$');
}
addch('\n');
exrefresh();
}
}
/* move or copy selected lines */
/*ARGSUSED*/
void cmd_move(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
MARK destmark;
/* parse the destination linespec. No defaults. Line 0 is okay */
destmark = cursor;
if (!strcmp(extra, "0"))
{
destmark = 0L;
}
else if (linespec(extra, &destmark) == extra || !destmark)
{
msg("invalid destination address");
return;
}
/* flesh the marks out to encompass whole lines */
frommark &= ~(BLKSIZE - 1);
tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
destmark = (destmark & ~(BLKSIZE - 1)) + BLKSIZE;
/* make sure the destination is valid */
if (cmd == CMD_MOVE && destmark >= frommark && destmark < tomark)
{
msg("invalid destination address");
}
/* Do it */
ChangeText
{
/* save the text to a cut buffer */
cutname('\0');
cut(frommark, tomark);
/* if we're not copying, delete the old text & adjust destmark */
if (cmd != CMD_COPY)
{
delete(frommark, tomark);
if (destmark >= frommark)
{
destmark -= (tomark - frommark);
}
}
/* add the new text */
paste(destmark, FALSE, FALSE);
}
/* move the cursor to the last line of the moved text */
cursor = destmark + (tomark - frommark) - BLKSIZE;
if (cursor < MARK_FIRST || cursor >= MARK_LAST + BLKSIZE)
{
cursor = MARK_LAST;
}
/* Reporting... */
rptlabel = ( (cmd == CMD_COPY) ? "copied" : "moved" );
}
/* execute EX commands from a file */
/*ARGSUSED*/
void cmd_source(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
/* must have a filename */
if (!*extra)
{
msg("\"source\" requires a filename");
return;
}
doexrc(extra);
}
#ifndef NO_AT
/*ARGSUSED*/
void cmd_at(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
static nest = FALSE;
int result;
char buf[MAXRCLEN];
/* don't allow nested macros */
if (nest)
{
msg("@ macros can't be nested");
return;
}
nest = TRUE;
/* require a buffer name */
if (*extra == '"')
extra++;
if (!*extra || !isascii(*extra) ||!islower(*extra))
{
msg("@ requires a cut buffer name (a-z)");
}
/* get the contents of the buffer */
result = cb2str(*extra, buf, (unsigned)(sizeof buf));
if (result <= 0)
{
msg("buffer \"%c is empty", *extra);
}
else if (result >= sizeof buf)
{
msg("buffer \"%c is too large to execute", *extra);
}
else
{
/* execute the contents of the buffer as ex commands */
exstring(buf, result, '\\');
}
nest = FALSE;
}
#endif

View file

@ -1,526 +0,0 @@
/*
* vi configuration file
* We try to automatically configure to various compilers and operating
* systems. Extend the autoconf section as needed.
*/
#ifndef _CONFIG_H
# define _CONFIG_H
/*************************** autoconf section ************************/
/* Commodore-Amiga */
#ifdef amiga
# define AMIGA 1
# define COMPILED_BY "Manx Aztec C 5.2b"
#endif
/* standard unix V (?) */
#ifdef M_SYSV
# define UNIXV 1
#endif
/* xelos system, University of Ulm */
#ifdef xelos
# define UNIXV 1
#endif
/* BSD UNIX? */
#ifdef bsd
# define BSD 1
#else
# ifdef sun
# define BSD 1
# endif
#endif
/* Microsoft C: sorry, Watcom does the same thing */
#ifdef M_I86
# ifndef M_SYSV
# define MSDOS 1
# ifdef IBMC2
# define COMPILED_BY "IBM C/2 1.00"
# else
# define MICROSOFT 1
# define COMPILED_BY "Microsoft C 5.10"
# endif
# endif
#endif
/* Borland's Turbo C */
#ifdef __TURBOC__
# define MSDOS 1
# define TURBOC 1
# ifdef __BORLANDC__
# define COMPILED_BY "Borland C 2.00"
# else
# define COMPILED_BY (__TURBOC__ >= 661 ? "Turbo C++ 1.00" : "Turbo C 2.00")
# endif
#endif
/* Tos Mark-Williams */
#ifdef M68000
# define TOS 1
# define COMPILED_BY "Mark Williams C"
#endif
/* Tos GNU-C */
#if defined(__atarist__) && defined(__gem__)
# define TOS 1
# define COMPILED_BY "GNU-C " __VERSION__
#endif
/* OS9/68000 */
#ifdef OSK
# define COMPILED_BY "Microware C V2.3 Edition 40"
#endif
/* DEC Rainbow, running MS-DOS (handled by earlier MS-DOS tests) */
/* (would need -DRAINBOW in CFLAGS to compile a Rainbow-compatible .EXE) */
#ifdef VMS
# define COMPILED_BY "VAX/VMS VAXC compiler"
# undef VMS
# define VMS 1
#endif
/*************************** end of autoconf section ************************/
/* All undefined symbols are defined to zero here, to allow for older */
/* compilers which dont understand #if defined() or #if UNDEFINED_SYMBOL */
/*************************** operating systems *****************************/
#ifndef BSD
# define BSD 0 /* UNIX - Berkeley 4.x */
#endif
#ifndef UNIXV
# define UNIXV 0 /* UNIX - AT&T SYSV */
#endif
#ifndef UNIX7
# define UNIX7 0 /* UNIX - version 7 */
#endif
#ifndef MSDOS
# define MSDOS 0 /* PC */
#endif
#ifndef TOS
# define TOS 0 /* Atari ST */
#endif
#ifndef AMIGA
# define AMIGA 0 /* Commodore Amiga */
#endif
#ifndef OSK
# define OSK 0 /* OS-9 / 68k */
#endif
#ifndef COHERENT
# define COHERENT 0 /* Coherent */
#endif
#ifndef RAINBOW /* DEC Rainbow support, under MS-DOS */
# define RAINBOW 0
#endif
#ifndef VMS
# define VMS 0 /* VAX/VMS */
#endif
/* Minix has no predefines */
#if !BSD && !UNIXV && !UNIX7 && !MSDOS && !TOS && !AMIGA && !OSK && !COHERENT && !VMS
# define MINIX 1
#else
# define MINIX 0
#endif
/* generic combination of Unices */
#if UNIXV || UNIX7 || BSD || MINIX || COHERENT
# define ANY_UNIX 1
#else
# define ANY_UNIX 0
#endif
/*************************** compilers **************************************/
#ifndef AZTEC_C
# define AZTEC_C 0
#endif
#ifndef MICROSOFT
# define MICROSOFT 0
#endif
#ifndef TURBOC
# define TURBOC 0
#endif
/******************************* Credit ************************************/
#if MSDOS
# define CREDIT "Ported to MS-DOS by Guntram Blohm & Martin Patzel"
# if RAINBOW
# define CREDIT2 "Rainbow support added by Willett Kempton"
# endif
#endif
#if AMIGA
# define CREDIT "Ported to AmigaDOS 2.04 by Mike Rieser & Dale Rahn"
#endif
#if TOS
# define CREDIT "Ported to Atari/TOS by Guntram Blohm & Martin Patzel"
#endif
#if OSK
# define CREDIT "Ported to Microware OS9/68k by Peter Reinig"
#endif
#if COHERENT
# define CREDIT "Ported to Coherent by Esa Ahola"
#endif
#if VMS
# define CREDIT "Ported to VAX/VMS by John Campbell"
#endif
/*************************** functions depending on OS *********************/
/* There are two terminal-related functions that we need: ttyread() and
* ttywrite(). The ttyread() function implements read-with-timeout and is
* a true function on all systems. The ttywrite() function is almost always
* just a macro...
*/
#if !TOS && !AMIGA
# define ttywrite(buf, len) write(1, buf, (unsigned)(len)) /* raw write */
#endif
/* The strchr() function is an official standard now, so everybody has it
* except Unix version 7 (which is old) and BSD Unix (which is academic).
* Those guys use something called index() to do the same thing.
*/
#if BSD || UNIX7 || OSK
# define strchr index
#endif
extern char *strchr();
/* BSD uses bcopy() instead of memcpy() */
#if BSD
# define memcpy(dest, src, siz) bcopy(src, dest, siz)
#endif
/* BSD uses getwd() instead of getcwd(). The arguments are a little different,
* but we'll ignore that and hope for the best; adding arguments to the macro
* would mess up an "extern" declaration of the function.
*/
#if BSD || COHERENT
# define getcwd getwd
#endif
extern char *getcwd();
/* text versa binary mode for read/write */
#if !TOS
#define tread(fd,buf,n) read(fd,buf,(unsigned)(n))
#define twrite(fd,buf,n) write(fd,buf,(unsigned)(n))
#endif
/**************************** Compiler quirks *********************************/
/* the UNIX version 7 and (some) TOS compilers, don't allow "void" */
#if UNIX7 || TOS
# define void int
#endif
/* as far as I know, all compilers except version 7 support unsigned char */
/* NEWFLASH: the Minix-ST compiler has subtle problems with unsigned char */
#if UNIX7 || MINIX
# define UCHAR(c) ((c) & 0xff)
# define uchar char
#else
# define UCHAR(c) ((unsigned char)(c))
# define uchar unsigned char
#endif
/* Some compilers prefer to have malloc declared as returning a (void *) */
#if BSD || AMIGA
extern void *malloc();
#else
extern char *malloc();
#endif
/* everybody but Amiga wants lseek declared here */
/* LSC: MINIX Does not want it either! */
#if !AMIGA && !defined(__minix)
extern long lseek();
#endif
/******************* Names of files and environment vars **********************/
#if ANY_UNIX
# ifndef TMPDIR
# if MINIX
# define TMPDIR "/tmp"
# endif
# endif
# ifndef PRSVDIR
# define PRSVDIR "/usr/preserve" /* directory where preserved file live */
# endif
# ifndef PRSVINDEX
# define PRSVINDEX "/usr/preserve/Index" /* index of files in PRSVDIR */
# endif
# ifndef EXRC
# define EXRC ".exrc" /* init file in current directory */
# endif
# define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */
# ifndef SHELL
# define SHELL "/bin/sh" /* default shell */
# endif
# if COHERENT
# ifndef REDIRECT
# define REDIRECT ">" /* Coherent CC writes errors to stdout */
# endif
# endif
#endif
#if AMIGA /* Specify AMIGA environment */
# ifndef CC_COMMAND
# define CC_COMMAND "cc" /* generic C compiler */
# endif
# ifndef COLON
# define COLON ':' /* Amiga files can also end in `:' */
# endif
# ifndef SYSEXRC
# define SYSEXRC "S:" EXRC /* name of ".exrc" file in system dir */
# endif
# ifndef MAXRCLEN
# define MAXRCLEN 2048 /* max size of a .exrc file */
# endif
# ifndef NBUFS
# define NBUFS 10 /* must be at least 3 -- more is better */
# endif
# ifndef NEEDSYNC
# define NEEDSYNC TRUE /* assume ":se sync" by default */
# endif
# ifndef PRSVDIR
# define PRSVDIR "Elvis:" /* directory where preserved file live */
# endif
# ifndef PRSVINDEX
# define PRSVINDEX "Elvis:Index" /* index of files in PRSVDIR */
# endif
# ifndef REDIRECT
# define REDIRECT ">" /* Amiga writes errors to stdout */
# endif
# ifndef SCRATCHIN
# define SCRATCHIN "%sSIXXXXXX"
# endif
# ifndef SCRATCHOUT
# define SCRATCHOUT "%sSOXXXXXX"
# endif
# ifndef SHELL
# define SHELL "newshell" /* default shell */
# endif
# ifndef TERMTYPE
# define TERMTYPE "amiga" /* default termtype */
# endif
# ifndef TMPDIR /* for AMIGA should end in `:' or `/' */
# define TMPDIR "T:" /* directory where temp files live */
# endif
# ifndef TMPNAME
# define TMPNAME "%selv_%x.%x" /* format of names for temp files */
# endif
#endif
#if MSDOS || TOS
/* do not change TMPNAME and SCRATCH*: they MUST begin with '%s\\'! */
# ifndef TMPDIR
# define TMPDIR "C:\\tmp" /* directory where temp files live */
# endif
# ifndef PRSVDIR
# define PRSVDIR "C:\\preserve" /* directory where preserved file live */
# endif
# ifndef PRSVINDEX
# define PRSVINDEX "C:\\preserve\\Index" /* index of files in PRSVDIR */
# endif
# define TMPNAME "%s\\elv_%x.%x" /* temp file */
# if MSDOS
# if MICROSOFT
# define CC_COMMAND "cl -c" /* C compiler */
# else
# if __BORLANDC__ /* Borland C */
# define CC_COMMAND "bcc" /* C compiler */
# else
# if TURBOC /* Turbo C */
# define CC_COMMAND "tcc" /* C compiler */
# endif /* TURBOC */
# endif /* BORLANDC */
# endif /* MICROSOFT */
# endif /* MSDOS */
# define SCRATCHIN "%s\\siXXXXXX" /* DOS ONLY - output of filter program */
# define SCRATCHOUT "%s\\soXXXXXX" /* temp file used as input to filter */
# define SLASH '\\'
# ifndef SHELL
# if TOS
# define SHELL "shell.ttp" /* default shell */
# else
# define SHELL "command.com" /* default shell */
# endif
# endif
# define NEEDSYNC TRUE /* assume ":se sync" by default */
# if TOS && __GNUC__ /* probably on other systems, too */
# define REDIRECT "2>" /* GNUC reports on 2, others on 1 */
# define CC_COMMAND "gcc -c"
# else
# define REDIRECT ">" /* shell's redirection of stderr */
# endif
#endif
#if VMS
/* do not change TMPNAME, and SCRATCH*: they MUST begin with '%s\\'! */
# ifndef TMPDIR
# define TMPDIR "sys$scratch:" /* directory where temp files live */
# endif
# define TMPNAME "%selv_%x.%x;1" /* temp file */
# define SCRATCHIN "%ssiXXXXXX" /* DOS ONLY - output of filter program */
# define SCRATCHOUT "%ssoXXXXXX" /* temp file used as input to filter */
# define SLASH '\:' /* Worry point... jdc */
# ifndef SHELL
# define SHELL "" /* default shell */
# endif
# define REDIRECT ">" /* shell's redirection of stderr */
# define tread(fd,buf,n) vms_read(fd,buf,(unsigned)(n))
# define close vms_close
# define lseek vms_lseek
# define unlink vms_delete
# define delete __delete /* local routine conflicts w/VMS rtl routine. */
# define rpipe vms_rpipe
# define rpclose vms_rpclose
# define ttyread vms_ttyread
/* There is no sync() on vms */
# define sync()
/* jdc -- seems VMS external symbols are case insensitive */
# define m_fWord m_fw_ord
# define m_bWord m_bw_ord
# define m_eWord m_ew_ord
# define m_Nsrch m_n_srch
# define m_Fch m_f_ch
# define m_Tch m_t_ch
# define v_Xchar v_x_char
/* jdc -- also, braindead vms curses always found by linker. */
# define LINES elvis_LINES
# define COLS elvis_COLS
# define curscr elvis_curscr
# define stdscr elvis_stdscr
# define initscr elvis_initscr
# define endwin elvis_endwin
# define wrefresh elvis_wrefresh
#endif
#if OSK
# ifndef TMPDIR
# define TMPDIR "/dd/tmp" /* directory where temp files live */
# endif
# ifndef PRSVDIR
# define PRSVDIR "/dd/usr/preserve" /* directory where preserved file live */
# endif
# ifndef PRSVINDEX
# define PRSVINDEX "/dd/usr/preserve/Index" /* index of files in PRSVDIR */
# endif
# ifndef CC_COMMAND
# define CC_COMMAND "cc -r" /* name of the compiler */
# endif
# ifndef EXRC
# define EXRC ".exrc" /* init file in current directory */
# endif
# define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */
# ifndef SHELL
# define SHELL "shell" /* default shell */
# endif
# define FILEPERMS (S_IREAD|S_IWRITE) /* file permissions used for creat() */
# define REDIRECT ">>-" /* shell's redirection of stderr */
# define sync() /* OS9 doesn't need a sync() */
#endif
#ifndef TAGS
# define TAGS "tags" /* name of the tags file */
#endif
#ifndef TMPNAME
# define TMPNAME "%s/elv_%x.%x" /* format of names for temp files */
#endif
#ifndef EXINIT
# define EXINIT "EXINIT" /* name of EXINIT environment variable */
#endif
#ifndef EXRC
# define EXRC "elvis.rc" /* name of ".exrc" file in current dir */
#endif
#ifndef HMEXRC
# define HMEXRC EXRC /* name of ".exrc" file in home dir */
#endif
#ifndef KEYWORDPRG
# define KEYWORDPRG "ref"
#endif
#ifndef SCRATCHOUT
# define SCRATCHIN "%s/SIXXXXXX"
# define SCRATCHOUT "%s/SOXXXXXX"
#endif
#ifndef ERRLIST
# define ERRLIST "errlist"
#endif
#ifndef SLASH
# define SLASH '/'
#endif
#ifndef SHELL
# define SHELL "shell"
#endif
#ifndef REG
# define REG register
#endif
#ifndef NEEDSYNC
# define NEEDSYNC FALSE
#endif
#ifndef FILEPERMS
# define FILEPERMS 0666
#endif
#ifndef PRESERVE
# define PRESERVE "elvprsv" /* name of the "preserve" program */
#endif
#ifndef CC_COMMAND
# define CC_COMMAND "cc -c"
#endif
#ifndef MAKE_COMMAND
# define MAKE_COMMAND "make"
#endif
#ifndef REDIRECT
# define REDIRECT "2>"
#endif
#ifndef BLKSIZE
# ifdef CRUNCH
# define BLKSIZE 1024
# else
# define BLKSIZE 2048
# endif
#endif
#ifndef KEYBUFSIZE
# define KEYBUFSIZE 1000
#endif
#endif /* ndef _CONFIG_H */

View file

@ -1,819 +0,0 @@
/* ctags.c */
/* This is a reimplementation of the ctags(1) program. It supports ANSI C,
* and has heaps o' flags. It is meant to be distributed with elvis.
*/
#include <stdio.h>
#include "config.h"
#ifndef FALSE
# define FALSE 0
# define TRUE 1
#endif
#ifndef TAGS
# define TAGS "tags"
#endif
#ifndef REFS
# define REFS "refs"
#endif
#ifndef BLKSIZE
# define BLKSIZE 1024
#endif
#include "ctype.c" /* yes, that really is the .c file, not the .h one. */
/* -------------------------------------------------------------------------- */
/* Some global variables */
/* The following boolean variables are set according to command line flags */
int incl_static; /* -s include static tags */
int incl_types; /* -t include typedefs and structs */
int incl_vars; /* -v include variables */
int make_refs; /* -r generate a "refs" file */
int append_files; /* -a append to "tags" [and "refs"] files */
/* The following are used for outputting to the "tags" and "refs" files */
FILE *tags; /* used for writing to the "tags" file */
FILE *refs; /* used for writing to the "refs" file */
/* -------------------------------------------------------------------------- */
/* These are used for reading a source file. It keeps track of line numbers */
char *file_name; /* name of the current file */
FILE *file_fp; /* stream used for reading the file */
long file_lnum; /* line number in the current file */
long file_seek; /* fseek() offset to the start of current line */
int file_afternl; /* boolean: was previous character a newline? */
int file_prevch; /* a single character that was ungotten */
int file_header; /* boolean: is the current file a header file? */
/* This function opens a file, and resets the line counter. If it fails, it
* it will display an error message and leave the file_fp set to NULL.
*/
void file_open(name)
char *name; /* name of file to be opened */
{
/* if another file was already open, then close it */
if (file_fp)
{
fclose(file_fp);
}
/* try to open the file for reading. The file must be opened in
* "binary" mode because otherwise fseek() would misbehave under DOS.
*/
#if MSDOS || TOS
file_fp = fopen(name, "rb");
#else
file_fp = fopen(name, "r");
#endif
if (!file_fp)
{
perror(name);
}
/* reset the name & line number */
file_name = name;
file_lnum = 0L;
file_seek = 0L;
file_afternl = TRUE;
/* determine whether this is a header file */
file_header = FALSE;
name += strlen(name) - 2;
if (name >= file_name && name[0] == '.' && (name[1] == 'h' || name[1] == 'H'))
{
file_header = TRUE;
}
}
/* This function reads a single character from the stream. If the *previous*
* character was a newline, then it also increments file_lnum and sets
* file_offset.
*/
int file_getc()
{
int ch;
/* if there is an ungotten character, then return it. Don't do any
* other processing on it, though, because we already did that the
* first time it was read.
*/
if (file_prevch)
{
ch = file_prevch;
file_prevch = 0;
return ch;
}
/* if previous character was a newline, then we're starting a line */
if (file_afternl)
{
file_afternl = FALSE;
file_seek = ftell(file_fp);
file_lnum++;
}
/* Get a character. If no file is open, then return EOF */
ch = (file_fp ? getc(file_fp) : EOF);
/* if it is a newline, then remember that fact */
if (ch == '\n')
{
file_afternl = TRUE;
}
/* return the character */
return ch;
}
/* This function ungets a character from the current source file */
void file_ungetc(ch)
int ch; /* character to be ungotten */
{
file_prevch = ch;
}
/* This function copies the current line out some other fp. It has no effect
* on the file_getc() function. During copying, any '\' characters are doubled
* and a leading '^' or trailing '$' is also quoted. The newline character is
* not copied.
*
* This is meant to be used when generating a tag line.
*/
void file_copyline(seek, fp)
long seek; /* where the lines starts in the source file */
FILE *fp; /* the output stream to copy it to */
{
long oldseek;/* where the file's pointer was before we messed it up */
char ch; /* a single character from the file */
char next; /* the next character from this file */
/* go to the start of the line */
oldseek = ftell(file_fp);
fseek(file_fp, seek, 0);
/* if first character is '^', then emit \^ */
ch = getc(file_fp);
if (ch == '^')
{
putc('\\', fp);
putc('^', fp);
ch = getc(file_fp);
}
/* write everything up to, but not including, the newline */
while (ch != '\n')
{
/* preread the next character from this file */
next = getc(file_fp);
/* if character is '\', or a terminal '$', then quote it */
if (ch == '\\' || (ch == '$' && next == '\n'))
{
putc('\\', fp);
}
putc(ch, fp);
/* next character... */
ch = next;
}
/* seek back to the old position */
fseek(file_fp, oldseek, 0);
}
/* -------------------------------------------------------------------------- */
/* This section handles preprocessor directives. It strips out all of the
* directives, and may emit a tag for #define directives.
*/
int cpp_afternl; /* boolean: look for '#' character? */
int cpp_prevch; /* an ungotten character, if any */
int cpp_refsok; /* boolean: can we echo characters out to "refs"? */
/* This function opens the file & resets variables */
void cpp_open(name)
char *name; /* name of source file to be opened */
{
/* use the lower-level file_open function to open the file */
file_open(name);
/* reset variables */
cpp_afternl = TRUE;
cpp_refsok = TRUE;
}
/* This function copies a character from the source file to the "refs" file */
void cpp_echo(ch)
int ch; /* the character to copy */
{
static wasnl;
/* echo non-EOF chars, unless not making "ref", or echo turned off */
if (ch != EOF && make_refs && cpp_refsok && !file_header)
{
/* try to avoid blank lines */
if (ch == '\n')
{
if (wasnl)
{
return;
}
wasnl = TRUE;
}
else
{
wasnl = FALSE;
}
/* add the character */
putc(ch, refs);
}
}
/* This function returns the next character which isn't part of a directive */
int cpp_getc()
{
static
int ch; /* the next input character */
char *scan;
/* if we have an ungotten character, then return it */
if (cpp_prevch)
{
ch = cpp_prevch;
cpp_prevch = 0;
return ch;
}
/* Get a character from the file. Return it if not special '#' */
ch = file_getc();
if (ch == '\n')
{
cpp_afternl = TRUE;
cpp_echo(ch);
return ch;
}
else if (ch != '#' || !cpp_afternl)
{
/* normal character. Any non-whitespace should turn off afternl */
if (ch != ' ' && ch != '\t')
{
cpp_afternl = FALSE;
}
cpp_echo(ch);
return ch;
}
/* Yikes! We found a directive */
/* see whether this is a #define line */
scan = " define ";
while (*scan)
{
if (*scan == ' ')
{
/* space character matches any whitespace */
do
{
ch = file_getc();
} while (ch == ' ' || ch == '\t');
file_ungetc(ch);
}
else
{
/* other characters should match exactly */
ch = file_getc();
if (ch != *scan)
{
file_ungetc(ch);
break;
}
}
scan++;
}
/* is this a #define line? and should we generate a tag for it? */
if (!*scan && (file_header || incl_static))
{
/* if not a header, then this will be a static tag */
if (!file_header)
{
fputs(file_name, tags);
putc(':', tags);
}
/* output the tag name */
for (ch = file_getc(); isalnum(ch) || ch == '_'; ch = file_getc())
{
putc(ch, tags);
}
/* output a tab, the filename, another tab, and the line number */
fprintf(tags, "\t%s\t%ld\n", file_name, file_lnum);
}
/* skip to the end of the directive -- a newline that isn't preceded
* by a '\' character.
*/
while (ch != EOF && ch != '\n')
{
if (ch == '\\')
{
ch = file_getc();
}
ch = file_getc();
}
/* return the newline that we found at the end of the directive */
cpp_echo(ch);
return ch;
}
/* This puts a character back into the input queue for the source file */
cpp_ungetc(ch)
int ch; /* a character to be ungotten */
{
cpp_prevch = ch;
}
/* -------------------------------------------------------------------------- */
/* This is the lexical analyser. It gets characters from the preprocessor,
* and gives tokens to the parser. Some special codes are...
* (deleted) / *...* / (comments)
* (deleted) //...\n (comments)
* (deleted) (* (parens used in complex declaration)
* (deleted) [...] (array subscript, when ... contains no ])
* (deleted) struct (intro to structure declaration)
* BODY {...} ('{' can occur anywhere, '}' only at BOW if ... has '{')
* ARGS (...{ (args of function, not extern or forward)
* ARGS (...); (args of an extern/forward function declaration)
* COMMA , (separate declarations that have same scope)
* SEMICOLON ; (separate declarations that have different scope)
* SEMICOLON =...; (initializer)
* TYPEDEF typedef (the "typedef" keyword)
* STATIC static (the "static" keyword)
* STATIC private (the "static" keyword)
* STATIC PRIVATE (the "static" keyword)
* NAME [a-z]+ (really any valid name that isn't reserved word)
*/
/* #define EOF -1 */
#define DELETED 0
#define BODY 1
#define ARGS 2
#define COMMA 3
#define SEMICOLON 4
#define TYPEDEF 5
#define STATIC 6
#define EXTERN 7
#define NAME 8
char lex_name[BLKSIZE]; /* the name of a "NAME" token */
long lex_seek; /* start of line that contains lex_name */
lex_gettoken()
{
int ch; /* a character from the preprocessor */
int next; /* the next character */
int token; /* the token that we'll return */
int i;
/* loop until we get a token that isn't "DELETED" */
do
{
/* get the next character */
ch = cpp_getc();
/* process the character */
switch (ch)
{
case ',':
token = COMMA;
break;
case ';':
token = SEMICOLON;
break;
case '/':
/* get the next character */
ch = cpp_getc();
switch (ch)
{
case '*': /* start of C comment */
ch = cpp_getc();
next = cpp_getc();
while (next != EOF && (ch != '*' || next != '/'))
{
ch = next;
next = cpp_getc();
}
break;
case '/': /* start of a C++ comment */
do
{
ch = cpp_getc();
} while (ch != '\n' && ch != EOF);
break;
default: /* some other slash */
cpp_ungetc(ch);
}
token = DELETED;
break;
case '(':
ch = cpp_getc();
if (ch == '*')
{
token = DELETED;
}
else
{
next = cpp_getc();
while (ch != '{' && ch != EOF && (ch != ')' || next != ';'))/*}*/
{
ch = next;
next = cpp_getc();
}
if (ch == '{')/*}*/
{
cpp_ungetc(ch);
}
else if (next == ';')
{
cpp_ungetc(next);
}
token = ARGS;
}
break;
case '{':/*}*/
/* don't send the next characters to "refs" */
cpp_refsok = FALSE;
/* skip ahead to closing '}', or to embedded '{' */
do
{
ch = cpp_getc();
} while (ch != '{' && ch != '}' && ch != EOF);
/* if has embedded '{', then skip to '}' in column 1 */
if (ch == '{') /*}*/
{
ch = cpp_getc();
next = cpp_getc();
while (ch != EOF && (ch != '\n' || next != '}'))/*{*/
{
ch = next;
next = cpp_getc();
}
}
/* resume "refs" processing */
cpp_refsok = TRUE;
cpp_echo('}');
token = BODY;
break;
case '[':
/* skip to matching ']' */
do
{
ch = cpp_getc();
} while (ch != ']' && ch != EOF);
token = DELETED;
break;
case '=':
/* skip to next ';' */
do
{
ch = cpp_getc();
/* leave array initializers out of "refs" */
if (ch == '{')
{
cpp_refsok = FALSE;
}
} while (ch != ';' && ch != EOF);
/* resume echoing to "refs" */
if (!cpp_refsok)
{
cpp_refsok = TRUE;
cpp_echo('}');
cpp_echo(';');
}
token = SEMICOLON;
break;
case EOF:
token = EOF;
break;
default:
/* is this the start of a name/keyword? */
if (isalpha(ch) || ch == '_')
{
/* collect the whole word */
lex_name[0] = ch;
for (i = 1, ch = cpp_getc();
i < BLKSIZE - 1 && (isalnum(ch) || ch == '_');
i++, ch = cpp_getc())
{
lex_name[i] = ch;
}
lex_name[i] = '\0';
cpp_ungetc(ch);
/* is it a reserved word? */
if (!strcmp(lex_name, "typedef"))
{
token = TYPEDEF;
lex_seek = -1L;
}
else if (!strcmp(lex_name, "static")
|| !strcmp(lex_name, "private")
|| !strcmp(lex_name, "PRIVATE"))
{
token = STATIC;
lex_seek = -1L;
}
else if (!strcmp(lex_name, "extern")
|| !strcmp(lex_name, "EXTERN")
|| !strcmp(lex_name, "FORWARD"))
{
token = EXTERN;
lex_seek = -1L;
}
else
{
token = NAME;
lex_seek = file_seek;
}
}
else /* not part of a name/keyword */
{
token = DELETED;
}
} /* end switch(ch) */
} while (token == DELETED);
return token;
}
/* -------------------------------------------------------------------------- */
/* This is the parser. It locates tag candidates, and then decides whether to
* generate a tag for them.
*/
/* This function generates a tag for the object in lex_name, whose tag line is
* located at a given seek offset.
*/
void maketag(scope, seek)
int scope; /* 0 if global, or STATIC if static */
long seek; /* the seek offset of the line */
{
/* output the tagname and filename fields */
if (scope == EXTERN)
{
/* whoa! we should *never* output a tag for "extern" decl */
return;
}
else if (scope == STATIC)
{
fprintf(tags, "%s:%s\t%s\t", file_name, lex_name, file_name);
}
else
{
fprintf(tags, "%s\t%s\t", lex_name, file_name);
}
/* output the target line */
putc('/', tags);
putc('^', tags);
file_copyline(seek, tags);
putc('$', tags);
putc('/', tags);
putc('\n', tags);
}
/* This function parses a source file, adding any tags that it finds */
void ctags(name)
char *name; /* the name of a source file to be checked */
{
int prev; /* the previous token from the source file */
int token; /* the current token from the source file */
int scope; /* normally 0, but could be a TYPEDEF or STATIC token */
int gotname;/* boolean: does lex_name contain a tag candidate? */
long tagseek;/* start of line that contains lex_name */
/* open the file */
cpp_open(name);
/* reset */
scope = 0;
gotname = FALSE;
token = SEMICOLON;
/* parse until the end of the file */
while (prev = token, (token = lex_gettoken()) != EOF)
{
/* scope keyword? */
if (token == TYPEDEF || token == STATIC || token == EXTERN)
{
scope = token;
gotname = FALSE;
continue;
}
/* name of a possible tag candidate? */
if (token == NAME)
{
tagseek = file_seek;
gotname = TRUE;
continue;
}
/* if NAME BODY, without ARGS, then NAME is a struct tag */
if (gotname && token == BODY && prev != ARGS)
{
gotname = FALSE;
/* ignore if in typedef -- better name is coming soon */
if (scope == TYPEDEF)
{
continue;
}
/* generate a tag, if -t and maybe -s */
if (incl_types && (file_header || incl_static))
{
maketag(file_header ? 0 : STATIC, tagseek);
}
}
/* If NAME ARGS BODY, then NAME is a function */
if (gotname && prev == ARGS && token == BODY)
{
gotname = FALSE;
/* generate a tag, maybe checking -s */
if (scope != STATIC || incl_static)
{
maketag(scope, tagseek);
}
}
/* If NAME SEMICOLON or NAME COMMA, then NAME is var/typedef */
if (gotname && (token == SEMICOLON || token == COMMA))
{
gotname = FALSE;
/* generate a tag, if -v/-t and maybe -s */
if (scope == TYPEDEF && incl_types && (file_header || incl_static)
|| scope == STATIC && incl_vars && incl_static
|| incl_vars)
{
/* a TYPEDEF outside of a header is STATIC */
if (scope == TYPEDEF && !file_header)
{
maketag(STATIC, tagseek);
}
else /* use whatever scope was declared */
{
maketag(scope, tagseek);
}
}
}
/* reset after a semicolon or ARGS BODY pair */
if (token == SEMICOLON || (prev == ARGS && token == BODY))
{
scope = 0;
gotname = FALSE;
}
}
/* The source file will be automatically closed */
}
/* -------------------------------------------------------------------------- */
void usage()
{
fprintf(stderr, "usage: ctags [flags] filenames...\n");
fprintf(stderr, "\t-s include static functions\n");
fprintf(stderr, "\t-t include typedefs\n");
fprintf(stderr, "\t-v include variable declarations\n");
fprintf(stderr, "\t-r generate a \"refs\" file, too\n");
fprintf(stderr, "\t-a append to \"tags\", instead of overwriting\n");
exit(2);
}
#if AMIGA
# include "amiwild.c"
#endif
#if VMS
# include "vmswild.c"
#endif
main(argc, argv)
int argc;
char **argv;
{
int i, j;
#if MSDOS || TOS
char **wildexpand();
argv = wildexpand(&argc, argv);
#endif
/* build the tables used by the ctype macros */
_ct_init("");
/* parse the option flags */
for (i = 1; i < argc && argv[i][0] == '-'; i++)
{
for (j = 1; argv[i][j]; j++)
{
switch (argv[i][j])
{
case 's': incl_static = TRUE; break;
case 't': incl_types = TRUE; break;
case 'v': incl_vars = TRUE; break;
case 'r': make_refs = TRUE; break;
case 'a': append_files = TRUE; break;
default: usage();
}
}
}
/* There should always be at least one source file named in args */
if (i == argc)
{
usage();
}
/* open the "tags" and maybe "refs" files */
tags = fopen(TAGS, append_files ? "a" : "w");
if (!tags)
{
perror(TAGS);
exit(3);
}
if (make_refs)
{
refs = fopen(REFS, append_files ? "a" : "w");
if (!refs)
{
perror(REFS);
exit(4);
}
}
/* parse each source file */
for (; i < argc; i++)
{
ctags(argv[i]);
}
/* close "tags" and maybe "refs" */
fclose(tags);
if (make_refs)
{
fclose(refs);
}
#ifdef SORT
/* This is a hack which will sort the tags list. It should
* on UNIX and OS-9. You may have trouble with csh. Note
* that the tags list only has to be sorted if you intend to
* use it with the real vi; elvis permits unsorted tags.
*/
# if OSK
system("qsort tags >-_tags; -nx; del tags; rename _tags tags");
# else
system("sort tags >_tags$$; mv _tags$$ tags");
# endif
#endif
exit(0);
/*NOTREACHED*/
}
#if MSDOS || TOS
# define WILDCARD_NO_MAIN
# include "wildcard.c"
#endif

View file

@ -1,74 +0,0 @@
/* ctype.c */
/* This file contains the tables and initialization function for elvis'
* version of <ctype.h>. It should be portable.
*/
#include "config.h"
#include "ctype.h"
uchar _ct_toupper[256];
uchar _ct_tolower[256];
uchar _ct_ctypes[256];
/* This function initializes the tables used by the ctype macros. It should
* be called at the start of the program. It can be called again anytime you
* wish to change the non-standard "flipcase" list. The "flipcase" list is
* a string of characters which are taken to be lowercase/uppercase pairs.
* If you don't want to use any special flipcase characters, then pass an
* empty string.
*/
void _ct_init(flipcase)
uchar *flipcase; /* list of non-standard lower/upper letter pairs */
{
int i;
uchar *scan;
/* reset all of the tables */
for (i = 0; i < 256; i++)
{
_ct_toupper[i] = _ct_tolower[i] = i;
_ct_ctypes[i] = 0;
}
/* add the digits */
for (scan = (uchar *)"0123456789"; *scan; scan++)
{
_ct_ctypes[*scan] |= _CT_DIGIT | _CT_ALNUM;
}
/* add the whitespace */
for (scan = (uchar *)" \t\n\r\f"; *scan; scan++)
{
_ct_ctypes[*scan] |= _CT_SPACE;
}
/* add the standard ASCII letters */
for (scan = (uchar *)"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"; *scan; scan += 2)
{
_ct_ctypes[scan[0]] |= _CT_LOWER | _CT_ALNUM;
_ct_ctypes[scan[1]] |= _CT_UPPER | _CT_ALNUM;
_ct_toupper[scan[0]] = scan[1];
_ct_tolower[scan[1]] = scan[0];
}
/* add the flipcase letters */
for (scan = flipcase; scan[0] && scan[1]; scan += 2)
{
_ct_ctypes[scan[0]] |= _CT_LOWER | _CT_ALNUM;
_ct_ctypes[scan[1]] |= _CT_UPPER | _CT_ALNUM;
_ct_toupper[scan[0]] = scan[1];
_ct_tolower[scan[1]] = scan[0];
}
/* include '_' in the isalnum() list */
_ct_ctypes[UCHAR('_')] |= _CT_ALNUM;
/* !!! find the control characters in an ASCII-dependent way */
for (i = 0; i < ' '; i++)
{
_ct_ctypes[i] |= _CT_CNTRL;
}
_ct_ctypes[127] |= _CT_CNTRL;
_ct_ctypes[255] |= _CT_CNTRL;
}

View file

@ -1,40 +0,0 @@
/* ctype.h */
/* This file contains macros definitions and extern declarations for a
* version of <ctype.h> which is aware of the o_flipcase letters used in
* elvis.
*
* This file uses the "uchar" data type and "UCHAR" conversion macro which
* are defined in "config.h". Consequently, any file that includes this
* header must include config.h first.
*/
#ifndef _CT_UPPER
#define _CT_UPPER 0x01
#define _CT_LOWER 0x02
#define _CT_SPACE 0x04
#define _CT_DIGIT 0x08
#define _CT_ALNUM 0x10
#define _CT_CNTRL 0x20
#define isalnum(c) (_ct_ctypes[UCHAR(c)] & _CT_ALNUM)
#define isalpha(c) (_ct_ctypes[UCHAR(c)] & (_CT_LOWER|_CT_UPPER))
#define isdigit(c) (_ct_ctypes[UCHAR(c)] & _CT_DIGIT)
#define islower(c) (_ct_ctypes[UCHAR(c)] & _CT_LOWER)
#define isspace(c) (_ct_ctypes[UCHAR(c)] & _CT_SPACE)
#define isupper(c) (_ct_ctypes[UCHAR(c)] & _CT_UPPER)
#define iscntrl(c) (_ct_ctypes[UCHAR(c)] & _CT_CNTRL)
#define ispunct(c) (!_ct_ctypes[UCHAR(c)]) /* punct = "none of the above" */
#define isascii(c) (!((c) & 0x80))
#define toupper(c) _ct_toupper[UCHAR(c)]
#define tolower(c) _ct_tolower[UCHAR(c)]
extern uchar _ct_toupper[];
extern uchar _ct_tolower[];
extern uchar _ct_ctypes[];
extern void _ct_init(/* char *flipcase */);
#endif /* ndef _CT_UPPER */

View file

@ -1,925 +0,0 @@
/* curses.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the functions & variables needed for a tiny subset of
* curses. The principle advantage of this version of curses is its
* extreme speed. Disadvantages are potentially larger code, few supported
* functions, limited compatibility with full curses, and only stdscr.
*/
#include "config.h"
#include "vi.h"
#if ANY_UNIX
/* The termios/termio/sgtty #ifdefs were a mess, so I removed all but termios.
* (KJB)
*/
# include <termios.h>
# if MINIX
# include <sys/ioctl.h>
# endif
#endif
#if TOS
# include <osbind.h>
#endif
#if OSK
# include <sgstat.h>
#endif
#if VMS
extern int VMS_read_raw; /* Set in initscr() */
#endif
extern char *getenv();
static void starttcap();
/* variables, publicly available & used in the macros */
char *termtype; /* name of terminal entry */
short ospeed; /* speed of the tty, eg B2400 */
#if OSK
char PC_; /* Pad char */
char *BC; /* backspace character string */
#else
char PC; /* Pad char */
#endif
WINDOW *stdscr; /* pointer into kbuf[] */
WINDOW kbuf[KBSIZ]; /* a very large output buffer */
int LINES; /* :li#: number of rows */
int COLS; /* :co#: number of columns */
int AM; /* :am: boolean: auto margins? */
int PT; /* :pt: boolean: physical tabs? */
char *VB; /* :vb=: visible bell */
char *UP; /* :up=: move cursor up */
char *SO = ""; /* :so=: standout start */
char *SE = ""; /* :se=: standout end */
char *US = ""; /* :us=: underline start */
char *UE = ""; /* :ue=: underline end */
char *MD = ""; /* :md=: bold start */
char *ME = ""; /* :me=: bold end */
char *AS = ""; /* :as=: alternate (italic) start */
char *AE = ""; /* :ae=: alternate (italic) end */
#ifndef NO_VISIBLE
char *MV; /* :mv=: "visible" selection start */
#endif
char *CM; /* :cm=: cursor movement */
char *CE; /* :ce=: clear to end of line */
char *CD; /* :cd=: clear to end of screen */
char *AL; /* :al=: add a line */
char *DL; /* :dl=: delete a line */
#if OSK
char *SR_; /* :sr=: scroll reverse */
#else
char *SR; /* :sr=: scroll reverse */
#endif
char *KS = ""; /* :ks=: init string for cursor */
char *KE = ""; /* :ke=: restore string for cursor */
char *KU; /* :ku=: key sequence sent by up arrow */
char *KD; /* :kd=: key sequence sent by down arrow */
char *KL; /* :kl=: key sequence sent by left arrow */
char *KR; /* :kr=: key sequence sent by right arrow */
char *HM; /* :HM=: key sequence sent by the <Home> key */
char *EN; /* :EN=: key sequence sent by the <End> key */
char *PU; /* :PU=: key sequence sent by the <PgUp> key */
char *PD; /* :PD=: key sequence sent by the <PgDn> key */
char *KI; /* :kI=: key sequence sent by the <Insert> key */
#ifndef NO_FKEY
char *FKEY[NFKEYS]; /* :k0=: ... :k9=: sequences sent by function keys */
#endif
char *IM = ""; /* :im=: insert mode start */
char *IC = ""; /* :ic=: insert the following character */
char *EI = ""; /* :ei=: insert mode end */
char *DC; /* :dc=: delete a character */
char *TI = ""; /* :ti=: terminal init */ /* GB */
char *TE = ""; /* :te=: terminal exit */ /* GB */
#ifndef NO_CURSORSHAPE
#if 1
char *CQ = (char *)0;/* :cQ=: normal cursor */
char *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
char *CV = (char *)2;/* :cV=: cursor used for VI command mode */
char *CI = (char *)3;/* :cI=: cursor used for VI input mode */
char *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
#else
char *CQ = ""; /* :cQ=: normal cursor */
char *CX = ""; /* :cX=: cursor used for EX command/entry */
char *CV = ""; /* :cV=: cursor used for VI command mode */
char *CI = ""; /* :cI=: cursor used for VI input mode */
char *CR = ""; /* :cR=: cursor used for VI replace mode */
#endif
#endif
char *aend = ""; /* end an attribute -- either UE or ME */
char ERASEKEY; /* backspace key taken from ioctl structure */
#ifndef NO_COLOR
char normalcolor[16];
char SOcolor[16];
char SEcolor[16];
char UScolor[16];
char UEcolor[16];
char MDcolor[16];
char MEcolor[16];
char AScolor[16];
char AEcolor[16];
# ifndef NO_POPUP
char POPUPcolor[16];
# endif
# ifndef NO_VISIBLE
char VISIBLEcolor[16];
# endif
#endif
#if ANY_UNIX
static struct termios oldtermio; /* original tty mode */
static struct termios newtermio; /* cbreak/noecho tty mode */
#endif
#if OSK
static struct sgbuf oldsgttyb; /* orginal tty mode */
static struct sgbuf newsgttyb; /* noecho tty mode */
#endif
static char *capbuf; /* capability string buffer */
/* Initialize the Curses package. */
void initscr()
{
/* make sure TERM variable is set */
termtype = getenv("TERM");
#if VMS
/* VMS getenv() handles TERM as a environment setting. Foreign
* terminal support can be implemented by setting the ELVIS_TERM
* logical or symbol to match a tinytcap entry.
*/
if (!strcmp(termtype,"unknown"))
termtype = getenv("ELVIS_TERM");
#endif
#if MSDOS
/* For MS-DOS, if TERM is unset we can default to "pcbios", or
* maybe "rainbow".
*/
if (!termtype)
{
#ifdef RAINBOW
if (*(unsigned char far*)(0xffff000eL) == 6 /* Rainbow 100a */
|| *(unsigned char far*)(0xffff000eL) == 148)/* Rainbow 100b */
{
termtype = "rainbow";
}
else
#endif
termtype = "pcbios";
}
if (!strcmp(termtype, "pcbios"))
#else
if (!termtype)
#endif
{
#if ANY_UNIX
write(2, "Environment variable TERM must be set\n", (unsigned)38);
exit(1);
#endif
#if OSK
writeln(2, "Environment variable TERM must be set\n", (unsigned)38);
exit(1);
#endif
#if AMIGA
termtype = TERMTYPE;
starttcap(termtype);
#endif
#if MSDOS
starttcap("pcbios");
#endif
#if TOS
termtype = "vt52";
starttcap(termtype);
#endif
#if VMS
write(2, "UNKNOWN terminal: define ELVIS_TERM\n", (unsigned)36);
exit(1);
#endif
}
else
{
#if MSDOS
*o_pcbios = 0;
#endif
/* start termcap stuff */
starttcap(termtype);
}
/* create stdscr and curscr */
stdscr = kbuf;
/* change the terminal mode to cbreak/noecho */
#if ANY_UNIX
tcgetattr(2, &oldtermio);
#endif
#if OSK
_gs_opt(0, &oldsgttyb);
#endif
#if VMS
VMS_read_raw = 1; /* cbreak/noecho */
vms_open_tty();
#endif
resume_curses(TRUE);
}
/* Shut down the Curses package. */
void endwin()
{
/* change the terminal mode back the way it was */
suspend_curses();
#if AMIGA
amiclosewin();
#endif
}
static int curses_active = FALSE;
/* Send any required termination strings. Turn off "raw" mode. */
void suspend_curses()
{
#ifndef NO_CURSORSHAPE
if (has_CQ)
{
do_CQ();
}
#endif
if (has_TE) /* GB */
{
do_TE();
}
if (has_KE)
{
do_KE();
}
#ifndef NO_COLOR
quitcolor();
#endif
refresh();
/* change the terminal mode back the way it was */
#if ANY_UNIX
tcsetattr(2, TCSADRAIN, &oldtermio);
#endif
#if OSK
_ss_opt(0, &oldsgttyb);
#endif
#if AMIGA
ttyshutdown();
#endif
#if MSDOS
raw_set_stdio(FALSE);
#endif
#if VMS
VMS_read_raw = 0;
#endif
curses_active = FALSE;
}
/* put the terminal in RAW mode. If "quietly" is FALSE, then ask the user
* to hit a key, and wait for keystroke before returning.
*/
void resume_curses(quietly)
int quietly;
{
if (!curses_active)
{
/* change the terminal mode to cbreak/noecho */
#if ANY_UNIX
ospeed = cfgetospeed(&oldtermio);
ERASEKEY = oldtermio.c_cc[VERASE];
newtermio = oldtermio;
newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
newtermio.c_oflag &= ~OPOST;
newtermio.c_lflag &= ISIG;
newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
newtermio.c_cc[VMIN] = 1;
newtermio.c_cc[VTIME] = 0;
newtermio.c_cc[VSUSP] = 0;
tcsetattr(2, TCSADRAIN, &newtermio);
#endif
#if OSK
newsgttyb = oldsgttyb;
newsgttyb.sg_echo = 0;
newsgttyb.sg_eofch = 0;
newsgttyb.sg_kbach = 0;
newsgttyb.sg_kbich = ctrl('C');
_ss_opt(0, &newsgttyb);
ospeed = oldsgttyb.sg_baud;
ERASEKEY = oldsgttyb.sg_bspch;
#endif
#if AMIGA
/* turn on window resize and RAW */
ttysetup();
#endif
#if MSDOS
raw_set_stdio(TRUE);
#endif
#if VMS
VMS_read_raw = 1;
{ int c;
read(0,&c,0); /* Flush the tty buffer. */
}
ERASEKEY = '\177'; /* Accept <DEL> as <^H> for VMS */
#endif
if (has_TI) /* GB */
{
do_TI();
}
if (has_KS)
{
do_KS();
}
curses_active = TRUE;
}
/* If we're supposed to quit quietly, then we're done */
if (quietly)
{
return;
}
signal(SIGINT, SIG_IGN);
move(LINES - 1, 0);
do_SO();
#if VMS
qaddstr("\n[Press <RETURN> to continue]");
#else
qaddstr("[Press <RETURN> to continue]");
#endif
do_SE();
refresh();
ttyread(kbuf, 20, 0); /* in RAW mode, so <20 is very likely */
if (kbuf[0] == ':')
{
mode = MODE_COLON;
addch('\n');
refresh();
}
else
{
mode = MODE_VI;
redraw(MARK_UNSET, FALSE);
}
exwrote = FALSE;
signal(SIGINT, (void(*)()) trapint);
}
/* This function fetches an optional string from termcap */
static void mayhave(T, s)
char **T; /* where to store the returned pointer */
char *s; /* name of the capability */
{
char *val;
val = tgetstr(s, &capbuf);
if (val)
{
*T = val;
}
}
/* This function fetches a required string from termcap */
static void musthave(T, s)
char **T; /* where to store the returned pointer */
char *s; /* name of the capability */
{
mayhave(T, s);
if (!*T)
{
write(2, "This termcap entry lacks the :", (unsigned)30);
write(2, s, (unsigned)2);
write(2, "=: capability\n", (unsigned)14);
#if OSK
write(2, "\l", 1);
#endif
exit(1);
}
}
/* This function fetches a pair of strings from termcap. If one of them is
* missing, then the other one is ignored.
*/
static void pair(T, U, sT, sU)
char **T; /* where to store the first pointer */
char **U; /* where to store the second pointer */
char *sT; /* name of the first capability */
char *sU; /* name of the second capability */
{
mayhave(T, sT);
mayhave(U, sU);
if (!**T || !**U)
{
*T = *U = "";
}
}
void getsize(int signo);
/* Read everything from termcap */
static void starttcap(term)
char *term;
{
static char cbmem[800];
/* allocate memory for capbuf */
capbuf = cbmem;
/* get the termcap entry */
switch (tgetent(kbuf, term))
{
case -1:
write(2, "Can't read /etc/termcap\n", (unsigned)24);
#if OSK
write(2, "\l", 1);
#endif
exit(2);
case 0:
write(2, "Unrecognized TERM type\n", (unsigned)23);
#if OSK
write(2, "\l", 1);
#endif
exit(3);
}
/* get strings */
musthave(&UP, "up");
mayhave(&VB, "vb");
musthave(&CM, "cm");
pair(&SO, &SE, "so", "se");
mayhave(&TI, "ti");
mayhave(&TE, "te");
if (tgetnum("ug") <= 0)
{
pair(&US, &UE, "us", "ue");
pair(&MD, &ME, "md", "me");
/* get italics, or have it default to underline */
pair(&AS, &AE, "as", "ae");
if (!*AS)
{
AS = US;
AE = UE;
}
}
#ifndef NO_VISIBLE
MV = SO; /* by default */
mayhave(&MV, "mv");
#endif
mayhave(&AL, "al");
mayhave(&DL, "dl");
musthave(&CE, "ce");
mayhave(&CD, "cd");
#if OSK
mayhave(&SR_, "sr");
#else
mayhave(&SR, "sr");
#endif
pair(&IM, &EI, "im", "ei");
mayhave(&IC, "ic");
mayhave(&DC, "dc");
/* other termcap stuff */
AM = (tgetflag("am") && !tgetflag("xn"));
PT = tgetflag("pt");
#if AMIGA
amiopenwin(termtype); /* Must run this before ttysetup(); */
ttysetup(); /* Must run this before getsize(0); */
#endif
getsize(0);
/* Key sequences */
pair(&KS, &KE, "ks", "ke");
mayhave(&KU, "ku"); /* up */
mayhave(&KD, "kd"); /* down */
mayhave(&KL, "kl"); /* left */
mayhave(&KR, "kr"); /* right */
mayhave(&PU, "kP"); /* PgUp */
mayhave(&PD, "kN"); /* PgDn */
mayhave(&HM, "kh"); /* Home */
mayhave(&EN, "kH"); /* End */
mayhave(&KI, "kI"); /* Insert */
#ifndef CRUNCH
if (!PU) mayhave(&PU, "K2"); /* "3x3 pad" names for PgUp, etc. */
if (!PD) mayhave(&PD, "K5");
if (!HM) mayhave(&HM, "K1");
if (!EN) mayhave(&EN, "K4");
mayhave(&PU, "PU"); /* old XENIX names for PgUp, etc. */
mayhave(&PD, "PD"); /* (overrides others, if used.) */
mayhave(&HM, "HM");
mayhave(&EN, "EN");
#endif
#ifndef NO_FKEY
mayhave(&FKEY[0], "k0"); /* function key codes */
mayhave(&FKEY[1], "k1");
mayhave(&FKEY[2], "k2");
mayhave(&FKEY[3], "k3");
mayhave(&FKEY[4], "k4");
mayhave(&FKEY[5], "k5");
mayhave(&FKEY[6], "k6");
mayhave(&FKEY[7], "k7");
mayhave(&FKEY[8], "k8");
mayhave(&FKEY[9], "k9");
# ifndef NO_SHIFT_FKEY
mayhave(&FKEY[10], "s0"); /* shift function key codes */
mayhave(&FKEY[11], "s1");
mayhave(&FKEY[12], "s2");
mayhave(&FKEY[13], "s3");
mayhave(&FKEY[14], "s4");
mayhave(&FKEY[15], "s5");
mayhave(&FKEY[16], "s6");
mayhave(&FKEY[17], "s7");
mayhave(&FKEY[18], "s8");
mayhave(&FKEY[19], "s9");
# ifndef NO_CTRL_FKEY
mayhave(&FKEY[20], "c0"); /* control function key codes */
mayhave(&FKEY[21], "c1");
mayhave(&FKEY[22], "c2");
mayhave(&FKEY[23], "c3");
mayhave(&FKEY[24], "c4");
mayhave(&FKEY[25], "c5");
mayhave(&FKEY[26], "c6");
mayhave(&FKEY[27], "c7");
mayhave(&FKEY[28], "c8");
mayhave(&FKEY[29], "c9");
# ifndef NO_ALT_FKEY
mayhave(&FKEY[30], "a0"); /* alt function key codes */
mayhave(&FKEY[31], "a1");
mayhave(&FKEY[32], "a2");
mayhave(&FKEY[33], "a3");
mayhave(&FKEY[34], "a4");
mayhave(&FKEY[35], "a5");
mayhave(&FKEY[36], "a6");
mayhave(&FKEY[37], "a7");
mayhave(&FKEY[38], "a8");
mayhave(&FKEY[39], "a9");
# endif
# endif
# endif
#endif
#ifndef NO_CURSORSHAPE
/* cursor shapes */
CQ = tgetstr("cQ", &capbuf);
if (has_CQ)
{
CX = tgetstr("cX", &capbuf);
if (!CX) CX = CQ;
CV = tgetstr("cV", &capbuf);
if (!CV) CV = CQ;
CI = tgetstr("cI", &capbuf);
if (!CI) CI = CQ;
CR = tgetstr("cR", &capbuf);
if (!CR) CR = CQ;
}
# ifndef CRUNCH
else
{
CQ = CV = "";
pair(&CQ, &CV, "ve", "vs");
CX = CI = CR = CQ;
}
# endif /* !CRUNCH */
#endif /* !NO_CURSORSHAPE */
#ifndef NO_COLOR
strcpy(SOcolor, SO);
strcpy(SEcolor, SE);
strcpy(AScolor, AS);
strcpy(AEcolor, AE);
strcpy(MDcolor, MD);
strcpy(MEcolor, ME);
strcpy(UScolor, US);
strcpy(UEcolor, UE);
# ifndef NO_POPUP
strcpy(POPUPcolor, SO);
# endif
# ifndef NO_VISIBLE
strcpy(VISIBLEcolor, MV);
# endif
#endif
}
/* This function gets the window size. It uses the TIOCGWINSZ ioctl call if
* your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
* This function is called once during initialization, and thereafter it is
* called whenever the SIGWINCH signal is sent to this process.
*/
void getsize(signo)
int signo;
{
int lines;
int cols;
#ifdef TIOCGWINSZ
struct winsize size;
#endif
#ifdef SIGWINCH
/* reset the signal vector */
signal(SIGWINCH, getsize);
#endif
/* get the window size, one way or another. */
lines = cols = 0;
#ifdef TIOCGWINSZ
if (ioctl(2, TIOCGWINSZ, &size) >= 0)
{
lines = size.ws_row;
cols = size.ws_col;
}
#endif
#if AMIGA
/* Amiga gets window size by asking the console.device */
if (!strcmp(TERMTYPE, termtype))
{
auto long len;
auto char buf[30];
Write(Output(), "\2330 q", 4); /* Ask the console.device */
len = Read(Input(), buf, 29);
buf[len] = '\000';
sscanf(&buf[5], "%d;%d", &lines, &cols);
}
#endif
if ((lines == 0 || cols == 0) && signo == 0)
{
LINES = tgetnum("li");
COLS = tgetnum("co");
}
#if MSDOS
# ifdef RAINBOW
if (!strcmp(termtype, "rainbow"))
{
/* Determine whether Rainbow is in 80-column or 132-column mode */
cols = *(unsigned char far *)0xee000f57L;
}
else
# endif
{
lines = v_rows();
cols = v_cols();
}
#endif
if (lines >= 2)
{
LINES = lines;
}
if (cols >= 30)
{
COLS = cols;
}
/* Make sure we got values that we can live with */
if (LINES < 2 || COLS < 30)
{
write(2, "Screen too small\n", (unsigned)17);
#if OSK
write(2, "\l", 1);
#endif
endwin();
exit(2);
}
#if AMIGA
if (*o_lines != LINES || *o_columns != COLS)
{
*o_lines = LINES;
*o_columns = COLS;
}
#endif
}
/* This is a function version of addch() -- it is used by tputs() */
int faddch(ch)
int ch;
{
addch(ch);
return 0;
}
/* This function quickly adds a string to the output queue. It does *NOT*
* convert \n into <CR><LF>.
*/
void qaddstr(str)
char *str;
{
REG char *s_, *d_;
#if MSDOS
if (o_pcbios[0])
{
while (*str)
qaddch(*str++);
return;
}
#endif
for (s_=(str), d_=stdscr; *d_++ = *s_++; )
{
}
stdscr = d_ - 1;
}
/* Output the ESC sequence needed to go into any video mode, if supported */
void attrset(a)
int a;
{
do_aend();
if (a == A_BOLD)
{
do_MD();
aend = ME;
}
else if (a == A_UNDERLINE)
{
do_US();
aend = UE;
}
else if (a == A_ALTCHARSET)
{
do_AS();
aend = AE;
}
else
{
aend = "";
}
}
/* Insert a single character into the display */
void insch(ch)
int ch;
{
if (has_IM)
do_IM();
do_IC();
qaddch(ch);
if (has_EI)
do_EI();
}
void wrefresh()
{
if (stdscr != kbuf)
{
VOIDBIOS(;,ttywrite(kbuf, (unsigned)(stdscr - kbuf)));
stdscr = kbuf;
}
}
void wqrefresh()
{
if (stdscr - kbuf > 2000)
{
VOIDBIOS(stdscr = kbuf,
{
ttywrite(kbuf, (unsigned)(stdscr - kbuf));
stdscr = kbuf;
});
}
}
#ifndef NO_COLOR
/* This function is called during termination. It resets color modes */
int ansiquit()
{
/* if ANSI color terminal, then reset the colors */
if (!strcmp(UP, "\033[A"))
{
tputs("\033[37;40m\033[m", 1, faddch);
clrtoeol();
return 1;
}
return 0;
}
/* This sets the color strings that work for ANSI terminals. If the TERMCAP
* doesn't look like an ANSI terminal, then it returns FALSE. If the colors
* aren't understood, it also returns FALSE. If all goes well, it returns TRUE
*/
int ansicolor(cmode, attrbyte)
int cmode; /* mode to set, e.g. A_NORMAL */
int attrbyte; /* IBM PC attribute byte */
{
char temp[16]; /* hold the new mode string */
/* if not ANSI-ish, then fail */
if (strcmp(UP, "\033[A") && strcmp(UP, "\033OA"))
{
msg("Don't know how to set colors for this terminal");
return 0;
}
/* construct the color string */
sprintf(temp, "\033[m\033[3%c;4%c%s%sm",
"04261537"[attrbyte & 0x07],
"04261537"[(attrbyte >> 4) & 0x07],
(attrbyte & 0x08) ? ";1" : "",
(attrbyte & 0x80) ? ";5" : "");
/* stick it in the right place */
switch (cmode)
{
case A_NORMAL:
if (!strcmp(MEcolor, normalcolor))
strcpy(MEcolor, temp);
if (!strcmp(UEcolor, normalcolor))
strcpy(UEcolor, temp);
if (!strcmp(AEcolor, normalcolor))
strcpy(AEcolor, temp);
if (!strcmp(SEcolor, normalcolor))
strcpy(SEcolor, temp);
strcpy(normalcolor, temp);
tputs(normalcolor, 1, faddch);
break;
case A_BOLD:
strcpy(MDcolor, temp);
strcpy(MEcolor, normalcolor);
break;
case A_UNDERLINE:
strcpy(UScolor, temp);
strcpy(UEcolor, normalcolor);
break;
case A_ALTCHARSET:
strcpy(AScolor, temp);
strcpy(AEcolor, normalcolor);
break;
case A_STANDOUT:
strcpy(SOcolor, temp);
strcpy(SEcolor, normalcolor);
break;
#ifndef NO_POPUP
case A_POPUP:
strcpy(POPUPcolor, temp);
break;
#endif
#ifndef NO_VISIBLE
case A_VISIBLE:
strcpy(VISIBLEcolor, temp);
break;
#endif
}
return 1;
}
/* This function outputs the ESC sequence needed to switch the screen back
* to "normal" mode. On color terminals which haven't had their color set
* yet, this is one of the termcap strings; for color terminals that really
* have had colors defined, we just the "normal color" escape sequence.
*/
endcolor()
{
if (aend == ME)
tputs(MEcolor, 1, faddch);
else if (aend == UE)
tputs(UEcolor, 1, faddch);
else if (aend == AE)
tputs(AEcolor, 1, faddch);
else if (aend == SE)
tputs(SEcolor, 1, faddch);
aend = "";
return 0;
}
#endif /* !NO_COLOR */

View file

@ -1,319 +0,0 @@
/* curses.h */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This is the header file for a small, fast, fake curses package */
/* termcap stuff */
extern char *tgoto();
extern char *tgetstr();
extern void tputs();
#if MSDOS
/* BIOS interface used instead of termcap for MS-DOS */
extern int vmode;
extern void v_up();
extern void v_cb();
extern void v_cs();
extern void v_ce();
extern void v_cl();
extern void v_cd();
extern void v_al();
extern void v_dl();
extern void v_sr();
extern void v_move();
#endif
/* faddch() is a function. a pointer to it is passed to tputs() */
extern int faddch();
/* data types */
#define WINDOW char
/* CONSTANTS & SYMBOLS */
#define TRUE 1
#define FALSE 0
#define A_NORMAL 0
#define A_STANDOUT 1
#define A_BOLD 2
#define A_UNDERLINE 3
#define A_ALTCHARSET 4
#define A_POPUP 5
#define A_VISIBLE 6
#define KBSIZ 4096
/* figure out how many function keys we need to allow. */
#ifndef NO_FKEY
# ifdef NO_SHIFT_FKEY
# define NFKEYS 10
# else
# ifdef NO_CTRL_FKEY
# define NFKEYS 20
# else
# ifdef NO_ALT_FKEY
# define NFKEYS 30
# else
# define NFKEYS 40
# endif
# endif
# endif
extern char *FKEY[NFKEYS]; /* :k0=:...:k9=: codes sent by function keys */
#endif
/* extern variables, defined in curses.c */
extern char *termtype; /* name of terminal entry */
extern short ospeed; /* tty speed, eg B2400 */
#if OSK
extern char PC_; /* Pad char */
extern char *BC; /* Backspace char string */
#else
extern char PC; /* Pad char */
#endif
extern WINDOW *stdscr; /* pointer into kbuf[] */
extern WINDOW kbuf[KBSIZ]; /* a very large output buffer */
extern int LINES; /* :li#: number of rows */
extern int COLS; /* :co#: number of columns */
extern int AM; /* :am: boolean: auto margins? */
extern int PT; /* :pt: boolean: physical tabs? */
extern char *VB; /* :vb=: visible bell */
extern char *UP; /* :up=: move cursor up */
extern char *SO; /* :so=: standout start */
extern char *SE; /* :se=: standout end */
extern char *US; /* :us=: underline start */
extern char *UE; /* :ue=: underline end */
extern char *MD; /* :md=: bold start */
extern char *ME; /* :me=: bold end */
extern char *AS; /* :as=: alternate (italic) start */
extern char *AE; /* :ae=: alternate (italic) end */
#ifndef NO_VISIBLE
extern char *MV; /* :mv=: "visible" selection start */
#endif
extern char *CM; /* :cm=: cursor movement */
extern char *CE; /* :ce=: clear to end of line */
extern char *CD; /* :cd=: clear to end of screen */
extern char *AL; /* :al=: add a line */
extern char *DL; /* :dl=: delete a line */
#if OSK
extern char *SR_; /* :sr=: scroll reverse */
#else
extern char *SR; /* :sr=: scroll reverse */
#endif
extern char *KS; /* :ks=: init string for cursor */
extern char *KE; /* :ke=: restore string for cursor */
extern char *KU; /* :ku=: sequence sent by up key */
extern char *KD; /* :kd=: sequence sent by down key */
extern char *KL; /* :kl=: sequence sent by left key */
extern char *KR; /* :kr=: sequence sent by right key */
extern char *PU; /* :PU=: key sequence sent by PgUp key */
extern char *PD; /* :PD=: key sequence sent by PgDn key */
extern char *HM; /* :HM=: key sequence sent by Home key */
extern char *EN; /* :EN=: key sequence sent by End key */
extern char *KI; /* :kI=: key sequence sent by Insert key */
extern char *IM; /* :im=: insert mode start */
extern char *IC; /* :ic=: insert following char */
extern char *EI; /* :ei=: insert mode end */
extern char *DC; /* :dc=: delete a character */
extern char *TI; /* :ti=: terminal init */ /* GB */
extern char *TE; /* :te=: terminal exit */ /* GB */
#ifndef NO_CURSORSHAPE
extern char *CQ; /* :cQ=: normal cursor */
extern char *CX; /* :cX=: cursor used for EX command/entry */
extern char *CV; /* :cV=: cursor used for VI command mode */
extern char *CI; /* :cI=: cursor used for VI input mode */
extern char *CR; /* :cR=: cursor used for VI replace mode */
#endif
extern char *aend; /* end an attribute -- either UE or ME */
extern char ERASEKEY; /* taken from the ioctl structure */
#ifndef NO_COLOR
extern char SOcolor[];
extern char SEcolor[];
extern char UScolor[];
extern char UEcolor[];
extern char MDcolor[];
extern char MEcolor[];
extern char AScolor[];
extern char AEcolor[];
# ifndef NO_POPUP
extern char POPUPcolor[];
# endif
# ifndef NO_VISIBLE
extern char VISIBLEcolor[];
# endif
extern char normalcolor[];
#endif /* undef NO_COLOR */
/* Msdos-versions may use bios; others always termcap.
* Will emit some 'code has no effect' warnings in unix.
*/
#if MSDOS
extern char o_pcbios[1]; /* BAH! */
#define CHECKBIOS(x,y) (*o_pcbios ? (x) : (y))
#define VOIDBIOS(x,y) {if (*o_pcbios) {x;} else {y;}}
#else
#define CHECKBIOS(x,y) (y)
#define VOIDBIOS(x,y) {y;}
#endif
#ifndef NO_COLOR
# define setcolor(m,a) CHECKBIOS(bioscolor(m,a), ansicolor(m,a))
# define fixcolor() VOIDBIOS(;, tputs(normalcolor, 1, faddch))
# define quitcolor() CHECKBIOS(biosquit(), ansiquit())
# define do_SO() VOIDBIOS((vmode=A_STANDOUT), tputs(SOcolor, 1, faddch))
# define do_SE() VOIDBIOS((vmode=A_NORMAL), tputs(SEcolor, 1, faddch))
# define do_US() VOIDBIOS((vmode=A_UNDERLINE), tputs(UScolor, 1, faddch))
# define do_UE() VOIDBIOS((vmode=A_NORMAL), tputs(UEcolor, 1, faddch))
# define do_MD() VOIDBIOS((vmode=A_BOLD), tputs(MDcolor, 1, faddch))
# define do_ME() VOIDBIOS((vmode=A_NORMAL), tputs(MEcolor, 1, faddch))
# define do_AS() VOIDBIOS((vmode=A_ALTCHARSET), tputs(AScolor, 1, faddch))
# define do_AE() VOIDBIOS((vmode=A_NORMAL), tputs(AEcolor, 1, faddch))
# define do_POPUP() VOIDBIOS((vmode=A_POPUP), tputs(POPUPcolor, 1, faddch))
# define do_VISIBLE() VOIDBIOS((vmode=A_VISIBLE), tputs(VISIBLEcolor, 1, faddch))
#else
# define do_SO() VOIDBIOS((vmode=A_STANDOUT), tputs(SO, 1, faddch))
# define do_SE() VOIDBIOS((vmode=A_NORMAL), tputs(SE, 1, faddch))
# define do_US() VOIDBIOS((vmode=A_UNDERLINE), tputs(US, 1, faddch))
# define do_UE() VOIDBIOS((vmode=A_NORMAL), tputs(UE, 1, faddch))
# define do_MD() VOIDBIOS((vmode=A_BOLD), tputs(MD, 1, faddch))
# define do_ME() VOIDBIOS((vmode=A_NORMAL), tputs(ME, 1, faddch))
# define do_AS() VOIDBIOS((vmode=A_ALTCHARSET), tputs(AS, 1, faddch))
# define do_AE() VOIDBIOS((vmode=A_NORMAL), tputs(AE, 1, faddch))
# define do_POPUP() VOIDBIOS((vmode=A_POPUP), tputs(SO, 1, faddch))
# define do_VISIBLE() VOIDBIOS((vmode=A_VISIBLE), tputs(MV, 1, faddch))
#endif
#define do_VB() VOIDBIOS(;, tputs(VB, 1, faddch))
#define do_UP() VOIDBIOS(v_up(), tputs(UP, 1, faddch))
#undef do_CM /* move */
#define do_CE() VOIDBIOS(v_ce(), tputs(CE, 1, faddch))
#define do_CD() VOIDBIOS(v_cd(), tputs(CD, 1, faddch))
#define do_AL() VOIDBIOS(v_al(), tputs(AL, LINES, faddch))
#define do_DL() VOIDBIOS(v_dl(), tputs(DL, LINES, faddch))
#if OSK
#define do_SR() VOIDBIOS(v_sr(), tputs(SR_, 1, faddch))
#else
#define do_SR() VOIDBIOS(v_sr(), tputs(SR, 1, faddch))
#endif
#define do_KS() VOIDBIOS(1, tputs(KS, 1, faddch))
#define do_KE() VOIDBIOS(1, tputs(KE, 1, faddch))
#define do_IM() VOIDBIOS(;, tputs(IM, 1, faddch))
#define do_IC() VOIDBIOS(;, tputs(IC, 1, faddch))
#define do_EI() VOIDBIOS(;, tputs(EI, 1, faddch))
#define do_DC() VOIDBIOS(;, tputs(DC, COLS, faddch))
#define do_TI() VOIDBIOS(;, (void)ttywrite(TI, (unsigned)strlen(TI)))
#define do_TE() VOIDBIOS(;, (void)ttywrite(TE, (unsigned)strlen(TE)))
#ifndef NO_CURSORSHAPE
# define do_CQ() VOIDBIOS(v_cs(), tputs(CQ, 1, faddch))
# define do_CX() VOIDBIOS(v_cs(), tputs(CX, 1, faddch))
# define do_CV() VOIDBIOS(v_cs(), tputs(CV, 1, faddch))
# define do_CI() VOIDBIOS(v_cb(), tputs(CI, 1, faddch))
# define do_CR() VOIDBIOS(v_cb(), tputs(CR, 1, faddch))
#endif
#ifndef NO_COLOR
# define do_aend() VOIDBIOS((vmode=A_NORMAL), endcolor())
#else
# define do_aend() VOIDBIOS((vmode=A_NORMAL), tputs(aend, 1, faddch))
#endif
#define has_AM CHECKBIOS(1, AM)
#define has_PT CHECKBIOS(0, PT)
#define has_VB CHECKBIOS((char *)0, VB)
#define has_UP CHECKBIOS((char *)1, UP)
#define has_SO CHECKBIOS((char)1, (*SO))
#define has_SE CHECKBIOS((char)1, (*SE))
#define has_US CHECKBIOS((char)1, (*US))
#define has_UE CHECKBIOS((char)1, (*UE))
#define has_MD CHECKBIOS((char)1, (*MD))
#define has_ME CHECKBIOS((char)1, (*ME))
#define has_AS CHECKBIOS((char)1, (*AS))
#define has_AE CHECKBIOS((char)1, (*AE))
#undef has_CM /* cursor move: don't need */
#define has_CB CHECKBIOS(1, 0)
#define has_CS CHECKBIOS(1, 0)
#define has_CE CHECKBIOS((char *)1, CE)
#define has_CD CHECKBIOS((char *)1, CD)
#define has_AL CHECKBIOS((char *)1, AL)
#define has_DL CHECKBIOS((char *)1, DL)
#if OSK
#define has_SR CHECKBIOS((char *)1, SR_)
#else
#define has_SR CHECKBIOS((char *)1, SR)
#endif
#define has_KS CHECKBIOS((char)1, (*KS))
#define has_KE CHECKBIOS((char)1, (*KE))
#define has_KU KU
#define has_KD KD
#define has_KL KL
#define has_KR KR
#define has_HM HM
#define has_EN EN
#define has_PU PU
#define has_PD PD
#define has_KI KI
#define has_IM CHECKBIOS((char)0, (*IM))
#define has_IC CHECKBIOS((char)0, (*IC))
#define has_EI CHECKBIOS((char)0, (*EI))
#define has_DC CHECKBIOS((char *)0, DC)
#define has_TI CHECKBIOS((char)0, (*TI))
#define has_TE CHECKBIOS((char)0, (*TE))
#ifndef NO_CURSORSHAPE
#define has_CQ CHECKBIOS((char *)1, CQ)
#endif
/* (pseudo)-Curses-functions */
#ifdef lint
# define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\r') : (stdscr[-1] = '\n')))
#else
# if OSK
# define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\l') : (stdscr[-1] = stdscr[-1])))
# else
# define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\r') : 0))
# endif
#endif
#ifdef AZTEC_C
# define qaddch(ch) CHECKBIOS(v_put(ch), (*stdscr = (ch), *stdscr++))
#else
#define qaddch(ch) CHECKBIOS(v_put(ch), (*stdscr++ = (ch)))
#endif
#if OSK
#define addch(ch) if (qaddch(ch) == '\n') qaddch('\l'); else
#else
#define addch(ch) if (qaddch(ch) == '\n') qaddch('\r'); else
#endif
extern void initscr();
extern void endwin();
extern void suspend_curses();
extern void resume_curses();
extern void attrset();
extern void insch();
extern void qaddstr();
extern void wrefresh();
extern void wqrefresh();
#define addstr(str) {qaddstr(str); _addCR;}
#define move(y,x) VOIDBIOS(v_move(x,y), tputs(tgoto(CM, x, y), 1, faddch))
#define mvaddch(y,x,ch) {move(y,x); addch(ch);}
#define refresh() VOIDBIOS(;, wrefresh())
#define standout() do_SO()
#define standend() do_SE()
#define clrtoeol() do_CE()
#define clrtobot() do_CD()
#define insertln() do_AL()
#define deleteln() do_DL()
#define delch() do_DC()
#define scrollok(w,b)
#define raw()
#define echo()
#define cbreak()
#define noraw()
#define noecho()
#define nocbreak()

View file

@ -1,700 +0,0 @@
/* cut.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains function which manipulate the cut buffers. */
#include "config.h"
#include "vi.h"
#if TURBOC
#include <process.h> /* needed for getpid */
#endif
#if TOS
#include <osbind.h>
#define rename(a,b) Frename(0,a,b)
#endif
# define NANONS 9 /* number of anonymous buffers */
static struct cutbuf
{
short *phys; /* pointer to an array of #s of BLKs containing text */
int nblks; /* number of blocks in phys[] array */
int start; /* offset into first block of start of cut */
int end; /* offset into last block of end of cut */
int tmpnum; /* ID number of the temp file */
char lnmode; /* boolean: line-mode cut? (as opposed to char-mode) */
}
named[27], /* cut buffers "a through "z and ". */
anon[NANONS]; /* anonymous cut buffers */
static char cbname; /* name chosen for next cut/paste operation */
static char dotcb; /* cut buffer to use if "doingdot" is set */
#ifndef NO_RECYCLE
/* This function builds a list of all blocks needed in the current tmp file
* for the contents of cut buffers.
* !!! WARNING: if you have more than ~450000 bytes of text in all of the
* cut buffers, then this will fail disastrously, because buffer overflow
* is *not* allowed for.
*/
int cutneeds(need)
BLK *need; /* this is where we deposit the list */
{
struct cutbuf *cb; /* used to count through cut buffers */
int i; /* used to count through blocks of a cut buffer */
int n; /* total number of blocks in list */
n = 0;
/* first the named buffers... */
for (cb = named; cb < &named[27]; cb++)
{
if (cb->tmpnum != tmpnum)
continue;
for (i = cb->nblks; i-- > 0; )
{
need->n[n++] = cb->phys[i];
}
}
/* then the anonymous buffers */
for (cb = anon; cb < &anon[NANONS]; cb++)
{
if (cb->tmpnum != tmpnum)
continue;
for (i = cb->nblks; i-- > 0; )
{
need->n[n++] = cb->phys[i];
}
}
/* return the length of the list */
return n;
}
#endif
static void maybezap(num)
int num; /* the tmpnum of the temporary file to [maybe] delete */
{
char cutfname[80];
int i;
/* if this is the current tmp file, then we'd better keep it! */
if (tmpfd >= 0 && num == tmpnum)
{
return;
}
/* see if anybody else needs this tmp file */
for (i = 27; --i >= 0; )
{
if (named[i].nblks > 0 && named[i].tmpnum == num)
{
break;
}
}
if (i < 0)
{
for (i = NANONS; --i >= 0 ; )
{
if (anon[i].nblks > 0 && anon[i].tmpnum == num)
{
break;
}
}
}
/* if nobody else needs it, then discard the tmp file */
if (i < 0)
{
#if MSDOS || TOS
strcpy(cutfname, o_directory);
if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i - 1]))
cutfname[i++] = SLASH;
sprintf(cutfname + i, TMPNAME + 3, getpid(), num);
#else
sprintf(cutfname, TMPNAME, o_directory, getpid(), num);
#endif
unlink(cutfname);
}
}
/* This function frees a cut buffer. If it was the last cut buffer that
* refered to an old temp file, then it will delete the temp file. */
static void cutfree(buf)
struct cutbuf *buf;
{
int num;
/* return immediately if the buffer is already empty */
if (buf->nblks <= 0)
{
return;
}
/* else free up stuff */
num = buf->tmpnum;
buf->nblks = 0;
#ifdef DEBUG
if (!buf->phys)
msg("cutfree() tried to free a NULL buf->phys pointer.");
else
#endif
free((char *)buf->phys);
/* maybe delete the temp file */
maybezap(num);
}
/* This function is called when we are about to abort a tmp file.
*
* To minimize the number of extra files lying around, only named cut buffers
* are preserved in a file switch; the anonymous buffers just go away.
*/
void cutswitch()
{
int i;
/* mark the current temp file as being "obsolete", and close it. */
storename((char *)0);
close(tmpfd);
tmpfd = -1;
/* discard all anonymous cut buffers */
for (i = 0; i < NANONS; i++)
{
cutfree(&anon[i]);
}
/* delete the temp file, if we don't really need it */
maybezap(tmpnum);
}
/* This function should be called just before termination of vi */
void cutend()
{
int i;
/* free the anonymous buffers, if they aren't already free */
cutswitch();
/* free all named cut buffers, since they might be forcing an older
* tmp file to be retained.
*/
for (i = 0; i < 27; i++)
{
cutfree(&named[i]);
}
/* delete the temp file */
maybezap(tmpnum);
}
/* This function is used to select the cut buffer to be used next */
void cutname(name)
int name; /* a single character */
{
cbname = name;
}
/* This function copies a selected segment of text to a cut buffer */
void cut(from, to)
MARK from; /* start of text to cut */
MARK to; /* end of text to cut */
{
int first; /* logical number of first block in cut */
int last; /* logical number of last block used in cut */
long line; /* a line number */
int lnmode; /* boolean: will this be a line-mode cut? */
MARK delthru;/* end of text temporarily inserted for apnd */
REG struct cutbuf *cb;
REG long l;
REG int i;
REG char *scan;
char *blkc;
/* detect whether this must be a line-mode cut or char-mode cut */
if (markidx(from) == 0 && markidx(to) == 0)
lnmode = TRUE;
else
lnmode = FALSE;
/* by default, we don't "delthru" anything */
delthru = MARK_UNSET;
/* handle the "doingdot" quirks */
if (doingdot)
{
if (!cbname)
{
cbname = dotcb;
}
}
else if (cbname != '.')
{
dotcb = cbname;
}
/* decide which cut buffer to use */
if (!cbname)
{
/* free up the last anonymous cut buffer */
cutfree(&anon[NANONS - 1]);
/* shift the anonymous cut buffers */
for (i = NANONS - 1; i > 0; i--)
{
anon[i] = anon[i - 1];
}
/* use the first anonymous cut buffer */
cb = anon;
cb->nblks = 0;
}
else if (cbname >= 'a' && cbname <= 'z')
{
cb = &named[cbname - 'a'];
cutfree(cb);
}
#ifndef CRUNCH
else if (cbname >= 'A' && cbname <= 'Z')
{
cb = &named[cbname - 'A'];
if (cb->nblks > 0)
{
/* resolve linemode/charmode differences */
if (!lnmode && cb->lnmode)
{
from &= ~(BLKSIZE - 1);
if (markidx(to) != 0 || to == from)
{
to = to + BLKSIZE - markidx(to);
}
lnmode = TRUE;
}
/* insert the old cut-buffer before the new text */
mark[28] = to;
delthru = paste(from, FALSE, TRUE);
if (delthru == MARK_UNSET)
{
return;
}
delthru++;
to = mark[28];
}
cutfree(cb);
}
#endif /* not CRUNCH */
else if (cbname == '.')
{
cb = &named[26];
cutfree(cb);
}
else
{
msg("Invalid cut buffer name: \"%c", cbname);
dotcb = cbname = '\0';
return;
}
cbname = '\0';
cb->tmpnum = tmpnum;
/* detect whether we're doing a line mode cut */
cb->lnmode = lnmode;
/* ---------- */
/* Reporting... */
if (markidx(from) == 0 && markidx(to) == 0)
{
rptlines = markline(to) - markline(from);
rptlabel = "yanked";
}
/* ---------- */
/* make sure each block has a physical disk address */
blksync();
/* find the first block in the cut */
line = markline(from);
for (first = 1; line > lnum[first]; first++)
{
}
/* fetch text of the block containing that line */
blkc = scan = blkget(first)->c;
/* find the mark in the block */
for (l = lnum[first - 1]; ++l < line; )
{
while (*scan++ != '\n')
{
}
}
scan += markidx(from);
/* remember the offset of the start */
cb->start = scan - blkc;
/* ---------- */
/* find the last block in the cut */
line = markline(to);
for (last = first; line > lnum[last]; last++)
{
}
/* fetch text of the block containing that line */
if (last != first)
{
blkc = scan = blkget(last)->c;
}
else
{
scan = blkc;
}
/* find the mark in the block */
for (l = lnum[last - 1]; ++l < line; )
{
while (*scan++ != '\n')
{
}
}
if (markline(to) <= nlines)
{
scan += markidx(to);
}
/* remember the offset of the end */
cb->end = scan - blkc;
/* ------- */
/* remember the physical block numbers of all included blocks */
cb->nblks = last - first;
if (cb->end > 0)
{
cb->nblks++;
}
#ifdef lint
cb->phys = (short *)0;
#else
cb->phys = (short *)malloc((unsigned)(cb->nblks * sizeof(short)));
#endif
for (i = 0; i < cb->nblks; i++)
{
cb->phys[i] = hdr.n[first++];
}
#ifndef CRUNCH
/* if we temporarily inserted text for appending, then delete that
* text now -- before the user sees it.
*/
if (delthru)
{
line = rptlines;
delete(from, delthru);
rptlines = line;
rptlabel = "yanked";
}
#endif /* not CRUNCH */
}
static void readcutblk(cb, blkno)
struct cutbuf *cb;
int blkno;
{
char cutfname[50];/* name of an old temp file */
int fd; /* either tmpfd or the result of open() */
#if MSDOS || TOS
int i;
#endif
/* decide which fd to use */
if (cb->tmpnum == tmpnum)
{
fd = tmpfd;
}
else
{
#if MSDOS || TOS
strcpy(cutfname, o_directory);
if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i-1]))
cutfname[i++]=SLASH;
sprintf(cutfname+i, TMPNAME+3, getpid(), cb->tmpnum);
#else
sprintf(cutfname, TMPNAME, o_directory, getpid(), cb->tmpnum);
#endif
fd = open(cutfname, O_RDONLY);
}
/* get the block */
lseek(fd, (long)cb->phys[blkno] * (long)BLKSIZE, 0);
if (read(fd, tmpblk.c, (unsigned)BLKSIZE) != BLKSIZE)
{
msg("Error reading back from tmp file for pasting!");
}
/* close the fd, if it isn't tmpfd */
if (fd != tmpfd)
{
close(fd);
}
}
/* This function inserts text from a cut buffer, and returns the MARK where
* insertion ended. Return MARK_UNSET on errors.
*/
MARK paste(at, after, retend)
MARK at; /* where to insert the text */
int after; /* boolean: insert after mark? (rather than before) */
int retend; /* boolean: return end of text? (rather than start) */
{
REG struct cutbuf *cb;
REG int i;
/* handle the "doingdot" quirks */
if (doingdot)
{
if (!cbname)
{
if (dotcb >= '1' && dotcb < '1' + NANONS - 1)
{
dotcb++;
}
cbname = dotcb;
}
}
else if (cbname != '.')
{
dotcb = cbname;
}
/* decide which cut buffer to use */
if (cbname >= 'A' && cbname <= 'Z')
{
cb = &named[cbname - 'A'];
}
else if (cbname >= 'a' && cbname <= 'z')
{
cb = &named[cbname - 'a'];
}
else if (cbname >= '1' && cbname <= '9')
{
cb = &anon[cbname - '1'];
}
else if (cbname == '.')
{
cb = &named[26];
}
else if (!cbname)
{
cb = anon;
}
else
{
msg("Invalid cut buffer name: \"%c", cbname);
cbname = '\0';
return MARK_UNSET;
}
/* make sure it isn't empty */
if (cb->nblks == 0)
{
if (cbname)
msg("Cut buffer \"%c is empty", cbname);
else
msg("Cut buffer is empty");
cbname = '\0';
return MARK_UNSET;
}
cbname = '\0';
/* adjust the insertion MARK for "after" and line-mode cuts */
if (cb->lnmode)
{
at &= ~(BLKSIZE - 1);
if (after)
{
at += BLKSIZE;
}
}
else if (after)
{
/* careful! if markidx(at) == 0 we might be pasting into an
* empty line -- so we can't blindly increment "at".
*/
if (markidx(at) == 0)
{
pfetch(markline(at));
if (plen != 0)
{
at++;
}
}
else
{
at++;
}
}
/* put a copy of the "at" mark in the mark[] array, so it stays in
* sync with changes made via add().
*/
mark[27] = at;
/* simple one-block paste? */
if (cb->nblks == 1)
{
/* get the block */
readcutblk(cb, 0);
/* isolate the text we need within it */
if (cb->end)
{
tmpblk.c[cb->end] = '\0';
}
/* insert it */
ChangeText
{
add(at, &tmpblk.c[cb->start]);
}
}
else
{
/* multi-block paste */
ChangeText
{
i = cb->nblks - 1;
/* add text from the last block first */
if (cb->end > 0)
{
readcutblk(cb, i);
tmpblk.c[cb->end] = '\0';
add(at, tmpblk.c);
i--;
}
/* add intervening blocks */
while (i > 0)
{
readcutblk(cb, i);
add(at, tmpblk.c);
i--;
}
/* add text from the first cut block */
readcutblk(cb, 0);
add(at, &tmpblk.c[cb->start]);
}
}
/* Reporting... */
rptlines = markline(mark[27]) - markline(at);
rptlabel = "pasted";
/* return the mark at the beginning/end of inserted text */
if (retend)
{
return mark[27] - 1L;
}
return at;
}
#ifndef NO_AT
/* This function copies characters from a cut buffer into a string.
* It returns the number of characters in the cut buffer. If the cut
* buffer is too large to fit in the string (i.e. if cb2str() returns
* a number >= size) then the characters will not have been copied.
* It returns 0 if the cut buffer is empty, and -1 for invalid cut buffers.
*/
int cb2str(name, buf, size)
int name; /* the name of a cut-buffer to get: a-z only! */
char *buf; /* where to put the string */
unsigned size; /* size of buf */
{
REG struct cutbuf *cb;
REG char *src;
REG char *dest;
/* decide which cut buffer to use */
if (name >= 'a' && name <= 'z')
{
cb = &named[name - 'a'];
}
else
{
return -1;
}
/* if the buffer is empty, return 0 */
if (cb->nblks == 0)
{
return 0;
}
/* !!! if not a single-block cut, then fail */
if (cb->nblks != 1)
{
return size;
}
/* if too big, return the size now, without doing anything */
if (cb->end - cb->start >= size)
{
return cb->end - cb->start;
}
/* get the block */
readcutblk(cb, 0);
/* isolate the string within that blk */
if (cb->start == 0)
{
tmpblk.c[cb->end] = '\0';
}
else
{
for (dest = tmpblk.c, src = dest + cb->start; src < tmpblk.c + cb->end; )
{
*dest++ = *src++;
}
*dest = '\0';
}
/* copy the string into the buffer */
if (buf != tmpblk.c)
{
strcpy(buf, tmpblk.c);
}
/* return the length */
return cb->end - cb->start;
}
#endif

View file

@ -1,287 +0,0 @@
/* elvprsv.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the portable sources for the "elvprsv" program.
* "Elvprsv" is run by Elvis when Elvis is about to die. It is also
* run when the computer boots up. It is not intended to be run directly
* by the user, ever.
*
* Basically, this program does the following four things:
* - It extracts the text from the temporary file, and places the text in
* a file in the /usr/preserve directory.
* - It adds a line to the /usr/preserve/Index file, describing the file
* that it just preserved.
* - It removes the temporary file.
* - It sends mail to the owner of the file, saying that the file was
* preserved, and how it can be recovered.
*
* The /usr/preserve/Index file is a log file that contains one line for each
* file that has ever been preserved. Each line of this file describes one
* preserved file. The first word on the line is the name of the file that
* contains the preserved text. The second word is the full pathname of the
* file that was being edited; for anonymous buffers, this is the directory
* name plus "/foo".
*
* If elvprsv's first argument (after the command name) starts with a hyphen,
* then the characters after the hyphen are used as a description of when
* the editor went away. This is optional.
*
* The remaining arguments are all the names of temporary files that are
* to be preserved. For example, on a UNIX system, the /etc/rc file might
* invoke it this way:
*
* elvprsv "-the system went down" /tmp/elv_*.*
*
* This file contains only the portable parts of the preserve program.
* It must #include a system-specific file. The system-specific file is
* expected to define the following functions:
*
* char *ownername(char *filename) - returns name of person who owns file
*
* void mail(char *user, char *name, char *when)
* - tell user that file was preserved
*/
#include <stdio.h>
#include "config.h"
#include "vi.h"
#if AMIGA
BLK tmpblk;
#error AMIGA here DEBUG
# include "amiwild.c"
# include "amiprsv.c"
#endif
#if OSK
# undef sprintf
#endif
#if ANY_UNIX || OSK
# include "prsvunix.c"
#endif
#if MSDOS || TOS
# include "prsvdos.c"
# define WILDCARD_NO_MAIN
# include "wildcard.c"
#endif
BLK buf;
BLK hdr;
BLK name;
int rewrite_now; /* boolean: should we send text directly to orig file? */
/* This function preserves a single file, and announces its success/failure
* via an e-mail message.
*/
void preserve(tname, when)
char *tname; /* name of a temp file to be preserved */
char *when; /* description of when the editor died */
{
int infd; /* fd used for reading from the temp file */
FILE *outfp; /* fp used for writing to the recovery file */
FILE *index; /* fp used for appending to index file */
char outname[100]; /* the name of the recovery file */
char *user; /* name of the owner of the temp file */
#if AMIGA
char *prsvdir;
#endif
int i;
/* open the temp file */
infd = open(tname, O_RDONLY|O_BINARY);
if (infd < 0)
{
/* if we can't open the file, then we should assume that
* the filename contains wildcard characters that weren't
* expanded... and also assume that they weren't expanded
* because there are no files that need to be preserved.
* THEREFORE... we should silently ignore it.
* (Or loudly ignore it if the user was using -R)
*/
if (rewrite_now)
{
perror(tname);
}
return;
}
/* read the header and name from the file */
if (read(infd, hdr.c, BLKSIZE) != BLKSIZE
|| read(infd, name.c, BLKSIZE) != BLKSIZE)
{
/* something wrong with the file - sorry */
fprintf(stderr, "%s: trucated header blocks\n", tname);
close(infd);
return;
}
/* If the filename block contains an empty string, then Elvis was
* only keeping the temp file around because it contained some text
* that was needed for a named cut buffer. The user doesn't care
* about that kind of temp file, so we should silently delete it.
*/
if (name.c[0] == '\0' && name.c[1] == '\177')
{
close(infd);
unlink(tname);
return;
}
if (rewrite_now)
{
/* we don't need to open the index file */
index = (FILE *)0;
/* make sure we can read every block! */
for (i = 1; i < MAXBLKS && hdr.n[i]; i++)
{
lseek(infd, (long)hdr.n[i] * (long)BLKSIZE, 0);
if (read(infd, buf.c, BLKSIZE) != BLKSIZE)
{
/* messed up header */
fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c);
close(infd);
return;
}
}
/* open the user's file for writing */
outfp = fopen(name.c, "w");
if (!outfp)
{
perror(name.c);
close(infd);
return;
}
}
else
{
/* open/create the index file */
index = fopen(PRSVINDEX, "a");
if (!index)
{
perror(PRSVINDEX);
exit(1);
}
/* create the recovery file in the PRESVDIR directory */
#if AMIGA
prsvdir = &PRSVDIR[strlen(PRSVDIR) - 1];
if (*prsvdir == '/' || *prsvdir == ':')
{
sprintf(outname, "%sp%ld", PRSVDIR, ftell(index));
}
else
#endif
sprintf(outname, "%s%cp%ld", PRSVDIR, SLASH, ftell(index));
outfp = fopen(outname, "w");
if (!outfp)
{
perror(outname);
close(infd);
fclose(index);
return;
}
}
/* write the text of the file out to the recovery file */
for (i = 1; i < MAXBLKS && hdr.n[i]; i++)
{
lseek(infd, (long)hdr.n[i] * (long)BLKSIZE, 0);
if (read(infd, buf.c, BLKSIZE) != BLKSIZE)
{
/* messed up header */
fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c);
fclose(outfp);
close(infd);
if (index)
{
fclose(index);
}
unlink(outname);
return;
}
fputs(buf.c, outfp);
}
/* add a line to the index file */
if (index)
{
fprintf(index, "%s %s\n", outname, name.c);
}
/* close everything */
close(infd);
fclose(outfp);
if (index)
{
fclose(index);
}
/* Are we doing this due to something more frightening than just
* a ":preserve" command?
*/
if (*when)
{
/* send a mail message */
mail(ownername(tname), name.c, when);
/* remove the temp file -- the editor has died already */
unlink(tname);
}
}
main(argc, argv)
int argc;
char **argv;
{
int i;
char *when = "the editor went away";
#if MSDOS || TOS
/* expand any wildcards in the command line */
argv = wildexpand(&argc, argv);
#endif
/* do we have a "when" argument? */
i = 1;
if (argc >= i + 1 && !strcmp(argv[i], "-R"))
{
rewrite_now = 1;
when = "";
i++;
#if ANY_UNIX
setuid(geteuid());
#endif
}
#if OSK
else
{
setuid(0);
}
#endif
if (argc >= i + 1 && argv[i][0] == '-')
{
when = argv[i] + 1;
i++;
}
/* preserve everything we're supposed to */
while (i < argc)
{
preserve(argv[i], when);
i++;
}
}

View file

@ -1,199 +0,0 @@
/* elvrec.c */
/* This file contains the file recovery program */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
#include <stdio.h>
#include "config.h"
#include "vi.h"
#include <sys/stat.h>
void recover(basename, outname)
char *basename; /* the name of the file to recover */
char *outname; /* the name of the file to write to */
{
char pathname[500]; /* full pathname of the file to recover */
char line[600]; /* a line from the /usr/preserve/Index file */
int ch; /* a character from the text being recovered */
FILE *from; /* the /usr/preserve file, or /usr/preserve/Index */
FILE *to; /* the user's text file */
char *ptr;
struct stat st;
#if OSK
int uid;
#endif
/* convert basename to a full pathname */
if (basename)
{
#ifndef CRUNCH
# if MSDOS || TOS
if (!basename[0] || basename[1] != ':')
# else
if (basename[0] != SLASH)
# endif
{
ptr = getcwd(pathname, sizeof pathname);
if (ptr != pathname)
{
strcpy(pathname, ptr);
}
ptr = pathname + strlen(pathname);
*ptr++ = SLASH;
strcpy(ptr, basename);
}
else
#endif
{
strcpy(pathname, basename);
}
}
#if OSK
uid = getuid();
if(setuid(0))
exit(_errmsg(errno, "Can't set uid\n"));
#endif
/* scan the /usr/preserve/Index file, for the *oldest* unrecovered
* version of this file.
*/
from = fopen(PRSVINDEX, "r");
while (from && fgets(line, sizeof line, from))
{
/* strip off the newline from the end of the string */
line[strlen(line) - 1] = '\0';
/* parse the line into a "preserve" name and a "text" name */
for (ptr = line; *ptr != ' '; ptr++)
{
}
*ptr++ = '\0';
/* If the "preserve" file is missing, then ignore this line
* because it describes a file that has already been recovered.
*/
if (stat(line, &st) < 0)
{
continue;
}
/* are we looking for a specific file? */
if (basename)
{
/* quit if we found it */
if (!strcmp(ptr, pathname))
{
break;
}
}
else
{
/* list this file as "available for recovery" */
puts(ptr);
}
}
/* file not found? */
if (!basename || !from || feof(from))
{
if (from != NULL) fclose(from);
if (basename)
{
fprintf(stderr, "%s: no recovered file has that exact name\n", pathname);
}
return;
}
if (from != NULL) fclose(from);
/* copy the recovered text back into the user's file... */
/* open the /usr/preserve file for reading */
from = fopen(line, "r");
if (!from)
{
perror(line);
exit(2);
}
#if ANY_UNIX
/* Be careful about user-id. We want to be running under the user's
* real id when we open/create the user's text file... but we want
* to be superuser when we delete the /usr/preserve file. For UNIX,
* we accomplish this by deleting the /usr/preserve file *now*,
* when it is open but before we've read it. Then we revert to the
* user's real id.
*/
unlink(line);
setuid(getuid());
#endif
#if OSK
setuid(uid);
#endif
if (outname == NULL) return;
/* open the user's file for writing */
to = fopen(outname, "w");
if (!to)
{
perror(ptr);
exit(2);
}
/* copy the text */
while ((ch = getc(from)) != EOF)
{
putc(ch, to);
}
#if !ANY_UNIX
#if OSK
fclose(from);
setuid(0);
#endif
/* delete the /usr/preserve file */
unlink(line);
#if OSK
setuid(uid);
#endif
#endif
}
main(argc, argv)
int argc;
char **argv;
{
/* check arguments */
if (argc > 3)
{
fprintf(stderr, "usage: %s [preserved_file [recovery_file]]\n", argv[0]);
exit(1);
}
/* recover the requested file, or list recoverable files */
if (argc == 3)
{
/* recover the file, but write it to a different filename */
recover (argv[1], argv[2]);
}
else if (argc == 2)
{
/* recover the file */
recover(argv[1], argv[1]);
}
else
{
/* list the recoverable files */
recover((char *)0, (char *)0);
}
/* success! */
exit(0);
}

View file

@ -1,722 +0,0 @@
/* ex.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the code for reading ex commands. */
#include "config.h"
#include "ctype.h"
#include "vi.h"
/* This data type is used to describe the possible argument combinations */
typedef short ARGT;
#define FROM 1 /* allow a linespec */
#define TO 2 /* allow a second linespec */
#define BANG 4 /* allow a ! after the command name */
#define EXTRA 8 /* allow extra args after command name */
#define XFILE 16 /* expand wildcards in extra part */
#define NOSPC 32 /* no spaces allowed in the extra part */
#define DFLALL 64 /* default file range is 1,$ */
#define DFLNONE 128 /* no default file range */
#define NODFL 256 /* do not default to the current file name */
#define EXRCOK 512 /* can be in a .exrc file */
#define NL 1024 /* if mode!=MODE_EX, then write a newline first */
#define PLUS 2048 /* allow a line number, as in ":e +32 foo" */
#define ZERO 4096 /* allow 0 to be given as a line number */
#define NOBAR 8192 /* treat following '|' chars as normal */
#define FILES (XFILE + EXTRA) /* multiple extra files allowed */
#define WORD1 (EXTRA + NOSPC) /* one extra word allowed */
#define FILE1 (FILES + NOSPC) /* 1 file allowed, defaults to current file */
#define NAMEDF (FILE1 + NODFL) /* 1 file allowed, defaults to "" */
#define NAMEDFS (FILES + NODFL) /* multiple files allowed, default is "" */
#define RANGE (FROM + TO) /* range of linespecs allowed */
#define NONE 0 /* no args allowed at all */
/* This array maps ex command names to command codes. The order in which
* command names are listed below is significant -- ambiguous abbreviations
* are always resolved to be the first possible match. (e.g. "r" is taken
* to mean "read", not "rewind", because "read" comes before "rewind")
*/
static struct
{
char *name; /* name of the command */
CMD code; /* enum code of the command */
void (*fn)();/* function which executes the command */
ARGT argt; /* command line arguments permitted/needed/used */
}
cmdnames[] =
{ /* cmd name cmd code function arguments */
{"append", CMD_APPEND, cmd_append, FROM+ZERO+BANG },
#ifdef DEBUG
{"bug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL},
#endif
{"change", CMD_CHANGE, cmd_append, RANGE+BANG },
{"delete", CMD_DELETE, cmd_delete, RANGE+WORD1 },
{"edit", CMD_EDIT, cmd_edit, BANG+FILE1+PLUS },
{"file", CMD_FILE, cmd_file, NAMEDF },
{"global", CMD_GLOBAL, cmd_global, RANGE+BANG+EXTRA+DFLALL+NOBAR},
{"insert", CMD_INSERT, cmd_append, FROM+BANG },
{"join", CMD_INSERT, cmd_join, RANGE+BANG },
{"k", CMD_MARK, cmd_mark, FROM+WORD1 },
{"list", CMD_LIST, cmd_print, RANGE+NL },
{"move", CMD_MOVE, cmd_move, RANGE+EXTRA },
{"next", CMD_NEXT, cmd_next, BANG+NAMEDFS },
{"Next", CMD_PREVIOUS, cmd_next, BANG },
{"print", CMD_PRINT, cmd_print, RANGE+NL },
{"quit", CMD_QUIT, cmd_xit, BANG },
{"read", CMD_READ, cmd_read, FROM+ZERO+NAMEDF},
{"substitute", CMD_SUBSTITUTE, cmd_substitute, RANGE+EXTRA },
{"to", CMD_COPY, cmd_move, RANGE+EXTRA },
{"undo", CMD_UNDO, cmd_undo, NONE },
{"vglobal", CMD_VGLOBAL, cmd_global, RANGE+EXTRA+DFLALL+NOBAR},
{"write", CMD_WRITE, cmd_write, RANGE+BANG+FILE1+DFLALL},
{"xit", CMD_XIT, cmd_xit, BANG+NL },
{"yank", CMD_YANK, cmd_delete, RANGE+WORD1 },
{"!", CMD_BANG, cmd_shell, EXRCOK+RANGE+NAMEDFS+DFLNONE+NL+NOBAR},
{"#", CMD_NUMBER, cmd_print, RANGE+NL },
{"<", CMD_SHIFTL, cmd_shift, RANGE },
{">", CMD_SHIFTR, cmd_shift, RANGE },
{"=", CMD_EQUAL, cmd_file, RANGE },
{"&", CMD_SUBAGAIN, cmd_substitute, RANGE },
#ifndef NO_AT
{"@", CMD_AT, cmd_at, EXTRA },
#endif
#ifndef NO_ABBR
{"abbreviate", CMD_ABBR, cmd_map, EXRCOK+BANG+EXTRA},
#endif
{"args", CMD_ARGS, cmd_args, EXRCOK+NAMEDFS },
#ifndef NO_ERRLIST
{"cc", CMD_CC, cmd_make, BANG+FILES },
#endif
{"cd", CMD_CD, cmd_cd, EXRCOK+BANG+NAMEDF},
{"copy", CMD_COPY, cmd_move, RANGE+EXTRA },
#ifndef NO_DIGRAPH
{"digraph", CMD_DIGRAPH, cmd_digraph, EXRCOK+BANG+EXTRA},
#endif
#ifndef NO_ERRLIST
{"errlist", CMD_ERRLIST, cmd_errlist, BANG+NAMEDF },
#endif
{"ex", CMD_EDIT, cmd_edit, BANG+FILE1 },
{"mark", CMD_MARK, cmd_mark, FROM+WORD1 },
#ifndef NO_MKEXRC
{"mkexrc", CMD_MKEXRC, cmd_mkexrc, NAMEDF },
#endif
{"number", CMD_NUMBER, cmd_print, RANGE+NL },
{"put", CMD_PUT, cmd_put, FROM+ZERO+WORD1 },
{"set", CMD_SET, cmd_set, EXRCOK+EXTRA },
{"shell", CMD_SHELL, cmd_shell, NL },
{"source", CMD_SOURCE, cmd_source, EXRCOK+NAMEDF },
#ifdef SIGTSTP
{"stop", CMD_STOP, cmd_suspend, NONE },
#endif
{"tag", CMD_TAG, cmd_tag, BANG+WORD1 },
{"version", CMD_VERSION, cmd_version, EXRCOK+NONE },
{"visual", CMD_VISUAL, cmd_edit, BANG+NAMEDF },
{"wq", CMD_WQUIT, cmd_xit, NL },
#ifdef DEBUG
{"debug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL},
{"validate", CMD_VALIDATE, cmd_validate, BANG+NL },
#endif
{"chdir", CMD_CD, cmd_cd, EXRCOK+BANG+NAMEDF},
#ifndef NO_COLOR
{"color", CMD_COLOR, cmd_color, EXRCOK+EXTRA },
#endif
#ifndef NO_ERRLIST
{"make", CMD_MAKE, cmd_make, BANG+NAMEDFS },
#endif
{"map", CMD_MAP, cmd_map, EXRCOK+BANG+EXTRA},
{"previous", CMD_PREVIOUS, cmd_next, BANG },
{"rewind", CMD_REWIND, cmd_next, BANG },
#ifdef SIGTSTP
{"suspend", CMD_SUSPEND, cmd_suspend, NONE },
#endif
{"unmap", CMD_UNMAP, cmd_map, EXRCOK+BANG+EXTRA},
#ifndef NO_ABBR
{"unabbreviate",CMD_UNABBR, cmd_map, EXRCOK+WORD1 },
#endif
{(char *)0}
};
/* This function parses a search pattern - given a pointer to a / or ?,
* it replaces the ending / or ? with a \0, and returns a pointer to the
* stuff that came after the pattern.
*/
char *parseptrn(ptrn)
REG char *ptrn;
{
REG char *scan;
for (scan = ptrn + 1;
*scan && *scan != *ptrn;
scan++)
{
/* allow backslashed versions of / and ? in the pattern */
if (*scan == '\\' && scan[1] != '\0')
{
scan++;
}
}
if (*scan)
{
*scan++ = '\0';
}
return scan;
}
/* This function parses a line specifier for ex commands */
char *linespec(s, markptr)
REG char *s; /* start of the line specifier */
MARK *markptr; /* where to store the mark's value */
{
long num;
REG char *t;
/* parse each ;-delimited clause of this linespec */
do
{
/* skip an initial ';', if any */
if (*s == ';')
{
s++;
}
/* skip leading spaces */
while (isspace(*s))
{
s++;
}
/* dot means current position */
if (*s == '.')
{
s++;
*markptr = cursor;
}
/* '$' means the last line */
else if (*s == '$')
{
s++;
*markptr = MARK_LAST;
}
/* digit means an absolute line number */
else if (isdigit(*s))
{
for (num = 0; isdigit(*s); s++)
{
num = num * 10 + *s - '0';
}
*markptr = MARK_AT_LINE(num);
}
/* appostrophe means go to a set mark */
else if (*s == '\'')
{
s++;
*markptr = m_tomark(cursor, 1L, (int)*s);
s++;
}
/* slash means do a search */
else if (*s == '/' || *s == '?')
{
/* put a '\0' at the end of the search pattern */
t = parseptrn(s);
/* search for the pattern */
*markptr &= ~(BLKSIZE - 1);
if (*s == '/')
{
pfetch(markline(*markptr));
if (plen > 0)
*markptr += plen - 1;
*markptr = m_fsrch(*markptr, s);
}
else
{
*markptr = m_bsrch(*markptr, s);
}
/* adjust command string pointer */
s = t;
}
/* if linespec was faulty, quit now */
if (!*markptr)
{
return s;
}
/* maybe add an offset */
t = s;
if (*t == '-' || *t == '+')
{
s++;
for (num = 0; isdigit(*s); s++)
{
num = num * 10 + *s - '0';
}
if (num == 0)
{
num = 1;
}
*markptr = m_updnto(*markptr, num, *t);
}
} while (*s == ';' || *s == '+' || *s == '-');
/* protect against invalid line numbers */
num = markline(*markptr);
if (num < 1L || num > nlines)
{
msg("Invalid line number -- must be from 1 to %ld", nlines);
*markptr = MARK_UNSET;
}
return s;
}
/* This function reads an ex command and executes it. */
void ex()
{
char cmdbuf[150];
REG int cmdlen;
static long oldline;
significant = FALSE;
oldline = markline(cursor);
while (mode == MODE_EX)
{
/* read a line */
#ifdef CRUNCH
cmdlen = vgets(':', cmdbuf, sizeof(cmdbuf));
#else
cmdlen = vgets(*o_prompt ? ':' : '\0', cmdbuf, sizeof(cmdbuf));
#endif
if (cmdlen < 0)
{
return;
}
/* if empty line, assume ".+1" */
if (cmdlen == 0)
{
strcpy(cmdbuf, ".+1");
qaddch('\r');
clrtoeol();
}
else
{
addch('\n');
}
refresh();
/* parse & execute the command */
doexcmd(cmdbuf);
/* handle autoprint */
if (significant || markline(cursor) != oldline)
{
significant = FALSE;
oldline = markline(cursor);
if (*o_autoprint && mode == MODE_EX)
{
cmd_print(cursor, cursor, CMD_PRINT, FALSE, "");
}
}
}
}
void doexcmd(cmdbuf)
char *cmdbuf; /* string containing an ex command */
{
REG char *scan; /* used to scan thru cmdbuf */
MARK frommark; /* first linespec */
MARK tomark; /* second linespec */
REG int cmdlen; /* length of the command name given */
CMD cmd; /* what command is this? */
ARGT argt; /* argument types for this command */
short forceit; /* bang version of a command? */
REG int cmdidx; /* index of command */
REG char *build; /* used while copying filenames */
int iswild; /* boolean: filenames use wildcards? */
int isdfl; /* using default line ranges? */
int didsub; /* did we substitute file names for % or # */
/* ex commands can't be undone via the shift-U command */
U_line = 0L;
/* permit extra colons at the start of the line */
for (; *cmdbuf == ':'; cmdbuf++)
{
}
/* ignore command lines that start with a double-quote */
if (*cmdbuf == '"')
{
return;
}
scan = cmdbuf;
/* parse the line specifier */
if (nlines < 1)
{
/* no file, so don't allow addresses */
}
else if (*scan == '%')
{
/* '%' means all lines */
frommark = MARK_FIRST;
tomark = MARK_LAST;
scan++;
}
else if (*scan == '0')
{
frommark = tomark = MARK_UNSET;
scan++;
}
else
{
frommark = cursor;
scan = linespec(scan, &frommark);
tomark = frommark;
if (frommark && *scan == ',')
{
scan++;
scan = linespec(scan, &tomark);
}
if (!tomark)
{
/* faulty line spec -- fault already described */
return;
}
if (frommark > tomark)
{
msg("first address exceeds the second");
return;
}
}
isdfl = (scan == cmdbuf);
/* skip whitespace */
while (isspace(*scan))
{
scan++;
}
/* if no command, then just move the cursor to the mark */
if (!*scan)
{
if (tomark != MARK_UNSET)
cursor = tomark;
return;
}
/* figure out how long the command name is */
if (!isalpha(*scan))
{
cmdlen = 1;
}
else
{
for (cmdlen = 1;
isalpha(scan[cmdlen]);
cmdlen++)
{
}
}
/* lookup the command code */
for (cmdidx = 0;
cmdnames[cmdidx].name && strncmp(scan, cmdnames[cmdidx].name, cmdlen);
cmdidx++)
{
}
argt = cmdnames[cmdidx].argt;
cmd = cmdnames[cmdidx].code;
if (cmd == CMD_NULL)
{
msg("Unknown command \"%.*s\"", cmdlen, scan);
return;
}
/* !!! if the command doesn't have NOBAR set, then replace | with \0 */
/* if the command ended with a bang, set the forceit flag */
scan += cmdlen;
if ((argt & BANG) && *scan == '!')
{
scan++;
forceit = 1;
}
else
{
forceit = 0;
}
/* skip any more whitespace, to leave scan pointing to arguments */
while (isspace(*scan))
{
scan++;
}
/* a couple of special cases for filenames */
if (argt & XFILE)
{
/* if names were given, process them */
if (*scan)
{
for (build = tmpblk.c, iswild = didsub = FALSE; *scan; scan++)
{
switch (*scan)
{
case '\\':
if (scan[1] == '\\' || scan[1] == '%' || scan[1] == '#')
{
*build++ = *++scan;
}
else
{
*build++ = '\\';
}
break;
case '%':
if (!*origname)
{
msg("No filename to substitute for %%");
return;
}
strcpy(build, origname);
while (*build)
{
build++;
}
didsub = TRUE;
break;
case '#':
if (!*prevorig)
{
msg("No filename to substitute for #");
return;
}
strcpy(build, prevorig);
while (*build)
{
build++;
}
didsub = TRUE;
break;
case '*':
case '?':
#if !(MSDOS || TOS)
case '[':
case '`':
case '{': /* } */
case '$':
case '~':
#endif
*build++ = *scan;
iswild = TRUE;
break;
default:
*build++ = *scan;
}
}
*build = '\0';
if (cmd == CMD_BANG
|| cmd == CMD_READ && tmpblk.c[0] == '!'
|| cmd == CMD_WRITE && tmpblk.c[0] == '!')
{
if (didsub)
{
if (mode != MODE_EX)
{
addch('\n');
}
addstr(tmpblk.c);
addch('\n');
exrefresh();
}
}
else
{
if (iswild && tmpblk.c[0] != '>')
{
scan = wildcard(tmpblk.c);
}
}
}
else /* no names given, maybe assume origname */
{
if (!(argt & NODFL))
{
strcpy(tmpblk.c, origname);
}
else
{
*tmpblk.c = '\0';
}
}
scan = tmpblk.c;
}
/* bad arguments? */
if (!(argt & EXRCOK) && nlines < 1L)
{
msg("Can't use the \"%s\" command in a %s file", cmdnames[cmdidx].name, EXRC);
return;
}
if (!(argt & (ZERO | EXRCOK)) && frommark == MARK_UNSET)
{
msg("Can't use address 0 with \"%s\" command.", cmdnames[cmdidx].name);
return;
}
if (!(argt & FROM) && frommark != cursor && nlines >= 1L)
{
msg("Can't use address with \"%s\" command.", cmdnames[cmdidx].name);
return;
}
if (!(argt & TO) && tomark != frommark && nlines >= 1L)
{
msg("Can't use a range with \"%s\" command.", cmdnames[cmdidx].name);
return;
}
if (!(argt & EXTRA) && *scan)
{
msg("Extra characters after \"%s\" command.", cmdnames[cmdidx].name);
return;
}
if ((argt & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!')))
{
build = scan;
#ifndef CRUNCH
if ((argt & PLUS) && *build == '+')
{
while (*build && !isspace(*build))
{
build++;
}
while (*build && isspace(*build))
{
build++;
}
}
#endif /* not CRUNCH */
for (; *build; build++)
{
if (isspace(*build))
{
msg("Too many %s to \"%s\" command.",
(argt & XFILE) ? "filenames" : "arguments",
cmdnames[cmdidx].name);
return;
}
}
}
/* some commands have special default ranges */
if (isdfl && (argt & DFLALL))
{
frommark = MARK_FIRST;
tomark = MARK_LAST;
}
else if (isdfl && (argt & DFLNONE))
{
frommark = tomark = 0L;
}
/* write a newline if called from visual mode */
if ((argt & NL) && mode != MODE_EX && !exwrote)
{
addch('\n');
exrefresh();
}
/* act on the command */
(*cmdnames[cmdidx].fn)(frommark, tomark, cmd, forceit, scan);
}
/* This function executes EX commands from a file. It returns 1 normally, or
* 0 if the file could not be opened for reading.
*/
int doexrc(filename)
char *filename; /* name of a ".exrc" file */
{
int fd; /* file descriptor */
int len; /* length of the ".exrc" file */
/* !!! kludge: we use U_text as the buffer. This has the side-effect
* of interfering with the shift-U visual command. Disable shift-U.
*/
U_line = 0L;
/* open the file, read it, and close */
fd = open(filename, O_RDONLY);
if (fd < 0)
{
return 0;
}
len = tread(fd, U_text, BLKSIZE);
close(fd);
/* execute the string */
exstring(U_text, len, ctrl('V'));
return 1;
}
/* This function executes EX commands from a string. The commands may be
* separated by newlines or by | characters. It also handles quoting.
* Each individual command is limited to 132 bytes, but the total string
* may be longer.
*/
void exstring(buf, len, qchar)
char *buf; /* the commands to execute */
int len; /* the length of the string */
int qchar; /* the quote character -- ^V for file, or \ for kbd */
{
char single[133]; /* a single command */
char *src, *dest;
int i;
/* find & do each command */
for (src = buf; src < &buf[len]; src++)
{
/* Copy a single command into single[]. Convert any quoted |
* into a normal |, and stop at a newline or unquoted |.
*/
for (dest = single, i = 0;
i < 132 && src < &buf[len] && *src != '\n' && *src != '|';
src++, i++)
{
if (src[0] == qchar && src[1] == '|')
{
src++;
}
*dest++ = *src;
}
*dest = '\0';
/* do it */
doexcmd(single);
}
}

View file

@ -1,266 +0,0 @@
/* fmt.c */
/* usage: fmt [-width] [files]...
*
* Fmt rearrages text in order to make each line have roughly the
* same width. Indentation and word spacing is preserved.
*
* The default width is 72 characters, but you can override that via -width.
* If no files are given on the command line, then it reads stdin.
*/
#include <stdio.h>
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
int width = 72; /* the desired line width */
int isblank; /* is the current output line blank? */
int indent; /* width of the indentation */
char ind[512]; /* indentation text */
char word[1024]; /* word buffer */
/* This function displays a usage message and quits */
void usage()
{
fprintf(stderr, "usage: fmt [-width] [files]...\n");
exit(2);
}
/* This function outputs a single word. It takes care of spacing and the
* newlines within a paragraph.
*/
void putword()
{
int i; /* index into word[], or whatever */
int ww; /* width of the word */
int sw; /* width of spacing after word */
static int psw; /* space width of previous word */
static int tab; /* the width of text already written */
/* separate the word and its spacing */
for (ww = 0; word[ww] && word[ww] != ' '; ww++)
{
}
sw = strlen(word) - ww;
word[ww] = '\0';
/* if no spacing (that is, the word was at the end of the line) then
* assume 1 space unless the last char of the word was punctuation
*/
if (sw == 0)
{
sw = 1;
if (word[ww - 1] == '.' || word[ww - 1] == '?' || word[ww - 1] == '!')
sw = 2;
}
/* if this is the first word on the line... */
if (isblank)
{
/* output the indentation first */
fputs(ind, stdout);
tab = indent;
}
else /* text has already been written to this output line */
{
/* will the word fit on this line? */
if (psw + ww + tab <= width)
{
/* yes - so write the previous word's spacing */
for (i = 0; i < psw; i++)
{
putchar(' ');
}
tab += psw;
}
else
{
/* no, so write a newline and the indentation */
putchar('\n');
fputs(ind, stdout);
tab = indent;
}
}
/* write the word itself */
fputs(word, stdout);
tab += ww;
/* remember this word's spacing */
psw = sw;
/* this output line isn't blank anymore. */
isblank = FALSE;
}
/* This function reformats text. */
void fmt(in)
FILE *in; /* the name of the input stream */
{
int ch; /* character from input stream */
int prevch; /* the previous character in the loop */
int i; /* index into ind[] or word[] */
int inword; /* boolean: are we between indent & newline? */
/* for each character in the stream... */
for (indent = -1, isblank = TRUE, inword = FALSE, i = 0, prevch = '\n';
(ch = getc(in)) != EOF;
prevch = ch)
{
/* is this the end of a line? */
if (ch == '\n')
{
/* if end of last word in the input line */
if (inword)
{
/* if it really is a word */
if (i > 0)
{
/* output it */
word[i] = '\0';
putword();
}
}
else /* blank line in input */
{
/* finish the previous paragraph */
if (!isblank)
{
putchar('\n');
isblank = TRUE;
}
/* output a blank line */
putchar('\n');
}
/* continue with next input line... */
indent = -1;
i = 0;
inword = FALSE;
continue;
}
/* if we're expecting indentation now... */
if (indent < 0)
{
/* if this is part of the indentation... */
if (ch == ' ' || ch == '\t')
{
/* remember it */
ind[i++] = ch;
}
else /* end of indentation */
{
/* mark the end of the indentation string */
ind[i] = '\0';
/* calculate the width of the indentation */
for (i = indent = 0; ind[i]; i++)
{
if (ind[i] == '\t')
indent = (indent | 7) + 1;
else
indent++;
}
/* reset the word index */
i = 0;
/* reprocess that last character */
ungetc(ch, in);
}
/* continue in the for-loop */
continue;
}
/* if we get here, we're either in a word or in the space
* after a word.
*/
inword = TRUE;
/* is this the start of a new word? */
if (ch != ' ' && prevch == ' ')
{
/* yes! output the previous word */
word[i] = '\0';
putword();
/* reset `i' to the start of the word[] buffer */
i = 0;
}
word[i++] = ch;
}
/* if necessary, write a final newline */
if (!isblank)
{
putchar('\n');
isblank = TRUE;
}
}
int main(argc, argv)
int argc;
char **argv;
{
FILE *in; /* an input stream */
int error; /* if non-zero, then an error occurred */
int i;
/* handle the -width flag, if given */
if (argc > 1 && argv[1][0] == '-')
{
width = atoi(argv[1] + 1);
if (width <= 0)
{
usage();
}
argc--;
argv++;
}
/* if no filenames given, then process stdin */
if (argc == 1)
{
fmt(stdin);
}
else /* one or more filenames given */
{
for (error = 0, i = 1; i < argc; i++)
{
in = fopen(argv[i], "r");
if (!in)
{
perror(argv[i]);
error = 3;
}
else
{
fmt(in);
fclose(in);
}
}
}
/* exit, possibly indicating an error */
exit(error);
/*NOTREACHED*/
}

View file

@ -1,852 +0,0 @@
/* input.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the input() function, which implements vi's INPUT mode.
* It also contains the code that supports digraphs.
*/
#include "config.h"
#include "ctype.h"
#include "vi.h"
#ifndef NO_DIGRAPH
static struct _DIG
{
struct _DIG *next;
char key1;
char key2;
char dig;
char save;
} *digs;
char digraph(key1, key2)
char key1; /* the underlying character */
char key2; /* the second character */
{
int newkey;
REG struct _DIG *dp;
/* if digraphs are disabled, then just return the new char */
if (!*o_digraph)
{
return key2;
}
/* remember the new key, so we can return it if this isn't a digraph */
newkey = key2;
/* sort key1 and key2, so that their original order won't matter */
if (key1 > key2)
{
key2 = key1;
key1 = newkey;
}
/* 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 newkey;
}
/* else use the digraph key */
return dp->dig;
}
/* this function lists or defines digraphs */
void do_digraph(bang, extra)
int bang;
char extra[];
{
int dig;
REG struct _DIG *dp;
struct _DIG *prev;
static int user_defined = FALSE; /* 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 = TRUE;
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 >= COLS)
{
addch('\n');
exrefresh();
dig = 7;
}
listbuf[3] = dp->key1;
listbuf[4] = dp->key2;
listbuf[6] = dp->dig;
qaddstr(listbuf);
}
}
addch('\n');
exrefresh();
return;
}
/* make sure we have at least two characters */
if (!extra[1])
{
msg("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
msg("%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)
{
dp = (struct _DIG *)malloc(sizeof *dp);
if (!dp)
{
msg("Out of space in the digraph table");
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;
}
# ifndef NO_MKEXRC
void savedigs(fd)
int fd;
{
static char buf[] = "digraph! XX Y\n";
REG 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
#endif
/* This function allows the user to replace an existing (possibly zero-length)
* chunk of text with typed-in text. It returns the MARK of the last character
* that the user typed in.
*/
MARK input(from, to, when, above)
MARK from; /* where to start inserting text */
MARK to; /* extent of text to delete */
int when; /* either WHEN_VIINP or WHEN_VIREP */
int above; /* boolean: take indentation from lower line? */
{
char key[2]; /* key char followed by '\0' char */
char *build; /* used in building a newline+indent string */
char *scan; /* used while looking at the indent chars of a line */
MARK m; /* some place in the text */
#ifndef NO_EXTENSIONS
int quit = FALSE; /* boolean: are we exiting after this? */
int inchg; /* boolean: have we done a "beforedo()" yet? */
#endif
#ifdef DEBUG
/* if "from" and "to" are reversed, complain */
if (from > to)
{
msg("ERROR: input(%ld:%d, %ld:%d)",
markline(from), markidx(from),
markline(to), markidx(to));
return MARK_UNSET;
}
#endif
key[1] = 0;
/* if we're replacing text with new text, save the old stuff */
/* (Alas, there is no easy way to save text for replace mode) */
if (from != to)
{
cut(from, to);
}
/* if doing a dot command, then reuse the previous text */
if (doingdot)
{
ChangeText
{
/* delete the text that's there now */
if (from != to)
{
delete(from, to);
}
/* insert the previous text */
cutname('.');
cursor = paste(from, FALSE, TRUE) + 1L;
}
}
else /* interactive version */
{
/* assume that whoever called this already did a beforedo() */
#ifndef NO_EXTENSIONS
inchg = TRUE;
#endif
/* if doing a change within the line... */
if (from != to && markline(from) == markline(to))
{
/* mark the end of the text with a "$" */
change(to - 1, to, "$");
}
else
{
/* delete the old text right off */
if (from != to)
{
delete(from, to);
}
to = from;
}
/* handle autoindent of the first line, maybe */
cursor = from;
m = (above ? (cursor + BLKSIZE) : (cursor - BLKSIZE));
if (*o_autoindent && markidx(m) == 0
&& markline(m) >= 1L && markline(m) <= nlines)
{
/* Only autoindent blank lines. */
pfetch(markline(cursor));
if (plen == 0)
{
/* Okay, we really want to autoindent */
pfetch(markline(m));
for (scan = ptext, build = tmpblk.c;
*scan == ' ' || *scan == '\t';
)
{
*build++ = *scan++;
}
if (build > tmpblk.c)
{
*build = '\0';
add(cursor, tmpblk.c);
cursor += (build - tmpblk.c);
if (cursor > to)
to = cursor;
}
}
}
/* repeatedly add characters from the user */
for (;;)
{
/* Get a character */
redraw(cursor, TRUE);
#ifdef DEBUG2
msg("cursor=%ld.%d, to=%ld.%d",
markline(cursor), markidx(cursor),
markline(to), markidx(to));
#endif
#ifndef NO_ABBR
pfetch(markline(cursor));
build = ptext;
if (pline == markline(from))
build += markidx(from);
for (scan = ptext + markidx(cursor); --scan >= build && isalnum(*scan); )
{
}
scan++;
key[0] = getabkey(when, scan, (int)(ptext + markidx(cursor) - scan));
#else
key[0] = getkey(when);
#endif
#ifndef NO_VISIBLE
if (key[0] != '\0' && V_from != MARK_UNSET)
{
msg("Can't modify text during a selection");
beep();
continue;
}
#endif
#ifndef NO_EXTENSIONS
if (key[0] == ctrl('O'))
{
if (inchg)
{
if (cursor < to)
{
delete(cursor, to);
redraw(cursor, TRUE);
}
afterdo();
inchg = FALSE;
}
}
else if (key[0] != ctrl('['))
{
if (!inchg)
{
beforedo(FALSE);
inchg = TRUE;
}
}
#endif
#ifndef CRUNCH
/* if wrapmargin is set & we're past the
* warpmargin, then change the last whitespace
* characters on line into a newline
*/
if (*o_wrapmargin != 0)
{
pfetch(markline(cursor));
if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
{
build = tmpblk.c;
*build++ = '\n';
if (*o_autoindent)
{
/* figure out indent for next line */
for (scan = ptext; *scan == ' ' || *scan == '\t'; )
{
*build++ = *scan++;
}
}
*build = '\0';
scan = ptext + plen;
m = cursor & ~(BLKSIZE - 1);
while (ptext < scan)
{
scan--;
if (*scan != ' ' && *scan != '\t')
continue;
/*break up line, and we do autoindent if needed*/
change(m + (scan - ptext), m + (scan - ptext) + 1, tmpblk.c);
cursor = (cursor & ~(BLKSIZE - 1))
+ BLKSIZE
+ strlen(tmpblk.c) - 1
+ plen - (scan - ptext) - 1;
/*remove trailing spaces on previous line*/
pfetch(markline(m));
scan = ptext + plen;
while (ptext < scan)
{
scan--;
if (*scan != ' ' && *scan != '\t')
break;
}
delete(m + (scan-ptext) + 1, m + plen);
break;
}
}
}
#endif /* !CRUNCH */
/* process it */
switch (*key)
{
#ifndef NO_EXTENSIONS
case ctrl('O'): /* special movement mapped keys */
*key = getkey(0);
switch (*key)
{
case 'h': m = m_left(cursor, 0L); break;
case 'j':
case 'k': m = m_updnto(cursor, 0L, *key); break;
case 'l': m = cursor + 1; break;
case 'B':
case 'b': m = m_bword(cursor, 0L, *key); break;
case 'W':
case 'w': m = m_fword(cursor, 0L, *key, '\0'); break;
case '^': m = m_front(cursor, 0L); break;
case '$': m = m_rear(cursor, 0L); break;
case ctrl('B'):
case ctrl('F'):
m = m_scroll(cursor, 0L, *key); break;
case 'x':
#ifndef NO_VISIBLE
if (V_from)
beep();
else
#endif
ChangeText
{
m = v_xchar(cursor, 0L, 'x');
}
break;
case 'i': m = to = from = cursor;
when = WHEN_VIINP + WHEN_VIREP - when;
break;
case 'K':
pfetch(markline(cursor));
changes++; /* <- after this, we can alter ptext */
ptext[markidx(cursor)] = 0;
for (scan = ptext + markidx(cursor) - 1;
scan >= ptext && isalnum(*scan);
scan--)
{
}
scan++;
m = (*scan ? v_keyword(scan, cursor, 0L) : cursor);
break;
# ifndef NO_VISIBLE
case 'v':
case 'V':
if (V_from)
V_from = MARK_UNSET;
else
V_from = cursor;
m = from = to = cursor;
V_linemd = (*key == 'V');
break;
case 'd':
case 'y':
case '\\':
/* do nothing if unmarked */
if (!V_from)
{
msg("You must mark the text first");
beep();
break;
}
/* "from" must come before "to" */
if (V_from < cursor)
{
from = V_from;
to = cursor;
}
else
{
from = cursor;
to = V_from;
}
/* we don't need V_from anymore */
V_from = MARK_UNSET;
if (V_linemd)
{
/* adjust for line mode */
from &= ~(BLKSIZE - 1);
to |= (BLKSIZE - 1);
}
else
{
/* in character mode, we must
* worry about deleting the newline
* at the end of the last line
*/
pfetch(markline(to));
if (markidx(to) == plen)
to |= (BLKSIZE - 1);
}
to++;
switch (*key)
{
case 'y':
cut(from, to);
break;
case 'd':
ChangeText
{
cut(from, to);
delete(from, to);
}
cursor = from;
break;
#ifndef NO_POPUP
case '\\':
ChangeText
{
cursor = v_popup(from, to);
}
break;
#endif
}
m = from = to = cursor;
break;
case 'p':
case 'P':
V_from = MARK_UNSET;
ChangeText
{
m = from = to = cursor = paste(cursor, (*key == 'p'), FALSE);
}
break;
# endif /* !NO_VISIBLE */
default: m = MARK_UNSET;
}
/* adjust the moved cursor */
if (m != cursor)
{
m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0));
if (*key == '$' || (*key == 'l' && m <= cursor))
{
m++;
}
}
/* if the cursor is reasonable, use it */
if (m == MARK_UNSET)
{
beep();
}
else
{
from = to = cursor = m;
}
break;
case ctrl('Z'):
if (getkey(0) == ctrl('Z'))
{
quit = TRUE;
goto BreakBreak;
}
break;
#endif
case ctrl('['):
/* if last line contains only whitespace, then remove whitespace */
if (*o_autoindent)
{
pfetch(markline(cursor));
for (scan = ptext; isspace(*scan); scan++)
{
}
if (scan > ptext && !*scan)
{
cursor &= ~(BLKSIZE - 1L);
if (to < cursor + plen)
{
to = cursor + plen;
}
}
}
goto BreakBreak;
case ctrl('U'):
if (markline(cursor) == markline(from))
{
cursor = from;
}
else
{
cursor &= ~(BLKSIZE - 1);
}
break;
case ctrl('D'):
case ctrl('T'):
if (to > cursor)
{
delete(cursor, to);
}
mark[27] = cursor;
cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, "");
if (mark[27])
{
cursor = mark[27];
}
else
{
cursor = m_front(cursor, 0L);
}
to = cursor;
break;
case '\b':
if (cursor <= from)
{
beep();
}
else if (markidx(cursor) == 0)
{
cursor -= BLKSIZE;
pfetch(markline(cursor));
cursor += plen;
}
else
{
cursor--;
}
break;
case ctrl('W'):
m = m_bword(cursor, 1L, 'b');
if (markline(m) == markline(cursor) && m >= from)
{
cursor = m;
if (from > cursor)
{
from = cursor;
}
}
else
{
beep();
}
break;
case '\n':
#if OSK
case '\l':
#else
case '\r':
#endif
build = tmpblk.c;
*build++ = '\n';
if (*o_autoindent)
{
/* figure out indent for next line */
pfetch(markline(cursor));
for (scan = ptext; *scan == ' ' || *scan == '\t'; )
{
*build++ = *scan++;
}
/* remove indent from this line, if blank */
if ((scan - ptext) >= markidx(cursor) && plen > 0)
{
to = cursor &= ~(BLKSIZE - 1);
delete(cursor, cursor + plen);
}
}
*build = 0;
if (cursor >= to && when != WHEN_VIREP)
{
add(cursor, tmpblk.c);
}
else
{
change(cursor, to, tmpblk.c);
}
redraw(cursor, TRUE);
to = cursor = (cursor & ~(BLKSIZE - 1))
+ BLKSIZE
+ (int)(build - tmpblk.c) - 1;
break;
case ctrl('A'):
case ctrl('P'):
if (cursor < to)
{
delete(cursor, to);
}
if (*key == ctrl('A'))
{
cutname('.');
}
to = cursor = paste(cursor, FALSE, TRUE) + 1L;
break;
case ctrl('V'):
if (cursor >= to && when != WHEN_VIREP)
{
add(cursor, "^");
}
else
{
change(cursor, to, "^");
to = cursor + 1;
}
redraw(cursor, TRUE);
*key = getkey(0);
if (*key == '\n')
{
/* '\n' too hard to handle */
#if OSK
*key = '\l';
#else
*key = '\r';
#endif
}
change(cursor, cursor + 1, key);
cursor++;
if (cursor > to)
{
to = cursor;
}
break;
case ctrl('L'):
case ctrl('R'):
redraw(MARK_UNSET, FALSE);
break;
default:
if (cursor >= to && when != WHEN_VIREP)
{
add(cursor, key);
cursor++;
to = cursor;
}
else
{
pfetch(markline(cursor));
if (markidx(cursor) == plen)
{
add(cursor, key);
}
else
{
#ifndef NO_DIGRAPH
*key = digraph(ptext[markidx(cursor)], *key);
#endif
change(cursor, cursor + 1, key);
}
cursor++;
}
#ifndef NO_SHOWMATCH
/* show matching "({[" if necessary */
if (*o_showmatch && strchr(")}]", *key))
{
redraw(cursor, TRUE);
m = m_match(cursor - 1, 0L);
if (markline(m) >= topline
&& markline(m) <= botline)
{
redraw(m, TRUE);
refresh();
sleep(1);
}
}
#endif
} /* end switch(*key) */
} /* end for(;;) */
BreakBreak:;
/* delete any excess characters */
if (cursor < to)
{
#ifndef NO_EXTENSIONS
/* if we aren't in the middle of a change, start one! */
if (!inchg)
{
beforedo(FALSE);
inchg = TRUE;
}
#endif
delete(cursor, to);
}
} /* end if doingdot else */
/* put the new text into a cut buffer for possible reuse */
if (!doingdot)
{
blksync();
cutname('.');
cut(from, cursor);
}
/* move to last char that we inputted, unless it was newline */
if (markidx(cursor) != 0)
{
cursor--;
}
redraw(cursor, FALSE);
#ifndef NO_EXTENSIONS
if (quit)
{
/* if this is a nested "do", then cut it short */
abortdo();
/* exit, unless we can't write out the file */
cursor = v_xit(cursor, 0L, 'Z');
}
#endif
rptlines = 0L;
return cursor;
}

View file

@ -1,512 +0,0 @@
/* main.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the main() function of vi */
/* HACK! bcc needs to disable use of precompiled headers for this file,
or else command line args will not be passed to elvis */
#if __BORLANDC__
#include "borland.h"
#endif
#include "config.h"
#include <setjmp.h>
#include "vi.h"
extern trapint(); /* defined below */
extern char *getenv();
jmp_buf jmpenv;
#ifndef NO_DIGRAPH
static init_digraphs();
#endif
/*---------------------------------------------------------------------*/
#if AMIGA
# include "amiwild.c"
main (argc, argv)
#else
# if VMS
# include "vmswild.c"
main (argc, argv)
# else
int main(argc, argv)
# endif
#endif
int argc;
char *argv[];
{
int i;
char *cmd = (char *)0;
char *err = (char *)0;
char *str;
char *tag = (char *)0;
/* set mode to MODE_VI or MODE_EX depending on program name */
switch (argv[0][strlen(argv[0]) - 1])
{
case 'x': /* "ex" */
mode = MODE_EX;
break;
case 'w': /* "view" */
mode = MODE_VI;
*o_readonly = TRUE;
break;
#ifndef NO_EXTENSIONS
case 't': /* "edit" or "input" */
mode = MODE_VI;
*o_inputmode = TRUE;
break;
#endif
default: /* "vi" or "elvis" */
mode = MODE_VI;
}
#ifndef DEBUG
# ifdef SIGQUIT
/* normally, we ignore SIGQUIT. SIGINT is trapped later */
signal(SIGQUIT, SIG_IGN);
# endif
#endif
/* temporarily ignore SIGINT */
signal(SIGINT, SIG_IGN);
/* start curses */
initscr();
cbreak();
noecho();
scrollok(stdscr, TRUE);
/* arrange for deadly signals to be caught */
# ifdef SIGHUP
signal(SIGHUP, (void(*)()) deathtrap);
# endif
# ifndef DEBUG
# ifdef SIGILL
signal(SIGILL, (void(*)()) deathtrap);
# endif
# ifdef SIGBUS
signal(SIGBUS, (void(*)()) deathtrap);
# endif
# ifdef SIGSEGV
signal(SIGSEGV, (void(*)()) deathtrap);
# endif
# ifdef SIGSYS
signal(SIGSYS, (void(*)()) deathtrap);
# endif
# endif /* !DEBUG */
# ifdef SIGPIPE
signal(SIGPIPE, (void(*)()) deathtrap);
# endif
# ifdef SIGTERM
signal(SIGTERM, (void(*)()) deathtrap);
# endif
# ifdef SIGUSR1
signal(SIGUSR1, (void(*)()) deathtrap);
# endif
# ifdef SIGUSR2
signal(SIGUSR2, (void(*)()) deathtrap);
# endif
/* initialize the options - must be done after initscr(), so that
* we can alter LINES and COLS if necessary.
*/
initopts();
/* map the arrow keys. The KU,KD,KL,and KR variables correspond to
* the :ku=: (etc.) termcap capabilities. The variables are defined
* as part of the curses package.
*/
if (has_KU) mapkey(has_KU, "k", WHEN_VICMD|WHEN_INMV, "<Up>");
if (has_KD) mapkey(has_KD, "j", WHEN_VICMD|WHEN_INMV, "<Down>");
if (has_KL) mapkey(has_KL, "h", WHEN_VICMD|WHEN_INMV, "<Left>");
if (has_KR) mapkey(has_KR, "l", WHEN_VICMD|WHEN_INMV, "<Right>");
if (has_HM) mapkey(has_HM, "^", WHEN_VICMD|WHEN_INMV, "<Home>");
if (has_EN) mapkey(has_EN, "$", WHEN_VICMD|WHEN_INMV, "<End>");
if (has_PU) mapkey(has_PU, "\002", WHEN_VICMD|WHEN_INMV, "<PageUp>");
if (has_PD) mapkey(has_PD, "\006", WHEN_VICMD|WHEN_INMV, "<PageDn>");
if (has_KI) mapkey(has_KI, "i", WHEN_VICMD|WHEN_INMV, "<Insert>");
#if MSDOS
# if RAINBOW
if (!strcmp("rainbow", o_term))
{
mapkey("\033[1~", "/", WHEN_VICMD, "<Find>");
mapkey("\033[3~", "x", WHEN_VICMD|WHEN_INMV, "<Remove>");
mapkey("\033[4~", "v", WHEN_VICMD|WHEN_INMV, "<Select>");
mapkey("\033[17~", ":sh\n", WHEN_VICMD, "<Intrpt>");
mapkey("\033[19~", ":q\n", WHEN_VICMD, "<Cancel>");
mapkey("\033[21~", "ZZ", WHEN_VICMD, "<Exit>");
mapkey("\033[26~", "V", WHEN_VICMD|WHEN_INMV, "<AddlOp>");
mapkey("\033[28~", "\\", WHEN_VICMD|WHEN_INMV, "<Help>");
mapkey("\033[29~", "K", WHEN_VICMD|WHEN_INMV, "<Do>");
}
else
# endif /* RAINBOW */
{
mapkey("#S", "x", WHEN_VICMD|WHEN_INMV, "<Delete>");
mapkey("#s", "B", WHEN_VICMD|WHEN_INMV, "^<Left>");
mapkey("#t", "W", WHEN_VICMD|WHEN_INMV, "^<Right>");
}
#else /* not MSDOS */
# if COHERENT
mapkey("\033[P", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
# else
#if AMIGA
mapkey("\233?~", "\\", WHEN_VICMD|WHEN_INMV, "<Help>");
#endif
if (ERASEKEY != '\177')
{
mapkey("\177", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
}
# endif
#endif
#ifndef NO_DIGRAPH
init_digraphs();
#endif /* NO_DIGRAPH */
/* process any flags */
for (i = 1; i < argc && *argv[i] == '-'; i++)
{
switch (argv[i][1])
{
case 'R': /* readonly */
*o_readonly = TRUE;
break;
case 'L':
case 'r': /* recover */
msg("Use the `elvrec` program to recover lost files");
endmsgs();
refresh();
endwin();
exit(0);
break;
case 't': /* tag */
if (argv[i][2])
{
tag = argv[i] + 2;
}
else
{
tag = argv[++i];
}
break;
case 'v': /* vi mode */
mode = MODE_VI;
break;
case 'e': /* ex mode */
mode = MODE_EX;
break;
#ifndef NO_EXTENSIONS
case 'i': /* input mode */
*o_inputmode = TRUE;
break;
#endif
#ifndef NO_ERRLIST
case 'm': /* use "errlist" as the errlist */
if (argv[i][2])
{
err = argv[i] + 2;
}
else if (i + 1 < argc)
{
err = argv[++i];
}
else
{
err = "";
}
break;
#endif
#ifndef CRUNCH
case 'c': /* run the following command, later */
if (argv[i][2])
{
cmd = argv[i] + 2;
}
else
{
cmd = argv[++i];
}
break;
case 'w': /* set the window size */
if (argv[i][2])
{
*o_window = atoi(argv[i] + 2);
wset = TRUE;
}
else
{
*o_window = atoi(argv[++i]);
wset = TRUE;
}
break;
#endif
default:
msg("Ignoring unknown flag \"%s\"", argv[i]);
}
}
/* if we were given an initial ex command, save it... */
if (i < argc && *argv[i] == '+')
{
if (argv[i][1])
{
cmd = argv[i++] + 1;
}
else
{
cmd = "$"; /* "vi + file" means start at EOF */
i++;
}
}
/* the remaining args are file names. */
if (i < argc)
{
strcpy(args, argv[i]);
while (++i < argc && strlen(args) + 1 + strlen(argv[i]) < sizeof args)
{
strcat(args, " ");
strcat(args, argv[i]);
}
#if MSDOS || TOS
/* expand wildcard characters, if necessary */
if (strchr(args, '*') || strchr(args, '?'))
{
strcpy(args, wildcard(args));
}
#endif
strcpy(tmpblk.c, args);
cmd_args(MARK_UNSET, MARK_UNSET, CMD_ARGS, TRUE, tmpblk.c);
}
else
{
/* empty args list */
args[0] = '\0';
nargs = 1;
argno = -1;
}
/* perform the .exrc files and EXINIT environment variable */
#ifdef SYSEXRC
doexrc(SYSEXRC);
#endif
#ifdef HMEXRC
str = getenv("HOME");
if (str && *str)
{
strcpy(tmpblk.c, str);
str = tmpblk.c + strlen(tmpblk.c);
#if !VMS
# if AMIGA /* Don't SLASH a device. "Elvis:.exrc" */
if (str[-1] != COLON && str[-1] != SLASH)
# else
if (str[-1] != SLASH)
# endif
{
*str++ = SLASH;
}
#endif
strcpy(str, HMEXRC);
doexrc(tmpblk.c);
}
#endif
#ifndef CRUNCH
if (*o_exrc)
#endif
{
doexrc(EXRC);
}
#ifdef EXINIT
str = getenv(EXINIT);
if (str)
{
exstring(str, strlen(str), ctrl('V'));
}
#endif
/* search for a tag (or an error) now, if desired */
blkinit();
if (tag)
{
cmd_tag(MARK_FIRST, MARK_FIRST, CMD_TAG, 0, tag);
}
#ifndef NO_ERRLIST
else if (err)
{
cmd_errlist(MARK_FIRST, MARK_FIRST, CMD_ERRLIST, 0, err);
}
#endif
/* if no tag/err, or tag failed, then start with first arg */
if (tmpfd < 0)
{
/* start with first arg */
cmd_next(MARK_UNSET, MARK_UNSET, CMD_NEXT, FALSE, "");
/* pretend to do something, just to force a recoverable
* version of the file out to disk
*/
ChangeText
{
}
clrflag(file, MODIFIED);
}
/* now we do the immediate ex command that we noticed before */
if (cmd)
{
doexcmd(cmd);
}
/* repeatedly call ex() or vi() (depending on the mode) until the
* mode is set to MODE_QUIT
*/
while (mode != MODE_QUIT)
{
if (setjmp(jmpenv))
{
/* Maybe we just aborted a change? */
abortdo();
}
signal(SIGINT, (void(*)()) trapint);
switch (mode)
{
case MODE_VI:
vi();
break;
case MODE_EX:
ex();
break;
#ifdef DEBUG
default:
msg("mode = %d?", mode);
mode = MODE_QUIT;
#endif
}
}
/* free up the cut buffers */
cutend();
/* end curses */
#ifndef NO_CURSORSHAPE
if (has_CQ)
do_CQ();
#endif
endmsgs();
move(LINES - 1, 0);
clrtoeol();
refresh();
endwin();
exit(0);
/*NOTREACHED*/
}
/*ARGSUSED*/
int trapint(signo)
int signo;
{
beep();
resume_curses(FALSE);
abortdo();
#if OSK
sigmask(-1);
#endif
signal(signo, (void (*)())trapint);
doingglobal = FALSE;
longjmp(jmpenv, 1);
return 0;
}
#ifndef NO_DIGRAPH
/* This stuff us used to build the default digraphs table. */
static 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 */
""
};
static init_digraphs()
{
int i;
for (i = 0; *digtable[i]; i++)
{
do_digraph(FALSE, digtable[i]);
}
do_digraph(FALSE, (char *)0);
return 0;
}
#endif /* NO_DIGRAPH */

View file

@ -1,103 +0,0 @@
/* misc.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains functions which didn't seem happy anywhere else */
#include "config.h"
#include "vi.h"
/* find a particular line & return a pointer to a copy of its text */
char *fetchline(line)
long line; /* line number of the line to fetch */
{
int i;
REG char *scan; /* used to search for the line in a BLK */
long l; /* line number counter */
static BLK buf; /* holds ONLY the selected line (as string) */
REG char *cpy; /* used while copying the line */
static long nextline; /* } These four variables are used */
static long chglevel; /* } to implement a shortcut when */
static char *nextscan; /* } consecutive lines are fetched */
static long nextlnum; /* } */
/* can we do a shortcut? */
if (changes == chglevel && line == nextline)
{
scan = nextscan;
}
else
{
/* scan lnum[] to determine which block its in */
for (i = 1; line > lnum[i]; i++)
{
}
nextlnum = lnum[i];
/* fetch text of the block containing that line */
scan = blkget(i)->c;
/* find the line in the block */
for (l = lnum[i - 1]; ++l < line; )
{
while (*scan++ != '\n')
{
}
}
}
/* copy it into a block by itself, with no newline */
for (cpy = buf.c; *scan != '\n'; )
{
*cpy++ = *scan++;
}
*cpy = '\0';
/* maybe speed up the next call to fetchline() ? */
if (line < nextlnum)
{
nextline = line + 1;
chglevel = changes;
nextscan = scan + 1;
}
else
{
nextline = 0;
}
/* Calls to fetchline() interfere with calls to pfetch(). Make sure
* that pfetch() resets itself on its next invocation.
*/
pchgs = 0L;
/* Return a pointer to the line's text */
return buf.c;
}
/* error message from the regexp code */
void regerror(txt)
char *txt; /* an error message */
{
msg("RE error: %s", txt);
}
/* This function is equivelent to the pfetch() macro */
void pfetch(l)
long l; /* line number of line to fetch */
{
if(l != pline || changes != pchgs)
{
pline = (l);
ptext = fetchline(pline);
plen = strlen(ptext);
pchgs = changes;
}
}

View file

@ -1,474 +0,0 @@
/* modify.c */
/* This file contains the low-level file modification functions:
* delete(frommark, tomark) - removes line or portions of lines
* add(frommark, text) - inserts new text
* change(frommark, tomark, text) - delete, then add
*/
#include "config.h"
#include "vi.h"
#ifdef DEBUG2
# include <stdio.h>
static FILE *dbg;
/*VARARGS1*/
debout(msg, arg1, arg2, arg3, arg4, arg5)
char *msg, *arg1, *arg2, *arg3, *arg4, *arg5;
{
if (!dbg)
{
dbg = fopen("debug.out", "w");
if (!dbg)
return;
setbuf(dbg, (FILE *)0);
}
fprintf(dbg, msg, arg1, arg2, arg3, arg4, arg5);
}
#endif /* DEBUG2 */
/* delete a range of text from the file */
void delete(frommark, tomark)
MARK frommark; /* first char to be deleted */
MARK tomark; /* AFTER last char to be deleted */
{
int i; /* used to move thru logical blocks */
REG char *scan; /* used to scan thru text of the blk */
REG char *cpy; /* used when copying chars */
BLK *blk; /* a text block */
long l; /* a line number */
MARK m; /* a traveling version of frommark */
#ifdef DEBUG2
debout("delete(%ld.%d, %ld.%d)\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark));
#endif
/* if not deleting anything, quit now */
if (frommark == tomark)
{
return;
}
/* This is a change */
changes++;
significant = TRUE;
/* supply clues to the redraw module */
redrawrange(markline(frommark), markline(tomark), markline(frommark));
/* adjust marks 'a through 'z and '' as needed */
l = markline(tomark);
for (i = 0; i < NMARKS; i++)
{
if (mark[i] < frommark)
{
continue;
}
else if (mark[i] < tomark)
{
mark[i] = MARK_UNSET;
}
else if (markline(mark[i]) == l)
{
if (markline(frommark) == l)
{
mark[i] -= markidx(tomark) - markidx(frommark);
}
else
{
mark[i] -= markidx(tomark);
}
}
else
{
mark[i] -= MARK_AT_LINE(l - markline(frommark));
}
}
/* Reporting... */
if (markidx(frommark) == 0 && markidx(tomark) == 0)
{
rptlines = markline(tomark) - markline(frommark);
rptlabel = "deleted";
}
/* find the block containing frommark */
l = markline(frommark);
for (i = 1; lnum[i] < l; i++)
{
}
/* process each affected block... */
for (m = frommark;
m < tomark && lnum[i] < INFINITY;
m = MARK_AT_LINE(lnum[i - 1] + 1))
{
/* fetch the block */
blk = blkget(i);
/* find the mark in the block */
scan = blk->c;
for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--)
{
while (*scan++ != '\n')
{
}
}
scan += markidx(m);
/* figure out where the changes to this block end */
if (markline(tomark) > lnum[i])
{
cpy = blk->c + BLKSIZE;
}
else if (markline(tomark) == markline(m))
{
cpy = scan - markidx(m) + markidx(tomark);
}
else
{
cpy = scan;
for (l = markline(tomark) - markline(m);
l > 0;
l--)
{
while (*cpy++ != '\n')
{
}
}
cpy += markidx(tomark);
}
/* delete the stuff by moving chars within this block */
while (cpy < blk->c + BLKSIZE)
{
*scan++ = *cpy++;
}
while (scan < blk->c + BLKSIZE)
{
*scan++ = '\0';
}
/* adjust tomark to allow for lines deleted from this block */
tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m));
/* if this block isn't empty now, then advance i */
if (*blk->c)
{
i++;
}
/* the buffer has changed. Update hdr and lnum. */
blkdirty(blk);
}
/* must have at least 1 line */
if (nlines == 0)
{
blk = blkadd(1);
blk->c[0] = '\n';
blkdirty(blk);
cursor = MARK_FIRST;
}
}
/* add some text at a specific place in the file */
void add(atmark, newtext)
MARK atmark; /* where to insert the new text */
char *newtext; /* NUL-terminated string to insert */
{
REG char *scan; /* used to move through string */
REG char *build; /* used while copying chars */
int addlines; /* number of lines we're adding */
int lastpart; /* size of last partial line */
BLK *blk; /* the block to be modified */
int blkno; /* the logical block# of (*blk) */
REG char *newptr; /* where new text starts in blk */
BLK buf; /* holds chars from orig blk */
BLK linebuf; /* holds part of line that didn't fit */
BLK *following; /* the BLK following the last BLK */
int i;
long l;
#ifdef DEBUG2
debout("add(%ld.%d, \"%s\")\n", markline(atmark), markidx(atmark), newtext);
#endif
#ifdef lint
buf.c[0] = 0;
#endif
/* if not adding anything, return now */
if (!*newtext)
{
return;
}
/* This is a change */
changes++;
significant = TRUE;
/* count the number of lines in the new text */
for (scan = newtext, lastpart = addlines = 0; *scan; )
{
if (*scan++ == '\n')
{
addlines++;
lastpart = 0;
}
else
{
lastpart++;
}
}
/* Reporting... */
if (lastpart == 0 && markidx(atmark) == 0)
{
rptlines = addlines;
rptlabel = "added";
}
/* extract the line# from atmark */
l = markline(atmark);
/* supply clues to the redraw module */
if ((markidx(atmark) == 0 && lastpart == 0) || addlines == 0)
{
redrawrange(l, l, l + addlines);
}
else
{
/* make sure the last line gets redrawn -- it was
* split, so its appearance has changed
*/
redrawrange(l, l + 1L, l + addlines + 1L);
}
/* adjust marks 'a through 'z and '' as needed */
for (i = 0; i < NMARKS; i++)
{
if (mark[i] < atmark)
{
/* earlier line, or earlier in same line: no change */
continue;
}
else if (markline(mark[i]) > l)
{
/* later line: move down a whole number of lines */
mark[i] += MARK_AT_LINE(addlines);
}
else
{
/* later in same line */
if (addlines > 0)
{
/* multi-line add, which split this line:
* move down, and possibly left or right,
* depending on where the split was and how
* much text was inserted after the last \n
*/
mark[i] += MARK_AT_LINE(addlines) + lastpart - markidx(atmark);
}
else
{
/* totally within this line: move right */
mark[i] += lastpart;
}
}
}
/* get the block to be modified */
for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++)
{
}
blk = blkget(blkno);
buf = *blk;
/* figure out where the new text starts */
for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1;
l > 0;
l--)
{
while (*newptr++ != '\n')
{
}
}
newptr += markidx(atmark);
/* keep start of old block */
build = blk->c + (int)(newptr - buf.c);
/* fill this block (or blocks) from the newtext string */
while (*newtext)
{
while (*newtext && build < blk->c + BLKSIZE - 1)
{
*build++ = *newtext++;
}
if (*newtext)
{
/* save the excess */
for (scan = linebuf.c + BLKSIZE;
build > blk->c && build[-1] != '\n';
)
{
*--scan = *--build;
}
/* write the block */
while (build < blk->c + BLKSIZE)
{
*build++ = '\0';
}
blkdirty(blk);
/* add another block */
blkno++;
blk = blkadd(blkno);
/* copy in the excess from last time */
for (build = blk->c; scan < linebuf.c + BLKSIZE; )
{
*build++ = *scan++;
}
}
}
/* fill this block(s) from remainder of orig block */
while (newptr < buf.c + BLKSIZE && *newptr)
{
while (newptr < buf.c + BLKSIZE
&& *newptr
&& build < blk->c + BLKSIZE - 1)
{
*build++ = *newptr++;
}
if (newptr < buf.c + BLKSIZE && *newptr)
{
/* save the excess */
for (scan = linebuf.c + BLKSIZE;
build > blk->c && build[-1] != '\n';
)
{
*--scan = *--build;
}
/* write the block */
while (build < blk->c + BLKSIZE)
{
*build++ = '\0';
}
blkdirty(blk);
/* add another block */
blkno++;
blk = blkadd(blkno);
/* copy in the excess from last time */
for (build = blk->c; scan < linebuf.c + BLKSIZE; )
{
*build++ = *scan++;
}
}
}
/* see if we can combine our last block with the following block */
if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6))
{
/* hey, we probably can! Get the following block & see... */
following = blkget(blkno + 1);
if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1)
{
/* we can! Copy text from following to blk */
for (scan = following->c; *scan; )
{
*build++ = *scan++;
}
while (build < blk->c + BLKSIZE)
{
*build++ = '\0';
}
blkdirty(blk);
/* pretend the following was the last blk */
blk = following;
build = blk->c;
}
}
/* that last block is dirty by now */
while (build < blk->c + BLKSIZE)
{
*build++ = '\0';
}
blkdirty(blk);
}
/* change the text of a file */
void change(frommark, tomark, newtext)
MARK frommark, tomark;
char *newtext;
{
int i;
long l;
char *text;
BLK *blk;
#ifdef DEBUG2
debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark), newtext);
#endif
/* optimize for single-character replacement */
if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n')
{
/* find the block containing frommark */
l = markline(frommark);
for (i = 1; lnum[i] < l; i++)
{
}
/* get the block */
blk = blkget(i);
/* find the line within the block */
for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++)
{
if (*text == '\n')
{
i--;
}
}
/* replace the char */
text += markidx(frommark);
if (*text == newtext[0])
{
/* no change was needed - same char */
return;
}
else if (*text != '\n')
{
/* This is a change */
changes++;
significant = TRUE;
ChangeText
{
*text = newtext[0];
blkdirty(blk);
}
redrawrange(markline(frommark), markline(tomark), markline(frommark));
return;
}
/* else it is a complex change involving newline... */
}
/* couldn't optimize, so do delete & add */
ChangeText
{
delete(frommark, tomark);
add(frommark, newtext);
rptlabel = "changed";
}
}

View file

@ -1,585 +0,0 @@
/* move1.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains most movement functions */
#include "config.h"
#include "vi.h"
#include "ctype.h"
MARK m_updnto(m, cnt, cmd)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
char cmd; /* the command character */
{
DEFAULT(cmd == 'G' ? nlines : 1L);
/* move up or down 'cnt' lines */
switch (cmd)
{
case ctrl('P'):
case '-':
case 'k':
m -= MARK_AT_LINE(cnt);
break;
case 'G':
if (cnt < 1L || cnt > nlines)
{
msg("Only %ld lines", nlines);
return MARK_UNSET;
}
m = MARK_AT_LINE(cnt);
break;
case '_':
cnt--;
/* fall through... */
default:
m += MARK_AT_LINE(cnt);
}
/* if that left us screwed up, then fail */
if (m < MARK_FIRST || markline(m) > nlines)
{
return MARK_UNSET;
}
return m;
}
/*ARGSUSED*/
MARK m_right(m, cnt, key, prevkey)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
int key; /* movement keystroke */
int prevkey;/* operator keystroke, or 0 if none */
{
int idx; /* index of the new cursor position */
DEFAULT(1);
/* If used with an operator, then move 1 less character, since the 'l'
* command includes the character that it moves onto.
*/
if (prevkey != '\0')
{
cnt--;
}
/* move to right, if that's OK */
pfetch(markline(m));
idx = markidx(m) + cnt;
if (idx < plen)
{
m += cnt;
}
else
{
return MARK_UNSET;
}
return m;
}
/*ARGSUSED*/
MARK m_left(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
DEFAULT(1);
/* move to the left, if that's OK */
if (markidx(m) >= cnt)
{
m -= cnt;
}
else
{
return MARK_UNSET;
}
return m;
}
/*ARGSUSED*/
MARK m_tocol(m, cnt, cmd)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
int cmd; /* either ctrl('X') or '|' */
{
char *text; /* text of the line */
int col; /* column number */
int idx; /* index into the line */
/* if doing ^X, then adjust for sideways scrolling */
if (cmd == ctrl('X'))
{
DEFAULT(*o_columns & 0xff);
cnt += leftcol;
}
else
{
DEFAULT(1);
}
/* internally, columns are numbered 0..COLS-1, not 1..COLS */
cnt--;
/* if 0, that's easy */
if (cnt == 0)
{
m &= ~(BLKSIZE - 1);
return m;
}
/* find that column within the line */
pfetch(markline(m));
text = ptext;
for (col = idx = 0; col < cnt && *text; text++, idx++)
{
if (*text == '\t' && !*o_list)
{
col += *o_tabstop;
col -= col % *o_tabstop;
}
else if (UCHAR(*text) < ' ' || *text == '\177')
{
col += 2;
}
#ifndef NO_CHARATTR
else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
{
text += 2; /* plus one more as part of for loop */
}
#endif
else
{
col++;
}
}
if (!*text)
{
/* the desired column was past the end of the line, so
* act like the user pressed "$" instead.
*/
return m | (BLKSIZE - 1);
}
else
{
m = (m & ~(BLKSIZE - 1)) + idx;
}
return m;
}
/*ARGSUSED*/
MARK m_front(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument (ignored) */
{
char *scan;
/* move to the first non-whitespace character */
pfetch(markline(m));
scan = ptext;
m &= ~(BLKSIZE - 1);
while (*scan == ' ' || *scan == '\t')
{
scan++;
m++;
}
return m;
}
/*ARGSUSED*/
MARK m_rear(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument (ignored) */
{
/* Try to move *EXTREMELY* far to the right. It is fervently hoped
* that other code will convert this to a more reasonable MARK before
* anything tries to actually use it. (See adjmove() in vi.c)
*/
return m | (BLKSIZE - 1);
}
#ifndef NO_SENTENCE
static int isperiod(ptr)
char *ptr; /* pointer to possible sentence-ender */
{
/* if not '.', '?', or '!', then it isn't a sentence ender */
if (*ptr != '.' && *ptr != '?' && *ptr != '!')
{
return FALSE;
}
/* skip any intervening ')', ']', or '"' characters */
do
{
ptr++;
} while (*ptr == ')' || *ptr == ']' || *ptr == '"');
/* do we have two spaces or EOL? */
if (!*ptr || ptr[0] == ' ' && ptr[1] == ' ')
{
return TRUE;
}
return FALSE;
}
/*ARGSUSED*/
MARK m_sentence(m, cnt, cmd)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
int cmd; /* either '(' or ')' */
{
REG char *text;
REG long l;
DEFAULT(1);
/* If '(' command, then move back one word, so that if we hit '(' at
* the start of a sentence we don't simply stop at the end of the
* previous sentence and bounce back to the start of this one again.
*/
if (cmd == '(')
{
m = m_bword(m, 1L, 'b');
if (!m)
{
return m;
}
}
/* get the current line */
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
/* for each requested sentence... */
while (cnt-- > 0)
{
/* search forward for one of [.?!] followed by spaces or EOL */
do
{
if (cmd == ')')
{
/* move forward, wrap at end of line */
if (!text[0])
{
if (l >= nlines)
{
return MARK_UNSET;
}
l++;
pfetch(l);
text = ptext;
}
else
{
text++;
}
}
else
{
/* move backward, wrap at beginning of line */
if (text == ptext)
{
do
{
if (l <= 1)
{
return MARK_FIRST;
}
l--;
pfetch(l);
} while (!*ptext);
text = ptext + plen - 1;
}
else
{
text--;
}
}
} while (!isperiod(text));
}
/* construct a mark for this location */
m = buildmark(text);
/* move forward to the first word of the next sentence */
m = m_fword(m, 1L, 'w', '\0');
return m;
}
#endif
MARK m_paragraph(m, cnt, cmd)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
int cmd; /* either '{' or '}' */
{
char *text; /* text of the current line */
char *pscn; /* used to scan thru value of "paragraphs" option */
long l, ol; /* current line number, original line number */
int dir; /* -1 if we're moving up, or 1 if down */
char col0; /* character to expect in column 0 */
#ifndef NO_SENTENCE
# define SENTENCE(x) (x)
char *list; /* either o_sections or o_paragraph */
#else
# define SENTENCE(x)
#endif
DEFAULT(1);
/* set the direction, based on the command */
switch (cmd)
{
case '{':
dir = -1;
col0 = '\0';
SENTENCE(list = o_paragraphs);
break;
case '}':
dir = 1;
col0 = '\0';
SENTENCE(list = o_paragraphs);
break;
case '[':
if (getkey(0) != '[')
{
return MARK_UNSET;
}
dir = -1;
col0 = '{';
SENTENCE(list = o_sections);
break;
case ']':
if (getkey(0) != ']')
{
return MARK_UNSET;
}
dir = 1;
col0 = '{';
SENTENCE(list = o_sections);
break;
}
ol = l = markline(m);
/* for each paragraph that we want to travel through... */
while (l > 0 && l <= nlines && cnt-- > 0)
{
/* skip blank lines between paragraphs */
while (l > 0 && l <= nlines && col0 == *(text = fetchline(l)))
{
l += dir;
}
/* skip non-blank lines that aren't paragraph separators
*/
do
{
#ifndef NO_SENTENCE
if (*text == '.' && l != ol)
{
for (pscn = list; pscn[0] && pscn[1]; pscn += 2)
{
if (pscn[0] == text[1] && pscn[1] == text[2])
{
pscn = (char *)0;
goto BreakBreak;
}
}
}
#endif
l += dir;
} while (l > 0 && l <= nlines && col0 != *(text = fetchline(l)));
BreakBreak: ;
}
if (l > nlines)
{
m = MARK_LAST;
}
else if (l <= 0)
{
m = MARK_FIRST;
}
else
{
m = MARK_AT_LINE(l);
}
return m;
}
/*ARGSUSED*/
MARK m_match(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument (normally 0) */
{
long l;
REG char *text;
REG char match;
REG char nest;
REG int count;
#ifndef NO_EXTENSIONS
/* if we're given a number, then treat it as a percentage of the file */
if (cnt > 0)
{
/* make sure it is a reasonable number */
if (cnt > 100)
{
msg("can only be from 1%% to 100%%");
return MARK_UNSET;
}
/* return the appropriate line number */
l = (nlines - 1L) * cnt / 100L + 1L;
return MARK_AT_LINE(l);
}
#endif /* undef NO_EXTENSIONS */
/* get the current line */
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
/* search forward within line for one of "[](){}" */
for (match = '\0'; !match && *text; text++)
{
/* tricky way to recognize 'em in ASCII */
nest = *text;
if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
{
match = nest ^ ('[' ^ ']');
}
else if ((nest & 0xfe) == '(')
{
match = nest ^ ('(' ^ ')');
}
else
{
match = 0;
}
}
if (!match)
{
return MARK_UNSET;
}
text--;
/* search forward or backward for match */
if (match == '(' || match == '[' || match == '{')
{
/* search backward */
for (count = 1; count > 0; )
{
/* wrap at beginning of line */
if (text == ptext)
{
do
{
if (l <= 1L)
{
return MARK_UNSET;
}
l--;
pfetch(l);
} while (!*ptext);
text = ptext + plen - 1;
}
else
{
text--;
}
/* check the char */
if (*text == match)
count--;
else if (*text == nest)
count++;
}
}
else
{
/* search forward */
for (count = 1; count > 0; )
{
/* wrap at end of line */
if (!*text)
{
if (l >= nlines)
{
return MARK_UNSET;
}
l++;
pfetch(l);
text = ptext;
}
else
{
text++;
}
/* check the char */
if (*text == match)
count--;
else if (*text == nest)
count++;
}
}
/* construct a mark for this place */
m = buildmark(text);
return m;
}
/*ARGSUSED*/
MARK m_tomark(m, cnt, key)
MARK m; /* movement is relative to this mark */
long cnt; /* (ignored) */
int key; /* keystroke - the mark to move to */
{
/* mark '' is a special case */
if (key == '\'' || key == '`')
{
if (mark[26] == MARK_UNSET)
{
return MARK_FIRST;
}
else
{
return mark[26];
}
}
/* if not a valid mark number, don't move */
if (key < 'a' || key > 'z')
{
return MARK_UNSET;
}
/* return the selected mark -- may be MARK_UNSET */
if (!mark[key - 'a'])
{
msg("mark '%c is unset", key);
}
return mark[key - 'a'];
}

View file

@ -1,291 +0,0 @@
/* move2.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This function contains the movement functions that perform RE searching */
#include "config.h"
#include "vi.h"
#include "regexp.h"
extern long atol();
static regexp *re; /* compiled version of the pattern to search for */
static prevsf; /* boolean: previous search direction was forward? */
#ifndef NO_EXTENSIONS
/*ARGSUSED*/
MARK m_wsrch(word, m, cnt)
char *word; /* the word to search for */
MARK m; /* the starting point */
int cnt; /* ignored */
{
char buffer[30];
/* wrap \< and \> around the word */
strcpy(buffer, "/\\<");
strcat(buffer, word);
strcat(buffer, "\\>");
/* show the searched-for word on the bottom line */
move(LINES - 1, 0);
qaddstr(buffer);
clrtoeol();
refresh();
/* search for the word */
return m_fsrch(m, buffer);
}
#endif
MARK m_nsrch(m)
MARK m; /* where to start searching */
{
if (prevsf)
{
m = m_fsrch(m, (char *)0);
prevsf = TRUE;
}
else
{
m = m_bsrch(m, (char *)0);
prevsf = FALSE;
}
return m;
}
MARK m_Nsrch(m)
MARK m; /* where to start searching */
{
if (prevsf)
{
m = m_bsrch(m, (char *)0);
prevsf = TRUE;
}
else
{
m = m_fsrch(m, (char *)0);
prevsf = FALSE;
}
return m;
}
MARK m_fsrch(m, ptrn)
MARK m; /* where to start searching */
char *ptrn; /* pattern to search for */
{
long l; /* line# of line to be searched */
char *line; /* text of line to be searched */
int wrapped;/* boolean: has our search wrapped yet? */
int pos; /* where we are in the line */
#ifndef CRUNCH
long delta = INFINITY;/* line offset, for things like "/foo/+1" */
#endif
/* remember: "previous search was forward" */
prevsf = TRUE;
if (ptrn && *ptrn)
{
/* locate the closing '/', if any */
line = parseptrn(ptrn);
#ifndef CRUNCH
if (*line)
{
delta = atol(line);
}
#endif
ptrn++;
/* free the previous pattern */
if (re) free(re);
/* compile the pattern */
re = regcomp(ptrn);
if (!re)
{
return MARK_UNSET;
}
}
else if (!re)
{
msg("No previous expression");
return MARK_UNSET;
}
/* search forward for the pattern */
pos = markidx(m) + 1;
pfetch(markline(m));
if (pos >= plen)
{
pos = 0;
m = (m | (BLKSIZE - 1)) + 1;
}
wrapped = FALSE;
for (l = markline(m); l != markline(m) + 1 || !wrapped; l++)
{
/* wrap search */
if (l > nlines)
{
/* if we wrapped once already, then the search failed */
if (wrapped)
{
break;
}
/* else maybe we should wrap now? */
if (*o_wrapscan)
{
l = 0;
wrapped = TRUE;
continue;
}
else
{
break;
}
}
/* get this line */
line = fetchline(l);
/* check this line */
if (regexec(re, &line[pos], (pos == 0)))
{
/* match! */
if (wrapped && *o_warn)
msg("(wrapped)");
#ifndef CRUNCH
if (delta != INFINITY)
{
l += delta;
if (l < 1 || l > nlines)
{
msg("search offset too big");
return MARK_UNSET;
}
force_flags = LNMD|INCL;
return MARK_AT_LINE(l);
}
#endif
return MARK_AT_LINE(l) + (int)(re->startp[0] - line);
}
pos = 0;
}
/* not found */
msg(*o_wrapscan ? "Not found" : "Hit bottom without finding RE");
return MARK_UNSET;
}
MARK m_bsrch(m, ptrn)
MARK m; /* where to start searching */
char *ptrn; /* pattern to search for */
{
long l; /* line# of line to be searched */
char *line; /* text of line to be searched */
int wrapped;/* boolean: has our search wrapped yet? */
int pos; /* last acceptable idx for a match on this line */
int last; /* remembered idx of the last acceptable match on this line */
int try; /* an idx at which we strat searching for another match */
#ifndef CRUNCH
long delta = INFINITY;/* line offset, for things like "/foo/+1" */
#endif
/* remember: "previous search was not forward" */
prevsf = FALSE;
if (ptrn && *ptrn)
{
/* locate the closing '?', if any */
line = parseptrn(ptrn);
#ifndef CRUNCH
if (*line)
{
delta = atol(line);
}
#endif
ptrn++;
/* free the previous pattern, if any */
if (re) free(re);
/* compile the pattern */
re = regcomp(ptrn);
if (!re)
{
return MARK_UNSET;
}
}
else if (!re)
{
msg("No previous expression");
return MARK_UNSET;
}
/* search backward for the pattern */
pos = markidx(m);
wrapped = FALSE;
for (l = markline(m); l != markline(m) - 1 || !wrapped; l--)
{
/* wrap search */
if (l < 1)
{
if (*o_wrapscan)
{
l = nlines + 1;
wrapped = TRUE;
continue;
}
else
{
break;
}
}
/* get this line */
line = fetchline(l);
/* check this line */
if (regexec(re, line, 1) && (int)(re->startp[0] - line) < pos)
{
/* match! now find the last acceptable one in this line */
do
{
last = (int)(re->startp[0] - line);
try = (int)(re->endp[0] - line);
} while (try > 0
&& regexec(re, &line[try], FALSE)
&& (int)(re->startp[0] - line) < pos);
if (wrapped && *o_warn)
msg("(wrapped)");
#ifndef CRUNCH
if (delta != INFINITY)
{
l += delta;
if (l < 1 || l > nlines)
{
msg("search offset too big");
return MARK_UNSET;
}
force_flags = LNMD|INCL;
return MARK_AT_LINE(l);
}
#endif
return MARK_AT_LINE(l) + last;
}
pos = BLKSIZE;
}
/* not found */
msg(*o_wrapscan ? "Not found" : "Hit top without finding RE");
return MARK_UNSET;
}

View file

@ -1,163 +0,0 @@
/* move3.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains movement functions that perform character searches */
#include "config.h"
#include "vi.h"
#ifndef NO_CHARSEARCH
static MARK (*prevfwdfn)(); /* function to search in same direction */
static MARK (*prevrevfn)(); /* function to search in opposite direction */
static char prev_key; /* sought cvhar from previous [fFtT] */
MARK m__ch(m, cnt, cmd)
MARK m; /* current position */
long cnt;
char cmd; /* command: either ',' or ';' */
{
MARK (*tmp)();
if (!prevfwdfn)
{
msg("No previous f, F, t, or T command");
return MARK_UNSET;
}
if (cmd == ',')
{
m = (*prevrevfn)(m, cnt, prev_key);
/* Oops! we didn't want to change the prev*fn vars! */
tmp = prevfwdfn;
prevfwdfn = prevrevfn;
prevrevfn = tmp;
return m;
}
else
{
return (*prevfwdfn)(m, cnt, prev_key);
}
}
/* move forward within this line to next occurrence of key */
MARK m_fch(m, cnt, key)
MARK m; /* where to search from */
long cnt;
char key; /* what to search for */
{
REG char *text;
DEFAULT(1);
prevfwdfn = m_fch;
prevrevfn = m_Fch;
prev_key = key;
pfetch(markline(m));
text = ptext + markidx(m);
while (cnt-- > 0)
{
do
{
m++;
text++;
} while (*text && *text != key);
}
if (!*text)
{
return MARK_UNSET;
}
return m;
}
/* move backward within this line to previous occurrence of key */
MARK m_Fch(m, cnt, key)
MARK m; /* where to search from */
long cnt;
char key; /* what to search for */
{
REG char *text;
DEFAULT(1);
prevfwdfn = m_Fch;
prevrevfn = m_fch;
prev_key = key;
pfetch(markline(m));
text = ptext + markidx(m);
while (cnt-- > 0)
{
do
{
m--;
text--;
} while (text >= ptext && *text != key);
}
if (text < ptext)
{
return MARK_UNSET;
}
return m;
}
/* move forward within this line almost to next occurrence of key */
MARK m_tch(m, cnt, key)
MARK m; /* where to search from */
long cnt;
char key; /* what to search for */
{
/* skip the adjacent char */
pfetch(markline(m));
if (plen <= markidx(m))
{
return MARK_UNSET;
}
m++;
m = m_fch(m, cnt, key);
if (m == MARK_UNSET)
{
return MARK_UNSET;
}
prevfwdfn = m_tch;
prevrevfn = m_Tch;
return m - 1;
}
/* move backward within this line almost to previous occurrence of key */
MARK m_Tch(m, cnt, key)
MARK m; /* where to search from */
long cnt;
char key; /* what to search for */
{
/* skip the adjacent char */
if (markidx(m) == 0)
{
return MARK_UNSET;
}
m--;
m = m_Fch(m, cnt, key);
if (m == MARK_UNSET)
{
return MARK_UNSET;
}
prevfwdfn = m_Tch;
prevrevfn = m_tch;
return m + 1;
}
#endif

View file

@ -1,211 +0,0 @@
/* move4.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains movement functions which are screen-relative */
#include "config.h"
#include "vi.h"
/* This moves the cursor to a particular row on the screen */
/*ARGSUSED*/
MARK m_row(m, cnt, key)
MARK m; /* the cursor position */
long cnt; /* the row we'll move to */
int key; /* the keystroke of this move - H/L/M */
{
DEFAULT(1);
/* calculate destination line based on key */
cnt--;
switch (key)
{
case 'H':
cnt = topline + cnt;
break;
case 'M':
cnt = topline + (LINES - 1) / 2;
break;
case 'L':
cnt = botline - cnt;
break;
}
/* return the mark of the destination line */
return MARK_AT_LINE(cnt);
}
/* This function repositions the current line to show on a given row */
MARK m_z(m, cnt, key)
MARK m; /* the cursor */
long cnt; /* the line number we're repositioning */
int key; /* key struck after the z */
{
long newtop;
int i;
/* Which line are we talking about? */
if (cnt < 0 || cnt > nlines)
{
return MARK_UNSET;
}
if (cnt)
{
m = MARK_AT_LINE(cnt);
newtop = cnt;
}
else
{
newtop = markline(m);
}
/* allow a "window size" number to be entered */
for (i = 0; key >= '0' && key <= '9'; key = getkey(0))
{
i = i * 10 + key - '0';
}
#ifndef CRUNCH
if (i > 0 && i <= LINES - 1)
{
*o_window = i;
wset = TRUE;
}
#else
/* the number is ignored if -DCRUNCH */
#endif
/* figure out which line will have to be at the top of the screen */
switch (key)
{
case '\n':
#if OSK
case '\l':
#else
case '\r':
#endif
case '+':
break;
case '.':
case 'z':
newtop -= LINES / 2;
break;
case '-':
newtop -= LINES - 1;
break;
default:
return MARK_UNSET;
}
/* make the new topline take effect */
redraw(MARK_UNSET, FALSE);
if (newtop >= 1)
{
topline = newtop;
}
else
{
topline = 1L;
}
redrawrange(0L, INFINITY, INFINITY);
/* The cursor doesn't move */
return m;
}
/* This function scrolls the screen. It does this by calling redraw() with
* an off-screen line as the argument. It will move the cursor if necessary
* so that the cursor is on the new screen.
*/
/*ARGSUSED*/
MARK m_scroll(m, cnt, key)
MARK m; /* the cursor position */
long cnt; /* for some keys: the number of lines to scroll */
int key; /* keystroke that causes this movement */
{
MARK tmp; /* a temporary mark, used as arg to redraw() */
/* adjust cnt, and maybe *o_scroll, depending of key */
switch (key)
{
case ctrl('F'):
case ctrl('B'):
DEFAULT(1);
redrawrange(0L, INFINITY, INFINITY); /* force complete redraw */
cnt = cnt * (LINES - 1) - 2; /* keeps two old lines on screen */
break;
case ctrl('E'):
case ctrl('Y'):
DEFAULT(1);
break;
case ctrl('U'):
case ctrl('D'):
if (cnt == 0) /* default */
{
cnt = *o_scroll;
}
else
{
if (cnt > LINES - 1)
{
cnt = LINES - 1;
}
*o_scroll = cnt;
}
break;
}
/* scroll up or down, depending on key */
switch (key)
{
case ctrl('B'):
case ctrl('Y'):
case ctrl('U'):
cnt = topline - cnt;
if (cnt < 1L)
{
cnt = 1L;
m = MARK_FIRST;
}
tmp = MARK_AT_LINE(cnt) + markidx(m);
redraw(tmp, FALSE);
if (markline(m) > botline)
{
m = MARK_AT_LINE(botline);
}
break;
case ctrl('F'):
case ctrl('E'):
case ctrl('D'):
cnt = botline + cnt;
if (cnt > nlines)
{
cnt = nlines;
m = MARK_LAST;
}
tmp = MARK_AT_LINE(cnt) + markidx(m);
redraw(tmp, FALSE);
if (markline(m) < topline)
{
m = MARK_AT_LINE(topline);
}
break;
}
return m;
}

View file

@ -1,256 +0,0 @@
/* move5.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the word-oriented movement functions */
#include "config.h"
#include "ctype.h"
#include "vi.h"
MARK m_fword(m, cnt, cmd, prevkey)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
int cmd; /* either 'w' or 'W' */
int prevkey;/* previous command... if 'c' then exclude whitespace */
{
REG long l;
REG char *text;
REG int i;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
#ifndef CRUNCH
/* As a special case, "cw" or "cW" on whitespace without a count
* treats the single whitespace character under the cursor as a word.
*/
if (cnt == 1L && prevkey == 'c' && isspace(*text))
{
return m + 1L;
}
#endif
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
i = *text++;
if (cmd == 'W')
{
/* include any non-whitespace */
while (i && !isspace(i))
{
i = *text++;
}
}
else if (isalnum(i) || i == '_')
{
/* include an alphanumeric word */
while (i && isalnum(i))
{
i = *text++;
}
}
else
{
/* include contiguous punctuation */
while (i && !isalnum(i) && !isspace(i))
{
i = *text++;
}
}
/* if not part of "cw" or "cW" command... */
if (prevkey != 'c' || cnt > 0)
{
/* include trailing whitespace */
while (!i || isspace(i))
{
/* did we hit the end of this line? */
if (!i)
{
/* "dw" shouldn't delete newline after word */
if (prevkey && cnt == 0)
{
break;
}
/* move to next line, if there is one */
l++;
if (l > nlines)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext;
}
i = *text++;
}
}
text--;
}
/* if argument to operator, then back off 1 char since "w" and "W"
* include the last char in the affected text.
*/
if (prevkey)
{
text--;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}
MARK m_bword(m, cnt, cmd)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
int cmd; /* either 'b' or 'B' */
{
REG long l;
REG char *text;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
text--;
/* include preceding whitespace */
while (text < ptext || isspace(*text))
{
/* did we hit the end of this line? */
if (text < ptext)
{
/* move to preceding line, if there is one */
l--;
if (l <= 0)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext + plen - 1;
}
else
{
text--;
}
}
if (cmd == 'B')
{
/* include any non-whitespace */
while (text >= ptext && !isspace(*text))
{
text--;
}
}
else if (isalnum(*text) || *text == '_')
{
/* include an alphanumeric word */
while (text >= ptext && isalnum(*text))
{
text--;
}
}
else
{
/* include contiguous punctuation */
while (text >= ptext && !isalnum(*text) && !isspace(*text))
{
text--;
}
}
text++;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}
MARK m_eword(m, cnt, cmd)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
int cmd; /* either 'e' or 'E' */
{
REG long l;
REG char *text;
REG int i;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
if (*text)
text++;
i = *text++;
/* include preceding whitespace */
while (!i || isspace(i))
{
/* did we hit the end of this line? */
if (!i)
{
/* move to next line, if there is one */
l++;
if (l > nlines)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext;
}
i = *text++;
}
if (cmd == 'E')
{
/* include any non-whitespace */
while (i && !isspace(i))
{
i = *text++;
}
}
else if (isalnum(i) || i == '_')
{
/* include an alphanumeric word */
while (i && isalnum(i))
{
i = *text++;
}
}
else
{
/* include contiguous punctuation */
while (i && !isalnum(i) && !isspace(i))
{
i = *text++;
}
}
text -= 2;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}

View file

@ -1,795 +0,0 @@
/* opts.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the code that manages the run-time options -- The
* values that can be modified via the "set" command.
*/
#include "config.h"
#include "vi.h"
#include "ctype.h"
#include <sys/null.h>
extern char *getenv();
/* maximum width to permit for strings, including ="" */
#define MAXWIDTH 20
/* These are the default values of all options */
char o_autoindent[1] = {FALSE};
char o_autoprint[1] = {TRUE};
char o_autotab[1] = {TRUE};
char o_autowrite[1] = {FALSE};
char o_columns[3] = {80, 32, 255};
char o_directory[30] = TMPDIR;
char o_edcompatible[1] = {FALSE};
char o_equalprg[80] = {"fmt"};
char o_errorbells[1] = {TRUE};
char o_exrefresh[1] = {TRUE};
char o_ignorecase[1] = {FALSE};
char o_keytime[3] = {1, 0, 50};
char o_keywordprg[80] = {KEYWORDPRG};
char o_lines[3] = {25, 2, 96};
char o_list[1] = {FALSE};
char o_number[1] = {FALSE};
char o_readonly[1] = {FALSE};
char o_remap[1] = {TRUE};
char o_report[3] = {5, 1, 127};
char o_scroll[3] = {12, 1, 127};
char o_shell[60] = SHELL;
char o_shiftwidth[3] = {8, 1, 255};
char o_sidescroll[3] = {8, 1, 40};
char o_sync[1] = {NEEDSYNC};
char o_tabstop[3] = {8, 1, 40};
char o_term[30] = "?";
char o_flash[1] = {TRUE};
char o_warn[1] = {TRUE};
char o_wrapscan[1] = {TRUE};
#ifndef CRUNCH
char o_beautify[1] = {FALSE};
char o_exrc[1] = {FALSE};
char o_mesg[1] = {TRUE};
char o_more[1] = {TRUE};
char o_novice[1] = {FALSE};
char o_prompt[1] = {TRUE};
char o_taglength[3] = {0, 0, 30};
char o_terse[1] = {FALSE};
char o_window[3] = {0, 1, 24};
char o_wrapmargin[3] = {0, 0, 255};
char o_writeany[1] = {FALSE};
#endif
#ifndef NO_ERRLIST
char o_cc[30] = {CC_COMMAND};
char o_make[30] = {MAKE_COMMAND};
#endif
#ifndef NO_CHARATTR
char o_charattr[1] = {FALSE};
#endif
#ifndef NO_DIGRAPH
char o_digraph[1] = {FALSE};
char o_flipcase[80]
# ifdef CS_IBMPC
= {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245"}
# endif
# ifdef CS_LATIN1
/* initialized by initopts() */
# endif
;
#endif
#ifndef NO_SENTENCE
char o_hideformat[1] = {FALSE};
#endif
#ifndef NO_EXTENSIONS
char o_inputmode[1] = {FALSE};
char o_ruler[1] = {FALSE};
#endif
#ifndef NO_MAGIC
char o_magic[1] = {TRUE};
#endif
#ifndef NO_MODELINES
char o_modelines[1] = {FALSE};
#endif
#ifndef NO_SENTENCE
char o_paragraphs[30] = "PPppIPLPQP";
char o_sections[30] = "NHSHSSSEse";
#endif
#if MSDOS
char o_pcbios[1] = {TRUE};
#endif
#ifndef NO_SHOWMATCH
char o_showmatch[1] = {FALSE};
#endif
#ifndef NO_SHOWMODE
char o_smd[1] = {FALSE};
#endif
/* The following describes the names & types of all options */
#define BOOL 0
#define NUM 1
#define STR 2
#define SET 0x01 /* this option has had its value altered */
#define CANSET 0x02 /* this option can be set at any time */
#define RCSET 0x06 /* this option can be set in a .exrc file only */
#define NOSAVE 0x0a /* this option should never be saved by mkexrc */
#define WSET 0x20 /* is this the "window" size option? */
#define MR 0x40 /* does this option affect the way text is displayed? */
struct
{
char *name; /* name of an option */
char *nm; /* short name of an option */
char type; /* type of an option */
char flags; /* boolean: has this option been set? */
char *value; /* value */
}
opts[] =
{
/* name type flags value */
{ "autoindent", "ai", BOOL, CANSET, o_autoindent },
{ "autoprint", "ap", BOOL, CANSET, o_autoprint },
{ "autotab", "at", BOOL, CANSET, o_autotab },
{ "autowrite", "aw", BOOL, CANSET, o_autowrite },
#ifndef CRUNCH
{ "beautify", "bf", BOOL, CANSET, o_beautify },
#endif
#ifndef NO_ERRLIST
{ "cc", "cc", STR, CANSET, o_cc },
#endif
#ifndef NO_CHARATTR
{ "charattr", "ca", BOOL, CANSET|MR, o_charattr },
#endif
{ "columns", "co", NUM, SET|NOSAVE|MR, o_columns },
#ifndef NO_DIGRAPH
{ "digraph", "dig", BOOL, CANSET, o_digraph },
#endif
{ "directory", "dir", STR, RCSET, o_directory },
{ "edcompatible","ed", BOOL, CANSET, o_edcompatible },
{ "equalprg", "ep", STR, CANSET, o_equalprg },
{ "errorbells", "eb", BOOL, CANSET, o_errorbells },
#ifndef CRUNCH
{ "exrc", "exrc", BOOL, CANSET, o_exrc },
#endif
{ "exrefresh", "er", BOOL, CANSET, o_exrefresh },
{ "flash", "vbell",BOOL, CANSET, o_flash },
#ifndef NO_DIGRAPH
{ "flipcase", "fc", STR, CANSET, o_flipcase },
#endif
#ifndef NO_SENTENCE
{ "hideformat", "hf", BOOL, CANSET|MR, o_hideformat },
#endif
{ "ignorecase", "ic", BOOL, CANSET, o_ignorecase },
#ifndef NO_EXTENSIONS
{ "inputmode", "im", BOOL, CANSET, o_inputmode },
#endif
{ "keytime", "kt", NUM, CANSET, o_keytime },
{ "keywordprg", "kp", STR, CANSET, o_keywordprg },
{ "lines", "ls", NUM, SET|NOSAVE|MR, o_lines },
{ "list", "li", BOOL, CANSET|MR, o_list },
#ifndef NO_MAGIC
{ "magic", "ma", BOOL, CANSET, o_magic },
#endif
#ifndef NO_ERRLIST
{ "make", "mk", STR, CANSET, o_make },
#endif
#ifndef CRUNCH
{ "mesg", "me", BOOL, CANSET, o_mesg },
#endif
#ifndef NO_MODELINES
{ "modelines", "ml", BOOL, CANSET, o_modelines },
#endif
#ifndef CRUNCH
{ "more", "mo", BOOL, CANSET, o_more },
{ "novice", "nov", BOOL, CANSET, o_novice },
#endif
{ "number", "nu", BOOL, CANSET|MR, o_number },
#ifndef NO_SENTENCE
{ "paragraphs", "para", STR, CANSET, o_paragraphs },
#endif
#if MSDOS
{ "pcbios", "pc", BOOL, SET|NOSAVE, o_pcbios },
#endif
#ifndef CRUNCH
{ "prompt", "pr", BOOL, CANSET, o_prompt },
#endif
{ "readonly", "ro", BOOL, CANSET, o_readonly },
{ "remap", "remap",BOOL, CANSET, o_remap },
{ "report", "re", NUM, CANSET, o_report },
#ifndef NO_EXTENSIONS
{ "ruler", "ru", BOOL, CANSET, o_ruler },
#endif
{ "scroll", "sc", NUM, CANSET, o_scroll },
#ifndef NO_SENTENCE
{ "sections", "sect", STR, CANSET, o_sections },
#endif
{ "shell", "sh", STR, CANSET, o_shell },
#ifndef NO_SHOWMATCH
{ "showmatch", "sm", BOOL, CANSET, o_showmatch },
#endif
#ifndef NO_SHOWMODE
{ "showmode", "smd", BOOL, CANSET, o_smd },
#endif
{ "shiftwidth", "sw", NUM, CANSET, o_shiftwidth },
{ "sidescroll", "ss", NUM, CANSET, o_sidescroll },
{ "sync", "sy", BOOL, CANSET, o_sync },
{ "tabstop", "ts", NUM, CANSET|MR, o_tabstop },
#ifndef CRUNCH
{ "taglength", "tl", NUM, CANSET, o_taglength },
#endif
{ "term", "te", STR, SET, o_term },
#ifndef CRUNCH
{ "terse", "tr", BOOL, CANSET, o_terse },
{ "timeout", "to", BOOL, CANSET, o_keytime },
#endif
#ifndef CRUNCH
{ "window", "wi", NUM, CANSET|MR|WSET, o_window },
{ "wrapmargin", "wm", NUM, CANSET, o_wrapmargin },
#endif
{ "wrapscan", "ws", BOOL, CANSET, o_wrapscan },
#ifndef CRUNCH
{ "writeany", "wr", BOOL, CANSET, o_writeany },
#endif
{ NULL, NULL, 0, CANSET, NULL }
};
/* This function initializes certain options from environment variables, etc. */
void initopts()
{
char *val;
int i;
/* set some stuff from environment variables */
#if MSDOS
if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
#else
if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
#endif
{
strcpy(o_shell, val);
}
strcpy(o_term, termtype);
#if MSDOS
if (strcmp(termtype, "pcbios"))
{
o_pcbios[0] = FALSE;
}
else
{
o_pcbios[0] = TRUE;
}
#endif
#if AMIGA || MSDOS || TOS
if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
|| (val = getenv("TEMP")))
strcpy(o_directory, val);
#endif
#ifndef CRUNCH
if ((val = getenv("LINES")) && atoi(val) > 4) /* yes, ASSIGNMENT! */
{
LINES = atoi(val);
}
if ((val = getenv("COLUMNS")) && atoi(val) > 30) /* yes, ASSIGNMENT! */
{
COLS = atoi(val);
}
#endif
*o_lines = LINES;
*o_columns = COLS;
*o_scroll = LINES / 2 - 1;
#ifndef CRUNCH
if (o_window[0] == 0)
{
o_window[0] = o_window[2] = *o_lines;
}
#endif
/* disable the flash option if we don't know how to do a flash */
if (!has_VB)
{
for (i = 0; opts[i].value != o_flash; i++)
{
}
opts[i].flags &= ~CANSET;
*o_flash = FALSE;
}
#ifndef NO_DIGRAPH
# ifdef CS_LATIN1
for (i = 0, val = o_flipcase; i < 32; i++)
{
/* leave out the multiply/divide symbols */
if (i == 23)
continue;
/* add lower/uppercase pair */
*val++ = i + 0xe0;
*val++ = i + 0xc0;
}
*val = '\0';
# endif /* CS_LATIN1 */
/* initialize the ctype package */
_ct_init(o_flipcase);
#else
_ct_init("");
#endif /* not NO_DIGRAPH */
}
/* This function lists the current values of all options */
void dumpopts(all)
int all; /* boolean: dump all options, or just set ones? */
{
#ifndef NO_OPTCOLS
int i, j, k;
char nbuf[4]; /* used for converting numbers to ASCII */
int widths[5]; /* width of each column, including gap */
int ncols; /* number of columns */
int nrows; /* number of options per column */
int nset; /* number of options to be output */
int width; /* width of a particular option */
int todump[60]; /* indicies of options to be dumped */
/* step 1: count the number of set options */
for (nset = i = 0; opts[i].name; i++)
{
if (all || (opts[i].flags & SET))
{
todump[nset++] = i;
}
}
/* step two: try to use as many columns as possible */
for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
{
/* how many would go in this column? */
nrows = (nset + ncols - 1) / ncols;
/* figure out the width of each column */
for (i = 0; i < ncols; i++)
{
widths[i] = 0;
for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
{
/* figure out the width of a particular option */
switch (opts[todump[k]].type)
{
case BOOL:
if (!*opts[todump[k]].value)
width = 2;
else
width = 0;
break;
case STR:
width = 3 + strlen(opts[todump[k]].value);
if (width > MAXWIDTH)
width = MAXWIDTH;
break;
case NUM:
width = 4;
break;
}
width += strlen(opts[todump[k]].name);
/* if this is the widest so far, widen col */
if (width > widths[i])
{
widths[i] = width;
}
}
}
/* if the total width is narrow enough, then use it */
for (width = -2, i = 0; i < ncols; i++)
{
width += widths[i] + 2;
}
if (width < COLS - 1)
{
break;
}
}
/* step 3: output the columns */
nrows = (nset + ncols - 1) / ncols;
for (i = 0; i < nrows; i++)
{
for (j = 0; j < ncols; j++)
{
/* if we hit the end of the options, quit */
k = i + j * nrows;
if (k >= nset)
{
break;
}
/* output this option's value */
width = 0;
switch (opts[todump[k]].type)
{
case BOOL:
if (!*opts[todump[k]].value)
{
qaddch('n');
qaddch('o');
width = 2;
}
qaddstr(opts[todump[k]].name);
width += strlen(opts[todump[k]].name);
break;
case NUM:
sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
qaddstr(opts[todump[k]].name);
qaddch('=');
qaddstr(nbuf);
width = 4 + strlen(opts[todump[k]].name);
break;
case STR:
qaddstr(opts[todump[k]].name);
qaddch('=');
qaddch('"');
strcpy(tmpblk.c, opts[todump[k]].value);
width = 3 + strlen(tmpblk.c);
if (width > MAXWIDTH)
{
width = MAXWIDTH;
strcpy(tmpblk.c + MAXWIDTH - 6, "...");
}
qaddstr(tmpblk.c);
qaddch('"');
width += strlen(opts[todump[k]].name);
break;
}
/* pad the field to the correct size */
if (k + nrows <= nset)
{
while (width < widths[j] + 2)
{
qaddch(' ');
width++;
}
}
}
addch('\n');
exrefresh();
}
#else
int i;
int col;
char nbuf[4];
for (i = col = 0; opts[i].name; i++)
{
/* if not set and not all, ignore this option */
if (!all && !(opts[i].flags & SET))
{
continue;
}
/* align this option in one of the columns */
if (col > 52)
{
addch('\n');
col = 0;
}
else if (col > 26)
{
while (col < 52)
{
qaddch(' ');
col++;
}
}
else if (col > 0)
{
while (col < 26)
{
qaddch(' ');
col++;
}
}
switch (opts[i].type)
{
case BOOL:
if (!*opts[i].value)
{
qaddch('n');
qaddch('o');
col += 2;
}
qaddstr(opts[i].name);
col += strlen(opts[i].name);
break;
case NUM:
sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
qaddstr(opts[i].name);
qaddch('=');
qaddstr(nbuf);
col += 4 + strlen(opts[i].name);
break;
case STR:
qaddstr(opts[i].name);
qaddch('=');
qaddch('"');
qaddstr(opts[i].value);
qaddch('"');
col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
break;
}
exrefresh();
}
if (col > 0)
{
addch('\n');
exrefresh();
}
#endif
}
#ifndef NO_MKEXRC
/* This function saves the current configuration of options to a file */
void saveopts(fd)
int fd; /* file descriptor to write to */
{
int i;
char buf[256], *pos;
/* write each set options */
for (i = 0; opts[i].name; i++)
{
/* if unset or unsettable, ignore this option */
if ((opts[i].flags & (SET|CANSET|NOSAVE)) != (SET|CANSET))
{
continue;
}
strcpy(buf, "set ");
pos = &buf[4];
switch (opts[i].type)
{
case BOOL:
if (!*opts[i].value)
{
*pos++='n';
*pos++='o';
}
strcpy(pos, opts[i].name);
strcat(pos, "\n");
break;
case NUM:
sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
break;
case STR:
sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
break;
}
twrite(fd, buf, (unsigned)strlen(buf));
}
}
#endif
/* This function changes the values of one or more options. */
void setopts(assignments)
char *assignments; /* a string containing option assignments */
{
char *name; /* name of variable in assignments */
char *value; /* value of the variable */
char *scan; /* used for moving through strings */
char *build; /* used for copying chars from "scan" */
char *prefix; /* pointer to "neg" or "no" at front of a boolean */
int quote; /* boolean: inside '"' quotes? */
int i, j;
#ifndef CRUNCH
/* reset the upper limit of "window" option to lines-1 */
*o_window = *o_lines - 1;
#endif
/* for each assignment... */
for (name = assignments; *name; )
{
/* skip whitespace */
if (*name == ' ' || *name == '\t')
{
name++;
continue;
}
/* after the name, find the value (if any) */
for (scan = name; isalnum(*scan); scan++)
{
}
if (*scan == '=')
{
*scan++ = '\0';
value = build = scan;
for (quote = FALSE; *scan && (quote || !isspace(*scan)); scan++)
{
if (*scan == '"')
{
quote = !quote;
}
else if (*scan == '\\' && scan[1])
{
*build++ = *++scan;
}
else
{
*build++ = *scan;
}
}
if (*scan)
scan++;
*build = '\0';
}
else /* no "=" so it is probably boolean... */
{
if (*scan)
{
*scan++ = '\0';
}
value = NULL;
prefix = name;
#ifndef CRUNCH
if (!strcmp(name, "novice"))
/* don't check for a "no" prefix */;
else
#endif
if (prefix[0] == 'n' && prefix[1] == 'o')
name += 2;
else if (prefix[0] == 'n' && prefix[1] == 'e' && prefix[2] == 'g')
name += 3;
}
/* find the variable */
for (i = 0;
opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
i++)
{
}
/* change the variable */
if (!opts[i].name)
{
msg("invalid option name \"%s\"", name);
}
else if ((opts[i].flags & CANSET) != CANSET)
{
msg("option \"%s\" can't be altered", name);
}
else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
{
msg("option \"%s\" can only be set in a %s file", name, EXRC);
}
else if (value)
{
switch (opts[i].type)
{
case BOOL:
msg("option \"[no]%s\" is boolean", name);
break;
case NUM:
j = atoi(value);
if (j == 0 && *value != '0')
{
msg("option \"%s\" must have a numeric value", name);
}
else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
{
msg("option \"%s\" must have a value between %d and %d",
name, opts[i].value[1], opts[i].value[2] & 0xff);
}
else
{
*opts[i].value = atoi(value);
opts[i].flags |= SET;
}
break;
case STR:
strcpy(opts[i].value, value);
opts[i].flags |= SET;
break;
}
if (opts[i].flags & MR)
{
redraw(MARK_UNSET, FALSE);
}
#ifndef CRUNCH
if (opts[i].flags & WSET)
{
wset = TRUE;
}
#endif
}
else /* valid option, no value */
{
if (opts[i].type == BOOL)
{
if (prefix == name)
*opts[i].value = TRUE;
else if (prefix[1] == 'o')
*opts[i].value = FALSE;
else
*opts[i].value = !*opts[i].value;
opts[i].flags |= SET;
if (opts[i].flags & MR)
{
redraw(MARK_UNSET, FALSE);
}
}
else
{
msg("option \"%s\" must be given a value", name);
}
}
/* move on to the next option */
name = scan;
}
/* special processing ... */
#ifndef CRUNCH
/* if "novice" is set, then ":set report=1 showmode nomagic" */
if (*o_novice)
{
*o_report = 1;
# ifndef NO_SHOWMODE
*o_smd = TRUE;
# endif
# ifndef NO_MAGIC
*o_magic = FALSE;
# endif
}
#endif
/* if "readonly" then set the READONLY flag for this file */
if (*o_readonly)
{
setflag(file, READONLY);
}
#ifndef NO_DIGRAPH
/* re-initialize the ctype package */
_ct_init(o_flipcase);
#endif /* not NO_DIGRAPH */
/* copy o_lines and o_columns into LINES and COLS */
LINES = (*o_lines & 255);
COLS = (*o_columns & 255);
}

View file

@ -1,105 +0,0 @@
/* prsvunix.c */
/* This file contains the UNIX-specific parts of the "elvprsv" program. */
#if OSK
#define ELVPRSV
#include "osk.c"
#else
#include <sys/stat.h>
#include <pwd.h>
#endif
/* This variable is used to add extra error messages for mail sent to root */
char *ps;
/* This function returns the login name of the owner of a file */
char *ownername(filename)
char *filename; /* name of a file */
{
struct stat st;
struct passwd *pw;
/* stat the file, to get its uid */
if (stat(filename, &st) < 0)
{
ps = "stat() failed";
return "root";
}
/* get the /etc/passwd entry for that user */
pw = getpwuid(st.st_uid);
if (!pw)
{
ps = "uid not found in password file";
return "root";
}
/* return the user's name */
return pw->pw_name;
}
/* This function sends a mail message to a given user, saying that a file
* has been preserved.
*/
void mail(user, file, when)
char *user; /* name of user who should receive the mail */
char *file; /* name of original text file that was preserved */
char *when; /* description of why the file was preserved */
{
char cmd[80];/* buffer used for constructing a "mail" command */
FILE *m, *popen(); /* stream used for giving text to the "mail" program */
char *base; /* basename of the file */
/* separate the directory name from the basename. */
for (base = file + strlen(file); --base > file && *base != SLASH; )
{
}
if (*base == SLASH)
{
*base++ = '\0';
}
/* for anonymous buffers, pretend the name was "foo" */
if (!strcmp(base, "*"))
{
base = "foo";
}
/* open a pipe to the "mail" program */
#if OSK
sprintf(cmd, "mail \"-s=%s preserved!\" %s", base, user);
#else /* ANY_UNIX */
sprintf(cmd, "mail %s >/dev/null 2>/dev/null", user);
#endif
m = popen(cmd, "w");
if (!m)
{
/* Can't send mail! Hope the user figures it out. */
return;
}
/* Tell the user that the file was preserved */
fprintf(m, "A version of your file \"%s%c%s\"\n", file, SLASH, base);
fprintf(m, "was preserved when %s.\n", when);
fprintf(m, "To recover this file, do the following:\n");
fprintf(m, "\n");
#if OSK
fprintf(m, " chd %s\n", file);
#else /* ANY_UNIX */
fprintf(m, " cd %s\n", file);
#endif
fprintf(m, " elvrec %s\n", base);
fprintf(m, "\n");
fprintf(m, "With fond wishes for a speedy recovery,\n");
fprintf(m, " Elvis\n");
if (ps)
{
fprintf(m, "\nP.S. %s\n", ps);
ps = (char *)0;
}
/* close the stream */
pclose(m);
}

View file

@ -1,183 +0,0 @@
/* recycle.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the functions perform garbage collection and allocate
* reusable blocks.
*/
#include "config.h"
#include "vi.h"
#ifndef NO_RECYCLE
/* this whole file would have be skipped if NO_RECYCLE is defined */
#define BTST(bitno, byte) ((byte) & (1 << (bitno)))
#define BSET(bitno, byte) ((byte) |= (1 << (bitno)))
#define BCLR(bitno, byte) ((byte) &= ~(1 << (bitno)))
#define TST(blkno) ((blkno) < MAXBIT ? BTST((blkno) & 7, bitmap[(blkno) >> 3]) : 1)
#define SET(blkno) if ((blkno) < MAXBIT) BSET((blkno) & 7, bitmap[(blkno) >> 3])
#define CLR(blkno) if ((blkno) < MAXBIT) BCLR((blkno) & 7, bitmap[(blkno) >> 3])
/* bitmap of free blocks in first 4096k of tmp file */
static unsigned char bitmap[512];
#define MAXBIT (sizeof bitmap << 3)
/* this function locates all free blocks in the current tmp file */
void garbage()
{
int i;
BLK oldhdr;
/* start by assuming every block is free */
for (i = 0; i < sizeof bitmap; i++)
{
bitmap[i] = 255;
}
/* header blocks aren't free */
#ifndef lint
CLR(0);
CLR(1);
#endif
/* blocks needed for current hdr aren't free */
for (i = 1; i < MAXBLKS; i++)
{
CLR(hdr.n[i]);
}
/* blocks needed for undo version aren't free */
lseek(tmpfd, 0L, 0);
if (read(tmpfd, &oldhdr, (unsigned)sizeof oldhdr) != sizeof oldhdr)
{
msg("garbage() failed to read oldhdr??");
for (i = 0; i < sizeof bitmap; i++)
{
bitmap[i] = 0;
}
return;
}
for (i = 1; i < MAXBLKS; i++)
{
CLR(oldhdr.n[i]);
}
/* blocks needed for cut buffers aren't free */
for (i = cutneeds(&oldhdr) - 1; i >= 0; i--)
{
CLR(oldhdr.n[i]);
}
}
/* This function allocates the first available block in the tmp file */
long allocate()
{
int i;
long offset;
/* search for the first byte with a free bit set */
for (i = 0; i < sizeof bitmap && bitmap[i] == 0; i++)
{
}
/* if we hit the end of the bitmap, return the end of the file */
if (i == sizeof bitmap)
{
offset = lseek(tmpfd, 0L, 2);
}
else /* compute the offset for the free block */
{
for (i <<= 3; TST(i) == 0; i++)
{
}
offset = (long)i * (long)BLKSIZE;
/* mark the block as "allocated" */
CLR(i);
}
return offset;
}
#endif
#ifdef DEBUG
# include <stdio.h>
# undef malloc
# undef free
# define MEMMAGIC 0x19f72cc0L
# define MAXALLOC 800
static char *allocated[MAXALLOC];
static char *fromfile[MAXALLOC];
static int fromline[MAXALLOC];
static int sizes[MAXALLOC];
char *dbmalloc(size, file, line)
int size;
char *file;
int line;
{
char *ret;
int i;
size = size + sizeof(long) - (size % sizeof(long));
ret = (char *)malloc(size + 2 * sizeof(long)) + sizeof(long);
for (i = 0; i < MAXALLOC && allocated[i]; i++)
{
}
if (i == MAXALLOC)
{
endwin();
fprintf(stderr, "\r\n%s(%d): Too many malloc calls!\n", file, line);
abort();
}
sizes[i] = size/sizeof(long);
allocated[i] = ret;
fromfile[i] = file;
fromline[i] = line;
((long *)ret)[-1] = MEMMAGIC;
((long *)ret)[sizes[i]] = MEMMAGIC;
return ret;
}
dbfree(ptr, file, line)
char *ptr;
char *file;
int line;
{
int i;
for (i = 0; i < MAXALLOC && allocated[i] != ptr; i++)
{
}
if (i == MAXALLOC)
{
endwin();
fprintf(stderr, "\r\n%s(%d): attempt to free mem that wasn't allocated\n", file, line);
abort();
}
allocated[i] = (char *)0;
if (((long *)ptr)[-1] != MEMMAGIC)
{
endwin();
fprintf(stderr, "\r\n%s(%d): underflowed malloc space, allocated at %s(%d)\n", file, line, fromfile[i], fromline[i]);
abort();
}
if (((long *)ptr)[sizes[i]] != MEMMAGIC)
{
endwin();
fprintf(stderr, "\r\n%s(%d): overflowed malloc space, allocated at %s(%d)\n", file, line, fromfile[i], fromline[i]);
abort();
}
free(ptr - sizeof(long));
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,525 +0,0 @@
/* ref2.c */
/* This is a totally rewritten version of ref. This version looks for the
* desired function name in the "tags" file, and then reads the header out
* from the source file. There is no longer any need for a "refs" file.
*
* Usage: ref [-a] [-t] [-f file] [-c class] tag
* Options: -t output tag info, not the description
* -f file default filename for static functions
* -c class default class names for class functions
*/
#include <stdio.h>
#include "config.h"
extern char *getenv();
extern char *fgets();
/* This is the default path that is searched for tags */
#if OSK
# define DEFTAGPATH ".:/dd/defs:/dd/defs/sys:/dd/usr/src/lib:../lib:/dd/usr/lib"
#else
# if ANY_UNIX
# define DEFTAGPATH ".:/usr/include:/usr/include/sys:/usr/src/lib:../lib:/usr/local/lib"
# else
# if MSDOS || TOS
# define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib"
# define SEP ';'
# else
# if AMIGA
# define DEFTAGPATH ".;Include:;Include:sys"
# define SEP ';'
# else /* any other OS */
# define DEFTAGPATH "."
# endif
# endif
# endif
#endif
#ifndef SEP
# define SEP ':'
#endif
/* These variables reflect the command-line options given by the user. */
int taginfo; /* boolean: give only the tag info? (not header?) */
char *def_file; /* default filename for static functions */
char *def_class; /* default classname for class members */
int colons; /* #colons in tag: 0=normal, 1=static, 2=member */
/* This function checks for a tag in the "tags" file of given directory.
* If the tag is found, then it returns a pointer to a static buffer which
* contains the filename, a tab character, and a linespec for finding the
* the tag. If the tag is not found in the "tags" file, or if the "tags"
* file cannot be opened or doesn't exist, then this function returns NULL.
*/
char *cktagdir(tag, dir)
char *tag; /* name of the tag to look for */
char *dir; /* name of the directory to check */
{
char buf[BLKSIZE];
static char found[BLKSIZE];
FILE *tfile;
int len;
#if AMIGA
if (dir[strlen(dir) - 1] == COLON)
sprintf(buf, "%s%s", dir, TAGS); /* no slash after colon. */
else
#endif
/* construct the name of the "tags" file in this directory */
sprintf(buf, "%s%c%s", dir, SLASH, TAGS);
/* Try to open the tags file. Return NULL if can't open */
#if AMIGA
if (buf[0] == '.' && buf[1] == SLASH)
tfile = fopen(&buf[2], "r");
else
#endif
tfile = fopen(buf, "r");
if (!tfile)
{
return (char *)0;
}
/* compute the length of the tagname once */
len = strlen(tag);
/* read lines until we get the one for this tag */
found[0] = '\0';
while (fgets(buf, sizeof buf, tfile))
{
/* is this the one we want? */
if (!strncmp(buf, tag, len) && buf[len] == '\t')
{
/* we've found a match -- remember it */
strcpy(found, buf);
/* if there is no default file, or this match is in
* the default file, then we've definitely found the
* one we want. Break out of the loop now.
*/
if (!def_file || !strncmp(&buf[len + 1], def_file, strlen(def_file)))
{
break;
}
}
}
/* we're through reading */
fclose(tfile);
/* if there's anything in found[], use it */
if (found[0])
{
return &found[len + 1];
}
/* else we didn't find it */
return (char *)0;
}
/* This function reads a single textline from a binary file. It returns
* the number of bytes read, or 0 at EOF.
*/
#ifdef __NBSD_LIBC
/* Avoid name pollution with stdio's getline. */
#define getline ref_getline
#endif
int getline(buf, limit, fp)
char *buf; /* buffer to read into */
int limit; /* maximum characters to read */
FILE *fp; /* binary stream to read from */
{
int bytes; /* number of bytes read so far */
int ch; /* single character from file */
for (bytes = 0, ch = 0; ch != '\n' && --limit > 0 && (ch = getc(fp)) != EOF; bytes++)
{
#if MSDOS || TOS
/* since this is a binary file, we'll need to manually strip CR's */
if (ch == '\r')
{
continue;
}
#endif
*buf++ = ch;
}
*buf = '\0';
return bytes;
}
/* This function reads a source file, looking for a given tag. If it finds
* the tag, then it displays it and returns TRUE. Otherwise it returns FALSE.
* To display the tag, it attempts to output any introductory comment, the
* tag line itself, and any arguments. Arguments are assumed to immediately
* follow the tag line, and start with whitespace. Comments are assumed to
* start with lines that begin with "/ *", "//", "(*", or "--", and end at the
* tag line or at a blank line.
*/
int lookup(dir, entry)
char *dir; /* name of the directory that contains the source */
char *entry; /* source filename, <Tab>, linespec */
{
char buf[BLKSIZE]; /* pathname of sourcefile */
long lnum; /* line number */
long here; /* seek position where current line began */
long comment; /* seek position of introductory comment, or -1L */
FILE *sfile; /* used for reading the source file */
int len; /* length of string */
char *ptr;
/* construct the pathname of the source file */
strcpy(buf, dir);
ptr = buf + strlen(buf);
#if AMIGA
if (ptr[-1] != COLON)
#endif
*ptr++ = SLASH;
while (*entry != '\t')
{
*ptr++ = *entry++;
}
*ptr = '\0';
entry++;
/* searching for string or number? */
if (*entry >= '0' && *entry <= '9')
{
/* given a specific line number */
lnum = atol(entry);
entry = (char *)0;
}
else
{
/* given a string -- strip off "/^" and "$/\n" */
entry += 2;
len = strlen(entry) - 2;
if (entry[len - 1] == '$')
{
entry[len - 1] = '\n';
}
lnum = 0L;
}
/* Open the file. Note that we open the file in binary mode even
* though we know it is a text file, because ftell() and fseek()
* don't work on text files.
*/
#if MSDOS || TOS
sfile = fopen(buf, "rb");
#else
# if AMIGA
if (buf[0] == '.' && buf[1] == SLASH)
sfile = fopen(&buf[2], "r");
else
# endif
sfile = fopen(buf, "r");
#endif
if (!sfile)
{
/* can't open the real source file. Try "refs" instead */
#if AMIGA
if (dir[strlen(dir) - 1] == COLON)
sprintf(buf, "%srefs", dir);
else
#endif
sprintf(buf, "%s%crefs", dir, SLASH);
#if MSDOS || TOS
sfile = fopen(buf, "rb");
#else
# if AMIGA
if (buf[0] == '.' && buf[1] == SLASH)
sfile = fopen(&buf[2], "r");
else
# endif
sfile = fopen(buf, "r");
#endif
if (!sfile)
{
/* failed! */
return 0;
}
}
/* search the file */
for (comment = -1L; here = ftell(sfile), getline(buf, BLKSIZE, sfile) > 0; )
{
/* Is this the start/end of a comment? */
if (comment == -1L)
{
/* starting a comment? */
if (buf[0] == '/' && buf[1] == '*'
|| buf[0] == '/' && buf[1] == '/'
|| buf[0] == '(' && buf[1] == '*'
|| buf[0] == '-' && buf[1] == '-')
{
comment = here;
}
}
else
{
/* ending a comment? */
if (buf[0] == '\n' || buf[0] == '#')
{
comment = -1L;
}
}
/* is this the tag line? */
if (--lnum == 0L || (entry && !strncmp(buf, entry, len)))
{
/* if there were introductory comments, show them */
if (comment != -1L)
{
fseek(sfile, comment, 0);
while (comment != here)
{
getline(buf, BLKSIZE, sfile);
fputs(buf, stdout);
comment = ftell(sfile);
}
/* re-fetch the tag line */
fgets(buf, BLKSIZE, sfile);
}
/* show the tag line */
fputs(buf, stdout);
/* show any argument lines */
while (getline(buf, BLKSIZE, sfile) > 0
&& buf[0] != '#'
&& strchr(buf, '{') == (char *)0)
{
fputs(buf, stdout);
}
/* Done! Close the file, and return TRUE */
fclose(sfile);
return 1;
}
}
/* not found -- return FALSE */
return 0;
}
/* This function searches through the entire search path for a given tag.
* If it finds the tag, then it displays the info and returns TRUE;
* otherwise it returns FALSE.
*/
int find(tag)
char *tag; /* the tag to look up */
{
char *tagpath;
char dir[80];
char *ptr;
int len;
if (colons == 1)
{
/* looking for static function -- only look in current dir */
tagpath = ".";
}
else
{
/* get the tagpath from the environment. Default to DEFTAGPATH */
tagpath = getenv("TAGPATH");
if (!tagpath)
{
tagpath = DEFTAGPATH;
}
}
/* for each entry in the path... */
while (*tagpath)
{
/* Copy the entry into the dir[] buffer */
for (ptr = dir; *tagpath && *tagpath != SEP; tagpath++)
{
*ptr++ = *tagpath;
}
if (*tagpath == SEP)
{
tagpath++;
}
/* if the entry ended with "/tags", then strip that off */
len = strlen(TAGS);
if (&dir[len] < ptr && ptr[-len - 1] == SLASH && !strncmp(&ptr[-len], TAGS, len))
{
ptr -= len + 1;
}
/* if the entry is now an empty string, then assume "." */
if (ptr == dir)
{
*ptr++ = '.';
}
*ptr = '\0';
/* look for the tag in this path. If found, then display it
* and exit.
*/
ptr = cktagdir(tag, dir);
if (ptr)
{
/* just supposed to display tag info? */
if (taginfo)
{
/* then do only that! */
if (strcmp(dir, "."))
{
printf("%s%c%s", dir, SLASH, ptr);
}
else
{
/* avoid leading "./" if possible */
fputs(ptr, stdout);
}
return 1;
}
else
{
/* else look up the declaration of the thing */
return lookup(dir, ptr);
}
}
}
/* if we get here, then the tag wasn't found anywhere */
return 0;
}
void usage()
{
fputs("usage: ref [-a] [-t] [-c class] [-f file] tag\n", stderr);
fputs(" -a function's args may be flush against left margin\n", stderr);
fputs(" -t output tag info, instead of the function header\n", stderr);
fputs(" -f File tag might be a static function in File\n", stderr);
fputs(" -c Class tag might be a member of class Class\n", stderr);
exit(2);
}
int countcolons(str)
char *str;
{
while (*str != ':' && *str)
{
str++;
}
if (str[0] != ':')
{
return 0;
}
else if (str[1] != ':')
{
return 1;
}
return 2;
}
int main(argc, argv)
int argc;
char **argv;
{
char def_tag[100]; /* used to build tag name with default file/class */
int i;
/* parse flags */
for (i = 1; i < argc && argv[i][0] == '-'; i++)
{
switch (argv[i][1])
{
case 't':
taginfo = 1;
break;
case 'f':
if (argv[i][2])
{
def_file = &argv[i][2];
}
else if (++i < argc)
{
def_file = argv[i];
}
else
{
usage();
}
break;
case 'c':
if (argv[i][2])
{
def_class = &argv[i][2];
}
else if (++i < argc)
{
def_class = argv[i];
}
else
{
usage();
}
break;
default:
usage();
}
}
/* if no tag was given, complain */
if (i + 1 != argc)
{
usage();
}
/* does the tag have an explicit class or file? */
colons = countcolons(argv[i]);
/* if not, then maybe try some defaults */
if (colons == 0)
{
/* try a static function in the file first */
if (def_file)
{
sprintf(def_tag, "%s:%s", def_file, argv[i]);
colons = 1;
if (find(def_tag))
{
exit(0);
}
}
/* try a member function for a class */
if (def_class)
{
sprintf(def_tag, "%s::%s", def_class, argv[i]);
colons = 2;
if (find(def_tag))
{
exit(0);
}
}
/* oh, well */
colons = 0;
}
/* find the tag */
if (find(argv[i]))
{
exit(0);
}
exit(1);
/*NOTREACHED*/
}

View file

@ -1,934 +0,0 @@
/* regexp.c */
/* This file contains the code that compiles regular expressions and executes
* them. It supports the same syntax and features as vi's regular expression
* code. Specifically, the meta characters are:
* ^ matches the beginning of a line
* $ matches the end of a line
* \< matches the beginning of a word
* \> matches the end of a word
* . matches any single character
* [] matches any character in a character class
* \( delimits the start of a subexpression
* \) delimits the end of a subexpression
* * repeats the preceding 0 or more times
* NOTE: You cannot follow a \) with a *.
*
* The physical structure of a compiled RE is as follows:
* - First, there is a one-byte value that says how many character classes
* are used in this regular expression
* - Next, each character class is stored as a bitmap that is 256 bits
* (32 bytes) long.
* - A mixture of literal characters and compiled meta characters follows.
* This begins with M_BEGIN(0) and ends with M_END(0). All meta chars
* are stored as a \n followed by a one-byte code, so they take up two
* bytes apiece. Literal characters take up one byte apiece. \n can't
* be used as a literal character.
*
* If NO_MAGIC is defined, then a different set of functions is used instead.
* That right, this file contains TWO versions of the code.
*/
#include <setjmp.h>
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
static char *previous; /* the previous regexp, used when null regexp is given */
#ifndef NO_MAGIC
/* THE REAL REGEXP PACKAGE IS USED UNLESS "NO_MAGIC" IS DEFINED */
/* These are used to classify or recognize meta-characters */
#define META '\0'
#define BASE_META(m) ((m) - 256)
#define INT_META(c) ((c) + 256)
#define IS_META(m) ((m) >= 256)
#define IS_CLASS(m) ((m) >= M_CLASS(0) && (m) <= M_CLASS(9))
#define IS_START(m) ((m) >= M_START(0) && (m) <= M_START(9))
#define IS_END(m) ((m) >= M_END(0) && (m) <= M_END(9))
#define IS_CLOSURE(m) ((m) >= M_SPLAT && (m) <= M_RANGE)
#define ADD_META(s,m) (*(s)++ = META, *(s)++ = BASE_META(m))
#define GET_META(s) (*(s) == META ? INT_META(*++(s)) : *s)
/* These are the internal codes used for each type of meta-character */
#define M_BEGLINE 256 /* internal code for ^ */
#define M_ENDLINE 257 /* internal code for $ */
#define M_BEGWORD 258 /* internal code for \< */
#define M_ENDWORD 259 /* internal code for \> */
#define M_ANY 260 /* internal code for . */
#define M_SPLAT 261 /* internal code for * */
#define M_PLUS 262 /* internal code for \+ */
#define M_QMARK 263 /* internal code for \? */
#define M_RANGE 264 /* internal code for \{ */
#define M_CLASS(n) (265+(n)) /* internal code for [] */
#define M_START(n) (275+(n)) /* internal code for \( */
#define M_END(n) (285+(n)) /* internal code for \) */
/* These are used during compilation */
static int class_cnt; /* used to assign class IDs */
static int start_cnt; /* used to assign start IDs */
static int end_stk[NSUBEXP];/* used to assign end IDs */
static int end_sp;
static char *retext; /* points to the text being compiled */
/* error-handling stuff */
jmp_buf errorhandler;
#define FAIL(why) regerror(why); longjmp(errorhandler, 1)
/* This function builds a bitmap for a particular class */
static char *makeclass(text, bmap)
REG char *text; /* start of the class */
REG char *bmap; /* the bitmap */
{
REG int i;
int complement = 0;
/* zero the bitmap */
for (i = 0; bmap && i < 32; i++)
{
bmap[i] = 0;
}
/* see if we're going to complement this class */
if (*text == '^')
{
text++;
complement = 1;
}
/* add in the characters */
while (*text && *text != ']')
{
/* is this a span of characters? */
if (text[1] == '-' && text[2])
{
/* spans can't be backwards */
if (text[0] > text[2])
{
FAIL("Backwards span in []");
}
/* add each character in the span to the bitmap */
for (i = text[0]; bmap && i <= text[2]; i++)
{
bmap[i >> 3] |= (1 << (i & 7));
}
/* move past this span */
text += 3;
}
else
{
/* add this single character to the span */
i = *text++;
if (bmap)
{
bmap[i >> 3] |= (1 << (i & 7));
}
}
}
/* make sure the closing ] is missing */
if (*text++ != ']')
{
FAIL("] missing");
}
/* if we're supposed to complement this class, then do so */
if (complement && bmap)
{
for (i = 0; i < 32; i++)
{
bmap[i] = ~bmap[i];
}
}
return text;
}
/* This function gets the next character or meta character from a string.
* The pointer is incremented by 1, or by 2 for \-quoted characters. For [],
* a bitmap is generated via makeclass() (if re is given), and the
* character-class text is skipped.
*/
static int gettoken(sptr, re)
char **sptr;
regexp *re;
{
int c;
c = **sptr;
++*sptr;
if (c == '\\')
{
c = **sptr;
++*sptr;
switch (c)
{
case '<':
return M_BEGWORD;
case '>':
return M_ENDWORD;
case '(':
if (start_cnt >= NSUBEXP)
{
FAIL("Too many \\(s");
}
end_stk[end_sp++] = start_cnt;
return M_START(start_cnt++);
case ')':
if (end_sp <= 0)
{
FAIL("Mismatched \\)");
}
return M_END(end_stk[--end_sp]);
case '*':
return (*o_magic ? c : M_SPLAT);
case '.':
return (*o_magic ? c : M_ANY);
case '+':
return M_PLUS;
case '?':
return M_QMARK;
#ifndef CRUNCH
case '{':
return M_RANGE;
#endif
default:
return c;
}
}
else if (*o_magic)
{
switch (c)
{
case '^':
if (*sptr == retext + 1)
{
return M_BEGLINE;
}
return c;
case '$':
if (!**sptr)
{
return M_ENDLINE;
}
return c;
case '.':
return M_ANY;
case '*':
return M_SPLAT;
case '[':
/* make sure we don't have too many classes */
if (class_cnt >= 10)
{
FAIL("Too many []s");
}
/* process the character list for this class */
if (re)
{
/* generate the bitmap for this class */
*sptr = makeclass(*sptr, re->program + 1 + 32 * class_cnt);
}
else
{
/* skip to end of the class */
*sptr = makeclass(*sptr, (char *)0);
}
return M_CLASS(class_cnt++);
default:
return c;
}
}
else /* unquoted nomagic */
{
switch (c)
{
case '^':
if (*sptr == retext + 1)
{
return M_BEGLINE;
}
return c;
case '$':
if (!**sptr)
{
return M_ENDLINE;
}
return c;
default:
return c;
}
}
/*NOTREACHED*/
}
/* This function calculates the number of bytes that will be needed for a
* compiled RE. Its argument is the uncompiled version. It is not clever
* about catching syntax errors; that is done in a later pass.
*/
static unsigned calcsize(text)
char *text;
{
unsigned size;
int token;
retext = text;
class_cnt = 0;
start_cnt = 1;
end_sp = 0;
size = 5;
while ((token = gettoken(&text, (regexp *)0)) != 0)
{
if (IS_CLASS(token))
{
size += 34;
}
#ifndef CRUNCH
else if (token == M_RANGE)
{
size += 4;
while ((token = gettoken(&text, (regexp *)0)) != 0
&& token != '}')
{
}
if (!token)
{
return size;
}
}
#endif
else if (IS_META(token))
{
size += 2;
}
else
{
size++;
}
}
return size;
}
/* This function compiles a regexp. */
regexp *regcomp(exp)
char *exp;
{
int needfirst;
unsigned size;
int token;
int peek;
char *build;
regexp *re;
#ifndef CRUNCH
int from;
int to;
int digit;
#endif
/* prepare for error handling */
re = (regexp *)0;
if (setjmp(errorhandler))
{
if (re)
{
free(re);
}
return (regexp *)0;
}
/* if an empty regexp string was given, use the previous one */
if (*exp == 0)
{
if (!previous)
{
FAIL("No previous RE");
}
exp = previous;
}
else /* non-empty regexp given, so remember it */
{
if (previous)
free(previous);
previous = (char *)malloc((unsigned)(strlen(exp) + 1));
if (previous)
strcpy(previous, exp);
}
/* allocate memory */
class_cnt = 0;
start_cnt = 1;
end_sp = 0;
retext = exp;
size = calcsize(exp) + sizeof(regexp) + 10; /* !!! 10 bytes for slop */
#ifdef lint
re = ((regexp *)0) + size;
#else
re = (regexp *)malloc((unsigned)size);
#endif
if (!re)
{
FAIL("Not enough memory for this RE");
}
/* compile it */
build = &re->program[1 + 32 * class_cnt];
re->program[0] = class_cnt;
for (token = 0; token < NSUBEXP; token++)
{
re->startp[token] = re->endp[token] = (char *)0;
}
re->first = 0;
re->bol = 0;
re->minlen = 0;
needfirst = 1;
class_cnt = 0;
start_cnt = 1;
end_sp = 0;
retext = exp;
for (token = M_START(0), peek = gettoken(&exp, re);
token;
token = peek, peek = gettoken(&exp, re))
{
/* special processing for the closure operator */
if (IS_CLOSURE(peek))
{
/* detect misuse of closure operator */
if (IS_START(token))
{
FAIL("Closure operator follows nothing");
}
else if (IS_META(token) && token != M_ANY && !IS_CLASS(token))
{
FAIL("Closure operators can only follow a normal character or . or []");
}
#ifndef CRUNCH
/* if \{ \} then read the range */
if (peek == M_RANGE)
{
from = 0;
for (digit = gettoken(&exp, re);
!IS_META(digit) && isdigit(digit);
digit = gettoken(&exp, re))
{
from = from * 10 + digit - '0';
}
if (digit == '}')
{
to = from;
}
else if (digit == ',')
{
to = 0;
for (digit = gettoken(&exp, re);
!IS_META(digit) && isdigit(digit);
digit = gettoken(&exp, re))
{
to = to * 10 + digit - '0';
}
if (to == 0)
{
to = 255;
}
}
if (digit != '}')
{
FAIL("Bad characters after \\{");
}
else if (to < from || to == 0 || from >= 255)
{
FAIL("Invalid range for \\{ \\}");
}
re->minlen += from;
}
else
#endif
if (peek != M_SPLAT)
{
re->minlen++;
}
/* it is okay -- make it prefix instead of postfix */
ADD_META(build, peek);
#ifndef CRUNCH
if (peek == M_RANGE)
{
*build++ = from;
*build++ = (to < 255 ? to : 255);
}
#endif
/* take care of "needfirst" - is this the first char? */
if (needfirst && peek == M_PLUS && !IS_META(token))
{
re->first = token;
}
needfirst = 0;
/* we used "peek" -- need to refill it */
peek = gettoken(&exp, re);
if (IS_CLOSURE(peek))
{
FAIL("* or \\+ or \\? doubled up");
}
}
else if (!IS_META(token))
{
/* normal char is NOT argument of closure */
if (needfirst)
{
re->first = token;
needfirst = 0;
}
re->minlen++;
}
else if (token == M_ANY || IS_CLASS(token))
{
/* . or [] is NOT argument of closure */
needfirst = 0;
re->minlen++;
}
/* the "token" character is not closure -- process it normally */
if (token == M_BEGLINE)
{
/* set the BOL flag instead of storing M_BEGLINE */
re->bol = 1;
}
else if (IS_META(token))
{
ADD_META(build, token);
}
else
{
*build++ = token;
}
}
/* end it with a \) which MUST MATCH the opening \( */
ADD_META(build, M_END(0));
if (end_sp > 0)
{
FAIL("Not enough \\)s");
}
return re;
}
/*---------------------------------------------------------------------------*/
/* This function checks for a match between a character and a token which is
* known to represent a single character. It returns 0 if they match, or
* 1 if they don't.
*/
int match1(re, ch, token)
regexp *re;
REG char ch;
REG int token;
{
if (!ch)
{
/* the end of a line can't match any RE of width 1 */
return 1;
}
if (token == M_ANY)
{
return 0;
}
else if (IS_CLASS(token))
{
if (re->program[1 + 32 * (token - M_CLASS(0)) + (ch >> 3)] & (1 << (ch & 7)))
return 0;
}
else if (ch == token || *o_ignorecase && tolower(ch) == tolower(token))
{
return 0;
}
return 1;
}
/* This function checks characters up to and including the next closure, at
* which point it does a recursive call to check the rest of it. This function
* returns 0 if everything matches, or 1 if something doesn't match.
*/
int match(re, str, prog, here)
regexp *re; /* the regular expression */
char *str; /* the string */
REG char *prog; /* a portion of re->program, an compiled RE */
REG char *here; /* a portion of str, the string to compare it to */
{
REG int token; /* the roken pointed to by prog */
REG int nmatched;/* counter, used during closure matching */
REG int closure;/* the token denoting the type of closure */
int from; /* minimum number of matches in closure */
int to; /* maximum number of matches in closure */
for (token = GET_META(prog); !IS_CLOSURE(token); prog++, token = GET_META(prog))
{
switch (token)
{
/*case M_BEGLINE: can't happen; re->bol is used instead */
case M_ENDLINE:
if (*here)
return 1;
break;
case M_BEGWORD:
if (here != str &&
(here[-1] == '_' || isalnum(here[-1])))
return 1;
break;
case M_ENDWORD:
if (here[0] == '_' || isalnum(here[0]))
return 1;
break;
case M_START(0):
case M_START(1):
case M_START(2):
case M_START(3):
case M_START(4):
case M_START(5):
case M_START(6):
case M_START(7):
case M_START(8):
case M_START(9):
re->startp[token - M_START(0)] = (char *)here;
break;
case M_END(0):
case M_END(1):
case M_END(2):
case M_END(3):
case M_END(4):
case M_END(5):
case M_END(6):
case M_END(7):
case M_END(8):
case M_END(9):
re->endp[token - M_END(0)] = (char *)here;
if (token == M_END(0))
{
return 0;
}
break;
default: /* literal, M_CLASS(n), or M_ANY */
if (match1(re, *here, token) != 0)
return 1;
here++;
}
}
/* C L O S U R E */
/* step 1: see what we have to match against, and move "prog" to point
* to the remainder of the compiled RE.
*/
closure = token;
prog++;
switch (closure)
{
case M_SPLAT:
from = 0;
to = strlen(str); /* infinity */
break;
case M_PLUS:
from = 1;
to = strlen(str); /* infinity */
break;
case M_QMARK:
from = 0;
to = 1;
break;
#ifndef CRUNCH
case M_RANGE:
from = UCHAR(*prog++);
to = UCHAR(*prog++);
if (to == 255)
{
to = strlen(str); /* infinity */
}
break;
#endif
}
token = GET_META(prog);
prog++;
/* step 2: see how many times we can match that token against the string */
for (nmatched = 0;
nmatched < to && *here && match1(re, *here, token) == 0;
nmatched++, here++)
{
}
/* step 3: try to match the remainder, and back off if it doesn't */
while (nmatched >= from && match(re, str, prog, here) != 0)
{
nmatched--;
here--;
}
/* so how did it work out? */
if (nmatched >= from)
return 0;
return 1;
}
/* This function searches through a string for text that matches an RE. */
int regexec(re, str, bol)
regexp *re; /* the compiled regexp to search for */
char *str; /* the string to search through */
int bol; /* boolean: does str start at the beginning of a line? */
{
char *prog; /* the entry point of re->program */
int len; /* length of the string */
REG char *here;
/* if must start at the beginning of a line, and this isn't, then fail */
if (re->bol && !bol)
{
return 0;
}
len = strlen(str);
prog = re->program + 1 + 32 * re->program[0];
/* search for the RE in the string */
if (re->bol)
{
/* must occur at BOL */
if ((re->first
&& match1(re, *(char *)str, re->first))/* wrong first letter? */
|| len < re->minlen /* not long enough? */
|| match(re, (char *)str, prog, str)) /* doesn't match? */
return 0; /* THEN FAIL! */
}
#ifndef CRUNCH
else if (!*o_ignorecase)
{
/* can occur anywhere in the line, noignorecase */
for (here = (char *)str;
(re->first && re->first != *here)
|| match(re, (char *)str, prog, here);
here++, len--)
{
if (len < re->minlen)
return 0;
}
}
#endif
else
{
/* can occur anywhere in the line, ignorecase */
for (here = (char *)str;
(re->first && match1(re, *here, (int)re->first))
|| match(re, (char *)str, prog, here);
here++, len--)
{
if (len < re->minlen)
return 0;
}
}
/* if we didn't fail, then we must have succeeded */
return 1;
}
/*============================================================================*/
#else /* NO_MAGIC */
regexp *regcomp(exp)
char *exp;
{
char *src;
char *dest;
regexp *re;
int i;
/* allocate a big enough regexp structure */
#ifdef lint
re = (regexp *)0;
#else
re = (regexp *)malloc((unsigned)(strlen(exp) + 1 + sizeof(struct regexp)));
#endif
if (!re)
{
regerror("Could not malloc a regexp structure");
return (regexp *)0;
}
/* initialize all fields of the structure */
for (i = 0; i < NSUBEXP; i++)
{
re->startp[i] = re->endp[i] = (char *)0;
}
re->minlen = 0;
re->first = 0;
re->bol = 0;
/* copy the string into it, translating ^ and $ as needed */
for (src = exp, dest = re->program + 1; *src; src++)
{
switch (*src)
{
case '^':
if (src == exp)
{
re->bol += 1;
}
else
{
*dest++ = '^';
re->minlen++;
}
break;
case '$':
if (!src[1])
{
re->bol += 2;
}
else
{
*dest++ = '$';
re->minlen++;
}
break;
case '\\':
if (src[1])
{
*dest++ = *++src;
re->minlen++;
}
else
{
regerror("extra \\ at end of regular expression");
}
break;
default:
*dest++ = *src;
re->minlen++;
}
}
*dest = '\0';
return re;
}
/* This "helper" function checks for a match at a given location. It returns
* 1 if it matches, 0 if it doesn't match here but might match later on in the
* string, or -1 if it could not possibly match
*/
static int reghelp(prog, string, bolflag)
struct regexp *prog;
char *string;
int bolflag;
{
char *scan;
char *str;
/* if ^, then require bolflag */
if ((prog->bol & 1) && !bolflag)
{
return -1;
}
/* if it matches, then it will start here */
prog->startp[0] = string;
/* compare, possibly ignoring case */
if (*o_ignorecase)
{
for (scan = &prog->program[1]; *scan; scan++, string++)
if (tolower(*scan) != tolower(*string))
return *string ? 0 : -1;
}
else
{
for (scan = &prog->program[1]; *scan; scan++, string++)
if (*scan != *string)
return *string ? 0 : -1;
}
/* if $, then require string to end here, too */
if ((prog->bol & 2) && *string)
{
return 0;
}
/* if we get to here, it matches */
prog->endp[0] = string;
return 1;
}
int regexec(prog, string, bolflag)
struct regexp *prog;
char *string;
int bolflag;
{
int rc;
/* keep trying to match it */
for (rc = reghelp(prog, string, bolflag); rc == 0; rc = reghelp(prog, string, 0))
{
string++;
}
/* did we match? */
return rc == 1;
}
#endif

View file

@ -1,21 +0,0 @@
/*
* Definitions etc. for regexp(3) routines.
*
* Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
* not the System V one.
*/
#define NSUBEXP 10
typedef struct regexp {
char *startp[NSUBEXP];
char *endp[NSUBEXP];
int minlen; /* length of shortest possible match */
char first; /* first character, if known; else \0 */
char bol; /* boolean: must start at beginning of line? */
char program[1]; /* Unwarranted chumminess with compiler. */
} regexp;
extern regexp *regcomp();
extern int regexec();
extern void regsub();
extern void regerror();

View file

@ -1,243 +0,0 @@
/* regsub.c */
/* This file contains the regsub() function, which performs substitutions
* after a regexp match has been found.
*/
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
/* perform substitutions after a regexp match */
void regsub(re, src, dst)
regexp *re; /* the regexp with pointers into matched text */
REG char *src; /* the replacement string */
REG char *dst; /* where to put the result of the subst */
{
REG char *cpy; /* pointer to start of text to copy */
REG char *end; /* pointer to end of text to copy */
REG char c;
char *start;
#ifndef CRUNCH
int mod = 0;/* used to track \U, \L, \u, \l, and \E */
int len; /* used to calculate length of subst string */
static char *prev; /* a copy of the text from the previous subst */
/* replace \~ (or maybe ~) by previous substitution text */
/* step 1: calculate the length of the new substitution text */
for (len = strlen(src), c = '\0', cpy = src; *cpy; cpy++)
{
# ifdef NO_MAGIC
if (c == '\\' && *cpy == '~')
# else
if (c == (*o_magic ? '\0' : '\\') && *cpy == '~')
# endif
{
if (!prev)
{
regerror("No prev text to substitute for ~");
return;
}
len += strlen(prev) - 1;
# ifndef NO_MAGIC
if (!*o_magic)
# endif
len -= 1; /* because we lose the \ too */
}
/* watch backslash quoting */
if (c != '\\' && *cpy == '\\')
c = '\\';
else
c = '\0';
}
/* allocate memory for the ~ed version of src */
start = cpy = (char *)malloc((unsigned)(len + 1));
if (!cpy)
{
regerror("Not enough memory for ~ expansion");
return;
}
/* copy src into start, replacing the ~s by the previous text */
while (*src)
{
# ifndef NO_MAGIC
if (*o_magic && *src == '~')
{
strcpy(cpy, prev);
cpy += strlen(prev);
src++;
}
else if (!*o_magic && *src == '\\' && *(src + 1) == '~')
# else /* NO_MAGIC */
if (*src == '\\' && *(src + 1) == '~')
# endif /* NO_MAGIC */
{
strcpy(cpy, prev);
cpy += strlen(prev);
src += 2;
}
else
{
*cpy++ = *src++;
}
}
*cpy = '\0';
#ifdef DEBUG
if ((int)(cpy - start) != len)
{
msg("Bug in regsub.c! Predicted length = %d, Actual length = %d", len, (int)(cpy - start));
}
#endif
/* remember this as the "previous" for next time */
if (prev)
free(prev);
prev = src = start;
#endif /* undef CRUNCH */
start = src;
while ((c = *src++) != '\0')
{
#ifndef NO_MAGIC
/* recognize any meta characters */
if (c == '&' && *o_magic)
{
cpy = re->startp[0];
end = re->endp[0];
}
else
#endif /* not NO_MAGIC */
if (c == '\\')
{
c = *src++;
switch (c)
{
#ifndef NO_MAGIC
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* \0 thru \9 mean "copy subexpression" */
c -= '0';
cpy = re->startp[c];
end = re->endp[c];
break;
# ifndef CRUNCH
case 'U':
case 'u':
case 'L':
case 'l':
/* \U and \L mean "convert to upper/lowercase" */
mod = c;
continue;
case 'E':
case 'e':
/* \E ends the \U or \L */
mod = 0;
continue;
# endif /* not CRUNCH */
case '&':
/* "\&" means "original text" */
if (*o_magic)
{
*dst++ = c;
continue;
}
cpy = re->startp[0];
end = re->endp[0];
break;
#else /* NO_MAGIC */
case '&':
/* "\&" means "original text" */
cpy = re->startp[0];
end = re->endp[0];
break;
#endif /* NO_MAGIC */
default:
/* ordinary char preceded by backslash */
*dst++ = c;
continue;
}
}
#ifndef CRUNCH
# if OSK
else if (c == '\l')
# else
else if (c == '\r')
# endif
{
/* transliterate ^M into newline */
*dst++ = '\n';
continue;
}
#endif /* !CRUNCH */
else
{
/* ordinary character, so just copy it */
*dst++ = c;
continue;
}
/* Note: to reach this point in the code, we must have evaded
* all "continue" statements. To do that, we must have hit
* a metacharacter that involves copying.
*/
/* if there is nothing to copy, loop */
if (!cpy)
continue;
/* copy over a portion of the original */
while (cpy < end)
{
#ifndef NO_MAGIC
# ifndef CRUNCH
switch (mod)
{
case 'U':
case 'u':
/* convert to uppercase */
*dst++ = toupper(*cpy++);
break;
case 'L':
case 'l':
/* convert to lowercase */
*dst++ = tolower(*cpy++);
break;
default:
/* copy without any conversion */
*dst++ = *cpy++;
}
/* \u and \l end automatically after the first char */
if (mod && (mod == 'u' || mod == 'l'))
{
mod = 0;
}
# else /* CRUNCH */
*dst++ = *cpy++;
# endif /* CRUNCH */
#else /* NO_MAGIC */
*dst++ = *cpy++;
#endif /* NO_MAGIC */
}
}
*dst = '\0';
}

View file

@ -1,415 +0,0 @@
/* system.c -- UNIX version */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains a new version of the system() function and related stuff.
*
* Entry points are:
* system(cmd) - run a single shell command
* wildcard(names) - expand wildcard characters in filanames
* filter(m,n,cmd,back) - run text lines through a filter program
*
* This is probably the single least portable file in the program. The code
* shown here should work correctly if it links at all; it will work on UNIX
* and any O.S./Compiler combination which adheres to UNIX forking conventions.
*/
#include "config.h"
#include "vi.h"
extern char **environ;
#if ANY_UNIX
/* This is a new version of the system() function. The only difference
* between this one and the library one is: this one uses the o_shell option.
*/
int system(cmd)
char *cmd; /* a command to run */
{
int pid; /* process ID of child */
int died;
int status; /* exit status of the command */
signal(SIGINT, SIG_IGN);
pid = fork();
switch (pid)
{
case -1: /* error */
msg("fork() failed");
status = -1;
break;
case 0: /* child */
/* for the child, close all files except stdin/out/err */
for (status = 3; status < 60 && (close(status), errno != EINVAL); status++)
{
}
signal(SIGINT, SIG_DFL);
if (cmd == o_shell)
{
execle(o_shell, o_shell, (char *)0, environ);
}
else
{
execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
}
msg("execle(\"%s\", ...) failed", o_shell);
exit(1); /* if we get here, the exec failed */
default: /* parent */
do
{
died = wait(&status);
} while (died >= 0 && died != pid);
if (died < 0)
{
status = -1;
}
signal(SIGINT, (void (*)()) trapint);
}
return status;
}
/* This private function opens a pipe from a filter. It is similar to the
* system() function above, and to popen(cmd, "r").
*/
int rpipe(cmd, in)
char *cmd; /* the filter command to use */
int in; /* the fd to use for stdin */
{
int r0w1[2];/* the pipe fd's */
/* make the pipe */
if (pipe(r0w1) < 0)
{
return -1; /* pipe failed */
}
/* The parent process (elvis) ignores signals while the filter runs.
* The child (the filter program) will reset this, so that it can
* catch the signal.
*/
signal(SIGINT, SIG_IGN);
switch (fork())
{
case -1: /* error */
return -1;
case 0: /* child */
/* close the "read" end of the pipe */
close(r0w1[0]);
/* redirect stdout to go to the "write" end of the pipe */
close(1);
dup(r0w1[1]);
close(2);
dup(r0w1[1]);
close(r0w1[1]);
/* redirect stdin */
if (in != 0)
{
close(0);
dup(in);
close(in);
}
/* the filter should accept SIGINT signals */
signal(SIGINT, SIG_DFL);
/* exec the shell to run the command */
execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
exit(1); /* if we get here, exec failed */
default: /* parent */
/* close the "write" end of the pipe */
close(r0w1[1]);
return r0w1[0];
}
}
#endif /* non-DOS */
#if OSK
/* This private function opens a pipe from a filter. It is similar to the
* system() function above, and to popen(cmd, "r").
*/
int rpipe(cmd, in)
char *cmd; /* the filter command to use */
int in; /* the fd to use for stdin */
{
return osk_popen(cmd, "r", in, 0);
}
#endif
#if ANY_UNIX || OSK
/* This function closes the pipe opened by rpipe(), and returns 0 for success */
int rpclose(fd)
int fd;
{
int status;
close(fd);
wait(&status);
signal(SIGINT, (void (*)()) trapint);
return status;
}
#endif /* non-DOS */
/* This function expands wildcards in a filename or filenames. It does this
* by running the "echo" command on the filenames via the shell; it is assumed
* that the shell will expand the names for you. If for any reason it can't
* run echo, then it returns the names unmodified.
*/
#if MSDOS || TOS
#define PROG "wildcard "
#define PROGLEN 9
#include <string.h>
#else
#define PROG "echo "
#define PROGLEN 5
#endif
#if !AMIGA
char *wildcard(names)
char *names;
{
# if VMS
/*
We could use expand() [vmswild.c], but what's the point on VMS?
Anyway, echo is the wrong thing to do, it takes too long to build
a subprocess on VMS and any "echo" program would have to be supplied
by elvis. More importantly, many VMS utilities expand names
themselves (the shell doesn't do any expansion) so the concept is
non-native. jdc
*/
return names;
# else
int i, j, fd;
REG char *s, *d;
/* build the echo command */
if (names != tmpblk.c)
{
/* the names aren't in tmpblk.c, so we can do it the easy way */
strcpy(tmpblk.c, PROG);
strcat(tmpblk.c, names);
}
else
{
/* the names are already in tmpblk.c, so shift them to make
* room for the word "echo "
*/
for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; )
{
*--d = *--s;
}
strncpy(names, PROG, PROGLEN);
}
/* run the command & read the resulting names */
fd = rpipe(tmpblk.c, 0);
if (fd < 0) return names;
i = 0;
do
{
j = tread(fd, tmpblk.c + i, BLKSIZE - i);
i += j;
} while (j > 0);
/* successful? */
if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0)
{
tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */
return tmpblk.c;
}
else
{
return names;
}
# endif
}
#endif
/* This function runs a range of lines through a filter program, and replaces
* the original text with the filtered version. As a special case, if "to"
* is MARK_UNSET, then it runs the filter program with stdin coming from
* /dev/null, and inserts any output lines.
*/
int filter(from, to, cmd, back)
MARK from, to; /* the range of lines to filter */
char *cmd; /* the filter command */
int back; /* boolean: will we read lines back? */
{
int scratch; /* fd of the scratch file */
int fd; /* fd of the pipe from the filter */
char scrout[50]; /* name of the scratch out file */
MARK new; /* place where new text should go */
long sent, rcvd; /* number of lines sent/received */
int i, j;
/* write the lines (if specified) to a temp file */
if (to)
{
/* we have lines */
#if MSDOS || TOS
strcpy(scrout, o_directory);
if ((i=strlen(scrout)) && !strchr("\\/:", scrout[i-1]))
scrout[i++]=SLASH;
strcpy(scrout+i, SCRATCHOUT+3);
#else
sprintf(scrout, SCRATCHOUT, o_directory);
#endif
mktemp(scrout);
cmd_write(from, to, CMD_BANG, FALSE, scrout);
sent = markline(to) - markline(from) + 1L;
/* use those lines as stdin */
scratch = open(scrout, O_RDONLY);
if (scratch < 0)
{
unlink(scrout);
return -1;
}
}
else
{
scratch = 0;
sent = 0L;
}
/* start the filter program */
#if VMS
/*
VMS doesn't know a thing about file descriptor 0. The rpipe
concept is non-portable. Hence we need a file name argument.
*/
fd = rpipe(cmd, scratch, scrout);
#else
fd = rpipe(cmd, scratch);
#endif
if (fd < 0)
{
if (to)
{
close(scratch);
unlink(scrout);
}
return -1;
}
if (back)
{
ChangeText
{
/* adjust MARKs for whole lines, and set "new" */
from &= ~(BLKSIZE - 1);
if (to)
{
to &= ~(BLKSIZE - 1);
to += BLKSIZE;
new = to;
}
else
{
new = from + BLKSIZE;
}
#if VMS
/* Reading from a VMS mailbox (pipe) is record oriented... */
# define tread vms_pread
#endif
/* repeatedly read in new text and add it */
rcvd = 0L;
while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
{
tmpblk.c[i] = '\0';
add(new, tmpblk.c);
#if VMS
/* What! An advantage to record oriented reads? */
new += (i - 1);
new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
rcvd++;
#else
for (i = 0; tmpblk.c[i]; i++)
{
if (tmpblk.c[i] == '\n')
{
new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
rcvd++;
}
else
{
new++;
}
}
#endif
}
}
/* delete old text, if any */
if (to)
{
cut(from, to);
delete(from, to);
}
}
else
{
/* read the command's output, and copy it to the screen */
while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
{
for (j = 0; j < i; j++)
{
addch(tmpblk.c[j]);
}
}
rcvd = 0;
}
/* Reporting... */
if (sent >= *o_report || rcvd >= *o_report)
{
if (sent > 0L && rcvd > 0L)
{
msg("%ld lines out, %ld lines back", sent, rcvd);
}
else if (sent > 0)
{
msg("%ld lines written to filter", sent);
}
else
{
msg("%ld lines read from filter", rcvd);
}
}
rptlines = 0L;
/* cleanup */
rpclose(fd);
if (to)
{
close(scratch);
unlink(scrout);
}
return 0;
}

View file

@ -1,230 +0,0 @@
/* tinyprnt.c */
#if OSK
#define sprintf Sprintf
#endif
/* This is a limited version of sprintf(). It is useful for Minix-PC and
* Coherent-286 because those systems are both limited to 64k+64k and the
* standard sprintf() is just too damn big.
*
* It should also be useful for OS-9 because OS-9's sprintf() doesn't
* understand the true meaning of asterisks in a format string. This one
* does.
*/
/* Place-holders in format strings look like "%<pad><clip><type>".
*
* The <pad> adds space to the front (or, if negative, to the back) of the
* output value, to pad it to a given width. If <pad> is absent, then 0 is
* assumed. If <pad> is an asterisk, then the next argument is assumed to
* be an (int) which used as the pad width.
*
* The <clip> string can be absent, in which case no clipping is done.
* However, if it is present, then it should be either a "." followed by
* a number, or a "." followed by an asterisk. The asterisk means that the
* next argument is an (int) which should be used as the pad width. Clipping
* only affects strings; for other data types it is ignored.
*
* The <type> is one of "s" for strings, "c" for characters (really ints that
* are assumed to be legal char values), "d" for ints, "ld" for long ints, or
* "%" to output a percent sign.
*/
/* NOTE: Variable argument lists are handled by direct stack-twiddling. Sorry! */
static void cvtnum(buf, num, base)
char *buf; /* where to store the number */
unsigned long num; /* the number to convert */
int base; /* either 8, 10, or 16 */
{
static char digits[] = "0123456789abcdef";
unsigned long tmp;
/* if the number is 0, then just stuff a "0" into the buffer */
if (num == 0L)
{
buf[0] = '0';
buf[1] = '\0';
return;
}
/* use tmp to figure out how many digits we'll need */
for (tmp = num; tmp > 0; tmp /= base)
{
buf++;
}
/* mark the spot that will be the end of the string */
*buf = '\0';
/* generate all digits, as needed */
for (tmp = num; tmp > 0; tmp /= base)
{
*--buf = digits[tmp % base];
}
}
int sprintf(buf, fmt, argref)
char *buf; /* where to deposit the formatted output */
char *fmt; /* the format string */
int argref; /* the first argument is located at &argref */
{
char *argptr;/* pointer to next argument on the stack */
int pad; /* value of the pad string */
int clip; /* value of the clip string */
long num; /* a binary number being converted to ASCII digits */
long digit; /* used during conversion */
char *src, *dst;
/* make argptr point to the first argument after the format string */
argptr = (char *)&argref;
/* loop through the whole format string */
while (*fmt)
{
/* if not part of a place-holder, then copy it literally */
if (*fmt != '%')
{
*buf++ = *fmt++;
continue;
}
/* found a place-holder! Get <pad> value */
fmt++;
if ('*' == *fmt)
{
pad = *((int *)argptr)++;
fmt++;
}
else if (*fmt == '-' || (*fmt >= '0' && *fmt <= '9'))
{
pad = atol(fmt);
do
{
fmt++;
} while (*fmt >= '0' && *fmt <= '9');
}
else
{
pad = 0;
}
/* get a <clip> value */
if (*fmt == '.')
{
fmt++;
if ('*' == *fmt)
{
clip = *((int *)argptr)++;
fmt++;
}
else if (*fmt >= '0' && *fmt <= '9')
{
clip = atol(fmt);
do
{
fmt++;
} while (*fmt >= '0' && *fmt <= '9');
}
}
else
{
clip = 0;
}
/* handle <type>, possibly noticing <clip> */
switch (*fmt++)
{
case 'c':
buf[0] = *((int *)argptr)++;
buf[1] = '\0';
break;
case 's':
src = *((char **)argptr)++;
if (!src)
{
src = "(null)";
}
if (clip)
{
strncpy(buf, src, clip);
buf[clip] = '\0';
}
else
{
strcpy(buf, src);
}
break;
case 'l':
fmt++; /* to skip the "d" in "%ld" */
num = *((long *)argptr)++;
dst = buf;
if (num < 0)
{
*dst++ = '-';
num = -num;
}
cvtnum(dst, num, 10);
break;
case 'x':
num = *((int *)argptr)++;
cvtnum(buf, num, 16);
break;
case 'd':
num = *((int *)argptr)++;
dst = buf;
if (num < 0)
{
*dst++ = '-';
num = -num;
}
cvtnum(dst, num, 10);
break;
default:
buf[0] = fmt[-1];
buf[1] = '\0';
}
/* now fix the padding, if the value is too short */
clip = strlen(buf);
if (pad < 0)
{
/* add spaces after the value */
pad = -pad - clip;
for (buf += clip; pad > 0; pad--)
{
*buf++ = ' ';
}
*buf = '\0';
}
else
{
/* add spaces before the value */
pad -= clip;
if (pad > 0)
{
src = buf + clip;
dst = src + pad;
*dst = '\0';
while (src > buf)
{
*--dst = *--src;
}
while (dst > buf)
{
*--dst = ' ';
}
}
buf += strlen(buf);
}
}
/* mark the end of the output string */
*buf = '\0';
}

View file

@ -1,388 +0,0 @@
/* tinytcap.c */
/* This file contains functions which simulate the termcap functions.
*
* It doesn't access a "termcap" file. Instead, it uses an initialized array
* of strings to store the entries. Any string that doesn't start with a ':'
* is taken to be the name of a type of terminal. Any string that does start
* with a ':' is interpretted as the list of fields describing all of the
* terminal types that precede it.
*
* Note: since these are C strings, you can't use special sequences like
* ^M or \E in the fields; your C compiler won't understand them. Also,
* at run time there is no way to tell the difference between ':' and '\072'
* so I sure hope your terminal definition doesn't require a ':' character.
*
* getenv(TERM) on VMS checks the SET TERM device setting. To implement
* non-standard terminals set the logical ELVIS_TERM in VMS. (jdc)
*
* Other possible terminal types are...
* TERM_WYSE925 - "wyse925", a Wyse 50 terminal emulating Televideo 925
* ... or you could set $TERMCAP to the terminal's description string, which
* $TERM set up to match it.
*
* Note that you can include several terminal types at the same time. Elvis
* chooses which entry to use at runtime, based primarily on the value of $TERM.
*/
#include "config.h"
extern char *getenv();
/* decide which terminal descriptions should *always* be included. */
#if MSDOS
# define TERM_NANSI
# define TERM_DOSANSI
# if RAINBOW
# define TERM_RAINBOW
# endif
#endif
#if VMS
# define TERM_VT100
# define TERM_VT100W
# define TERM_VT52
#endif
#if AMIGA
# define TERM_AMIGA /* Internal Amiga termcap entry */
/* # define TERM_VT52 /* The rest of these are here for those */
# define TERM_VT100 /* people who want to use elvis over an */
/* # define TERM_NANSI /* AUX: port (serial.device). */
/* # define TERM_DOSANSI /* Take out all but AMIGA to save memory. */
/* # define TERM_MINIX /* Vanilla ANSI? */
/* # define TERM_925 /* Hang a terminal off your Amiga */
#endif
#if MINIX || UNIXV
# define TERM_MINIX
#endif
#if COHERENT
# define TERM_COHERENT
#endif
#if TOS
# define TERM_ATARI
#endif
static char *termcap[] =
{
#ifdef TERM_AMIGA
"AA",
"amiga",
"Amiga ANSI",
/* Amiga termcap modified from version 1.3 by Kent Polk */
":co#80:li#24:am:bs:bw:xn:\
:AL=\233%dL:DC=\233%dP:DL=\233%dM:DO=\233%dB:\
:LE=\233%dD:RI=\233%dC:SF=\233%dS:SR=\233%dT:UP=\233%dA:IC=\233%d@:\
:ae=\2330m:al=\233L:as=\2333m:bl=\007:bt=\233Z:cd=\233J:\
:ce=\233K:cl=\013:cm=\233%i%d;%dH:dc=\233P:dl=\233M:do=\233B:\
:kb=^H:ho=\233H:ic=\233@:is=\23320l:\
:mb=\2337;2m:md=\2331m:me=\2330m:mh=\2332m:mk=\2338m:mr=\2337m:nd=\233C:\
:rs=\033c:se=\2330m:sf=\233S:so=\2337m:sb=\233T:sr=\233T:ue=\23323m:\
:up=\233A:us=\2334m:vb=\007:ve=\233\040p:vi=\2330\040p:\
:k1=\2330~:k2=\2331~:k3=\2332~:k4=\2333~:k5=\2334~:\
:k6=\2335~:k7=\2336~:k8=\2337~:k9=\2338~:k0=\2339~:\
:s1=\23310~:s2=\23311~:s3=\23312~:s4=\23313~:s5=\23314~:\
:s6=\23315~:s7=\23316~:s8=\23317~:s9=\23318~:s0=\23319~:\
:kd=\233B:kl=\233D:kn#10:kr=\233C:ku=\233A:le=\233D:\
:kP=\233T:kN=\233S:kh=\233\040A:kH=\233\040@:",
#endif
#ifdef TERM_NANSI
"fansi",
"nnansi",
"nansi",
"pcbios",
":al=\033[L:dl=\033[M:am:bs:ce=\033[K:cl=\033[2J:\
:cm=\033[%i%d;%dH:co#80:do=\033[B:\
:k1=#;:k2=#<:k3=#=:k4=#>:k5=#?:k6=#@:k7=#A:k8=#B:k9=#C:k0=#D:\
:s1=#T:s2=#U:s3=#V:s4=#W:s5=#X:s6=#Y:s7=#Z:s8=#[:s9=#\\:s0=#]:\
:c1=#^:c2=#_:c3=#`:c4=#a:c5=#b:c6=#c:c7=#d:c8=#e:c9=#f:c0=#g:\
:a1=#h:a2=#i:a3=#j:a4=#k:a5=#l:a6=#m:a7=#n:a8=#o:a9=#p:a0=#q:\
:kd=#P:kh=#G:kH=#O:kI=#R:kl=#K:kN=#Q:kP=#I:kr=#M:ku=#H:\
:li#25:md=\033[1m:me=\033[m:nd=\033[C:se=\033[m:so=\033[7m:\
:ue=\033[m:up=\033[A:us=\033[4m:",
#endif
#ifdef TERM_DOSANSI
#if !ANY_UNIX
"ansi",
#endif
"dosansi",
":am:bs:ce=\033[K:cl=\033[2J:\
:cm=\033[%i%d;%dH:co#80:do=\033[B:\
:k1=#;:k2=#<:k3=#=:k4=#>:k5=#?:k6=#@:k7=#A:k8=#B:k9=#C:k0=#D:\
:s1=#T:s2=#U:s3=#V:s4=#W:s5=#X:s6=#Y:s7=#Z:s8=#[:s9=#\\:s0=#]:\
:c1=#^:c2=#_:c3=#`:c4=#a:c5=#b:c6=#c:c7=#d:c8=#e:c9=#f:c0=#g:\
:a1=#h:a2=#i:a3=#j:a4=#k:a5=#l:a6=#m:a7=#n:a8=#o:a9=#p:a0=#q:\
:kd=#P:kh=#G:kH=#O:kI=#R:kl=#K:kN=#Q:kP=#I:kr=#M:ku=#H:\
:li#25:md=\033[1m:me=\033[m:nd=\033[C:se=\033[m:so=\033[7m:\
:ue=\033[m:up=\033[A:us=\033[4m:",
#endif
#ifdef TERM_RAINBOW
"vt220",
"rainbow",
":al=\033[L:dl=\033[M:am:bs:ce=\033[K:cl=\033[2J:\
:cm=\033[%i%d;%dH:co#80:do=\033[B:kd=\033[B:kl=\033[D:\
:kr=\033[C:ku=\033[A:kP=\033[5~:kN=\033[6~:kI=\033[2~:\
:li#24:md=\033[1m:me=\033[m:nd=\033[C:se=\033[m:so=\033[7m:\
:ue=\033[m:up=\033[A:us=\033[4m:xn:",
#endif
#ifdef TERM_VT100
"vt100-80",
"vt200-80",
"vt300-80",
"vt101-80",
"vt102-80",
":al=\033[L:am:bs:ce=\033[K:cl=\033[2J:cm=\033[%i%d;%dH:\
:co#80:dl=\033[M:do=\033[B:k0=\033[20~:k1=\033[1~:\
:k2=\033[2~:k3=\033[3~:k4=\033[4~:k5=\033[5~:k6=\033[6~:\
:k7=\033[17~:k8=\033[18~:k9=\033[19~:kd=\033[B:kh=\033[H:\
:kH=\033[Y:kI=\033[I:kl=\033[D:kN=\033[U:kP=\033[V:\
:kr=\033[C:ku=\033[A:li#24:md=\033[1m:me=\033[m:nd=\033[C:\
:se=\033[m:so=\033[7m:ti=\033[1;24r\033[24;1H:\
:ue=\033[m:up=\033[A:us=\033[4m:xn:",
#endif
#ifdef TERM_VT100W
"vt100-w",
"vt200-w",
"vt300-w",
"vt101-w",
"vt102-w",
"vt100-132",
"vt200-132",
"vt300-132",
"vt101-132",
"vt102-132",
":al=\033[L:am:bs:ce=\033[K:cl=\033[2J:cm=\033[%i%d;%dH:\
:co#132:dl=\033[M:do=\033[B:k0=\033[20~:k1=\033[1~:\
:k2=\033[2~:k3=\033[3~:k4=\033[4~:k5=\033[5~:k6=\033[6~:\
:k7=\033[17~:k8=\033[18~:k9=\033[19~:kd=\033[B:kh=\033[H:\
:kH=\033[Y:kI=\033[I:kl=\033[D:kN=\033[U:kP=\033[V:\
:kr=\033[C:ku=\033[A:li#24:md=\033[1m:me=\033[m:nd=\033[C:\
:se=\033[m:so=\033[7m:ti=\033[1;24r\033[24;1H:\
:ue=\033[m:up=\033[A:us=\033[4m:xn:",
#endif
#ifdef TERM_VT52
"vt52",
":do=\n:le=\b:up=\033A:nd=\033C:cm=\033Y%+ %+ :ti=\033e\033v:\
:sr=\033I:cd=\033J:ce=\033K:cl=\033H\033J:co#80:li#24:\
:ku=\033A:kd=\033B:kr=\033C:kl=\033D:kb=\b:pt:am:xn:bs:",
#endif
#ifdef TERM_MINIX
"minix",
"ansi",
"AT386",
":al=\033[L:am:bs:ce=\033[K:cl=\033[2J:cm=\033[%i%d;%dH:\
:co#80:dl=\033[M:do=\033[B:k0=\033[20~:k1=\033[1~:\
:k2=\033[2~:k3=\033[3~:k4=\033[4~:k5=\033[5~:k6=\033[6~:\
:k7=\033[17~:k8=\033[18~:k9=\033[19~:kd=\033[B:kh=\033[H:\
:kH=\033[Y:kI=\033[I:kl=\033[D:kN=\033[U:kP=\033[V:\
:kr=\033[C:ku=\033[A:li#25:md=\033[1m:me=\033[m:nd=\033[C:\
:se=\033[m:so=\033[7m:ue=\033[m:up=\033[A:us=\033[4m:",
#endif /* MINIX */
#ifdef TERM_COHERENT
"coherent",
"ansipc",
":al=\033[L:am:bs:ce=\033[K:cl=\033[2J:cm=\033[%i%d;%dH:\
:co#80:dl=\033[M:do=\033[B:k0=\033[0x:k1=\033[1x:k2=\033[2x:\
:k3=\033[3x:k4=\033[4x:k5=\033[5x:k6=\033[6x:\
:k7=\033[7x:k8=\033[8x:k9=\033[9x:kd=\033[B:kh=\033[H:\
:kH=\033[24H:kI=\033[@:kl=\033[D:kN=\033[U:kP=\033[V:\
:kr=\033[C:ku=\033[A:li#24:md=\033[1m:me=\033[m:\
:nd=\033[C:se=\033[m:so=\033[7m:ue=\033[m:up=\033[A:\
:us=\033[4m:",
#endif /* COHERENT */
#ifdef TERM_ATARI
"atari-st",
"vt52",
":al=\033L:am:bs:ce=\033K:cl=\033E:cm=\033Y%i%+ %+ :\
:co#80:dl=\033M:do=\033B:\
:k1=#;:k2=#<:k3=#=:k4=#>:k5=#?:k6=#@:k7=#A:k8=#B:k9=#C:k0=#D:\
:s1=#T:s2=#U:s3=#V:s4=#W:s5=#X:s6=#Y:s7=#Z:s8=#[:s9=#\\:s0=#]:\
:c1=#^:c2=#_:c3=#`:c4=#a:c5=#b:c6=#c:c7=#d:c8=#e:c9=#f:c0=#g:\
:a1=#h:a2=#i:a3=#j:a4=#k:a5=#l:a6=#m:a7=#n:a8=#o:a9=#p:a0=#q:\
kd=#P:kh=#G:kI=#R:kl=#K:kr=#M:ku=#H:li#25:nd=\033C:se=\033q:\
:so=\033p:te=:ti=\033e\033v:up=\033A:",
#endif
#ifdef TERM_925
"wyse925",
":xn@:\
:hs:am:bs:co#80:li#24:cm=\033=%+ %+ :cl=\033*:cd=\033y:\
:ce=\033t:is=\033l\033\":\
:al=\033E:dl=\033R:im=:ei=:ic=\033Q:dc=\033W:\
:ho=\036:nd=\014:bt=\033I:pt:so=\033G4:se=\033G0:sg#1:us=\033G8:ue=\033G0:ug#1:\
:up=\013:do=\026:kb=\010:ku=\013:kd=\026:kl=\010:kr=\014:\
:kh=\036:ma=\026\012\014 :\
:k1=\001@\r:k2=\001A\r:k3=\001B\r:k4=\001C\r:k5=\001D\r:k6=\001E\r:k7=\001F\r:\
:k8=\001G\r:k9=\001H\r:k0=\001I\r:ko=ic,dc,al,dl,cl,ce,cd,bt:\
:ts=\033f:fs=\033g:ds=\033h:sr=\033j:", /* was :xn: for tvi925 alone*/
#endif
(char *)0
};
static char *fields;
/*ARGSUSED*/
int tgetent(bp, name)
char *bp; /* buffer for storing the entry -- ignored */
char *name; /* name of the entry */
{
int i;
/* if TERMCAP is defined, and seems to match, then use it */
fields = getenv("TERMCAP");
if (fields)
{
for (i = 0; fields[i] && fields[i] != ':'; i++)
{
if (!strncmp(fields + i, name, strlen(name)))
{
return 1;
}
}
}
/* locate the entry in termcap[] */
for (i = 0; termcap[i] && strcmp(termcap[i], name); i++)
{
}
if (!termcap[i])
{
return 0;
}
/* search forward for fields */
while (termcap[i][0] != ':')
{
i++;
}
fields = termcap[i];
return 1;
}
static char *find(id, vtype)
char *id; /* name of a value to locate */
int vtype; /* '=' for strings, '#' for numbers, or 0 for bools */
{
int i;
/* search for a ':' followed by the two-letter id */
for (i = 0; fields[i]; i++)
{
if (fields[i] == ':'
&& fields[i + 1] == id[0]
&& fields[i + 2] == id[1])
{
/* if correct type, then return its value */
if (fields[i + 3] == vtype)
return &fields[i + 4];
else
return (char *)0;
}
}
return (char *)0;
}
int tgetnum(id)
char *id;
{
id = find(id, '#');
if (id)
{
return atoi(id);
}
return -1;
}
int tgetflag(id)
char *id;
{
if (find(id, ':'))
{
return 1;
}
return 0;
}
/*ARGSUSED*/
char *tgetstr(id, bp)
char *id;
char **bp; /* pointer to pointer to buffer - ignored */
{
char *cpy;
/* find the string */
id = find(id, '=');
if (!id)
{
return (char *)0;
}
/* copy it into the buffer, and terminate it with NUL */
for (cpy = *bp; *id != ':'; )
{
if (id[0] == '\\' && id[1] == 'E')
*cpy++ = '\033', id += 2;
else
*cpy++ = *id++;
}
*cpy++ = '\0';
/* update the bp pointer */
id = *bp;
*bp = cpy;
/* return a pointer to the copy of the string */
return id;
}
/*ARGSUSED*/
char *tgoto(cm, destcol, destrow)
char *cm; /* cursor movement string -- ignored */
int destcol;/* destination column, 0 - 79 */
int destrow;/* destination row, 0 - 24 */
{
static char buf[30];
#ifdef CRUNCH
# if TOS
sprintf(buf, "\033Y%c%c", ' ' + destrow, ' ' + destcol);
# else
sprintf(buf, "\033[%d;%dH", destrow + 1, destcol + 1);
# endif
#else
if (cm[1] == 'Y' || cm[1] == '=')
sprintf(buf, "\033%c%c%c", cm[1], ' ' + destrow, ' ' + destcol);
else
sprintf(buf, "\033[%d;%dH", destrow + 1, destcol + 1);
#endif
return buf;
}
/*ARGSUSED*/
void tputs(cp, affcnt, outfn)
char *cp; /* the string to output */
int affcnt; /* number of affected lines -- ignored */
int (*outfn)(); /* the output function */
{
while (*cp)
{
(*outfn)(*cp);
cp++;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,762 +0,0 @@
/* tmp.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains functions which create & readback a TMPFILE */
#include "config.h"
#include "vi.h"
#if TOS
# include <stat.h>
#else
# if OSK
# include "osk.h"
# else
# if AMIGA
# include "amistat.h"
# else
# include <sys/stat.h>
# endif
# endif
#endif
#if TURBOC
# include <process.h>
#endif
#ifndef NO_MODELINES
static void do_modelines(l, stop)
long l; /* line number to start at */
long stop; /* line number to stop at */
{
char *str; /* used to scan through the line */
char *start; /* points to the start of the line */
char buf[80];
/* if modelines are disabled, then do nothing */
if (!*o_modelines)
{
return;
}
/* for each line... */
for (; l <= stop; l++)
{
/* for each position in the line.. */
for (str = fetchline(l); *str; str++)
{
/* if it is the start of a modeline command... */
if ((str[0] == 'e' && str[1] == 'x'
|| str[0] == 'v' && str[1] == 'i')
&& str[2] == ':')
{
start = str += 3;
/* find the end */
for (str = start + strlen(start); *--str != ':'; )
{
}
/* if it is a well-formed modeline, execute it */
if (str > start && str - start < sizeof buf)
{
strncpy(buf, start, (int)(str - start));
exstring(buf, str - start, '\\');
break;
}
}
}
}
}
#endif
/* The FAIL() macro prints an error message and then exits. */
#define FAIL(why,arg) mode = MODE_EX; msg(why, arg); endwin(); exit(9)
/* This is the name of the temp file */
static char tmpname[80];
/* This function creates the temp file and copies the original file into it.
* Returns if successful, or stops execution if it fails.
*/
int tmpstart(filename)
char *filename; /* name of the original file */
{
int origfd; /* fd used for reading the original file */
struct stat statb; /* stat buffer, used to examine inode */
REG BLK *this; /* pointer to the current block buffer */
REG BLK *next; /* pointer to the next block buffer */
int inbuf; /* number of characters in a buffer */
int nread; /* number of bytes read */
REG int j, k;
int i;
long nbytes;
/* switching to a different file certainly counts as a change */
changes++;
redraw(MARK_UNSET, FALSE);
/* open the original file for reading */
*origname = '\0';
if (filename && *filename)
{
strcpy(origname, filename);
origfd = open(origname, O_RDONLY);
if (origfd < 0 && errno != ENOENT)
{
msg("Can't open \"%s\"", origname);
return tmpstart("");
}
if (origfd >= 0)
{
if (stat(origname, &statb) < 0)
{
FAIL("Can't stat \"%s\"", origname);
}
#if TOS
if (origfd >= 0 && (statb.st_mode & S_IJDIR))
#else
# if OSK
if (origfd >= 0 && (statb.st_mode & S_IFDIR))
# else
if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG)
# endif
#endif
{
msg("\"%s\" is not a regular file", origname);
return tmpstart("");
}
}
else
{
stat(".", &statb);
}
if (origfd >= 0)
{
origtime = statb.st_mtime;
#if OSK
if (*o_readonly || !(statb.st_mode &
((getuid() >> 16) == 0 ? S_IOWRITE | S_IWRITE :
((statb.st_gid != (getuid() >> 16) ? S_IOWRITE : S_IWRITE)))))
#endif
#if AMIGA || MSDOS || (TOS && defined(__GNUC__))
if (*o_readonly || !(statb.st_mode & S_IWRITE))
#endif
#if TOS && !defined(__GNUC__)
if (*o_readonly || (statb.st_mode & S_IJRON))
#endif
#if ANY_UNIX
if (*o_readonly || !(statb.st_mode &
((geteuid() == 0) ? 0222 :
((statb.st_uid != geteuid() ? 0022 : 0200)))))
#endif
#if VMS
if (*o_readonly)
#endif
{
setflag(file, READONLY);
}
}
else
{
origtime = 0L;
}
}
else
{
setflag(file, NOFILE);
origfd = -1;
origtime = 0L;
stat(".", &statb);
}
/* make a name for the tmp file */
tmpnum++;
#if MSDOS || TOS
/* MS-Dos doesn't allow multiple slashes, but supports drives
* with current directories.
* This relies on TMPNAME beginning with "%s\\"!!!!
*/
strcpy(tmpname, o_directory);
if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1]))
tmpname[i++]=SLASH;
sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum);
#else
sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum);
#endif
/* make sure nobody else is editing the same file */
if (access(tmpname, 0) == 0)
{
FAIL("Temp file \"%s\" already exists?", tmpname);
}
/* create the temp file */
#if ANY_UNIX
close(creat(tmpname, 0600)); /* only we can read it */
#else
close(creat(tmpname, FILEPERMS)); /* anybody body can read it, alas */
#endif
tmpfd = open(tmpname, O_RDWR | O_BINARY);
if (tmpfd < 0)
{
FAIL("Can't create temp file... Does directory \"%s\" exist?", o_directory);
return 1;
}
/* allocate space for the header in the file */
write(tmpfd, hdr.c, (unsigned)BLKSIZE);
write(tmpfd, tmpblk.c, (unsigned)BLKSIZE);
#ifndef NO_RECYCLE
/* initialize the block allocator */
/* This must already be done here, before the first attempt
* to write to the new file! GB */
garbage();
#endif
/* initialize lnum[] */
for (i = 1; i < MAXBLKS; i++)
{
lnum[i] = INFINITY;
}
lnum[0] = 0;
/* if there is no original file, then create a 1-line file */
if (origfd < 0)
{
hdr.n[0] = 0; /* invalid inode# denotes new file */
this = blkget(1); /* get the new text block */
strcpy(this->c, "\n"); /* put a line in it */
lnum[1] = 1L; /* block 1 ends with line 1 */
nlines = 1L; /* there is 1 line in the file */
nbytes = 1L;
if (*origname)
{
msg("\"%s\" [NEW FILE] 1 line, 1 char", origname);
}
else
{
msg("\"[NO FILE]\" 1 line, 1 char");
}
}
else /* there is an original file -- read it in */
{
nbytes = nlines = 0;
/* preallocate 1 "next" buffer */
i = 1;
next = blkget(i);
inbuf = 0;
/* loop, moving blocks from orig to tmp */
for (;;)
{
/* "next" buffer becomes "this" buffer */
this = next;
/* read [more] text into this block */
nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf);
if (nread < 0)
{
close(origfd);
close(tmpfd);
tmpfd = -1;
unlink(tmpname);
FAIL("Error reading \"%s\"", origname);
}
/* convert NUL characters to something else */
for (j = k = inbuf; k < inbuf + nread; k++)
{
if (!this->c[k])
{
setflag(file, HADNUL);
this->c[j++] = 0x80;
}
#ifndef CRUNCH
else if (*o_beautify && this->c[k] < ' ' && this->c[k] > 0)
{
if (this->c[k] == '\t'
|| this->c[k] == '\n'
|| this->c[k] == '\f')
{
this->c[j++] = this->c[k];
}
else if (this->c[k] == '\b')
{
/* delete '\b', but complain */
setflag(file, HADBS);
}
/* else silently delete control char */
}
#endif
else
{
this->c[j++] = this->c[k];
}
}
inbuf = j;
/* if the buffer is empty, quit */
if (inbuf == 0)
{
goto FoundEOF;
}
#if MSDOS || TOS
/* BAH! MS text mode read fills inbuf, then compresses eliminating \r
but leaving garbage at end of buf. The same is true for TURBOC. GB. */
memset(this->c + inbuf, '\0', BLKSIZE - inbuf);
#endif
/* search backward for last newline */
for (k = inbuf; --k >= 0 && this->c[k] != '\n';)
{
}
if (k++ < 0)
{
if (inbuf >= BLKSIZE - 1)
{
k = 80;
}
else
{
k = inbuf;
}
}
/* allocate next buffer */
next = blkget(++i);
/* move fragmentary last line to next buffer */
inbuf -= k;
for (j = 0; k < BLKSIZE; j++, k++)
{
next->c[j] = this->c[k];
this->c[k] = 0;
}
/* if necessary, add a newline to this buf */
for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; )
{
}
if (this->c[k] != '\n')
{
setflag(file, ADDEDNL);
this->c[k + 1] = '\n';
}
/* count the lines in this block */
for (k = 0; k < BLKSIZE && this->c[k]; k++)
{
if (this->c[k] == '\n')
{
nlines++;
}
nbytes++;
}
if(i >= MAXBLKS) {
FAIL("Too many blocks: %d.", i);
}
lnum[i - 1] = nlines;
}
FoundEOF:
/* if this is a zero-length file, add 1 line */
if (nlines == 0)
{
this = blkget(1); /* get the new text block */
strcpy(this->c, "\n"); /* put a line in it */
lnum[1] = 1; /* block 1 ends with line 1 */
nlines = 1; /* there is 1 line in the file */
nbytes = 1;
}
#if MSDOS || TOS
/* each line has an extra CR that we didn't count yet */
nbytes += nlines;
#endif
/* report the number of lines in the file */
msg("\"%s\" %s %ld line%s, %ld char%s",
origname,
(tstflag(file, READONLY) ? "[READONLY]" : ""),
nlines,
nlines == 1 ? "" : "s",
nbytes,
nbytes == 1 ? "" : "s");
}
/* initialize the cursor to start of line 1 */
cursor = MARK_FIRST;
/* close the original file */
close(origfd);
/* any other messages? */
if (tstflag(file, HADNUL))
{
msg("This file contained NULs. They've been changed to \\x80 chars");
}
if (tstflag(file, ADDEDNL))
{
msg("Newline characters have been inserted to break up long lines");
}
#ifndef CRUNCH
if (tstflag(file, HADBS))
{
msg("Backspace characters deleted due to ':set beautify'");
}
#endif
storename(origname);
#ifndef NO_MODELINES
if (nlines > 10)
{
do_modelines(1L, 5L);
do_modelines(nlines - 4L, nlines);
}
else
{
do_modelines(1L, nlines);
}
#endif
/* force all blocks out onto the disk, to support file recovery */
blksync();
return 0;
}
/* This function copies the temp file back onto an original file.
* Returns TRUE if successful, or FALSE if the file could NOT be saved.
*/
int tmpsave(filename, bang)
char *filename; /* the name to save it to */
int bang; /* forced write? */
{
int fd; /* fd of the file we're writing to */
REG int len; /* length of a text block */
REG BLK *this; /* a text block */
long bytes; /* byte counter */
REG int i;
/* if no filename is given, assume the original file name */
if (!filename || !*filename)
{
filename = origname;
}
/* if still no file name, then fail */
if (!*filename)
{
msg("Don't know a name for this file -- NOT WRITTEN");
return FALSE;
}
/* can't rewrite a READONLY file */
#if AMIGA
if (!strcmp(filename, origname) && tstflag(file, READONLY) && !bang)
#else
if (!strcmp(filename, origname) && *o_readonly && !bang)
#endif
{
msg("\"%s\" [READONLY] -- NOT WRITTEN", filename);
return FALSE;
}
/* open the file */
if (*filename == '>' && filename[1] == '>')
{
filename += 2;
while (*filename == ' ' || *filename == '\t')
{
filename++;
}
#ifdef O_APPEND
fd = open(filename, O_WRONLY|O_APPEND);
#else
fd = open(filename, O_WRONLY);
lseek(fd, 0L, 2);
#endif
}
else
{
/* either the file must not exist, or it must be the original
* file, or we must have a bang, or "writeany" must be set.
*/
if (strcmp(filename, origname) && access(filename, 0) == 0 && !bang
#ifndef CRUNCH
&& !*o_writeany
#endif
)
{
msg("File already exists - Use :w! to overwrite");
return FALSE;
}
#if VMS
/* Create a new VMS version of this file. */
{
char *strrchr(), *ptr = strrchr(filename,';');
if (ptr) *ptr = '\0'; /* Snip off any ;number in the name */
}
#endif
fd = creat(filename, FILEPERMS);
}
if (fd < 0)
{
msg("Can't write to \"%s\" -- NOT WRITTEN", filename);
return FALSE;
}
/* write each text block to the file */
bytes = 0L;
for (i = 1; i < MAXBLKS && (this = blkget(i)) && this->c[0]; i++)
{
for (len = 0; len < BLKSIZE && this->c[len]; len++)
{
}
if (twrite(fd, this->c, len) < len)
{
msg("Trouble writing to \"%s\"", filename);
if (!strcmp(filename, origname))
{
setflag(file, MODIFIED);
}
close(fd);
return FALSE;
}
bytes += len;
}
/* reset the "modified" flag, but not the "undoable" flag */
clrflag(file, MODIFIED);
significant = FALSE;
/* report lines & characters */
#if MSDOS || TOS
bytes += nlines; /* for the inserted carriage returns */
#endif
msg("Wrote \"%s\" %ld lines, %ld characters", filename, nlines, bytes);
/* close the file */
close(fd);
return TRUE;
}
/* This function deletes the temporary file. If the file has been modified
* and "bang" is FALSE, then it returns FALSE without doing anything; else
* it returns TRUE.
*
* If the "autowrite" option is set, then instead of returning FALSE when
* the file has been modified and "bang" is false, it will call tmpend().
*/
int tmpabort(bang)
int bang;
{
/* if there is no file, return successfully */
if (tmpfd < 0)
{
return TRUE;
}
/* see if we must return FALSE -- can't quit */
if (!bang && tstflag(file, MODIFIED))
{
/* if "autowrite" is set, then act like tmpend() */
if (*o_autowrite)
return tmpend(bang);
else
return FALSE;
}
/* delete the tmp file */
cutswitch();
strcpy(prevorig, origname);
prevline = markline(cursor);
*origname = '\0';
origtime = 0L;
blkinit();
nlines = 0;
initflags();
return TRUE;
}
/* This function saves the file if it has been modified, and then deletes
* the temporary file. Returns TRUE if successful, or FALSE if the file
* needs to be saved but can't be. When it returns FALSE, it will not have
* deleted the tmp file, either.
*/
int tmpend(bang)
int bang;
{
/* save the file if it has been modified */
if (tstflag(file, MODIFIED) && !tmpsave((char *)0, FALSE) && !bang)
{
return FALSE;
}
/* delete the tmp file */
tmpabort(TRUE);
return TRUE;
}
/* If the tmp file has been changed, then this function will force those
* changes to be written to the disk, so that the tmp file will survive a
* system crash or power failure.
*/
#if AMIGA || MSDOS || TOS
sync()
{
/* MS-DOS and TOS don't flush their buffers until the file is closed,
* so here we close the tmp file and then immediately reopen it.
*/
close(tmpfd);
tmpfd = open(tmpname, O_RDWR | O_BINARY);
return 0;
}
#endif
/* This function stores the file's name in the second block of the temp file.
* SLEAZE ALERT! SLEAZE ALERT! The "tmpblk" buffer is probably being used
* to store the arguments to a command, so we can't use it here. Instead,
* we'll borrow the buffer that is used for "shift-U".
*/
storename(name)
char *name; /* the name of the file - normally origname */
{
#ifndef CRUNCH
int len;
char *ptr;
#endif
/* we're going to clobber the U_text buffer, so reset U_line */
U_line = 0L;
if (!name)
{
strncpy(U_text, "", BLKSIZE);
U_text[1] = 127;
}
#ifndef CRUNCH
else if (*name != SLASH)
{
/* get the directory name */
ptr = getcwd(U_text, BLKSIZE);
if (ptr != U_text)
{
strcpy(U_text, ptr);
}
/* append a slash to the directory name */
len = strlen(U_text);
U_text[len++] = SLASH;
/* append the filename, padded with heaps o' NULs */
strncpy(U_text + len, *name ? name : "foo", BLKSIZE - len);
}
#endif
else
{
/* copy the filename into U_text */
strncpy(U_text, *name ? name : "foo", BLKSIZE);
}
if (tmpfd >= 0)
{
/* write the name out to second block of the temp file */
lseek(tmpfd, (long)BLKSIZE, 0);
write(tmpfd, U_text, (unsigned)BLKSIZE);
}
return 0;
}
/* This function handles deadly signals. It restores sanity to the terminal
* preserves the current temp file, and deletes any old temp files.
*/
int deathtrap(sig)
int sig; /* the deadly signal that we caught */
{
char *why;
/* restore the terminal's sanity */
endwin();
#ifdef CRUNCH
why = "-Elvis died";
#else
/* give a more specific description of how Elvis died */
switch (sig)
{
# ifdef SIGHUP
case SIGHUP: why = "-the modem lost its carrier"; break;
# endif
# ifndef DEBUG
# ifdef SIGILL
case SIGILL: why = "-Elvis hit an illegal instruction"; break;
# endif
# ifdef SIGBUS
case SIGBUS: why = "-Elvis had a bus error"; break;
# endif
# if defined(SIGSEGV) && !defined(TOS)
case SIGSEGV: why = "-Elvis had a segmentation violation"; break;
# endif
# ifdef SIGSYS
case SIGSYS: why = "-Elvis munged a system call"; break;
# endif
# endif /* !DEBUG */
# ifdef SIGPIPE
case SIGPIPE: why = "-the pipe reader died"; break;
# endif
# ifdef SIGTERM
case SIGTERM: why = "-Elvis was terminated"; break;
# endif
# if !MINIX
# ifdef SIGUSR1
case SIGUSR1: why = "-Elvis was killed via SIGUSR1"; break;
# endif
# ifdef SIGUSR2
case SIGUSR2: why = "-Elvis was killed via SIGUSR2"; break;
# endif
# endif
default: why = "-Elvis died"; break;
}
#endif
/* if we had a temp file going, then preserve it */
if (tmpnum > 0 && tmpfd >= 0)
{
close(tmpfd);
sprintf(tmpblk.c, "%s \"%s\" %s", PRESERVE, why, tmpname);
system(tmpblk.c);
}
/* delete any old temp files */
cutend();
/* exit with the proper exit status */
exit(sig);
}

View file

@ -1,218 +0,0 @@
/* unix.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the unix-specific versions the ttyread() functions.
* There are actually three versions of ttyread() defined here, because
* BSD, SysV, and V7 all need quite different implementations.
*/
#include "config.h"
#if ANY_UNIX
# include "vi.h"
# if BSD
/* For BSD, we use select() to wait for characters to become available,
* and then do a read() to actually get the characters. We also try to
* handle SIGWINCH -- if the signal arrives during the select() call, then
* we adjust the o_columns and o_lines variables, and fake a control-L.
*/
# include <sys/types.h>
# include <sys/time.h>
int ttyread(buf, len, time)
char *buf; /* where to store the gotten characters */
int len; /* maximum number of characters to read */
int time; /* maximum time to allow for reading */
{
fd_set rd; /* the file descriptors that we want to read from */
static tty; /* 'y' if reading from tty, or 'n' if not a tty */
int i;
struct timeval t;
struct timeval *tp;
/* do we know whether this is a tty or not? */
if (!tty)
{
tty = (isatty(0) ? 'y' : 'n');
}
/* compute the timeout value */
if (time)
{
t.tv_sec = time / 10;
t.tv_usec = (time % 10) * 100000L;
tp = &t;
}
else
{
tp = (struct timeval *)0;
}
/* loop until we get characters or a definite EOF */
for (;;)
{
if (tty == 'y')
{
/* wait until timeout or characters are available */
FD_ZERO(&rd);
FD_SET(0, &rd);
i = select(1, &rd, (fd_set *)0, (fd_set *)0, tp);
}
else
{
/* if reading from a file or pipe, never timeout!
* (This also affects the way that EOF is detected)
*/
i = 1;
}
/* react accordingly... */
switch (i)
{
case -1: /* assume we got an EINTR because of SIGWINCH */
if (*o_lines != LINES || *o_columns != COLS)
{
*o_lines = LINES;
*o_columns = COLS;
#ifndef CRUNCH
if (!wset)
{
*o_window = LINES - 1;
}
#endif
if (mode != MODE_EX)
{
/* pretend the user hit ^L */
*buf = ctrl('L');
return 1;
}
}
break;
case 0: /* timeout */
return 0;
default: /* characters available */
return read(0, buf, len);
}
}
}
# else
# if M_SYSV
/* For System-V or Coherent, we use VMIN/VTIME to implement the timeout.
* For no timeout, VMIN should be 1 and VTIME should be 0; for timeout,
* VMIN should be 0 and VTIME should be the timeout value.
*/
# include <termio.h>
int ttyread(buf, len, time)
char *buf; /* where to store the gotten characters */
int len; /* maximum number of characters to read */
int time; /* maximum time to allow for reading */
{
struct termio tio;
int bytes; /* number of bytes actually read */
/* arrange for timeout */
ioctl(0, TCGETA, &tio);
if (time)
{
tio.c_cc[VMIN] = 0;
tio.c_cc[VTIME] = time;
}
else
{
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
}
ioctl(0, TCSETA, &tio);
/* Perform the read. Loop if EINTR error happens */
while ((bytes = read(0, buf, len)) < 0)
{
/* probably EINTR error because a SIGWINCH was received */
if (*o_lines != LINES || *o_columns != COLS)
{
*o_lines = LINES;
*o_columns = COLS;
#ifndef CRUNCH
if (!wset)
{
*o_window = LINES - 1;
}
#endif
if (mode != MODE_EX)
{
/* pretend the user hit ^L */
*buf = ctrl('L');
return 1;
}
}
}
/* return the number of bytes read */
return bytes;
/* NOTE: The terminal may be left in a timeout-mode after this function
* returns. This shouldn't be a problem since Elvis *NEVER* tries to
* read from the keyboard except through this function.
*/
}
# else /* any other version of UNIX, assume it is V7 compatible */
/* For V7 UNIX (including Minix) we set an alarm() before doing a blocking
* read(), and assume that the SIGALRM signal will cause the read() function
* to give up.
*/
#include <setjmp.h>
static jmp_buf env;
/*ARGSUSED*/
int dummy(signo)
int signo;
{
longjmp(env, 1);
}
int ttyread(buf, len, time)
char *buf; /* where to store the gotten characters */
int len; /* maximum number of characters to read */
int time; /* maximum time to allow for reading */
{
/* arrange for timeout */
signal(SIGALRM, (void (*)()) dummy);
alarm(time);
/* perform the blocking read */
if (setjmp(env) == 0)
{
len = read(0, buf, len);
}
else /* I guess we timed out */
{
len = 0;
}
/* cancel the alarm */
signal(SIGALRM, (void (*)())dummy); /* work around a bug in Minix */
alarm(0);
/* return the number of bytes read */
if (len < 0)
len = 0;
return len;
}
# endif /* !(M_SYSV || COHERENT) */
# endif /* !BSD */
#endif /* ANY_UNIX */

View file

@ -1,115 +0,0 @@
/* vars.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains variables which weren't happy anyplace else */
#include "config.h"
#include "vi.h"
/*------------------------------------------------------------------------*/
/* used to remember whether the file has been modified */
struct _viflags viflags;
/* used to access the tmp file */
long lnum[MAXBLKS];
long nlines;
int tmpfd = -1;
int tmpnum;
#ifndef CRUNCH
int wset = FALSE;
#endif
/* used to keep track of the current file & alternate file */
long origtime;
char origname[256];
char prevorig[256];
long prevline = 1;
/* used to track various places in the text */
MARK mark[NMARKS]; /* marks 'a through 'z, plus mark '' */
MARK cursor; /* the cursor position within the file */
/* which mode of the editor we're in */
int mode; /* vi mode? ex mode? quitting? */
/* used to manage the args list */
char args[BLKSIZE]; /* list of filenames to edit */
int argno; /* index of current file in args list */
int nargs; /* number of filenames in args[] */
/* dummy var, never explicitly referenced */
int bavar; /* used only in BeforeAfter macros */
/* used to detect changes that invalidate cached text/blocks */
long changes; /* incremented when file is changed */
int significant; /* boolean: was a *REAL* change made? */
/* used to support the pfetch() macro */
int plen; /* length of the line */
long pline; /* line number that len refers to */
long pchgs; /* "changes" level that len refers to */
char *ptext; /* text of previous line, if valid */
/* misc temporary storage - mostly for strings */
BLK tmpblk; /* a block used to accumulate changes */
/* screen oriented stuff */
long topline; /* file line number of top line */
int leftcol; /* column number of left col */
int physcol; /* physical column number that cursor is on */
int physrow; /* physical row number that cursor is on */
/* used to help minimize that "[Hit a key to continue]" message */
int exwrote; /* Boolean: was the last ex command wordy? */
/* This variable affects the behaviour of certain functions -- most importantly
* the input function.
*/
int doingdot; /* boolean: are we doing the "." command? */
/* This variable affects the behaviour of the ":s" command, and it is also
* used to detect & prohibit nesting of ":g" commands
*/
int doingglobal; /* boolean: are doing a ":g" command? */
/* This variable is zeroed before a command executes, and later ORed with the
* command's flags after the command has been executed. It is used to force
* certain flags to be TRUE for *some* invocations of a particular command.
* For example, "/regexp/+offset" forces the LNMD flag, and sometimes a "p"
* or "P" command will force FRNT.
*/
int force_flags;
/* These are used for reporting multi-line changes to the user */
long rptlines; /* number of lines affected by a command */
char *rptlabel; /* description of how lines were affected */
/* These store info that pertains to the shift-U command */
long U_line; /* line# of the undoable line, or 0l for none */
char U_text[BLKSIZE]; /* contents of the undoable line */
#ifndef NO_VISIBLE
/* These are used to implement the 'v' and 'V' commands */
MARK V_from; /* starting point for v or V */
int V_linemd; /* boolean: doing line-mode version? (V, not v) */
#endif
/* Bigger stack req'ed for TOS and TURBOC */
#if TOS
long _stksize = 16384;
#endif
#if TURBOC
#include <dos.h>
extern unsigned _stklen = 16384U;
#endif

View file

@ -1,975 +0,0 @@
/* vcmd.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the functions that handle VI commands */
#include "config.h"
#include "ctype.h"
#include "vi.h"
#if MSDOS
# include <process.h>
# include <string.h>
#endif
#if TOS
# include <osbind.h>
# include <string.h>
#endif
#if OSK
# include <stdio.h>
#endif
/* This function puts the editor in EX mode */
MARK v_quit()
{
move(LINES - 1, 0);
mode = MODE_EX;
return cursor;
}
/* This function causes the screen to be redrawn */
MARK v_redraw()
{
redraw(MARK_UNSET, FALSE);
return cursor;
}
/* This function executes a string of EX commands, and waits for a user keystroke
* before returning to the VI screen. If that keystroke is another ':', then
* another EX command is read and executed.
*/
/*ARGSUSED*/
MARK v_1ex(m, text)
MARK m; /* the current line */
char *text; /* the first command to execute */
{
/* run the command. be careful about modes & output */
exwrote = (mode == MODE_COLON);
doexcmd(text);
exrefresh();
/* if mode is no longer MODE_VI, then we should quit right away! */
if (mode != MODE_VI && mode != MODE_COLON)
return cursor;
/* The command did some output. Wait for a keystoke. */
if (exwrote)
{
mode = MODE_VI;
msg("[Hit <RETURN> to continue]");
if (getkey(0) == ':')
{ mode = MODE_COLON;
addch('\n');
}
else
redraw(MARK_UNSET, FALSE);
}
return cursor;
}
/* This function undoes the last change */
/*ARGSUSED*/
MARK v_undo(m)
MARK m; /* (ignored) */
{
if (undo())
{
redraw(MARK_UNSET, FALSE);
}
return cursor;
}
/* This function deletes the character(s) that the cursor is on */
MARK v_xchar(m, cnt, cmd)
MARK m; /* where to start deletions */
long cnt; /* number of chars to delete */
int cmd; /* either 'x' or 'X' */
{
DEFAULT(1);
/* for 'X', adjust so chars are deleted *BEFORE* cursor */
if (cmd == 'X')
{
if (markidx(m) < cnt)
return MARK_UNSET;
m -= cnt;
}
/* make sure we don't try to delete more thars than there are */
pfetch(markline(m));
if (markidx(m + cnt) > plen)
{
cnt = plen - markidx(m);
}
if (cnt == 0L)
{
return MARK_UNSET;
}
/* do it */
ChangeText
{
cut(m, m + cnt);
delete(m, m + cnt);
}
return m;
}
/* This function defines a mark */
/*ARGSUSED*/
MARK v_mark(m, count, key)
MARK m; /* where the mark will be */
long count; /* (ignored) */
int key; /* the ASCII label of the mark */
{
if (key < 'a' || key > 'z')
{
msg("Marks must be from a to z");
}
else
{
mark[key - 'a'] = m;
}
return m;
}
/* This function toggles upper & lower case letters */
MARK v_ulcase(m, cnt)
MARK m; /* where to make the change */
long cnt; /* number of chars to flip */
{
REG char *pos;
REG int j;
DEFAULT(1);
/* fetch the current version of the line */
pfetch(markline(m));
/* for each position in the line */
for (j = 0, pos = &ptext[markidx(m)]; j < cnt && *pos; j++, pos++)
{
if (isupper(*pos))
{
tmpblk.c[j] = tolower(*pos);
}
else
{
tmpblk.c[j] = toupper(*pos);
}
}
/* if the new text is different from the old, then change it */
if (strncmp(tmpblk.c, &ptext[markidx(m)], j))
{
ChangeText
{
tmpblk.c[j] = '\0';
change(m, m + j, tmpblk.c);
}
}
return m + j;
}
MARK v_replace(m, cnt, key)
MARK m; /* first char to be replaced */
long cnt; /* number of chars to replace */
int key; /* what to replace them with */
{
REG char *text;
REG int i;
DEFAULT(1);
/* map ^M to '\n' */
if (key == '\r')
{
key = '\n';
}
/* make sure the resulting line isn't too long */
if (cnt > BLKSIZE - 2 - markidx(m))
{
cnt = BLKSIZE - 2 - markidx(m);
}
/* build a string of the desired character with the desired length */
for (text = tmpblk.c, i = cnt; i > 0; i--)
{
*text++ = key;
}
*text = '\0';
/* make sure cnt doesn't extend past EOL */
pfetch(markline(m));
key = markidx(m);
if (key + cnt > plen)
{
cnt = plen - key;
}
/* do the replacement */
ChangeText
{
change(m, m + cnt, tmpblk.c);
}
if (*tmpblk.c == '\n')
{
return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
}
else
{
return m + cnt - 1;
}
}
MARK v_overtype(m)
MARK m; /* where to start overtyping */
{
MARK end; /* end of a substitution */
static long width; /* width of a single-line replace */
/* the "doingdot" version of replace is really a substitution */
if (doingdot)
{
/* was the last one really repeatable? */
if (width < 0)
{
msg("Can't repeat a multi-line overtype command");
return MARK_UNSET;
}
/* replacing nothing by nothing? Don't bother */
if (width == 0)
{
return m;
}
/* replace some chars by repeated text */
return v_subst(m, width);
}
/* Normally, we input starting here, in replace mode */
ChangeText
{
end = input(m, m, WHEN_VIREP, FALSE);
}
/* if we ended on the same line we started on, then this
* overtype is repeatable via the dot key.
*/
if (markline(end) == markline(m) && end >= m - 1L)
{
width = end - m + 1L;
}
else /* it isn't repeatable */
{
width = -1L;
}
return end;
}
/* This function selects which cut buffer to use */
/*ARGSUSED*/
MARK v_selcut(m, cnt, key)
MARK m;
long cnt;
int key;
{
cutname(key);
return m;
}
/* This function pastes text from a cut buffer */
/*ARGSUSED*/
MARK v_paste(m, cnt, cmd)
MARK m; /* where to paste the text */
long cnt; /* (ignored) */
int cmd; /* either 'p' or 'P' */
{
MARK dest;
ChangeText
{
/* paste the text, and find out where it ends */
dest = paste(m, cmd == 'p', TRUE);
/* was that a line-mode paste? */
if (dest && markline(dest) != markline(m))
{
/* line-mode pastes leave the cursor at the front
* of the first pasted line.
*/
dest = m;
if (cmd == 'p')
{
dest += BLKSIZE;
}
force_flags |= FRNT;
}
}
return dest;
}
/* This function yanks text into a cut buffer */
MARK v_yank(m, n)
MARK m, n; /* range of text to yank */
{
cut(m, n);
return m;
}
/* This function deletes a range of text */
MARK v_delete(m, n)
MARK m, n; /* range of text to delete */
{
/* illegal to try and delete nothing */
if (n <= m)
{
return MARK_UNSET;
}
/* Do it */
ChangeText
{
cut(m, n);
delete(m, n);
}
return m;
}
/* This starts input mode without deleting anything */
MARK v_insert(m, cnt, key)
MARK m; /* where to start (sort of) */
long cnt; /* repeat how many times? */
int key; /* what command is this for? {a,A,i,I,o,O} */
{
int wasdot;
long reps;
int above; /* boolean: new line going above old line? */
DEFAULT(1);
ChangeText
{
/* tweak the insertion point, based on command key */
above = FALSE;
switch (key)
{
case 'i':
break;
case 'a':
pfetch(markline(m));
if (plen > 0)
{
m++;
}
break;
case 'I':
m = m_front(m, 1L);
break;
case 'A':
pfetch(markline(m));
m = (m & ~(BLKSIZE - 1)) + plen;
break;
case 'O':
m &= ~(BLKSIZE - 1);
add(m, "\n");
above = TRUE;
break;
case 'o':
m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
add(m, "\n");
break;
}
/* insert the same text once or more */
for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
{
m = input(m, m, WHEN_VIINP, above) + 1;
}
if (markidx(m) > 0)
{
m--;
}
doingdot = wasdot;
}
#ifndef CRUNCH
# ifndef NO_EXTENSIONS
if (key == 'i' && *o_inputmode && mode == MODE_VI)
{
msg("Now in command mode! To return to input mode, hit <i>");
}
# endif
#endif
return m;
}
/* This starts input mode with some text deleted */
MARK v_change(m, n)
MARK m, n; /* the range of text to change */
{
int lnmode; /* is this a line-mode change? */
/* swap them if they're in reverse order */
if (m > n)
{
MARK tmp;
tmp = m;
m = n;
n = tmp;
}
/* for line mode, retain the last newline char */
lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n);
if (lnmode)
{
n -= BLKSIZE;
pfetch(markline(n));
n = (n & ~(BLKSIZE - 1)) + plen;
}
ChangeText
{
cut(m, n);
m = input(m, n, WHEN_VIINP, FALSE);
}
return m;
}
/* This function replaces a given number of characters with input */
MARK v_subst(m, cnt)
MARK m; /* where substitutions start */
long cnt; /* number of chars to replace */
{
DEFAULT(1);
/* make sure we don't try replacing past EOL */
pfetch(markline(m));
if (markidx(m) + cnt > plen)
{
cnt = plen - markidx(m);
}
/* Go for it! */
ChangeText
{
cut(m, m + cnt);
m = input(m, m + cnt, WHEN_VIINP, FALSE);
}
return m;
}
/* This calls the ex "join" command to join some lines together */
MARK v_join(m, cnt)
MARK m; /* the first line to be joined */
long cnt; /* number of other lines to join */
{
MARK joint; /* where the lines were joined */
DEFAULT(1);
/* figure out where the joint will be */
pfetch(markline(m));
joint = (m & ~(BLKSIZE - 1)) + plen;
/* join the lines */
cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, "");
/* the cursor should be left at the joint */
return joint;
}
/* This calls the ex "<" command to shift some lines left */
MARK v_lshift(m, n)
MARK m, n; /* range of lines to shift */
{
/* adjust for inclusive endmarks in ex */
n -= BLKSIZE;
cmd_shift(m, n, CMD_SHIFTL, FALSE, (char *)0);
return m;
}
/* This calls the ex ">" command to shift some lines right */
MARK v_rshift(m, n)
MARK m, n; /* range of lines to shift */
{
/* adjust for inclusive endmarks in ex */
n -= BLKSIZE;
cmd_shift(m, n, CMD_SHIFTR, FALSE, (char *)0);
return m;
}
/* This filters some lines through a preset program, to reformat them */
MARK v_reformat(m, n)
MARK m, n; /* range of lines to shift */
{
/* adjust for inclusive endmarks in ex */
n -= BLKSIZE;
/* run the filter command */
filter(m, n, o_equalprg, TRUE);
redraw(MARK_UNSET, FALSE);
return m;
}
/* This runs some lines through a filter program */
MARK v_filter(m, n)
MARK m, n; /* range of lines to shift */
{
char cmdln[150]; /* a shell command line */
/* adjust for inclusive endmarks in ex */
n -= BLKSIZE;
if (vgets('!', cmdln, sizeof(cmdln)) > 0)
{
filter(m, n, cmdln, TRUE);
}
redraw(MARK_UNSET, FALSE);
return m;
}
/* This function runs the ex "file" command to show the file's status */
MARK v_status()
{
cmd_file(cursor, cursor, CMD_FILE, 0, "");
return cursor;
}
/* This function runs the ":&" command to repeat the previous :s// */
MARK v_again(m, n)
MARK m, n;
{
cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, "");
return cursor;
}
/* This function switches to the previous file, if possible */
MARK v_switch()
{
if (!*prevorig)
msg("No previous file");
else
{ strcpy(tmpblk.c, prevorig);
cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c);
}
return cursor;
}
/* This function does a tag search on a keyword */
/*ARGSUSED*/
MARK v_tag(keyword, m, cnt)
char *keyword;
MARK m;
long cnt;
{
/* move the cursor to the start of the tag name, where m is */
cursor = m;
/* perform the tag search */
cmd_tag(cursor, cursor, CMD_TAG, 0, keyword);
return cursor;
}
#ifndef NO_EXTENSIONS
/* This function looks up a keyword by calling the helpprog program */
/*ARGSUSED*/
MARK v_keyword(keyword, m, cnt)
char *keyword;
MARK m;
long cnt;
{
int waswarn;
char cmdline[130];
move(LINES - 1, 0);
addstr("---------------------------------------------------------\n");
clrtoeol();
refresh();
sprintf(cmdline, "%s %s", o_keywordprg, keyword);
waswarn = *o_warn;
*o_warn = FALSE;
suspend_curses();
if (system(cmdline))
{
addstr("<<< failed >>>\n");
}
resume_curses(FALSE);
mode = MODE_VI;
redraw(MARK_UNSET, FALSE);
*o_warn = waswarn;
return m;
}
MARK v_increment(keyword, m, cnt)
char *keyword;
MARK m;
long cnt;
{
static sign;
char newval[12];
long atol();
DEFAULT(1);
/* get one more keystroke, unless doingdot */
if (!doingdot)
{
sign = getkey(0);
}
/* adjust the number, based on that second keystroke */
switch (sign)
{
case '+':
case '#':
cnt = atol(keyword) + cnt;
break;
case '-':
cnt = atol(keyword) - cnt;
break;
case '=':
break;
default:
return MARK_UNSET;
}
sprintf(newval, "%ld", cnt);
ChangeText
{
change(m, m + strlen(keyword), newval);
}
return m;
}
#endif
/* This function acts like the EX command "xit" */
/*ARGSUSED*/
MARK v_xit(m, cnt, key)
MARK m; /* ignored */
long cnt; /* ignored */
int key; /* must be a second 'Z' */
{
/* if second char wasn't 'Z', fail */
if (key != 'Z')
{
return MARK_UNSET;
}
/* move the cursor to the bottom of the screen */
move(LINES - 1, 0);
clrtoeol();
/* do the xit command */
cmd_xit(m, m, CMD_XIT, FALSE, "");
/* return the cursor */
return m;
}
/* This function undoes changes to a single line, if possible */
MARK v_undoline(m)
MARK m; /* where we hope to undo the change */
{
/* make sure we have the right line in the buffer */
if (markline(m) != U_line)
{
return MARK_UNSET;
}
/* fix it */
ChangeText
{
strcat(U_text, "\n");
change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text);
}
/* nothing in the buffer anymore */
U_line = -1L;
/* return, with the cursor at the front of the line */
return m & ~(BLKSIZE - 1);
}
#ifndef NO_ERRLIST
MARK v_errlist(m)
MARK m;
{
cmd_errlist(m, m, CMD_ERRLIST, FALSE, "");
return cursor;
}
#endif
#ifndef NO_AT
/*ARGSUSED*/
MARK v_at(m, cnt, key)
MARK m;
long cnt;
int key;
{
int size;
size = cb2str(key, tmpblk.c, BLKSIZE);
if (size <= 0 || size == BLKSIZE)
{
return MARK_UNSET;
}
execmap(0, tmpblk.c, FALSE);
return cursor;
}
#endif
#ifdef SIGTSTP
MARK v_suspend()
{
cmd_suspend(MARK_UNSET, MARK_UNSET, CMD_SUSPEND, FALSE, "");
return MARK_UNSET;
}
#endif
#ifndef NO_VISIBLE
/*ARGSUSED*/
MARK v_start(m, cnt, cmd)
MARK m; /* starting point for a v or V command */
long cnt; /* ignored */
int cmd; /* either 'v' or 'V' */
{
if (V_from)
{
V_from = MARK_UNSET;
}
else
{
V_from = m;
V_linemd = isupper(cmd);
}
return m;
}
#endif
#ifndef NO_POPUP
# define MENU_HEIGHT 11
# define MENU_WIDTH 23
MARK v_popup(m, n)
MARK m, n; /* the range of text to change */
{
int i;
int y, x; /* position where the window will pop up at */
int key; /* keystroke from the user */
int sel; /* index of the selected operation */
static int dfltsel;/* default value of sel */
static char *labels[11] =
{
"ESC cancel! ",
" d delete (cut) ",
" y yank (copy) ",
" p paste after ",
" P paste before ",
" > more indented ",
" < less indented ",
" = reformat ",
" ! external filter ",
" ZZ save & exit ",
" u undo previous "
};
/* try to position the menu near the cursor */
x = physcol - (MENU_WIDTH / 2);
if (x < 0)
x = 0;
else if (x + MENU_WIDTH + 2 > COLS)
x = COLS - MENU_WIDTH - 2;
if (markline(cursor) < topline || markline(cursor) > botline)
y = 0;
else if (markline(cursor) + 1L + MENU_HEIGHT > botline)
y = (int)(markline(cursor) - topline) - MENU_HEIGHT;
else
y = (int)(markline(cursor) - topline) + 1L;
/* draw the menu */
for (sel = 0; sel < MENU_HEIGHT; sel++)
{
move(y + sel, x);
do_POPUP();
if (sel == dfltsel)
qaddstr("-->");
else
qaddstr(" ");
qaddstr(labels[sel]);
do_SE();
}
/* get a selection */
move(y + dfltsel, x + 4);
for (sel = dfltsel; (key = getkey(WHEN_POPUP)) != '\\' && key != '\r'; )
{
/* erase the selection arrow */
move(y + sel, x);
do_POPUP();
qaddstr(" ");
qaddstr(labels[sel]);
do_SE();
/* process the user's keystroke */
if (key == 'j' && sel < MENU_HEIGHT - 1)
{
sel++;
}
else if (key == 'k' && sel > 0)
{
sel--;
}
else if (key == '\033')
{
sel = 0;
break;
}
else
{
for (i = 1; i < MENU_HEIGHT && labels[i][1] != key; i++)
{
}
if (i < MENU_HEIGHT)
{
sel = i;
break;
}
}
/* redraw the arrow, possibly in a new place */
move(y + sel, x);
do_POPUP();
qaddstr("-->");
qaddstr(labels[sel]);
do_SE();
move(y + sel, x + 4);
}
/* in most cases, the default selection is "paste after" */
dfltsel = 3;
/* perform the appropriate action */
switch (sel)
{
case 0:
m = cursor;
dfltsel = 0;
break;
case 1: /* delete (cut) */
m = v_delete(m, n);
break;
case 2: /* yank (copy) */
m = v_yank(m, n);
break;
case 3: /* paste after */
m = v_paste(n, 1L, 'P');
break;
case 4: /* paste before */
m = v_paste(m, 1L, 'P');
dfltsel = 4;
break;
case 5: /* more indented */
m = v_rshift(m, n);
dfltsel = 5;
break;
case 6: /* less indented */
m = v_lshift(m, n);
dfltsel = 6;
break;
case 7: /* reformat */
m = v_reformat(m, n);
dfltsel = 7;
break;
case 8: /* external filter */
m = v_filter(m, n);
dfltsel = 0;
break;
case 9: /* save & exit */
/* get confirmation first */
do
{
key = getkey(0);
} while (key != '\\' && key != 'Z' && key != '\r' /* good */
&& key != '\033'); /* bad */
if (key != '\033')
{
m = v_xit(m, 0L, 'Z');
}
break;
case 10: /* undo previous */
m = v_undo(m);
dfltsel = 9;
break;
}
/* arrange for the menu to be erased (except that "chg from kbd"
* already erased it, and "save & exit" doesn't care)
*/
if (sel != 5 && sel != 9)
redraw(MARK_UNSET, FALSE);
return m;
}
#endif /* undef NO_POPUP */

View file

@ -1,815 +0,0 @@
/* vi.c */
/* Author:
* Steve Kirkendall
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
#include "config.h"
#include "ctype.h"
#include "vi.h"
/* This array describes what each key does */
#define NO_FUNC (MARK (*)())0
#define NO_ARGS 0
#define CURSOR 1
#define CURSOR_CNT_KEY 2
#define CURSOR_MOVED 3
#define CURSOR_EOL 4
#define ZERO 5
#define DIGIT 6
#define CURSOR_TEXT 7
#define KEYWORD 8
#define ARGSMASK 0x0f
#define C_C_K_REP1 (CURSOR_CNT_KEY | 0x10)
#define C_C_K_CUT (CURSOR_CNT_KEY | 0x20)
#define C_C_K_MARK (CURSOR_CNT_KEY | 0x30)
#define C_C_K_CHAR (CURSOR_CNT_KEY | 0x40)
#ifndef NO_SHOWMODE
static int keymodes[] = {0, WHEN_REP1, WHEN_CUT, WHEN_MARK, WHEN_CHAR};
# define KEYMODE(args) (keymodes[(args) >> 4])
#else
# define KEYMODE(args) 0
#endif
static struct keystru
{
MARK (*func)(); /* the function to run */
uchar args; /* description of the args needed */
#ifndef NO_VISIBLE
short flags;
#else
uchar flags; /* other stuff */
#endif
}
vikeys[] =
{
/* NUL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#ifndef NO_EXTENSIONS
/* ^A find cursor word */ {m_wsrch, KEYWORD, MVMT|NREL|VIZ},
#else
/* ^A not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* ^B page backward */ {m_scroll, CURSOR, FRNT|VIZ},
/* ^C not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^D scroll dn 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ},
/* ^E scroll up */ {m_scroll, CURSOR, NCOL|VIZ},
/* ^F page forward */ {m_scroll, CURSOR, FRNT|VIZ},
/* ^G show file status */ {v_status, NO_ARGS, NO_FLAGS},
/* ^H move left, like h*/ {m_left, CURSOR, MVMT|VIZ},
/* ^I not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^J move down */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL},
/* ^K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^L redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ},
/* ^M mv front next ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
/* ^N move down */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL|NCOL},
/* ^O not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^P move up */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL|NCOL},
/* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ},
/* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^U scroll up 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ},
/* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^X move to phys col */ {m_tocol, CURSOR, MVMT|NREL|VIZ},
/* ^Y scroll down */ {m_scroll, CURSOR, NCOL|VIZ},
#ifdef SIGTSTP
/* ^Z suspend elvis */ {v_suspend, NO_ARGS, NO_FLAGS},
#else
/* ^Z not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS},
/* ^^ previous file */ {v_switch, CURSOR, NO_FLAGS},
/* ^_ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* SPC move right,like l*/ {m_right, CURSOR, MVMT|INCL|VIZ},
/* ! run thru filter */ {v_filter, CURSOR_MOVED, FRNT|LNMD|INCL|VIZ},
/* " select cut buffer*/ {v_selcut, C_C_K_CUT, PTMV|VIZ},
#ifndef NO_EXTENSIONS
/* # increment number */ {v_increment, KEYWORD, SDOT},
#else
/* # not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* $ move to rear */ {m_rear, CURSOR, MVMT|INCL|VIZ},
/* % move to match */ {m_match, CURSOR, MVMT|INCL|VIZ},
/* & repeat subst */ {v_again, CURSOR_MOVED, SDOT|NCOL|LNMD|INCL},
/* ' move to a mark */ {m_tomark, C_C_K_MARK, MVMT|FRNT|NREL|LNMD|INCL|VIZ},
#ifndef NO_SENTENCE
/* ( mv back sentence */ {m_sentence, CURSOR, MVMT|VIZ},
/* ) mv fwd sentence */ {m_sentence, CURSOR, MVMT|VIZ},
#else
/* ( not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ) not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
#ifndef NO_ERRLIST
/* * errlist */ {v_errlist, CURSOR, FRNT|NREL},
#else
/* * not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* + mv front next ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
#ifndef NO_CHARSEARCH
/* , reverse [fFtT] cmd*/ {m__ch, CURSOR, MVMT|INCL|VIZ},
#else
/* , not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* - mv front prev ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
/* . special... */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* / forward search */ {m_fsrch, CURSOR_TEXT, MVMT|NREL|VIZ},
/* 0 part of count? */ {NO_FUNC, ZERO, MVMT|PTMV|VIZ},
/* 1 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* 2 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* 3 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* 4 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* 5 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* 6 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* 7 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* 8 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* 9 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
/* : run single EX cmd*/ {v_1ex, CURSOR_TEXT, NO_FLAGS},
#ifndef NO_CHARSEARCH
/* ; repeat [fFtT] cmd*/ {m__ch, CURSOR, MVMT|INCL|VIZ},
#else
/* ; not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS|VIZ},
#endif
/* < shift text left */ {v_lshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
/* = preset filter */ {v_reformat, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
/* > shift text right */ {v_rshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
/* ? backward search */ {m_bsrch, CURSOR_TEXT, MVMT|NREL|VIZ},
#ifndef NO_AT
/* @ execute a cutbuf */ {v_at, C_C_K_CUT, NO_FLAGS},
#else
/* @ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* A append at EOL */ {v_insert, CURSOR, SDOT},
/* B move back Word */ {m_bword, CURSOR, MVMT|VIZ},
/* C change to EOL */ {v_change, CURSOR_EOL, SDOT},
/* D delete to EOL */ {v_delete, CURSOR_EOL, SDOT},
/* E move end of Word */ {m_eword, CURSOR, MVMT|INCL|VIZ},
#ifndef NO_CHARSEARCH
/* F move bk to char */ {m_Fch, C_C_K_CHAR, MVMT|INCL|VIZ},
#else
/* F not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* G move to line # */ {m_updnto, CURSOR, MVMT|NREL|LNMD|FRNT|INCL|VIZ},
/* H move to row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
/* I insert at front */ {v_insert, CURSOR, SDOT},
/* J join lines */ {v_join, CURSOR, SDOT},
#ifndef NO_EXTENSIONS
/* K look up keyword */ {v_keyword, KEYWORD, NO_FLAGS},
#else
/* K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* L move to last row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
/* M move to mid row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
/* N reverse prev srch*/ {m_Nsrch, CURSOR, MVMT|NREL|VIZ},
/* O insert above line*/ {v_insert, CURSOR, SDOT},
/* P paste before */ {v_paste, CURSOR, SDOT},
/* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS},
/* R overtype */ {v_overtype, CURSOR, SDOT},
/* S change line */ {v_change, CURSOR_MOVED, SDOT},
#ifndef NO_CHARSEARCH
/* T move bk to char */ {m_Tch, C_C_K_CHAR, MVMT|INCL|VIZ},
#else
/* T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* U undo whole line */ {v_undoline, CURSOR, FRNT},
#ifndef NO_VISIBLE
/* V start visible */ {v_start, CURSOR, INCL|LNMD|VIZ},
#else
/* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* W move forward Word*/ {m_fword, CURSOR, MVMT|INCL|VIZ},
/* X delete to left */ {v_xchar, CURSOR, SDOT},
/* Y yank text */ {v_yank, CURSOR_MOVED, NCOL},
/* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS},
/* [ move back section*/ {m_paragraph, CURSOR, MVMT|LNMD|NREL|VIZ},
#ifndef NO_POPUP
/* \ pop-up menu */ {v_popup, CURSOR_MOVED, VIZ},
#else
/* \ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* ] move fwd section */ {m_paragraph, CURSOR, MVMT|LNMD|NREL|VIZ},
/* ^ move to front */ {m_front, CURSOR, MVMT|VIZ},
/* _ current line */ {m_updnto, CURSOR, MVMT|LNMD|FRNT|INCL},
/* ` move to mark */ {m_tomark, C_C_K_MARK, MVMT|NREL|VIZ},
/* a append at cursor */ {v_insert, CURSOR, SDOT},
/* b move back word */ {m_bword, CURSOR, MVMT|VIZ},
/* c change text */ {v_change, CURSOR_MOVED, SDOT|VIZ},
/* d delete op */ {v_delete, CURSOR_MOVED, SDOT|VIZ},
/* e move end word */ {m_eword, CURSOR, MVMT|INCL|VIZ},
#ifndef NO_CHARSEARCH
/* f move fwd for char*/ {m_fch, C_C_K_CHAR, MVMT|INCL|VIZ},
#else
/* f not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* g not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* h move left */ {m_left, CURSOR, MVMT|VIZ},
/* i insert at cursor */ {v_insert, CURSOR, SDOT},
/* j move down */ {m_updnto, CURSOR, MVMT|NCOL|LNMD|VIZ|INCL},
/* k move up */ {m_updnto, CURSOR, MVMT|NCOL|LNMD|VIZ|INCL},
/* l move right */ {m_right, CURSOR, MVMT|INCL|VIZ},
/* m define a mark */ {v_mark, C_C_K_MARK, NO_FLAGS},
/* n repeat prev srch */ {m_nsrch, CURSOR, MVMT|NREL|VIZ},
/* o insert below line*/ {v_insert, CURSOR, SDOT},
/* p paste after */ {v_paste, CURSOR, SDOT},
/* q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* r replace chars */ {v_replace, C_C_K_REP1, SDOT},
/* s subst N chars */ {v_subst, CURSOR, SDOT},
#ifndef NO_CHARSEARCH
/* t move fwd to char */ {m_tch, C_C_K_CHAR, MVMT|INCL|VIZ},
#else
/* t not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* u undo */ {v_undo, CURSOR, NO_FLAGS},
#ifndef NO_VISIBLE
/* v start visible */ {v_start, CURSOR, INCL|VIZ},
#else
/* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* w move fwd word */ {m_fword, CURSOR, MVMT|INCL|VIZ},
/* x delete character */ {v_xchar, CURSOR, SDOT},
/* y yank text */ {v_yank, CURSOR_MOVED, NCOL|VIZ},
/* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL|VIZ},
/* { back paragraph */ {m_paragraph, CURSOR, MVMT|LNMD|VIZ},
/* | move to column */ {m_tocol, CURSOR, MVMT|NREL|VIZ},
/* } fwd paragraph */ {m_paragraph, CURSOR, MVMT|LNMD|VIZ},
/* ~ upper/lowercase */ {v_ulcase, CURSOR, SDOT},
/* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}
};
void vi()
{
REG int key; /* keystroke from user */
long count; /* numeric argument to some functions */
REG struct keystru *keyptr;/* pointer to vikeys[] element */
MARK tcurs; /* temporary cursor */
int prevkey;/* previous key, if d/c/y/</>/! */
MARK range; /* start of range for d/c/y/</>/! */
char text[132];
int dotkey; /* last "key" of a change */
int dotpkey;/* last "prevkey" of a change */
int dotkey2;/* last extra "getkey()" of a change */
int dotcnt; /* last "count" of a change */
int firstkey;
REG int i;
/* tell the redraw() function to start from scratch */
redraw(MARK_UNSET, FALSE);
#ifdef lint
/* lint says that "range" might be used before it is set. This
* can't really happen due to the way "range" and "prevkey" are used,
* but lint doesn't know that. This line is here ONLY to keep lint
* happy.
*/
range = 0L;
#endif
/* safeguard against '.' with no previous command */
dotkey = dotpkey = dotkey2 = dotcnt = 0;
/* go immediately into insert mode, if ":set inputmode" */
firstkey = 0;
#ifndef NO_EXTENSIONS
if (*o_inputmode)
{
firstkey = 'i';
}
#endif
/* Repeatedly handle VI commands */
for (count = 0, prevkey = '\0'; mode == MODE_VI; )
{
/* if we've moved off the undoable line, then we can't undo it at all */
if (markline(cursor) != U_line)
{
U_line = 0L;
}
/* report any changes from the previous command */
if (rptlines >= *o_report)
{
redraw(cursor, FALSE);
msg("%ld line%s %s", rptlines, (rptlines==1?"":"s"), rptlabel);
}
rptlines = 0L;
/* get the next command key. It must be ASCII */
if (firstkey)
{
key = firstkey;
firstkey = 0;
}
else
{
do
{
key = getkey(WHEN_VICMD);
} while (key < 0 || key > 127);
}
/* Convert a doubled-up operator such as "dd" into "d_" */
if (prevkey && key == prevkey)
{
key = '_';
}
/* look up the structure describing this command */
keyptr = &vikeys[key];
/* '&' and uppercase operators always act like doubled */
if (!prevkey && keyptr->args == CURSOR_MOVED
&& (key == '&' || isupper(key)))
{
range = cursor;
prevkey = key;
key = '_';
keyptr = &vikeys[key];
}
#ifndef NO_VISIBLE
/* if we're in the middle of a v/V command, reject commands
* that aren't operators or movement commands
*/
if (V_from && !(keyptr->flags & VIZ))
{
beep();
prevkey = 0;
count = 0;
continue;
}
#endif
/* if we're in the middle of a d/c/y/</>/! command, reject
* anything but movement.
*/
if (prevkey && !(keyptr->flags & (MVMT|PTMV)))
{
beep();
prevkey = 0;
count = 0;
continue;
}
/* set the "dot" variables, if we're supposed to */
if (((keyptr->flags & SDOT)
|| (prevkey && vikeys[prevkey].flags & SDOT))
#ifndef NO_VISIBLE
&& !V_from
#endif
)
{
dotkey = key;
dotpkey = prevkey;
dotkey2 = '\0';
dotcnt = count;
/* remember the line before any changes are made */
if (U_line != markline(cursor))
{
U_line = markline(cursor);
strcpy(U_text, fetchline(U_line));
}
}
/* if this is "." then set other vars from the "dot" vars */
if (key == '.')
{
key = dotkey;
keyptr = &vikeys[key];
prevkey = dotpkey;
if (prevkey)
{
range = cursor;
}
if (count == 0)
{
count = dotcnt;
}
doingdot = TRUE;
/* remember the line before any changes are made */
if (U_line != markline(cursor))
{
U_line = markline(cursor);
strcpy(U_text, fetchline(U_line));
}
}
else
{
doingdot = FALSE;
}
/* process the key as a command */
tcurs = cursor;
force_flags = NO_FLAGS;
switch (keyptr->args & ARGSMASK)
{
case ZERO:
if (count == 0)
{
tcurs = cursor & ~(BLKSIZE - 1);
break;
}
/* else fall through & treat like other digits... */
case DIGIT:
count = count * 10 + key - '0';
break;
case KEYWORD:
/* if not on a keyword, fail */
pfetch(markline(cursor));
key = markidx(cursor);
if (!isalnum(ptext[key]))
{
tcurs = MARK_UNSET;
break;
}
/* find the start of the keyword */
while (key > 0 && isalnum(ptext[key - 1]))
{
key--;
}
tcurs = (cursor & ~(BLKSIZE - 1)) + key;
/* copy it into a buffer, and NUL-terminate it */
i = 0;
do
{
text[i++] = ptext[key++];
} while (isalnum(ptext[key]));
text[i] = '\0';
/* call the function */
tcurs = (*keyptr->func)(text, tcurs, count);
count = 0L;
break;
case NO_ARGS:
if (keyptr->func)
{
(*keyptr->func)();
}
else
{
beep();
}
count = 0L;
break;
case CURSOR:
tcurs = (*keyptr->func)(cursor, count, key, prevkey);
count = 0L;
break;
case CURSOR_CNT_KEY:
if (doingdot)
{
tcurs = (*keyptr->func)(cursor, count, dotkey2);
}
else
{
/* get a key */
i = getkey(KEYMODE(keyptr->args));
if (i == '\033') /* ESC */
{
count = 0;
tcurs = MARK_UNSET;
break; /* exit from "case CURSOR_CNT_KEY" */
}
else if (i == ctrl('V'))
{
i = getkey(0);
}
/* if part of an SDOT command, remember it */
if (keyptr->flags & SDOT
|| (prevkey && vikeys[prevkey].flags & SDOT))
{
dotkey2 = i;
}
/* do it */
tcurs = (*keyptr->func)(cursor, count, i);
}
count = 0L;
break;
case CURSOR_MOVED:
#ifndef NO_VISIBLE
if (V_from)
{
range = cursor;
tcurs = V_from;
count = 0L;
prevkey = key;
key = (V_linemd ? 'V' : 'v');
keyptr = &vikeys[key];
}
else
#endif
{
prevkey = key;
range = cursor;
force_flags = LNMD|INCL;
}
break;
case CURSOR_EOL:
prevkey = key;
/* a zero-length line needs special treatment */
pfetch(markline(cursor));
if (plen == 0)
{
/* act on a zero-length section of text */
range = tcurs = cursor;
key = '0';
}
else
{
/* act like CURSOR_MOVED with '$' movement */
range = cursor;
tcurs = m_rear(cursor, 1L);
key = '$';
}
count = 0L;
keyptr = &vikeys[key];
break;
case CURSOR_TEXT:
do
{
text[0] = key;
if (vgets(key, text + 1, sizeof text - 1) >= 0)
{
/* reassure user that <CR> was hit */
qaddch('\r');
refresh();
/* call the function with the text */
tcurs = (*keyptr->func)(cursor, text);
}
else
{
if (exwrote || mode == MODE_COLON)
{
redraw(MARK_UNSET, FALSE);
}
mode = MODE_VI;
}
} while (mode == MODE_COLON);
count = 0L;
break;
}
/* if that command took us out of vi mode, then exit the loop
* NOW, without tweaking the cursor or anything. This is very
* important when mode == MODE_QUIT.
*/
if (mode != MODE_VI)
{
break;
}
/* now move the cursor, as appropriate */
if (keyptr->args == CURSOR_MOVED)
{
/* the < and > keys have FRNT,
* but it shouldn't be applied yet
*/
tcurs = adjmove(cursor, tcurs, 0);
}
else
{
tcurs = adjmove(cursor, tcurs, (int)keyptr->flags | force_flags);
}
/* was that the end of a d/c/y/</>/! command? */
if (prevkey && ((keyptr->flags & MVMT)
#ifndef NO_VISIBLE
|| V_from
#endif
) && count == 0L)
{
#ifndef NO_VISIBLE
/* turn off the hilight */
V_from = 0L;
#endif
/* if the movement command failed, cancel operation */
if (tcurs == MARK_UNSET)
{
prevkey = 0;
count = 0;
continue;
}
/* make sure range=front and tcurs=rear. Either way,
* leave cursor=range since that's where we started.
*/
cursor = range;
if (tcurs < range)
{
range = tcurs;
tcurs = cursor;
}
/* The 'w' and 'W' destinations should never take us
* to the front of a line. Instead, they should take
* us only to the end of the preceding line.
*/
if ((keyptr->flags & (MVMT|NREL|LNMD|FRNT|INCL)) == MVMT
&& markline(range) < markline(tcurs)
&& (markline(tcurs) > nlines || tcurs == m_front(tcurs, 0L)))
{
tcurs = (tcurs & ~(BLKSIZE - 1)) - BLKSIZE;
pfetch(markline(tcurs));
tcurs += plen;
}
/* adjust for line mode & inclusion of last char/line */
i = (keyptr->flags | vikeys[prevkey].flags);
switch ((i | force_flags) & (INCL|LNMD))
{
case INCL:
tcurs++;
break;
case INCL|LNMD:
tcurs += BLKSIZE;
/* fall through... */
case LNMD:
range &= ~(BLKSIZE - 1);
tcurs &= ~(BLKSIZE - 1);
break;
}
/* run the function */
tcurs = (*vikeys[prevkey].func)(range, tcurs);
if (mode == MODE_VI)
{
(void)adjmove(cursor, cursor, 0);
cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags);
}
/* cleanup */
prevkey = 0;
}
else if (!prevkey)
{
if (tcurs != MARK_UNSET)
cursor = tcurs;
}
}
}
/* This function adjusts the MARK value that they return; here we make sure
* it isn't past the end of the line, and that the column hasn't been
* *accidentally* changed.
*/
MARK adjmove(old, new, flags)
MARK old; /* the cursor position before the command */
REG MARK new; /* the cursor position after the command */
int flags; /* various flags regarding cursor mvmt */
{
static int colno; /* the column number that we want */
REG char *text; /* used to scan through the line's text */
REG int i;
#ifdef DEBUG
watch();
#endif
/* if the command failed, bag it! */
if (new == MARK_UNSET)
{
beep();
return old;
}
/* if this is a non-relative movement, set the '' mark */
if (flags & NREL)
{
mark[26] = old;
}
/* make sure it isn't past the end of the file */
if (markline(new) < 1)
{
new = MARK_FIRST;
}
else if (markline(new) > nlines)
{
new = MARK_LAST;
}
/* fetch the new line */
pfetch(markline(new));
/* move to the front, if we're supposed to */
if (flags & FRNT)
{
new = m_front(new, 1L);
}
/* change the column#, or change the mark to suit the column# */
if (!(flags & NCOL))
{
/* change the column# */
i = markidx(new);
if (i == BLKSIZE - 1)
{
new &= ~(BLKSIZE - 1);
if (plen > 0)
{
new += plen - 1;
}
colno = BLKSIZE * 8; /* one heck of a big colno */
}
else if (plen > 0)
{
if (i >= plen)
{
new = (new & ~(BLKSIZE - 1)) + plen - 1;
}
colno = idx2col(new, ptext, FALSE);
}
else
{
new &= ~(BLKSIZE - 1);
colno = 0;
}
}
else
{
/* adjust the mark to get as close as possible to column# */
for (i = 0, text = ptext; i <= colno && *text; text++)
{
if (*text == '\t' && !*o_list)
{
i += *o_tabstop - (i % *o_tabstop);
}
else if (UCHAR(*text) < ' ' || *text == 127)
{
i += 2;
}
#ifndef NO_CHARATTR
else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2])
{
text += 2; /* plus one more in "for()" stmt */
}
#endif
else
{
i++;
}
}
if (text > ptext)
{
text--;
}
new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext);
}
return new;
}
#ifdef DEBUG
watch()
{
static wasset;
if (*origname)
{
wasset = TRUE;
}
else if (wasset)
{
mode = MODE_EX;
msg("origname was clobbered");
endwin();
abort();
}
if (wasset && nlines == 0)
{
mode = MODE_EX;
msg("nlines=0");
endwin();
abort();
}
}
#endif

View file

@ -1,596 +0,0 @@
/* vi.h */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
#define VERSION "ELVIS 1.5, by Steve Kirkendall (23 March 1992)"
#define COPYING "This version of ELVIS is freely redistributable."
#include <errno.h>
extern int errno;
#if TOS && !defined(__GNUC__)
#define ENOENT (-AEFILNF)
#endif
#if TOS || VMS
# include <types.h>
# define O_RDONLY 0
# define O_WRONLY 1
# define O_RDWR 2
# ifdef __GNUC__
# define S_IJDIR S_IFDIR
# endif
#else
# if OSK
# include <modes.h>
# define O_RDONLY S_IREAD
# define O_WRONLY S_IWRITE
# define O_RDWR (S_IREAD | S_IWRITE)
# define ENOENT E_PNNF
# define sprintf Sprintf
# else
# include <sys/types.h>
# if COHERENT
# include <sys/fcntl.h>
# else
# include <fcntl.h>
# endif
# endif
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
#include "curses.h"
#include <signal.h>
/*------------------------------------------------------------------------*/
/* Miscellaneous constants. */
#define INFINITY 2000000001L /* a very large integer */
#define LONGKEY 10 /* longest possible raw :map key */
#ifndef MAXRCLEN
# define MAXRCLEN 1000 /* longest possible :@ command */
#endif
/*------------------------------------------------------------------------*/
/* These describe how temporary files are divided into blocks */
#define MAXBLKS (BLKSIZE / sizeof(unsigned short))
typedef union
{
char c[BLKSIZE]; /* for text blocks */
unsigned short n[MAXBLKS]; /* for the header block */
}
BLK;
/*------------------------------------------------------------------------*/
/* These are used manipulate BLK buffers. */
extern BLK hdr; /* buffer for the header block */
extern BLK *blkget(); /* given index into hdr.c[], reads block */
extern BLK *blkadd(); /* inserts a new block into hdr.c[] */
/*------------------------------------------------------------------------*/
/* These are used to keep track of various flags */
extern struct _viflags
{
short file; /* file flags */
}
viflags;
/* file flags */
#define NEWFILE 0x0001 /* the file was just created */
#define READONLY 0x0002 /* the file is read-only */
#define HADNUL 0x0004 /* the file contained NUL characters */
#define MODIFIED 0x0008 /* the file has been modified, but not saved */
#define NOFILE 0x0010 /* no name is known for the current text */
#define ADDEDNL 0x0020 /* newlines were added to the file */
#define HADBS 0x0040 /* backspace chars were lost from the file */
#define UNDOABLE 0x0080 /* file has been modified */
#define NOTEDITED 0x0100 /* the :file command has been used */
/* macros used to set/clear/test flags */
#define setflag(x,y) viflags.x |= y
#define clrflag(x,y) viflags.x &= ~y
#define tstflag(x,y) (viflags.x & y)
#define initflags() viflags.file = 0;
/* The options */
extern char o_autoindent[1];
extern char o_autoprint[1];
extern char o_autotab[1];
extern char o_autowrite[1];
extern char o_columns[3];
extern char o_directory[30];
extern char o_edcompatible[1];
extern char o_equalprg[80];
extern char o_errorbells[1];
extern char o_exrefresh[1];
extern char o_ignorecase[1];
extern char o_keytime[3];
extern char o_keywordprg[80];
extern char o_lines[3];
extern char o_list[1];
extern char o_number[1];
extern char o_readonly[1];
extern char o_remap[1];
extern char o_report[3];
extern char o_scroll[3];
extern char o_shell[60];
extern char o_shiftwidth[3];
extern char o_sidescroll[3];
extern char o_sync[1];
extern char o_tabstop[3];
extern char o_term[30];
extern char o_flash[1];
extern char o_warn[1];
extern char o_wrapscan[1];
#ifndef CRUNCH
extern char o_beautify[1];
extern char o_exrc[1];
extern char o_mesg[1];
extern char o_more[1];
extern char o_novice[1];
extern char o_prompt[1];
extern char o_taglength[3];
extern char o_terse[1];
extern char o_window[3];
extern char o_wrapmargin[3];
extern char o_writeany[1];
#endif
#ifndef NO_ERRLIST
extern char o_cc[30];
extern char o_make[30];
#endif
#ifndef NO_CHARATTR
extern char o_charattr[1];
#endif
#ifndef NO_DIGRAPH
extern char o_digraph[1];
extern char o_flipcase[80];
#endif
#ifndef NO_SENTENCE
extern char o_hideformat[1];
#endif
#ifndef NO_EXTENSIONS
extern char o_inputmode[1];
extern char o_ruler[1];
#endif
#ifndef NO_MAGIC
extern char o_magic[1];
#endif
#ifndef NO_MODELINES
extern char o_modelines[1];
#endif
#ifndef NO_SENTENCE
extern char o_paragraphs[30];
extern char o_sections[30];
#endif
#if MSDOS
extern char o_pcbios[1];
#endif
#ifndef NO_SHOWMATCH
extern char o_showmatch[1];
#endif
#ifndef NO_SHOWMODE
extern char o_smd[1];
#endif
/*------------------------------------------------------------------------*/
/* These help support the single-line multi-change "undo" -- shift-U */
extern char U_text[BLKSIZE];
extern long U_line;
/*------------------------------------------------------------------------*/
/* These are used to refer to places in the text */
typedef long MARK;
#define markline(x) (long)((x) / BLKSIZE)
#define markidx(x) (int)((x) & (BLKSIZE - 1))
#define MARK_UNSET ((MARK)0)
#define MARK_FIRST ((MARK)BLKSIZE)
#define MARK_LAST ((MARK)(nlines * BLKSIZE))
#define MARK_AT_LINE(x) ((MARK)(x) * BLKSIZE)
#define NMARKS 29
extern MARK mark[NMARKS]; /* marks a-z, plus mark ' and two temps */
extern MARK cursor; /* mark where line is */
/*------------------------------------------------------------------------*/
/* These are used to keep track of the current & previous files. */
extern long origtime; /* modification date&time of the current file */
extern char origname[256]; /* name of the current file */
extern char prevorig[256]; /* name of the preceding file */
extern long prevline; /* line number from preceding file */
/*------------------------------------------------------------------------*/
/* misc housekeeping variables & functions */
extern int tmpfd; /* fd used to access the tmp file */
extern int tmpnum; /* counter used to generate unique filenames */
extern long lnum[MAXBLKS]; /* last line# of each block */
extern long nlines; /* number of lines in the file */
extern char args[BLKSIZE]; /* file names given on the command line */
extern int argno; /* the current element of args[] */
extern int nargs; /* number of filenames in args */
extern long changes; /* counts changes, to prohibit short-cuts */
extern int significant; /* boolean: was a *REAL* change made? */
extern BLK tmpblk; /* a block used to accumulate changes */
extern long topline; /* file line number of top line */
extern int leftcol; /* column number of left col */
#define botline (topline + LINES - 2)
#define rightcol (leftcol + COLS - (*o_number ? 9 : 1))
extern int physcol; /* physical column number that cursor is on */
extern int physrow; /* physical row number that cursor is on */
extern int exwrote; /* used to detect verbose ex commands */
extern int doingdot; /* boolean: are we doing the "." command? */
extern int doingglobal; /* boolean: are doing a ":g" command? */
extern long rptlines; /* number of lines affected by a command */
extern char *rptlabel; /* description of how lines were affected */
extern char *fetchline(); /* read a given line from tmp file */
extern char *parseptrn(); /* isolate a regexp in a line */
extern MARK paste(); /* paste from cut buffer to a given point */
extern char *wildcard(); /* expand wildcards in filenames */
extern MARK input(); /* inserts characters from keyboard */
extern char *linespec(); /* finds the end of a /regexp/ string */
#define ctrl(ch) ((ch)&037)
#ifndef NO_RECYCLE
extern long allocate(); /* allocate a free block of the tmp file */
#endif
extern int trapint(); /* trap handler for SIGINT */
extern int deathtrap(); /* trap handler for deadly signals */
extern void blkdirty(); /* marks a block as being "dirty" */
extern void blkflush(); /* writes a single dirty block to the disk */
extern void blksync(); /* forces all "dirty" blocks to disk */
extern void blkinit(); /* resets the block cache to "empty" state */
extern void beep(); /* rings the terminal's bell */
extern void exrefresh(); /* writes text to the screen */
extern void msg(); /* writes a printf-style message to the screen */
extern void endmsgs(); /* if "manymsgs" is set, then scroll up 1 line */
extern void garbage(); /* reclaims any garbage blocks */
extern void redraw(); /* updates the screen after a change */
extern void resume_curses();/* puts the terminal in "cbreak" mode */
extern void beforedo(); /* saves current revision before a new change */
extern void afterdo(); /* marks end of a beforedo() change */
extern void abortdo(); /* like "afterdo()" followed by "undo()" */
extern int undo(); /* restores file to previous undo() */
extern void dumpkey(); /* lists key mappings to the screen */
extern void mapkey(); /* defines a new key mapping */
extern void savekeys(); /* lists key mappings to a file */
extern void redrawrange(); /* records clues from modify.c */
extern void cut(); /* saves text in a cut buffer */
extern void delete(); /* deletes text */
extern void add(); /* adds text */
extern void change(); /* deletes text, and then adds other text */
extern void cutswitch(); /* updates cut buffers when we switch files */
extern void do_abbr(); /* defines or lists abbreviations */
extern void do_digraph(); /* defines or lists digraphs */
extern void exstring(); /* execute a string as EX commands */
extern void dumpopts();
extern void setopts();
extern void saveopts();
extern void savedigs();
extern void saveabbr();
extern void savecolor();
extern void cutname();
extern void cutname();
extern void initopts();
extern void cutend();
#ifndef CRUNCH
extern int wset; /* boolean: has the "window" size been set? */
#endif
/*------------------------------------------------------------------------*/
/* macros that are used as control structures */
#define BeforeAfter(before, after) for((before),bavar=1;bavar;(after),bavar=0)
#define ChangeText BeforeAfter(beforedo(FALSE),afterdo())
extern int bavar; /* used only in BeforeAfter macros */
/*------------------------------------------------------------------------*/
/* These are the movement commands. Each accepts a mark for the starting */
/* location & number and returns a mark for the destination. */
extern MARK m_updnto(); /* k j G */
extern MARK m_right(); /* h */
extern MARK m_left(); /* l */
extern MARK m_tocol(); /* | */
extern MARK m_front(); /* ^ */
extern MARK m_rear(); /* $ */
extern MARK m_fword(); /* w */
extern MARK m_bword(); /* b */
extern MARK m_eword(); /* e */
extern MARK m_paragraph(); /* { } [[ ]] */
extern MARK m_match(); /* % */
#ifndef NO_SENTENCE
extern MARK m_sentence(); /* ( ) */
#endif
extern MARK m_tomark(); /* 'm */
#ifndef NO_EXTENSIONS
extern MARK m_wsrch(); /* ^A */
#endif
extern MARK m_nsrch(); /* n */
extern MARK m_Nsrch(); /* N */
extern MARK m_fsrch(); /* /regexp */
extern MARK m_bsrch(); /* ?regexp */
#ifndef NO_CHARSEARCH
extern MARK m__ch(); /* ; , */
extern MARK m_fch(); /* f */
extern MARK m_tch(); /* t */
extern MARK m_Fch(); /* F */
extern MARK m_Tch(); /* T */
#endif
extern MARK m_row(); /* H L M */
extern MARK m_z(); /* z */
extern MARK m_scroll(); /* ^B ^F ^E ^Y ^U ^D */
/* Some stuff that is used by movement functions... */
extern MARK adjmove(); /* a helper fn, used by move fns */
/* This macro is used to set the default value of cnt */
#define DEFAULT(val) if (cnt < 1) cnt = (val)
/* These are used to minimize calls to fetchline() */
extern int plen; /* length of the line */
extern long pline; /* line number that len refers to */
extern long pchgs; /* "changes" level that len refers to */
extern char *ptext; /* text of previous line, if valid */
extern void pfetch();
extern char digraph();
/* This is used to build a MARK that corresponds to a specific point in the
* line that was most recently pfetch'ed.
*/
#define buildmark(text) (MARK)(BLKSIZE * pline + (int)((text) - ptext))
/*------------------------------------------------------------------------*/
/* These are used to handle EX commands. */
#define CMD_NULL 0 /* NOT A VALID COMMAND */
#define CMD_ABBR 1 /* "define an abbreviation" */
#define CMD_ARGS 2 /* "show me the args" */
#define CMD_APPEND 3 /* "insert lines after this line" */
#define CMD_AT 4 /* "execute a cut buffer's contents via EX" */
#define CMD_BANG 5 /* "run a single shell command" */
#define CMD_CC 6 /* "run `cc` and then do CMD_ERRLIST" */
#define CMD_CD 7 /* "change directories" */
#define CMD_CHANGE 8 /* "change some lines" */
#define CMD_COLOR 9 /* "change the default colors" */
#define CMD_COPY 10 /* "copy the selected text to a given place" */
#define CMD_DELETE 11 /* "delete the selected text" */
#define CMD_DIGRAPH 12 /* "add a digraph, or display them all" */
#define CMD_EDIT 13 /* "switch to a different file" */
#define CMD_EQUAL 14 /* "display a line number" */
#define CMD_ERRLIST 15 /* "locate the next error in a list" */
#define CMD_FILE 16 /* "show the file's status" */
#define CMD_GLOBAL 17 /* "globally search & do a command" */
#define CMD_INSERT 18 /* "insert lines before the current line" */
#define CMD_JOIN 19 /* "join the selected line & the one after" */
#define CMD_LIST 20 /* "print lines, making control chars visible" */
#define CMD_MAKE 21 /* "run `make` and then do CMD_ERRLIST" */
#define CMD_MAP 22 /* "adjust the keyboard map" */
#define CMD_MARK 23 /* "mark this line" */
#define CMD_MKEXRC 24 /* "make a .exrc file" */
#define CMD_MOVE 25 /* "move the selected text to a given place" */
#define CMD_NEXT 26 /* "switch to next file in args" */
#define CMD_NUMBER 27 /* "print lines from the file w/ line numbers" */
#define CMD_PRESERVE 28 /* "act as though vi crashed" */
#define CMD_PREVIOUS 29 /* "switch to the previous file in args" */
#define CMD_PRINT 30 /* "print the selected text" */
#define CMD_PUT 31 /* "insert any cut lines before this line" */
#define CMD_QUIT 32 /* "quit without writing the file" */
#define CMD_READ 33 /* "append the given file after this line */
#define CMD_RECOVER 34 /* "recover file after vi crashes" - USE -r FLAG */
#define CMD_REWIND 35 /* "rewind to first file" */
#define CMD_SET 36 /* "set a variable's value" */
#define CMD_SHELL 37 /* "run some lines through a command" */
#define CMD_SHIFTL 38 /* "shift lines left" */
#define CMD_SHIFTR 39 /* "shift lines right" */
#define CMD_SOURCE 40 /* "interpret a file's contents as ex commands" */
#define CMD_STOP 41 /* same as CMD_SUSPEND */
#define CMD_SUBAGAIN 42 /* "repeat the previous substitution" */
#define CMD_SUBSTITUTE 43 /* "substitute text in this line" */
#define CMD_SUSPEND 44 /* "suspend the vi session" */
#define CMD_TR 45 /* "transliterate chars in the selected lines" */
#define CMD_TAG 46 /* "go to a particular tag" */
#define CMD_UNABBR 47 /* "remove an abbreviation definition" */
#define CMD_UNDO 48 /* "undo the previous command" */
#define CMD_UNMAP 49 /* "remove a key sequence map */
#define CMD_VERSION 50 /* "describe which version this is" */
#define CMD_VGLOBAL 51 /* "apply a cmd to lines NOT containing an RE" */
#define CMD_VISUAL 52 /* "go into visual mode" */
#define CMD_WQUIT 53 /* "write this file out (any case) & quit" */
#define CMD_WRITE 54 /* "write the selected(?) text to a given file" */
#define CMD_XIT 55 /* "write this file out (if modified) & quit" */
#define CMD_YANK 56 /* "copy the selected text into the cut buffer" */
#ifdef DEBUG
# define CMD_DEBUG 57 /* access to internal data structures */
# define CMD_VALIDATE 58 /* check for internal consistency */
#endif
typedef int CMD;
extern void ex();
extern void vi();
extern void doexcmd();
extern void cmd_append();
extern void cmd_args();
#ifndef NO_AT
extern void cmd_at();
#endif
extern void cmd_cd();
#ifndef NO_COLOR
extern void cmd_color();
#endif
extern void cmd_delete();
#ifndef NO_DIGRAPH
extern void cmd_digraph();
#endif
extern void cmd_edit();
#ifndef NO_ERRLIST
extern void cmd_errlist();
#endif
extern void cmd_file();
extern void cmd_global();
extern void cmd_join();
extern void cmd_mark();
#ifndef NO_ERRLIST
extern void cmd_make();
#endif
extern void cmd_map();
#ifndef NO_MKEXRC
extern void cmd_mkexrc();
#endif
extern void cmd_next();
extern void cmd_print();
extern void cmd_put();
extern void cmd_read();
extern void cmd_set();
extern void cmd_shell();
extern void cmd_shift();
extern void cmd_source();
extern void cmd_substitute();
extern void cmd_tag();
extern void cmd_undo();
extern void cmd_version();
extern void cmd_write();
extern void cmd_xit();
extern void cmd_move();
#ifdef DEBUG
extern void cmd_debug();
extern void cmd_validate();
#endif
#ifdef SIGTSTP
extern void cmd_suspend();
#endif
/*----------------------------------------------------------------------*/
/* These are used to handle VI commands */
extern MARK v_1ex(); /* : */
extern MARK v_mark(); /* m */
extern MARK v_quit(); /* Q */
extern MARK v_redraw(); /* ^L ^R */
extern MARK v_ulcase(); /* ~ */
extern MARK v_undo(); /* u */
extern MARK v_xchar(); /* x X */
extern MARK v_replace(); /* r */
extern MARK v_overtype(); /* R */
extern MARK v_selcut(); /* " */
extern MARK v_paste(); /* p P */
extern MARK v_yank(); /* y Y */
extern MARK v_delete(); /* d D */
extern MARK v_join(); /* J */
extern MARK v_insert(); /* a A i I o O */
extern MARK v_change(); /* c C */
extern MARK v_subst(); /* s */
extern MARK v_lshift(); /* < */
extern MARK v_rshift(); /* > */
extern MARK v_reformat(); /* = */
extern MARK v_filter(); /* ! */
extern MARK v_status(); /* ^G */
extern MARK v_switch(); /* ^^ */
extern MARK v_tag(); /* ^] */
extern MARK v_xit(); /* ZZ */
extern MARK v_undoline(); /* U */
extern MARK v_again(); /* & */
#ifndef NO_EXTENSIONS
extern MARK v_keyword(); /* K */
extern MARK v_increment(); /* * */
#endif
#ifndef NO_ERRLIST
extern MARK v_errlist(); /* * */
#endif
#ifndef NO_AT
extern MARK v_at(); /* @ */
#endif
#ifdef SIGTSTP
extern MARK v_suspend(); /* ^Z */
#endif
#ifndef NO_POPUP
extern MARK v_popup(); /* \ */
#endif
/*----------------------------------------------------------------------*/
/* These flags describe the quirks of the individual visual commands */
#define NO_FLAGS 0x00
#define MVMT 0x01 /* this is a movement command */
#define PTMV 0x02 /* this can be *part* of a movement command */
#define FRNT 0x04 /* after move, go to front of line */
#define INCL 0x08 /* include last char when used with c/d/y */
#define LNMD 0x10 /* use line mode of c/d/y */
#define NCOL 0x20 /* this command can't change the column# */
#define NREL 0x40 /* this is "non-relative" -- set the '' mark */
#define SDOT 0x80 /* set the "dot" variables, for the "." cmd */
#ifndef NO_VISIBLE
# define VIZ 0x100 /* commands which can be used with 'v' */
#else
# define VIZ 0
#endif
/* This variable is zeroed before a command executes, and later ORed with the
* command's flags after the command has been executed. It is used to force
* certain flags to be TRUE for *some* invocations of a particular command.
* For example, "/regexp/+offset" forces the LNMD flag, and sometimes a "p"
* or "P" command will force FRNT.
*/
extern int force_flags;
/*----------------------------------------------------------------------*/
/* These describe what mode we're in */
#define MODE_EX 1 /* executing ex commands */
#define MODE_VI 2 /* executing vi commands */
#define MODE_COLON 3 /* executing an ex command from vi mode */
#define MODE_QUIT 4
extern int mode;
#define WHEN_VICMD 1 /* getkey: we're reading a VI command */
#define WHEN_VIINP 2 /* getkey: we're in VI's INPUT mode */
#define WHEN_VIREP 4 /* getkey: we're in VI's REPLACE mode */
#define WHEN_EX 8 /* getkey: we're in EX mode */
#define WHEN_MSG 16 /* getkey: we're at a "more" prompt */
#define WHEN_POPUP 32 /* getkey: we're in the pop-up menu */
#define WHEN_REP1 64 /* getkey: we're getting a single char for 'r' */
#define WHEN_CUT 128 /* getkey: we're getting a cut buffer name */
#define WHEN_MARK 256 /* getkey: we're getting a mark name */
#define WHEN_CHAR 512 /* getkey: we're getting a destination for f/F/t/T */
#define WHEN_INMV 4096 /* in input mode, interpret the key in VICMD mode */
#define WHEN_FREE 8192 /* free the keymap after doing it once */
#define WHENMASK (WHEN_VICMD|WHEN_VIINP|WHEN_VIREP|WHEN_REP1|WHEN_CUT|WHEN_MARK|WHEN_CHAR)
#ifndef NO_VISIBLE
extern MARK V_from;
extern int V_linemd;
extern MARK v_start();
#endif
#ifdef DEBUG
# define malloc(size) dbmalloc(size, __FILE__, __LINE__)
# define free(ptr) dbfree(ptr, __FILE__, __LINE__)
extern char *dbmalloc();
#endif

34
dist/nvi/Changes vendored Normal file
View file

@ -0,0 +1,34 @@
Changes since 1.81.5
* various compilation fixes
* support for newer DBs
* tcl support compiles again
Changes since 1.81.4
* add Changes document
* the preserve command overwrote the edited file; the problem
is really in DB; a bandaid was added
* configure changes
- -rpath now on by default
- check for iconv
* handle incomplete/invalid input
* upgrade libtool and automake
* Motif front-end was getting out of sync; fixed
* ^T works in presence of wide chars
* fix use of OPT_GLOBAL (YAMAMOTO Takashi <takashi.yamamoto@bigfoot.com>)
* missing fallback function added
* fix use of both leftright and number
(problem reported by Dima Dorfman <dima@unixfreak.org>)
* install everything 1.79 installed
* fix count argument for commands
(problem reported by Arfst Ludwig <Arfst.Ludwig@LHSystems.COM>)
* perl changes
- map no longer assumes its argument is the name of a perl function
- EXISTS for marks
* documentation changes
- vi.ref converted to texinfo
- vsplit documented
Changes since 1.81.3
* support for newer ncurses
* various other wide character related changes
* eliminate spurious cursor movements on split screens
* use of gtk-1.2 allowed again
* small fix to Motif front-end

39
dist/nvi/LICENSE vendored Normal file
View file

@ -0,0 +1,39 @@
/*-
* Id: LICENSE,v 8.17 2000/08/18 14:58:41 bostic Exp (Sleepycat) Date: 2000/08/18 14:58:41
*/
The following are the copyrights and redistribution conditions that apply
to this copy of the Vi software.
/*
* Copyright (c) 1991, 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
* Keith Bostic. All rights reserved.
* Copyright (c) 1999, 2000
* Sven Verdoolaege. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

104
dist/nvi/README vendored Normal file
View file

@ -0,0 +1,104 @@
# Id: README,v 8.153 2001/04/30 09:31:12 skimo Exp (Berkeley) Date: 2001/04/30 09:31:12
This is version 1.81.6 (2007-11-18) of nex/nvi, a reimplementation of the ex/vi
text editors originally distributed as part of the Fourth Berkeley
Software Distribution (4BSD), by the University of California, Berkeley.
The directory layout is as follows:
LICENSE ....... Copyright, use and redistribution information.
README ........ This file.
build.unix .... UNIX build directory.
catalog ....... Message catalogs; see catalog/README.
cl ............ Vi interface to the curses(3) library.
clib .......... C library replacement source code.
common ........ Code shared by ex and vi.
db ............ A stripped-down, replacement db(3) library.
dist .......... Various files used to build the vi distribution.
docs .......... Ex/vi documentation, both current and historic.
docs/README ... Documentation overview.
docs/edit ..... Edit: A tutorial.
docs/exref .... Ex Reference Manual -- Version 3.7.
docs/vi.man ... UNIX manual page for nex/nvi.
docs/vi.ref ... Nex/nvi reference manual.
docs/vitut .... An Introduction to Display Editing with Vi.
ex ............ Ex source code.
gtk ........... Vi gtk application.
include ....... Replacement include files.
ip ............ Library interface to vi: vi side.
ipc ........... Library interface to vi: application side.
motif ......... Vi motif application.
motif_l ....... Motif library interface to vi.
perl_api ...... Perl scripting language support.
perl_scripts .. Perl scripts.
regex ......... POSIX 1003.2 regular expression library.
tcl_api ....... Tcl scripting language support.
tcl_scripts ... Tcl scripts.
vi ............ Vi source code.
To build DB for a UNIX platform:
cd build.unix
../dist/configure
make
To build multiple UNIX versions of DB in the same source tree, create
a new directory then configure and build.
mkdir build.bsdos3.0
cd build.bsdos3.0
../dist/configure
make
For additional information about building DB for UNIX platforms, the
description of possible configuration options and other information
on DB configuration and build issues, see the file build.unix/README.
Bug fixes and updated versions of this software will periodically be made
available. For more information, as well as a list of Frequently Asked
Questions, see:
http://www.bostic.com/vi
To ask questions about vi, report vi problems, request notification of
future releases and/or bug fixes, or to contact the authors for any
reason, please send email to:
bostic@bostic.com
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
o This software is several years old and is the product of many folks' work.
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.
IEEE POSIX 1003.2 style regular expression support is courtesy of
Henry Spencer, for which I am *very* grateful.
Elan Amir did the original 4BSD curses work that made it possible
to support a full-screen editor using curses.
George Neville-Neil added the Tcl interpreter, and the initial
interpreter design was his.
Sven Verdoolaege added the Perl interpreter.
Rob Mayoff provided the original Cscope support.
o Many, many people suggested enhancements, and provided bug reports and
testing, far too many to individually thank.
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.

17
dist/nvi/README.1st vendored Normal file
View file

@ -0,0 +1,17 @@
This is a development version of nvi.
Use at your own risk.
Please do not contact the original authors about bugs you
find in this version. Contact skimo-vi@kotnet.org instead.
There is no guarantee that anything in this version will be
available in upcoming stable releases.
New versions will be made available on
http://www.kotnet.org/~skimo/nvi
As always this software comes with absolutely NO WARRANTY.
Now read the original README file.
Sven Verdoolaege

22
dist/nvi/README.DB3 vendored Normal file
View file

@ -0,0 +1,22 @@
This version of vi requires DB3.1 or better, which can be found
on http://www.sleepycat.com/ .
Note that there is a small problem with DB 3.2 in that it will
not let nvi read in a final line that doesn't end in a newline.
This should be fixed in DB 3.3
If your system library (such as glibc prior to version 2.2) uses a
previous version of db (e.g. DB2) internally, you must configure with
--enable-dynamic-loading to avoid symbols in the internally used db from
being resolved against the newer db.
If, on top of that, the vi binary is explicitly linked against that
previous version of db (such as might happen if you enable the perl
embedding), you should compile the 3.x version with all symbols internally
resolved. In case you use the Gnu linker (ld), this can be accomplished
by passing it the -Bsymbolic option. You can do this by setting CC
to e.g. "gcc -Wl,-Bsymbolic" prior to configuring db.
See docs/ref/build_unix/flags.html in the db distribution for more
information.
skimo@kotnet.org

123
dist/nvi/TODO vendored Normal file
View file

@ -0,0 +1,123 @@
# Id: TODO,v 8.2 1997/04/12 15:53:31 bostic Exp (Berkeley) Date: 1997/04/12 15:53:31
========================================================================
GENERAL
========================================================================
2.0: Open mode is not yet implemented.
========================================================================
DB
========================================================================
1.N When nvi edits files that don't have trailing newlines, it appends
one, regardless. This is required, by default, from POSIX.2.
1.N: If you run out of space in the recovery directory, the recovery
file is left in place.
2.0: It's known that it's possible to sync the backing files in the
wrong manner, leaving backup files that aren't recoverable. This
is going to be left alone until we have a logging version of DB,
which will hopefully fix this (or at least make it possible to
easily do so).
========================================================================
VI
========================================================================
1.N: Make the search pattern and command history (what the '.' command
executes) remembered between windows, or configurable so that it
is.
1.N: Change the screen scrolling to not eat user characters... i.e.
g/pattern/foo should not eat already entered chars.
1.N: The vi main command loop should use the general-purpose overflow
and underflow routines. In addition, the vi command loop uses
unsigned longs -- should probably be fixed as a 32-bit unsigned
type, and then check to make sure it's never used as as variable
type again.
1.N: Should "view" set a lock on the file?
1.N: Should "view" copy the file (or even open a recovery file)?
1.N: The strings found by searches should be highlighted until the next
character is entered.
1.N: Display a split vi screen for the :help command.
1.N: When getting a key for a continue screen, we should always read from
the terminal, not from a mapped key.
1.N: The sentence, paragraph and section movement commands don't match
historic practice in some boundary cases. This should be left
alone until POSIX 1003.2 makes up its mind.
1.N: The vs_sm_fill routine should scroll if possible, not always redraw.
1.N: Think about setting a dirty/inuse bits on the lines of the SMAP
structure. That way the message routines could steal lines and
refresh would continue to work, because it would know not to touch
the lines that were in use.
========================================================================
EX
========================================================================
2.0: ^C isn't passed to the shell in the script windows as an interrupt
character.
2.0: It would be nice to inverse video the replaced text during
interactive substitute.
2.0: The :args command should put the current file name out in reverse
video. This isn't going to be easy, currently only full lines can
be in reverse video, not just parts.
========================================================================
CURSES
========================================================================
1.N In single-line screens, have to press 'q' twice when quitting out
of a ":set all" display.
========================================================================
MOTIF/IPC
========================================================================
1.N: We currently permit the user to change the lines, columns and term
edit options. Shouldn't that be illegal in a window interface?
========================================================================
REDESIGN
========================================================================
2.0: There's a serious problem with error returns -- we need to separate
command failure from fatal error, consistently, over the entire source
tree. We need to rework all of vi to have three return values:
0: success
1: vi error, continue
2: fatal error, die
Right now we don't recognize fatal errors for what they are.
2.0: The complete list of POSIX.1 calls that can return EINTR are:
wait, waitpid, sleep, dup2, close, read, write,
fcntl(SETLCKW) tcsetattr, tcdrain
The problem is that technically, any system/library call can
return EINTR, so, while nvi blocks (most of?) the obvious ones,
someone may have to do a complete pass and block signals
everywhere.
2.0: The options hardtabs, lisp, optimize, redraw, and slowopen
are recognized, but not implemented.
2.0: Field editing shouldn't be hard to add to nvi:
Field editing file template:
version #
field # row/column start row/column stop
label field # Label string
re field # Matching re string.
field # row/column start row/column stop
label field # Label string
re field # Matching re string.
<tab> moves to the next field
<bs> in column 0 moves to the previous field

362
dist/nvi/build.unix/README vendored Normal file
View file

@ -0,0 +1,362 @@
# Id: README,v 8.29 2001/05/13 20:52:36 skimo Exp (Berkeley) Date: 2001/05/13 20:52:36
Nvi uses the GNU autoconf program for configuration and compilation. You
should enter:
../dist/configure
make
and nvi will configure the system and build one or two binaries: nvi and
tknvi. You can use any path to the configure script, e.g., to build for
an x86 architecture, I suggest that you do:
mkdir build.x86
cd build.x86
../dist/configure
make
There are options that you can specify to the configure command. See
the next section for a description of these options.
If you want to rebuild or reconfigure nvi, for example, because you change
your mind as to the curses library that you want to use, create a new
directory and reconfigure it using "configure" and whatever options you
choose, don't try to selectively edit the files.
By default, nvi is installed as "vi", with hard links to "ex" and "view".
To install them using different names, use the configure program options.
For example, to install them as "nvi", "nex" and "nview", use:
configure --program-prefix=n
See the section below on installation for details.
Note, if you're building nvi on a LynxOS system, you should read the
README.LynxOS file in this directory for additional build instructions
that are specific to that operating system.
If you have trouble with this procedure, send email to the addresses
listed in ../README. In that email, please provide a complete script
of the output for all of the above commands that you entered.
=-=-=-=-=-=-=
NVI'S OPTIONS TO THE CONFIGURE PROGRAM
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
There are many options that you can enter to the configuration program.
To see a complete list of the options, enter "configure --help". Only
a few of them are nvi specific. These options are as follows:
--disable-re DON'T use the nvi-provided RE routines.
--enable-debug Build a debugging version.
--enable-perlinterp Include a Perl interpreter in vi.
--enable-tclinterp Include a Tk/Tcl interpreter in vi.
--enable-gtk Build a gtk front-end.
--enable-motif Build a motif front-end.
--enable-threads Turn on thread support.
--enable-widechar Build a wide character aware vi (experimental).
--with-curses=DIR Path to curses installation.
--with-db3=db3prefix Path to db3 installation.
--enable-dynamic-loading Load DB 3 dynamically.
disable-re:
By default, nvi loads its own versions of the POSIX 1003.2 Regular
Expression routines (which are Henry Spencer's implementation).
If your C library contains an implementation of the POSIX 1003.2
RE routines (note, this is NOT the same as the historic UNIX RE
routines), and you want to use them instead, enter:
--disable-re
as an argument to configure, and the RE routines will be taken
from whatever libraries you load. Please ensure that your RE
routines implement Henry Spencer's extensions for doing vi-style
"word" searches.
enable-debug:
If you want to build nvi with no optimization (i.e. without -O
as a compiler flag), with -g as a compiler flag, and with DEBUG
defined during compilation, enter:
--enable-debug
as an argument to configure.
enable-perlinterp:
If you have the Perl 5 libraries and you want to compile in the
Perl interpreter, enter:
--enable-perlinterp
as an argument to configure. (Note: this is NOT possible with
Perl 4, or even with Perl 5 versions earlier than 5.002.)
enable-tclinterp:
If you have the Tk/Tcl libraries and you want to compile in the
Tcl/Tk interpreter, enter:
--enable-tclinterp
as an argument to configure. If your Tk/Tcl include files and
libraries aren't in the standard library and include locations,
see the next section of this README file for more information.
enable-gtk:
If you have the Gtk libraries and you want to build the Gtk
nvi front-end, enter:
--enable-gtk
as an argument to configure. If your Gtk include files and
libraries aren't in the standard library and include locations,
see the next section of this README file for more information.
See also the enable-threads option.
enable-motif:
If you have the Motif libraries and you want to build the Motif
nvi front-end, enter:
--enable-motif
as an argument to configure. If your Motif include files and
libraries aren't in the standard library and include locations,
see the next section of this README file for more information.
enable-threads:
If you want to be able to use multiple windows in the Gtk
front-end, you should specify this option.
with-curses:
Specifies the path where curses is installed.
with-db3:
Specifies the path where DB3 is installed.
See README.DB3 for more information about DB3.
enable-dynamic-loading:
Dynamically load DB3 library.
See README.DB3 for more information about DB3.
enable-widechar:
Enables support for wide characters.
Note that this is still rather experimental.
If you try this out on Solaris, you will want to point nvi
to the curses in /usr/xpg4/ which is CSI compliant.
=-=-=-=-=-=-=
ADDING OR CHANGING COMPILERS, OR COMPILE OR LOAD LINE FLAGS
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
If you want to use a specific compiler, specify the CC environment
variable before running configure. For example:
env CC=gcc configure
Using anything other than the native compiler will almost certainly
mean that you'll want to check the compile and load line flags, too.
If you want to specify additional load line flags, specify the ADDLDFLAGS
environment variable before running configure. For example:
env ADDLDFLAGS="-Q" configure
would specify the -Q flag in the load line when the nvi programs are
loaded.
If you don't want configure to use the default load line flags for the
system, specify the LDFLAGS environment variable before running configure.
For example:
env LDFLAGS="-32" configure
will cause configure to set the load line flags to "-32", and not set
them based on the current system.
If you want to specify additional compile line flags, specify the
ADDCPPFLAGS environment variable before running configure. For example:
env ADDCPPFLAGS="-I../foo" configure
would cause the compiler to be passed the -I../foo flag when compiling
test programs during configuration as well as when building nvi object
files.
If you don't want configure to use the default compile line flags for the
system, specify the CPPFLAGS environment variable before running configure.
For example:
env CPPFLAGS="-I.." configure
will cause configure to use "-I.." as the compile line flags instead of
the default values.
=-=-=-=-=-=-=
ADDING LIBRARIES AND INCLUDE FILES
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
If the Tk/Tcl or any other include files or libraries are in non-standard
places on your system, you will need to specify the directory path where
they can be found.
If you want to specify additional library paths, set the ADDLIBS environment
variable before running configure. For example:
env ADDLIBS="-L/a/b -L/e/f -ldb" configure
would specify two additional directories to search for libraries, /a/b
and /e/f, and one additional library to load, "db".
If you want to specify additional include paths, specify the ADDCPPFLAGS
environment variable before running configure. For example:
env ADDCPPFLAGS="-I/usr/local/include" LIBS="-ldb" configure
would search /usr/local/include for include files, as well as load the db
library as described above.
As a final example, let's say that you've downloaded ncurses from the net
and you've built it in a directory named ncurses which is at the same
level in the filesystem hierarchy as nvi. You would enter something like:
env ADDCPPFLAGS="-I../../ncurses/include" \
ADDLIBS="-L../../ncurses/libraries" configure
to cause nvi to look for the curses include files and the curses library
in the ncurses environment.
Notes:
Make sure that you prepend -L to any library directory names, and
that you prepend -I to any include file directory names! Also,
make sure that you quote the paths as shown above, i.e. with
single or double quotes around the values you're specifying for
ADDCPPFLAGS and ADDLIBS.
=-=-=-=-=-=
You should NOT need to add any libraries or include files to load
the Perl5 interpreter. The configure script will obtain that
information directly from the Perl5 program. This means that the
configure script must be able to find perl in its path. It looks
for "perl5" first, and then "perl". If you're building a Perl
interpreter and neither is found, it's a fatal error.
=-=-=-=-=-=
You do not need to specify additional libraries to load Tk/Tcl,
Perl or curses, as the nvi configuration script adds the
appropriate libraries to the load line whenever you specify
--enable-tknvi or other Perl or Tk/Tcl related option, or build
the Tk/Tcl or curses version of nvi. The library names that are
automatically loaded are as follows:
for Perl: -lperl
for Tk/Tcl: -ltk -ltcl -lm
for curses: -lcurses
In addition, the configure script loads:
... the X libraries when loading the Tk/Tcl libraries,
if they exist.
... the -ltermcap or -ltermlib libraries when loading
any curses library, if they exist.
=-=-=-=-=-=
The env command is available on most systems, and simply sets one
or more environment variables before running a command. If the
env command is not available to you, you can set the environment
variables in your shell before running configure. For example,
in sh or ksh, you could do:
ADDLIBS="-L/a/b -L/e/f -ldb" configure
and in csh or tcsh, you could do:
setenv ADDLIBS "-L/a/b -L/e/f -ldb"
configure
See your shell manual page for further information.
=-=-=-=-=-=-=
INSTALLING NVI
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Nvi installs the following files into the following locations, with
the following default values:
Variables: Default value:
prefix /usr/local
exec_prefix $(prefix)
bindir $(prefix)/bin
datadir $(prefix)/share
mandir $(prefix)/man
File(s): Default location
----------------------------------------
vi $(bindir)/vi
vi.1 $(mandir)/man1/vi.1
vi.0 $(mandir)/cat1/vi.0
Perl scripts $(datadir)/vi/perl/
Tcl scripts $(datadir)/vi/tcl/
Message Catalogs $(datadir)/vi/catalog/
Notes:
There are two hard links to the vi program, named ex and view.
Similarly, there are two hard links to the unformatted vi manual
page, named ex.1 and view.1, and two hard links to the formatted
manual page, named ex.0 and view.0. These links are created when
the program and man pages are installed.
If you want to install vi, ex, view and the man pages as nvi, nex,
nview, use the configure option --program-prefix=n. Other, more
complex transformations are possible -- use configure --help to
see more options.
To move the entire installation tree somewhere besides /usr/local,
change the value of both "exec_prefix" and "prefix". To move the
binaries to a different place, change the value of "bindir".
Similarly, to put the datafiles (the message catalogs, Perl and
Tcl scripts) or the man pages in a different place, change the
value of "datadir" or "mandir". These values can be changed as
part of configuration:
configure --exec_prefix=/usr/contrib --prefix=/usr/share
or when doing the install itself:
make exec_prefix=/usr/contrib prefix=/usr/contrib install
The datafile directory (e.g., /usr/local/share/vi by default) is
completely removed and then recreated as part of the installation
process.
=-=-=-=-=-=-=
NVI AND THE CURSES LIBRARY
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
The major portability problem for nvi is selecting a curses library.
Unfortunately, it is common to find broken versions of curses -- the
original System V curses was broken, resulting in all vendors whose
implementations are derived from System V having broken implementations
in turn.
If you use the vendor's or other curses library, and you see any of the
following symptoms:
+ Core dumps in curses routines.
+ Missing routines when compiling.
+ Repainting the wrong characters on the screen.
+ Displaying inverse video in the wrong places.
+ Failure to reset your terminal to the correct modes on exit.
you have a broken curses implementation, and you should reconfigure nvi
to use another curses library.
An alternative for your vendor's curses is ncurses, available from
ftp://ftp.gnu.org/pub/gnu/ncurses/
One final note. If you see the following symptoms:
+ Line-by-line screen repainting instead of scrolling.
it usually means that your termcap or terminfo information is insufficient
for the terminal.

320
dist/nvi/build.unix/README.LynxOS vendored Normal file
View file

@ -0,0 +1,320 @@
README.LynxOS
=============
Written by Ronald F. Guilmette <rfg@monkeys.com>
Last modified Wed Aug 14 23:10:07 PDT 1996
------------------------------------------
0. Introduction
---------------
This file describes how to build and install the Berkeley nvi editor for
the LynxOS 2.4.0 operating system.
LynxOS 2.4.0 is available for a variety of different hardware platforms, in
particular, x86, m680x0, Sparc, and PowerPC. I have successfully built nvi
on all four of these flavors of LynxOS by following the procedures given in
this file.
Note that these procedures may not work on versions of LynxOS prior to 2.4.0.
(As I understand it, a good deal of work went into making the 2.4.0 release
more POSIX-compliant, and I have no idea what build glitches, if any, you
might encounter if you try to build nvi on a pre-2.4.0 version of LynxOS.)
There are basically four steps to configuring, building, and installing nvi
on LynxOS, namely:
1. Get setup to use the proper C compiler.
2. Replace your installed `tr' program.
3. Fix your system include files.
4. Do a normal configure, build, and install of nvi.
These steps are described in separate sections below.
1. Get Setup to Use the Proper C Compiler
------------------------------------------
The first step when building nvi on LynxOS is to set your $PATH environment
variable properly so that the gcc 2.x compiler appears first on your path,
prior to the older (and less robust) gcc 1.xx compiler (typically installed
as /bin/gcc) and/or the old Lynx proprietary C compiler (typically installed
as /bin/cc), both of which may also be present on your system.
Note that for most operating systems, the configure script for nvi tries
to use whatever compiler you have installed (and in your $PATH) as "cc",
however in the special case of LynxOS, the configure script will auto-
matically try to find a "gcc" program on your $PATH in preference to a
compiler called "cc". If the nvi configure script only find a compiler
called "cc", that's OK. It will still try to see if that is really just
the GNU C compiler installed under the name "cc".
Regardless of the name however (be it "gcc" or "cc") the first C compiler
in your $PATH should be some _recent_ (i.e. 2.0 or later) version of the
GNU C compiler... and the nvi configure script now checks that this is the
case, and fails if it isn't.
Oddly enough, LynxOS 2.4.0 (and some prior versions) shipped with as many
as three different C compilers installed, so it is important to set your
$PATH environment variable carfully in order to get the proper C compiler
to appear first in your $PATH. You want to avoid having either the /bin/gcc
compiler or the /bin/cc compiler be the first C compiler in your $PATH.
To make sure that the GNU C version 2.x compiler which was shipped with your
LynxOS system appears first on your path, you will need to either set your
$PATH variable (for sh/bash/ksh users) or your $path variable (for csh/tcsh
users). You can, of course, just do this at the shell command prompt, but
it is probably better to actually edit this change into your .profile file
(for sh/bash/ksh users) or into your .cshrc file (for csh/tcsh users).
The pathname of the directory that contains the GNU C version 2.x compiler
is (unfortunately) dependent upon the exact type of LynxOS system you have.
For LynxOS 2.4.0 on x86 systems, gcc 2.x is located in:
/cygnus/94q4-lynxos-x86/bin
For LynxOS 2.4.0 on m680x0 systems, gcc 2.x is located in:
/cygnus/94q4-lynxos-68k/bin
For LynxOS 2.4.0 on Sparc systems, gcc 2.x is located in:
/cygnus/94q4-lynxos-usparc/bin
For LynxOS 2.4.0 on PowerPC systems, gcc 2.x is located in:
/cygnus/95q2-lynxos-ppc/bin
(Note also that these locations may change in LynxOS 2.5.x and beyond.)
Anyway, it is imperative that you setup your $PATH environment variable
(*before* you do the configure step for nvi) so that the GNU C version 2.x
compiler appears in your $PATH before either the /bin/cc or /bin/gcc
compilers (if present). If you fail to do this, the configure step for
nvi will fail, because the compiler script actually checks (now) that the
compiler you are using (if your are on a LynxOS system) is gcc 2.0 or
later.
To make absolutely sure that you will be configuring and building nvi with
the proper C compiler (i.e. the GNU C version 2.x compiler on your system)
you should add the directory name listed above for your specific system type
to your $PATH setting in your $HOME/.profile file. (For csh/tcsh users, you
will instead want to add the relevant directory name to the setting of your
$path variable in your ~/.cshrc file.) Once you have added the proper direc-
tory name (from the list given above) to your $HOME/.profile file (or to your
~/.cshrc file, if you are using csh or tcsh) you should log out completely
and then log back into the system just to make sure your new $PATH/$path
setting takes effect properly.
When you finish making this adjustment to your $PATH (or $path), the most
up-to-date version of gcc on your system should be available to you as the
first `gcc' program on your $PATH. You should verify that this is indeed the
case simply by typing `gcc -v' and then checking the version number reported
by the compiler. It should say either "2.6-94q4" or (on PowerPC systems) it
should say "2.6-95q2". If you don't get these results, try again to set your
$PATH (or $path) until you do. You won't be able to build nvi until you are
properly setup to use gcc version 2.0 or later.
Performing the steps shown above will insure that your subsequent configura-
tion and build steps for nvi will make use of the most up-to-date version of
gcc that was shipped with your Lynx operating system. (Note that the versions
of gcc which are currently shipping with LynxOS 2.4.0 are also somewhat out-
of-date themselves, but they are still quite a bit newer and more bug-free
and ANSI conformant that those other two C compilers, /bin/cc and /bin/gcc,
which also ship with LynxOS 2.4.0.)
(Note: At present, LynxOS version 2.4.0 is the latest officially released
version of LynxOS, and all of the above information is accurate and correct
for LynxOS 2.4.0 as of the time of this writing. However it is rumored that
future releases of LynxOS may provide a still newer version of gcc, and that
it may be located in the /usr/bin directory. Thus, if you are building nvi
for some LynxOS version later than 2.4.0, you may wish to check and see if
your system has a program called /usr/bin/gcc, and use that version of gcc,
if available, rather than the one suggested above.)
2. Replace Your Installed `tr' Program
---------------------------------------
The `tr' program which comes bundled with LynxOS 2.4.0 (as /bin/tr) has a
somewhat obscure bug which just happens to be tickled by almost all GNU
`autoconf' generated `configure' scripts (including the one that nowadays
comes bundled with nvi). Using the stock /bin/tr program on LynxOS when
executing such `configure' scripts _will_ cause these scripts to malfunction
in various ways. It is therefore imperative that you replace your LynxOS
/bin/tr program with a properly working version of the `tr' command _before_
you even try to configure nvi. (You can tell if your `tr' program has the
bug by executng the command "echo ab- | tr ab- ABC". If this yields the
string "Ab-" then you have the bug. If it yields "ABC" then you don't.)
You can obtain sources for a working version of the `tr' command as part of
the GNU `textutils' package (the latest version of which, at the time of this
writing, is 1.19). The GNU textutils package is available for downloading
from prep.ai.mit.edu in the pub/gnu directory. Look for the file named
textutils-1.19.tar.gz, or an even more recent version of textutils, if one
is available. Fetch it, gunzip it, untar it, and follow the directions in
the INSTALL file included in the tar file to build and install the entire
textutils set of utility programs (which includes a working `tr' program).
Then just make sure that the GNU version of `tr' appears on your $PATH
_before_ the LynxOS version of `tr' (i.e. /bin/tr). Be sure to do this
step _before_ you start to configure nvi.
When building the textutils set of programs, I suggest that you use the most
up-to-date C compiler available on your system (as described above). Also,
note that it will be important for you to AVOID using the -O (optimize)
compiler option when building the GNU textutils package, even if you are
using the most up-to-date version of gcc which shipped with your system.
If you try to use -O when building the textutils package on an x86 with
the Cygnus 94q4 C compiler, you will end up with a `tr' program which will
malfunction even worse than the one you are trying to replace! If you use
-O when building the textutils package on LynxOS on the PowerPC (using the
Cygnus 95q2 C compiler) you will just get yourself a compiler crash. So
just don't use -O when building textutils. You can avoid using -O by in-
voking make in the textutils directory as follows:
make CFLAGS="-g"
(Note: At present, LynxOS version 2.4.0 is the latest officially released
version of LynxOS, and all of the above information is accurate and correct
for LynxOS 2.4.0 as of the time of this writing. However it is rumored that
the bug in the /bin/tr program will be fixed in future releases of LynxOS,
so if you have a version of LynxOS later than 2.4.0, you may wish to check
and see if your /bin/tr program even has the problematic bug before bothering
with all of this.)
3. Fix Your System Include Files
---------------------------------
If you are building nvi on a PowerPC system, it is also important that you
apply the patches given at the end of this file to your /usr/include files.
(Note that you will have to be root in order to do this.) Two of the patches
included below fix a pair of serious bugs in the /usr/include/stdarg.h file
on the PowerPC, and you really _do_ want to have these bugs fixed anyway,
because without these fixes, anything that you compile which uses <stdarg.h>
will very likely malfunction at run-time.
Regardless of which LynxOS platform you are using (i.e. x86, PowerPC, Sparc,
or m680x0) you may want to apply all of the system include files patches that
are included below anyway. Doing so will clean up a few minor problems with
the relevant system include files (i.e. <stdarg.h>, <ioctl.h>, and <wait.h>)
and this step will also prevent a few warnings which you would otherwise get
during the build of nvi.
You can apply all of the patches given at the end of this file simply by
doing the following:
su root
cd /usr/include
/bin/patch < this-file
Where `this-file' is the actual full pathname of the file you are now reading,
wherever it may reside on your own system.
(Note: At present, LynxOS version 2.4.0 is the latest officially released
version of LynxOS, and all of the above information is accurate and correct
for LynxOS 2.4.0 as of the time of this writing. However it is rumored that
future releases of LynxOS may incorporate some or all of the important system
include file fixes provided below. Thus, if you are building nvi for some
LynxOS version later than 2.4.0, you should probably go ahead and try to
apply the patches given below to your system include files, and then just
don't worry about it if these patches seem to have already been applied.)
4. A Brief Note about Sendmail
-------------------------------
I should mention also that LynxOS does not normally ship with the `sendmail'
mail transfer program installed, either under /usr/lib/ or anywhere else for
that matter. This isn't really a big problem, but nvi normally wants and
expects to have a sendmail program available so that it can send users notifi-
cations (by mail) whenever a partially edited file is preserved by the editor
in response to a sudden system crash, a sudden system shutdown, or an unexpect-
ed serial-line hangup. You can configure and build nvi without any sendmail
program installed on your system, but you will get warnings about its absence
when you are doing the initial configure step prior to actually building nvi.
If you want to have a fully-functional nvi which does send out notification
messages (by mail) whenever partially edited files are preserved during a
serial line hangup or system crash, then you should get the BSD sendmail
sources (via ftp from ftp.cs.berkeley.edu), build and install sendmail, and
then reconfigure, rebuild, and reinstall nvi.
Please contact me at the E-mail address below if you experience any problems in
building or using nvi on LynxOS. I make no guarrantees, but I may be willing
to try to help.
Ron Guilmette
Roseville, California
<rfg@monkeys.com>
August 14, 1996
cut here for LynxOS 2.4.0 system include files patches
-----------------------------------------------------------------------------
*** wait.h Fri Apr 26 10:02:45 1996
--- wait.h Sun May 19 05:36:50 1996
***************
*** 94,104 ****
/* Function prototypes */
#ifndef __LYNXOS
- #ifdef _POSIX_SOURCE
extern pid_t wait _AP((int *));
extern pid_t waitpid _AP((pid_t, int *, int));
! #else
! extern int wait _AP((union wait *));
! extern int waitpid _AP((int, union wait *, int));
! extern int wait3 _AP((union wait *, int, struct rusage *));
#endif
#endif /* !__LYNXOS */
--- 94,101 ----
/* Function prototypes */
#ifndef __LYNXOS
extern pid_t wait _AP((int *));
extern pid_t waitpid _AP((pid_t, int *, int));
! #ifndef _POSIX_SOURCE
! extern int wait3 _AP((int *, int, struct rusage *));
#endif
#endif /* !__LYNXOS */
*** ioctl.h Fri Apr 26 16:50:51 1996
--- ioctl.h Sat May 18 17:55:16 1996
***************
*** 572,576 ****
#ifndef __LYNXOS
! extern int ioctl _AP((int, int, char *));
#endif
--- 572,576 ----
#ifndef __LYNXOS
! extern int ioctl _AP((int, int, ...));
#endif
*** stdarg.h Fri Apr 26 16:51:02 1996
--- stdarg.h Sat May 18 19:34:13 1996
***************
*** 88,92 ****
(((sizeof(TYPE) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
! #define va_start(AP, LASTARG) (AP = ((char *) __builtin_next_arg ()))
void va_end(va_list); /* Defined in libgcc.a */
--- 88,92 ----
(((sizeof(TYPE) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
! #define va_start(AP, LASTARG) (AP = ((char *) __builtin_next_arg (LASTARG)))
void va_end(va_list); /* Defined in libgcc.a */
***************
*** 162,166 ****
(((sizeof(TYPE) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
! #define va_start(AP, LASTARG) (AP = ((char *) __builtin_next_arg ()))
void va_end(va_list); /* Defined in libgcc.a */
--- 162,166 ----
(((sizeof(TYPE) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
! #define va_start(AP, LASTARG) (AP = ((char *) __builtin_next_arg (LASTARG)))
void va_end(va_list); /* Defined in libgcc.a */

10
dist/nvi/build.unix/README.Solaris vendored Normal file
View file

@ -0,0 +1,10 @@
There are some known problems with Solaris curses.
Please give ncurses a try when you encounter a screen output problem.
Apparently, the more recent Solaris compilers invoke the incremental linker,
`ild', when the "-g" option is used and one or more "xxx.o" files are
specified on the command line during the link phase. Unfortunately, the
executable produced is up to 3-4 times as big as an executable generated
by the standard linker `ld'.
You can bypass this by adding "-xildoff" to LDFLAGS or by
setting CFLAGS (to something that does not contain "-g").

84
dist/nvi/catalog/Makefile vendored Normal file
View file

@ -0,0 +1,84 @@
# Id: Makefile,v 8.30 1996/11/27 11:59:09 bostic Exp (Berkeley) Date: 1996/11/27 11:59:09
CAT= dutch english french german ru_RU.KOI8-R spanish swedish
FILES= ../cl/*.c ../common/*.c ../ex/*.c ../vi/*.c
all: dump ${CAT}
${CAT}: english.base
@echo "... $@"; \
rm -f $@; \
sort -u $@.base | \
awk '{ \
if ($$1 == 1) { \
print "\nMESSAGE NUMBER 1 IS NOT LEGAL"; \
exit 1; \
} \
if (++nline > $$1) { \
print "DUPLICATE MESSAGE NUMBER " $$1; \
exit 1; \
} \
for (; nline < $$1; ++nline) \
print ""; \
print $0; \
}' | \
sed -e '1s/^/VI_MESSAGE_CATALOG/' \
-e '/"/s/^[^"]*"//' \
-e '1!s/"$$/X/' > $@; \
chmod 444 $@; \
if grep DUPLICATE $@ > /dev/null; then \
grep DUPLICATE $@; \
fi; \
if grep 'NOT LEGAL' $@ > /dev/null; then \
grep 'NOT LEGAL' $@; \
fi
CHK= dutch.check english.check french.check german.check \
ru_RU.KOI8-R.check spanish.check swedish.check
check: ${CHK}
${CHK}: ${CAT}
@echo "... $@"; \
f=`basename $@ .check`; \
(echo "Unused message id's (this is okay):"; \
awk '{ \
while (++nline < $$1) \
printf "%03d\n", nline; \
}' < $$f.base; \
echo =========================; \
echo "MISSING ERROR MESSAGES (Please add!):"; \
awk '{print $$1}' < $$f.base | sort -u > __ck1; \
awk '{print $$1}' < english.base | sort -u > __ck2; \
comm -13 __ck1 __ck2; \
echo =========================; \
echo "Extra error messages (just delete them):"; \
comm -23 __ck1 __ck2; \
echo =========================; \
echo "MESSAGES WITH THE SAME MESSAGE ID's (FIX!):"; \
for j in \
`sed '/^$$/d' < $$f.base | sort -u | \
awk '{print $$1}' | uniq -d`; do \
egrep $$j $$f.base; \
done; \
echo =========================; \
echo "Duplicate messages, both id and message (this is okay):"; \
sed '/^$$/d' < $$f.base | sort | uniq -c | \
awk '$$1 != 1 { print $$0 }' | sort -n; \
echo =========================; \
echo "Duplicate messages, just message (this is okay):"; \
sed '/^$$/d' < $$f | sort | uniq -c | \
awk '$$1 != 1 { print $$0 }' | sort -n; \
echo =========================) > $@
english.base: dump ${FILES} #Makefile
./dump ${FILES} |\
sed -e '/|/!d' \
-e 's/|/ "/' \
-e 's/^"//' \
-e 's/\\"/"/g' |\
sort -n > $@
dump: dump.c
${CC} -O -o dump dump.c
clean:
rm -f dump dump.o ${CAT} english.base *.check __ck1 __ck2

166
dist/nvi/catalog/README vendored Normal file
View file

@ -0,0 +1,166 @@
# Id: README,v 8.4 1994/11/22 09:52:04 bostic Exp (Berkeley) Date: 1994/11/22 09:52:04
Generally, all non-system error and informational messages in nvi are
catalog messages, i.e. they can be tailored to a specific langauge.
Command strings, usage strings, system errors and other "known text"
are not. It would certainly be possible to internationalize all the
text strings in nvi, but it's unclear that it's the right thing to do.
First, there's no portable way to do message catalogs. The System V
scheme is a reasonable choice, but none of the 4BSD derived systems
support it. So, catalogs are completely implemented within nvi, and
don't require any library support.
Message catalogs in nvi are fairly simple. Every catalog message
consists of two parts -- an initial number followed by a pipe (`|')
character, followed by the English text for the message. For example:
msgq(sp, M_ERR, "001|This is an error message");
would be a typical message.
When the msgq() routine is called, if the user has specified a message
catalog and the format string (the third argument) has a leading number,
then it is converted to a record number, and that record is retrieved
from the message catalog and used as a replacement format string. If
the record can't be retrieved for any reason, the English text is displayed
instead.
Each message format string MUST map into the English format string, i.e.
it can't display more or different arguments than the English one.
For example:
msgq(sp, M_ERR, "002|Error: %d %x", arg1, arg2);
is a format string that displays two arguments. It is possible, however,
to reorder the arguments or to not display all of them. The convention
nvi uses is the System V printf(3) convention, i.e. "%[0-9]*$" is the name
of a specific, numbered argument. For example:
msgq(sp, M_ERR, "002|Error: %2$d %1$x", arg1, arg2);
displays the arguments in reverse order.
If the system supports this convention in its library printf routines
(as specified by the test #define NL_ARGMAX), nvi uses those routines.
Otherwise, there is some serious magic going on in common/msg.c to make
this all work.
Arguments to the msgq function are required to contain ONLY printable
characters. No further translation is done by the msgq routine before
displaying the message on the screen. For example, in the msgq call:
msgq(sp, M_ERR, "003|File: %s", file_name);
"file_name" must contain only printable characters. The routine
msg_print() returns a printable version of a string in allocated
memory. For example:
char *p;
p = msg_print(sp, file_name);
msgq(sp, M_ERR, M("003", "File: %s"), p);
FREE_SPACE(sp, p, 0);
makes sure that "file_name" is printable before calling the msgq
routine.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
The message catalogs themselves are maintained in two files. The first
is the "base file" which contains two fields, a record number and the
message itself. All base files are named using the convention
"vi_<language>.base", e.g. the English one is "vi_english.base". For
example:
002 "Unable to create temporary file"
003 "Warning: %s is not a regular file"
004 "%s already locked, session is read-only"
005 "%s: remove"
006 "%s: close"
007 "%s: remove"
008 "%s: remove"
009 "Read-only file, not written; use ! to override"
010 "Read-only file, not written"
are the first few lines of the current vi_english.base file. Note that
message #1 is missing -- the first message of each catalog is a special
one, so that nvi can recognize message catalog files. It's added by the
Makefile script that creates the second version of the message catalog.
The second file is the file used by nvi to access messages, and is a list
of the messages, one per line:
VI_MESSAGE_CATALOG
Unable to create temporary fileX
Warning: %s is not a regular fileX
%s already locked, session is read-onlyX
%s: removeX
%s: closeX
%s: removeX
%s: removeX
Read-only file, not written; use ! to overrideX
Read-only file, not writtenX
Note that all messages have had a trailing 'X' character appended. This
is to provide nvi a place to store a trailing nul for the message so that
C library routines that expect one won't be disappointed.
These files are named for their language, e.g. "vi_english". The second
files are automatically created from the first files.
To create a new catalog for nvi:
Copy the file vi_english.base to a file that you can modify , e.g. "cp
vi_english.base vi_german.base". For each of the messages in the file,
replace the message with the string that you want to use. To find out
what the arguments to a message are, I'm afraid you'll have to search
the source code for the message number. You can find them fairly quickly
by doing:
cd ..; egrep '123\|' */*.[chys]
I'm sorry that there's not an easier way, but I couldn't think of
anything that wasn't a lot of work.
If, for some reason, you don't have the file vi_english.base, or you
have new sources for which you want to create a new base catalog, you
can create it by running the command "make english" in the catalog
directory.
Once you've translated all of the strings, then add your catalog to the
"CAT=" line of the Makefile, and run the command "make catalog". This
will create the second (and corresponding) file for each file named
<language>.base.
Don't worry about missing line numbers, i.e. base files that look like:
005 Message number 5.
007 Message number 7.
This simply means that a message was deleted during the course of nvi's
development. It will be taken care of automatically when you create
the second form of the file.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
If you add new messages to the nvi sources, you can check your work by
doing "make english; make check". The "make check" target lists unused
message numbers, duplicate message numbers, and duplicate messages.
Unused message numbers are only useful if you are condensing messages.
Duplicate message numbers are a serious problem and have to be fixed.
Duplicate messages are only interesting if a message appears often enough
that it's worth creating a routine so that the string is only need in
a single place.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
To select a catalog when running nvi, set the "msgcat" option. If the
value of this option ends with a '/', it is treated as the name of a
directory that contains a message catalog "vi_XXXX", where XXXX is the
value of the LANG environmental variable, if it's set, or the value of
the LC_MESSAGES environmental variable if it's not. If neither of those
environmental variables are set, or if the option doesn't end in a '/',
the option is treated as the full path name of the message catalog to use.
If any messages are missing from the catalog, the backup text (English)
is used instead.

91
dist/nvi/catalog/dump.c vendored Normal file
View file

@ -0,0 +1,91 @@
/* $NetBSD: dump.c,v 1.2 2008/06/11 21:30:52 aymeric Exp $ */
/*-
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* %sccs.include.redist.c%
*/
#ifndef lint
static char copyright[] =
"%Z% 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[] = "Id: dump.c,v 8.1 1994/08/31 13:27:37 bostic Exp (Berkeley) Date: 1994/08/31 13:27:37";
#endif /* not lint */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
static void
parse(fp)
FILE *fp;
{
int ch, s1, s2, s3;
#define TESTD(s) { \
if ((s = getc(fp)) == EOF) \
return; \
if (!isdigit(s)) \
continue; \
}
#define TESTP { \
if ((ch = getc(fp)) == EOF) \
return; \
if (ch != '|') \
continue; \
}
#define MOVEC(t) { \
do { \
if ((ch = getc(fp)) == EOF) \
return; \
} while (ch != (t)); \
}
for (;;) {
MOVEC('"');
TESTD(s1);
TESTD(s2);
TESTD(s3);
TESTP;
putchar('"');
putchar(s1);
putchar(s2);
putchar(s3);
putchar('|');
for (;;) { /* dump to end quote. */
if ((ch = getc(fp)) == EOF)
return;
putchar(ch);
if (ch == '"')
break;
if (ch == '\\') {
if ((ch = getc(fp)) == EOF)
return;
putchar(ch);
}
}
putchar('\n');
}
}
int
main(argc, argv)
int argc;
char *argv[];
{
FILE *fp;
for (; *argv != NULL; ++argv) {
if ((fp = fopen(*argv, "r")) == NULL) {
perror(*argv);
exit (1);
}
parse(fp);
(void)fclose(fp);
}
exit (0);
}

306
dist/nvi/catalog/dutch.base vendored Normal file
View file

@ -0,0 +1,306 @@
002 "regel te lang"
003 "kan regel %lu niet verwijderen"
004 "kan niet toevoegen aan regel %lu"
005 "kan niet invoegen vooraan regel %lu"
006 "kan regel %lu niet opslaan"
007 "kan laatste regel niet lezen"
008 "Fout: kan regel %lu niet vinden"
009 "log bestand"
010 "Er vindt geen logging plaats, kan wijzigingen niet ongedaan maken"
011 "geen wijzigingen om ongedaan te maken"
012 "Er vindt geen logging plaats, kan wijzigingen niet ongedaan maken"
013 "Er vindt geen logging plaats, herhaling niet mogelijk"
014 "geen wijzigingen om te herhalen"
015 "%s/%d: schrijven naar log mislukt"
016 "Vi's standaard invoer en uitvoer moeten aan een terminal gekoppeld zijn"
017 "Merk %s: niet gezet"
018 "Merk %s: de regel is verwijderd"
019 "Merk %s: de cursor positie bestaat niet meer"
020 "Fout: "
021 "nieuw bestand"
022 "naam veranderd"
023 "gewijzigd"
024 "ongewijzigd"
025 "NIET BEVEILIGD"
026 "niet schrijfbaar"
027 "regel %lu uit %lu [%ld%%]"
028 "leeg bestand"
029 "regel %lu"
030 "Het bestand %s is geen message catalog"
031 "Niet in staat om de standaard %s optie in te stellen"
032 "Gebruik: %s"
033 "set: optie %s onbekend: 'set all' laat alle opties zien"
034 "set: [no]%s optie kan geen waarde hebben"
035 "set: %s optie moet een waarde hebben"
036 "set: %s optie: %s"
037 "set: %s optie: %s: getal is te groot"
038 "set: %s optie: %s is een ongeldige waarde"
039 "set: %s optie moet een waarde hebben"
040 "Te weinig kolommen op het scherm, minder dan %d"
041 "Aantal kolommen te groot, meer dan %d"
042 "Te weinig regels op het scherm, minder dan %d"
043 "Aantal regels te groot, meer dan %d"
044 "De lisp optie is niet ondersteund"
045 "messages niet uitgeschakeld: %s"
046 "messages niet geactiveerd: %s"
047 "set: de %s optie moet karakter paren bevatten"
053 "De standaard buffer is leeg"
054 "Buffer %s is leeg"
055 "Bestanden met newlines in de naam kunnen niet hersteld worden"
056 "Wijzigingen kunnen niet ongedaan gemaakt worden als deze sessie mislukt"
057 "Bestand wordt gecopieerd voor herstel..."
058 "Herstel mechanisme werkt niet: %s"
059 "Wijzigingen kunnen niet ongedaan gemaakt worden als deze sessie mislukt"
060 "Kon bestand niet veilig stellen: %s"
061 "Bestand wordt gecopieerd voor herstel..."
062 "Informatie met betrekking tot gebruiker nummer %u niet gevonden"
063 "Kan herstel bestand niet beveiligen"
064 "herstel buffer overgelopen"
065 "herstel bestand"
066 "%s: verminkt herstel bestand"
067 "%s: verminkt herstel bestand"
068 "U heeft geen bestand genaamd %s te herstellen"
069 "U kan eerdere versies van dit bestand herstellen"
070 "U kan nog meer bestanden herstellen"
071 "kan geen email versturen: %s"
072 "Bestand leeg; niets om te doorzoeken"
073 "Einde van het bestand bereikt zonder dat het patroon gevonden is"
074 "Geen vorig zoek patroon"
075 "Patroon niet gevonden"
076 "Begin van het bestand bereikt zonder dat het patroon gevonden is"
077 "Zoek-operatie omgeslagen"
078 "Bezig met zoeken..."
079 "Geen niet-printbaar karakter gevonden"
080 "Onbekend commando"
082 "Commando niet beschikbaar in ex mode"
083 "Aantal mag niet nul zijn"
084 "%s: ongeldige regel aanduiding"
085 "Interne fout in syntax tabel (%s: %s)"
086 "Gebruik: %s"
087 "%s: tijdelijke buffer niet vrijgegeven"
088 "Vlag offset voor regel 1"
089 "Vlag offset voorbij bestands einde"
090 "bestand/scherm veranderd tijdens uitvoeren van @ in een blok"
091 "bestand/scherm veranderd tijdens uitvoeren van globaal/v commando"
092 "Ex commando mislukt: rest van commando(s) genegeerd"
093 "Ex commando mislukt: gemappede toetsen genegeerd"
094 "Het tweede adres is kleiner dan het eerste"
095 "Geen merk naam opgegeven"
096 "\\ niet gevolgd door / of ?"
097 "Referentie aan een regel nummer kleiner dan 0"
098 "Het %s commando is onbekend"
099 "Adres waarde te groot"
100 "Adres waarde te klein"
101 "Ongeldige adres combinatie"
102 "Ongeldig adres: slechts %lu regels in het bestand aanwezig"
103 "Ongeldig adres: het bestand is leeg"
104 "Het %s commando staat het adres 0 niet toe"
105 "Geen afkortingen om weer te geven"
106 "Afkortingen moeten eindigen met een "woord" letter"
107 "Afkortingen mogen geen tabulaties of spaties bevatten"
108 "Afkortingen mogen geen woord/niet-woord karakters mengen, behalve aan het einde"
109 ""%s" is geen afkorting"
110 "Vi commando mislukt: gemappede toetsen genegeerd"
111 "Dit is het laatste bestand"
112 "Dit is het eerste bestand"
113 "Dit is het eerste bestand"
114 "lijst met bestanden is leeg"
115 "Geen voorgaand commando om "!" te vervangen"
116 "Geen bestandsnaam voor %%"
117 "Geen bestandsnaam voor #"
118 "Fout: execl: %s"
119 "I/O fout: %s"
120 "Bestand gewijzigd sinds laatste schrijfactie; schrijf het weg of gebruik ! om het te forceren"
121 "Kan uw home directory niet vinden"
122 "Nieuwe huidige directory: %s"
123 "Geen cut buffers aanwezig"
124 "Het %s commando kan niet gebruikt worden in een globaal of v commando"
125 "%s/%s: niet gelezen: noch U noch root is de eigenaar"
126 "%s/%s: niet gelezen: U bent niet de eigenaar"
127 "%s/%s: niet gelezen: kan gewijzigd worden door andere gebruikers"
128 "%s: niet gelezen: noch U noch root is de eigenaar""
129 "%s: niet gelezen: U bent niet de eigenaar"
130 "%s: niet gelezen: kan gewijzigd worden door andere gebruikers"
131 "Geen volgende regel om samen te voegen"
132 "Geen input map entries"
133 "Geen command map entries"
134 "Het %s karakter kan niet ge-remapped worden"
135 ""%s" is niet gemapped"
136 "Merk naam moet een enkel karakter zijn"
137 "%s bestaat al, niet weggeschreven; gebruik ! om het te forceren"
138 "Nieuw .exrc bestand: %s. "
139 "doel regel ligt in het blok"
140 "Het open commando vereist dat de open optie actief is"
141 "Het open commando is nog niet ondersteund"
142 "Kan dit bestand niet veilig stellen"
143 "Bestand veilig gesteld"
144 "%s resulteert in te veel bestandsnamen"
145 "Alleen echte bestanden en named pipes kunnen gelezen worden"
146 "%s: lees beveiliging niet beschikbaar"
147 "Bezig met lezen..."
148 "%s: %lu regels, %lu karakters"
149 "Geen achtergrond schermen aanwezig"
150 "Het script commando is alleen beschikbaar in vi mode"
151 "Geen comando om uit te voeren"
152 "shiftwidth optie op 0 gezet"
153 "Count te groot"
154 "Count te klein"
155 "Reguliere expressie opgegeven; r vlag heeft geen betekenis"
156 "De #, l en p vlaggen kunnen niet gecombineerd worden met de c vlag in vi mode"
157 "Geen match gevonden"
158 "Geen voorafgaande tag aanwezig"
159 "Minder dan %s elementen op de tags stapel; gebruik :display t[ags]"
160 "Geen bestand genaamd %s op de tags stapel; gebruik :display t[ags]"
161 "Kies Enter om door te gaan: "
162 "%s: tag niet gevonden"
163 "%s: verminkte tag in %s"
164 "%s: Het regel nummer van deze tag is voorbij het einde van het bestand"
165 "De tags stapel is leeg"
166 "%s: zoek patroon niet gevonden"
167 "%d andere bestanden te wijzigen"
168 "Buffer %s is leeg"
169 "Bevestig wijziging? [n]"
170 "Onderbroken"
171 "Geen voorafgaande buffer om uit te voeren"
172 "Geen vorige reguliere expressie"
173 "Het %s commando vereist dat er een bestand geladen is"
174 "Gebruik: %s"
175 "Het visual commando vereist dat de open optie actief is"
177 "Leeg bestand"
178 "Geen voorafgaand F, f, T of t zoek commando"
179 "%s niet gevonden"
180 "Geen voorafgaand bestand te bewerken"
181 "Cursor niet op een getal"
182 "Getal wordt te groot"
183 "Getal wordt te klein"
184 "Geen overeenkomstig karakter op deze regel"
185 "Overeenkomstig karakter niet gevonden"
186 "Geen karakters te vervangen"
187 "Geen ander scherm aanwezig"
188 "Karakters achter het zoek patroon, de regel offset, en/of het z commando"
189 "Geen voorafgaand zoek patroon"
190 "Zoekopdracht na omslag teruggekeerd op originele positie"
191 "Afkorting overschrijdt expansie limiet: karakters genegeerd"
192 "Ongeldig karakter; quote to enter"
193 "Reeds aan het begin van de invoer"
194 "Niet meer karakters te verwijderen"
195 "Verplaatsing voorbij het einde van het bestand"
196 "Verplaatsing voorbij het einde van de regel"
197 "Cursor niet verplaatst"
198 "Reeds aan het begin van het bestand"
199 "Verplaatsing voorbij het begin van het bestand"
200 "Reeds in de eerste kolom"
201 "Buffers moeten voor het commando opgegeven worden"
202 "Reeds bij het einde van het bestand"
203 "Reeds bij het einde van de regel"
204 "%s is geen vi commando"
205 "Gebruik: %s"
206 "Geen karakters te verwijderen"
207 "Het Q commando vereist de ex terminal interface"
208 "Geen commando om te herhalen"
209 "Het bestand is leeg"
210 "%s mag niet gebruikt worden als een verplaatsings commando"
211 "Al in commando mode"
212 "Cursor niet in een woord"
214 "Windows optie waarde is te groot, maximum is %u"
215 "Toevoegen"
216 "Veranderen"
217 "Commando"
218 "Invoegen"
219 "Vervangen"
220 "Verplaatsing voorbij het eind van het scherm"
221 "Verplaatsing voorbij het begin van het scherm"
222 "Scherm moet meer dan %d regels hebben om het te kunnen splitsen"
223 "Er zijn geen achtergrond schermen"
224 "Er is geen achtergrond scherm waarin U bestand %s aan het bewerken bent"
225 "U kan uw enige scherm niet in de achtergrond zetten"
226 "Het scherm kan slechts verkleind worden tot %d regels"
227 "Het scherm kan niet kleiner"
228 "Het scherm kan niet groter"
230 "Dit scherm kan niet gesuspend worden"
231 "Onderbroken: gemappede toetsen genegeerd"
232 "vi: tijdelijke buffer niet vrijgegeven"
233 "Deze terminal heeft geen %s toets"
234 "Er kan slechts een buffer opgegeven worden"
235 "Getal groter dan %lu"
236 "Onderbroken"
237 "Aanmaken van tijdelijk bestand is mislukt"
238 "Waarschuwing: %s is geen regulier bestand"
239 "%s is al geopend, bestand is in deze sessie niet schrijfbaar"
240 "%s: verwijdering mislukt"
241 "%s: sluiting mislukt"
242 "%s: verwijdering mislukt"
243 "%s: verwijdering mislukt"
244 "Bestand niet schrijfbaar, niet weggeschreven; gebruik ! om het te forceren"
245 "Bestand niet schrijfbaar, niet weggeschreven"
246 "%s bestaat al, niet weggeschreven; gebruik ! om het te forceren"
247 "%s bestaat al, niet weggeschreven"
248 "Gebruik ! om een incompleet bestand weg te schrijven"
249 "Bestand incompleet, niet weggeschreven"
250 "%s: bestand op disk nieuwer dan deze versie; gebruik ! om het te forceren"
251 "%s: bestand op disk nieuwer dan deze versie"
252 "%s: schrijf beveiliging niet beschikbaar"
253 "Bezig met schrijven..."
254 "%s: WAARSCHUWING: BESTAND INCOMPLEET"
255 "Reeds op de eerste tag van deze groep"
256 "%s: nieuw bestand: %lu regels, %lu karakters"
257 "%s: %lu regels, %lu karakters"
258 "%s resulteert in te veel bestandsnamen"
259 "%s: geen normaal bestand"
260 "%s: U bent niet de eigenaar"
261 "%s: kan gewijzigd worden door andere gebruikers"
262 "Bestand gewijzigd sinds laatste schrijfactie; schrijf het weg of gebruik ! om het te forceren"
263 "Bestand gewijzigd sinds laatste schrijfactie; schrijf het weg of gebruik :edit! om het te forceren"
264 "Bestand gewijzigd sinds laatste schrijfactie; schrijf het weg of gebruik ! om het te forceren"
265 "Tijdelijk bestand; exit negeert wijzigingen"
266 "Bestand niet schrijfbaar, wijzigingen niet automatisch weggeschreven"
267 "log opnieuw gestart"
268 "Bevestig? [ynq]"
269 "Druk op een toets om door te gaan: "
270 "Druk op een toets om door te gaan [: voor meer ex commandos]: "
271 "Druk op een toets om door te gaan [q om te stoppen]: "
272 "Deze vorm van %s vereist de ex terminal interface"
273 "Entering ex input mode."
274 "Commando mislukt, nog geen bestand geladen."
275 " doorgaan?"
276 "Onverwacht character event"
277 "Onverwacht end-of-file event"
278 "Geen match gevonden voor dit patroon"
279 "Onverwacht interrupt event"
280 "Onverwacht quit event"
281 "Onverwacht repaint event"
282 "Reeds op de laatste tag van deze groep"
283 "Het %s command vereist de ex terminal interface"
284 "Deze vorm van %s is niet ondersteund als de secure edit optie actief is"
285 "Onverwacht string event"
286 "Onverwacht timeout event"
287 "Onverwacht write event"
289 "Shell expansies zijn niet ondersteund als de secure edit optie actief is"
290 "Het %s commando is niet ondersteund als de secure edit optie actief is"
291 "set: %s mag niet uitgezet worden"
292 "Scherm te klein."
293 "toegevoegd"
294 "gewijzigd"
295 "verwijderd"
296 "samengevoegd"
297 "verplaatst"
298 "verschoven"
299 "gebufferd"
300 "regel"
301 "regels"
302 "Vi was niet geladen met een Tcl interpreter"
303 "Bestand gewijzigd sinds het de laatste keer weg is geschreven."
304 "Shell expansie mislukt"
305 "Geen %s edit optie opgegeven"
306 "Vi was niet geladen met een Perl interpreter"
307 "Geen ex commando om uit te voeren"
308 "Kies <CR> om commando uit te voeren, :q om te stoppen"
309 "Gebruik "cscope help" voor uitleg"
310 "Nog geen cscope connectie aanwezig"
311 "%s: onbekend zoek type: gebruik een van %s"
312 "%d: onbekende cscope sessie"
313 "set: de %s optie mag nooit aangezet worden"
314 "set: de %s optie mag nooit op 0 gezet worden"
315 "%s: toegevoegd: %lu regels, %lu karakters"
316 "Onverwacht resize event"
317 "%d bestanden te wijzigen"

1
dist/nvi/catalog/dutch.owner vendored Normal file
View file

@ -0,0 +1 @@
J.G. Vons <Gert-Jan.Vons@ocegr.fr>

1
dist/nvi/catalog/english.owner vendored Normal file
View file

@ -0,0 +1 @@
Keith Bostic <bostic@cs.berkeley.edu>

308
dist/nvi/catalog/french.base vendored Normal file
View file

@ -0,0 +1,308 @@
002 "Dépassement de longueur de ligne"
003 "impossible de supprimer la ligne %lu"
004 "impossible d'ajouter à la ligne %lu"
005 "impossible d'insérer devant la ligne %lu"
006 "impossible de stocker la ligne %lu"
007 "impossible d'obtenir la dernière ligne"
008 "Erreur : impossible de récupérer la ligne %lu"
009 "Fichier journal"
010 "Aucune journalisation n'étant effectuée, impossible d'annuler"
011 "Aucune action à annuler"
012 "Aucune journalisation n'étant effectuée, impossible d'annuler"
013 "Aucune journalisation n'étant effectuée, reprise actualisée impossible"
014 "Aucune action à refaire"
015 "%s/%d : Erreur d'écriture de journal"
016 "L'entrée et la sortie Vi standards doivent être un terminal"
017 "Marque %s : non définie"
018 "Marque %s : la ligne a été supprimée"
019 "Marque %s : la position du curseur n'existe plus"
020 "Erreur : "
021 "nouveau fichier"
022 "le nom a changé"
023 "modifié"
024 "non modifié"
025 "DÉVERROUILLÉ"
026 "lecture seule"
027 "ligne %lu de %lu [%ld%%]"
028 "fichier vide"
029 "ligne %lu"
030 "Ce fichier %s n'est pas un catalogue de messages"
031 "Impossible de configurer option %s par défaut"
032 "Utilisation : %s"
033 "Définition : pas d'option %s : 'set all' donne toutes les valeurs optionnelles"
034 "Définition : option [no]%s ne prend pas de valeur"
035 "Définition : l'option %s n'est pas booléenne"
036 "Définition : option %s : %s"
037 "Définition : option %s : %s : Dépassement de valeur"
038 "Définition : option %s : %s n'est pas un nombre valide"
039 "Définition : l'option %s n'est pas booléenne"
040 "Les colonnes de l'écran sont trop petites, inférieures à %d"
041 "Les colonnes de l'écran sont trop grandes, supérieures à %d"
042 "Les lignes de l'écran sont trop courtes, inférieures à %d"
043 "Les lignes de l'écran sont trop longues, supérieures à %d"
044 "L'option lisp n'est pas implémentée"
045 "Les messages ne sont pas désactivés : %s"
046 "Les messages ne sont pas activés : %s"
047 "Dfinition : l'option de %s doit ˆtre en groupe de deux caractŠres"
053 "Le tampon par défaut est vide"
054 "Le tampon %s est vide"
055 "Les fichiers dont le nom contient des caractères de saut de ligne sont irrécupérables"
056 "Impossible de récupérer les modifications si la session échoue"
057 "Copie en cours du fichier pour récupération..."
058 "La préservation a échoué : %s"
059 "Impossible de récupérer les modifications si la session échoue"
060 "La sauvegarde du fichier a échoué : %s"
061 "Copie en cours du fichier pour récupération..."
062 "Les renseignements sur l'identité %u de l'utilisateur sont introuvables"
063 "Impossible de verrouiller le fichier de récupération"
064 "Débordement de tampon du fichier de récupération"
065 "Fichier de récupération"
066 "%s : Fichier de récupération malformé"
067 "%s : Fichier de récupération malformé"
068 "Aucun fichier nommé %s à récupérer, que vous puissiez lire"
069 "Il existe des versions récupérables antérieures à ce fichier"
070 "Vous avez d'autres fichiers à récupérer"
071 "pas d'envoi d'email : %s"
072 "Fichier vide, rien à rechercher"
073 "Fin de fichier atteinte sans trouver le motif"
074 "Pas de motif de recherche précédent"
075 "Motif introuvable"
076 "Début du fichier atteint sans trouver le motif"
077 "La recherche est revenue à son point de départ"
078 "Recherche en cours..."
079 "Caractère non-imprimable introuvable"
080 "Nom de commande inconnu"
082 "%s : Commande non disponible en ex mode"
083 "Le compteur ne peut être zéro"
084 "%s : mauvaise spécification de ligne"
085 "Erreur de tableau de syntaxe interne (%s: %s)"
086 "Utilisation : %s"
087 "%s : tampon temporaire non libéré"
088 "Décalage de drapeau hors de la ligne 1"
089 "Décalage de drapeau hors de la fin du fichier"
090 "@ avec plage, en cours d'exécution quand le fichier/l'écran a changé"
091 "Commande Global/v en cours d'exécution quand le fichier/l'écran a changé"
092 "La commande ex a échoué : commandes en attente abandonnées"
093 "La commande ex a échoué : les touches affectées sont abandonnées"
094 "La deuxième adresse est plus petite que la première"
095 "Aucun nom de marque fourni"
096 "\\ non suivi par / ou ?"
097 "Référence à un numéro de ligne inférieure à 0"
098 "La commande %s est inconnue"
099 "Dépassement de la valeur adresse"
100 "Dépassement négatif de la valeur adresse"
101 "Combinaison d'adresse non valide"
102 "Adresse non valide : il n'y a que %lu lignes dans ce fichier"
103 "Adresse non valide : le fichier est vide"
104 "La commande %s ne permet pas une adresse de 0"
105 "Pas d'abréviations à afficher"
106 "Les abréviations doivent finir par un caractère"mot"
107 "Les abréviations ne peuvent pas contenir de tabulations ni d'espaces"
108 "Les abréviations ne peuvent pas contenir un mélange de caractères mot/non-mot, sauf à la fin"
109 ""%s" n'est pas une abréviation"
110 "La commande Vi a échoué : Les touches affectées ont été abandonnées"
111 "Plus de fichiers à éditer"
112 "Pas de fichiers précédents à éditer"
113 "Pas de fichiers précédents à rembobiner"
114 "Pas de liste de fichiers à afficher"
115 "Pas de commande précédente à remplacer"!""
116 "Pas de nom de fichier à substituer à %%"
117 "Pas de nom de fichier à substituer à #"
118 "Erreur : execl : %s"
119 "Erreur E/S : %s"
120 "Fichier modifié depuis la dernière écriture complète ; écrire ou utiliser ! pour outrepasser"
121 "Impossible de trouver l'emplacement du répertoire d'origine"
122 "Nouveau répertoire en cours : %s"
123 "Pas de tampon de coupure à afficher"
124 "La commande %s ne peut pas être utilisée à l'intérieur d'une commande globale ou commande v"
125 "%s/%s : échec de source : ni vous ni le super-utilisateur n'êtes les propriétaires "
126 "%s/%s : échec de source : vous n'êtes pas le propriétaire"
127 "%s/%s : échec de source : peut être écrit par un utilisateur autre que le propriétaire"
128 "%s : échec de source : ni vous ni le super-utilisateur n'êtes les propriétaires"
129 "%s : échec de source : vous n'êtes pas le propriétaire"
130 "%s : échec de source : peut être écrit par un utilisateur autre que le propriétaire"
131 "Pas de lignes suivantes à joindre"
132 "Pas d'entrées de mappage d'entrée"
133 "Pas d'entrées de mappage de commandes"
134 "Le caractère %s ne peut pas être remappé"
135 ""%s" n'est pas actuellement mappé"
136 "Les noms de marque ne doivent avoir qu'un caractère"
137 "%s existe, non enregistré; utiliser ! pour outrepasser"
138 "Nouveau fichier exrc : %s"
139 "La ligne de destination est à l'intérieur de la plage à déplacer"
140 "La commande ouverte nécessite que l'option ouverte soit définie"
141 "La commande ouverte n'est pas encore implémentée"
142 "La préservation de ce fichier est impossible"
143 "Fichier préservé"
144 "%s: étendu dans trop de noms de fichiers"
145 "Vous ne pouvez lire que les fichiers standards et les canaux de transmission nommés"
146 "%s: Interdiction de lecture non disponible"
147 "Lecture en cours..."
148 "%s: %lu lignes, %lu caractères"
149 "Pas d'écrans d'arrière-plan à afficher"
150 "La commande script n'est disponible qu'en mode vi"
151 "Pas de commande à exécuter"
152 "Option de largeur de décalage définie sur 0"
153 "Compter dépassement"
154 "Compter dépassement négatif"
155 "Expression standard spécifiée; drapeau r superflu"
156 "Vous ne pouvez pas en mode vi, combiner les drapeaux #, l et p avec le drapeau c"
157 "Aucune correspondance trouvée"
158 "Aucune marque précédente entrée"
159 "Moins de %s entrées dans la pile de marques ; utilisez t[ags]"
160 "Pas de fichier %s vers lequel retourner dans la pile de marques ; utiliser : affichage t[ags]"
161 "Appuyez sur Entrée pour continuer :"
162 "%s : marque introuvable"
163 "%s : marque corrompue en %s"
164 "%s : le numéro de ligne de la marque dépasse la fin du fichier"
165 "La pile de marques est vide"
166 "%s : motif de recherche introuvable"
167 "%d fichiers supplémentaires à éditer"
168 "Le tampon %s est vide
169 "Confirmer les changements ? [n]"
170 "Interrompu"
171 "Pas de tampon précédent à exécuter"
172 "Pas d'expression standard précédente"
173 "La commande %s nécessite qu'un fichier ait déjà été lu en mémoire"
174 "Utilisation : %s"
175 "La commande visual nécessite que l'option open soit définie"
177 "Fichier vide"
178 "Pas de recherche précédente F, f, T ou t"
179 "%s introuvable"
180 "Pas de fichier précédent à éditer"
181 "Le curseur n'est pas dans un nombre"
182 "Le nombre obtenu est trop grand"
183 "Le nombre obtenu est trop petit"
184 "Pas de correspondance de caractère sur cette ligne"
185 "Caractère correspondant introuvable"
186 "Pas de caractères à remplacer"
187 "Pas d'autre écran vers lequel basculer"
188 "Caractères après la chaîne de recherche, décalage de ligne et/ou commande z"
189 "Pas de motif de recherche précédent"
190 "La recherche est revenue à son point de départ"
191 "L'abréviation a dépassé la limite de l'expansion : caractères abandonnés"
192 "Caractère non valide ; guillemet pour saisir"
193 "Déjà au début de l'insertion"
194 "Plus de caractères à effacer"
195 "Déplacement hors de fin de fichier"
196 "Déplacement hors de fin de ligne"
197 "Aucun mouvement de curseur n'a été effectué"
198 "Déjà au début du fichier"
199 "Déplacement hors du début du fichier"
200 "Déjà dans la première colonne"
201 "Les tampons doivent être spécifiés avant la commande"
202 "Déjà à la fin du fichier"
203 "Déjà à la fin de la ligne"
204 "%s n'est pas une commande vi"
205 "Utilisation : %s"
206 "Pas de caractères à supprimer"
207 "La commande Q nécessite une interface terminal ex"
208 "Pas de commande à répéter"
209 "Le fichier est vide"
209 "Le fichier est vide"
210 "Vous ne pouvez pas utiliser %s comme commande de déplacement"
211 "Déjà en mode commande"
212 "Le curseur n'est pas dans un mot"
214 "Valeur optionnelle de fenêtre trop grande, maximum est %u"
215 "Ajouter"
216 "Changer"
217 "Commande"
218 "Insérer"
219 "Remplacer"
220 "Déplacement hors de la fin d'écran"
221 "Déplacement hors du début d'écran"
222 "L'écran doit être supérieur à %d lignes pour se fractionner"
223 "Il n'y a pas d'écran d'arrière-plan"
224 "Il n'y a pas d'écran d'arrière-plan qui édite un fichier nommé %s"
225 "Vous ne pouvez pas mettre à l'arrière-plan votre seul écran affiché"
226 "L'écran ne peut être réduit qu'à %d rangs"
227 "L'écran n'est pas auto-réductible"
228 "L'écran n'est pas auto-extensible"
230 "Vous ne pouvez pas mettre cet écran en attente"
231 "Interrompu : les touches affectées ont été abandonnées"
232 "vi : le tampon temporaire n' a pas été libéré"
233 "Ce terminal n'a pas de touche %s"
234 "Vous ne pouvez spécifier qu'un seul tampon"
235 "Nombre supérieur à %lu"
236 "Interrompu"
237 "Impossible de créer un fichier temporaire"
238 "Avertissement : %s n'est pas un fichier standard"
239 "%s déjà verrouillé, session en lecture seule"
240 "%s: supprimer"
241 "%s: fermer"
242 "%s: supprimer"
243 "%s: supprimer"
244 "Fichier en lecture seule, non écrit, utiliser ! pour outrepasser"
245 "Fichier en lecture seule, non écrit"
246 "%s existe, non écrit; utiliser ! pour outrepasser"
247 "%s existe, non écrit"
248 "Fichier partiel, non écrit; utiliser ! pour outrepasser"
249 "Fichier partiel, non écrit"
250 "%s: fichier modifié plus récemment que cet exemplaire; utiliser ! pour outrepasser"
251 "%s: fichier modifié plus récemment que cet exemplaire"
252 "%s: interdiction d'écriture non disponible"
253 "Ecriture en cours..."
254 "%s: AVERTISSEMENT : FICHIER TRONQUÉ"
255 "Première marque de ce groupe déjà atteinte"
256 "%s: nouveau fichier : %lu lignes, %lu caractères"
257 "%s: %lu lignes, %lu caractères"
258 "%s étendue à trop de noms de fichiers"
259 "%s: pas un fichier standard"
260 "%s: ne vous appartient pas"
261 "%s: accessible par un utilisateur autre que son propriétaire"
262 "Fichier modifé depuis la dernière écriture complète ; écrire ou utiliser ! pour outrepasser "
263 "Fichier modifé depuis la dernière écriture complète ; écrire ou utiliser :edit! pour outrepasser"
264 "Fichier modifé depuis la dernière écriture complète ; écrire ou utiliser ! pour outrepasser"
265 "Fichier temporaire ; quitter annulera les modifications"
266 "Fichier en lecture seule ; les modifications ne sont pas écrites automatiquement"
267 "Journal redémarré"
268 "confirmer ? [ynq]"
269 "Appuyez sur n'importe quelle touche pour continuer : "
270 "Appuyez sur n'importe quelle touche pour continuer [: pour entrer plus de commandes ex] : "
271 "Appuyez sur n'importe quelle touche pour continuer [q pour Quitter]: "
272 "Cette forme de %s nécessite l'interface de terminal ex"
273 "Entrée de mode entrée ex."
274 "La commande a échoué, aucun fichier n'a encore été lu."
275 "cont?"
276 "Evénement imprévu de caractère"
277 "Evénement imprévu de fin-de-fichier"
278 "Pas de correspondances pour cette requête"
279 "Evénement imprévu d'interruption"
280 "Evénement quitter imprévu"
281 "Evénement imprévu de rafraîchissement"
282 "La dernière marque de ce groupe a déjà été atteinte"
283 "La commande %s nécessite l'interface de terminal ex"
284 "Cette forme de %s n'est pas reconnue quand l'option d'édition protégée est activée"
285 "Evénement imprévu de chaîne"
286 "Evénement imprévu de délai imparti"
287 "Evénement d'écriture imprévu"
289 "Les expansions du shell ne sont pas reconnues quand l'option d'édition protégée est activée"
290 "La commande %s n'est pas reconnue quand l'option d'édition protégée est activée"
291 "Définition : l'option %s ne peut pas être désactivée"
292 "Affichage trop petit."
293 "ajouté"
294 "changé"
295 "supprimé"
296 "joint"
297 "déplacé"
298 "décalé"
299 "coupé"
300 "ligne"
301 "lignes"
302 "Vi n'a pas été chargé avec un interprétateur Tcl"
303 "Ficher modifié depuis le dernier enregistrement."
304 "L'expansion du shell a échoué"
304 "L'expansion du shell a échoué"
305 "Pas d'option d'édition %s spécifiée"
306 "Vi n'a pas été chargé avec un interprétateur Perl"
307 "Pas de commande ex à exécuter"
308 "Entrez <CR> pour exécuter une commande, :q pour quitter"
309 "Utiliser "cscope help" pour obtenir de l'aide"
310 "Aucune connexion cscope n'est lancée"
311 "%s : type de recherche inconnu : utiliser un des %s"
312 "%d : Il n'existe pas de telle session cscope"
313 "Définition : l'option %s ne peut jamais être activée"
314 "Définition : l'option %s ne peut jamais être définie sur 0"
315 "%s: joints : %lu lignes, %lu caractères"
316 "événement imprévu de redimensionnement"
317 "%d fichiers à éditer"

306
dist/nvi/catalog/german.base vendored Normal file
View file

@ -0,0 +1,306 @@
002 "Zeilenlängen-Überlauf"
003 "kann Zeile %lu nicht löschen"
004 "kann an Zeile %lu nicht anfügen"
005 "kann in Zeile %lu nicht einfügen"
006 "kann Zeile %lu nicht speichern"
007 "kann letzte Zeile nicht lesen"
008 "Fehler: kann Zeile %lu nicht wiederherstellen"
009 "Protokolldatei"
010 "Keine Protokollierung aktiv, Rückgängigmachen nicht möglich"
011 "Keine Änderungen rückgängig zu machen"
012 "Keine Protokollierung aktiv, Rückgängigmachen nicht möglich"
013 "Keine Protokollierung aktiv, Wiederholung von Änderungen nicht möglich"
014 "Keine Änderungen zu wiederholen"
015 "%s/%d: Protokollschreibfehler"
016 "Vi's Standardein- und -ausgabe muß ein Terminal sein"
017 "Marke %s: nicht gesetzt"
018 "Marke %s: die Zeile wurde gelöscht"
019 "Marke %s: Cursorposition existiert nicht mehr"
020 "Fehler: "
021 "neue Datei"
022 "Name geändert"
023 "geändert"
024 "nicht geändert"
025 "NICHT GELOCKT"
026 "nur zum Lesen"
027 "Zeile %lu von %lu [%ld%%]"
028 "leere Datei"
029 "Zeile %lu"
030 "Die Datei %s ist kein Meldungskatalog"
031 "Setzen der Voreinstellung für %s Option nicht möglich"
032 "Benutzung: %s"
033 "set: keine %s Option: 'set all' zeigt alle Optionen mit Werten an"
034 "set: der [no]%s Option kann kein Wert zugewiesen werden"
035 "set: %s ist keine Boolsche Option"
036 "set: %s Option: %s"
037 "set: %s Option: %s: Werte-Überlauf"
038 "set: %s Option: %s ist eine ungültige Zahl"
039 "set: %s ist keine Boolsche Option"
040 "Bildschirm hat zu wenig Spalten, weniger als %d"
041 "Bildschirm hat zu viele Spalten, mehr als %d"
042 "Bildschirm hat zu wenig Zeilen, weniger als %d"
043 "Bildschirm hat zu viele Zeilen, mehr als %d"
044 "Die lisp-Option ist nicht implementiert"
045 "Meldungen nicht abgeschaltet: %s"
046 "Meldungen nicht eingeschaltet: %s"
047 "set: Die %s Option muss Gruppen zu zwei Zeichen enthalten"
053 "Der Standardpuffer ist leer"
054 "Puffer %s ist leer"
055 "Dateien mit newlines im Namen sind nicht wiederherstellbar"
056 "Änderungen nicht wiederherstellbar, falls die Editorsitzung schiefgeht"
057 "kopiere Datei für Wiederherstellung ..."
058 "Rettungsmechanismus funktioniert nicht: %s"
059 "Änderungen nicht wiederherstellbar, falls die Editorsitzung schiefgeht"
060 "Sicherung der Datei gescheitert: %s"
061 "kopiere Datei für Wiederherstellung ..."
062 "Informationen über den Benutzer mit id %u nicht gefunden"
063 "Wiederherstellungsdatei kann nicht gelockt werden"
064 "Puffer der Wiederherstellungsdatei übergelaufen"
065 "Wiederherstellungsdatei"
066 "%s: Wiederherstellungsdatei hat falsches Format"
067 "%s: Wiederherstellungsdatei hat falsches Format"
068 "Keine von Ihnen lesbaren Dateien mit Namen %s zum Wiederherstellen"
069 "Es gibt ältere Versionen dieser Datei von Ihnen zum Wiederherstellen"
070 "Sie haben noch andere Dateien zum Wiederherstellen"
071 "schicke keine email: %s"
072 "Datei leer; nichts zu suchen"
073 "Dateiende erreicht, ohne das Suchmuster zu finden"
074 "Kein altes Suchmuster"
075 "Suchmuster nicht gefunden"
076 "Dateianfang erreicht, ohne das Suchmuster zu finden"
077 "Suche beginnt von vorn"
078 "suche ..."
079 "Keine nichtdruckbaren Zeichen gefunden"
080 "Unbekannter Kommandoname"
082 "%s: Kommando im ex-Modus nicht verfügbar"
083 "Anzahl darf nicht Null sein"
084 "%s: falsche Zeilenangabe"
085 "Interner Syntaxtabellenfehler (%s: %s)"
086 "Benutzung: %s"
087 "%s: temporärer Puffer nicht freigegeben"
088 "Flagoffset vor Zeile 1"
089 "Flagoffset hinter dem Dateiende"
090 "@ mit Bereich lief, als Datei/Anzeige geändert wurde"
091 "globales oder v-Kommando lief, als Datei/Anzeige geändert wurde"
092 "Ex-Kommando mißlungen: restliche Kommandoeingabe ignoriert"
093 "Ex-Kommando mißlungen: umdefinierte Tasten ungültig"
094 "Die zweite Adresse ist kleiner als die erste"
095 "Kein Markenname angegeben"
096 "\\ ohne folgenden / oder ?"
097 "Referenz auf eine negative Zeilennummer"
098 "Das Kommando %s ist unbekannt"
099 "Adreßwert zu groß"
100 "Adreßwert zu klein"
101 "Ungültige Adreßkombination"
102 "Ungültige Adresse: nur %lu Zeilen in der Datei"
103 "Ungültige Adresse: die Datei ist leer"
104 "Das Kommando %s erlaubt keine Adresse 0"
105 "Keine Abkürzungen zum Anzeigen"
106 "Abkürzungen müssen mit einem "Wort"-Zeichen enden"
107 "Abkürzungen dürfen keine Tabulator- oder Leerzeichen enthalten"
108 "In Abkürzungen dürfen außer am Ende Wort- und Nicht-Wort-Zeichen nicht gemischt werden"
109 ""%s" ist keine Abkürzung"
110 "Vi Kommando mißlungen: umdefinierte Tasten ungültig"
111 "Keine weiteren Dateien zu editieren"
112 "Keine vorhergehenden Dateien zu editieren"
113 "Keine vorhergehenden Dateien für rewind"
114 "Keine Dateiliste zum Anzeigen"
115 "Kein vorhergehendes Kommando, um "!" zu ersetzen"
116 "Kein Dateiname für %%"
117 "Kein Dateiname für #"
118 "Fehler: execl: %s"
119 "E/A-Fehler: %s"
120 "Datei wurde seit dem letzten vollständigen Schreiben geändert; schreibe oder verwende ! zum ignorieren"
121 "Kann Homedirectory nicht bestimmen"
122 "Neues aktuelles Directory: %s"
123 "Keine Puffer anzuzeigen"
124 "Das Kommando %s kann nicht als Teil eines global oder v Kommandos verwendet werden"
125 "%s/%s: nicht gelesen: gehört weder Ihnen noch root"
126 "%s/%s: nicht gelesen: gehört nicht Ihnen"
127 "%s/%s: nicht gelesen: anderer Benutzer als Eigentümer hat Schreibrecht"
128 "%s: nicht gelesen: gehört weder Ihnen noch root"
129 "%s: nicht gelesen: gehört nicht Ihnen"
130 "%s: nicht gelesen: anderer Benutzer als Eigentümer hat Schreibrecht"
131 "Keine folgenden Zeilen zum Verbinden"
132 "Kein input-Map Eintrag"
133 "Kein command-Map Eintrag"
134 "Das %s Zeichen kann nicht umgemappt werden"
135 ""%s" ist momentan nicht gemappt"
136 "Markennamen müssen einzelne Buchstaben sein"
137 "%s existiert, nicht geschrieben; verwende ! zum Überschreiben"
138 "Neue .exrc Datei: %s. "
139 "Zielzeile ist innerhalb des Verschiebebereichs"
140 "Das open Kommando verlangt, daß die open Option gesetzt ist"
141 "Das open Kommando ist nocht nicht implementiert"
142 "Rettung dieser Datei nicht möglich"
143 "Datei gerettet"
144 "%s wurde in zu viele Dateinamen expandiert"
145 "Nur reguläre Dateien und named pipes können gelesen werden"
146 "%s: Locken zum Lesen war nicht möglich"
147 "lese ..."
148 "%s: %lu Zeilen, %lu Zeichen"
149 "Keine Hintergrundanzeigen vorhanden"
150 "Das script Kommando ist nur im vi Modus verfügbar"
151 "Kein Kommando auszuführen"
152 "shiftwidth Option auf 0 gesetzt"
153 "Anzahl-Überlauf"
154 "Anzahl-Unterlauf"
155 "Regulärer Ausdruck angegeben; r Flag bedeutungslos"
156 "Die #, l und p Flags können im vi Modus nicht mit dem c Flag kombiniert werden"
157 "Keine Übereinstimmung gefunden"
158 "Kein vorhergehender 'tag' angegeben"
159 "Weniger als %s Einträge auf dem 'tag'-Stack; verwende :display t[ags]"
160 "Keine Datei namens %s auf dem 'tag'-Stack; verwende :display t[ags]"
161 "Drücke Enter um fortzufahren: "
162 "%s: 'tag' nicht gefunden"
163 "%s: kaputter 'tag' in %s"
164 "%s: die Zeilennummer des 'tag' ist hinter dem Dateiende"
165 "Der 'tag' Stack ist leer"
166 "%s: Suchmuster nicht gefunden"
167 "%d weitere Dateien zu editieren"
168 "Puffer %s ist leer"
169 "Bestätige Änderung [n]"
170 "Unterbrochen."
171 "Kein vorhergehender Puffer zum Ausführen"
172 "Kein vorhergehender regulärer Ausdruck"
173 "Das Kommando %s verlangt, daß bereits eine Datei eingelesen wurde"
174 "Benutzung: %s"
175 "Das visual Kommando verlangt daß die open Option gesetzt ist"
177 "Leere Datei"
178 "Keine vorhergehende F, f, T oder t Suche"
179 "%s nicht gefunden"
180 "Keine vorhergehende Datei zu editieren"
181 "Cursor nicht auf einer Zahl"
182 "Sich ergebende Zahl ist zu groß"
183 "Sich ergebende Zahl ist zu klein"
184 "Kein korrespondierendes Zeichen in dieser Zeile"
185 "Korrespondierendes Zeichen nicht gefunden"
186 "Keine Zeichen zu ersetzen"
187 "Keine andere Anzeige zum Hinschalten"
188 "Zeichen nach Suchmuster, Zeilenoffset und/oder z Kommando"
189 "Kein altes Suchmuster"
190 "Suche zur ursprünglichen Position zurückgekehrt"
191 "Abkürzung überschreitet Expansionsgrenze: Zeichen weggelassen"
192 "Nicht erlaubtes Zeichen; maskiere zum Eingeben"
193 "Bereits am Anfang der Eingabe"
194 "Keine weiteren Zeichen zu löschen"
195 "Bewegung hinter das Dateiende"
196 "Bewegung hinter das Zeilenende"
197 "Keine Cursorbewegung gemacht"
198 "Bereits am Dateianfang"
199 "Bewegung vor den Dateianfang"
200 "Bereits in der ersten Spalte"
201 "Puffer sollen vor dem Kommando angegeben werden"
202 "Bereits am Dateiende"
203 "Bereits am Zeilenende"
204 "%s ist kein vi Kommando"
205 "Benutzung: %s"
206 "Keine Zeichen zu löschen"
207 "Das Q Kommando benötigt das ex Terminal Interface"
208 "Kein Kommando zu wiederholen"
209 "Die Datei ist leer"
210 "%s kann nicht als Bewegungskommando verwendet werden"
211 "Bereits im Kommando-Modus"
212 " Cursor nicht auf einem Wort"
214 "Wert der Window Option ist zu groß, max ist %u"
215 "Anhängen"
216 "Ändern"
217 "Kommando"
218 "Einfügen"
219 "Ersetzen"
220 "Bewegung hinter das Anzeigenende"
221 "Bewegung vor den Anzeigenanfang"
222 "Anzeige muß für Bildschirmteilung größer als %d sein"
223 "Keine Hintergrundanzeigen vorhanden"
224 "Es gibt keine Hintergrundanzeige, die eine Datei namens %s editiert"
225 "Die einzige dargestellte Anzeige kann nicht in den Hintergrund gebracht werden"
226 "Die Anzeige kann nur auf %d Zeilen verkleinert werden"
227 "Die Anzeige kann nicht verkleinert werden"
228 "Die Anzeige kann nicht vergrößert werden"
230 "Diese Anzeige kann nicht gestopt werden"
231 "Unterbrochen: umdefinierte Tasten ungültig"
232 "vi: temporärer Puffer nicht freigegeben"
233 "Dieses Terminal hat keine %s Taste"
234 "es kann nur ein Puffer angegeben werden"
235 "Zahl größer als %lu"
236 "Unterbrochen"
237 "Nicht möglich, temporäre Datei anzulegen"
238 "Warnung: %s ist keine reguläre Datei"
239 "%s ist bereits gelockt, Editorsitzung schreibgeschützt"
240 "%s: löschen"
241 "%s: schließen"
242 "%s: löschen"
243 "%s: löschen"
244 "Datei nicht schreibbar, nicht geschrieben; verwende ! zum Überschreiben"
245 "Datei nicht schreibbar, nicht geschrieben"
246 "%s existiert, nicht geschrieben; verwende ! zum Überschreiben"
247 "%s existiert, nicht geschrieben"
248 "Teil der Datei, nicht geschrieben; verwende ! zum Überschreiben"
249 "Teil der Datei, nicht geschrieben"
250 "%s: Datei wurde später als diese Kopie verändert; verwende ! zum Überschreiben"
251 "%s: Datei wurde später als diese Kopie verändert"
252 "%s: Locken zum Schreiben war nicht möglich"
253 "schreibe ..."
254 "%s: WARNUNG: DATEI ABGESCHNITTEN"
255 "Bereits am ersten 'tag' dieser Gruppe"
256 "%s: neue Datei: %lu Zeilen, %lu Zeichen"
257 "%s: %lu Zeilen, %lu Zeichen"
258 "%s wurde in zu viele Dateinamen expandiert"
259 "%s: keine reguläre Datei"
260 "%s: gehört nicht Ihnen"
261 "%s: anderer Benutzer als Eigentümer hat Zugriff"
262 "Datei wurde seit dem letzten vollständigen Schreiben geändert; schreibe oder verwende ! zum ignorieren"
263 "Datei wurde seit dem letzten vollständigen Schreiben geändert; schreibe oder verwende :edit! zum ignorieren"
264 "Datei wurde seit dem letzten vollständigen Schreiben geändert; schreibe oder verwende ! zum ignorieren"
265 "Datei ist temporär; beim Verlassen gehen die Änderungen verloren"
266 "Datei ist schreibgeschützt, Änderungen werden nicht automatisch geschrieben"
267 "Portokollierung neu begonnen"
268 "bestätigen [ynq]"
269 "Drücke beliebige Taste um fortzufahren"
270 "Drücke beliebige Taste um fortzufahren [: um weitere Kommandos einzugeben]: "
271 "Drücke beliebige Taste um fortzufahren [q zum Verlassen]: "
272 "Diese Form von %s benötigt das ex Terminal-Interface"
273 "Gehe in ex Eingabe-Modus.\n"
274 "Kommando schiefgelaufen, noch keine Datei eingelesen"
275 " weiter?"
276 "unerwartetes Zeichen - Ereignis"
277 "unerwartetes Dateiende - Ereignis"
278 "Keine Position zum Anspringen gefunden"
279 "unerwartetes Unterbrechungs - Ereignis"
280 "unerwartetes Verlassen - Ereignis"
281 "unerwartetes Wiederherstellungs - Ereignis"
282 "Bereits am letzten 'tag' dieser Gruppe"
283 "Das %s Kommando benötigt das ex Terminal-Interface"
284 "Diese Form von %s wird nicht unterstützt wenn die 'secure edit' - Option gesetzt ist"
285 "unerwartetes Zeichenketten - Ereignis"
286 "unerwartetes timeout - Ereignis"
287 "unerwartetes Schreibe - Ereignis"
289 "Shell Expandierungen nicht unterstützt wenn die 'secure edit' - Option gesetzt ist"
290 "Das %s Kommando wird nicht unterstützt wenn die 'secure edit' - Option gesetzt ist"
291 "set: %s kann nicht ausgeschaltet werden"
292 "Anzeige zu klein."
293 "angefügt"
294 "geändert"
295 "gelöscht"
296 "verbunden"
297 "verschoben"
298 "geschoben"
299 "in Puffer geschrieben"
300 "Zeile"
301 "Zeilen"
302 "Vi wurde nicht mit dem Tcl Interpreter gelinkt"
303 "Datei wurde seit dem letzten Schreiben verändert."
304 "Shell Expansion hat nicht geklappt"
305 "Es ist keine %s Editieroption angegeben"
306 "Vi wurde nicht mit einem Perl Interpreter geladen"
307 "Kein ex Kommando auszuführen"
308 "Drücke <CR> um ein Kommando auszuführen, :q zum verlassen"
309 "Verwende "cscope help" für Hilestellung"
310 "Keine cscope Verbindung aktiv"
311 "%s: unbekannter Suchtyp: verwende einen aus %s"
312 "%d: keine solche cscope Verbindung"
313 "set: die %s Option kann nicht eingeschaltet werden"
314 "set: die %s Option kann nicht auf 0 gesetzt werden"
315 "%s: angefügt: %lu Zeilen, %lu Zeichen"
316 "unerwartetes Größenveränderungs - Ereignis"
317 "%d Dateien zu edieren"

2
dist/nvi/catalog/german.owner vendored Normal file
View file

@ -0,0 +1,2 @@
Bernhard Daeubler <daeb@physik.uni-ulm.de>
Joerg Wunsch <joerg_wunsch@uriah.heep.sax.de>

214
dist/nvi/catalog/ru_RU.KOI8-R.base vendored Normal file
View file

@ -0,0 +1,214 @@
002 "Переполнение значения длины строки"
003 "невозможно удалить строку %lu"
004 "невозможно добавить к строке %lu"
005 "невозможно вставить в строку %lu"
006 "невозможно сохранить строку %lu"
007 "невозможно достать последнюю строку"
009 "Файл записей"
010 "Записи не велись, невозможно отменить последнюю команду"
011 "Нет изменений для отмены"
012 "Записи не велись, невозможно отменить последнюю команду"
013 "Записи не велись, невозможно просмотреть вперед"
014 "Нет изменений для переделки"
015 "%s/%d: ошибка при записи протокола"
016 "Стандартный ввод/вывод для VI должен быть терминал"
017 "Отметка %s: не установлена"
018 "Отметка %s: строка была удалена"
019 "Отметка %s: позиции курсора больше не существует"
020 "Ошибка: "
030 "Файл %s не является каталогом сообщений"
031 "Невозможно установить опцию %s по умолчанию"
032 "Использование: %s"
033 "Опции %s нет: 'set all' показывает все возможные опции"
034 "set: [no]%s не принимает такого значения"
035 "set: %s опция не является логической"
038 "set: неправильное значение %s"
039 "set: %s опция не является логической"
040 "Количество колонок экрана слишком мало, меньше чем %d"
041 "Количество колонок экрана слишком велико, больше чем %d"
042 "Количество строк экрана слишком мало, меньше чем %d"
043 "Количество строк экрана слишком велико, больше чем %d"
044 "Опция lisp отсутствует"
045 "Сообщения не выключены: %s"
046 "Сообщения не включены: %s"
048 "Опция paragraph должна состоять из групп с двумя символами"
049 "Опция section должна состоять из групп с двумя символами"
053 "Стартовый буфер пуст"
054 "Буфер %s пуст"
055 "Файлы с символами перевода строки в имени не могут быть восстановлены"
056 "Изменения не сохранены при крахе сессии"
058 "Сохранение не удалось: %s"
059 "Изменения не сохраняются при обрыве сессии"
060 "Сохранение копии файла не удалось: %s"
062 "Информации на пользователя %u не найдено"
063 "Невозможно защитить спасенный файл"
064 "Буфер восстановленного файла переполнен"
065 "Восстановленный файл"
066 "%s: не до конца восстановленный файл"
067 "%s: не до конца восстановленный файл"
068 "Файлов с именем %s, которые Вы можете читать, не существует"
069 "Есть старые версии файла, которые можно восстановить"
070 "Существуют другие файлы, которые можно восстановить"
071 "е-mail не послан: %s"
072 "Файл пуст - искать нечего"
073 "Достигнут конец файла без нахождения образца поиска"
074 "Не задан образец поиска"
075 "Образец поиска не найден"
076 "Доступно начало файла без нахождения образца поиска"
077 "Поиск зациклен"
079 "Непечатных символов не найдено"
080 "Неизвестная команда"
082 "%s: команда не доступна в режиме ex"
083 "Счетчик не может быть нулем"
084 "%s: неправильное указание строки"
085 "Внутренняя ошибка в синтаксисе (%s: %s)"
086 "Использование: %s"
087 "%s: временный буфер не использован"
088 "Метка поставлена перед строкой 1"
089 "Метка поставлена после конца файла"
092 "Команда ex не удалась: последующие команды забыты"
094 "Второй адрес меньше чем первый"
095 "Не указано название отметки"
096 "\\ не завершается / или ?"
097 "Ссылка к строке с номером меньше 0"
098 "Команда %s неизвестна"
099 "Переполнение значения адреса"
100 "Недобор значения адреса"
101 "Недопустимая комбинация в адресе"
102 "Неправильный адрес: всего %lu строк в файле"
103 "Неправильный адрес: файл пуст"
104 "Комманда %s не может использовать адрес 0"
105 "Аббревиатуры отсутствуют"
106 "Аббревиатуры должны заканчиваться символом "word""
107 "Аббревиатуры не могут содержать символоы табляции или пробелы"
108 "Аббревиатуры не могут сочетаться с символами слов/не-слов, за исключением конца строки"
109 ""%s" не является аббревиатурой"
111 "Файлов для редактирования больше нет"
112 "Отсутствие предыдущего файла для редактирования"
113 "Отсутствие предыдущего файла для просмотра назад"
114 "Нет файлов"
115 "Отсутствие предыдущей команды для замены "!""
116 "Отсутствие замены для %%"
117 "Отсутствие замены для #"
118 "Ошибка: execl: %s"
119 "Ошибка ввода/вывода: %s"
120 "Файл изменен с момента последней полной записи: используйте ! для обхода"
121 "Невозможно найти домашний каталог"
122 "Новый каталог: %s"
123 "Нет вырезаных буферов"
124 "Команда %s не может быть использована внутри глобальной или v команды"
125 "%s/%s: не открыт: не принадлежит Вам или root-у"
126 "%s/%s: не открыт: не принадлежит Вам"
127 "%s/%s: не открыт: возможность записи у пользователя, не являющегося владельцем"
128 "%s: не считан: не принадлежит Вам или root-у"
129 "%s: не считан: не принадлежит Вам"
130 "%s: не считан: возможность записи у пользователя, не являющегося владельцем"
131 "Последующие строки отсутствуют"
132 "Отсутствие параметров ввода"
133 "Отсутствие параметров команды"
134 "Символ %s не может быть переназначен"
135 ""%s" на данный момент не назначен"
136 "Имя метки должно быть одним символом"
137 "%s существует, не записан; используйте ! для обхода"
138 "Новый файл exrc: %s"
139 "Строка переноса находится внутри параметров переноса"
140 "Команда open подразумевает установку опции open"
141 "Команда open не реализована"
142 "Защита файла невозможна"
143 "Файл защищен"
144 "%s расширился в слишком большое количество имен файлов"
146 "%s: защита на чтение была недоступна"
148 "%s: %lu строк, %lu символов"
149 "Нет теневых окон"
150 "Команда script используется только в режиме vi"
151 "Нет команды для исполнения"
152 "Опция shiftwidth установлена на 0"
153 "Переполнение счетчика"
154 "Цикл выполнен не до конца"
155 "Указано регулярное выражение: флаг r не нужен"
156 "Флаги #, l и p не могут быть объединены с флагом c в режиме vi"
157 "Совпадений нет"
158 "Метка отсутствует"
159 "В стеке меток записей меньше, чем %s, используйте :display t[ags]"
160 "Файла с именем %s в стеке меток нет; используйте :display t[ags]"
162 "%s: метка не найдена"
163 "%s: плохая метка в %s"
165 "Стек меток пуст"
166 "%s: образец поиска не найден"
168 "Буфер %s пуст"
170 "Прервано"
171 "Отсутствие буфера для использования"
172 "Нет предидущего регулярного выражения"
173 "Команда %s подразумевает наличие прочтенного файла"
174 "Использование: %s"
175 "Команда visual подразумевает обязательную установку опции open"
177 "Пустой файл"
178 "Нет предыдущего поиска F, f, T, или t"
179 "%s не найдено"
180 "Нет предыдущего файла для редактирования"
181 "Курсор стоит не на цифре"
182 "Полученное число слишком велико"
183 "Полученное число слишком мало"
184 "Подходящего символа нет на этой строке"
185 "Подходящий символ не найден"
186 "Нет символов для удаления"
187 "Другого экрана не существует"
188 "Символы после строки для поиска, смещения строки и/или команды z"
189 "Прошлый образец поиска отсутствует"
190 "Поиск завершился на начальной позиции"
192 "Символ неправилен; квотируйте для ввода"
193 "Уже на начале вставки"
194 "Нет символов для удаления"
195 "Передвижение за конец файла"
196 "Передвижение за конец строки"
197 "Движение строки не сделано"
198 "Уже на начале файла"
199 "Движение курсора за начало файла"
200 "Уже в первой колонке"
201 "Буферы должны быть указаны до выполнения команды"
202 "Уже на конце файла"
203 "Уже на конце строки"
204 "%s не является командой VI"
205 "Использование: %s"
206 "Нет символов для удаления"
208 "Нет команды для повтора"
210 "Команда %s не может быть использована как команда перемещения"
211 "Уже в командном режиме"
214 "Значение опции windows слишком велико, максимальное значение = %u"
220 "Движение курсора за конец экрана"
221 "Движение курсора за начало экрана"
223 "Теневых окон нет"
224 "Не существует теневого окна с редактированием файла %s"
225 "Вы не можете сделать единственное окно теневым"
226 "Экран может быть сжат"
227 "Экран не может быть сжат только до %d строк"
228 "Экран не может быть расширен"
233 "Данный тип терминала не имеет клавиши %s"
237 "Невозможно создать временный файл"
238 "Внимание: %s специальный файл"
239 "%s уже заблокирован, доступен только на чтение"
240 "%s: удален"
241 "%s: закрыт"
242 "%s: удален"
243 "%s: удален"
244 "Файл только для чтения, не записан: Используйте ! для обхода"
245 "Файл только для чтения, не записан"
246 "%s существует, не записан; используйте ! для обхода"
247 "%s существует, не записан"
248 "Используйте ! для частичной записи файла"
249 "Часть файла, файл не записан"
250 "%s: Файл изменялся позднее, чем данная копия: используйте ! для обхода"
251 "%s: Файл изменялся позднее, чем данная копия"
252 "%s: защита на запись была недоступна"
254 "%s: ВНИМАНИЕ: ФАЙЛ УСЕЧЕН"
256 "%s: новый файл: %lu строк, %lu символов"
257 "%s: %lu строк, %lu символов"
258 "%s расширился в слишком большое количество имен файлов"
259 "%s: специальный файл"
260 "%s: не принадлежит Вам"
261 "%s: доступен не только Вам"
262 "Файл изменен со времени последней записи: сохраните или используйте ! для обхода"
263 "Файл изменен со времени последней записи: сохраните или используйте :edit для обхода"
264 "Файл изменен со времени последней записи: сохраните или используйте ! для обхода"
265 "Файл временный: выход сотрет любые изменения"
267 "Записи начаты заново"

2
dist/nvi/catalog/ru_RU.KOI8-R.owner vendored Normal file
View file

@ -0,0 +1,2 @@
Andrey A. Chernov <ache@nagual.ru>
Dima Ruban <dima@rdy.com>

308
dist/nvi/catalog/spanish.base vendored Normal file
View file

@ -0,0 +1,308 @@
002 "Desbordamiento de longitud de l¡nea"
003 "no se puede borrar la l¡nea %lu"
004 "no se puede a¤adir la l¡nea %lu"
005 "no se puede insertar en la l¡nea %lu"
006 "no se puede guardar la l¡nea %lu"
007 "no se puede obtener la £ltima l¡nea"
008 "Error: no se puede recuperar la l¡nea %lu"
009 "Archivo de log"
010 "No se realiza log, no se puede deshacer"
011 "No hay cambios para deshacer"
012 "No se realiza log, no se puede deshacer"
013 "No se realiza log, no se puede remontar hacia adelante"
014 "No hay cambios para rehacer"
015 "%s/%d: error de log"
016 "La entrada y salida est ndar de Vi debe ser una terminal"
017 "Marcar %s: no determinado"
018 "Marcar %s: se borr¢ la l¡nea"
019 "Marcar %s: la posici¢n del cursor ya no existe"
020 "Error: "
021 "nuevo archivo"
022 "nombre cambiado"
023 "modificado"
024 "no modificado"
025 "DESTRABADO"
026 "lectura solamente"
027 "l¡nea %lu de %lu [%ld%%]"
028 "archivo vac¡o"
029 "l¡nea %lu"
030 "El archivo %s no es un cat logo de mensajes"
031 "No se puede determinar la opci¢n por omisi¢n %s"
032 "Uso: %s"
033 "determinar: no hay opci¢n %s: 'determinar todo' establece todos los valores de opci¢n"
034 "determinar: [no] hay opci¢n %s no tiene valor"
035 "determinar: opci¢n %s no es booleano"
036 "determinar: opci¢n %s: %s"
037 "determinar: opci¢n %s: %s: desbordamiento de valores"
038 "determinar: opci¢n %s: %s es un n£mero ilegal"
039 "determinar: opci¢n %s no es booleano"
040 "Las columnas en pantalla son demasiado peque¤as, menos de %d"
041 "Las columnas en pantalla son demasiado grandes, m s de %d"
042 "Las l¡neas en pantalla son demasiado peque¤as, menos de %d"
043 "Las l¡neas en pantalla son demasiado grandes, m s de %d"
044 "La opci¢n lisp no est  implementada"
045 "mensajes no desconectados: %s"
046 "mensajes no conectados: %s"
047 "determinar: La opci¢n de %s debe estar en dos grupos de caracteres"
053 "El buffer por omisi¢n est  vac¡o"
054 "El buffer %s est  vac¡o"
055 "Los archivos con nuevas l¡neas en el nombre son irrecuperables"
056 "Las modificaciones no pueden recuperarse si la sesi¢n falla"
057 "Copiando archivo para recuperaci¢n..."
058 "Preservaci¢n fracasada: %s"
059 "Las modificaciones no pueden recuperarse si la sesi¢n falla"
060 "Archivo de respaldo fracasado: %s"
061 "Copiando archivo para recuperaci¢n..."
062 "Informaci¢n sobre identificaci¢n del usuario %u no encontrada"
063 "No se puede trabar archivo de recuperaci¢n"
064 "Desbordamiento de buffer de archivo de recuperaci¢n"
065 "Archivo de recuperaci¢n"
066 "%s: archivo de recuperaci¢n defectuoso"
067 "%s: archivo de recuperaci¢n defectuoso"
068 "No hay archivos denominados %s, que usted pueda leer, para recuperar"
069 "Existen versiones m s antiguas de este archivo que usted puede recuperar"
070 "Existen otros archivos que usted puede recuperar"
071 "no env¡a email: %s"
072 "Archivo vac¡o; no hay nada para buscar"
073 "Se alcanz¢ el final del archivo sin encontrar el patr¢n"
074 "No hay patr¢n anterior de b£squeda"
075 "No se encontr¢ el patr¢n"
076 " Se alcanz¢ el principio del archivo sin encontrar el patr¢n"
077 "B£squeda reiniciada"
078 "Buscando..."
079 "No se encontr¢ ning£n car cter no imprimible"
080 "Nombre de comando desconocido"
082 "%s: comando no disponible en modalidad ex"
083 "La cuenta no puede ser cero"
084 "%s: mala especificaci¢n de l¡nea"
085 "Error interno de tabla de sintaxis (%s: %s)"
086 "Uso: %s"
087 "%s: buffer temporario no liberado"
088 "Desplazamiento de marcador a antes de la l¡nea 1"
089 "Desplazamiento de marcador m s all  del final del archivo"
090 "@ con rango que corre cuando se cambia el archivo/la pantalla"
091 "Comando global/v que corre cuando se cambia el archivo/la pantalla"
092 "Comando Ex fracasado: comandos pendientes descartados"
093 "Comando Ex fracasado: teclas mapeadas descartadas"
094 "La segunda direcci¢n es m s peque¤a que la primera"
095 "No se suministra nombre de marca"
096 "\\ no es seguido por / o ?"
097 "Referencia a un n£mero de l¡nea menor que 0"
098 "El comando %s es desconocido"
099 "Desbordamiento de valor de direcci¢n"
100 "Subdesbordamiento de valor de direcci¢n"
101 "Combinaci¢n de direcci¢n ilegal"
102 "Direcci¢n ilegal: s¢lo %lu l¡neas en el archivo"
103 "Direcci¢n ilegal: el archivo est  vac¡o"
104 "El comando %s no permite una direcci¢n de 0"
105 "No hay abreviaturas para visualizar"
106 "Las abreviaturas deben terminar con un car cter de \"palabra\" "
107 "Las abreviaturas no pueden contener tabs o espacios"
108 "Las abreviaturas no pueden mezclar caracteres palabra/no-palabra, salvo al final"
109 "\"%s\" no es una abreviatura"
110 "Comando Vi fracasado: teclas mapeadas descartadas"
111 "No hay m s archivos para editar"
112 "No hay archivos anteriores para editar"
113 "No hay archivos anteriores para rebobinar"
114 "No hay lista de archivos para visualizar"
115 "No hay un comando anterior para reemplazar a \"!\""
116 "No hay nombre de archivo para sustituir por %%"
117 "No hay nombre de archivo para sustituir por #"
118 "Error: execl: %s"
119 "Error de E/S: %s"
120 "Archivo modificado desde la £ltima escritura completa; escribir o usar ! para alterar"
121 "No se puede encontrar la ubicaci¢n del directorio inicial"
122 "Nuevo directorio actual: %s"
123 "No hay buffers sueltos para visualizar"
124 "El comando %s no puede usarse como parte de un comando global o v"
125 "%s/%s: sin fuente: no le pertenece a usted o a ra¡z"
126 "%s/%s: sin fuente: no le pertenece a usted"
127 "%s/%s: sin fuente: puede ser escrito por un usuario que no sea el propietario"
128 "%s: sin fuente: no le pertenece a usted o a ra¡z"
129 "%s: sin fuente: no le pertenece a usted"
130 "%s: sin fuente: puede ser escrito por un usuario que no sea el propietario"
131 "No hay l¡neas siguientes para unir"
132 "No hay anotaciones de mapa de entrada"
133 "No hay anotaciones de mapa de comando"
134 "El car cter %s no puede remapearse"
135 "\"%s\" no est  mapeado actualmente"
136 "Marca de nombres debe ser un s¢lo car cter"
137 "%s existe, no est  escrito; usar ! para alterar"
138 "Nuevo archivo exrc: %s"
139 "La l¡nea de destino se encuentra dentro del rango de movimiento"
140 "El comando abierto requiere que se determine la opci¢n abierta"
141 "El comando abierto no se ha implementado a£n"
142 "No es posible preservar este archivo"
143 "Archivo preservado"
144 "%s: expandido a demasiados nombres de archivo"
145 "S¢lo pueden leerse los archivos regulares y los conductos nombrados"
146 "%s: traba de lectura no disponible"
147 "Leyendo..."
148 "%s: %lu l¡neas, %lu caracteres"
149 "No hay pantallas de fondo para mostrar"
150 "El comando de script s¢lo est  disponible en modalidad vi"
151 "No hay comando para ejecutar"
152 "opci¢n de ancho de desplazamiento en 0"
153 "Desbordamiento de cuenta"
154 "Subdesbordamiento de cuenta"
155 "Expresi¢n regular especificada; marcador r no tiene significado"
156 "Los marcadores #, l y p no pueden combinarse con el marcador c en la modalidad vi"
157 "No se encontr¢ coincidencia"
158 "No se ingres¢ un identificador anterior"
159 "Se encontraron menos de %s anotaciones en la pila de identificadores; usar :visualizar i[dentificadores]"
160 "No hay archivo %s en la pila de identificadores al que se pueda volver; usar :visualizar i[dentificadores]"
161 "Presionar Intro para continuar: "
162 "%s: no se encontr¢ el identificador"
163 "%s: identificador corrompido en %s"
164 "%s: el n£mero de l¡nea del identificador es posterior al final del archivo"
165 "La pila de identificadores est  vac¡a"
166 "%s: patr¢n de b£squeda no encontrado"
167 "%d archivos m s para editar"
168 "El buffer %s est  vac¡o"
169 "¨Confirmar cambio? [n]"
170 "Interrumpido"
171 "No hay buffer anterior para ejecutar"
172 "No hay expresi¢n regular anterior"
173 "El comando %s requiere que se haya le¡do un archivo"
174 "Uso: %s"
175 "El comando visual requiere que se determine la opci¢n abierta"
177 "Archivo vac¡o"
178 "No hay b£squeda F, f, T o t anterior"
179 "%s no se encontr¢"
180 "No hay archivo anterior para editar"
181 "El cursor no est  en un n£mero"
182 "El n£mero resultante es demasiado grande"
183 " El n£mero resultante es demasiado peque¤o"
184 "No hay car cter coincidente en esta l¡nea"
185 "No se encontr¢ un car cter coincidente"
186 "No hay caracteres para reemplazar"
187 "No hay otra pantalla a la que se pueda pasar"
188 "Caracteres despus de cadena de b£squeda, desplazamiento de l¡nea y/o comando z"
189 "No hay patr¢n anterior de b£squeda"
190 "B£squeda vuelve a la posici¢n inicial"
191 "Se super¢ el l¡mite de expansi¢n de abreviatura: se descartaron caracteres"
192 "Car cter ilegal; mencionar para entrar"
193 "Ya se encuentra al principio de la inserci¢n"
194 "No hay m s caracteres para borrar"
195 "Movimiento m s all  del final del archivo"
196 "Movimiento m s all  del final de la l¡nea"
197 "No hay movimiento del cursor"
198 "Ya se encuentra al principio del archivo"
199 "Movimiento m s all  del principio del archivo"
200 "Ya se encuentra en la primera columna"
201 "Los buffers deben especificarse antes del comando"
202 "Ya se encuentra al final del archivo"
203 "Ya se encuentra al final de la l¡nea"
204 "%s no es un comando vi"
205 "Uso: %s"
206 "No hay caracteres para borrar"
207 "El comando Q requiere la interfase de terminal ex"
208 "No hay comando para repetir"
209 "El archivo est  vac¡o"
209 "El archivo est  vac¡o"
210 "%s no puede usarse como comando de movimiento"
211 "Ya se encuentra en modalidad de comando"
212 "El cursor no se encuentra en una palabra"
214 "El valor de opci¢n de Windows es demasiado grande, el m x. es %u"
215 "A¤adir"
216 "Cambiar"
217 "Comando"
218 "Insertar"
219 "Reemplazar"
220 "El movimiento va m s all  del final de la pantalla"
221 "El movimiento va m s all  del principio de la pantalla"
222 "La pantalla debe tener m s de %d l¡neas para dividirse"
223 "No hay pantallas de fondo"
224 "No hay pantalla de fondo editando un archivo denominado %s"
225 "No se puede poner fondo a la £nica pantalla que se visualiza"
226 "La pantalla s¢lo puede reducirse a %d hileras"
227 "La pantalla no puede reducirse"
228 "La pantalla no puede aumentarse"
230 "Esta pantalla no puede suspenderse"
231 "Interrumpido: teclas mapeadas descartadas"
232 "vi: buffer temporario no liberado"
233 "Esta terminal no tiene tecla %s"
234 "S¢lo un buffer puede especificarse"
235 "N£mero mayor que %lu"
236 "Interrumpido"
237 "No se puede crear archivo temporario"
238 "Advertencia: %s no es un archivo regular"
239 "%s ya se encuentra trabado, la sesi¢n es de lectura solamente"
240 "%s: eliminar"
241 "%s: cerrar"
242 "%s: eliminar"
243 "%s: eliminar"
244 "Archivo de lectura solamente, no escrito; usar ! para alterar"
245 " Archivo de lectura solamente, no escrito"
246 "%s existe, no escrito; usar ! para alterar"
247 "%s existe, no escrito"
248 "Archivo parcial, no escrito; usar ! para alterar"
249 "Archivo parcial, no escrito"
250 "%s: archivo modificado m s recientemente que esta copia; usar ! para alterar"
251 "%s: archivo modificado m s recientemente que esta copia"
252 "%s: la traba de escritura no estaba disponible"
253 "Escribiendo..."
254 "%s: ADVERTENCIA: ARCHIVO TRUNCADO"
255 "Ya se encuentra en el primer identificador de este grupo"
256 "%s: nuevo archivo: %lu l¡neas, %lu caracteres"
257 "%s: %lu l¡neas, %lu caracteres"
258 "%s expandido a demasiados nombres de archivos"
259 "%s: no es un archivo regular"
260 "%s: no le pertenece"
261 "%s: accesible por un usuario que no sea el propietario"
262 "Archivo modificado desde la £ltima escritura completa; escribir o usar ! para alterar"
263 "Archivo modificado desde la £ltima escritura completa; escribir o usar :editar! para alterar"
264 "Archivo modificado desde la £ltima escritura completa; escribir o usar ! para alterar"
265 "El archivo es temporario; al salir se descartar n las modificaciones"
266 "Archivo de lectura solamente, las modificaciones no se autoescriben"
267 "Se reinici¢ el log"
268 "confirmar? [snq]"
269 "Presionar cualquier tecla para continuar: "
270 "Presionar cualquier tecla para continuar [: para ingresar m s comandos ex]: "
271 "Presionar cualquier tecla para continuar [q para salir]: "
272 "Esta forma de %s requiere la interfase terminal ex"
273 "Ingresando en la modalidad de entrada ex."
274 "Comando fracasado, no hay archivo le¡do aun."
275 " cont?"
276 "Evento inesperado de car cter"
277 "Evento inesperado de final de archivo"
278 "No hay coincidencias para consulta"
279 "Evento inesperado de interrupci¢n"
280 "Evento inesperado de salida"
281 "Evento inesperado de repintura"
282 "Ya se encuentra en el £ltimo identificador de este grupo"
283 "El comando %s requiere la interfase terminal ex"
284 "Esta forma de %s no se encuentra soportada cuando se determina la opci¢n de edici¢n segura"
285 "Evento inesperado de cadena"
286 "Evento inesperado de tiempo excedido"
287 "Evento inesperado de escritura"
289 "Las expansiones de shell no se encuentran soportadas cuando se determina la opci¢n de edici¢n segura"
290 "El comando %s no se encuentra soportado cuando se determina la opci¢n de edici¢n segura"
291 "determinar: la opci¢n %s puede no estar desconectada"
292 "El monitor es demasiado peque¤o."
293 "agregado"
294 "cambiado"
295 "borrado"
296 "unido"
297 "movido"
298 "desplazado"
299 "arrancado"
300 "l¡nea"
301 "l¡neas"
302 "Vi no se carg¢ con un intrprete Tcl"
303 "Archivo modificado desde la £ltima escritura."
304 "Expansi¢n de shell fracasada"
304 "Expansi¢n de shell fracasada"
305 "No hay opci¢n de edici¢n %s especificada"
306 "Vi no se carg¢ con un intrprete Perl"
307 "No hay comando ex para ejecutar"
308 "Ingresar <CR> para ejecutar un comando, :q para salir"
309 "Usar \"cscope ayuda\" para obtener ayuda"
310 "No hay conexiones cscope corriendo"
311 "%s: tipo de b£squeda desconocido: usar uno de %s"
312 "%d: no existe esta sesi¢n cscope"
313 "determinar: la opci¢n %s no puede conectarse nunca"
314 "determinar: la opci¢n %s no puede determinarse nunca en 0"
315 "%s: a¤adido: %lu l¡neas, %lu caracteres"
316 "Evento inesperado de modificaci¢n de tama¤o"
317 "%d archivos para editar"

19
dist/nvi/catalog/spell.ok vendored Normal file
View file

@ -0,0 +1,19 @@
ARGMAX
LC
NL
XXXX
arg1
arg2
chys
english
english.base
german.base
langauge
msg
msg.c
msgcat
msgq
nvi
nvi's
pathname
sp

306
dist/nvi/catalog/swedish.base vendored Normal file
View file

@ -0,0 +1,306 @@
002 "För långa rader"
003 "kan inte ta bort rad %lu"
004 "kan inte lägga till på rad %lu"
005 "kan inte sätta in på rad %lu"
006 "kan inte lagra rad %lu"
007 "kan inte hämta sista raden"
008 "Fel: kan inte hämta rad %lu"
009 "Loggningsfil"
010 "Loggning utförs inte, ångra är inte möjligt"
011 "Inga ändringar att ångra"
012 "Loggning utförs inte, ångra är inte möjligt"
013 "Loggning utförs inte, ångra ångra är inte möjligt"
014 "Inga ändringar att återgöra"
015 "%s/%d: fel vid loggning"
016 "Vi:s standard in och ut måste gå till en terminal"
017 "Markering %s: inte satt"
018 "Markering %s: raden har tagits bort"
019 "Markering %s: markörpositionen finns inte längre"
020 "Fel: "
021 "ny fil"
022 "namnet ändrades"
023 "ändrad"
024 "oförändrad"
025 "OLÅST"
026 "inte skrivbar"
027 "rad %lu av %lu [%ld%%]"
028 "tom fil"
029 "rad %lu"
030 "Filen %s är ingen meddelandekatalog"
031 "Kan inte sätta standardvärde för %s flaggan"
032 "Användning: %s"
033 "set: %s är en okänd flagga: "set all" visar alla flaggor"
034 "set: [no]%s flaggan kan inte ges ett värde"
035 "set: %s flaggan är inte boleansk"
036 "set: %s flaggan: %s"
037 "set: %s flaggan: %s: för stort värde"
038 "set: %s flaggan: %s är ett otillåtet tal"
039 "set: %s flaggan är inte boleansk"
040 "Fönsterkolumnerna är för få, mindre än %d"
041 "Fönsterkolumnerna är för många, fler än %d"
042 "Fönsterraderna är för få, mindre än %d"
043 "Fönsterraderna är för många, fler än %d"
044 "Lisp flaggan är inte implementerad"
045 "meddelanden är inte avslagna: %s"
046 "meddelanden är inte påslagna: %s"
047 "set: %s flaggan måste ges i teckengrupper om två"
053 "Standardbufferten är tom"
054 "Buffer %s är tom"
055 "Filer med radmatning i namnet kan inte återskapas"
056 "Ändringar kan inte återskapas om programmet kraschar"
057 "Kopierar filen för återskapning..."
058 "Säkerhetskopiering misslyckades: %s"
059 "Ändringar kan inte återskapas om programmet kraschar"
060 "Misslyckades att säkerhetskopiera filen: %s"
061 "Kopierar filen för återskapning..."
062 "Kan inte hitta information om användaridentitet %u"
063 "Kan inte låsa återskapningsfilen"
064 "Återskapningsfilens buffer överskriven"
065 "Återskapningsfil"
066 "%s: Återskapningsfilen är korrupt"
067 "%s: Återskapningsfilen är korrupt"
068 "Det finns ingen fil %s, läsbar av dig, att återskapa"
069 "Det finns äldre versioner av denna fil som du kan återskapa"
070 "Det finns andra filer du kan återskapa"
071 "skickar inte email: %s"
072 "Filen är tom; inget att söka i"
073 "Kom till slutet på filen utan att hitta söksträngen"
074 "Ingen tidigare söksträng"
075 "Hittar inte söksträngen"
076 "Kom till början av filen utan att hitta söksträngen"
077 "Sökningen slog runt"
078 "Söker..."
079 "Inga icke skrivbara tecken funna"
080 "Okänt kommandonamn"
082 "%s: kommandot är inte tillgängligt i "ex" läge"
083 "Talet får inte vara noll"
084 "%s: Ogiltig radspecifikation"
085 "Fel i intern syntaxtabell (%s: %s)"
086 "Användning: %s"
087 "%s: temporärbuffert inte frisläppt"
088 "Offset är före rad 1"
089 "Offset är efter slutet på filen"
090 "@ med intervall exekverades när filen/fönstret ändrades"
091 "Global/v kommando exekverades när filen/fönstret ändrades"
092 "Ex kommando misslyckades: efterföljande kommandon ignorerade"
093 "Ex kommando misslyckades: omdefinierade tangenter ignorerade"
094 "Den andra adressen är mindre än den första"
095 "Inget namn på markering givet"
096 "\\ följs inte av / eller ?"
097 "Referens till ett radnummer mindre än 0"
098 "%s kommandot är inte känt"
099 "Värdet på adressen är för stort"
100 "Värdet på adressen är för litet"
101 "Otillåten adresskombination"
102 "Otillåten adress: bara %lu rader finns i filen"
103 "Otillåten adress: filen är tom"
104 "%s kommandot tillåter inte en adress som är 0"
105 "Inga förkortningar att visa"
106 "Förkortningar måste sluta med ett "ord" tecken"
107 "Förkortningar kan inte innehålla mellanslag eller tab"
108 "Förkortningar kan inte blanda "ord"/"icke ord" tecken, utom i slutet"
109 ""%s" är ingen förkortning"
110 "Vi kommando misslyckades: omdefinierade tangenter ignorerade"
111 "Inga fler filer att editera"
112 "Inga tidigare filer att editera"
113 "Inga tidigare filer att spela tillbaka"
114 "Ingen fillista att visa"
115 "Inget tidigare kommando att ersätta "!" med"
116 "Inget filnamn att ersätta %% med"
117 "Inget filnamn att ersätta # med"
118 "Fel: execl: %s"
119 "I/O fel: %s"
120 "Filen ändrad efter sista skrivning; spara eller använd !"
121 "Kan inte hitta hemkatalog"
122 "Ny nuvarande katalog: %s"
123 "Inga "cut buffers" att visa"
124 "%s kommandot kan inte används som del i ett "global" eller v kommando"
125 "%s/%s: inte läst: varken du eller root är ägare"
126 "%s/%s: inte läst: du är inte ägare"
127 "%s/%s: inte läst: skrivbar av annan än ägaren"
128 "%s: inte läst: varken du eller root är ägare"
129 "%s: inte läst: du är inte ägare"
130 "%s: inte läst: skrivbar av annan än ägaren"
131 "Ingen nästa rad att sätta ihop med"
132 "Det finns inget i inmatningsmappningen"
133 "Det finns inget i kommandomappningen"
134 "%s tecknet kan inte mappas om"
135 ""%s" är inte ommappat just nu"
136 "Namn på markeringar måste vara ett tecken långa"
137 "%s finns, inget sparat; använd ! för att spara"
138 "Ny exrc fil: %s"
139 "Målraden ligger inne i området som ska flyttas"
140 "Open kommandot kräver att open flaggan är satt"
141 "Open kommandot är inte implementerat ännu"
142 "Säkerhetskopiering av filen är inte möjligt"
143 "Filen säkerhetskopierad"
144 "%s expanderade till för många filnamn"
145 "Endast vanliga filer och namngivna rör kan läsas"
146 "%s: läslåset är otillgängligt"
147 "Läser..."
148 "%s: %lu rader, %lu tecken"
149 "Inga bakgrundsfönster att visa"
150 "Script kommandot finns bara i "vi" läge"
151 "Inget kommando att exekvera"
152 "shiftwidth flaggan satt till 0"
153 "Talet har för stort värde"
154 "Talet har för litet värde"
155 "Reguljärt uttryck är givet; r flaggan är meningslös"
156 "#, l och p flaggorna kan inte kombineras med c flaggan i "vi" läge"
157 "Ingen matchande text funnen"
158 "Inget tidigare märke har givits"
159 "Det är färre än %s märken i stacken; använd :display t[ags]"
160 "Det finns ingen fil %s i märkesstacken; använd :display t[ags]"
161 "Tryck Enter för att fortsätta: "
162 "%s: märke inte funnet"
163 "%s: korrupt märke i %s"
164 "%s: märkets radnummer är bortom filslutet"
165 "Märkesstacken är tom"
166 "%s: söksträngen inte funnen"
167 "%d filer till att editera"
168 "Buffert %s är tom"
169 "Bekräfta ändring? [n]"
170 "Avbruten"
171 "Ingen tidigare buffert att exekvera"
172 "Inget tidigare reguljärt uttryck"
173 "%s kommandot kräver att en fil redan lästs in"
174 "Användning: %s"
175 "Visual kommandot kräver att open flaggan är satt"
177 "Tom fil"
178 "Ingen tidigare F, f, T eller t sökning"
179 "%s inte funnen"
180 "Ingen tidigare fil att editera"
181 "Markören är inte i ett tal"
182 "Det resulterande talet är för stort"
183 "Det resulterande talet är för litet"
184 "Inget matchande tecken på denna rad"
185 "Matchande tecken inte funnet"
186 "Det finns inga tecken att ersätta"
187 "Det finns inget fönster att byta till"
188 "Tecken efter söksträng, radoffset och/eller z kommandot"
189 "Ingen tidigare söksträng"
190 "Sökningen slog runt till ursprungliga positionen"
191 "Förkortning överskred expanderingsgränsen: tecken har tagits bort"
192 "Ogiltigt tecken; använd "quote" för att sätta in"
193 "Redan i början på insättningen"
194 "Inga fler tecken att ta bort"
195 "Försök att gå bortom slutet på filen"
196 "Försök att gå bortom slutet på raden"
197 "Ingen förflyttning gjord"
198 "Redan i början på filen"
199 "Försök att gå före början på filen"
200 "Redan i första kolumnen"
201 "Buffertar måste anges före kommandot"
202 "Redan i slutet av filen"
203 "Redan på slutet av raden"
204 "%s är inte ett "vi" kommando"
205 "Användning: %s"
206 "Inga tecken att ta bort"
207 "Q kommandot kräver "ex" i terminalläge"
208 "Inget kommando att repetera"
209 "Filen är tom"
210 "%s kan inte användas som ett förflyttningskommando"
211 "Redan i kommando läge"
212 "Markören är inte i ett ord"
214 "Windows flaggans värde är för stor, största värde är %u"
215 "Lägg till"
216 "Ändra"
217 "Kommando"
218 "Sätt in"
219 "Ersätt"
220 "Förflyttning bortom fönsterslut"
221 "Förflyttning till före fönstrets början"
222 "Fönstret måste vara större än %d rader för delning"
223 "Det finns inga fönster i bakgrunden"
224 "Det finns inget fönster i bakgrunden som editerar filen %s"
225 "Du får inte sätta ditt enda synliga fönster i bakgrunden"
226 "Fönstret kan bara krympa till %d rader"
227 "Fönstret kan inte krympa"
228 "Fönstret kan inte växa"
230 "Detta fönster kan inte pausas"
231 "Avbrutet: omdefinierade tangenter ignorerade"
232 "vi: temporärbuffertar inte frisläppta"
233 "Denna terminal har ingen %s tangent"
234 "Endast en buffert kan anges"
235 "Talet är större än %lu"
236 "Avbrutet"
237 "Kan inte skapa temporär fil"
238 "Warning: %s är inte en normal fil"
239 "%s är redan låst, detta blir en icke skrivbar session"
240 "%s: ta bort"
241 "%s: stäng"
242 "%s: ta bort"
243 "%s: ta bort"
244 "Ej skrivbar fil, filen inte sparad; använd ! för att skriva över"
245 "Ej skrivbar fil, filen inte sparad"
246 "%s finns, ej sparad; använd ! för att utföra operationen"
247 "%s finns, filen inte sparad"
248 "Ofullständig fil, filen inte sparad, använd ! för att skriva över"
249 "Ofullständig fil, filen inte sparad"
250 "%s: filen ändrad efter denna kopia togs; använd ! för att utföra operationen"
251 "%s: filen ändrad efter denna kopia togs"
252 "%s: skrivlåset är otillgängligt"
253 "Skriver..."
254 "%s: VARNING: FILEN TRUNKERAD"
255 "Redan vid första märket i denna grupp"
256 "%s: ny fil: %lu rader, %lu tecken"
257 "%s: %lu rader, %lu tecken"
258 "%s expanderade till för många filnamn"
259 "%s är inte en normal fil"
260 "%s ägs inte av dig"
261 "%s är åtkomstbar av andra än ägaren"
262 "Filen har ändrats efter den sparats; spara eller använd !"
263 "Filen har ändrats efter den sparats; spara eller använd :edit!"
264 "Filen har ändrats efter den sparats; spara eller använd !"
265 "Filen är temporär; exit kastar bort ändringarna"
266 "Ej skrivbar fil, ändringar har inte automatsparats"
267 "Loggningen startar om"
268 "bekräfta? [ynq]"
269 "Tryck på en tangent för att fortsätta: "
270 "Tryck på en tangent för att fortsätta [: för att ge fler kommandon]: "
271 "Tryck på en tangent för att fortsätta [q för att avsluta]: "
272 "Den formen av %s kräver "ex" i terminalläge"
273 "Går till "ex" inmatningsläge."
274 "Kommandot misslyckades, ingen fil inläst ännu."
275 " forts?"
276 "Oväntad teckenhändelse"
277 "Oväntad filslutshändelse"
278 "Sökningen hittade ingenting"
279 "Oväntad avbrottshändelse"
280 "Oväntad avslutningshändelse"
281 "Oväntad omritningshändelse"
282 "Redan vid sista märket i denna grupp"
283 "%s kommandot kräver "ex" i terminalläge"
284 "Den formen av %s är inte tillgänglig när secure edit flaggan är satt"
285 "Oväntad stränghändelse"
286 "Oväntad tidshändelse"
287 "Oväntad skrivhändelse"
289 "Skalexpansion är inte tillgänglig när secure edit flaggan är satt"
290 "%s kommandot är inte tillgänglig när secure edit flaggan är satt"
291 "set: %s kan inte slås av"
292 "Fönstret för litet."
293 "tillagda"
294 "ändrade"
295 "borttagna"
296 "ihopsatta"
297 "flyttade"
298 "flyttade"
299 "inklistrade"
300 "rad"
301 "rader"
302 "Vi har inte länkats med en Tcl tolk"
303 "Filen har ändrats efter den sparats."
304 "Skalexpansion misslyckades"
305 "Ingen %s edit flagga given"
306 "Vi har inte länkats med en Perl tolk"
307 "Inga "ex" kommandon att exekvera"
308 "Tryck <CR> för att exekvera kommando, :q för att avsluta"
309 "Gör "cscope help" för hjälp"
310 "Inga cscope kopplingar körs"
311 "%s: okänd söktyp: använd en av %s"
312 "%d: ingen sådan cscope session"
313 "set: %s flaggan får aldrig slås på"
314 "set: %s flaggan får aldrig sättas till 0"
315 "%s: tillagt: %lu rader, %lu tecken"
316 "Oväntad storleksändring"
317 "%d filer att editera"

1
dist/nvi/catalog/swedish.owner vendored Normal file
View file

@ -0,0 +1 @@
Jan Djarv <jan.djarv@mbox200.swipnet.se>

174
dist/nvi/cl/README.signal vendored Normal file
View file

@ -0,0 +1,174 @@
# Id: README.signal,v 10.1 1995/06/23 10:28:17 bostic Exp (Berkeley) Date: 1995/06/23 10:28:17
There are six (normally) asynchronous actions about which vi cares:
SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP and SIGWINCH.
The assumptions:
1: The DB routines are not reentrant.
2: The curses routines may not be reentrant.
3: Neither DB nor curses will restart system calls.
XXX
Note, most C library functions don't restart system calls. So, we should
*probably* start blocking around any imported function that we don't know
doesn't make a system call. This is going to be a genuine annoyance...
SIGHUP, SIGTERM
Used for file recovery. The DB routines can't be reentered, nor
can they handle interrupted system calls, so the vi routines that
call DB block signals. This means that DB routines could be
called at interrupt time, if necessary.
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, especially things like
making it a pure text widget. 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 cl_init.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.)

120
dist/nvi/cl/cl.h vendored Normal file
View file

@ -0,0 +1,120 @@
/* $NetBSD: cl.h,v 1.2 2010/02/03 15:34:37 roy Exp $ */
/*-
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*
* Id: cl.h,v 10.32 2001/08/28 11:33:40 skimo Exp (Berkeley) Date: 2001/08/28 11:33:40
*/
/* Avoid clash on OSF1 */
#undef DB
#ifdef USE_SLANG_CURSES
#include <slcurses.h>
#else
#ifdef HAVE_NCURSESW_NCURSES_H /* { */
#include <ncursesw/ncurses.h>
#else /* } { */
#ifdef HAVE_NCURSES_H /* { */
#include <ncurses.h>
#else /* } { */
#include <curses.h>
#include <term.h>
#include <termcap.h>
#endif /* } */
#endif
#endif
typedef struct _cl_private {
char ibuf[256]; /* Input keys. */
size_t skip; /* Remaining keys. */
CONVWIN cw; /* Conversion buffer. */
int eof_count; /* EOF count. */
struct termios orig; /* Original terminal values. */
struct termios ex_enter;/* Terminal values to enter ex. */
struct termios vi_enter;/* Terminal values to enter vi. */
char *el; /* Clear to EOL terminal string. */
char *cup; /* Cursor movement terminal string. */
char *cuu1; /* Cursor up terminal string. */
char *rmso, *smso; /* Inverse video terminal strings. */
char *smcup, *rmcup; /* Terminal start/stop strings. */
char *oname; /* Original screen window name. */
SCR *focus; /* Screen that has the "focus". */
int killersig; /* Killer signal. */
#define INDX_HUP 0
#define INDX_INT 1
#define INDX_TERM 2
#define INDX_WINCH 3
#define INDX_MAX 4 /* Original signal information. */
struct sigaction oact[INDX_MAX];
enum { /* Tty group write mode. */
TGW_UNKNOWN=0, TGW_SET, TGW_UNSET } tgw;
enum { /* Terminal initialization strings. */
TE_SENT=0, TI_SENT } ti_te;
#define CL_IN_EX 0x0001 /* Currently running ex. */
#define CL_LAYOUT 0x0002 /* Screen layout changed. */
#define CL_RENAME 0x0004 /* X11 xterm icon/window renamed. */
#define CL_RENAME_OK 0x0008 /* User wants the windows renamed. */
#define CL_SCR_EX_INIT 0x0010 /* Ex screen initialized. */
#define CL_SCR_VI_INIT 0x0020 /* Vi screen initialized. */
#define CL_SIGHUP 0x0040 /* SIGHUP arrived. */
#define CL_SIGINT 0x0080 /* SIGINT arrived. */
#define CL_SIGTERM 0x0100 /* SIGTERM arrived. */
#define CL_SIGWINCH 0x0200 /* SIGWINCH arrived. */
#define CL_STDIN_TTY 0x0400 /* Talking to a terminal. */
u_int32_t flags;
} CL_PRIVATE;
#define CLP(sp) ((CL_PRIVATE *)((sp)->gp->cl_private))
#define GCLP(gp) ((CL_PRIVATE *)gp->cl_private)
#define CLSP(sp) ((WINDOW *)((sp)->cl_private))
/* Return possibilities from the keyboard read routine. */
typedef enum { INP_OK=0, INP_EOF, INP_ERR, INP_INTR, INP_TIMEOUT } input_t;
/* The screen position relative to a specific window. */
/*
#define RCNO(sp, cno) (sp)->coff + (cno)
#define RLNO(sp, lno) (sp)->roff + (lno)
*/
#define RCNO(sp, cno) (cno)
#define RLNO(sp, lno) (lno)
/*
* XXX
* Some implementations of curses.h don't define these for us. Used for
* compatibility only.
*/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#include "extern.h"
#ifdef USE_PERL_SETENV
#include "../perl_api/extern.h"
#define cl_setenv(sp,name,val) perl_setenv(sp,name,val)
#define cl_unsetenv(sp,name) perl_setenv(sp,name,NULL)
#else
#define cl_setenv(sp,name,val) setenv(name,val,1)
#define cl_unsetenv(sp,name) unsetenv(name)
#endif

350
dist/nvi/cl/cl_bsd.c vendored Normal file
View file

@ -0,0 +1,350 @@
/* $NetBSD: cl_bsd.c,v 1.4 2010/02/03 15:34:37 roy Exp $ */
/*-
* Copyright (c) 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*/
#include "config.h"
#ifndef lint
static const char sccsid[] = "Id: cl_bsd.c,v 8.32 2000/12/01 13:56:17 skimo Exp (Berkeley) Date: 2000/12/01 13:56:17";
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <bitstring.h>
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "../common/common.h"
#include "../vi/vi.h"
#include "cl.h"
#ifndef HAVE_CURSES_SETUPTERM
static char *ke; /* Keypad on. */
static char *ks; /* Keypad off. */
static char *vb; /* Visible bell string. */
#endif
/*
* HP's support the entire System V curses package except for the tigetstr
* and tigetnum functions. Ultrix supports the BSD curses package except
* for the idlok function. Cthulu only knows why. Break things up into a
* minimal set of functions.
*/
#ifndef HAVE_CURSES_WADDNSTR
/*
* waddnstr --
*
* PUBLIC: #ifndef HAVE_CURSES_WADDNSTR
* PUBLIC: int waddnstr __P((WINDOW*, char *, int));
* PUBLIC: #endif
*/
int
waddnstr(w, s, n)
WINDOW *w;
char *s;
int n;
{
int ch;
while (n-- && (ch = *s++))
waddch(w, ch);
return (OK);
}
#endif
#ifndef HAVE_CURSES_BEEP
/*
* beep --
*
* PUBLIC: #ifndef HAVE_CURSES_BEEP
* PUBLIC: void beep __P((void));
* PUBLIC: #endif
*/
void
beep()
{
(void)write(1, "\007", 1); /* '\a' */
}
#endif /* !HAVE_CURSES_BEEP */
#ifndef HAVE_CURSES_FLASH
/*
* flash --
* Flash the screen.
*
* PUBLIC: #ifndef HAVE_CURSES_FLASH
* PUBLIC: void flash __P((void));
* PUBLIC: #endif
*/
void
flash()
{
if (vb != NULL) {
(void)tputs(vb, 1, cl_putchar);
(void)fflush(stdout);
} else
beep();
}
#endif /* !HAVE_CURSES_FLASH */
#ifndef HAVE_CURSES_IDLOK
/*
* idlok --
* Turn on/off hardware line insert/delete.
*
* PUBLIC: #ifndef HAVE_CURSES_IDLOK
* PUBLIC: void idlok __P((WINDOW *, int));
* PUBLIC: #endif
*/
void
idlok(win, bf)
WINDOW *win;
int bf;
{
return;
}
#endif /* !HAVE_CURSES_IDLOK */
#ifndef HAVE_CURSES_KEYPAD
/*
* keypad --
* Put the keypad/cursor arrows into or out of application mode.
*
* PUBLIC: #ifndef HAVE_CURSES_KEYPAD
* PUBLIC: int keypad __P((void *, int));
* PUBLIC: #endif
*/
int
keypad(a, on)
void *a;
int on;
{
char *p;
if ((p = tigetstr(on ? "smkx" : "rmkx")) != (char *)-1) {
(void)tputs(p, 0, cl_putchar);
(void)fflush(stdout);
}
return (0);
}
#endif /* !HAVE_CURSES_KEYPAD */
#ifndef HAVE_CURSES_NEWTERM
/*
* newterm --
* Create a new curses screen.
*
* PUBLIC: #ifndef HAVE_CURSES_NEWTERM
* PUBLIC: void *newterm __P((const char *, FILE *, FILE *));
* PUBLIC: #endif
*/
void *
newterm(a, b, c)
const char *a;
FILE *b, *c;
{
return (initscr());
}
#endif /* !HAVE_CURSES_NEWTERM */
#ifndef HAVE_CURSES_SETUPTERM
/*
* setupterm --
* Set up terminal.
*
* PUBLIC: #ifndef HAVE_CURSES_SETUPTERM
* PUBLIC: void setupterm __P((char *, int, int *));
* PUBLIC: #endif
*/
void
setupterm(ttype, fno, errp)
char *ttype;
int fno, *errp;
{
static char buf[2048];
char *p;
if ((*errp = tgetent(buf, ttype)) > 0) {
if (ke != NULL)
free(ke);
ke = ((p = tigetstr("rmkx")) == (char *)-1) ?
NULL : strdup(p);
if (ks != NULL)
free(ks);
ks = ((p = tigetstr("smkx")) == (char *)-1) ?
NULL : strdup(p);
if (vb != NULL)
free(vb);
vb = ((p = tigetstr("flash")) == (char *)-1) ?
NULL : strdup(p);
}
}
#endif /* !HAVE_CURSES_SETUPTERM */
#ifndef HAVE_CURSES_TIGETSTR
/* Terminfo-to-termcap translation table. */
typedef struct _tl {
const char *terminfo; /* Terminfo name. */
const char *termcap; /* Termcap name. */
} TL;
static const TL list[] = {
{ "cols", "co", }, /* Terminal columns. */
{ "cup", "cm", }, /* Cursor up. */
{ "cuu1", "up", }, /* Cursor up. */
{ "el", "ce", }, /* Clear to end-of-line. */
{ "flash", "vb", }, /* Visible bell. */
{ "kcub1", "kl", }, /* Cursor left. */
{ "kcud1", "kd", }, /* Cursor down. */
{ "kcuf1", "kr", }, /* Cursor right. */
{ "kcuu1", "ku", }, /* Cursor up. */
{ "kdch1", "kD", }, /* Delete character. */
{ "kdl1", "kL", }, /* Delete line. */
{ "ked", "kS", }, /* Delete to end of screen. */
{ "kel", "kE", }, /* Delete to eol. */
{ "kend", "@7", }, /* Go to eol. */
{ "khome", "kh", }, /* Go to sol. */
{ "kich1", "kI", }, /* Insert at cursor. */
{ "kil1", "kA", }, /* Insert line. */
{ "kind", "kF", }, /* Scroll down. */
{ "kll", "kH", }, /* Go to eol. */
{ "knp", "kN", }, /* Page down. */
{ "kpp", "kP", }, /* Page up. */
{ "kri", "kR", }, /* Scroll up. */
{ "lines", "li", }, /* Terminal lines. */
{ "rmcup", "te", }, /* Terminal end string. */
{ "rmkx", "ke", }, /* Exit "keypad-transmit" mode. */
{ "rmso", "se", }, /* Standout end. */
{ "smcup", "ti", }, /* Terminal initialization string. */
{ "smkx", "ks", }, /* Enter "keypad-transmit" mode. */
{ "smso", "so", }, /* Standout begin. */
};
#ifdef _AIX
/*
* AIX's implementation for function keys greater than 10 is different and
* only goes as far as 36.
*/
static const char codes[] = {
/* 0-10 */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';',
/* 11-20 */ '<', '>', '!', '@', '#', '$', '%', '^', '&', '*',
/* 21-30 */ '(', ')', '-', '_', '+', ',', ':', '?', '[', ']',
/* 31-36 */ '{', '}', '|', '~', '/', '='
};
#else
/*
* !!!
* Historically, the 4BSD termcap code didn't support functions keys greater
* than 9. This was silently enforced -- asking for key k12 would return 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 the
* implementors of any System V compatibility code or an extended termcap used
* those codes.
*/
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',
};
#endif /* _AIX */
/*
* lcmp --
* list comparison routine for bsearch.
*/
static int
lcmp(const void *a, const void *b)
{
return (strcmp(a, ((const TL *)b)->terminfo));
}
/*
* tigetstr --
*
* Vendors put the prototype for tigetstr into random include files, including
* <term.h>, which we can't include because it makes other systems unhappy.
* Try and work around the problem, since we only care about the return value.
*
* PUBLIC: #ifdef HAVE_CURSES_TIGETSTR
* PUBLIC: char *tigetstr();
* PUBLIC: #else
* PUBLIC: char *tigetstr __P((char *));
* PUBLIC: #endif
*/
char *
tigetstr(name)
const char *name;
{
static char sbuf[256];
TL *tlp;
int n;
char *p, mykeyname[3];
if ((tlp = bsearch(name,
list, sizeof(list) / sizeof(TL), sizeof(TL), lcmp)) == NULL) {
#ifdef _AIX
if (name[0] == 'k' &&
name[1] == 'f' && (n = atoi(name + 2)) <= 36) {
mykeyname[0] = 'k';
mykeyname[1] = codes[n];
mykeyname[2] = '\0';
#else
if (name[0] == 'k' &&
name[1] == 'f' && (n = atoi(name + 2)) <= 63) {
mykeyname[0] = n <= 10 ? 'k' : 'F';
mykeyname[1] = codes[n];
mykeyname[2] = '\0';
#endif
name = mykeyname;
}
} else
name = tlp->termcap;
p = sbuf;
#ifdef _AIX
return ((p = tgetstr(name, &p)) == NULL ? (char *)-1 : strcpy(sbuf, p));
#else
return (tgetstr(name, &p) == NULL ? (char *)-1 : sbuf);
#endif
}
/*
* tigetnum --
*
* PUBLIC: #ifndef HAVE_CURSES_TIGETSTR
* PUBLIC: int tigetnum __P((char *));
* PUBLIC: #endif
*/
int
tigetnum(name)
const char *name;
{
TL *tlp;
int val;
if ((tlp = bsearch(name,
list, sizeof(list) / sizeof(TL), sizeof(TL), lcmp)) != NULL) {
name = tlp->termcap;
}
return ((val = tgetnum(name)) == -1 ? -2 : val);
}
#endif /* !HAVE_CURSES_TIGETSTR */

894
dist/nvi/cl/cl_funcs.c vendored Normal file
View file

@ -0,0 +1,894 @@
/* $NetBSD: cl_funcs.c,v 1.4 2009/11/15 18:43:28 dsl Exp $ */
/*-
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*/
#include "config.h"
#ifndef lint
static const char sccsid[] = "Id: cl_funcs.c,v 10.72 2002/03/02 23:18:33 skimo Exp (Berkeley) Date: 2002/03/02 23:18:33";
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <bitstring.h>
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "../common/common.h"
#include "../vi/vi.h"
#include "cl.h"
static void cl_rdiv __P((SCR *));
static int
addstr4(SCR *sp, const void *str, size_t len, int wide)
{
CL_PRIVATE *clp;
WINDOW *win;
size_t y, x;
int iv;
clp = CLP(sp);
win = CLSP(sp) ? CLSP(sp) : stdscr;
/*
* If ex isn't in control, it's the last line of the screen and
* it's a split screen, use inverse video.
*/
iv = 0;
getyx(win, y, x);
if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
iv = 1;
(void)wstandout(win);
}
#ifdef USE_WIDECHAR
if (wide) {
if (waddnwstr(win, str, len) == ERR)
return (1);
} else
#endif
if (waddnstr(win, str, len) == ERR)
return (1);
if (iv)
(void)wstandend(win);
return (0);
}
/*
* cl_waddstr --
* Add len bytes from the string at the cursor, advancing the cursor.
*
* PUBLIC: int cl_waddstr __P((SCR *, const CHAR_T *, size_t));
*/
int
cl_waddstr(SCR *sp, const CHAR_T *str, size_t len)
{
return addstr4(sp, (const void *)str, len, 1);
}
/*
* cl_addstr --
* Add len bytes from the string at the cursor, advancing the cursor.
*
* PUBLIC: int cl_addstr __P((SCR *, const char *, size_t));
*/
int
cl_addstr(SCR *sp, const char *str, size_t len)
{
return addstr4(sp, (const void *)str, len, 0);
}
/*
* cl_attr --
* Toggle a screen attribute on/off.
*
* PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int));
*/
int
cl_attr(SCR *sp, scr_attr_t attribute, int on)
{
CL_PRIVATE *clp;
WINDOW *win;
clp = CLP(sp);
win = CLSP(sp) ? CLSP(sp) : stdscr;
switch (attribute) {
case SA_ALTERNATE:
/*
* !!!
* There's a major layering violation here. The problem is that the
* X11 xterm screen has what's known as an "alternate" screen. Some
* xterm termcap/terminfo entries include sequences to switch to/from
* that alternate screen as part of the ti/te (smcup/rmcup) strings.
* Vi runs in the alternate screen, so that you are returned to the
* same screen contents on exit from vi that you had when you entered
* vi. Further, when you run :shell, or :!date or similar ex commands,
* you also see the original screen contents. This wasn't deliberate
* on vi's part, it's just that it historically sent terminal init/end
* sequences at those times, and the addition of the alternate screen
* sequences to the strings changed the behavior of vi. The problem
* caused by this is that we don't want to switch back to the alternate
* screen while getting a new command from the user, when the user is
* continuing to enter ex commands, e.g.:
*
* :!date <<< switch to original screen
* [Hit return to continue] <<< prompt user to continue
* :command <<< get command from user
*
* Note that the :command input is a true vi input mode, e.g., input
* maps and abbreviations are being done. So, we need to be able to
* switch back into the vi screen mode, without flashing the screen.
*
* To make matters worse, the curses initscr() and endwin() calls will
* do this automatically -- so, this attribute isn't as controlled by
* the higher level screen as closely as one might like.
*/
if (on) {
if (clp->ti_te != TI_SENT) {
clp->ti_te = TI_SENT;
if (clp->smcup == NULL)
(void)cl_getcap(sp, "smcup", &clp->smcup);
if (clp->smcup != NULL)
(void)tputs(clp->smcup, 1, cl_putchar);
}
} else
if (clp->ti_te != TE_SENT) {
clp->ti_te = TE_SENT;
if (clp->rmcup == NULL)
(void)cl_getcap(sp, "rmcup", &clp->rmcup);
if (clp->rmcup != NULL)
(void)tputs(clp->rmcup, 1, cl_putchar);
(void)fflush(stdout);
}
(void)fflush(stdout);
break;
case SA_INVERSE:
if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
if (clp->smso == NULL)
return (1);
if (on)
(void)tputs(clp->smso, 1, cl_putchar);
else
(void)tputs(clp->rmso, 1, cl_putchar);
(void)fflush(stdout);
} else {
if (on)
(void)wstandout(win);
else
(void)wstandend(win);
}
break;
default:
abort();
}
return (0);
}
/*
* cl_baud --
* Return the baud rate.
*
* PUBLIC: int cl_baud __P((SCR *, u_long *));
*/
int
cl_baud(SCR *sp, u_long *ratep)
{
CL_PRIVATE *clp;
/*
* 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.
*/
clp = CLP(sp);
switch (cfgetospeed(&clp->orig)) {
case B50:
case B75:
case B110:
case B134:
case B150:
case B200:
case B300:
case B600:
*ratep = 600;
break;
case B1200:
*ratep = 1200;
break;
default:
*ratep = 9600;
break;
}
return (0);
}
/*
* cl_bell --
* Ring the bell/flash the screen.
*
* PUBLIC: int cl_bell __P((SCR *));
*/
int
cl_bell(SCR *sp)
{
if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE | SC_SCR_EX))
(void)write(STDOUT_FILENO, "\07", 1); /* \a */
else {
/*
* Vi has an edit option which determines if the terminal
* should be beeped or the screen flashed.
*/
if (O_ISSET(sp, O_FLASH))
(void)flash();
else
(void)beep();
}
return (0);
}
/*
* cl_clrtoeol --
* Clear from the current cursor to the end of the line.
*
* PUBLIC: int cl_clrtoeol __P((SCR *));
*/
int
cl_clrtoeol(SCR *sp)
{
WINDOW *win;
#if 0
size_t spcnt, y, x;
#endif
win = CLSP(sp) ? CLSP(sp) : stdscr;
#if 0
if (IS_VSPLIT(sp)) {
/* The cursor must be returned to its original position. */
getyx(win, y, x);
for (spcnt = (sp->coff + sp->cols) - x; spcnt > 0; --spcnt)
(void)waddch(win, ' ');
(void)wmove(win, y, x);
return (0);
} else
#endif
return (wclrtoeol(win) == ERR);
}
/*
* cl_cursor --
* Return the current cursor position.
*
* PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *));
*/
int
cl_cursor(SCR *sp, size_t *yp, size_t *xp)
{
WINDOW *win;
win = CLSP(sp) ? CLSP(sp) : stdscr;
/*
* The curses screen support splits a single underlying curses screen
* into multiple screens to support split screen semantics. For this
* reason the returned value must be adjusted to be relative to the
* current screen, and not absolute. Screens that implement the split
* using physically distinct screens won't need this hack.
*/
getyx(win, *yp, *xp);
/*
*yp -= sp->roff;
*xp -= sp->coff;
*/
return (0);
}
/*
* cl_deleteln --
* Delete the current line, scrolling all lines below it.
*
* PUBLIC: int cl_deleteln __P((SCR *));
*/
int
cl_deleteln(SCR *sp)
{
CHAR_T ch;
CL_PRIVATE *clp;
WINDOW *win;
size_t col, lno, spcnt, y, x;
clp = CLP(sp);
win = CLSP(sp) ? CLSP(sp) : stdscr;
/*
* This clause is required because the curses screen uses reverse
* video to delimit split screens. If the screen does not do this,
* this code won't be necessary.
*
* If the bottom line was in reverse video, rewrite it in normal
* video before it's scrolled.
*
* Check for the existence of a chgat function; XSI requires it, but
* historic implementations of System V curses don't. If it's not
* a #define, we'll fall back to doing it by hand, which is slow but
* acceptable.
*
* By hand means walking through the line, retrieving and rewriting
* each character. Curses has no EOL marker, so track strings of
* spaces, and copy the trailing spaces only if there's a non-space
* character following.
*/
if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) {
getyx(win, y, x);
#ifdef mvchgat
mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
#else
for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) {
(void)wmove(win, lno, col);
ch = winch(win);
if (isblank(ch))
++spcnt;
else {
(void)wmove(win, lno, col - spcnt);
for (; spcnt > 0; --spcnt)
(void)waddch(win, ' ');
(void)waddch(win, ch);
}
if (++col >= sp->cols)
break;
}
#endif
(void)wmove(win, y, x);
}
/*
* The bottom line is expected to be blank after this operation,
* and other screens must support that semantic.
*/
return (wdeleteln(win) == ERR);
}
/*
* cl_discard --
* Discard a screen.
*
* PUBLIC: int cl_discard __P((SCR *, SCR **));
*/
int
cl_discard(SCR *discardp, SCR **acquirep)
{
CL_PRIVATE *clp;
SCR* tsp;
if (discardp) {
clp = CLP(discardp);
F_SET(clp, CL_LAYOUT);
if (CLSP(discardp)) {
delwin(CLSP(discardp));
discardp->cl_private = NULL;
}
}
/* no screens got a piece; we're done */
if (!acquirep)
return 0;
for (; (tsp = *acquirep) != NULL; ++acquirep) {
clp = CLP(tsp);
F_SET(clp, CL_LAYOUT);
if (CLSP(tsp))
delwin(CLSP(tsp));
tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols,
tsp->roff, tsp->coff);
}
/* discardp is going away, acquirep is taking up its space. */
return (0);
}
/*
* cl_ex_adjust --
* Adjust the screen for ex. This routine is purely for standalone
* ex programs. All special purpose, all special case.
*
* PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t));
*/
int
cl_ex_adjust(SCR *sp, exadj_t action)
{
CL_PRIVATE *clp;
int cnt;
clp = CLP(sp);
switch (action) {
case EX_TERM_SCROLL:
/* Move the cursor up one line if that's possible. */
if (clp->cuu1 != NULL)
(void)tputs(clp->cuu1, 1, cl_putchar);
else if (clp->cup != NULL)
(void)tputs(tgoto(clp->cup,
0, LINES - 2), 1, cl_putchar);
else
return (0);
/* FALLTHROUGH */
case EX_TERM_CE:
/* Clear the line. */
if (clp->el != NULL) {
(void)putchar('\r');
(void)tputs(clp->el, 1, cl_putchar);
} else {
/*
* Historically, ex didn't erase the line, so, if the
* displayed line was only a single glyph, and <eof>
* was more than one glyph, the output would not fully
* overwrite the user's input. To fix this, output
* the maxiumum character number of spaces. Note,
* this won't help if the user entered extra prompt
* or <blank> characters before the command character.
* We'd have to do a lot of work to make that work, and
* it's almost certainly not worth the effort.
*/
for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
(void)putchar('\b');
for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
(void)putchar(' ');
(void)putchar('\r');
(void)fflush(stdout);
}
break;
default:
abort();
}
return (0);
}
/*
* cl_insertln --
* Push down the current line, discarding the bottom line.
*
* PUBLIC: int cl_insertln __P((SCR *));
*/
int
cl_insertln(SCR *sp)
{
WINDOW *win;
win = CLSP(sp) ? CLSP(sp) : stdscr;
/*
* The current line is expected to be blank after this operation,
* and the screen must support that semantic.
*/
return (winsertln(win) == ERR);
}
/*
* cl_keyval --
* Return the value for a special key.
*
* PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
*/
int
cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep)
{
CL_PRIVATE *clp;
/*
* VEOF, VERASE and VKILL are required by POSIX 1003.1-1990,
* VWERASE is a 4BSD extension.
*/
clp = CLP(sp);
switch (val) {
case KEY_VEOF:
*dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE;
break;
case KEY_VERASE:
*dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE;
break;
case KEY_VKILL:
*dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE;
break;
#ifdef VWERASE
case KEY_VWERASE:
*dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE;
break;
#endif
default:
*dnep = 1;
break;
}
return (0);
}
/*
* cl_move --
* Move the cursor.
*
* PUBLIC: int cl_move __P((SCR *, size_t, size_t));
*/
int
cl_move(SCR *sp, size_t lno, size_t cno)
{
WINDOW *win;
win = CLSP(sp) ? CLSP(sp) : stdscr;
/* See the comment in cl_cursor. */
if (wmove(win, RLNO(sp, lno), RCNO(sp, cno)) == ERR) {
msgq(sp, M_ERR, "Error: move: l(%zu + %zu) c(%zu + %zu)",
lno, sp->roff, cno, sp->coff);
return (1);
}
return (0);
}
/*
* cl_refresh --
* Refresh the screen.
*
* PUBLIC: int cl_refresh __P((SCR *, int));
*/
int
cl_refresh(SCR *sp, int repaint)
{
GS *gp;
CL_PRIVATE *clp;
WINDOW *win;
SCR *psp, *tsp;
size_t y, x;
gp = sp->gp;
clp = CLP(sp);
win = CLSP(sp) ? CLSP(sp) : stdscr;
/*
* If we received a killer signal, we're done, there's no point
* in refreshing the screen.
*/
if (clp->killersig)
return (0);
/*
* If repaint is set, the editor is telling us that we don't know
* what's on the screen, so we have to repaint from scratch.
*
* If repaint set or the screen layout changed, we need to redraw
* any lines separating vertically split screens. If the horizontal
* offsets are the same, then the split was vertical, and need to
* draw a dividing line.
*/
if (repaint || F_ISSET(clp, CL_LAYOUT)) {
getyx(stdscr, y, x);
for (psp = sp;
psp != (void *)&sp->wp->scrq; psp = psp->q.cqe_next)
for (tsp = psp->q.cqe_next;
tsp != (void *)&sp->wp->scrq;
tsp = tsp->q.cqe_next)
if (psp->roff == tsp->roff) {
if (psp->coff + psp->cols + 1 == tsp->coff)
cl_rdiv(psp);
else
if (tsp->coff + tsp->cols + 1 == psp->coff)
cl_rdiv(tsp);
}
(void)wmove(stdscr, y, x);
F_CLR(clp, CL_LAYOUT);
}
/*
* In the curses library, doing wrefresh(curscr) is okay, but the
* screen flashes when we then apply the refresh() to bring it up
* to date. So, use clearok().
*/
if (repaint)
clearok(curscr, 1);
/*
* Only do an actual refresh, when this is the focus window,
* i.e. the one holding the cursor. This assumes that refresh
* is called for that window after refreshing the others.
* This prevents the cursor being drawn in the other windows.
*/
return (wnoutrefresh(stdscr) == ERR ||
wnoutrefresh(win) == ERR ||
(sp == clp->focus && doupdate() == ERR));
}
/*
* cl_rdiv --
* Draw a dividing line between two vertically split screens.
*/
static void
cl_rdiv(SCR *sp)
{
size_t cnt;
for (cnt = 0; cnt < sp->rows - 1; ++cnt) {
wmove(stdscr, sp->roff + cnt, sp->cols + sp->coff);
waddch(stdscr, '|');
}
}
/*
* cl_rename --
* Rename the file.
*
* PUBLIC: int cl_rename __P((SCR *, char *, int));
*/
int
cl_rename(SCR *sp, char *name, int on)
{
CL_PRIVATE *clp;
FILE *pfp;
GS *gp;
char buf[256], *p;
gp = sp->gp;
clp = CLP(sp);
if (on) {
clp->focus = sp;
if (!F_ISSET(clp, CL_RENAME_OK))
return (0);
/*
* XXX
* We can only rename windows for xterm.
*/
if (strncmp(OG_STR(gp, GO_TERM), "xterm", sizeof("xterm") - 1))
return (0);
/*
* XXX
* Try and figure out the current name of this window. There
* are two forms of the xwininfo output I've seen:
*
* Window id: 0x400000d "name"
* Window id: 0x140000d (name)
*/
#define COMMAND \
"expr \"`xwininfo -id $WINDOWID | grep id:`\" : '.* [\"(]\\(.*\\)[\")]'"
if (clp->oname == NULL &&
(pfp = popen(COMMAND, "r")) != NULL) {
if (fgets(buf, sizeof(buf), pfp) != NULL &&
(p = strchr(buf, '\n')) != NULL) {
*p = '\0';
clp->oname = strdup(buf);
}
(void)fclose(pfp);
}
cl_setname(gp, name);
F_SET(clp, CL_RENAME);
} else
if (F_ISSET(clp, CL_RENAME)) {
cl_setname(gp, clp->oname);
F_CLR(clp, CL_RENAME);
}
return (0);
}
/*
* cl_setname --
* Set a X11 icon/window name.
*
* PUBLIC: void cl_setname __P((GS *, char *));
*/
void
cl_setname(GS *gp, char *name)
{
/* X11 xterm escape sequence to rename the icon/window. */
#define XTERM_RENAME "\033]0;%s\007"
(void)printf(XTERM_RENAME, name == NULL ? OG_STR(gp, GO_TERM) : name);
(void)fflush(stdout);
}
/*
* cl_split --
* Split a screen.
*
* PUBLIC: int cl_split __P((SCR *, SCR *));
*/
int
cl_split(SCR *origp, SCR *newp)
{
CL_PRIVATE *clp;
clp = CLP(origp);
F_SET(clp, CL_LAYOUT);
if (CLSP(origp))
delwin(CLSP(origp));
origp->cl_private = subwin(stdscr, origp->rows, origp->cols,
origp->roff, origp->coff);
newp->cl_private = subwin(stdscr, newp->rows, newp->cols,
newp->roff, newp->coff);
/* origp is the original screen, giving up space to newp. */
return (0);
}
/*
* cl_suspend --
* Suspend a screen.
*
* PUBLIC: int cl_suspend __P((SCR *, int *));
*/
int
cl_suspend(SCR *sp, int *allowedp)
{
struct termios t;
CL_PRIVATE *clp;
WINDOW *win;
GS *gp;
size_t y, x;
int changed;
gp = sp->gp;
clp = CLP(sp);
win = CLSP(sp) ? CLSP(sp) : stdscr;
*allowedp = 1;
/*
* The ex implementation of this function isn't needed by screens not
* supporting ex commands that require full terminal canonical mode
* (e.g. :suspend).
*
* The vi implementation of this function isn't needed by screens not
* supporting vi process suspension, i.e. any screen that isn't backed
* by a UNIX shell.
*
* Setting allowedp to 0 will cause the editor to reject the command.
*/
if (F_ISSET(sp, SC_EX)) {
/* Save the terminal settings, and restore the original ones. */
if (F_ISSET(clp, CL_STDIN_TTY)) {
(void)tcgetattr(STDIN_FILENO, &t);
(void)tcsetattr(STDIN_FILENO,
TCSASOFT | TCSADRAIN, &clp->orig);
}
/* Stop the process group. */
(void)kill(0, SIGTSTP);
/* Time passes ... */
/* Restore terminal settings. */
if (F_ISSET(clp, CL_STDIN_TTY))
(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
return (0);
}
/*
* Move to the lower left-hand corner of the screen.
*
* XXX
* Not sure this is necessary in System V implementations, but it
* shouldn't hurt.
*/
getyx(win, y, x);
(void)wmove(win, LINES - 1, 0);
(void)wrefresh(win);
/*
* Temporarily end the screen. System V introduced a semantic where
* endwin() could be restarted. We use it because restarting curses
* from scratch often fails in System V. 4BSD curses didn't support
* restarting after endwin(), so we have to do what clean up we can
* without calling it.
*/
/* Save the terminal settings. */
(void)tcgetattr(STDIN_FILENO, &t);
/* Restore the cursor keys to normal mode. */
(void)keypad(stdscr, FALSE);
/* Restore the window name. */
(void)cl_rename(sp, NULL, 0);
#ifdef HAVE_BSD_CURSES
(void)cl_attr(sp, SA_ALTERNATE, 0);
#else
(void)endwin();
#endif
/*
* XXX
* Restore the original terminal settings. This is bad -- the
* reset can cause character loss from the tty queue. However,
* we can't call endwin() in BSD curses implementations, and too
* many System V curses implementations don't get it right.
*/
(void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig);
/* Stop the process group. */
(void)kill(0, SIGTSTP);
/* Time passes ... */
/*
* If we received a killer signal, we're done. Leave everything
* unchanged. In addition, the terminal has already been reset
* correctly, so leave it alone.
*/
if (clp->killersig) {
F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
return (0);
}
/* Restore terminal settings. */
wrefresh(win); /* Needed on SunOs/Solaris ? */
if (F_ISSET(clp, CL_STDIN_TTY))
(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
#ifdef HAVE_BSD_CURSES
(void)cl_attr(sp, SA_ALTERNATE, 1);
#endif
/* Set the window name. */
(void)cl_rename(sp, sp->frp->name, 1);
/* Put the cursor keys into application mode. */
(void)keypad(stdscr, TRUE);
/* Refresh and repaint the screen. */
(void)wmove(win, y, x);
(void)cl_refresh(sp, 1);
/* If the screen changed size, set the SIGWINCH bit. */
if (cl_ssize(sp, 1, NULL, NULL, &changed))
return (1);
if (changed)
F_SET(CLP(sp), CL_SIGWINCH);
return (0);
}
/*
* cl_usage --
* Print out the curses usage messages.
*
* PUBLIC: void cl_usage __P((void));
*/
void
cl_usage(void)
{
#define USAGE "\
usage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\
usage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n"
(void)fprintf(stderr, "%s", USAGE);
#undef USAGE
}
#ifdef DEBUG
/*
* gdbrefresh --
* Stub routine so can flush out curses screen changes using gdb.
*/
int
gdbrefresh(void)
{
refresh();
return (0); /* XXX Convince gdb to run it. */
}
#endif

440
dist/nvi/cl/cl_main.c vendored Normal file
View file

@ -0,0 +1,440 @@
/* $NetBSD: cl_main.c,v 1.4 2011/09/16 16:13:41 joerg Exp $ */
/*-
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*/
#include "config.h"
#ifndef lint
static const char sccsid[] = "Id: cl_main.c,v 10.54 2001/07/29 19:07:27 skimo Exp (Berkeley) Date: 2001/07/29 19:07:27";
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#include <bitstring.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "../common/common.h"
#include "../ip/extern.h"
#include "cl.h"
#include "pathnames.h"
GS *__global_list; /* GLOBAL: List of screens. */
sigset_t __sigblockset; /* GLOBAL: Blocked signals. */
static void cl_func_std __P((WIN *));
#ifdef notused
static void cl_end __P((CL_PRIVATE *));
#endif
static CL_PRIVATE *cl_init __P((WIN *));
__dead static void perr __P((const char *, const char *));
static int setsig __P((int, struct sigaction *, void (*)(int)));
static void sig_end __P((GS *));
static void term_init __P((const char *, const char *));
/*
* main --
* This is the main loop for the standalone curses editor.
*/
int
main(int argc, char **argv)
{
static int reenter;
CL_PRIVATE *clp;
GS *gp;
WIN *wp;
size_t rows, cols;
int rval;
char **p_av, **t_av;
const char *ttype;
/* If loaded at 0 and jumping through a NULL pointer, stop. */
if (reenter++)
abort();
/* Create and initialize the global structure. */
__global_list = gp = gs_init(argv[0]);
/*
* Strip out any arguments that vi isn't going to understand. There's
* no way to portably call getopt twice, so arguments parsed here must
* be removed from the argument list.
*/
for (p_av = t_av = argv;;) {
if (*t_av == NULL) {
*p_av = NULL;
break;
}
if (!strcmp(*t_av, "--")) {
while ((*p_av++ = *t_av++) != NULL);
break;
}
*p_av++ = *t_av++;
}
/* Create new window */
wp = gs_new_win(gp);
/* Create and initialize the CL_PRIVATE structure. */
clp = cl_init(wp);
/*
* Initialize the terminal information.
*
* We have to know what terminal it is from the start, since we may
* have to use termcap/terminfo to find out how big the screen is.
*/
if ((ttype = getenv("TERM")) == NULL) {
if (isatty(STDIN_FILENO))
fprintf(stderr, "%s: warning: TERM is not set\n",
gp->progname);
ttype = "unknown";
}
term_init(gp->progname, ttype);
/* Add the terminal type to the global structure. */
if ((OG_D_STR(gp, GO_TERM) =
OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL)
perr(gp->progname, NULL);
/* Figure out how big the screen is. */
if (cl_ssize(NULL, 0, &rows, &cols, NULL))
exit (1);
/* Add the rows and columns to the global structure. */
OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows;
OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols;
/* Ex wants stdout to be buffered. */
(void)setvbuf(stdout, NULL, _IOFBF, 0);
/* Start catching signals. */
if (sig_init(gp, NULL))
exit (1);
/* Run ex/vi. */
rval = editor(wp, argc, argv);
/* Clean out the global structure. */
gs_end(gp);
/* Clean up signals. */
sig_end(gp);
/* Clean up the terminal. */
(void)cl_quit(gp);
/*
* XXX
* Reset the O_MESG option.
*/
if (clp->tgw != TGW_UNKNOWN)
(void)cl_omesg(NULL, clp, clp->tgw == TGW_SET);
/*
* XXX
* Reset the X11 xterm icon/window name.
*/
if (F_ISSET(clp, CL_RENAME))
cl_setname(gp, clp->oname);
/* If a killer signal arrived, pretend we just got it. */
if (clp->killersig) {
(void)signal(clp->killersig, SIG_DFL);
(void)kill(getpid(), clp->killersig);
/* NOTREACHED */
}
/* Free the global and CL private areas. */
#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
cl_end(clp);
free(gp);
#endif
exit (rval);
}
/*
* cl_init --
* Create and partially initialize the CL structure.
*/
static CL_PRIVATE *
cl_init(WIN *wp)
{
CL_PRIVATE *clp;
int fd;
GS *gp;
gp = wp->gp;
/* Allocate the CL private structure. */
CALLOC_NOMSG(NULL, clp, CL_PRIVATE *, 1, sizeof(CL_PRIVATE));
if (clp == NULL)
perr(gp->progname, NULL);
gp->cl_private = clp;
/*
* Set the CL_STDIN_TTY flag. It's purpose is to avoid setting
* and resetting the tty if the input isn't from there. We also
* use the same test to determine if we're running a script or
* not.
*/
if (isatty(STDIN_FILENO))
F_SET(clp, CL_STDIN_TTY);
else
F_SET(gp, G_SCRIPTED);
/*
* We expect that if we've lost our controlling terminal that the
* open() (but not the tcgetattr()) will fail.
*/
if (F_ISSET(clp, CL_STDIN_TTY)) {
if (tcgetattr(STDIN_FILENO, &clp->orig) == -1)
goto tcfail;
} else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
if (tcgetattr(fd, &clp->orig) == -1) {
tcfail: perr(gp->progname, "tcgetattr");
exit (1);
}
(void)close(fd);
}
/* Initialize the list of curses functions. */
cl_func_std(wp);
return (clp);
}
#ifdef notused
/*
* cl_end --
* Discard the CL structure.
*/
static void
cl_end(CL_PRIVATE *clp)
{
if (clp->oname != NULL)
free(clp->oname);
free(clp);
}
#endif
/*
* term_init --
* Initialize terminal information.
*/
static void
term_init(const char *name, const char *ttype)
{
int err;
/* Set up the terminal database information. */
setupterm(__UNCONST(ttype), STDOUT_FILENO, &err);
switch (err) {
case -1:
(void)fprintf(stderr,
"%s: No terminal database found\n", name);
exit (1);
case 0:
(void)fprintf(stderr,
"%s: %s: unknown terminal type\n", name, ttype);
exit (1);
}
}
#define GLOBAL_CLP \
CL_PRIVATE *clp = GCLP(__global_list);
static void
h_hup(int signo)
{
GLOBAL_CLP;
F_SET(clp, CL_SIGHUP);
clp->killersig = SIGHUP;
}
static void
h_int(int signo)
{
GLOBAL_CLP;
F_SET(clp, CL_SIGINT);
}
static void
h_term(int signo)
{
GLOBAL_CLP;
F_SET(clp, CL_SIGTERM);
clp->killersig = SIGTERM;
}
static void
h_winch(int signo)
{
GLOBAL_CLP;
F_SET(clp, CL_SIGWINCH);
}
#undef GLOBAL_CLP
/*
* sig_init --
* Initialize signals.
*
* PUBLIC: int sig_init __P((GS *, SCR *));
*/
int
sig_init(GS *gp, SCR *sp)
{
CL_PRIVATE *clp;
clp = GCLP(gp);
if (sp == NULL) {
(void)sigemptyset(&__sigblockset);
if (sigaddset(&__sigblockset, SIGHUP) ||
setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) ||
sigaddset(&__sigblockset, SIGINT) ||
setsig(SIGINT, &clp->oact[INDX_INT], h_int) ||
sigaddset(&__sigblockset, SIGTERM) ||
setsig(SIGTERM, &clp->oact[INDX_TERM], h_term)
#ifdef SIGWINCH
||
sigaddset(&__sigblockset, SIGWINCH) ||
setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch)
#endif
) {
perr(gp->progname, NULL);
return (1);
}
} else
if (setsig(SIGHUP, NULL, h_hup) ||
setsig(SIGINT, NULL, h_int) ||
setsig(SIGTERM, NULL, h_term)
#ifdef SIGWINCH
||
setsig(SIGWINCH, NULL, h_winch)
#endif
) {
msgq(sp, M_SYSERR, "signal-reset");
}
return (0);
}
/*
* setsig --
* Set a signal handler.
*/
static int
setsig(int signo, struct sigaction *oactp, void (*handler) (int))
{
struct sigaction act;
/*
* 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. Besides, you can't portably
* restart system calls (thanks, POSIX!). On the other hand, you
* can't portably NOT restart system calls (thanks, Sun!). SunOS
* used SA_INTERRUPT as their extension to NOT restart read calls.
* We sure hope nobody else used it for anything else. Mom told me
* there'd be days like this. She just never told me that there'd
* be so many.
*/
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
#ifdef SA_INTERRUPT
act.sa_flags = SA_INTERRUPT;
#else
act.sa_flags = 0;
#endif
return (sigaction(signo, &act, oactp));
}
/*
* sig_end --
* End signal setup.
*/
static void
sig_end(GS *gp)
{
CL_PRIVATE *clp;
clp = GCLP(gp);
(void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]);
(void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]);
(void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]);
#ifdef SIGWINCH
(void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]);
#endif
}
/*
* cl_func_std --
* Initialize the standard curses functions.
*/
static void
cl_func_std(WIN *wp)
{
GS *gp;
gp = wp->gp;
gp->scr_addstr = cl_addstr;
gp->scr_waddstr = cl_waddstr;
gp->scr_attr = cl_attr;
gp->scr_baud = cl_baud;
gp->scr_bell = cl_bell;
gp->scr_busy = NULL;
gp->scr_child = NULL;
gp->scr_clrtoeol = cl_clrtoeol;
gp->scr_cursor = cl_cursor;
gp->scr_deleteln = cl_deleteln;
gp->scr_reply = NULL;
gp->scr_discard = cl_discard;
gp->scr_event = cl_event;
gp->scr_ex_adjust = cl_ex_adjust;
gp->scr_fmap = cl_fmap;
gp->scr_insertln = cl_insertln;
gp->scr_keyval = cl_keyval;
gp->scr_move = cl_move;
wp->scr_msg = NULL;
gp->scr_optchange = cl_optchange;
gp->scr_refresh = cl_refresh;
gp->scr_rename = cl_rename;
gp->scr_screen = cl_screen;
gp->scr_split = cl_split;
gp->scr_suspend = cl_suspend;
gp->scr_usage = cl_usage;
}
/*
* perr --
* Print system error.
*/
static void
perr(const char *name, const char *msg)
{
(void)fprintf(stderr, "%s:", name);
if (msg != NULL)
(void)fprintf(stderr, "%s:", msg);
(void)fprintf(stderr, "%s\n", strerror(errno));
exit(1);
}

312
dist/nvi/cl/cl_read.c vendored Normal file
View file

@ -0,0 +1,312 @@
/* $NetBSD: cl_read.c,v 1.2 2008/12/05 22:51:42 christos Exp $ */
/*-
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*/
#include "config.h"
#ifndef lint
static const char sccsid[] = "Id: cl_read.c,v 10.29 2001/08/18 21:51:59 skimo Exp (Berkeley) Date: 2001/08/18 21:51:59";
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <sys/time.h>
#include <bitstring.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "../common/common.h"
#include "../ex/script.h"
#include "cl.h"
/* Pollution by Solaris curses. */
#undef columns
#undef lines
static input_t cl_read __P((SCR *,
u_int32_t, char *, size_t, int *, struct timeval *));
static int cl_resize __P((SCR *, size_t, size_t));
/*
* cl_event --
* Return a single event.
*
* PUBLIC: int cl_event __P((SCR *, EVENT *, u_int32_t, int));
*/
int
cl_event(SCR *sp, EVENT *evp, u_int32_t flags, int ms)
{
struct timeval t, *tp;
CL_PRIVATE *clp;
size_t lines, columns;
int changed, nr = 0;
const CHAR_T *wp;
size_t wlen;
int rc;
/*
* Queue signal based events. We never clear SIGHUP or SIGTERM events,
* so that we just keep returning them until the editor dies.
*/
clp = CLP(sp);
retest: if (LF_ISSET(EC_INTERRUPT) || F_ISSET(clp, CL_SIGINT)) {
if (F_ISSET(clp, CL_SIGINT)) {
F_CLR(clp, CL_SIGINT);
evp->e_event = E_INTERRUPT;
} else
evp->e_event = E_TIMEOUT;
return (0);
}
if (F_ISSET(clp, CL_SIGHUP | CL_SIGTERM | CL_SIGWINCH)) {
if (F_ISSET(clp, CL_SIGHUP)) {
evp->e_event = E_SIGHUP;
return (0);
}
if (F_ISSET(clp, CL_SIGTERM)) {
evp->e_event = E_SIGTERM;
return (0);
}
if (F_ISSET(clp, CL_SIGWINCH)) {
F_CLR(clp, CL_SIGWINCH);
if (cl_ssize(sp, 1, &lines, &columns, &changed))
return (1);
if (changed) {
(void)cl_resize(sp, lines, columns);
evp->e_event = E_WRESIZE;
return (0);
}
/* No real change, ignore the signal. */
}
}
/* Set timer. */
if (ms == 0)
tp = NULL;
else {
t.tv_sec = ms / 1000;
t.tv_usec = (ms % 1000) * 1000;
tp = &t;
}
/* Read input characters. */
read:
switch (cl_read(sp, LF_ISSET(EC_QUOTED | EC_RAW),
clp->ibuf + clp->skip, SIZE(clp->ibuf) - clp->skip, &nr, tp)) {
case INP_OK:
rc = INPUT2INT5(sp, clp->cw, clp->ibuf, nr + clp->skip,
wp, wlen);
evp->e_csp = __UNCONST(wp);
evp->e_len = wlen;
evp->e_event = E_STRING;
if (rc < 0) {
int n = -rc;
memmove(clp->ibuf, clp->ibuf + nr + clp->skip - n, n);
clp->skip = n;
if (wlen == 0)
goto read;
} else if (rc == 0)
clp->skip = 0;
else
msgq(sp, M_ERR, "323|Invalid input. Truncated.");
break;
case INP_ERR:
evp->e_event = E_ERR;
break;
case INP_EOF:
evp->e_event = E_EOF;
break;
case INP_INTR:
goto retest;
case INP_TIMEOUT:
evp->e_event = E_TIMEOUT;
break;
default:
abort();
}
return (0);
}
/*
* cl_read --
* Read characters from the input.
*/
static input_t
cl_read(SCR *sp, u_int32_t flags, char *bp, size_t blen, int *nrp, struct timeval *tp)
{
struct termios term1, term2;
struct timeval poll;
CL_PRIVATE *clp;
GS *gp;
fd_set rdfd;
input_t rval;
int maxfd, nr, term_reset;
gp = sp->gp;
clp = CLP(sp);
term_reset = 0;
/*
* 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(clp, CL_STDIN_TTY)) {
switch (nr = read(STDIN_FILENO, bp, blen)) {
case 0:
return (INP_EOF);
case -1:
goto err;
default:
*nrp = nr;
return (INP_OK);
}
/* NOTREACHED */
}
/*
* 2: A read with an associated timeout, e.g., trying to complete
* a map sequence. If input exists, we fall into #3.
*/
FD_ZERO(&rdfd);
poll.tv_sec = 0;
poll.tv_usec = 0;
if (tp != NULL) {
FD_SET(STDIN_FILENO, &rdfd);
switch (select(STDIN_FILENO + 1,
&rdfd, NULL, NULL, tp == NULL ? &poll : tp)) {
case 0:
return (INP_TIMEOUT);
case -1:
goto err;
default:
break;
}
}
/*
* The user can enter a key in the editor to quote a character. If we
* get here and the next key is supposed to be quoted, do what we can.
* Reset the tty so that the user can enter a ^C, ^Q, ^S. There's an
* obvious race here, when the key has already been entered, but there's
* nothing that we can do to fix that problem.
*
* The editor can ask for the next literal character even thought it's
* generally running in line-at-a-time mode. Do what we can.
*/
if (LF_ISSET(EC_QUOTED | EC_RAW) && !tcgetattr(STDIN_FILENO, &term1)) {
term_reset = 1;
if (LF_ISSET(EC_QUOTED)) {
term2 = term1;
term2.c_lflag &= ~ISIG;
term2.c_iflag &= ~(IXON | IXOFF);
(void)tcsetattr(STDIN_FILENO,
TCSASOFT | TCSADRAIN, &term2);
} else
(void)tcsetattr(STDIN_FILENO,
TCSASOFT | TCSADRAIN, &clp->vi_enter);
}
/*
* 3: Wait for input.
*
* Select on the command input and scripting window file descriptors.
* It's ugly that we wait on scripting file descriptors here, but it's
* the only way to keep from locking out scripting windows.
*/
if (F_ISSET(gp, G_SCRWIN)) {
FD_ZERO(&rdfd);
FD_SET(STDIN_FILENO, &rdfd);
maxfd = STDIN_FILENO;
if (sscr_check_input(sp, &rdfd, maxfd))
goto err;
}
/*
* 4: Read the input.
*
* !!!
* What's going on here is some scary stuff. Ex runs the terminal in
* canonical mode. So, the <newline> character terminating a line of
* input is returned in the buffer, but a trailing <EOF> character is
* not similarly included. As ex uses 0<EOF> and ^<EOF> as autoindent
* commands, it has to see the trailing <EOF> characters to determine
* the difference between the user entering "0ab" and "0<EOF>ab". We
* leave an extra slot in the buffer, so that we can add a trailing
* <EOF> character if the buffer isn't terminated by a <newline>. We
* lose if the buffer is too small for the line and exactly N characters
* are entered followed by an <EOF> character.
*/
#define ONE_FOR_EOF 1
switch (nr = read(STDIN_FILENO, bp, blen - ONE_FOR_EOF)) {
case 0: /* EOF. */
/*
* ^D in canonical mode returns a read of 0, i.e. EOF. EOF is
* a valid command, but we don't want to loop forever because
* the terminal driver is returning EOF because the user has
* disconnected. The editor will almost certainly try to write
* something before this fires, which should kill us, but You
* Never Know.
*/
if (++clp->eof_count < 50) {
bp[0] = clp->orig.c_cc[VEOF];
*nrp = 1;
rval = INP_OK;
} else
rval = INP_EOF;
break;
case -1: /* Error or interrupt. */
err: if (errno == EINTR)
rval = INP_INTR;
else {
rval = INP_ERR;
msgq(sp, M_SYSERR, "input");
}
break;
default: /* Input characters. */
if (F_ISSET(sp, SC_EX) && bp[nr - 1] != '\n')
bp[nr++] = clp->orig.c_cc[VEOF];
*nrp = nr;
clp->eof_count = 0;
rval = INP_OK;
break;
}
/* Restore the terminal state if it was modified. */
if (term_reset)
(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &term1);
return (rval);
}
/*
* cl_resize --
* Reset the options for a resize event.
*/
static int
cl_resize(SCR *sp, size_t lines, size_t columns)
{
int rval;
rval = api_opts_set(sp, L("lines"), NULL, lines, 0);
if (api_opts_set(sp, L("columns"), NULL, columns, 0))
rval = 1;
return (rval);
}

580
dist/nvi/cl/cl_screen.c vendored Normal file
View file

@ -0,0 +1,580 @@
/* $NetBSD: cl_screen.c,v 1.2 2008/12/05 22:51:42 christos Exp $ */
/*-
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*/
#include "config.h"
#ifndef lint
static const char sccsid[] = "Id: cl_screen.c,v 10.56 2002/05/03 19:59:44 skimo Exp (Berkeley) Date: 2002/05/03 19:59:44";
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#include <bitstring.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "../common/common.h"
#include "cl.h"
static int cl_ex_end __P((GS *));
static int cl_ex_init __P((SCR *));
static void cl_freecap __P((CL_PRIVATE *));
static int cl_vi_end __P((GS *));
static int cl_vi_init __P((SCR *));
static int cl_putenv __P((SCR *, const char *, const char *, u_long));
/*
* cl_screen --
* Switch screen types.
*
* PUBLIC: int cl_screen __P((SCR *, u_int32_t));
*/
int
cl_screen(SCR *sp, u_int32_t flags)
{
CL_PRIVATE *clp;
WINDOW *win;
GS *gp;
gp = sp->gp;
clp = CLP(sp);
win = CLSP(sp) ? CLSP(sp) : stdscr;
/* See if the current information is incorrect. */
if (F_ISSET(gp, G_SRESTART)) {
if (CLSP(sp)) {
delwin(CLSP(sp));
sp->cl_private = NULL;
}
if (cl_quit(gp))
return (1);
F_CLR(gp, G_SRESTART);
}
/* See if we're already in the right mode. */
if ((LF_ISSET(SC_EX) && F_ISSET(sp, SC_SCR_EX)) ||
(LF_ISSET(SC_VI) && F_ISSET(sp, SC_SCR_VI)))
return (0);
/*
* Fake leaving ex mode.
*
* We don't actually exit ex or vi mode unless forced (e.g. by a window
* size change). This is because many curses implementations can't be
* called twice in a single program. Plus, it's faster. If the editor
* "leaves" vi to enter ex, when it exits ex we'll just fall back into
* vi.
*/
if (F_ISSET(sp, SC_SCR_EX))
F_CLR(sp, SC_SCR_EX);
/*
* Fake leaving vi mode.
*
* Clear out the rest of the screen if we're in the middle of a split
* screen. Move to the last line in the current screen -- this makes
* terminal scrolling happen naturally. Note: *don't* move past the
* end of the screen, as there are ex commands (e.g., :read ! cat file)
* that don't want to. Don't clear the info line, its contents may be
* valid, e.g. :file|append.
*/
if (F_ISSET(sp, SC_SCR_VI)) {
F_CLR(sp, SC_SCR_VI);
if (sp->q.cqe_next != (void *)&sp->wp->scrq) {
(void)wmove(win, RLNO(sp, sp->rows), 0);
wclrtobot(win);
}
(void)wmove(win, RLNO(sp, sp->rows) - 1, 0);
wrefresh(win);
}
/* Enter the requested mode. */
if (LF_ISSET(SC_EX)) {
if (cl_ex_init(sp))
return (1);
F_SET(clp, CL_IN_EX | CL_SCR_EX_INIT);
/*
* If doing an ex screen for ex mode, move to the last line
* on the screen.
*/
if (F_ISSET(sp, SC_EX) && clp->cup != NULL)
tputs(tgoto(clp->cup,
0, O_VAL(sp, O_LINES) - 1), 1, cl_putchar);
} else {
if (cl_vi_init(sp))
return (1);
F_CLR(clp, CL_IN_EX);
F_SET(clp, CL_SCR_VI_INIT);
}
return (0);
}
/*
* cl_quit --
* Shutdown the screens.
*
* PUBLIC: int cl_quit __P((GS *));
*/
int
cl_quit(GS *gp)
{
CL_PRIVATE *clp;
int rval;
rval = 0;
clp = GCLP(gp);
/*
* If we weren't really running, ignore it. This happens if the
* screen changes size before we've called curses.
*/
if (!F_ISSET(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT))
return (0);
/* Clean up the terminal mappings. */
if (cl_term_end(gp))
rval = 1;
/* Really leave vi mode. */
if (F_ISSET(clp, CL_STDIN_TTY) &&
F_ISSET(clp, CL_SCR_VI_INIT) && cl_vi_end(gp))
rval = 1;
/* Really leave ex mode. */
if (F_ISSET(clp, CL_STDIN_TTY) &&
F_ISSET(clp, CL_SCR_EX_INIT) && cl_ex_end(gp))
rval = 1;
/*
* If we were running ex when we quit, or we're using an implementation
* of curses where endwin() doesn't get this right, restore the original
* terminal modes.
*
* XXX
* We always do this because it's too hard to figure out what curses
* implementations get it wrong. It may discard type-ahead characters
* from the tty queue.
*/
(void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig);
F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
return (rval);
}
/*
* cl_vi_init --
* Initialize the curses vi screen.
*/
static int
cl_vi_init(SCR *sp)
{
CL_PRIVATE *clp;
GS *gp;
char *o_cols, *o_lines, *o_term;
const char *ttype;
gp = sp->gp;
clp = CLP(sp);
/* If already initialized, just set the terminal modes. */
if (F_ISSET(clp, CL_SCR_VI_INIT))
goto fast;
/* Curses vi always reads from (and writes to) a terminal. */
if (!F_ISSET(clp, CL_STDIN_TTY) || !isatty(STDOUT_FILENO)) {
msgq(sp, M_ERR,
"016|Vi's standard input and output must be a terminal");
return (1);
}
/* We'll need a terminal type. */
if (opts_empty(sp, O_TERM, 0))
return (1);
ttype = O_STR(sp, O_TERM);
/*
* XXX
* Changing the row/column and terminal values is done by putting them
* into the environment, which is then read by curses. What this loses
* in ugliness, it makes up for in stupidity. We can't simply put the
* values into the environment ourselves, because in the presence of a
* kernel mechanism for returning the window size, entering values into
* the environment will screw up future screen resizing events, e.g. if
* the user enters a :shell command and then resizes their window. So,
* if they weren't already in the environment, we make sure to delete
* them immediately after setting them.
*
* XXX
* Putting the TERM variable into the environment is necessary, even
* though we're using newterm() here. We may be using initscr() as
* the underlying function.
*/
o_term = getenv("TERM");
cl_putenv(sp, "TERM", ttype, 0);
o_lines = getenv("LINES");
cl_putenv(sp, "LINES", NULL, (u_long)O_VAL(sp, O_LINES));
o_cols = getenv("COLUMNS");
cl_putenv(sp, "COLUMNS", NULL, (u_long)O_VAL(sp, O_COLUMNS));
/*
* We don't care about the SCREEN reference returned by newterm, we
* never have more than one SCREEN at a time.
*
* XXX
* The SunOS initscr() can't be called twice. Don't even think about
* using it. It fails in subtle ways (e.g. select(2) on fileno(stdin)
* stops working). (The SVID notes that applications should only call
* initscr() once.)
*
* XXX
* The HP/UX newterm doesn't support the NULL first argument, so we
* have to specify the terminal type.
*/
errno = 0;
if (newterm(__UNCONST(ttype), stdout, stdin) == NULL) {
if (errno)
msgq(sp, M_SYSERR, "%s", ttype);
else
msgq(sp, M_ERR, "%s: unknown terminal type", ttype);
return (1);
}
if (o_term == NULL)
cl_unsetenv(sp, "TERM");
if (o_lines == NULL)
cl_unsetenv(sp, "LINES");
if (o_cols == NULL)
cl_unsetenv(sp, "COLUMNS");
/*
* XXX
* Someone got let out alone without adult supervision -- the SunOS
* newterm resets the signal handlers. There's a race, but it's not
* worth closing.
*/
(void)sig_init(sp->gp, sp);
/*
* 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 flags like DISCARD and LNEXT.
*
* !!!
* If raw isn't turning off echo and newlines, something's wrong.
* However, it shouldn't hurt.
*/
noecho(); /* No character echo. */
nonl(); /* No CR/NL translation. */
raw(); /* 8-bit clean. */
idlok(stdscr, 1); /* Use hardware insert/delete line. */
/* Put the cursor keys into application mode. */
(void)keypad(stdscr, TRUE);
/*
* XXX
* The screen TI sequence just got sent. See the comment in
* cl_funcs.c:cl_attr().
*/
clp->ti_te = TI_SENT;
/*
* 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 force
* it to SIG_DFL after initializing the curses interface, which means
* that curses isn't going to take the signal. Since curses isn't
* reentrant (i.e., the whole curses SIGTSTP interface is a fantasy),
* we're doing The Right Thing.
*/
(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. The main curses code
* 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 originally.
* If they didn't, it's unclear what we're supposed to do here, but
* it's also pretty unlikely.
*/
if (tcgetattr(STDIN_FILENO, &clp->vi_enter)) {
msgq(sp, M_SYSERR, "tcgetattr");
goto err;
}
if (clp->orig.c_iflag & IXON)
clp->vi_enter.c_iflag |= IXON;
if (clp->orig.c_iflag & IXOFF)
clp->vi_enter.c_iflag |= IXOFF;
clp->vi_enter.c_lflag |= ISIG;
#ifdef VDSUSP
clp->vi_enter.c_cc[VDSUSP] = _POSIX_VDISABLE;
#endif
clp->vi_enter.c_cc[VQUIT] = _POSIX_VDISABLE;
clp->vi_enter.c_cc[VSUSP] = _POSIX_VDISABLE;
/*
* XXX
* OSF/1 doesn't turn off the <discard>, <literal-next> or <status>
* characters when curses switches into raw mode. It should be OK
* to do it explicitly for everyone.
*/
#ifdef VDISCARD
clp->vi_enter.c_cc[VDISCARD] = _POSIX_VDISABLE;
#endif
#ifdef VLNEXT
clp->vi_enter.c_cc[VLNEXT] = _POSIX_VDISABLE;
#endif
#ifdef VSTATUS
clp->vi_enter.c_cc[VSTATUS] = _POSIX_VDISABLE;
#endif
/* Initialize terminal based information. */
if (cl_term_init(sp))
goto err;
fast: /* Set the terminal modes. */
if (tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &clp->vi_enter)) {
if (errno == EINTR)
goto fast;
msgq(sp, M_SYSERR, "tcsetattr");
err: (void)cl_vi_end(sp->gp);
return (1);
}
return (0);
}
/*
* cl_vi_end --
* Shutdown the vi screen.
*/
static int
cl_vi_end(GS *gp)
{
CL_PRIVATE *clp;
clp = GCLP(gp);
/* Restore the cursor keys to normal mode. */
(void)keypad(stdscr, FALSE);
/*
* If we were running vi when we quit, scroll the screen up a single
* line so we don't lose any information.
*
* Move to the bottom of the window (some endwin implementations don't
* do this for you).
*/
if (!F_ISSET(clp, CL_IN_EX)) {
(void)move(0, 0);
(void)deleteln();
(void)move(LINES - 1, 0);
(void)refresh();
}
cl_freecap(clp);
/* End curses window. */
(void)endwin();
/*
* XXX
* The screen TE sequence just got sent. See the comment in
* cl_funcs.c:cl_attr().
*/
clp->ti_te = TE_SENT;
return (0);
}
/*
* cl_ex_init --
* Initialize the ex screen.
*/
static int
cl_ex_init(SCR *sp)
{
CL_PRIVATE *clp;
clp = CLP(sp);
/* If already initialized, just set the terminal modes. */
if (F_ISSET(clp, CL_SCR_EX_INIT))
goto fast;
/* If not reading from a file, we're done. */
if (!F_ISSET(clp, CL_STDIN_TTY))
return (0);
/* Get the ex termcap/terminfo strings. */
(void)cl_getcap(sp, "cup", &clp->cup);
(void)cl_getcap(sp, "smso", &clp->smso);
(void)cl_getcap(sp, "rmso", &clp->rmso);
(void)cl_getcap(sp, "el", &clp->el);
(void)cl_getcap(sp, "cuu1", &clp->cuu1);
/* Enter_standout_mode and exit_standout_mode are paired. */
if (clp->smso == NULL || clp->rmso == NULL) {
if (clp->smso != NULL) {
free(clp->smso);
clp->smso = NULL;
}
if (clp->rmso != NULL) {
free(clp->rmso);
clp->rmso = NULL;
}
}
/*
* Turn on canonical mode, with normal input and output processing.
* Start with the original terminal settings as the user probably
* had them (including any local extensions) set correctly for the
* current terminal.
*
* !!!
* We can't get everything that we need portably; for example, ONLCR,
* mapping <newline> to <carriage-return> on output isn't required
* by POSIX 1003.1b-1993. If this turns out to be a problem, then
* we'll either have to play some games on the mapping, or we'll have
* to make all ex printf's output \r\n instead of \n.
*/
clp->ex_enter = clp->orig;
clp->ex_enter.c_lflag |= ECHO | ECHOE | ECHOK | ICANON | IEXTEN | ISIG;
#ifdef ECHOCTL
clp->ex_enter.c_lflag |= ECHOCTL;
#endif
#ifdef ECHOKE
clp->ex_enter.c_lflag |= ECHOKE;
#endif
clp->ex_enter.c_iflag |= ICRNL;
clp->ex_enter.c_oflag |= OPOST;
#ifdef ONLCR
clp->ex_enter.c_oflag |= ONLCR;
#endif
fast: if (tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->ex_enter)) {
if (errno == EINTR)
goto fast;
msgq(sp, M_SYSERR, "tcsetattr");
return (1);
}
return (0);
}
/*
* cl_ex_end --
* Shutdown the ex screen.
*/
static int
cl_ex_end(GS *gp)
{
CL_PRIVATE *clp;
clp = GCLP(gp);
cl_freecap(clp);
return (0);
}
/*
* cl_getcap --
* Retrieve termcap/terminfo strings.
*
* PUBLIC: int cl_getcap __P((SCR *, char *, char **));
*/
int
cl_getcap(SCR *sp, const char *name, char **elementp)
{
size_t len;
char *t;
if ((t = tigetstr(name)) != NULL &&
t != (char *)-1 && (len = strlen(t)) != 0) {
MALLOC_RET(sp, *elementp, char *, len + 1);
memmove(*elementp, t, len + 1);
}
return (0);
}
/*
* cl_freecap --
* Free any allocated termcap/terminfo strings.
*/
static void
cl_freecap(CL_PRIVATE *clp)
{
if (clp->el != NULL) {
free(clp->el);
clp->el = NULL;
}
if (clp->cup != NULL) {
free(clp->cup);
clp->cup = NULL;
}
if (clp->cuu1 != NULL) {
free(clp->cuu1);
clp->cuu1 = NULL;
}
if (clp->rmso != NULL) {
free(clp->rmso);
clp->rmso = NULL;
}
if (clp->smso != NULL) {
free(clp->smso);
clp->smso = NULL;
}
}
/*
* cl_putenv --
* Put a value into the environment.
*/
static int
cl_putenv(SCR *sp, const char *name, const char *str, u_long value)
{
char buf[40];
if (str == NULL) {
(void)snprintf(buf, sizeof(buf), "%lu", value);
return (cl_setenv(sp, name, buf));
} else
return (cl_setenv(sp, name, str));
}

481
dist/nvi/cl/cl_term.c vendored Normal file
View file

@ -0,0 +1,481 @@
/* $NetBSD: cl_term.c,v 1.4 2011/11/23 19:25:27 tnozaki Exp $ */
/*-
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*/
#include "config.h"
#ifndef lint
static const char sccsid[] = "Id: cl_term.c,v 10.31 2001/07/08 13:06:56 skimo Exp (Berkeley) Date: 2001/07/08 13:06:56";
#endif /* not lint */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
#include <sys/stat.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 "../common/common.h"
#include "cl.h"
static int cl_pfmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
/*
* XXX
* THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE.
*/
typedef struct _tklist {
const char *ts; /* Key's termcap string. */
const char *output; /* Corresponding vi command. */
const char *name; /* Name. */
u_char value; /* Special value (for lookup). */
} TKLIST;
#define TKINIT(a, b, c) { a, b, c, 0 }
static TKLIST const c_tklist[] = { /* Command mappings. */
TKINIT("kil1", "O", "insert line"),
TKINIT("kdch1", "x", "delete character"),
TKINIT("kcud1", "j", "cursor down"),
TKINIT("kel", "D", "delete to eol"),
TKINIT("kind", "\004", "scroll down"), /* ^D */
TKINIT("kll", "$", "go to eol"),
TKINIT("kend", "$", "go to eol"),
TKINIT("khome", "^", "go to sol"),
TKINIT("kich1", "i", "insert at cursor"),
TKINIT("kdl1", "dd", "delete line"),
TKINIT("kcub1", "h", "cursor left"),
TKINIT("knp", "\006", "page down"), /* ^F */
TKINIT("kpp", "\002", "page up"), /* ^B */
TKINIT("kri", "\025", "scroll up"), /* ^U */
TKINIT("ked", "dG", "delete to end of screen"),
TKINIT("kcuf1", "l", "cursor right"),
TKINIT("kcuu1", "k", "cursor up"),
TKINIT(NULL, NULL, NULL),
};
static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */
TKINIT(NULL, NULL, NULL),
};
static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */
TKINIT("kcud1", "\033ja", "cursor down"), /* ^[ja */
TKINIT("kcub1", "\033ha", "cursor left"), /* ^[ha */
TKINIT("kcuu1", "\033ka", "cursor up"), /* ^[ka */
TKINIT("kcuf1", "\033la", "cursor right"), /* ^[la */
TKINIT(NULL, NULL, NULL),
};
/*
* cl_term_init --
* Initialize the special keys defined by the termcap/terminfo entry.
*
* PUBLIC: int cl_term_init __P((SCR *));
*/
int
cl_term_init(SCR *sp)
{
KEYLIST *kp;
SEQ *qp;
TKLIST const *tkp;
char *t;
CHAR_T name[60];
CHAR_T output[5];
CHAR_T ts[20];
const CHAR_T *wp;
size_t wlen;
/* Command mappings. */
for (tkp = c_tklist; tkp->name != NULL; ++tkp) {
if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
continue;
CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
MEMCPYW(name, wp, wlen);
CHAR2INT(sp, t, strlen(t), wp, wlen);
MEMCPYW(ts, wp, wlen);
CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen);
MEMCPYW(output, wp, wlen);
if (seq_set(sp, name, strlen(tkp->name), ts, strlen(t),
output, strlen(tkp->output), SEQ_COMMAND,
SEQ_NOOVERWRITE | SEQ_SCREEN))
return (1);
}
/* Input mappings needing to be looked up. */
for (tkp = m1_tklist; tkp->name != NULL; ++tkp) {
if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
continue;
for (kp = keylist;; ++kp)
if (kp->value == tkp->value)
break;
if (kp == NULL)
continue;
CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
MEMCPYW(name, wp, wlen);
CHAR2INT(sp, t, strlen(t), wp, wlen);
MEMCPYW(ts, wp, wlen);
output[0] = (UCHAR_T)kp->ch;
if (seq_set(sp, name, strlen(tkp->name), ts, strlen(t),
output, 1, SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
return (1);
}
/* Input mappings that are already set or are text deletions. */
for (tkp = m2_tklist; tkp->name != NULL; ++tkp) {
if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
continue;
/*
* !!!
* 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) {
CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
MEMCPYW(name, wp, wlen);
CHAR2INT(sp, t, strlen(t), wp, wlen);
MEMCPYW(ts, wp, wlen);
if (seq_set(sp, name, strlen(tkp->name),
ts, strlen(t), NULL, 0,
SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
return (1);
} else {
CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
MEMCPYW(name, wp, wlen);
CHAR2INT(sp, t, strlen(t), wp, wlen);
MEMCPYW(ts, wp, wlen);
CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen);
MEMCPYW(output, wp, wlen);
if (seq_set(sp, name, strlen(tkp->name),
ts, strlen(t), output, strlen(tkp->output),
SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
return (1);
}
}
/*
* Rework any function key mappings that were set before the
* screen was initialized.
*/
for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next)
if (F_ISSET(qp, SEQ_FUNCMAP))
(void)cl_pfmap(sp, qp->stype,
qp->input, qp->ilen, qp->output, qp->olen);
return (0);
}
/*
* cl_term_end --
* End the special keys defined by the termcap/terminfo entry.
*
* PUBLIC: int cl_term_end __P((GS *));
*/
int
cl_term_end(GS *gp)
{
SEQ *qp, *nqp;
/* Delete screen specific mappings. */
for (qp = gp->seqq.lh_first; qp != NULL; qp = nqp) {
nqp = qp->q.le_next;
if (F_ISSET(qp, SEQ_SCREEN))
(void)seq_mdel(qp);
}
return (0);
}
/*
* cl_fmap --
* Map a function key.
*
* PUBLIC: int cl_fmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
*/
int
cl_fmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen)
{
/* Ignore until the screen is running, do the real work then. */
if (F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_SCR_VI))
return (0);
if (F_ISSET(sp, SC_EX) && !F_ISSET(sp, SC_SCR_EX))
return (0);
return (cl_pfmap(sp, stype, from, flen, to, tlen));
}
/*
* cl_pfmap --
* Map a function key (private version).
*/
static int
cl_pfmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen)
{
size_t nlen;
char *p;
char name[64];
CHAR_T mykeyname[64];
CHAR_T ts[20];
const CHAR_T *wp;
size_t wlen;
(void)snprintf(name, sizeof(name), "kf%d",
(int)STRTOL(from+1,NULL,10));
if ((p = tigetstr(name)) == NULL ||
p == (char *)-1 || strlen(p) == 0)
p = NULL;
if (p == NULL) {
msgq_wstr(sp, M_ERR, from, "233|This terminal has no %s key");
return (1);
}
nlen = SPRINTF(mykeyname,
SIZE(mykeyname), L("function key %d"),
(int)STRTOL(from+1,NULL,10));
CHAR2INT(sp, p, strlen(p), wp, wlen);
MEMCPYW(ts, wp, wlen);
return (seq_set(sp, mykeyname, nlen,
ts, strlen(p), to, tlen, stype, SEQ_NOOVERWRITE | SEQ_SCREEN));
}
/*
* cl_optchange --
* Curses screen specific "option changed" routine.
*
* PUBLIC: int cl_optchange __P((SCR *, int, const char *, u_long *));
*/
int
cl_optchange(SCR *sp, int opt, const char *str, u_long *valp)
{
CL_PRIVATE *clp;
clp = CLP(sp);
switch (opt) {
case O_COLUMNS:
case O_LINES:
case O_TERM:
/*
* Changing the columns, lines or terminal require that
* we restart the screen.
*/
F_SET(sp->gp, G_SRESTART);
F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
break;
case O_MESG:
(void)cl_omesg(sp, clp, *valp);
break;
case O_WINDOWNAME:
if (*valp) {
F_SET(clp, CL_RENAME_OK);
/*
* If the screen is live, i.e. we're not reading the
* .exrc file, update the window.
*/
if (sp->frp != NULL && sp->frp->name != NULL)
(void)cl_rename(sp, sp->frp->name, 1);
} else {
F_CLR(clp, CL_RENAME_OK);
(void)cl_rename(sp, NULL, 0);
}
break;
}
return (0);
}
/*
* cl_omesg --
* Turn the tty write permission on or off.
*
* PUBLIC: int cl_omesg __P((SCR *, CL_PRIVATE *, int));
*/
int
cl_omesg(SCR *sp, CL_PRIVATE *clp, int on)
{
struct stat sb;
char *tty;
/* Find the tty, get the current permissions. */
if ((tty = ttyname(STDERR_FILENO)) == NULL) {
if (sp != NULL)
msgq(sp, M_SYSERR, "stderr");
return (1);
}
if (stat(tty, &sb) < 0) {
if (sp != NULL)
msgq(sp, M_SYSERR, "%s", tty);
return (1);
}
/* Save the original status if it's unknown. */
if (clp->tgw == TGW_UNKNOWN)
clp->tgw = sb.st_mode & S_IWGRP ? TGW_SET : TGW_UNSET;
/* Toggle the permissions. */
if (on) {
if (chmod(tty, sb.st_mode | S_IWGRP) < 0) {
if (sp != NULL)
msgq(sp, M_SYSERR,
"046|messages not turned on: %s", tty);
return (1);
}
} else
if (chmod(tty, sb.st_mode & ~S_IWGRP) < 0) {
if (sp != NULL)
msgq(sp, M_SYSERR,
"045|messages not turned off: %s", tty);
return (1);
}
return (0);
}
/*
* cl_ssize --
* Return the terminal size.
*
* PUBLIC: int cl_ssize __P((SCR *, int, size_t *, size_t *, int *));
*/
int
cl_ssize(SCR *sp, int sigwinch, size_t *rowp, size_t *colp, int *changedp)
{
#ifdef TIOCGWINSZ
struct winsize win;
#endif
size_t col, row;
int rval;
char *p;
/* Assume it's changed. */
if (changedp != NULL)
*changedp = 1;
/*
* !!!
* sp may be NULL.
*
* 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 suspend or a signal, only trust TIOCGWINSZ. */
if (sigwinch) {
/*
* Somebody didn't get TIOCGWINSZ right, or has suspend
* without window resizing support. The user just lost,
* but there's nothing we can do.
*/
if (row == 0 || col == 0) {
if (changedp != NULL)
*changedp = 0;
return (0);
}
/*
* 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 (sp != NULL &&
row == O_VAL(sp, O_LINES) && col == O_VAL(sp, O_COLUMNS)) {
if (changedp != NULL)
*changedp = 0;
return (0);
}
if (rowp != NULL)
*rowp = row;
if (colp != NULL)
*colp = col;
resizeterm(row, col);
return (0);
}
/*
* !!!
* 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 ((p = getenv("TERM")) == NULL)
goto noterm;
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;
}
}
/* 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 everything.
* Often, people can get nvi to stop messing up their screen by
* deleting the LINES and COLUMNS environment variables from their
* dot-files.
*/
if ((p = getenv("LINES")) != NULL)
row = strtol(p, NULL, 10);
if ((p = getenv("COLUMNS")) != NULL)
col = strtol(p, NULL, 10);
if (rowp != NULL)
*rowp = row;
if (colp != NULL)
*colp = col;
return (0);
}
/*
* cl_putchar --
* Function version of putchar, for tputs.
*
* PUBLIC: int cl_putchar __P((int));
*/
int
cl_putchar(int ch)
{
return (putchar(ch));
}

59
dist/nvi/cl/extern.h vendored Normal file
View file

@ -0,0 +1,59 @@
/* $NetBSD: extern.h,v 1.3 2010/02/03 15:34:37 roy Exp $ */
/* Do not edit: automatically built by build/distrib. */
#ifndef HAVE_CURSES_WADDNSTR
int waddnstr __P((WINDOW*, char *, int));
#endif
#ifndef HAVE_CURSES_BEEP
void beep __P((void));
#endif
#ifndef HAVE_CURSES_FLASH
void flash __P((void));
#endif
#ifndef HAVE_CURSES_IDLOK
void idlok __P((WINDOW *, int));
#endif
#ifndef HAVE_CURSES_KEYPAD
int keypad __P((void *, int));
#endif
#ifndef HAVE_CURSES_NEWTERM
void *newterm __P((const char *, FILE *, FILE *));
#endif
#ifndef HAVE_CURSES_SETUPTERM
void setupterm __P((char *, int, int *));
#endif
#ifndef HAVE_CURSES_TIGETSTR
char *tigetstr __P((const char *));
int tigetnum __P((const char *));
#endif
int cl_waddstr __P((SCR *, const CHAR_T *, size_t));
int cl_addstr __P((SCR *, const char *, size_t));
int cl_attr __P((SCR *, scr_attr_t, int));
int cl_baud __P((SCR *, u_long *));
int cl_bell __P((SCR *));
int cl_clrtoeol __P((SCR *));
int cl_cursor __P((SCR *, size_t *, size_t *));
int cl_deleteln __P((SCR *));
int cl_discard __P((SCR *, SCR **));
int cl_ex_adjust __P((SCR *, exadj_t));
int cl_insertln __P((SCR *));
int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
int cl_move __P((SCR *, size_t, size_t));
int cl_refresh __P((SCR *, int));
int cl_rename __P((SCR *, char *, int));
void cl_setname __P((GS *, char *));
int cl_split __P((SCR *, SCR *));
int cl_suspend __P((SCR *, int *));
void cl_usage __P((void));
int sig_init __P((GS *, SCR *));
int cl_event __P((SCR *, EVENT *, u_int32_t, int));
int cl_screen __P((SCR *, u_int32_t));
int cl_quit __P((GS *));
int cl_getcap __P((SCR *, const char *, char **));
int cl_term_init __P((SCR *));
int cl_term_end __P((GS *));
int cl_fmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
int cl_optchange __P((SCR *, int, const char *, u_long *));
int cl_omesg __P((SCR *, CL_PRIVATE *, int));
int cl_ssize __P((SCR *, int, size_t *, size_t *, int *));
int cl_putchar __P((int));

87
dist/nvi/clib/bsearch.c vendored Normal file
View file

@ -0,0 +1,87 @@
/* $NetBSD: bsearch.c,v 1.1.1.2 2008/05/18 14:29:38 aymeric Exp $ */
/*
* Copyright (c) 1990, 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.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)bsearch.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <stddef.h>
#include <stdlib.h>
#include "port.h"
/*
* Perform a binary search.
*
* The code below is a bit sneaky. After a comparison fails, we
* divide the work in half by moving either left or right. If lim
* is odd, moving left simply involves halving lim: e.g., when lim
* is 5 we look at item 2, so we change lim to 2 so that we will
* look at items 0 & 1. If lim is even, the same applies. If lim
* is odd, moving right again involes halving lim, this time moving
* the base up one item past p: e.g., when lim is 5 we change base
* to item 3 and make lim 2 so that we will look at items 3 and 4.
* If lim is even, however, we have to shrink it by one before
* halving: e.g., when lim is 4, we still looked at item 2, so we
* have to make lim 3, then halve, obtaining 1, so that we will only
* look at item 3.
*
* PUBLIC: #ifndef HAVE_BSEARCH
* PUBLIC: void *bsearch __P((const void *, const void *, size_t,
* PUBLIC: size_t, int (*)(const void *, const void *)));
* PUBLIC: #endif
*/
void *
bsearch(register const void *key, const void *base0, size_t nmemb, register size_t size, register int (*compar) (const void *, const void *))
{
register const char *base = base0;
register size_t lim;
register int cmp;
register const void *p;
for (lim = nmemb; lim != 0; lim >>= 1) {
p = base + (lim >> 1) * size;
cmp = (*compar)(key, p);
if (cmp == 0)
return ((void *)p);
if (cmp > 0) { /* key > p: move right */
base = (char *)p + size;
lim--;
} /* else move left */
}
return (NULL);
}

160
dist/nvi/clib/env.c vendored Normal file
View file

@ -0,0 +1,160 @@
/* $NetBSD: env.c,v 1.1.1.2 2008/05/18 14:29:38 aymeric Exp $ */
/*
* Copyright (c) 1987, 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.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)getenv.c 8.1 (Berkeley) 6/4/93";
static const char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <stdlib.h>
#include <string.h>
/*
* __findenv --
* Returns pointer to value associated with name, if any, else NULL.
* Sets offset to be the offset of the name/value combination in the
* environmental array, for use by setenv(3) and unsetenv(3).
* Explicitly removes '=' in argument name.
*
* This routine *should* be a static; don't use it.
*/
static char *
__findenv(register char *name, int *offset)
{
extern char **environ;
register int len;
register char *np;
register char **p, *c;
if (name == NULL || environ == NULL)
return (NULL);
for (np = name; *np && *np != '='; ++np)
continue;
len = np - name;
for (p = environ; (c = *p) != NULL; ++p)
if (strncmp(c, name, len) == 0 && c[len] == '=') {
*offset = p - environ;
return (c + len + 1);
}
return (NULL);
}
#ifndef HAVE_SETENV
/*
* setenv --
* Set the value of the environmental variable "name" to be
* "value". If rewrite is set, replace any current value.
*
* PUBLIC: #ifndef HAVE_SETENV
* PUBLIC: int setenv __P((const char *, const char *, int));
* PUBLIC: #endif
*/
setenv(name, value, rewrite)
register char *name;
register char *value;
int rewrite;
{
extern char **environ;
static int alloced; /* if allocated space before */
register char *c;
int l_value, offset;
if (*value == '=') /* no `=' in value */
++value;
l_value = strlen(value);
if ((c = __findenv(name, &offset))) { /* find if already exists */
if (!rewrite)
return (0);
if (strlen(c) >= l_value) { /* old larger; copy over */
while (*c++ = *value++);
return (0);
}
} else { /* create new slot */
register int cnt;
register char **p;
for (p = environ, cnt = 0; *p; ++p, ++cnt);
if (alloced) { /* just increase size */
environ = (char **)realloc((char *)environ,
(size_t)(sizeof(char *) * (cnt + 2)));
if (!environ)
return (-1);
}
else { /* get new space */
alloced = 1; /* copy old entries into it */
p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
if (!p)
return (-1);
memmove(p, environ, cnt * sizeof(char *));
environ = p;
}
environ[cnt + 1] = NULL;
offset = cnt;
}
for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
if (!(environ[offset] = /* name + `=' + value */
malloc((size_t)((int)(c - name) + l_value + 2))))
return (-1);
for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
for (*c++ = '='; *c++ = *value++;);
return (0);
}
#endif
#ifndef HAVE_UNSETENV
/*
* unsetenv(name) --
* Delete environmental variable "name".
*
* PUBLIC: #ifndef HAVE_UNSETENV
* PUBLIC: void unsetenv __P((const char *));
* PUBLIC: #endif
*/
void
unsetenv(name)
char *name;
{
extern char **environ;
register char **p;
int offset;
while (__findenv(name, &offset)) /* if set multiple times */
for (p = &environ[offset];; ++p)
if (!(*p = *(p + 1)))
break;
}
#endif

24
dist/nvi/clib/gethostname.c vendored Normal file
View file

@ -0,0 +1,24 @@
/* $NetBSD: gethostname.c,v 1.1.1.2 2008/05/18 14:29:38 aymeric Exp $ */
#include "config.h"
/*
* Solaris doesn't include the gethostname call by default.
*/
#include <sys/utsname.h>
#include <sys/systeminfo.h>
#include <netdb.h>
/*
* PUBLIC: #ifndef HAVE_GETHOSTNAME
* PUBLIC: int gethostname __P((char *, int));
* PUBLIC: #endif
*/
int
gethostname(host, len)
char *host;
int len;
{
return (sysinfo(SI_HOSTNAME, host, len) == -1 ? -1 : 0);
}

16
dist/nvi/clib/iswblank.c vendored Normal file
View file

@ -0,0 +1,16 @@
/* $NetBSD: iswblank.c,v 1.1.1.2 2008/05/18 14:29:38 aymeric Exp $ */
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "Id: iswblank.c,v 1.1 2001/10/11 19:22:29 skimo Exp";
#endif /* LIBC_SCCS and not lint */
#include <wchar.h>
#include <wctype.h>
int
iswblank (wint_t wc)
{
return iswctype(wc, wctype("blank"));
}

64
dist/nvi/clib/memchr.c vendored Normal file
View file

@ -0,0 +1,64 @@
/* $NetBSD: memchr.c,v 1.1.1.2 2008/05/18 14:29:38 aymeric Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)memchr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <string.h>
/*
* PUBLIC: #ifndef HAVE_MEMCHR
* PUBLIC: void *memchr __P((const void *, int, size_t));
* PUBLIC: #endif
*/
void *
memchr(const void *s, register unsigned char c, register size_t n)
{
if (n != 0) {
register const unsigned char *p = s;
do {
if (*p++ == c)
return ((void *)(p - 1));
} while (--n != 0);
}
return (NULL);
}

139
dist/nvi/clib/memset.c vendored Normal file
View file

@ -0,0 +1,139 @@
/* $NetBSD: memset.c,v 1.1.1.2 2008/05/18 14:29:38 aymeric Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Hibler and Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)memset.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <limits.h>
#include <string.h>
/*
* PUBLIC: #ifndef HAVE_MEMSET
* PUBLIC: void *memset __P((void *, int, size_t));
* PUBLIC: #endif
*/
#define wsize sizeof(u_int)
#define wmask (wsize - 1)
#ifdef BZERO
#define RETURN return
#define VAL 0
#define WIDEVAL 0
void
bzero(dst0, length)
void *dst0;
register size_t length;
#else
#define RETURN return (dst0)
#define VAL c0
#define WIDEVAL c
void *
memset(void *dst0, register int c0, register size_t length)
#endif
{
register size_t t;
register u_int c;
register u_char *dst;
dst = dst0;
/*
* If not enough words, just fill bytes. A length >= 2 words
* guarantees that at least one of them is `complete' after
* any necessary alignment. For instance:
*
* |-----------|-----------|-----------|
* |00|01|02|03|04|05|06|07|08|09|0A|00|
* ^---------------------^
* dst dst+length-1
*
* but we use a minimum of 3 here since the overhead of the code
* to do word writes is substantial.
*/
if (length < 3 * wsize) {
while (length != 0) {
*dst++ = VAL;
--length;
}
RETURN;
}
#ifndef BZERO
if ((c = (u_char)c0) != 0) { /* Fill the word. */
c = (c << 8) | c; /* u_int is 16 bits. */
#if UINT_MAX > 0xffff
c = (c << 16) | c; /* u_int is 32 bits. */
#endif
#if UINT_MAX > 0xffffffff
c = (c << 32) | c; /* u_int is 64 bits. */
#endif
}
#endif
/* Align destination by filling in bytes. */
if ((t = (int)dst & wmask) != 0) {
t = wsize - t;
length -= t;
do {
*dst++ = VAL;
} while (--t != 0);
}
/* Fill words. Length was >= 2*words so we know t >= 1 here. */
t = length / wsize;
do {
*(u_int *)dst = WIDEVAL;
dst += wsize;
} while (--t != 0);
/* Mop up trailing bytes, if any. */
t = length & wmask;
if (t != 0)
do {
*dst++ = VAL;
} while (--t != 0);
RETURN;
}

131
dist/nvi/clib/mkstemp.c vendored Normal file
View file

@ -0,0 +1,131 @@
/* $NetBSD: mkstemp.c,v 1.2 2011/03/21 14:53:02 tnozaki Exp $ */
/*
* Copyright (c) 1987, 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.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
static int _gettemp(char *path, register int *doopen);
/*
* PUBLIC: #ifndef HAVE_MKSTEMP
* PUBLIC: int mkstemp __P((char *));
* PUBLIC: #endif
*/
mkstemp(char *path)
{
int fd;
return (_gettemp(path, &fd) ? fd : -1);
}
char *
mktemp(char *path)
{
return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
}
static
_gettemp(char *path, register int *doopen)
{
extern int errno;
register char *start, *trv;
struct stat sbuf;
u_int pid;
pid = getpid();
for (trv = path; *trv; ++trv); /* extra X's get set to 0's */
while (*--trv == 'X') {
*trv = (pid % 10) + '0';
pid /= 10;
}
/*
* check the target directory; if you have six X's and it
* doesn't exist this runs for a *very* long time.
*/
for (start = trv + 1;; --trv) {
if (trv <= path)
break;
if (*trv == '/') {
*trv = '\0';
if (stat(path, &sbuf))
return(0);
if (!S_ISDIR(sbuf.st_mode)) {
errno = ENOTDIR;
return(0);
}
*trv = '/';
break;
}
}
for (;;) {
if (doopen) {
if ((*doopen =
open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
return(1);
if (errno != EEXIST)
return(0);
}
else if (stat(path, &sbuf))
return(errno == ENOENT ? 1 : 0);
/* tricky little algorithm for backward compatibility */
for (trv = start;;) {
if (!*trv)
return(0);
if (*trv == 'z')
*trv++ = 'a';
else {
if (isdigit((unsigned char)*trv))
*trv = 'a';
else
++*trv;
break;
}
}
}
/*NOTREACHED*/
}

46
dist/nvi/clib/mmap.c vendored Normal file
View file

@ -0,0 +1,46 @@
/* $NetBSD: mmap.c,v 1.1.1.2 2008/05/18 14:29:38 aymeric Exp $ */
#include "config.h"
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
/*
* This function fakes mmap() by reading `len' bytes from the file descriptor
* `fd' and returning a pointer to that memory. The "mapped" region can later
* be deallocated with munmap().
*
* Note: ONLY reading is supported and only reading of the exact size of the
* file will work.
*
* PUBLIC: #ifndef HAVE_MMAP
* PUBLIC: char *mmap __P((char *, size_t, int, int, int, off_t));
* PUBLIC: #endif
*/
char *
mmap(char *addr, size_t len, int prot, int flags, int fd, off_t off)
{
char *ptr;
if ((ptr = (char *)malloc(len)) == 0)
return ((char *)-1);
if (read(fd, ptr, len) < 0) {
free(ptr);
return ((char *)-1);
}
return (ptr);
}
/*
* PUBLIC: #ifndef HAVE_MMAP
* PUBLIC: int munmap __P((char *, size_t));
* PUBLIC: #endif
*/
int
munmap(char *addr, size_t len)
{
free(addr);
return (0);
}

47
dist/nvi/clib/snprintf.c vendored Normal file
View file

@ -0,0 +1,47 @@
/* $NetBSD: snprintf.c,v 1.1.1.2 2008/05/18 14:29:39 aymeric Exp $ */
#include "config.h"
#include <sys/types.h>
#include <stdio.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
/*
* PUBLIC: #ifndef HAVE_SNPRINTF
* PUBLIC: int snprintf __P((char *, size_t, const char *, ...));
* PUBLIC: #endif
*/
int
#ifdef __STDC__
snprintf(char *str, size_t n, const char *fmt, ...)
#else
snprintf(str, n, fmt, va_alist)
char *str;
size_t n;
const char *fmt;
va_dcl
#endif
{
va_list ap;
int rval;
#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
#ifdef SPRINTF_RET_CHARPNT
(void)vsprintf(str, fmt, ap);
va_end(ap);
return (strlen(str));
#else
rval = vsprintf(str, fmt, ap);
va_end(ap);
return (rval);
#endif
}

64
dist/nvi/clib/strdup.c vendored Normal file
View file

@ -0,0 +1,64 @@
/* $NetBSD: strdup.c,v 1.1.1.2 2008/05/18 14:29:39 aymeric Exp $ */
/*
* Copyright (c) 1988, 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.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
/*
* PUBLIC: #ifndef HAVE_STRDUP
* PUBLIC: char *strdup __P((const char *));
* PUBLIC: #endif
*/
char *
strdup(const char *str)
{
size_t len;
char *copy;
len = strlen(str) + 1;
if (!(copy = malloc((u_int)len)))
return (NULL);
memcpy(copy, str, len);
return (copy);
}

63
dist/nvi/clib/strpbrk.c vendored Normal file
View file

@ -0,0 +1,63 @@
/* $NetBSD: strpbrk.c,v 1.1.1.2 2008/05/18 14:29:39 aymeric Exp $ */
/*
* Copyright (c) 1985, 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.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <string.h>
/*
* Find the first occurrence in s1 of a character in s2 (excluding NUL).
*
* PUBLIC: #ifndef HAVE_STRPBRK
* PUBLIC: char *strpbrk __P((const char *, const char *));
* PUBLIC: #endif
*/
char *
strpbrk(register const char *s1, register const char *s2)
{
register const char *scanp;
register int c, sc;
while ((c = *s1++) != 0) {
for (scanp = s2; (sc = *scanp++) != 0;)
if (sc == c)
return ((char *)(s1 - 1));
}
return (NULL);
}

85
dist/nvi/clib/strsep.c vendored Normal file
View file

@ -0,0 +1,85 @@
/* $NetBSD: strsep.c,v 1.1.1.2 2008/05/18 14:29:39 aymeric Exp $ */
/*-
* Copyright (c) 1990, 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.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <string.h>
#include <stdio.h>
/*
* Get next token from string *stringp, where tokens are possibly-empty
* strings separated by characters from delim.
*
* Writes NULs into the string at *stringp to end tokens.
* delim need not remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no more tokens).
*
* If *stringp is NULL, strsep returns NULL.
*
* PUBLIC: #ifndef HAVE_STRSEP
* PUBLIC: char *strsep __P((char **, const char *));
* PUBLIC: #endif
*/
char *
strsep(register char **stringp, register const char *delim)
{
register char *s;
register const char *spanp;
register int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}

133
dist/nvi/clib/strtol.c vendored Normal file
View file

@ -0,0 +1,133 @@
/* $NetBSD: strtol.c,v 1.1.1.2 2008/05/18 14:29:39 aymeric Exp $ */
/*-
* Copyright (c) 1990, 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.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
/*
* Convert a string to a long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*
* PUBLIC: #ifndef HAVE_STRTOL
* PUBLIC: long strtol __P((const char *, char **, int));
* PUBLIC: #endif
*/
long
strtol(const char *nptr, char **endptr, register int base)
{
register const char *s = nptr;
register unsigned long acc;
register int c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
errno = ERANGE;
} else if (neg)
acc = -acc;
if (endptr != 0)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}

112
dist/nvi/clib/strtoul.c vendored Normal file
View file

@ -0,0 +1,112 @@
/* $NetBSD: strtoul.c,v 1.1.1.2 2008/05/18 14:29:39 aymeric Exp $ */
/*
* Copyright (c) 1990, 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.
*/
#include "config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
/*
* Convert a string to an unsigned long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*
* PUBLIC: #ifndef HAVE_STRTOUL
* PUBLIC: unsigned long strtoul __P((const char *, char **, int));
* PUBLIC: #endif
*/
unsigned long
strtoul(const char *nptr, char **endptr, register int base)
{
register const char *s = nptr;
register unsigned long acc;
register int c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
/*
* See strtol for comments as to the logic used.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
errno = ERANGE;
} else if (neg)
acc = -acc;
if (endptr != 0)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}

33
dist/nvi/clib/vsnprintf.c vendored Normal file
View file

@ -0,0 +1,33 @@
/* $NetBSD: vsnprintf.c,v 1.1.1.2 2008/05/18 14:29:39 aymeric Exp $ */
#include "config.h"
#include <sys/types.h>
#include <stdio.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
/*
* PUBLIC: #ifndef HAVE_VSNPRINTF
* PUBLIC: int vsnprintf __P((char *, size_t, const char *, ...));
* PUBLIC: #endif
*/
int
vsnprintf(str, n, fmt, ap)
char *str;
size_t n;
const char *fmt;
va_list ap;
{
#ifdef SPRINTF_RET_CHARPNT
(void)vsprintf(str, fmt, ap);
return (strlen(str));
#else
return (vsprintf(str, fmt, ap));
#endif
}

609
dist/nvi/common/api.c vendored Normal file
View file

@ -0,0 +1,609 @@
/* $NetBSD: api.c,v 1.2 2008/12/05 22:51:42 christos Exp $ */
/*-
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1992, 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
* Copyright (c) 1995
* George V. Neville-Neil. All rights reserved.
*
* See the LICENSE file for redistribution information.
*/
#include "config.h"
#ifndef lint
static const char sccsid[] = "Id: api.c,v 8.40 2002/06/08 19:30:33 skimo Exp (Berkeley) Date: 2002/06/08 19:30:33";
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <bitstring.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "../common/common.h"
#include "../ex/tag.h"
extern GS *__global_list; /* XXX */
/*
* api_fscreen --
* Return a pointer to the screen specified by the screen id
* or a file name.
*
* PUBLIC: SCR *api_fscreen __P((int, char *));
*/
SCR *
api_fscreen(int id, char *name)
{
GS *gp;
SCR *tsp;
WIN *wp;
gp = __global_list;
/* Search the displayed lists. */
for (wp = gp->dq.cqh_first;
wp != (void *)&gp->dq; wp = wp->q.cqe_next)
for (tsp = wp->scrq.cqh_first;
tsp != (void *)&wp->scrq; tsp = tsp->q.cqe_next)
if (name == NULL) {
if (id == tsp->id)
return (tsp);
} else if (!strcmp(name, tsp->frp->name))
return (tsp);
/* Search the hidden list. */
for (tsp = gp->hq.cqh_first;
tsp != (void *)&gp->hq; tsp = tsp->q.cqe_next)
if (name == NULL) {
if (id == tsp->id)
return (tsp);
} else if (!strcmp(name, tsp->frp->name))
return (tsp);
return (NULL);
}
/*
* api_aline --
* Append a line.
*
* PUBLIC: int api_aline __P((SCR *, db_recno_t, char *, size_t));
*/
int
api_aline(SCR *sp, db_recno_t lno, char *line, size_t len)
{
size_t wblen;
const CHAR_T *wbp;
CHAR2INT(sp, line, len, wbp, wblen);
return (db_append(sp, 1, lno, wbp, wblen));
}
/*
* api_extend --
* Extend file.
*
* PUBLIC: int api_extend __P((SCR *, db_recno_t));
*/
int
api_extend(SCR *sp, db_recno_t lno)
{
db_recno_t lastlno;
if (db_last(sp, &lastlno))
return 1;
while(lastlno < lno)
if (db_append(sp, 1, lastlno++, NULL, 0))
return 1;
return 0;
}
/*
* api_dline --
* Delete a line.
*
* PUBLIC: int api_dline __P((SCR *, db_recno_t));
*/
int
api_dline(SCR *sp, db_recno_t lno)
{
if (db_delete(sp, lno))
return 1;
/* change current line if deleted line is that one
* or one berfore that
*/
if (sp->lno >= lno && sp->lno > 1)
sp->lno--;
return 0;
}
/*
* api_gline --
* Get a line.
*
* PUBLIC: int api_gline __P((SCR *, db_recno_t, CHAR_T **, size_t *));
*/
int
api_gline(SCR *sp, db_recno_t lno, CHAR_T **linepp, size_t *lenp)
{
int isempty;
if (db_eget(sp, lno, linepp, lenp, &isempty)) {
if (isempty)
msgq(sp, M_ERR, "209|The file is empty");
return (1);
}
return (0);
}
/*
* api_iline --
* Insert a line.
*
* PUBLIC: int api_iline __P((SCR *, db_recno_t, CHAR_T *, size_t));
*/
int
api_iline(SCR *sp, db_recno_t lno, CHAR_T *line, size_t len)
{
return (db_insert(sp, lno, line, len));
}
/*
* api_lline --
* Return the line number of the last line in the file.
*
* PUBLIC: int api_lline __P((SCR *, db_recno_t *));
*/
int
api_lline(SCR *sp, db_recno_t *lnop)
{
return (db_last(sp, lnop));
}
/*
* api_sline --
* Set a line.
*
* PUBLIC: int api_sline __P((SCR *, db_recno_t, CHAR_T *, size_t));
*/
int
api_sline(SCR *sp, db_recno_t lno, CHAR_T *line, size_t len)
{
return (db_set(sp, lno, line, len));
}
/*
* api_getmark --
* Get the mark.
*
* PUBLIC: int api_getmark __P((SCR *, int, MARK *));
*/
int
api_getmark(SCR *sp, int markname, MARK *mp)
{
return (mark_get(sp, (ARG_CHAR_T)markname, mp, M_ERR));
}
/*
* api_setmark --
* Set the mark.
*
* PUBLIC: int api_setmark __P((SCR *, int, MARK *));
*/
int
api_setmark(SCR *sp, int markname, MARK *mp)
{
return (mark_set(sp, (ARG_CHAR_T)markname, mp, 1));
}
/*
* api_nextmark --
* Return the first mark if next not set, otherwise return the
* subsequent mark.
*
* PUBLIC: int api_nextmark __P((SCR *, int, char *));
*/
int
api_nextmark(SCR *sp, int next, char *namep)
{
LMARK *mp;
mp = sp->ep->marks.lh_first;
if (next)
for (; mp != NULL; mp = mp->q.le_next)
if (mp->name == *namep) {
mp = mp->q.le_next;
break;
}
if (mp == NULL)
return (1);
*namep = mp->name;
return (0);
}
/*
* api_getcursor --
* Get the cursor.
*
* PUBLIC: int api_getcursor __P((SCR *, MARK *));
*/
int
api_getcursor(SCR *sp, MARK *mp)
{
mp->lno = sp->lno;
mp->cno = sp->cno;
return (0);
}
/*
* api_setcursor --
* Set the cursor.
*
* PUBLIC: int api_setcursor __P((SCR *, MARK *));
*/
int
api_setcursor(SCR *sp, MARK *mp)
{
size_t len;
if (db_get(sp, mp->lno, DBG_FATAL, NULL, &len))
return (1);
if (mp->cno > len) {
msgq(sp, M_ERR, "Cursor set to nonexistent column");
return (1);
}
/* Set the cursor. */
sp->lno = mp->lno;
sp->cno = mp->cno;
return (0);
}
/*
* api_emessage --
* Print an error message.
*
* PUBLIC: void api_emessage __P((SCR *, char *));
*/
void
api_emessage(SCR *sp, char *text)
{
msgq(sp, M_ERR, "%s", text);
}
/*
* api_imessage --
* Print an informational message.
*
* PUBLIC: void api_imessage __P((SCR *, char *));
*/
void
api_imessage(SCR *sp, char *text)
{
msgq(sp, M_INFO, "%s", text);
}
/*
* api_edit
* Create a new screen and return its id
* or edit a new file in the current screen.
*
* PUBLIC: int api_edit __P((SCR *, char *, SCR **, int));
*/
int
api_edit(SCR *sp, char *file, SCR **spp, int newscreen)
{
EXCMD cmd;
size_t wlen;
const CHAR_T *wp;
if (file) {
ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
CHAR2INT(sp, file, strlen(file) + 1, wp, wlen);
argv_exp0(sp, &cmd, wp, wlen - 1 /* terminating 0 */);
} else
ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
if (newscreen)
cmd.flags |= E_NEWSCREEN; /* XXX */
if (cmd.cmd->fn(sp, &cmd))
return (1);
*spp = sp->nextdisp;
return (0);
}
/*
* api_escreen
* End a screen.
*
* PUBLIC: int api_escreen __P((SCR *));
*/
int
api_escreen(SCR *sp)
{
EXCMD cmd;
/*
* XXX
* If the interpreter exits anything other than the current
* screen, vi isn't going to update everything correctly.
*/
ex_cinit(sp, &cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0);
return (cmd.cmd->fn(sp, &cmd));
}
/*
* api_swscreen --
* Switch to a new screen.
*
* PUBLIC: int api_swscreen __P((SCR *, SCR *));
*/
int
api_swscreen(SCR *sp, SCR *new)
{
/*
* XXX
* If the interpreter switches from anything other than the
* current screen, vi isn't going to update everything correctly.
*/
sp->nextdisp = new;
F_SET(sp, SC_SSWITCH);
return (0);
}
/*
* api_map --
* Map a key.
*
* PUBLIC: int api_map __P((SCR *, char *, char *, size_t));
*/
int
api_map(SCR *sp, char *name, char *map, size_t len)
{
EXCMD cmd;
size_t wlen;
const CHAR_T *wp;
ex_cinit(sp, &cmd, C_MAP, 0, OOBLNO, OOBLNO, 0);
CHAR2INT(sp, name, strlen(name) + 1, wp, wlen);
argv_exp0(sp, &cmd, wp, wlen - 1);
CHAR2INT(sp, map, len, wp, wlen);
argv_exp0(sp, &cmd, wp, wlen);
return (cmd.cmd->fn(sp, &cmd));
}
/*
* api_unmap --
* Unmap a key.
*
* PUBLIC: int api_unmap __P((SCR *, char *));
*/
int
api_unmap(SCR *sp, char *name)
{
EXCMD cmd;
size_t wlen;
const CHAR_T *wp;
ex_cinit(sp, &cmd, C_UNMAP, 0, OOBLNO, OOBLNO, 0);
CHAR2INT(sp, name, strlen(name) + 1, wp, wlen);
argv_exp0(sp, &cmd, wp, wlen - 1);
return (cmd.cmd->fn(sp, &cmd));
}
/*
* api_opts_get --
* Return a option value as a string, in allocated memory.
* If the option is of type boolean, boolvalue is (un)set
* according to the value; otherwise boolvalue is -1.
*
* PUBLIC: int api_opts_get __P((SCR *, CHAR_T *, char **, int *));
*/
int
api_opts_get(SCR *sp, const CHAR_T *name, char **value, int *boolvalue)
{
OPTLIST const *op;
int offset;
if ((op = opts_search(name)) == NULL) {
opts_nomatch(sp, name);
return (1);
}
offset = op - optlist;
if (boolvalue != NULL)
*boolvalue = -1;
switch (op->type) {
case OPT_0BOOL:
case OPT_1BOOL:
MALLOC_RET(sp, *value, char *, STRLEN(op->name) + 2 + 1);
(void)sprintf(*value,
"%s"WS, O_ISSET(sp, offset) ? "" : "no", op->name);
if (boolvalue != NULL)
*boolvalue = O_ISSET(sp, offset);
break;
case OPT_NUM:
MALLOC_RET(sp, *value, char *, 20);
(void)sprintf(*value, "%lu", (u_long)O_VAL(sp, offset));
break;
case OPT_STR:
if (O_STR(sp, offset) == NULL) {
MALLOC_RET(sp, *value, char *, 2);
value[0] = '\0';
} else {
MALLOC_RET(sp,
*value, char *, strlen(O_STR(sp, offset)) + 1);
(void)sprintf(*value, "%s", O_STR(sp, offset));
}
break;
}
return (0);
}
/*
* api_opts_set --
* Set options.
*
* PUBLIC: int api_opts_set __P((SCR *, CHAR_T *, char *, u_long, int));
*/
int
api_opts_set(SCR *sp, const CHAR_T *name,
const char *str_value, u_long num_value, int bool_value)
{
ARGS *ap[2], a, b;
OPTLIST const *op;
int rval;
size_t blen;
CHAR_T *bp;
if ((op = opts_search(name)) == NULL) {
opts_nomatch(sp, name);
return (1);
}
switch (op->type) {
case OPT_0BOOL:
case OPT_1BOOL:
GET_SPACE_RETW(sp, bp, blen, 64);
a.len = SPRINTF(bp, 64, L("%s"WS), bool_value ? "" : "no", name);
break;
case OPT_NUM:
GET_SPACE_RETW(sp, bp, blen, 64);
a.len = SPRINTF(bp, 64, L(""WS"=%lu"), name, num_value);
break;
case OPT_STR:
GET_SPACE_RETW(sp, bp, blen, 1024);
a.len = SPRINTF(bp, 1024, L(""WS"=%s"), name, str_value);
break;
default:
bp = NULL;
break;
}
a.bp = bp;
b.len = 0;
b.bp = NULL;
ap[0] = &a;
ap[1] = &b;
rval = opts_set(sp, ap, NULL);
FREE_SPACEW(sp, bp, blen);
return (rval);
}
/*
* api_run_str --
* Execute a string as an ex command.
*
* PUBLIC: int api_run_str __P((SCR *, char *));
*/
int
api_run_str(SCR *sp, char *cmd)
{
size_t wlen;
const CHAR_T *wp;
CHAR2INT(sp, cmd, strlen(cmd)+1, wp, wlen);
return (ex_run_str(sp, NULL, wp, wlen - 1, 0, 0));
}
/*
* PUBLIC: TAGQ * api_tagq_new __P((SCR*, char*));
*/
TAGQ *
api_tagq_new(SCR *sp, char *tag)
{
TAGQ *tqp;
size_t len;
/* Allocate and initialize the tag queue structure. */
len = strlen(tag);
CALLOC_GOTO(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + len + 1);
CIRCLEQ_INIT(&tqp->tagq);
tqp->tag = tqp->buf;
memcpy(tqp->tag, tag, (tqp->tlen = len) + 1);
return tqp;
alloc_err:
return (NULL);
}
/*
* PUBLIC: void api_tagq_add __P((SCR*, TAGQ*, char*, char *, char *));
*/
void
api_tagq_add(SCR *sp, TAGQ *tqp, char *filename, char *search, char *msg)
{
TAG *tp;
const CHAR_T *wp;
size_t wlen;
size_t flen = strlen(filename);
size_t slen = strlen(search);
size_t mlen = strlen(msg);
CALLOC_GOTO(sp, tp, TAG *, 1,
sizeof(TAG) - 1 + flen + 1 +
(slen + 1 + mlen + 1) * sizeof(CHAR_T));
tp->fname = (char *)tp->buf;
memcpy(tp->fname, filename, flen + 1);
tp->fnlen = flen;
tp->search = (CHAR_T *)((char *)tp->fname + flen + 1);
CHAR2INT(sp, search, slen + 1, wp, wlen);
MEMCPYW(tp->search, wp, wlen);
tp->slen = slen;
tp->msg = tp->search + slen + 1;
CHAR2INT(sp, msg, mlen + 1, wp, wlen);
MEMCPYW(tp->msg, wp, wlen);
tp->mlen = mlen;
CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q);
alloc_err:
return;
}
/*
* PUBLIC: int api_tagq_push __P((SCR*, TAGQ**));
*/
int
api_tagq_push(SCR *sp, TAGQ **tqpp)
{
TAGQ *tqp;
tqp = *tqpp;
*tqpp = 0;
/* Check to see if we found anything. */
if (tqp->tagq.cqh_first == (void *)&tqp->tagq) {
free(tqp);
return 0;
}
tqp->current = tqp->tagq.cqh_first;
if (tagq_push(sp, tqp, 0, 0))
return 1;
return (0);
}
/*
* PUBLIC: void api_tagq_free __P((SCR*, TAGQ*));
*/
void
api_tagq_free(SCR *sp, TAGQ *tqp)
{
if (tqp)
tagq_free(sp, tqp);
}

31
dist/nvi/common/args.h vendored Normal file
View file

@ -0,0 +1,31 @@
/* $NetBSD: args.h,v 1.1.1.2 2008/05/18 14:29:40 aymeric Exp $ */
/*-
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*
* Id: args.h,v 10.2 1996/03/06 19:50:07 bostic Exp (Berkeley) Date: 1996/03/06 19:50:07
*/
/*
* 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;

112
dist/nvi/common/common.h vendored Normal file
View file

@ -0,0 +1,112 @@
/* $NetBSD: common.h,v 1.3 2012/01/27 16:41:22 christos Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1991, 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
*
* Id: common.h,v 10.20 2002/03/02 23:36:22 skimo Exp (Berkeley) Date: 2002/03/02 23:36:22
*/
/*
* Avoid include sys/types.h after definition of pgno_t
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <bitstring.h>
/*
* Porting information built at configuration time. Included before
* any of nvi's include files.
*/
#include "port.h"
/*
* Pseudo-local includes. These are files that are unlikely to exist
* on most machines to which we're porting vi, and we want to include
* them in a very specific order, regardless.
*/
#include "db.h"
#include <regex.h>
/*
* Forward structure declarations. Not pretty, but the include files
* are far too interrelated for a clean solution.
*/
typedef struct _cb CB;
typedef struct _csc CSC;
typedef struct _conv CONV;
typedef struct _conv_win CONVWIN;
typedef struct _event EVENT;
typedef struct _excmd EXCMD;
typedef struct _exf EXF;
typedef struct _fref FREF;
typedef struct _gs GS;
typedef struct _lmark LMARK;
typedef struct _mark MARK;
typedef struct _msg MSGS;
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 _tagq TAGQ;
typedef struct _text TEXT;
typedef struct _win WIN;
/* Autoindent state. */
typedef enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_t;
/* Busy message types. */
typedef enum { BUSY_ON = 1, BUSY_OFF, BUSY_UPDATE } busy_t;
/*
* 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.
*/
typedef enum { CONF_NO, CONF_QUIT, CONF_YES } conf_t;
/* Directions. */
typedef enum { NOTSET, FORWARD, BACKWARD } dir_t;
/* Line operations. */
typedef enum { LINE_APPEND, LINE_DELETE, LINE_INSERT, LINE_RESET } lnop_t;
/* Lock return values. */
typedef enum { LOCK_FAILED, LOCK_SUCCESS, LOCK_UNAVAIL } lockr_t;
/* Sequence types. */
typedef enum { SEQ_ABBREV, SEQ_COMMAND, SEQ_INPUT } seq_t;
#define ENTIRE_LINE ((size_t)-1)
/*
* Local includes.
*/
#include "key.h" /* Required by args.h. */
#include "args.h" /* Required by options.h. */
#include "options.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 "util.h" /* Required by ex.h. */
#include "mark.h" /* Required by gs.h. */
#include "conv.h" /* Required by ex.h and screen.h */
#include "../ex/ex.h" /* Required by gs.h. */
#include "gs.h" /* Required by screen.h. */
#include "log.h" /* Required by screen.h */
#include "screen.h" /* Required by exf.h. */
#include "exf.h"
#include "mem.h"
#if defined(USE_DB4_LOGGING)
#include "vi_auto.h"
#endif
#include "extern.h"

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