Termcap update, replacing elvis by nvi.
Removing elvis, importing nvi, ctags, updating libedit. Change-Id: I881eb04d2dc64cf112facd992de1114e1a59107f
This commit is contained in:
34
dist/nvi/Changes
vendored
Normal file
34
dist/nvi/Changes
vendored
Normal 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
39
dist/nvi/LICENSE
vendored
Normal 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
104
dist/nvi/README
vendored
Normal 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
17
dist/nvi/README.1st
vendored
Normal 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
22
dist/nvi/README.DB3
vendored
Normal 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
123
dist/nvi/TODO
vendored
Normal 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
362
dist/nvi/build.unix/README
vendored
Normal 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
320
dist/nvi/build.unix/README.LynxOS
vendored
Normal 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
10
dist/nvi/build.unix/README.Solaris
vendored
Normal 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
84
dist/nvi/catalog/Makefile
vendored
Normal 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
166
dist/nvi/catalog/README
vendored
Normal 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
91
dist/nvi/catalog/dump.c
vendored
Normal 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
306
dist/nvi/catalog/dutch.base
vendored
Normal 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
1
dist/nvi/catalog/dutch.owner
vendored
Normal file
@@ -0,0 +1 @@
|
||||
J.G. Vons <Gert-Jan.Vons@ocegr.fr>
|
||||
1
dist/nvi/catalog/english.owner
vendored
Normal file
1
dist/nvi/catalog/english.owner
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Keith Bostic <bostic@cs.berkeley.edu>
|
||||
308
dist/nvi/catalog/french.base
vendored
Normal file
308
dist/nvi/catalog/french.base
vendored
Normal 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 "D‚finition : 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
306
dist/nvi/catalog/german.base
vendored
Normal 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
2
dist/nvi/catalog/german.owner
vendored
Normal 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
214
dist/nvi/catalog/ru_RU.KOI8-R.base
vendored
Normal 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
2
dist/nvi/catalog/ru_RU.KOI8-R.owner
vendored
Normal 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
308
dist/nvi/catalog/spanish.base
vendored
Normal 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 despu‚s 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 int‚rprete 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 int‚rprete 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
19
dist/nvi/catalog/spell.ok
vendored
Normal 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
306
dist/nvi/catalog/swedish.base
vendored
Normal 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
1
dist/nvi/catalog/swedish.owner
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Jan Djarv <jan.djarv@mbox200.swipnet.se>
|
||||
174
dist/nvi/cl/README.signal
vendored
Normal file
174
dist/nvi/cl/README.signal
vendored
Normal 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
120
dist/nvi/cl/cl.h
vendored
Normal 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
350
dist/nvi/cl/cl_bsd.c
vendored
Normal 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
894
dist/nvi/cl/cl_funcs.c
vendored
Normal 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
440
dist/nvi/cl/cl_main.c
vendored
Normal 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
312
dist/nvi/cl/cl_read.c
vendored
Normal 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
580
dist/nvi/cl/cl_screen.c
vendored
Normal 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
481
dist/nvi/cl/cl_term.c
vendored
Normal 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
59
dist/nvi/cl/extern.h
vendored
Normal 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
87
dist/nvi/clib/bsearch.c
vendored
Normal 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
160
dist/nvi/clib/env.c
vendored
Normal 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
24
dist/nvi/clib/gethostname.c
vendored
Normal 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
16
dist/nvi/clib/iswblank.c
vendored
Normal 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
64
dist/nvi/clib/memchr.c
vendored
Normal 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
139
dist/nvi/clib/memset.c
vendored
Normal 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
131
dist/nvi/clib/mkstemp.c
vendored
Normal 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
46
dist/nvi/clib/mmap.c
vendored
Normal 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
47
dist/nvi/clib/snprintf.c
vendored
Normal 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
64
dist/nvi/clib/strdup.c
vendored
Normal 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
63
dist/nvi/clib/strpbrk.c
vendored
Normal 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
85
dist/nvi/clib/strsep.c
vendored
Normal 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
133
dist/nvi/clib/strtol.c
vendored
Normal 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
112
dist/nvi/clib/strtoul.c
vendored
Normal 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
33
dist/nvi/clib/vsnprintf.c
vendored
Normal 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
609
dist/nvi/common/api.c
vendored
Normal 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
31
dist/nvi/common/args.h
vendored
Normal 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
112
dist/nvi/common/common.h
vendored
Normal 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"
|
||||
414
dist/nvi/common/conv.c
vendored
Normal file
414
dist/nvi/common/conv.c
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
/* $NetBSD: conv.c,v 1.6 2009/01/18 03:45:50 lukem 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: conv.c,v 1.27 2001/08/18 21:41:41 skimo Exp (Berkeley) Date: 2001/08/18 21:41:41";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef USE_ICONV
|
||||
#include <langinfo.h>
|
||||
#include <iconv.h>
|
||||
|
||||
#define LANGCODESET nl_langinfo(CODESET)
|
||||
#else
|
||||
typedef int iconv_t;
|
||||
|
||||
#define LANGCODESET ""
|
||||
#endif
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#ifdef USE_WIDECHAR
|
||||
static int
|
||||
raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
|
||||
const CHAR_T **dst)
|
||||
{
|
||||
int i;
|
||||
CHAR_T **tostr = (CHAR_T **)(void *)&cw->bp1;
|
||||
size_t *blen = &cw->blen1;
|
||||
|
||||
BINC_RETW(NULL, *tostr, *blen, len);
|
||||
|
||||
*tolen = len;
|
||||
for (i = 0; i < len; ++i)
|
||||
(*tostr)[i] = (u_char) str[i];
|
||||
|
||||
*dst = cw->bp1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CONV_BUFFER_SIZE 512
|
||||
/* fill the buffer with codeset encoding of string pointed to by str
|
||||
* left has the number of bytes left in str and is adjusted
|
||||
* len contains the number of bytes put in the buffer
|
||||
*/
|
||||
#ifdef USE_ICONV
|
||||
#define CONVERT(str, left, src, len) \
|
||||
do { \
|
||||
size_t outleft; \
|
||||
char *bp = buffer; \
|
||||
outleft = CONV_BUFFER_SIZE; \
|
||||
errno = 0; \
|
||||
if (iconv(id, (const char **)&str, &left, &bp, &outleft) == (size_t)-1 \
|
||||
/* && errno != E2BIG */) \
|
||||
goto err; \
|
||||
if ((len = CONV_BUFFER_SIZE - outleft) == 0) { \
|
||||
error = -left; \
|
||||
goto err; \
|
||||
} \
|
||||
src = buffer; \
|
||||
} while (0)
|
||||
#else
|
||||
#define CONVERT(str, left, src, len)
|
||||
#endif
|
||||
|
||||
static int
|
||||
default_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const CHAR_T **dst, const char *enc)
|
||||
{
|
||||
int j;
|
||||
size_t i = 0;
|
||||
CHAR_T **tostr = (CHAR_T **)(void *)&cw->bp1;
|
||||
size_t *blen = &cw->blen1;
|
||||
mbstate_t mbs;
|
||||
size_t n;
|
||||
ssize_t nlen = len;
|
||||
const char *src = (const char *)str;
|
||||
iconv_t id = (iconv_t)-1;
|
||||
char buffer[CONV_BUFFER_SIZE];
|
||||
size_t left = len;
|
||||
int error = 1;
|
||||
|
||||
MEMSET(&mbs, 0, 1);
|
||||
BINC_RETW(NULL, *tostr, *blen, nlen);
|
||||
|
||||
#ifdef USE_ICONV
|
||||
if (strcmp(nl_langinfo(CODESET), enc)) {
|
||||
id = iconv_open(nl_langinfo(CODESET), enc);
|
||||
if (id == (iconv_t)-1)
|
||||
goto err;
|
||||
CONVERT(str, left, src, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0, j = 0; j < len; ) {
|
||||
n = mbrtowc((*tostr)+i, src+j, len-j, &mbs);
|
||||
/* NULL character converted */
|
||||
if (n == (size_t)-2) error = -(len-j);
|
||||
if (n == (size_t)-1 || n == (size_t)-2) goto err;
|
||||
if (n == 0) n = 1;
|
||||
j += n;
|
||||
if (++i >= *blen) {
|
||||
nlen += 256;
|
||||
BINC_RETW(NULL, *tostr, *blen, nlen);
|
||||
}
|
||||
if (id != (iconv_t)-1 && j == len && left) {
|
||||
CONVERT(str, left, src, len);
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
*tolen = i;
|
||||
|
||||
if (id != (iconv_t)-1)
|
||||
iconv_close(id);
|
||||
|
||||
*dst = cw->bp1;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
*tolen = i;
|
||||
if (id != (iconv_t)-1)
|
||||
iconv_close(id);
|
||||
*dst = cw->bp1;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
fe_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const CHAR_T **dst)
|
||||
{
|
||||
return default_char2int(sp, str, len, cw, tolen, dst, O_STR(sp, O_FILEENCODING));
|
||||
}
|
||||
|
||||
static int
|
||||
ie_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const CHAR_T **dst)
|
||||
{
|
||||
return default_char2int(sp, str, len, cw, tolen, dst, O_STR(sp, O_INPUTENCODING));
|
||||
}
|
||||
|
||||
static int
|
||||
cs_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const CHAR_T **dst)
|
||||
{
|
||||
return default_char2int(sp, str, len, cw, tolen, dst, LANGCODESET);
|
||||
}
|
||||
|
||||
static int
|
||||
CHAR_T_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const char **dst)
|
||||
{
|
||||
*tolen = len * sizeof(CHAR_T);
|
||||
*dst = (const char *)(const void *)str;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
CHAR_T_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const CHAR_T **dst)
|
||||
{
|
||||
*tolen = len / sizeof(CHAR_T);
|
||||
*dst = (const CHAR_T*) str;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int2raw(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, size_t *tolen,
|
||||
const char **dst)
|
||||
{
|
||||
int i;
|
||||
char **tostr = (char **)(void *)&cw->bp1;
|
||||
size_t *blen = &cw->blen1;
|
||||
|
||||
BINC_RETC(NULL, *tostr, *blen, len);
|
||||
|
||||
*tolen = len;
|
||||
for (i = 0; i < len; ++i)
|
||||
(*tostr)[i] = str[i];
|
||||
|
||||
*dst = cw->bp1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
default_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const char **pdst, const char *enc)
|
||||
{
|
||||
size_t i, j;
|
||||
int offset = 0;
|
||||
char **tostr = (char **)(void *)&cw->bp1;
|
||||
size_t *blen = &cw->blen1;
|
||||
mbstate_t mbs;
|
||||
size_t n;
|
||||
ssize_t nlen = len + MB_CUR_MAX;
|
||||
char *dst;
|
||||
size_t buflen;
|
||||
char buffer[CONV_BUFFER_SIZE];
|
||||
iconv_t id = (iconv_t)-1;
|
||||
|
||||
/* convert first len bytes of buffer and append it to cw->bp
|
||||
* len is adjusted => 0
|
||||
* offset contains the offset in cw->bp and is adjusted
|
||||
* cw->bp is grown as required
|
||||
*/
|
||||
#ifdef USE_ICONV
|
||||
#define CONVERT2(len, cw, offset) \
|
||||
do { \
|
||||
const char *bp = buffer; \
|
||||
while (len != 0) { \
|
||||
size_t outleft = cw->blen1 - offset; \
|
||||
char *obp = (char *)cw->bp1 + offset; \
|
||||
if (cw->blen1 < offset + MB_CUR_MAX) { \
|
||||
nlen += 256; \
|
||||
BINC_RETC(NULL, cw->bp1, cw->blen1, nlen); \
|
||||
} \
|
||||
errno = 0; \
|
||||
if (iconv(id, &bp, &len, &obp, &outleft) == (size_t)-1 && \
|
||||
errno != E2BIG) \
|
||||
goto err; \
|
||||
offset = cw->blen1 - outleft; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define CONVERT2(len, cw, offset)
|
||||
#endif
|
||||
|
||||
|
||||
MEMSET(&mbs, 0, 1);
|
||||
BINC_RETC(NULL, *tostr, *blen, nlen);
|
||||
dst = *tostr; buflen = *blen;
|
||||
|
||||
#ifdef USE_ICONV
|
||||
if (strcmp(nl_langinfo(CODESET), enc)) {
|
||||
id = iconv_open(enc, nl_langinfo(CODESET));
|
||||
if (id == (iconv_t)-1)
|
||||
goto err;
|
||||
dst = buffer; buflen = CONV_BUFFER_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0, j = 0; i < (size_t)len; ++i) {
|
||||
n = wcrtomb(dst+j, str[i], &mbs);
|
||||
if (n == (size_t)-1) goto err;
|
||||
j += n;
|
||||
if (buflen < j + MB_CUR_MAX) {
|
||||
if (id != (iconv_t)-1) {
|
||||
CONVERT2(j, cw, offset);
|
||||
} else {
|
||||
nlen += 256;
|
||||
BINC_RETC(NULL, *tostr, *blen, nlen);
|
||||
dst = *tostr; buflen = *blen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n = wcrtomb(dst+j, L'\0', &mbs);
|
||||
j += n - 1; /* don't count NUL at the end */
|
||||
*tolen = j;
|
||||
|
||||
if (id != (iconv_t)-1) {
|
||||
CONVERT2(j, cw, offset);
|
||||
*tolen = offset;
|
||||
}
|
||||
|
||||
*pdst = cw->bp1;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
*tolen = j;
|
||||
|
||||
*pdst = cw->bp1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
fe_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const char **dst)
|
||||
{
|
||||
return default_int2char(sp, str, len, cw, tolen, dst, O_STR(sp, O_FILEENCODING));
|
||||
}
|
||||
|
||||
static int
|
||||
cs_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
|
||||
size_t *tolen, const char **dst)
|
||||
{
|
||||
return default_int2char(sp, str, len, cw, tolen, dst, LANGCODESET);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
conv_init (SCR *orig, SCR *sp)
|
||||
{
|
||||
if (orig != NULL)
|
||||
MEMCPY(&sp->conv, &orig->conv, 1);
|
||||
else {
|
||||
setlocale(LC_ALL, "");
|
||||
#ifdef USE_WIDECHAR
|
||||
sp->conv.sys2int = cs_char2int;
|
||||
sp->conv.int2sys = cs_int2char;
|
||||
sp->conv.file2int = fe_char2int;
|
||||
sp->conv.int2file = fe_int2char;
|
||||
sp->conv.input2int = ie_char2int;
|
||||
#endif
|
||||
#ifdef USE_ICONV
|
||||
o_set(sp, O_FILEENCODING, OS_STRDUP, nl_langinfo(CODESET), 0);
|
||||
o_set(sp, O_INPUTENCODING, OS_STRDUP, nl_langinfo(CODESET), 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
conv_enc (SCR *sp, int option, const char *enc)
|
||||
{
|
||||
#if defined(USE_WIDECHAR) && defined(USE_ICONV)
|
||||
iconv_t id;
|
||||
char2wchar_t *c2w;
|
||||
wchar2char_t *w2c;
|
||||
|
||||
switch (option) {
|
||||
case O_FILEENCODING:
|
||||
c2w = &sp->conv.file2int;
|
||||
w2c = &sp->conv.int2file;
|
||||
break;
|
||||
case O_INPUTENCODING:
|
||||
c2w = &sp->conv.input2int;
|
||||
w2c = NULL;
|
||||
break;
|
||||
default:
|
||||
c2w = NULL;
|
||||
w2c = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!*enc) {
|
||||
if (c2w) *c2w = raw2int;
|
||||
if (w2c) *w2c = int2raw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(enc, "WCHAR_T")) {
|
||||
if (c2w) *c2w = CHAR_T_char2int;
|
||||
if (w2c) *w2c = CHAR_T_int2char;
|
||||
return 0;
|
||||
}
|
||||
|
||||
id = iconv_open(enc, nl_langinfo(CODESET));
|
||||
if (id == (iconv_t)-1)
|
||||
goto err;
|
||||
iconv_close(id);
|
||||
id = iconv_open(nl_langinfo(CODESET), enc);
|
||||
if (id == (iconv_t)-1)
|
||||
goto err;
|
||||
iconv_close(id);
|
||||
|
||||
switch (option) {
|
||||
case O_FILEENCODING:
|
||||
*c2w = fe_char2int;
|
||||
*w2c = fe_int2char;
|
||||
break;
|
||||
case O_INPUTENCODING:
|
||||
*c2w = ie_char2int;
|
||||
break;
|
||||
}
|
||||
|
||||
F_CLR(sp, SC_CONV_ERROR);
|
||||
F_SET(sp, SC_SCR_REFORMAT);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
switch (option) {
|
||||
case O_FILEENCODING:
|
||||
msgq(sp, M_ERR,
|
||||
"321|File encoding conversion not supported");
|
||||
break;
|
||||
case O_INPUTENCODING:
|
||||
msgq(sp, M_ERR,
|
||||
"322|Input encoding conversion not supported");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
28
dist/nvi/common/conv.h
vendored
Normal file
28
dist/nvi/common/conv.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/* $NetBSD: conv.h,v 1.4 2009/04/19 02:28:19 tnozaki Exp $ */
|
||||
|
||||
#define KEY_COL(sp, ch) \
|
||||
(INTISWIDE(ch) ? \
|
||||
(CHAR_WIDTH(sp, ch) >= 0) ? \
|
||||
(size_t)CHAR_WIDTH(sp, ch) : 1 /* extra space */ \
|
||||
: KEY_LEN(sp,ch))
|
||||
|
||||
struct _conv_win {
|
||||
void *bp1;
|
||||
size_t blen1;
|
||||
};
|
||||
|
||||
typedef int (*char2wchar_t)
|
||||
(SCR *, const char *, ssize_t, struct _conv_win *, size_t *, const CHAR_T **);
|
||||
typedef int (*wchar2char_t)
|
||||
(SCR *, const CHAR_T *, ssize_t, struct _conv_win *, size_t *, const char **);
|
||||
|
||||
struct _conv {
|
||||
char2wchar_t sys2int;
|
||||
wchar2char_t int2sys;
|
||||
char2wchar_t file2int;
|
||||
wchar2char_t int2file;
|
||||
char2wchar_t input2int;
|
||||
wchar2char_t int2disp;
|
||||
};
|
||||
void conv_init __P((SCR *, SCR *));
|
||||
int conv_enc __P((SCR *, int, const char *));
|
||||
354
dist/nvi/common/cut.c
vendored
Normal file
354
dist/nvi/common/cut.c
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
/* $NetBSD: cut.c,v 1.9 2012/01/27 16:41:22 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: cut.c,v 10.18 2001/06/25 15:19:09 skimo Exp (Berkeley) Date: 2001/06/25 15:19:09";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void cb_rotate __P((SCR *));
|
||||
|
||||
/*
|
||||
* cut --
|
||||
* Put a range of lines/columns into a TEXT buffer.
|
||||
*
|
||||
* There are two buffer areas, both found in the global structure. The first
|
||||
* is the linked list of all the buffers the user has named, the second is the
|
||||
* unnamed buffer storage. There is a pointer, too, which is the current
|
||||
* default buffer, i.e. it may point to the unnamed buffer or a named buffer
|
||||
* depending on into what buffer the last text was cut. Logically, in both
|
||||
* delete and yank operations, if the user names a buffer, the text is cut
|
||||
* into it. If it's a delete of information on more than a single line, the
|
||||
* contents of the numbered buffers are rotated up one, the contents of the
|
||||
* buffer named '9' are discarded, and the text is cut into the buffer named
|
||||
* '1'. The text is always cut into the unnamed buffer.
|
||||
*
|
||||
* In all cases, upper-case buffer names are the same as lower-case names,
|
||||
* with the exception that they cause the buffer to be appended to instead
|
||||
* of replaced. Note, however, that if text is appended to a buffer, the
|
||||
* default buffer only contains the appended text, not the entire contents
|
||||
* of the buffer.
|
||||
*
|
||||
* !!!
|
||||
* The contents of the default buffer would disappear after most operations
|
||||
* in historic vi. It's unclear that this is useful, so we don't bother.
|
||||
*
|
||||
* When users explicitly cut text into the numeric buffers, historic vi became
|
||||
* genuinely strange. I've never been able to figure out what was supposed to
|
||||
* happen. It behaved differently if you deleted text than if you yanked text,
|
||||
* and, in the latter case, the text was appended to the buffer instead of
|
||||
* replacing the contents. Hopefully it's not worth getting right, and here
|
||||
* we just treat the numeric buffers like any other named buffer.
|
||||
*
|
||||
* PUBLIC: int cut __P((SCR *, ARG_CHAR_T *, MARK *, MARK *, int));
|
||||
*/
|
||||
int
|
||||
cut(SCR *sp, ARG_CHAR_T *namep, MARK *fm, MARK *tm, int flags)
|
||||
{
|
||||
CB *cbp;
|
||||
ARG_CHAR_T name = '\0';
|
||||
db_recno_t lno;
|
||||
int append, copy_one, copy_def;
|
||||
|
||||
/*
|
||||
* If the user specified a buffer, put it there. (This may require
|
||||
* a copy into the numeric buffers. We do the copy so that we don't
|
||||
* have to reference count and so we don't have to deal with things
|
||||
* like appends to buffers that are used multiple times.)
|
||||
*
|
||||
* Otherwise, if it's supposed to be put in a numeric buffer (usually
|
||||
* a delete) put it there. The rules for putting things in numeric
|
||||
* buffers were historically a little strange. There were three cases.
|
||||
*
|
||||
* 1: Some motions are always line mode motions, which means
|
||||
* that the cut always goes into the numeric buffers.
|
||||
* 2: Some motions aren't line mode motions, e.g. d10w, but
|
||||
* can cross line boundaries. For these commands, if the
|
||||
* cut crosses a line boundary, it goes into the numeric
|
||||
* buffers. This includes most of the commands.
|
||||
* 3: Some motions aren't line mode motions, e.g. d`<char>,
|
||||
* but always go into the numeric buffers, regardless. This
|
||||
* was the commands: % ` / ? ( ) N n { } -- and nvi adds ^A.
|
||||
*
|
||||
* Otherwise, put it in the unnamed buffer.
|
||||
*/
|
||||
append = copy_one = copy_def = 0;
|
||||
if (namep != NULL) {
|
||||
name = *namep;
|
||||
if (LF_ISSET(CUT_NUMREQ) || (LF_ISSET(CUT_NUMOPT) &&
|
||||
(LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno))) {
|
||||
copy_one = 1;
|
||||
cb_rotate(sp);
|
||||
}
|
||||
if ((append = ISUPPER(name)) == 1) {
|
||||
if (!copy_one)
|
||||
copy_def = 1;
|
||||
name = TOLOWER(name);
|
||||
}
|
||||
namecb: CBNAME(sp, cbp, name);
|
||||
} else if (LF_ISSET(CUT_NUMREQ) || (LF_ISSET(CUT_NUMOPT) &&
|
||||
(LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno))) {
|
||||
name = '1';
|
||||
cb_rotate(sp);
|
||||
goto namecb;
|
||||
} else
|
||||
cbp = &sp->wp->dcb_store;
|
||||
|
||||
copyloop:
|
||||
/*
|
||||
* If this is a new buffer, create it and add it into the list.
|
||||
* Otherwise, if it's not an append, free its current contents.
|
||||
*/
|
||||
if (cbp == NULL) {
|
||||
CALLOC_RET(sp, cbp, CB *, 1, sizeof(CB));
|
||||
cbp->name = name;
|
||||
CIRCLEQ_INIT(&cbp->textq);
|
||||
LIST_INSERT_HEAD(&sp->wp->cutq, cbp, q);
|
||||
} else if (!append) {
|
||||
text_lfree(&cbp->textq);
|
||||
cbp->len = 0;
|
||||
cbp->flags = 0;
|
||||
}
|
||||
|
||||
|
||||
/* In line mode, it's pretty easy, just cut the lines. */
|
||||
if (LF_ISSET(CUT_LINEMODE)) {
|
||||
cbp->flags |= CB_LMODE;
|
||||
for (lno = fm->lno; lno <= tm->lno; ++lno)
|
||||
if (cut_line(sp, lno, 0, ENTIRE_LINE, cbp))
|
||||
goto cut_line_err;
|
||||
} else {
|
||||
/*
|
||||
* Get the first line. A length of ENTIRE_LINE causes cut_line
|
||||
* to cut from the MARK to the end of the line.
|
||||
*/
|
||||
if (cut_line(sp, fm->lno, fm->cno, fm->lno != tm->lno ?
|
||||
ENTIRE_LINE : (tm->cno - fm->cno) + 1, cbp))
|
||||
goto cut_line_err;
|
||||
|
||||
/* Get the intermediate lines. */
|
||||
for (lno = fm->lno; ++lno < tm->lno;)
|
||||
if (cut_line(sp, lno, 0, ENTIRE_LINE, cbp))
|
||||
goto cut_line_err;
|
||||
|
||||
/* Get the last line. */
|
||||
if (tm->lno != fm->lno &&
|
||||
cut_line(sp, lno, 0, tm->cno + 1, cbp))
|
||||
goto cut_line_err;
|
||||
}
|
||||
|
||||
append = 0; /* Only append to the named buffer. */
|
||||
sp->wp->dcbp = cbp; /* Repoint the default buffer on each pass. */
|
||||
|
||||
if (copy_one) { /* Copy into numeric buffer 1. */
|
||||
name = '1';
|
||||
CBNAME(sp, cbp, name);
|
||||
copy_one = 0;
|
||||
goto copyloop;
|
||||
}
|
||||
if (copy_def) { /* Copy into the default buffer. */
|
||||
cbp = &sp->wp->dcb_store;
|
||||
copy_def = 0;
|
||||
goto copyloop;
|
||||
}
|
||||
return (0);
|
||||
|
||||
cut_line_err:
|
||||
text_lfree(&cbp->textq);
|
||||
cbp->len = 0;
|
||||
cbp->flags = 0;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* cb_rotate --
|
||||
* Rotate the numbered buffers up one.
|
||||
*/
|
||||
static void
|
||||
cb_rotate(SCR *sp)
|
||||
{
|
||||
CB *cbp, *del_cbp;
|
||||
|
||||
del_cbp = NULL;
|
||||
for (cbp = sp->wp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next)
|
||||
switch(cbp->name) {
|
||||
case '1':
|
||||
cbp->name = '2';
|
||||
break;
|
||||
case '2':
|
||||
cbp->name = '3';
|
||||
break;
|
||||
case '3':
|
||||
cbp->name = '4';
|
||||
break;
|
||||
case '4':
|
||||
cbp->name = '5';
|
||||
break;
|
||||
case '5':
|
||||
cbp->name = '6';
|
||||
break;
|
||||
case '6':
|
||||
cbp->name = '7';
|
||||
break;
|
||||
case '7':
|
||||
cbp->name = '8';
|
||||
break;
|
||||
case '8':
|
||||
cbp->name = '9';
|
||||
break;
|
||||
case '9':
|
||||
del_cbp = cbp;
|
||||
break;
|
||||
}
|
||||
if (del_cbp != NULL) {
|
||||
LIST_REMOVE(del_cbp, q);
|
||||
text_lfree(&del_cbp->textq);
|
||||
free(del_cbp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cut_line --
|
||||
* Cut a portion of a single line.
|
||||
*
|
||||
* PUBLIC: int cut_line __P((SCR *, db_recno_t, size_t, size_t, CB *));
|
||||
*/
|
||||
int
|
||||
cut_line(SCR *sp, db_recno_t lno, size_t fcno, size_t clen, CB *cbp)
|
||||
{
|
||||
TEXT *tp;
|
||||
size_t len;
|
||||
CHAR_T *p;
|
||||
|
||||
/* Get the line. */
|
||||
if (db_get(sp, lno, DBG_FATAL, &p, &len))
|
||||
return (1);
|
||||
|
||||
/* Create a TEXT structure that can hold the entire line. */
|
||||
if ((tp = text_init(sp, NULL, 0, len)) == NULL)
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* If the line isn't empty and it's not the entire line,
|
||||
* copy the portion we want, and reset the TEXT length.
|
||||
*/
|
||||
if (len != 0) {
|
||||
if (clen == ENTIRE_LINE)
|
||||
clen = len - fcno;
|
||||
MEMCPYW(tp->lb, p + fcno, clen);
|
||||
tp->len = clen;
|
||||
}
|
||||
|
||||
/* Append to the end of the cut buffer. */
|
||||
CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
|
||||
cbp->len += tp->len;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* cut_close --
|
||||
* Discard all cut buffers.
|
||||
*
|
||||
* PUBLIC: void cut_close __P((WIN *));
|
||||
*/
|
||||
void
|
||||
cut_close(WIN *wp)
|
||||
{
|
||||
CB *cbp;
|
||||
|
||||
/* Free cut buffer list. */
|
||||
while ((cbp = wp->cutq.lh_first) != NULL) {
|
||||
if (cbp->textq.cqh_first != (void *)&cbp->textq)
|
||||
text_lfree(&cbp->textq);
|
||||
LIST_REMOVE(cbp, q);
|
||||
free(cbp);
|
||||
}
|
||||
|
||||
/* Free default cut storage. */
|
||||
cbp = &wp->dcb_store;
|
||||
if (cbp->textq.cqh_first != (void *)&cbp->textq)
|
||||
text_lfree(&cbp->textq);
|
||||
}
|
||||
|
||||
/*
|
||||
* text_init --
|
||||
* Allocate a new TEXT structure.
|
||||
*
|
||||
* PUBLIC: TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t));
|
||||
*/
|
||||
TEXT *
|
||||
text_init(SCR *sp, const CHAR_T *p, size_t len, size_t total_len)
|
||||
{
|
||||
TEXT *tp;
|
||||
|
||||
CALLOC(sp, tp, TEXT *, 1, sizeof(TEXT));
|
||||
if (tp == NULL)
|
||||
return (NULL);
|
||||
/* ANSI C doesn't define a call to malloc(3) for 0 bytes. */
|
||||
if ((tp->lb_len = total_len * sizeof(CHAR_T)) != 0) {
|
||||
MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len * sizeof(CHAR_T));
|
||||
if (tp->lb == NULL) {
|
||||
free(tp);
|
||||
return (NULL);
|
||||
}
|
||||
if (p != NULL && len != 0)
|
||||
MEMCPYW(tp->lb, p, len);
|
||||
}
|
||||
tp->len = len;
|
||||
return (tp);
|
||||
}
|
||||
|
||||
/*
|
||||
* text_lfree --
|
||||
* Free a chain of text structures.
|
||||
*
|
||||
* PUBLIC: void text_lfree __P((TEXTH *));
|
||||
*/
|
||||
void
|
||||
text_lfree(TEXTH *headp)
|
||||
{
|
||||
TEXT *tp;
|
||||
|
||||
while ((tp = headp->cqh_first) != (void *)headp) {
|
||||
CIRCLEQ_REMOVE(headp, tp, q);
|
||||
text_free(tp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* text_free --
|
||||
* Free a text structure.
|
||||
*
|
||||
* PUBLIC: void text_free __P((TEXT *));
|
||||
*/
|
||||
void
|
||||
text_free(TEXT *tp)
|
||||
{
|
||||
if (tp->lb != NULL)
|
||||
free(tp->lb);
|
||||
free(tp);
|
||||
}
|
||||
81
dist/nvi/common/cut.h
vendored
Normal file
81
dist/nvi/common/cut.h
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/* $NetBSD: cut.h,v 1.4 2011/03/21 14:53:02 tnozaki 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: cut.h,v 10.9 2000/07/22 17:31:18 skimo Exp (Berkeley) Date: 2000/07/22 17:31:18
|
||||
*/
|
||||
|
||||
typedef struct _texth TEXTH; /* TEXT list head structure. */
|
||||
CIRCLEQ_HEAD(_texth, _text);
|
||||
|
||||
/* Cut buffers. */
|
||||
struct _cb {
|
||||
LIST_ENTRY(_cb) q; /* Linked list of cut buffers. */
|
||||
TEXTH textq; /* Linked list of TEXT structures. */
|
||||
/* XXXX Needed ? Can non ascii-chars be cut buffer names ? */
|
||||
ARG_CHAR_T name; /* Cut buffer name. */
|
||||
size_t len; /* Total length of cut text. */
|
||||
|
||||
#define CB_LMODE 0x01 /* Cut was in line mode. */
|
||||
u_int8_t flags;
|
||||
};
|
||||
|
||||
/* Lines/blocks of text. */
|
||||
struct _text { /* Text: a linked list of lines. */
|
||||
CIRCLEQ_ENTRY(_text) q; /* Linked list of text structures. */
|
||||
CHAR_T *lb; /* Line buffer. */
|
||||
size_t lb_len; /* Line buffer length. */
|
||||
size_t len; /* Line length. */
|
||||
|
||||
/* These fields are used by the vi text input routine. */
|
||||
db_recno_t lno; /* 1-N: file line. */
|
||||
size_t cno; /* 0-N: file character in line. */
|
||||
size_t ai; /* 0-N: autoindent bytes. */
|
||||
size_t insert; /* 0-N: bytes to insert (push). */
|
||||
size_t offset; /* 0-N: initial, unerasable chars. */
|
||||
size_t owrite; /* 0-N: chars to overwrite. */
|
||||
size_t R_erase; /* 0-N: 'R' erase count. */
|
||||
size_t sv_cno; /* 0-N: Saved line cursor. */
|
||||
size_t sv_len; /* 0-N: Saved line length. */
|
||||
|
||||
/*
|
||||
* These fields returns information from the vi text input routine.
|
||||
*
|
||||
* The termination condition. Note, this field is only valid if the
|
||||
* text input routine returns success.
|
||||
* TERM_BS: User backspaced over the prompt.
|
||||
* TERM_CEDIT: User entered <edit-char>.
|
||||
* TERM_CR: User entered <carriage-return>; no data.
|
||||
* TERM_ESC: User entered <escape>; no data.
|
||||
* TERM_OK: Data available.
|
||||
* TERM_SEARCH: Incremental search.
|
||||
*/
|
||||
enum {
|
||||
TERM_BS, TERM_CEDIT, TERM_CR, TERM_ESC, TERM_OK, TERM_SEARCH
|
||||
} term;
|
||||
};
|
||||
|
||||
/*
|
||||
* Get named buffer 'name'.
|
||||
* Translate upper-case buffer names to lower-case buffer names.
|
||||
*/
|
||||
#define CBNAME(sp, cbp, nch) { \
|
||||
ARG_CHAR_T L__name; \
|
||||
L__name = ISUPPER(nch) ? \
|
||||
TOLOWER(nch) : (nch); \
|
||||
for (cbp = sp->wp->cutq.lh_first; \
|
||||
cbp != NULL; cbp = cbp->q.le_next) \
|
||||
if (cbp->name == L__name) \
|
||||
break; \
|
||||
}
|
||||
|
||||
/* Flags to the cut() routine. */
|
||||
#define CUT_LINEMODE 0x01 /* Cut in line mode. */
|
||||
#define CUT_NUMOPT 0x02 /* Numeric buffer: optional. */
|
||||
#define CUT_NUMREQ 0x04 /* Numeric buffer: required. */
|
||||
690
dist/nvi/common/db.c
vendored
Normal file
690
dist/nvi/common/db.c
vendored
Normal file
@@ -0,0 +1,690 @@
|
||||
/* $NetBSD: db.c,v 1.3 2008/12/09 16:50:22 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: db.c,v 10.48 2002/06/08 19:32:52 skimo Exp (Berkeley) Date: 2002/06/08 19:32:52";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "../vi/vi.h"
|
||||
|
||||
static int append __P((SCR*, db_recno_t, const CHAR_T*, size_t, lnop_t, int));
|
||||
|
||||
/*
|
||||
* db_eget --
|
||||
* Front-end to db_get, special case handling for empty files.
|
||||
*
|
||||
* PUBLIC: int db_eget __P((SCR *, db_recno_t, CHAR_T **, size_t *, int *));
|
||||
*/
|
||||
int
|
||||
db_eget(SCR *sp, db_recno_t lno, CHAR_T **pp, size_t *lenp, int *isemptyp)
|
||||
|
||||
/* Line number. */
|
||||
/* Pointer store. */
|
||||
/* Length store. */
|
||||
|
||||
{
|
||||
db_recno_t l1;
|
||||
|
||||
if (isemptyp != NULL)
|
||||
*isemptyp = 0;
|
||||
|
||||
/* If the line exists, simply return it. */
|
||||
if (!db_get(sp, lno, 0, pp, lenp))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If the user asked for line 0 or line 1, i.e. the only possible
|
||||
* line in an empty file, find the last line of the file; db_last
|
||||
* fails loudly.
|
||||
*/
|
||||
if ((lno == 0 || lno == 1) && db_last(sp, &l1))
|
||||
return (1);
|
||||
|
||||
/* If the file isn't empty, fail loudly. */
|
||||
if ((lno != 0 && lno != 1) || l1 != 0) {
|
||||
db_err(sp, lno);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (isemptyp != NULL)
|
||||
*isemptyp = 1;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* db_get --
|
||||
* Look in the text buffers for a line, followed by the cache, followed
|
||||
* by the database.
|
||||
*
|
||||
* PUBLIC: int db_get __P((SCR *, db_recno_t, u_int32_t, CHAR_T **, size_t *));
|
||||
*/
|
||||
int
|
||||
db_get(SCR *sp, db_recno_t lno, u_int32_t flags, CHAR_T **pp, size_t *lenp)
|
||||
/* Line number. */ /* Pointer store. */ /* Length store. */
|
||||
{
|
||||
DBT data, key;
|
||||
EXF *ep;
|
||||
TEXT *tp;
|
||||
db_recno_t l1, l2;
|
||||
const CHAR_T *wp;
|
||||
size_t wlen;
|
||||
size_t nlen;
|
||||
|
||||
/*
|
||||
* The underlying recno stuff handles zero by returning NULL, but
|
||||
* have to have an OOB condition for the look-aside into the input
|
||||
* buffer anyway.
|
||||
*/
|
||||
if (lno == 0)
|
||||
goto err1;
|
||||
|
||||
/* Check for no underlying file. */
|
||||
if ((ep = sp->ep) == NULL) {
|
||||
ex_emsg(sp, NULL, EXM_NOFILEYET);
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (LF_ISSET(DBG_NOCACHE))
|
||||
goto nocache;
|
||||
|
||||
/*
|
||||
* Look-aside into the TEXT buffers and see if the line we want
|
||||
* is there.
|
||||
*/
|
||||
if (F_ISSET(sp, SC_TINPUT)) {
|
||||
l1 = ((TEXT *)sp->tiq.cqh_first)->lno;
|
||||
l2 = ((TEXT *)sp->tiq.cqh_last)->lno;
|
||||
if (l1 <= lno && l2 >= lno) {
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp,
|
||||
"retrieve TEXT buffer line %lu\n", (u_long)lno);
|
||||
#endif
|
||||
for (tp = sp->tiq.cqh_first;
|
||||
tp->lno != lno; tp = tp->q.cqe_next);
|
||||
if (lenp != NULL)
|
||||
*lenp = tp->len;
|
||||
if (pp != NULL)
|
||||
*pp = tp->lb;
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Adjust the line number for the number of lines used
|
||||
* by the text input buffers.
|
||||
*/
|
||||
if (lno > l2)
|
||||
lno -= l2 - l1;
|
||||
}
|
||||
|
||||
/* Look-aside into the cache, and see if the line we want is there. */
|
||||
if (lno == sp->c_lno) {
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "retrieve cached line %lu\n", (u_long)lno);
|
||||
#endif
|
||||
if (lenp != NULL)
|
||||
*lenp = sp->c_len;
|
||||
if (pp != NULL)
|
||||
*pp = sp->c_lp;
|
||||
return (0);
|
||||
}
|
||||
sp->c_lno = OOBLNO;
|
||||
|
||||
nocache:
|
||||
nlen = 1024;
|
||||
retry:
|
||||
/* data.size contains length in bytes */
|
||||
BINC_GOTO(sp, CHAR_T, sp->c_lp, sp->c_blen, nlen);
|
||||
|
||||
/* Get the line from the underlying database. */
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &lno;
|
||||
key.size = sizeof(lno);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = sp->c_lp;
|
||||
data.ulen = sp->c_blen;
|
||||
data.flags = DB_DBT_USERMEM;
|
||||
switch (ep->db->get(ep->db, NULL, &key, &data, 0)) {
|
||||
case DB_BUFFER_SMALL:
|
||||
nlen = data.size;
|
||||
goto retry;
|
||||
default:
|
||||
goto err2;
|
||||
case DB_NOTFOUND:
|
||||
err1: if (LF_ISSET(DBG_FATAL))
|
||||
err2: db_err(sp, lno);
|
||||
alloc_err:
|
||||
err3: if (lenp != NULL)
|
||||
*lenp = 0;
|
||||
if (pp != NULL)
|
||||
*pp = NULL;
|
||||
return (1);
|
||||
case 0:
|
||||
;
|
||||
}
|
||||
|
||||
if (FILE2INT(sp, data.data, data.size, wp, wlen)) {
|
||||
if (!F_ISSET(sp, SC_CONV_ERROR)) {
|
||||
F_SET(sp, SC_CONV_ERROR);
|
||||
msgq(sp, M_ERR, "324|Conversion error on line %d", lno);
|
||||
}
|
||||
goto err3;
|
||||
}
|
||||
|
||||
/* Reset the cache. */
|
||||
if (wp != data.data) {
|
||||
BINC_GOTOW(sp, sp->c_lp, sp->c_blen, wlen);
|
||||
MEMCPYW(sp->c_lp, wp, wlen);
|
||||
}
|
||||
sp->c_lno = lno;
|
||||
sp->c_len = wlen;
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "retrieve DB line %lu\n", (u_long)lno);
|
||||
#endif
|
||||
if (lenp != NULL)
|
||||
*lenp = wlen;
|
||||
if (pp != NULL)
|
||||
*pp = sp->c_lp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* db_delete --
|
||||
* Delete a line from the file.
|
||||
*
|
||||
* PUBLIC: int db_delete __P((SCR *, db_recno_t));
|
||||
*/
|
||||
int
|
||||
db_delete(SCR *sp, db_recno_t lno)
|
||||
{
|
||||
DBT key;
|
||||
EXF *ep;
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "delete line %lu\n", (u_long)lno);
|
||||
#endif
|
||||
/* Check for no underlying file. */
|
||||
if ((ep = sp->ep) == NULL) {
|
||||
ex_emsg(sp, NULL, EXM_NOFILEYET);
|
||||
return (1);
|
||||
}
|
||||
if (ep->l_win && ep->l_win != sp->wp) {
|
||||
ex_emsg(sp, NULL, EXM_LOCKED);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Update marks, @ and global commands. */
|
||||
if (line_insdel(sp, LINE_DELETE, lno))
|
||||
return 1;
|
||||
|
||||
/* Log before change. */
|
||||
log_line(sp, lno, LOG_LINE_DELETE_B);
|
||||
|
||||
/* Update file. */
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &lno;
|
||||
key.size = sizeof(lno);
|
||||
if ((sp->db_error = ep->db->del(ep->db, NULL, &key, 0)) != 0) {
|
||||
msgq(sp, M_DBERR, "003|unable to delete line %lu",
|
||||
(u_long)lno);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Flush the cache, update line count, before screen update. */
|
||||
update_cache(sp, LINE_DELETE, lno);
|
||||
|
||||
/* File now modified. */
|
||||
if (F_ISSET(ep, F_FIRSTMODIFY))
|
||||
(void)rcv_init(sp);
|
||||
F_SET(ep, F_MODIFIED);
|
||||
|
||||
/* Log after change. */
|
||||
log_line(sp, lno, LOG_LINE_DELETE_F);
|
||||
|
||||
/* Update screen. */
|
||||
return (scr_update(sp, lno, LINE_DELETE, 1));
|
||||
}
|
||||
|
||||
/* maybe this could be simpler
|
||||
*
|
||||
* DB3 behaves differently from DB1
|
||||
*
|
||||
* if lno != 0 just go to lno and put the new line after it
|
||||
* if lno == 0 then if there are any record, put in front of the first
|
||||
* otherwise just append to the end thus creating the first
|
||||
* line
|
||||
*/
|
||||
static int
|
||||
append(SCR *sp, db_recno_t lno, const CHAR_T *p, size_t len, lnop_t op, int update)
|
||||
{
|
||||
DBT data, key;
|
||||
DBC *dbcp_put;
|
||||
EXF *ep;
|
||||
const char *fp;
|
||||
size_t flen;
|
||||
int rval;
|
||||
|
||||
/* Check for no underlying file. */
|
||||
if ((ep = sp->ep) == NULL) {
|
||||
ex_emsg(sp, NULL, EXM_NOFILEYET);
|
||||
return (1);
|
||||
}
|
||||
if (ep->l_win && ep->l_win != sp->wp) {
|
||||
ex_emsg(sp, NULL, EXM_LOCKED);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Log before change. */
|
||||
log_line(sp, lno + 1, LOG_LINE_APPEND_B);
|
||||
|
||||
/* Update file. */
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &lno;
|
||||
key.size = sizeof(lno);
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
if ((sp->db_error = ep->db->cursor(ep->db, NULL, &dbcp_put, 0)) != 0)
|
||||
return 1;
|
||||
|
||||
INT2FILE(sp, p, len, fp, flen);
|
||||
|
||||
if (lno != 0) {
|
||||
if ((sp->db_error = dbcp_put->c_get(dbcp_put, &key, &data, DB_SET)) != 0)
|
||||
goto err2;
|
||||
|
||||
data.data = __UNCONST(fp);
|
||||
data.size = flen;
|
||||
if ((sp->db_error = dbcp_put->c_put(dbcp_put, &key, &data, DB_AFTER)) != 0) {
|
||||
err2:
|
||||
(void)dbcp_put->c_close(dbcp_put);
|
||||
msgq(sp, M_DBERR,
|
||||
(op == LINE_APPEND)
|
||||
? "004|unable to append to line %lu"
|
||||
: "005|unable to insert at line %lu",
|
||||
(u_long)lno);
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
if ((sp->db_error = dbcp_put->c_get(dbcp_put, &key, &data, DB_FIRST)) != 0) {
|
||||
if (sp->db_error != DB_NOTFOUND)
|
||||
goto err2;
|
||||
|
||||
data.data = __UNCONST(fp);
|
||||
data.size = flen;
|
||||
if ((sp->db_error = ep->db->put(ep->db, NULL, &key, &data, DB_APPEND)) != 0) {
|
||||
goto err2;
|
||||
}
|
||||
} else {
|
||||
key.data = &lno;
|
||||
key.size = sizeof(lno);
|
||||
data.data = __UNCONST(fp);
|
||||
data.size = flen;
|
||||
if ((sp->db_error = dbcp_put->c_put(dbcp_put, &key, &data, DB_BEFORE)) != 0) {
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(void)dbcp_put->c_close(dbcp_put);
|
||||
|
||||
/* Flush the cache, update line count, before screen update. */
|
||||
update_cache(sp, LINE_INSERT, lno);
|
||||
|
||||
/* File now dirty. */
|
||||
if (F_ISSET(ep, F_FIRSTMODIFY))
|
||||
(void)rcv_init(sp);
|
||||
F_SET(ep, F_MODIFIED);
|
||||
|
||||
/* Log after change. */
|
||||
log_line(sp, lno + 1, LOG_LINE_APPEND_F);
|
||||
|
||||
/* Update marks, @ and global commands. */
|
||||
rval = line_insdel(sp, LINE_INSERT, lno + 1);
|
||||
|
||||
/*
|
||||
* Update screen.
|
||||
*
|
||||
* comment copied from db_append
|
||||
* XXX
|
||||
* Nasty hack. If multiple lines are input by the user, they aren't
|
||||
* committed until an <ESC> is entered. The problem is the screen was
|
||||
* updated/scrolled as each line was entered. So, when this routine
|
||||
* is called to copy the new lines from the cut buffer into the file,
|
||||
* it has to know not to update the screen again.
|
||||
*/
|
||||
return (scr_update(sp, lno + 1, LINE_INSERT, update) || rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* db_append --
|
||||
* Append a line into the file.
|
||||
*
|
||||
* PUBLIC: int db_append __P((SCR *, int, db_recno_t, CHAR_T *, size_t));
|
||||
*/
|
||||
int
|
||||
db_append(SCR *sp, int update, db_recno_t lno, const CHAR_T *p, size_t len)
|
||||
{
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "append to %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p);
|
||||
#endif
|
||||
|
||||
/* Update file. */
|
||||
return append(sp, lno, p, len, LINE_APPEND, update);
|
||||
}
|
||||
|
||||
/*
|
||||
* db_insert --
|
||||
* Insert a line into the file.
|
||||
*
|
||||
* PUBLIC: int db_insert __P((SCR *, db_recno_t, CHAR_T *, size_t));
|
||||
*/
|
||||
int
|
||||
db_insert(SCR *sp, db_recno_t lno, CHAR_T *p, size_t len)
|
||||
{
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "insert before %lu: len %lu {%.*s}\n",
|
||||
(u_long)lno, (u_long)len, MIN(len, 20), p);
|
||||
#endif
|
||||
return append(sp, lno - 1, p, len, LINE_INSERT, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* db_set --
|
||||
* Store a line in the file.
|
||||
*
|
||||
* PUBLIC: int db_set __P((SCR *, db_recno_t, CHAR_T *, size_t));
|
||||
*/
|
||||
int
|
||||
db_set(SCR *sp, db_recno_t lno, CHAR_T *p, size_t len)
|
||||
{
|
||||
DBT data, key;
|
||||
EXF *ep;
|
||||
const char *fp;
|
||||
size_t flen;
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "replace line %lu: len %lu {%.*s}\n",
|
||||
(u_long)lno, (u_long)len, MIN(len, 20), p);
|
||||
#endif
|
||||
/* Check for no underlying file. */
|
||||
if ((ep = sp->ep) == NULL) {
|
||||
ex_emsg(sp, NULL, EXM_NOFILEYET);
|
||||
return (1);
|
||||
}
|
||||
if (ep->l_win && ep->l_win != sp->wp) {
|
||||
ex_emsg(sp, NULL, EXM_LOCKED);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Log before change. */
|
||||
log_line(sp, lno, LOG_LINE_RESET_B);
|
||||
|
||||
INT2FILE(sp, p, len, fp, flen);
|
||||
|
||||
/* Update file. */
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &lno;
|
||||
key.size = sizeof(lno);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = __UNCONST(fp);
|
||||
data.size = flen;
|
||||
if ((sp->db_error = ep->db->put(ep->db, NULL, &key, &data, 0)) != 0) {
|
||||
msgq(sp, M_DBERR, "006|unable to store line %lu", (u_long)lno);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Flush the cache, update line count, before screen update. */
|
||||
update_cache(sp, LINE_RESET, lno);
|
||||
|
||||
/* File now dirty. */
|
||||
if (F_ISSET(ep, F_FIRSTMODIFY))
|
||||
(void)rcv_init(sp);
|
||||
F_SET(ep, F_MODIFIED);
|
||||
|
||||
/* Log after change. */
|
||||
log_line(sp, lno, LOG_LINE_RESET_F);
|
||||
|
||||
/* Update screen. */
|
||||
return (scr_update(sp, lno, LINE_RESET, 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* db_exist --
|
||||
* Return if a line exists.
|
||||
*
|
||||
* PUBLIC: int db_exist __P((SCR *, db_recno_t));
|
||||
*/
|
||||
int
|
||||
db_exist(SCR *sp, db_recno_t lno)
|
||||
{
|
||||
EXF *ep;
|
||||
|
||||
/* Check for no underlying file. */
|
||||
if ((ep = sp->ep) == NULL) {
|
||||
ex_emsg(sp, NULL, EXM_NOFILEYET);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (lno == OOBLNO)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Check the last-line number cache. Adjust the cached line
|
||||
* number for the lines used by the text input buffers.
|
||||
*/
|
||||
if (ep->c_nlines != OOBLNO)
|
||||
return (lno <= (F_ISSET(sp, SC_TINPUT) ?
|
||||
ep->c_nlines + (((TEXT *)sp->tiq.cqh_last)->lno -
|
||||
((TEXT *)sp->tiq.cqh_first)->lno) : ep->c_nlines));
|
||||
|
||||
/* Go get the line. */
|
||||
return (!db_get(sp, lno, 0, NULL, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* db_last --
|
||||
* Return the number of lines in the file.
|
||||
*
|
||||
* PUBLIC: int db_last __P((SCR *, db_recno_t *));
|
||||
*/
|
||||
int
|
||||
db_last(SCR *sp, db_recno_t *lnop)
|
||||
{
|
||||
DBT data, key;
|
||||
DBC *dbcp;
|
||||
EXF *ep;
|
||||
db_recno_t lno;
|
||||
const CHAR_T *wp;
|
||||
size_t wlen;
|
||||
|
||||
/* Check for no underlying file. */
|
||||
if ((ep = sp->ep) == NULL) {
|
||||
ex_emsg(sp, NULL, EXM_NOFILEYET);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the last-line number cache. Adjust the cached line
|
||||
* number for the lines used by the text input buffers.
|
||||
*/
|
||||
if (ep->c_nlines != OOBLNO) {
|
||||
*lnop = ep->c_nlines;
|
||||
if (F_ISSET(sp, SC_TINPUT))
|
||||
*lnop += ((TEXT *)sp->tiq.cqh_last)->lno -
|
||||
((TEXT *)sp->tiq.cqh_first)->lno;
|
||||
return (0);
|
||||
}
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &lno;
|
||||
key.size = sizeof(lno);
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
if ((sp->db_error = ep->db->cursor(ep->db, NULL, &dbcp, 0)) != 0)
|
||||
goto err1;
|
||||
switch (sp->db_error = dbcp->c_get(dbcp, &key, &data, DB_LAST)) {
|
||||
case DB_NOTFOUND:
|
||||
*lnop = 0;
|
||||
return (0);
|
||||
default:
|
||||
(void)dbcp->c_close(dbcp);
|
||||
alloc_err:
|
||||
err1:
|
||||
msgq(sp, M_DBERR, "007|unable to get last line");
|
||||
*lnop = 0;
|
||||
return (1);
|
||||
case 0:
|
||||
;
|
||||
}
|
||||
|
||||
memcpy(&lno, key.data, sizeof(lno));
|
||||
|
||||
if (lno != sp->c_lno) {
|
||||
FILE2INT(sp, data.data, data.size, wp, wlen);
|
||||
|
||||
/* Fill the cache. */
|
||||
BINC_GOTOW(sp, sp->c_lp, sp->c_blen, wlen);
|
||||
MEMCPYW(sp->c_lp, wp, wlen);
|
||||
sp->c_lno = lno;
|
||||
sp->c_len = wlen;
|
||||
}
|
||||
ep->c_nlines = lno;
|
||||
|
||||
(void)dbcp->c_close(dbcp);
|
||||
|
||||
/* Return the value. */
|
||||
*lnop = (F_ISSET(sp, SC_TINPUT) &&
|
||||
((TEXT *)sp->tiq.cqh_last)->lno > lno ?
|
||||
((TEXT *)sp->tiq.cqh_last)->lno : lno);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* db_err --
|
||||
* Report a line error.
|
||||
*
|
||||
* PUBLIC: void db_err __P((SCR *, db_recno_t));
|
||||
*/
|
||||
void
|
||||
db_err(SCR *sp, db_recno_t lno)
|
||||
{
|
||||
msgq(sp, M_ERR,
|
||||
"008|Error: unable to retrieve line %lu", (u_long)lno);
|
||||
}
|
||||
|
||||
/*
|
||||
* scr_update --
|
||||
* Update all of the screens that are backed by the file that
|
||||
* just changed.
|
||||
*
|
||||
* PUBLIC: int scr_update __P((SCR *sp, db_recno_t lno,
|
||||
* PUBLIC: lnop_t op, int current));
|
||||
*/
|
||||
int
|
||||
scr_update(SCR *sp, db_recno_t lno, lnop_t op, int current)
|
||||
{
|
||||
EXF *ep;
|
||||
SCR *tsp;
|
||||
WIN *wp;
|
||||
|
||||
if (F_ISSET(sp, SC_EX))
|
||||
return (0);
|
||||
|
||||
/* XXXX goes outside of window */
|
||||
ep = sp->ep;
|
||||
if (ep->refcnt != 1)
|
||||
for (wp = sp->gp->dq.cqh_first; wp != (void *)&sp->gp->dq;
|
||||
wp = wp->q.cqe_next)
|
||||
for (tsp = wp->scrq.cqh_first;
|
||||
tsp != (void *)&wp->scrq; tsp = tsp->q.cqe_next)
|
||||
if (sp != tsp && tsp->ep == ep)
|
||||
if (vs_change(tsp, lno, op))
|
||||
return (1);
|
||||
return (current ? vs_change(sp, lno, op) : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: void update_cache __P((SCR *sp, lnop_t op, db_recno_t lno));
|
||||
*/
|
||||
void
|
||||
update_cache(SCR *sp, lnop_t op, db_recno_t lno)
|
||||
{
|
||||
SCR* scrp;
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
|
||||
/* Flush the cache, update line count, before screen update. */
|
||||
/* The flushing is probably not needed, since it was incorrect
|
||||
* for db_insert. It might be better to adjust it, like
|
||||
* marks, @ and global
|
||||
*/
|
||||
for (scrp = ep->scrq.cqh_first; scrp != (void *)&ep->scrq;
|
||||
scrp = scrp->eq.cqe_next)
|
||||
switch (op) {
|
||||
case LINE_INSERT:
|
||||
case LINE_DELETE:
|
||||
if (lno <= scrp->c_lno)
|
||||
scrp->c_lno = OOBLNO;
|
||||
break;
|
||||
case LINE_RESET:
|
||||
if (lno == scrp->c_lno)
|
||||
scrp->c_lno = OOBLNO;
|
||||
/*FALLTHROUGH*/
|
||||
case LINE_APPEND:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ep->c_nlines != OOBLNO)
|
||||
switch (op) {
|
||||
case LINE_INSERT:
|
||||
++ep->c_nlines;
|
||||
break;
|
||||
case LINE_DELETE:
|
||||
--ep->c_nlines;
|
||||
/*FALLTHROUGH*/
|
||||
case LINE_APPEND:
|
||||
case LINE_RESET:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int line_insdel __P((SCR *sp, lnop_t op, db_recno_t lno));
|
||||
*/
|
||||
int
|
||||
line_insdel(SCR *sp, lnop_t op, db_recno_t lno)
|
||||
{
|
||||
int rval;
|
||||
|
||||
/* Update marks, @ and global commands. */
|
||||
rval = 0;
|
||||
if (mark_insdel(sp, op, lno))
|
||||
rval = 1;
|
||||
if (ex_g_insdel(sp, op, lno))
|
||||
rval = 1;
|
||||
|
||||
return rval;
|
||||
}
|
||||
146
dist/nvi/common/db.h
vendored
Normal file
146
dist/nvi/common/db.h
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/* $NetBSD: db.h,v 1.3 2008/08/05 15:49:18 aymeric Exp $ */
|
||||
|
||||
#include <db.h>
|
||||
|
||||
#ifndef DB_BUFFER_SMALL
|
||||
#define DB_BUFFER_SMALL ENOMEM
|
||||
#endif
|
||||
|
||||
#if USE_DB1 || (DB_VERSION_MAJOR >= 3 && DB_VERSION_MINOR >= 1)
|
||||
#define db_env_open(env,path,flags,mode) \
|
||||
(env)->open(env, path, flags, mode)
|
||||
#define db_env_remove(env,path,flags) \
|
||||
(env)->remove(env, path, flags)
|
||||
#else
|
||||
#define db_env_open(env,path,flags,mode) \
|
||||
(env)->open(env, path, NULL, flags, mode)
|
||||
#define db_env_remove(env,path,flags) \
|
||||
(env)->remove(env, path, NULL, flags)
|
||||
#endif
|
||||
|
||||
#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1
|
||||
#define db_open(db,file,type,flags,mode) \
|
||||
(db)->open(db, NULL, file, NULL, type, flags, mode)
|
||||
#else
|
||||
#define db_open(db,file,type,flags,mode) \
|
||||
(db)->open(db, file, NULL, type, flags, mode)
|
||||
#endif
|
||||
|
||||
#ifdef USE_DYNAMIC_LOADING
|
||||
#define db_create nvi_db_create
|
||||
#define db_env_create nvi_db_env_create
|
||||
#define db_strerror nvi_db_strerror
|
||||
|
||||
extern int (*nvi_db_create) __P((DB **, DB_ENV *, u_int32_t));
|
||||
extern int (*nvi_db_env_create) __P((DB_ENV **, u_int32_t));
|
||||
extern char *(*nvi_db_strerror) __P((int));
|
||||
#endif
|
||||
|
||||
#ifdef USE_DB1
|
||||
|
||||
#define DB_AFTER 1
|
||||
#define DB_APPEND 2
|
||||
#define DB_BEFORE 3
|
||||
#define DB_FIRST 7
|
||||
#define DB_LAST 15
|
||||
#define DB_SET 25
|
||||
|
||||
#define DB_NOTFOUND (-30989)
|
||||
|
||||
/* DBT emulation */
|
||||
typedef DBT DBT_v1;
|
||||
#undef DBT
|
||||
#define DBT DBT_new
|
||||
|
||||
typedef struct {
|
||||
void *data;
|
||||
size_t size;
|
||||
|
||||
u_int32_t ulen;
|
||||
|
||||
#define DB_DBT_USERMEM 0x040
|
||||
u_int32_t flags;
|
||||
} DBT;
|
||||
|
||||
/* DB_ENV emulation */
|
||||
struct __db_env_new;
|
||||
typedef struct __db_env_new DB_ENV;
|
||||
|
||||
struct __db_env_new {
|
||||
int (*close)(DB_ENV *, u_int32_t);
|
||||
int (*open)(DB_ENV *, char *, u_int32_t, int);
|
||||
#define DB_INIT_MPOOL 0x004000
|
||||
#define DB_PRIVATE 0x200000
|
||||
int (*remove)(DB_ENV *, char *, u_int32_t);
|
||||
|
||||
char *base_path;
|
||||
int mode;
|
||||
};
|
||||
|
||||
/* DBC emulation */
|
||||
|
||||
struct __dbc_new;
|
||||
typedef struct __dbc_new DBC;
|
||||
|
||||
typedef recno_t db_recno_t;
|
||||
#define DB_MAX_RECORDS MAX_REC_NUMBER
|
||||
|
||||
#define DB_UNKNOWN (-1)
|
||||
|
||||
/* DB emulation */
|
||||
typedef DB DB_old;
|
||||
#undef DB
|
||||
#define DB DB_new
|
||||
typedef struct __db_new DB;
|
||||
|
||||
#undef DB_TXN
|
||||
typedef void DB_TXN;
|
||||
|
||||
#undef DB_LSN
|
||||
typedef struct {
|
||||
int dummy;
|
||||
} DB_LSN;
|
||||
|
||||
struct __db_new {
|
||||
DB_old *actual_db;
|
||||
|
||||
int type;
|
||||
|
||||
int (*close)(DB *, u_int32_t);
|
||||
#define DB_NOSYNC 26 /* close() */
|
||||
|
||||
int (*open)(DB *, const char *, const char *, DBTYPE, u_int32_t, int);
|
||||
#define DB_CREATE 0x000001 /* Create file as necessary. */
|
||||
#define DB_TRUNCATE 0x004000 /* Discard existing DB (O_TRUNC) */
|
||||
|
||||
int (*sync)(DB *, u_int32_t);
|
||||
int (*get)(DB *, DB_TXN *, DBT *, DBT *, u_int32_t);
|
||||
int (*put)(DB *, DB_TXN *, DBT *, DBT *, u_int32_t);
|
||||
int (*del)(DB *, DB_TXN *, DBT *, u_int32_t);
|
||||
|
||||
int (*cursor)(DB *, DB_TXN *, DBC **, u_int32_t);
|
||||
|
||||
int (*set_flags)(DB *, u_int32_t);
|
||||
#define DB_RENUMBER 0x0008 /* Recno: renumber on insert/delete. */
|
||||
#define DB_SNAPSHOT 0x0020 /* Recno: snapshot the input. */
|
||||
|
||||
int (*set_pagesize)(DB *, u_int32_t);
|
||||
|
||||
int (*set_re_delim)(DB *, int);
|
||||
int (*set_re_source)(DB *, const char *);
|
||||
|
||||
RECNOINFO _recno_info;
|
||||
u_int32_t _pagesize;
|
||||
u_int32_t _flags;
|
||||
};
|
||||
|
||||
struct __dbc_new {
|
||||
DB *db;
|
||||
db_recno_t pos;
|
||||
DBT_v1 pos_key;
|
||||
int (*c_close)(DBC *);
|
||||
int (*c_get)(DBC *, DBT *, DBT *, u_int32_t);
|
||||
int (*c_put)(DBC *, DBT *, DBT *, u_int32_t);
|
||||
};
|
||||
|
||||
#endif /* USE_DB1 */
|
||||
360
dist/nvi/common/db1.c
vendored
Normal file
360
dist/nvi/common/db1.c
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* DB1->3 compatibility layer
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "../common/db.h"
|
||||
#include "../common/dbinternal.h"
|
||||
|
||||
/*
|
||||
* DB_ENV emulation
|
||||
*/
|
||||
|
||||
static int db1_dbenv_close(DB_ENV *, u_int32_t);
|
||||
static int db1_dbenv_open(DB_ENV *, char *, u_int32_t, int);
|
||||
static int db1_dbenv_remove(DB_ENV *, char *, u_int32_t);
|
||||
|
||||
int
|
||||
db_env_create(DB_ENV **dbenvp, u_int32_t flags) {
|
||||
DB_ENV *dbenv;
|
||||
|
||||
assert(flags == 0);
|
||||
|
||||
dbenv = malloc(sizeof *dbenv);
|
||||
if (dbenv == NULL)
|
||||
return -1;
|
||||
|
||||
dbenv->close = db1_dbenv_close;
|
||||
dbenv->open = db1_dbenv_open;
|
||||
dbenv->remove = db1_dbenv_remove;
|
||||
|
||||
dbenv->base_path = NULL;
|
||||
dbenv->mode = 0;
|
||||
|
||||
*dbenvp = dbenv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_dbenv_close(DB_ENV *dbenv, u_int32_t flags) {
|
||||
assert(flags == 0);
|
||||
|
||||
if (dbenv->base_path != NULL)
|
||||
free(dbenv->base_path);
|
||||
|
||||
free(dbenv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_dbenv_open(DB_ENV *dbenv, char *base_path, u_int32_t flags, int mode) {
|
||||
|
||||
/* We ignore flags on purpose */
|
||||
|
||||
dbenv->base_path = strdup(base_path);
|
||||
if (dbenv->base_path == NULL)
|
||||
return ENOSPC;
|
||||
|
||||
dbenv->mode = mode != 0? mode : 0660;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_dbenv_remove(DB_ENV *dbenv_fake, char *base_path, u_int32_t flags) {
|
||||
/* dbenv_fake is not a useful environment */
|
||||
/* XXX check if we have to remove files here */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DB emulation
|
||||
*/
|
||||
static int db1_db_close(DB *, u_int32_t);
|
||||
static int db1_db_open(DB *, const char *, const char *, DBTYPE, u_int32_t, int);
|
||||
static int db1_db_sync(DB *, u_int32_t);
|
||||
static int db1_db_get(DB *, DB_TXN *, DBT *, DBT *, u_int32_t);
|
||||
static int db1_db_put(DB *, DB_TXN *, DBT *, DBT *, u_int32_t);
|
||||
static int db1_db_del(DB *, DB_TXN *, DBT *, u_int32_t);
|
||||
static int db1_db_set_flags(DB *, u_int32_t);
|
||||
static int db1_db_set_pagesize(DB *, u_int32_t);
|
||||
static int db1_db_set_re_delim(DB *, int);
|
||||
static int db1_db_set_re_source(DB *, const char *);
|
||||
static int db1_db_cursor(DB *, DB_TXN *, DBC **, u_int32_t);
|
||||
|
||||
int
|
||||
db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags) {
|
||||
assert(flags == 0);
|
||||
|
||||
*dbp = malloc(sizeof **dbp);
|
||||
if (*dbp == NULL)
|
||||
return -1;
|
||||
|
||||
(*dbp)->type = DB_UNKNOWN;
|
||||
(*dbp)->actual_db = NULL;
|
||||
(*dbp)->_pagesize = 0;
|
||||
(*dbp)->_flags = 0;
|
||||
memset(&(*dbp)->_recno_info, 0, sizeof (RECNOINFO));
|
||||
|
||||
(*dbp)->close = db1_db_close;
|
||||
(*dbp)->open = db1_db_open;
|
||||
(*dbp)->sync = db1_db_sync;
|
||||
(*dbp)->get = db1_db_get;
|
||||
(*dbp)->put = db1_db_put;
|
||||
(*dbp)->del = db1_db_del;
|
||||
(*dbp)->set_flags = db1_db_set_flags;
|
||||
(*dbp)->set_pagesize = db1_db_set_pagesize;
|
||||
(*dbp)->set_re_delim = db1_db_set_re_delim;
|
||||
(*dbp)->set_re_source = db1_db_set_re_source;
|
||||
(*dbp)->cursor = db1_db_cursor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
db_strerror(int error) {
|
||||
return error > 0? strerror(error) : "record not found";
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_close(DB *db, u_int32_t flags) {
|
||||
if (flags & DB_NOSYNC) {
|
||||
/* XXX warn user? */
|
||||
}
|
||||
db->actual_db->close(db->actual_db);
|
||||
|
||||
db->type = DB_UNKNOWN;
|
||||
db->actual_db = NULL;
|
||||
db->_pagesize = 0;
|
||||
db->_flags = 0;
|
||||
memset(&db->_recno_info, 0, sizeof (RECNOINFO));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_open(DB *db, const char *file, const char *database, DBTYPE type,
|
||||
u_int32_t flags, int mode) {
|
||||
int oldflags = 0;
|
||||
|
||||
assert(database == NULL && !(flags & ~(DB_CREATE | DB_TRUNCATE)));
|
||||
|
||||
db->type = type;
|
||||
|
||||
if (flags & DB_CREATE)
|
||||
oldflags |= O_CREAT;
|
||||
if (flags & DB_TRUNCATE)
|
||||
oldflags |= O_TRUNC;
|
||||
|
||||
if (type == DB_RECNO) {
|
||||
const char *tmp = file;
|
||||
|
||||
/* The interface is reversed in DB3 */
|
||||
file = db->_recno_info.bfname;
|
||||
db->_recno_info.bfname = __UNCONST(tmp);
|
||||
|
||||
/* ... and so, we should avoid to truncate the main file! */
|
||||
oldflags &= ~O_TRUNC;
|
||||
|
||||
db->_recno_info.flags =
|
||||
db->_flags & DB_SNAPSHOT? R_SNAPSHOT : 0;
|
||||
db->_recno_info.psize = db->_pagesize;
|
||||
}
|
||||
|
||||
db->actual_db = dbopen(file, oldflags, mode, type,
|
||||
type == DB_RECNO? &db->_recno_info : NULL);
|
||||
|
||||
return db->actual_db == NULL? errno : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_sync(DB *db, u_int32_t flags) {
|
||||
assert(flags == 0);
|
||||
|
||||
return db->actual_db->sync(db->actual_db, db->type == DB_UNKNOWN?
|
||||
R_RECNOSYNC : 0) == 0? 0 : errno;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_get(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags) {
|
||||
int err;
|
||||
DBT_v1 data1;
|
||||
|
||||
assert(flags == 0 && txnid == NULL);
|
||||
|
||||
err = db->actual_db->get(db->actual_db, (DBT_v1 *) key, &data1, flags);
|
||||
if (err == 1)
|
||||
return DB_NOTFOUND;
|
||||
else if (err == -1)
|
||||
return errno;
|
||||
|
||||
if (data->flags & DB_DBT_USERMEM) {
|
||||
data->size = data1.size;
|
||||
if (data1.size > data->ulen)
|
||||
return DB_BUFFER_SMALL;
|
||||
|
||||
memcpy(data->data, data1.data, data1.size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_put(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags) {
|
||||
int err;
|
||||
DB_old *db_v1 = db->actual_db;
|
||||
DBT data1;
|
||||
DBT key1;
|
||||
recno_t recno = 1;
|
||||
|
||||
assert((flags & ~DB_APPEND) == 0 && txnid == NULL);
|
||||
|
||||
key1 = *key;
|
||||
|
||||
if (flags & DB_APPEND) {
|
||||
if (db_v1->seq(db_v1, (DBT_v1 *)(void *)key,
|
||||
(DBT_v1 *)(void *)&data1, R_LAST) == 1) {
|
||||
key1.data = &recno;
|
||||
key1.size = sizeof recno;
|
||||
}
|
||||
}
|
||||
err = db_v1->put(db_v1, (DBT_v1 *)(void *)&key1, (DBT_v1 *)(void *)data,
|
||||
0);
|
||||
|
||||
return err == -1? errno : err;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_del(DB *db, DB_TXN *txnid, DBT *key, u_int32_t flags) {
|
||||
int err;
|
||||
DB_old *db_v1 = db->actual_db;
|
||||
|
||||
assert(txnid == NULL && flags == 0);
|
||||
|
||||
err = db_v1->del(db_v1, (DBT_v1 *) key, 0);
|
||||
return err == -1? errno : err;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_set_flags(DB *db, u_int32_t flags) {
|
||||
assert((flags & ~(DB_RENUMBER | DB_SNAPSHOT)) == 0);
|
||||
|
||||
/* Can't prevent renumbering from happening with DB1 */
|
||||
assert((flags | db->_flags) & DB_RENUMBER);
|
||||
|
||||
|
||||
db->_flags |= flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_set_pagesize(DB *db, u_int32_t pagesize) {
|
||||
db->_pagesize = pagesize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_set_re_delim(DB *db, int re_delim) {
|
||||
db->_recno_info.bval = re_delim;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_db_set_re_source(DB *db, const char *re_source) {
|
||||
db->_recno_info.bfname = __UNCONST(re_source);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DBC emulation. Very basic, only one cursor at a time, enough for vi */
|
||||
|
||||
static int db1_dbc_close(DBC *);
|
||||
static int db1_dbc_get(DBC *, DBT *, DBT *, u_int32_t);
|
||||
static int db1_dbc_put(DBC *, DBT *, DBT *, u_int32_t);
|
||||
|
||||
static int
|
||||
db1_db_cursor(DB *db, DB_TXN *txn, DBC **cursorp, u_int32_t flags) {
|
||||
DBC *cursor;
|
||||
|
||||
assert(txn == NULL && flags == 0);
|
||||
|
||||
cursor = malloc(sizeof *cursor);
|
||||
if (cursor == NULL)
|
||||
return -1;
|
||||
|
||||
cursor->db = db;
|
||||
cursor->pos_key.data = &cursor->pos;
|
||||
cursor->pos_key.size = sizeof cursor->pos;
|
||||
cursor->c_close = db1_dbc_close;
|
||||
cursor->c_get = db1_dbc_get;
|
||||
cursor->c_put = db1_dbc_put;
|
||||
|
||||
*cursorp = cursor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_dbc_close(DBC *cursor) {
|
||||
free(cursor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_dbc_get(DBC *cursor, DBT *key, DBT *data, u_int32_t flags) {
|
||||
DB *db = cursor->db;
|
||||
DB_old *db_v1 = db->actual_db;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
switch(flags) {
|
||||
case DB_SET:
|
||||
ret = db_v1->seq(db_v1, (DBT_v1 *) key, (DBT_v1 *) data,
|
||||
R_CURSOR);
|
||||
cursor->pos = * (db_recno_t *) key->data;
|
||||
break;
|
||||
case DB_FIRST:
|
||||
ret = db_v1->seq(db_v1, (DBT_v1 *) key, (DBT_v1 *) data,
|
||||
R_FIRST);
|
||||
if (ret == 1)
|
||||
ret = DB_NOTFOUND;
|
||||
cursor->pos = * (db_recno_t *) key->data;
|
||||
break;
|
||||
case DB_LAST:
|
||||
ret = db_v1->seq(db_v1, (DBT_v1 *) key, (DBT_v1 *) data,
|
||||
R_LAST);
|
||||
if (ret == 1)
|
||||
ret = DB_NOTFOUND;
|
||||
cursor->pos = * (db_recno_t *) key->data;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
db1_dbc_put(DBC *cursor, DBT *key, DBT *data, u_int32_t flags) {
|
||||
DB *db = cursor->db;
|
||||
DB_old *db_v1 = db->actual_db;
|
||||
int ret = 0;
|
||||
|
||||
assert((flags & ~(DB_BEFORE | DB_AFTER)) == 0);
|
||||
|
||||
ret = db_v1->put(db_v1, &cursor->pos_key, (DBT_v1 *) data,
|
||||
flags == DB_BEFORE? R_IBEFORE : R_IAFTER);
|
||||
|
||||
return ret == -1? errno : ret;
|
||||
}
|
||||
3
dist/nvi/common/dbinternal.h
vendored
Normal file
3
dist/nvi/common/dbinternal.h
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
int db_env_create(DB_ENV **, u_int32_t);
|
||||
int db_create(DB **, DB_ENV *, u_int32_t);
|
||||
const char *db_strerror(int);
|
||||
160
dist/nvi/common/delete.c
vendored
Normal file
160
dist/nvi/common/delete.c
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
/* $NetBSD: delete.c,v 1.6 2012/01/27 16:41:22 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: delete.c,v 10.17 2001/06/25 15:19:09 skimo Exp (Berkeley) Date: 2001/06/25 15:19:09";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* del --
|
||||
* Delete a range of text.
|
||||
*
|
||||
* PUBLIC: int del __P((SCR *, MARK *, MARK *, int));
|
||||
*/
|
||||
int
|
||||
del(SCR *sp, MARK *fm, MARK *tm, int lmode)
|
||||
{
|
||||
db_recno_t lno;
|
||||
size_t blen, len, nlen, tlen;
|
||||
CHAR_T *bp, *p;
|
||||
int eof, rval;
|
||||
|
||||
bp = NULL;
|
||||
|
||||
/* Case 1 -- delete in line mode. */
|
||||
if (lmode) {
|
||||
for (lno = tm->lno; lno >= fm->lno; --lno) {
|
||||
if (db_delete(sp, lno))
|
||||
return (1);
|
||||
++sp->rptlines[L_DELETED];
|
||||
if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
|
||||
break;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Case 2 -- delete to EOF. This is a special case because it's
|
||||
* easier to pick it off than try and find it in the other cases.
|
||||
*/
|
||||
if (db_last(sp, &lno))
|
||||
return (1);
|
||||
if (tm->lno >= lno) {
|
||||
if (tm->lno == lno) {
|
||||
if (db_get(sp, lno, DBG_FATAL, &p, &len))
|
||||
return (1);
|
||||
eof = tm->cno != ENTIRE_LINE && tm->cno >= len ? 1 : 0;
|
||||
} else
|
||||
eof = 1;
|
||||
if (eof) {
|
||||
for (lno = tm->lno; lno > fm->lno; --lno) {
|
||||
if (db_delete(sp, lno))
|
||||
return (1);
|
||||
++sp->rptlines[L_DELETED];
|
||||
if (lno %
|
||||
INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
|
||||
break;
|
||||
}
|
||||
if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
|
||||
return (1);
|
||||
GET_SPACE_RETW(sp, bp, blen, fm->cno);
|
||||
MEMCPYW(bp, p, fm->cno);
|
||||
if (db_set(sp, fm->lno, bp, fm->cno))
|
||||
return (1);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Case 3 -- delete within a single line. */
|
||||
if (tm->lno == fm->lno) {
|
||||
if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
|
||||
return (1);
|
||||
GET_SPACE_RETW(sp, bp, blen, len);
|
||||
if (fm->cno != 0)
|
||||
MEMCPYW(bp, p, fm->cno);
|
||||
MEMCPYW(bp + fm->cno, p + (tm->cno + 1),
|
||||
len - (tm->cno + 1));
|
||||
if (db_set(sp, fm->lno,
|
||||
bp, len - ((tm->cno - fm->cno) + 1)))
|
||||
goto err;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Case 4 -- delete over multiple lines.
|
||||
*
|
||||
* Copy the start partial line into place.
|
||||
*/
|
||||
if ((tlen = fm->cno) != 0) {
|
||||
if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL))
|
||||
return (1);
|
||||
GET_SPACE_RETW(sp, bp, blen, tlen + 256);
|
||||
MEMCPYW(bp, p, tlen);
|
||||
}
|
||||
|
||||
/* Copy the end partial line into place. */
|
||||
if (db_get(sp, tm->lno, DBG_FATAL, &p, &len))
|
||||
goto err;
|
||||
if (len != 0 && tm->cno != len - 1) {
|
||||
/*
|
||||
* XXX
|
||||
* We can overflow memory here, if the total length is greater
|
||||
* than SIZE_T_MAX. The only portable way I've found to test
|
||||
* is depending on the overflow being less than the value.
|
||||
*/
|
||||
nlen = (len - (tm->cno + 1)) + tlen;
|
||||
if (tlen > nlen) {
|
||||
msgq(sp, M_ERR, "002|Line length overflow");
|
||||
goto err;
|
||||
}
|
||||
if (tlen == 0) {
|
||||
GET_SPACE_RETW(sp, bp, blen, nlen);
|
||||
} else
|
||||
ADD_SPACE_RETW(sp, bp, blen, nlen);
|
||||
|
||||
MEMCPYW(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1));
|
||||
tlen += len - (tm->cno + 1);
|
||||
}
|
||||
|
||||
/* Set the current line. */
|
||||
if (db_set(sp, fm->lno, bp, tlen))
|
||||
goto err;
|
||||
|
||||
/* Delete the last and intermediate lines. */
|
||||
for (lno = tm->lno; lno > fm->lno; --lno) {
|
||||
if (db_delete(sp, lno))
|
||||
goto err;
|
||||
++sp->rptlines[L_DELETED];
|
||||
if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
|
||||
break;
|
||||
}
|
||||
|
||||
done: rval = 0;
|
||||
if (0)
|
||||
err: rval = 1;
|
||||
if (bp != NULL)
|
||||
FREE_SPACEW(sp, bp, blen);
|
||||
return (rval);
|
||||
}
|
||||
47
dist/nvi/common/dldb.c
vendored
Normal file
47
dist/nvi/common/dldb.c
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/* $NetBSD: dldb.c,v 1.1.1.2 2008/05/18 14:29:41 aymeric Exp $ */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
static void relocate __P(());
|
||||
|
||||
#define RELOC(func,returntype,args,proto,types) \
|
||||
static returntype reloc_##func __P(proto); \
|
||||
returntype (*nvi_##func) __P(proto) = reloc_##func; \
|
||||
static returntype reloc_##func args \
|
||||
types \
|
||||
{ \
|
||||
relocate(); \
|
||||
return nvi_##func args; \
|
||||
}
|
||||
|
||||
RELOC(db_create,int,(a,b,c),(DB **, DB_ENV *, u_int32_t),
|
||||
DB**a;DB_ENV*b;u_int32_t c;)
|
||||
RELOC(db_env_create,int,(a,b),(DB_ENV **, u_int32_t),DB_ENV ** a;u_int32_t b;);
|
||||
RELOC(db_strerror,char *,(a),(int),int a;)
|
||||
|
||||
#define LOADSYM(func) \
|
||||
if ((nvi_##func = dlsym(handle, #func)) == NULL) \
|
||||
goto error;
|
||||
|
||||
static void
|
||||
relocate()
|
||||
{
|
||||
void *handle = dlopen(_PATH_DB3, RTLD_LAZY);
|
||||
|
||||
if (!handle)
|
||||
goto error;
|
||||
|
||||
LOADSYM(db_create)
|
||||
LOADSYM(db_env_create)
|
||||
LOADSYM(db_strerror)
|
||||
|
||||
return;
|
||||
error:
|
||||
fprintf(stderr, "Relocation error: %s\n", dlerror());
|
||||
abort();
|
||||
}
|
||||
1650
dist/nvi/common/exf.c
vendored
Normal file
1650
dist/nvi/common/exf.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
92
dist/nvi/common/exf.h
vendored
Normal file
92
dist/nvi/common/exf.h
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/* $NetBSD: exf.h,v 1.1.1.2 2008/05/18 14:29:45 aymeric 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*
|
||||
* Id: exf.h,v 10.19 2002/03/02 23:36:23 skimo Exp (Berkeley) Date: 2002/03/02 23:36:23
|
||||
*/
|
||||
/* Undo direction. */
|
||||
/*
|
||||
* exf --
|
||||
* The file structure.
|
||||
*/
|
||||
struct _exf {
|
||||
CIRCLEQ_ENTRY(_exf) q; /* Linked list of file structures. */
|
||||
int refcnt; /* Reference count. */
|
||||
|
||||
CIRCLEQ_HEAD(_escrh, _scr) scrq; /* Attached screens */
|
||||
/* Underlying database state. */
|
||||
DB_ENV *env; /* The DB environment. */
|
||||
char *env_path; /* DB environment directory. */
|
||||
DB *db; /* File db structure. */
|
||||
db_recno_t c_nlines; /* Cached lines in the file. */
|
||||
|
||||
DB *log; /* Log db structure. */
|
||||
db_recno_t l_high; /* Log last + 1 record number. */
|
||||
db_recno_t l_cur; /* Log current record number. */
|
||||
#ifdef USE_DB4_LOGGING
|
||||
DB_LSN lsn_first;
|
||||
DB_LSN lsn_high; /* LSN of last record. */
|
||||
DB_LSN lsn_cur; /* LSN of first record to undo. */
|
||||
#endif
|
||||
MARK l_cursor; /* Log cursor position. */
|
||||
dir_t lundo; /* Last undo direction. */
|
||||
WIN *l_win; /* Window owning transaction. */
|
||||
|
||||
LIST_HEAD(_markh, _lmark) marks;/* Linked list of file MARK's. */
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Mtime should be a struct timespec, but time_t is more portable.
|
||||
*/
|
||||
dev_t mdev; /* Device. */
|
||||
ino_t minode; /* Inode. */
|
||||
time_t mtime; /* Last modification time. */
|
||||
|
||||
int fcntl_fd; /* Fcntl locking fd; see exf.c. */
|
||||
int fd; /* File descriptor */
|
||||
|
||||
/*
|
||||
* Recovery in general, and these fields specifically, are described
|
||||
* in recover.c.
|
||||
*/
|
||||
#define RCV_PERIOD 120 /* Sync every two minutes. */
|
||||
char *rcv_path; /* Recover file name. */
|
||||
char *rcv_mpath; /* Recover mail file name. */
|
||||
int rcv_fd; /* Locked mail file descriptor. */
|
||||
|
||||
void *lock; /* Lock for log. */
|
||||
|
||||
#define F_DEVSET 0x001 /* mdev/minode fields initialized. */
|
||||
#define F_FIRSTMODIFY 0x002 /* File not yet modified. */
|
||||
#define F_MODIFIED 0x004 /* File is currently dirty. */
|
||||
#define F_MULTILOCK 0x008 /* Multiple processes running, lock. */
|
||||
#define F_NOLOG 0x010 /* Logging turned off. */
|
||||
#define F_RCV_NORM 0x020 /* Don't delete recovery files. */
|
||||
#define F_RCV_ON 0x040 /* Recovery is possible. */
|
||||
#define F_UNDO 0x080 /* No change since last undo. */
|
||||
u_int8_t flags;
|
||||
};
|
||||
|
||||
/* Flags to db_get(). */
|
||||
#define DBG_FATAL 0x001 /* If DNE, error message. */
|
||||
#define DBG_NOCACHE 0x002 /* Ignore the front-end cache. */
|
||||
|
||||
/* Flags to file_init() and file_write(). */
|
||||
#define FS_ALL 0x001 /* Write the entire file. */
|
||||
#define FS_APPEND 0x002 /* Append to the file. */
|
||||
#define FS_FORCE 0x004 /* Force is set. */
|
||||
#define FS_OPENERR 0x008 /* Open failed, try it again. */
|
||||
#define FS_POSSIBLE 0x010 /* Force could have been set. */
|
||||
#define FS_SETALT 0x020 /* Set alternate file name. */
|
||||
|
||||
/* Flags to rcv_sync(). */
|
||||
#define RCV_EMAIL 0x01 /* Send the user email, IFF file modified. */
|
||||
#define RCV_ENDSESSION 0x02 /* End the file session. */
|
||||
#define RCV_PRESERVE 0x04 /* Preserve backup file, IFF file modified. */
|
||||
#define RCV_SNAPSHOT 0x08 /* Snapshot the recovery, and send email. */
|
||||
218
dist/nvi/common/extern.h
vendored
Normal file
218
dist/nvi/common/extern.h
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
/* $NetBSD: extern.h,v 1.5 2011/11/23 19:25:28 tnozaki Exp $ */
|
||||
|
||||
/* Do not edit: automatically built by build/distrib. */
|
||||
SCR *api_fscreen __P((int, char *));
|
||||
int api_aline __P((SCR *, db_recno_t, char *, size_t));
|
||||
int api_extend __P((SCR *, db_recno_t));
|
||||
int api_dline __P((SCR *, db_recno_t));
|
||||
int api_gline __P((SCR *, db_recno_t, CHAR_T **, size_t *));
|
||||
int api_iline __P((SCR *, db_recno_t, CHAR_T *, size_t));
|
||||
int api_lline __P((SCR *, db_recno_t *));
|
||||
int api_sline __P((SCR *, db_recno_t, CHAR_T *, size_t));
|
||||
int api_getmark __P((SCR *, int, MARK *));
|
||||
int api_setmark __P((SCR *, int, MARK *));
|
||||
int api_nextmark __P((SCR *, int, char *));
|
||||
int api_getcursor __P((SCR *, MARK *));
|
||||
int api_setcursor __P((SCR *, MARK *));
|
||||
void api_emessage __P((SCR *, char *));
|
||||
void api_imessage __P((SCR *, char *));
|
||||
int api_edit __P((SCR *, char *, SCR **, int));
|
||||
int api_escreen __P((SCR *));
|
||||
int api_swscreen __P((SCR *, SCR *));
|
||||
int api_map __P((SCR *, char *, char *, size_t));
|
||||
int api_unmap __P((SCR *, char *));
|
||||
int api_opts_get __P((SCR *, const CHAR_T *, char **, int *));
|
||||
int api_opts_set __P((SCR *, const CHAR_T *, const char *, u_long, int));
|
||||
int api_run_str __P((SCR *, char *));
|
||||
TAGQ * api_tagq_new __P((SCR*, char*));
|
||||
void api_tagq_add __P((SCR*, TAGQ*, char*, char *, char *));
|
||||
int api_tagq_push __P((SCR*, TAGQ**));
|
||||
void api_tagq_free __P((SCR*, TAGQ*));
|
||||
int cut __P((SCR *, ARG_CHAR_T *, MARK *, MARK *, int));
|
||||
int cut_line __P((SCR *, db_recno_t, size_t, size_t, CB *));
|
||||
void cut_close __P((WIN *));
|
||||
TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t));
|
||||
void text_lfree __P((TEXTH *));
|
||||
void text_free __P((TEXT *));
|
||||
int db_eget __P((SCR *, db_recno_t, CHAR_T **, size_t *, int *));
|
||||
int db_get __P((SCR *, db_recno_t, u_int32_t, CHAR_T **, size_t *));
|
||||
int db_delete __P((SCR *, db_recno_t));
|
||||
int db_append __P((SCR *, int, db_recno_t, const CHAR_T *, size_t));
|
||||
int db_insert __P((SCR *, db_recno_t, CHAR_T *, size_t));
|
||||
int db_set __P((SCR *, db_recno_t, CHAR_T *, size_t));
|
||||
int db_exist __P((SCR *, db_recno_t));
|
||||
int db_last __P((SCR *, db_recno_t *));
|
||||
void db_err __P((SCR *, db_recno_t));
|
||||
int scr_update __P((SCR *sp, db_recno_t lno,
|
||||
lnop_t op, int current));
|
||||
void update_cache __P((SCR *sp, lnop_t op, db_recno_t lno));
|
||||
int line_insdel __P((SCR *sp, lnop_t op, db_recno_t lno));
|
||||
int del __P((SCR *, MARK *, MARK *, int));
|
||||
FREF *file_add __P((SCR *, const char *));
|
||||
int file_init __P((SCR *, FREF *, char *, int));
|
||||
int file_end __P((SCR *, EXF *, int));
|
||||
int file_write __P((SCR *, MARK *, MARK *, char *, int));
|
||||
int file_m1 __P((SCR *, int, int));
|
||||
int file_m2 __P((SCR *, int));
|
||||
int file_m3 __P((SCR *, int));
|
||||
int file_aw __P((SCR *, int));
|
||||
void set_alt_name __P((SCR *, const char *));
|
||||
lockr_t file_lock __P((SCR *, char *, int *, int, int));
|
||||
GS * gs_init __P((char*));
|
||||
WIN * gs_new_win __P((GS *gp));
|
||||
int win_end __P((WIN *wp));
|
||||
void gs_end __P((GS *));
|
||||
int v_key_init __P((SCR *));
|
||||
void v_key_ilookup __P((SCR *));
|
||||
size_t v_key_len __P((SCR *, ARG_CHAR_T));
|
||||
u_char *v_key_name __P((SCR *, ARG_CHAR_T));
|
||||
e_key_t v_key_val __P((SCR *, ARG_CHAR_T));
|
||||
int v_event_push __P((SCR *, EVENT *, const CHAR_T *, size_t, u_int));
|
||||
int v_event_get __P((SCR *, EVENT *, int, u_int32_t));
|
||||
void v_event_err __P((SCR *, EVENT *));
|
||||
int v_event_flush __P((SCR *, u_int));
|
||||
int log_init __P((SCR *, EXF *));
|
||||
int log_end __P((SCR *, EXF *));
|
||||
int log_cursor __P((SCR *));
|
||||
int log_line __P((SCR *, db_recno_t, u_int));
|
||||
int log_mark __P((SCR *, LMARK *));
|
||||
int log_backward __P((SCR *, MARK *));
|
||||
int log_setline __P((SCR *));
|
||||
int log_forward __P((SCR *, MARK *));
|
||||
int log_init __P((SCR *, EXF *));
|
||||
int log_end __P((SCR *, EXF *));
|
||||
int log_cursor __P((SCR *));
|
||||
int log_line __P((SCR *, db_recno_t, u_int));
|
||||
int log_mark __P((SCR *, LMARK *));
|
||||
int log_backward __P((SCR *, MARK *));
|
||||
int log_setline __P((SCR *));
|
||||
int log_forward __P((SCR *, MARK *));
|
||||
int editor __P((WIN *, int, char *[]));
|
||||
int mark_init __P((SCR *, EXF *));
|
||||
int mark_end __P((SCR *, EXF *));
|
||||
int mark_get __P((SCR *, ARG_CHAR_T, MARK *, mtype_t));
|
||||
int mark_set __P((SCR *, ARG_CHAR_T, MARK *, int));
|
||||
int mark_insdel __P((SCR *, lnop_t, db_recno_t));
|
||||
void msgq __P((SCR *, mtype_t, const char *, ...))
|
||||
__attribute__((__format__(__printf__, 3, 4)));
|
||||
void msgq_wstr __P((SCR *, mtype_t, const CHAR_T *, const char *));
|
||||
void msgq_str __P((SCR *, mtype_t, const char *, const char *));
|
||||
void mod_rpt __P((SCR *));
|
||||
void msgq_status __P((SCR *, db_recno_t, u_int));
|
||||
int msg_open __P((SCR *, const char *));
|
||||
void msg_close __P((GS *));
|
||||
const char *msg_cmsg __P((SCR *, cmsg_t, size_t *));
|
||||
const char *msg_cat __P((SCR *, const char *, size_t *));
|
||||
char *msg_print __P((SCR *, const char *, int *));
|
||||
void thread_init __P((GS *gp));
|
||||
int opts_init __P((SCR *, int *));
|
||||
int opts_set __P((SCR *, ARGS *[], const char *));
|
||||
int o_set __P((SCR *, int, u_int, const char *, u_long));
|
||||
int opts_empty __P((SCR *, int, int));
|
||||
void opts_dump __P((SCR *, enum optdisp));
|
||||
int opts_save __P((SCR *, FILE *));
|
||||
OPTLIST const *opts_search __P((const CHAR_T *));
|
||||
void opts_nomatch __P((SCR *, const CHAR_T *));
|
||||
int opts_copy __P((SCR *, SCR *));
|
||||
void opts_free __P((SCR *));
|
||||
int f_altwerase __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_columns __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_lines __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_lisp __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_msgcat __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_paragraph __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_print __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_readonly __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_recompile __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_reformat __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_section __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_ttywerase __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_w300 __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_w1200 __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_w9600 __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_window __P((SCR *, OPTION *, const char *, u_long *));
|
||||
int f_encoding __P((SCR *, OPTION *, const char *, u_long *));
|
||||
void thread_init __P((GS *gp));
|
||||
int put __P((SCR *, CB *, ARG_CHAR_T *, MARK *, MARK *, int));
|
||||
int rcv_tmp __P((SCR *, EXF *, char *));
|
||||
int rcv_init __P((SCR *));
|
||||
int rcv_sync __P((SCR *, u_int));
|
||||
int rcv_list __P((SCR *));
|
||||
int rcv_read __P((SCR *, FREF *));
|
||||
int screen_init __P((GS *, SCR *, SCR **));
|
||||
int screen_end __P((SCR *));
|
||||
SCR *screen_next __P((SCR *));
|
||||
int f_search __P((SCR *,
|
||||
MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
|
||||
int b_search __P((SCR *,
|
||||
MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
|
||||
void search_busy __P((SCR *, busy_t));
|
||||
int seq_set __P((SCR *, CHAR_T *,
|
||||
size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int));
|
||||
int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t));
|
||||
int seq_mdel __P((SEQ *));
|
||||
SEQ *seq_find
|
||||
__P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *));
|
||||
void seq_close __P((GS *));
|
||||
int seq_dump __P((SCR *, seq_t, int));
|
||||
int seq_save __P((SCR *, FILE *, const char *, seq_t));
|
||||
int e_memcmp __P((CHAR_T *, EVENT *, size_t));
|
||||
void vtrace_end __P((void));
|
||||
void vtrace_init __P((char *));
|
||||
void vtrace __P((const char *, ...))
|
||||
__attribute__((__format__(__printf__, 1, 2)));
|
||||
void *binc __P((SCR *, void *, size_t *, size_t));
|
||||
int nonblank __P((SCR *, db_recno_t, size_t *));
|
||||
const char *tail __P((const char *));
|
||||
char *v_strdup __P((SCR *, const char *, size_t));
|
||||
CHAR_T *v_wstrdup __P((SCR *, const CHAR_T *, size_t));
|
||||
enum nresult nget_uslong __P((SCR *, u_long *, const CHAR_T *, CHAR_T **, int));
|
||||
enum nresult nget_slong __P((SCR *, long *, const CHAR_T *, CHAR_T **, int));
|
||||
#ifdef USE_DB4_LOGGING
|
||||
int __vi_marker_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t));
|
||||
int __vi_marker_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
void *));
|
||||
int __vi_marker_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
void *));
|
||||
int __vi_marker_read __P((DB_ENV *, void *, __vi_marker_args **));
|
||||
int __vi_cursor_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, db_recno_t, size_t));
|
||||
int __vi_cursor_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
void *));
|
||||
int __vi_cursor_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
void *));
|
||||
int __vi_cursor_read __P((DB_ENV *, void *, __vi_cursor_args **));
|
||||
int __vi_mark_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
LMARK *));
|
||||
int __vi_mark_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
void *));
|
||||
int __vi_mark_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
void *));
|
||||
int __vi_mark_read __P((DB_ENV *, void *, __vi_mark_args **));
|
||||
int __vi_change_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, db_recno_t));
|
||||
int __vi_change_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
void *));
|
||||
int __vi_change_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
void *));
|
||||
int __vi_change_read __P((DB_ENV *, void *, __vi_change_args **));
|
||||
int __vi_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *,
|
||||
DB_LSN *, db_recops, void *), size_t *));
|
||||
int __vi_init_getpgnos __P((DB_ENV *, int (***)(DB_ENV *, DBT *,
|
||||
DB_LSN *, db_recops, void *), size_t *));
|
||||
int __vi_init_recover __P((DB_ENV *));
|
||||
#endif
|
||||
#ifdef USE_DB4_LOGGING
|
||||
int __vi_marker_recover
|
||||
__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
int __vi_cursor_recover
|
||||
__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
int __vi_mark_recover
|
||||
__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
int __vi_change_recover
|
||||
__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
int __vi_log_truncate __P((EXF *ep));
|
||||
int __vi_log_dispatch __P((DB_ENV *dbenv, DBT *data, DB_LSN *lsn, db_recops ops));
|
||||
int __vi_log_traverse __P((SCR *sp, undo_t undo, MARK *));
|
||||
#endif
|
||||
218
dist/nvi/common/gs.c
vendored
Normal file
218
dist/nvi/common/gs.c
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
/* $NetBSD: gs.c,v 1.2 2011/09/16 16:13:41 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000
|
||||
* Sven Verdoolaege. All rights reserved.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../perl_api/extern.h"
|
||||
|
||||
__dead static void perr __P((char *, char *));
|
||||
|
||||
/*
|
||||
* gs_init --
|
||||
* Create and partially initialize the GS structure.
|
||||
* PUBLIC: GS * gs_init __P((char*));
|
||||
*/
|
||||
GS *
|
||||
gs_init(char *name)
|
||||
{
|
||||
GS *gp;
|
||||
char *p;
|
||||
|
||||
/* Figure out what our name is. */
|
||||
if ((p = strrchr(name, '/')) != NULL)
|
||||
name = p + 1;
|
||||
|
||||
/* Allocate the global structure. */
|
||||
CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS));
|
||||
if (gp == NULL)
|
||||
perr(name, NULL);
|
||||
|
||||
gp->progname = name;
|
||||
|
||||
/* Common global structure initialization. */
|
||||
/* others will need to be copied from main.c */
|
||||
CIRCLEQ_INIT(&gp->dq);
|
||||
|
||||
CIRCLEQ_INIT(&gp->hq);
|
||||
gp->noprint = DEFAULT_NOPRINT;
|
||||
|
||||
/* Structures shared by screens so stored in the GS structure. */
|
||||
CIRCLEQ_INIT(&gp->frefq);
|
||||
CIRCLEQ_INIT(&gp->exfq);
|
||||
LIST_INIT(&gp->seqq);
|
||||
|
||||
thread_init(gp);
|
||||
|
||||
return (gp);
|
||||
}
|
||||
|
||||
/*
|
||||
* gs_new_win
|
||||
* Create new window
|
||||
* PUBLIC: WIN * gs_new_win __P((GS *gp));
|
||||
*/
|
||||
|
||||
WIN *
|
||||
gs_new_win(GS *gp)
|
||||
{
|
||||
WIN *wp;
|
||||
|
||||
CALLOC_NOMSG(NULL, wp, WIN *, 1, sizeof(*wp));
|
||||
if (!wp)
|
||||
return NULL;
|
||||
|
||||
/* Common global structure initialization. */
|
||||
LIST_INIT(&wp->ecq);
|
||||
LIST_INSERT_HEAD(&wp->ecq, &wp->excmd, q);
|
||||
|
||||
CIRCLEQ_INSERT_TAIL(&gp->dq, wp, q);
|
||||
CIRCLEQ_INIT(&wp->scrq);
|
||||
|
||||
CIRCLEQ_INIT(&wp->dcb_store.textq);
|
||||
LIST_INIT(&wp->cutq);
|
||||
|
||||
wp->gp = gp;
|
||||
|
||||
return wp;
|
||||
}
|
||||
|
||||
/*
|
||||
* win_end --
|
||||
* Remove window.
|
||||
*
|
||||
* PUBLIC: int win_end __P((WIN *wp));
|
||||
*/
|
||||
int
|
||||
win_end(WIN *wp)
|
||||
{
|
||||
SCR *sp;
|
||||
|
||||
CIRCLEQ_REMOVE(&wp->gp->dq, wp, q);
|
||||
|
||||
if (wp->ccl_sp != NULL) {
|
||||
(void)file_end(wp->ccl_sp, NULL, 1);
|
||||
(void)screen_end(wp->ccl_sp);
|
||||
}
|
||||
while ((sp = wp->scrq.cqh_first) != (void *)&wp->scrq)
|
||||
(void)screen_end(sp);
|
||||
|
||||
/* Free key input queue. */
|
||||
if (wp->i_event != NULL)
|
||||
free(wp->i_event);
|
||||
|
||||
/* Free cut buffers. */
|
||||
cut_close(wp);
|
||||
|
||||
/* Free default buffer storage. */
|
||||
(void)text_lfree(&wp->dcb_store.textq);
|
||||
|
||||
#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
|
||||
/* Free any temporary space. */
|
||||
if (wp->tmp_bp != NULL)
|
||||
free(wp->tmp_bp);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* gs_end --
|
||||
* End the program, discarding screens and most of the global area.
|
||||
*
|
||||
* PUBLIC: void gs_end __P((GS *));
|
||||
*/
|
||||
void
|
||||
gs_end(GS *gp)
|
||||
{
|
||||
MSGS *mp;
|
||||
SCR *sp;
|
||||
WIN *wp;
|
||||
|
||||
/* If there are any remaining screens, kill them off. */
|
||||
while ((wp = gp->dq.cqh_first) != (void *)&gp->dq)
|
||||
(void)win_end(wp);
|
||||
while ((sp = gp->hq.cqh_first) != (void *)&gp->hq)
|
||||
(void)screen_end(sp);
|
||||
|
||||
#ifdef HAVE_PERL_INTERP
|
||||
perl_end(gp);
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
|
||||
{ FREF *frp;
|
||||
/* Free FREF's. */
|
||||
while ((frp = gp->frefq.cqh_first) != (FREF *)&gp->frefq) {
|
||||
CIRCLEQ_REMOVE(&gp->frefq, frp, q);
|
||||
if (frp->name != NULL)
|
||||
free(frp->name);
|
||||
if (frp->tname != NULL)
|
||||
free(frp->tname);
|
||||
free(frp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free map sequences. */
|
||||
seq_close(gp);
|
||||
|
||||
/* Close message catalogs. */
|
||||
msg_close(gp);
|
||||
#endif
|
||||
|
||||
/* Ring the bell if scheduled. */
|
||||
if (F_ISSET(gp, G_BELLSCHED))
|
||||
(void)fprintf(stderr, "\07"); /* \a */
|
||||
|
||||
/*
|
||||
* Flush any remaining messages. If a message is here, it's almost
|
||||
* certainly the message about the event that killed us (although
|
||||
* it's possible that the user is sourcing a file that exits from the
|
||||
* editor).
|
||||
*/
|
||||
while ((mp = gp->msgq.lh_first) != NULL) {
|
||||
(void)fprintf(stderr, "%s%.*s",
|
||||
mp->mtype == M_ERR ? "ex/vi: " : "", (int)mp->len, mp->buf);
|
||||
LIST_REMOVE(mp, q);
|
||||
#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
|
||||
free(mp->buf);
|
||||
free(mp);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TRACE)
|
||||
/* Close tracing file descriptor. */
|
||||
vtrace_end();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* perr --
|
||||
* Print system error.
|
||||
*/
|
||||
static void
|
||||
perr(char *name, char *msg)
|
||||
{
|
||||
(void)fprintf(stderr, "%s:", name);
|
||||
if (msg != NULL)
|
||||
(void)fprintf(stderr, "%s:", msg);
|
||||
(void)fprintf(stderr, "%s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
212
dist/nvi/common/gs.h
vendored
Normal file
212
dist/nvi/common/gs.h
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
/* $NetBSD: gs.h,v 1.5 2011/03/21 14:53:02 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.
|
||||
*
|
||||
* Id: gs.h,v 10.55 2001/11/01 10:28:25 skimo Exp (Berkeley) Date: 2001/11/01 10:28:25
|
||||
*/
|
||||
|
||||
#define TEMPORARY_FILE_STRING "/tmp" /* Default temporary file name. */
|
||||
|
||||
/*
|
||||
* File reference structure (FREF). The structure contains the name of the
|
||||
* file, along with the information that follows the name.
|
||||
*
|
||||
* !!!
|
||||
* The read-only bit follows the file name, not the file itself.
|
||||
*/
|
||||
struct _fref {
|
||||
CIRCLEQ_ENTRY(_fref) q; /* Linked list of file references. */
|
||||
char *name; /* File name. */
|
||||
char *tname; /* Backing temporary file name. */
|
||||
|
||||
db_recno_t lno; /* 1-N: file cursor line. */
|
||||
size_t cno; /* 0-N: file cursor column. */
|
||||
|
||||
#define FR_CURSORSET 0x0001 /* If lno/cno values valid. */
|
||||
#define FR_DONTDELETE 0x0002 /* Don't delete the temporary file. */
|
||||
#define FR_EXNAMED 0x0004 /* Read/write renamed the file. */
|
||||
#define FR_NAMECHANGE 0x0008 /* If the name changed. */
|
||||
#define FR_NEWFILE 0x0010 /* File doesn't really exist yet. */
|
||||
#define FR_RECOVER 0x0020 /* File is being recovered. */
|
||||
#define FR_TMPEXIT 0x0040 /* Modified temporary file, no exit. */
|
||||
#define FR_TMPFILE 0x0080 /* If file has no name. */
|
||||
#define FR_UNLOCKED 0x0100 /* File couldn't be locked. */
|
||||
u_int16_t flags;
|
||||
};
|
||||
|
||||
/* Action arguments to scr_exadjust(). */
|
||||
typedef enum { EX_TERM_CE, EX_TERM_SCROLL } exadj_t;
|
||||
|
||||
/* Screen attribute arguments to scr_attr(). */
|
||||
typedef enum { SA_ALTERNATE, SA_INVERSE } scr_attr_t;
|
||||
|
||||
/* Key type arguments to scr_keyval(). */
|
||||
typedef enum { KEY_VEOF, KEY_VERASE, KEY_VKILL, KEY_VWERASE } scr_keyval_t;
|
||||
|
||||
/*
|
||||
* GS:
|
||||
*
|
||||
* Structure that describes global state of the running program.
|
||||
*/
|
||||
struct _gs {
|
||||
char *progname; /* Programe name. */
|
||||
|
||||
int id; /* Last allocated screen id. */
|
||||
CIRCLEQ_HEAD(_dqh, _win) dq; /* Displayed windows. */
|
||||
CIRCLEQ_HEAD(_hqh, _scr) hq; /* Hidden screens. */
|
||||
|
||||
void *perl_interp; /* Perl interpreter. */
|
||||
void *tcl_interp; /* Tcl_Interp *: Tcl interpreter. */
|
||||
|
||||
void *cl_private; /* Curses support private area. */
|
||||
void *tk_private; /* Tk/Tcl support private area. */
|
||||
|
||||
/* File references. */
|
||||
CIRCLEQ_HEAD(_frefh, _fref) frefq;
|
||||
/* File structures. */
|
||||
CIRCLEQ_HEAD(_exfh, _exf) exfq;
|
||||
|
||||
#define GO_COLUMNS 0 /* Global options: columns. */
|
||||
#define GO_LINES 1 /* Global options: lines. */
|
||||
#define GO_SECURE 2 /* Global options: secure. */
|
||||
#define GO_TERM 3 /* Global options: terminal type. */
|
||||
OPTION opts[GO_TERM + 1];
|
||||
|
||||
DB *msg; /* Message catalog DB. */
|
||||
MSGH msgq; /* User message list. */
|
||||
#define DEFAULT_NOPRINT '\1' /* Emergency non-printable character. */
|
||||
int noprint; /* Cached, unprintable character. */
|
||||
|
||||
char *c_option; /* Ex initial, command-line command. */
|
||||
|
||||
#ifdef DEBUG
|
||||
FILE *tracefp; /* Trace file pointer. */
|
||||
#endif
|
||||
|
||||
#define MAX_BIT_SEQ 0x7f /* Max + 1 fast check character. */
|
||||
LIST_HEAD(_seqh, _seq) seqq; /* Linked list of maps, abbrevs. */
|
||||
bitstr_t bit_decl(seqb, MAX_BIT_SEQ + 1);
|
||||
|
||||
#define MAX_FAST_KEY 0xff /* Max fast check character.*/
|
||||
#define KEY_LEN(sp, ch) \
|
||||
(((ch) & ~MAX_FAST_KEY) == 0 ? \
|
||||
sp->gp->cname[(unsigned char)ch].len : v_key_len(sp, ch))
|
||||
#define KEY_NAME(sp, ch) \
|
||||
(((ch) & ~MAX_FAST_KEY) == 0 ? \
|
||||
sp->gp->cname[(unsigned char)ch].name : v_key_name(sp, ch))
|
||||
struct {
|
||||
u_char name[MAX_CHARACTER_COLUMNS + 1];
|
||||
u_int8_t len;
|
||||
} cname[MAX_FAST_KEY + 1]; /* Fast lookup table. */
|
||||
|
||||
#define KEY_VAL(sp, ch) \
|
||||
(((ch) & ~MAX_FAST_KEY) == 0 ? \
|
||||
sp->gp->special_key[(unsigned char)ch] : v_key_val(sp,ch))
|
||||
e_key_t /* Fast lookup table. */
|
||||
special_key[MAX_FAST_KEY + 1];
|
||||
|
||||
/* Flags. */
|
||||
#define G_ABBREV 0x0001 /* If have abbreviations. */
|
||||
#define G_BELLSCHED 0x0002 /* Bell scheduled. */
|
||||
#define G_INTERRUPTED 0x0004 /* Interrupted. */
|
||||
#define G_RECOVER_SET 0x0008 /* Recover system initialized. */
|
||||
#define G_SCRIPTED 0x0010 /* Ex script session. */
|
||||
#define G_SCRWIN 0x0020 /* Scripting windows running. */
|
||||
#define G_SNAPSHOT 0x0040 /* Always snapshot files. */
|
||||
#define G_SRESTART 0x0080 /* Screen restarted. */
|
||||
u_int32_t flags;
|
||||
|
||||
/* Screen interface functions. */
|
||||
/* Add a string to the screen. */
|
||||
int (*scr_addstr) __P((SCR *, const char *, size_t));
|
||||
/* Add a string to the screen. */
|
||||
int (*scr_waddstr) __P((SCR *, const CHAR_T *, size_t));
|
||||
/* Toggle a screen attribute. */
|
||||
int (*scr_attr) __P((SCR *, scr_attr_t, int));
|
||||
/* Terminal baud rate. */
|
||||
int (*scr_baud) __P((SCR *, u_long *));
|
||||
/* Beep/bell/flash the terminal. */
|
||||
int (*scr_bell) __P((SCR *));
|
||||
/* Display a busy message. */
|
||||
void (*scr_busy) __P((SCR *, const char *, busy_t));
|
||||
/* Prepare child. */
|
||||
int (*scr_child) __P((SCR *));
|
||||
/* Clear to the end of the line. */
|
||||
int (*scr_clrtoeol) __P((SCR *));
|
||||
/* Return the cursor location. */
|
||||
int (*scr_cursor) __P((SCR *, size_t *, size_t *));
|
||||
/* Delete a line. */
|
||||
int (*scr_deleteln) __P((SCR *));
|
||||
/* Discard a screen. */
|
||||
int (*scr_discard) __P((SCR *, SCR **));
|
||||
/* Get a keyboard event. */
|
||||
int (*scr_event) __P((SCR *, EVENT *, u_int32_t, int));
|
||||
/* Ex: screen adjustment routine. */
|
||||
int (*scr_ex_adjust) __P((SCR *, exadj_t));
|
||||
int (*scr_fmap) /* Set a function key. */
|
||||
__P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
|
||||
/* Get terminal key value. */
|
||||
int (*scr_keyval) __P((SCR *, scr_keyval_t, CHAR_T *, int *));
|
||||
/* Insert a line. */
|
||||
int (*scr_insertln) __P((SCR *));
|
||||
/* Handle an option change. */
|
||||
int (*scr_optchange) __P((SCR *, int, const char *, u_long *));
|
||||
/* Move the cursor. */
|
||||
int (*scr_move) __P((SCR *, size_t, size_t));
|
||||
/* Refresh the screen. */
|
||||
int (*scr_refresh) __P((SCR *, int));
|
||||
/* Rename the file. */
|
||||
int (*scr_rename) __P((SCR *, char *, int));
|
||||
/* Reply to an event. */
|
||||
int (*scr_reply) __P((SCR *, int, char *));
|
||||
/* Set the screen type. */
|
||||
int (*scr_screen) __P((SCR *, u_int32_t));
|
||||
/* Split the screen. */
|
||||
int (*scr_split) __P((SCR *, SCR *));
|
||||
/* Suspend the editor. */
|
||||
int (*scr_suspend) __P((SCR *, int *));
|
||||
/* Print usage message. */
|
||||
void (*scr_usage) __P((void));
|
||||
|
||||
/* Threading stuff */
|
||||
void *th_private;
|
||||
|
||||
int (*run) __P((WIN *, void *(*)(void*), void *));
|
||||
|
||||
int (*lock_init) __P((WIN *, void **));
|
||||
#define LOCK_INIT(wp,s) \
|
||||
wp->gp->lock_init(wp, &s->lock)
|
||||
int (*lock_try) __P((WIN *, void **));
|
||||
#define LOCK_TRY(wp,s) \
|
||||
wp->gp->lock_try(wp, &s->lock)
|
||||
int (*lock_unlock) __P((WIN *, void **));
|
||||
#define LOCK_UNLOCK(wp,s) \
|
||||
wp->gp->lock_unlock(wp, &s->lock)
|
||||
int (*lock_end) __P((WIN *, void **));
|
||||
#define LOCK_END(wp,s) \
|
||||
wp->gp->lock_end(wp, &s->lock)
|
||||
};
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Block signals if there are asynchronous events. Used to keep DB system calls
|
||||
* from being interrupted and not restarted, as that will result in consistency
|
||||
* problems. This should be handled by DB.
|
||||
*/
|
||||
#ifdef BLOCK_SIGNALS
|
||||
#include <signal.h>
|
||||
extern sigset_t __sigblockset;
|
||||
#define SIGBLOCK \
|
||||
(void)sigprocmask(SIG_BLOCK, &__sigblockset, NULL)
|
||||
#define SIGUNBLOCK \
|
||||
(void)sigprocmask(SIG_UNBLOCK, &__sigblockset, NULL);
|
||||
#else
|
||||
#define SIGBLOCK
|
||||
#define SIGUNBLOCK
|
||||
#endif
|
||||
844
dist/nvi/common/key.c
vendored
Normal file
844
dist/nvi/common/key.c
vendored
Normal file
@@ -0,0 +1,844 @@
|
||||
/* $NetBSD: key.c,v 1.6 2011/03/21 14:53:02 tnozaki 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: key.c,v 10.48 2001/06/25 15:19:10 skimo Exp (Berkeley) Date: 2001/06/25 15:19:10";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "../vi/vi.h"
|
||||
|
||||
static int v_event_append __P((SCR *, EVENT *));
|
||||
static int v_event_grow __P((SCR *, int));
|
||||
static int v_key_cmp __P((const void *, const void *));
|
||||
static void v_keyval __P((SCR *, int, scr_keyval_t));
|
||||
static void v_sync __P((SCR *, int));
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Historic vi always used:
|
||||
*
|
||||
* ^D: autoindent deletion
|
||||
* ^H: last character deletion
|
||||
* ^W: last word deletion
|
||||
* ^Q: quote the next character (if not used in flow control).
|
||||
* ^V: quote the next character
|
||||
*
|
||||
* regardless of the user's choices for these characters. The user's erase
|
||||
* and kill characters worked in addition to these characters. Nvi wires
|
||||
* down the above characters, but in addition permits the VEOF, VERASE, VKILL
|
||||
* and VWERASE characters described by the user's termios structure.
|
||||
*
|
||||
* Ex was not consistent with this scheme, as it historically ran in tty
|
||||
* cooked mode. This meant that the scroll command and autoindent erase
|
||||
* characters were mapped to the user's EOF character, and the character
|
||||
* and word deletion characters were the user's tty character and word
|
||||
* deletion characters. This implementation makes it all consistent, as
|
||||
* described above for vi.
|
||||
*
|
||||
* !!!
|
||||
* This means that all screens share a special key set.
|
||||
*/
|
||||
KEYLIST keylist[] = {
|
||||
{K_BACKSLASH, '\\'}, /* \ */
|
||||
{K_CARAT, '^'}, /* ^ */
|
||||
{K_CNTRLD, '\004'}, /* ^D */
|
||||
{K_CNTRLR, '\022'}, /* ^R */
|
||||
{K_CNTRLT, '\024'}, /* ^T */
|
||||
{K_CNTRLZ, '\032'}, /* ^Z */
|
||||
{K_COLON, ':'}, /* : */
|
||||
{K_CR, '\r'}, /* \r */
|
||||
{K_ESCAPE, '\033'}, /* ^[ */
|
||||
{K_FORMFEED, '\f'}, /* \f */
|
||||
{K_HEXCHAR, '\030'}, /* ^X */
|
||||
{K_NL, '\n'}, /* \n */
|
||||
{K_RIGHTBRACE, '}'}, /* } */
|
||||
{K_RIGHTPAREN, ')'}, /* ) */
|
||||
{K_TAB, '\t'}, /* \t */
|
||||
{K_VERASE, '\b'}, /* \b */
|
||||
{K_VKILL, '\025'}, /* ^U */
|
||||
{K_VLNEXT, '\021'}, /* ^Q */
|
||||
{K_VLNEXT, '\026'}, /* ^V */
|
||||
{K_VWERASE, '\027'}, /* ^W */
|
||||
{K_ZERO, '0'}, /* 0 */
|
||||
|
||||
#define ADDITIONAL_CHARACTERS 4
|
||||
{K_NOTUSED, 0}, /* VEOF, VERASE, VKILL, VWERASE */
|
||||
{K_NOTUSED, 0},
|
||||
{K_NOTUSED, 0},
|
||||
{K_NOTUSED, 0},
|
||||
};
|
||||
static int nkeylist =
|
||||
(sizeof(keylist) / sizeof(keylist[0])) - ADDITIONAL_CHARACTERS;
|
||||
|
||||
/*
|
||||
* v_key_init --
|
||||
* Initialize the special key lookup table.
|
||||
*
|
||||
* PUBLIC: int v_key_init __P((SCR *));
|
||||
*/
|
||||
int
|
||||
v_key_init(SCR *sp)
|
||||
{
|
||||
int ch;
|
||||
GS *gp;
|
||||
KEYLIST *kp;
|
||||
int cnt;
|
||||
|
||||
gp = sp->gp;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* 8-bit only, for now. Recompilation should get you any 8-bit
|
||||
* character set, as long as nul isn't a character.
|
||||
*/
|
||||
(void)setlocale(LC_ALL, "");
|
||||
#if __linux__
|
||||
/*
|
||||
* In libc 4.5.26, setlocale(LC_ALL, ""), doesn't setup the table
|
||||
* for ctype(3c) correctly. This bug is fixed in libc 4.6.x.
|
||||
*
|
||||
* This code works around this problem for libc 4.5.x users.
|
||||
* Note that this code is harmless if you're using libc 4.6.x.
|
||||
*/
|
||||
(void)setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
v_key_ilookup(sp);
|
||||
|
||||
v_keyval(sp, K_CNTRLD, KEY_VEOF);
|
||||
v_keyval(sp, K_VERASE, KEY_VERASE);
|
||||
v_keyval(sp, K_VKILL, KEY_VKILL);
|
||||
v_keyval(sp, K_VWERASE, KEY_VWERASE);
|
||||
|
||||
/* Sort the special key list. */
|
||||
qsort(keylist, nkeylist, sizeof(keylist[0]), v_key_cmp);
|
||||
|
||||
/* Initialize the fast lookup table. */
|
||||
for (kp = keylist, cnt = nkeylist; cnt--; ++kp)
|
||||
gp->special_key[kp->ch] = kp->value;
|
||||
|
||||
/* Find a non-printable character to use as a message separator. */
|
||||
for (ch = 1; ch <= UCHAR_MAX; ++ch)
|
||||
if (!isprint(ch)) {
|
||||
gp->noprint = ch;
|
||||
break;
|
||||
}
|
||||
if (ch != gp->noprint) {
|
||||
msgq(sp, M_ERR, "079|No non-printable character found");
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_keyval --
|
||||
* Set key values.
|
||||
*
|
||||
* We've left some open slots in the keylist table, and if these values exist,
|
||||
* we put them into place. Note, they may reset (or duplicate) values already
|
||||
* in the table, so we check for that first.
|
||||
*/
|
||||
static void
|
||||
v_keyval(SCR *sp, int val, scr_keyval_t name)
|
||||
{
|
||||
KEYLIST *kp;
|
||||
CHAR_T ch;
|
||||
int dne;
|
||||
|
||||
/* Get the key's value from the screen. */
|
||||
if (sp->gp->scr_keyval(sp, name, &ch, &dne))
|
||||
return;
|
||||
if (dne)
|
||||
return;
|
||||
|
||||
/* Check for duplication. */
|
||||
for (kp = keylist; kp->value != K_NOTUSED; ++kp)
|
||||
if (kp->ch == ch) {
|
||||
kp->value = val;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add a new entry. */
|
||||
if (kp->value == K_NOTUSED) {
|
||||
keylist[nkeylist].ch = ch;
|
||||
keylist[nkeylist].value = val;
|
||||
++nkeylist;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* v_key_ilookup --
|
||||
* Build the fast-lookup key display array.
|
||||
*
|
||||
* PUBLIC: void v_key_ilookup __P((SCR *));
|
||||
*/
|
||||
void
|
||||
v_key_ilookup(SCR *sp)
|
||||
{
|
||||
UCHAR_T ch;
|
||||
unsigned char *p, *t;
|
||||
GS *gp;
|
||||
size_t len;
|
||||
|
||||
for (gp = sp->gp, ch = 0;; ++ch) {
|
||||
for (p = gp->cname[ch].name, t = v_key_name(sp, ch),
|
||||
len = gp->cname[ch].len = sp->clen; len--;)
|
||||
*p++ = *t++;
|
||||
if (ch == MAX_FAST_KEY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* v_key_len --
|
||||
* Return the length of the string that will display the key.
|
||||
* This routine is the backup for the KEY_LEN() macro.
|
||||
*
|
||||
* PUBLIC: size_t v_key_len __P((SCR *, ARG_CHAR_T));
|
||||
*/
|
||||
size_t
|
||||
v_key_len(SCR *sp, ARG_CHAR_T ch)
|
||||
{
|
||||
(void)v_key_name(sp, ch);
|
||||
return (sp->clen);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_key_name --
|
||||
* Return the string that will display the key. This routine
|
||||
* is the backup for the KEY_NAME() macro.
|
||||
*
|
||||
* PUBLIC: u_char *v_key_name __P((SCR *, ARG_CHAR_T));
|
||||
*/
|
||||
u_char *
|
||||
v_key_name(SCR *sp, ARG_CHAR_T ach)
|
||||
{
|
||||
static const char hexdigit[] = "0123456789abcdef";
|
||||
static const char octdigit[] = "01234567";
|
||||
int ch;
|
||||
size_t len, i;
|
||||
const char *chp;
|
||||
|
||||
if (INTISWIDE(ach))
|
||||
goto vis;
|
||||
ch = (unsigned char)ach;
|
||||
|
||||
/* See if the character was explicitly declared printable or not. */
|
||||
if ((chp = O_STR(sp, O_PRINT)) != NULL)
|
||||
for (; *chp != '\0'; ++chp)
|
||||
if (*chp == ch)
|
||||
goto pr;
|
||||
if ((chp = O_STR(sp, O_NOPRINT)) != NULL)
|
||||
for (; *chp != '\0'; ++chp)
|
||||
if (*chp == ch)
|
||||
goto nopr;
|
||||
|
||||
/*
|
||||
* Historical (ARPA standard) mappings. Printable characters are left
|
||||
* alone. Control characters less than 0x20 are represented as '^'
|
||||
* followed by the character offset from the '@' character in the ASCII
|
||||
* character set. Del (0x7f) is represented as '^' followed by '?'.
|
||||
*
|
||||
* XXX
|
||||
* The following code depends on the current locale being identical to
|
||||
* the ASCII map from 0x40 to 0x5f (since 0x1f + 0x40 == 0x5f). I'm
|
||||
* told that this is a reasonable assumption...
|
||||
*
|
||||
* XXX
|
||||
* This code will only work with CHAR_T's that are multiples of 8-bit
|
||||
* bytes.
|
||||
*
|
||||
* XXX
|
||||
* NB: There's an assumption here that all printable characters take
|
||||
* up a single column on the screen. This is not always correct.
|
||||
*/
|
||||
if (isprint(ch)) {
|
||||
pr: sp->cname[0] = ch;
|
||||
len = 1;
|
||||
goto done;
|
||||
}
|
||||
nopr: if (iscntrl(ch) && (ch < 0x20 || ch == 0x7f)) {
|
||||
sp->cname[0] = '^';
|
||||
sp->cname[1] = ch == 0x7f ? '?' : '@' + ch;
|
||||
len = 2;
|
||||
goto done;
|
||||
}
|
||||
vis: for (i = 1; i <= sizeof(CHAR_T); ++i)
|
||||
if ((ach >> i * CHAR_BIT) == 0)
|
||||
break;
|
||||
ch = (ach >> --i * CHAR_BIT) & UCHAR_MAX;
|
||||
if (O_ISSET(sp, O_OCTAL)) {
|
||||
sp->cname[0] = '\\';
|
||||
sp->cname[1] = octdigit[(ch & 0300) >> 6];
|
||||
sp->cname[2] = octdigit[(ch & 070) >> 3];
|
||||
sp->cname[3] = octdigit[ ch & 07 ];
|
||||
} else {
|
||||
sp->cname[0] = '\\';
|
||||
sp->cname[1] = 'x';
|
||||
sp->cname[2] = hexdigit[(ch & 0xf0) >> 4];
|
||||
sp->cname[3] = hexdigit[ ch & 0x0f ];
|
||||
}
|
||||
len = 4;
|
||||
done: sp->cname[sp->clen = len] = '\0';
|
||||
return (sp->cname);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_key_val --
|
||||
* Fill in the value for a key. This routine is the backup
|
||||
* for the KEY_VAL() macro.
|
||||
*
|
||||
* PUBLIC: int v_key_val __P((SCR *, ARG_CHAR_T));
|
||||
*/
|
||||
e_key_t
|
||||
v_key_val(SCR *sp, ARG_CHAR_T ch)
|
||||
{
|
||||
KEYLIST k, *kp;
|
||||
|
||||
k.ch = ch;
|
||||
kp = bsearch(&k, keylist, nkeylist, sizeof(keylist[0]), v_key_cmp);
|
||||
return (kp == NULL ? K_NOTUSED : kp->value);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_event_push --
|
||||
* Push events/keys onto the front of the buffer.
|
||||
*
|
||||
* There is a single input buffer in ex/vi. Characters are put onto the
|
||||
* end of the buffer by the terminal input routines, and pushed onto the
|
||||
* front of the buffer by various other functions in ex/vi. Each key has
|
||||
* an associated flag value, which indicates if it has already been quoted,
|
||||
* and if it is the result of a mapping or an abbreviation.
|
||||
*
|
||||
* PUBLIC: int v_event_push __P((SCR *, EVENT *, const CHAR_T *, size_t, u_int));
|
||||
*/
|
||||
int
|
||||
v_event_push(SCR *sp, EVENT *p_evp, const CHAR_T *p_s, size_t nitems, u_int flags)
|
||||
|
||||
/* Push event. */
|
||||
/* Push characters. */
|
||||
/* Number of items to push. */
|
||||
/* CH_* flags. */
|
||||
{
|
||||
EVENT *evp;
|
||||
GS *gp;
|
||||
WIN *wp;
|
||||
size_t total;
|
||||
|
||||
/* If we have room, stuff the items into the buffer. */
|
||||
gp = sp->gp;
|
||||
wp = sp->wp;
|
||||
if (nitems <= wp->i_next ||
|
||||
(wp->i_event != NULL && wp->i_cnt == 0 && nitems <= wp->i_nelem)) {
|
||||
if (wp->i_cnt != 0)
|
||||
wp->i_next -= nitems;
|
||||
goto copy;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are currently items in the queue, shift them up,
|
||||
* leaving some extra room. Get enough space plus a little
|
||||
* extra.
|
||||
*/
|
||||
#define TERM_PUSH_SHIFT 30
|
||||
total = wp->i_cnt + wp->i_next + nitems + TERM_PUSH_SHIFT;
|
||||
if (total >= wp->i_nelem && v_event_grow(sp, MAX(total, 64)))
|
||||
return (1);
|
||||
if (wp->i_cnt)
|
||||
MEMMOVE(wp->i_event + TERM_PUSH_SHIFT + nitems,
|
||||
wp->i_event + wp->i_next, wp->i_cnt);
|
||||
wp->i_next = TERM_PUSH_SHIFT;
|
||||
|
||||
/* Put the new items into the queue. */
|
||||
copy: wp->i_cnt += nitems;
|
||||
for (evp = wp->i_event + wp->i_next; nitems--; ++evp) {
|
||||
if (p_evp != NULL)
|
||||
*evp = *p_evp++;
|
||||
else {
|
||||
evp->e_event = E_CHARACTER;
|
||||
evp->e_c = *p_s++;
|
||||
evp->e_value = KEY_VAL(sp, evp->e_c);
|
||||
FL_INIT(evp->e_flags, flags);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_event_append --
|
||||
* Append events onto the tail of the buffer.
|
||||
*/
|
||||
static int
|
||||
v_event_append(SCR *sp, EVENT *argp)
|
||||
{
|
||||
CHAR_T *s; /* Characters. */
|
||||
EVENT *evp;
|
||||
WIN *wp;
|
||||
size_t nevents; /* Number of events. */
|
||||
|
||||
/* Grow the buffer as necessary. */
|
||||
nevents = argp->e_event == E_STRING ? argp->e_len : 1;
|
||||
wp = sp->wp;
|
||||
if (wp->i_event == NULL ||
|
||||
nevents > wp->i_nelem - (wp->i_next + wp->i_cnt))
|
||||
v_event_grow(sp, MAX(nevents, 64));
|
||||
evp = wp->i_event + wp->i_next + wp->i_cnt;
|
||||
wp->i_cnt += nevents;
|
||||
|
||||
/* Transform strings of characters into single events. */
|
||||
if (argp->e_event == E_STRING)
|
||||
for (s = argp->e_csp; nevents--; ++evp) {
|
||||
evp->e_event = E_CHARACTER;
|
||||
evp->e_c = *s++;
|
||||
evp->e_value = KEY_VAL(sp, evp->e_c);
|
||||
evp->e_flags = 0;
|
||||
}
|
||||
else
|
||||
*evp = *argp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Remove events from the queue. */
|
||||
#define QREM(len) { \
|
||||
if ((wp->i_cnt -= len) == 0) \
|
||||
wp->i_next = 0; \
|
||||
else \
|
||||
wp->i_next += len; \
|
||||
}
|
||||
|
||||
/*
|
||||
* v_event_get --
|
||||
* Return the next event.
|
||||
*
|
||||
* !!!
|
||||
* The flag EC_NODIGIT probably needs some explanation. First, the idea of
|
||||
* mapping keys is that one or more keystrokes act like a function key.
|
||||
* What's going on is that vi is reading a number, and the character following
|
||||
* the number may or may not be mapped (EC_MAPCOMMAND). For example, if the
|
||||
* user is entering the z command, a valid command is "z40+", and we don't want
|
||||
* to map the '+', i.e. if '+' is mapped to "xxx", we don't want to change it
|
||||
* into "z40xxx". However, if the user enters "35x", we want to put all of the
|
||||
* characters through the mapping code.
|
||||
*
|
||||
* Historical practice is a bit muddled here. (Surprise!) It always permitted
|
||||
* mapping digits as long as they weren't the first character of the map, e.g.
|
||||
* ":map ^A1 xxx" was okay. It also permitted the mapping of the digits 1-9
|
||||
* (the digit 0 was a special case as it doesn't indicate the start of a count)
|
||||
* as the first character of the map, but then ignored those mappings. While
|
||||
* it's probably stupid to map digits, vi isn't your mother.
|
||||
*
|
||||
* The way this works is that the EC_MAPNODIGIT causes term_key to return the
|
||||
* end-of-digit without "looking" at the next character, i.e. leaving it as the
|
||||
* user entered it. Presumably, the next term_key call will tell us how the
|
||||
* user wants it handled.
|
||||
*
|
||||
* There is one more complication. Users might map keys to digits, and, as
|
||||
* it's described above, the commands:
|
||||
*
|
||||
* :map g 1G
|
||||
* d2g
|
||||
*
|
||||
* would return the keys "d2<end-of-digits>1G", when the user probably wanted
|
||||
* "d21<end-of-digits>G". So, if a map starts off with a digit we continue as
|
||||
* before, otherwise, we pretend we haven't mapped the character, and return
|
||||
* <end-of-digits>.
|
||||
*
|
||||
* Now that that's out of the way, let's talk about Energizer Bunny macros.
|
||||
* It's easy to create macros that expand to a loop, e.g. map x 3x. It's
|
||||
* fairly easy to detect this example, because it's all internal to term_key.
|
||||
* If we're expanding a macro and it gets big enough, at some point we can
|
||||
* assume it's looping and kill it. The examples that are tough are the ones
|
||||
* where the parser is involved, e.g. map x "ayyx"byy. We do an expansion
|
||||
* on 'x', and get "ayyx"byy. We then return the first 4 characters, and then
|
||||
* find the looping macro again. There is no way that we can detect this
|
||||
* without doing a full parse of the command, because the character that might
|
||||
* cause the loop (in this case 'x') may be a literal character, e.g. the map
|
||||
* map x "ayy"xyy"byy is perfectly legal and won't cause a loop.
|
||||
*
|
||||
* Historic vi tried to detect looping macros by disallowing obvious cases in
|
||||
* the map command, maps that that ended with the same letter as they started
|
||||
* (which wrongly disallowed "map x 'x"), and detecting macros that expanded
|
||||
* too many times before keys were returned to the command parser. It didn't
|
||||
* get many (most?) of the tricky cases right, however, and it was certainly
|
||||
* possible to create macros that ran forever. And, even if it did figure out
|
||||
* what was going on, the user was usually tossed into ex mode. Finally, any
|
||||
* changes made before vi realized that the macro was recursing were left in
|
||||
* place. We recover gracefully, but the only recourse the user has in an
|
||||
* infinite macro loop is to interrupt.
|
||||
*
|
||||
* !!!
|
||||
* It is historic practice that mapping characters to themselves as the first
|
||||
* part of the mapped string was legal, and did not cause infinite loops, i.e.
|
||||
* ":map! { {^M^T" and ":map n nz." were known to work. The initial, matching
|
||||
* characters were returned instead of being remapped.
|
||||
*
|
||||
* !!!
|
||||
* It is also historic practice that the macro "map ] ]]^" caused a single ]
|
||||
* keypress to behave as the command ]] (the ^ got the map past the vi check
|
||||
* for "tail recursion"). Conversely, the mapping "map n nn^" went recursive.
|
||||
* What happened was that, in the historic vi, maps were expanded as the keys
|
||||
* were retrieved, but not all at once and not centrally. So, the keypress ]
|
||||
* pushed ]]^ on the stack, and then the first ] from the stack was passed to
|
||||
* the ]] command code. The ]] command then retrieved a key without entering
|
||||
* the mapping code. This could bite us anytime a user has a map that depends
|
||||
* on secondary keys NOT being mapped. I can't see any possible way to make
|
||||
* this work in here without the complete abandonment of Rationality Itself.
|
||||
*
|
||||
* XXX
|
||||
* The final issue is recovery. It would be possible to undo all of the work
|
||||
* that was done by the macro if we entered a record into the log so that we
|
||||
* knew when the macro started, and, in fact, this might be worth doing at some
|
||||
* point. Given that this might make the log grow unacceptably (consider that
|
||||
* cursor keys are done with maps), for now we leave any changes made in place.
|
||||
*
|
||||
* PUBLIC: int v_event_get __P((SCR *, EVENT *, int, u_int32_t));
|
||||
*/
|
||||
int
|
||||
v_event_get(SCR *sp, EVENT *argp, int timeout, u_int32_t flags)
|
||||
{
|
||||
EVENT *evp, ev;
|
||||
GS *gp;
|
||||
SEQ *qp;
|
||||
int init_nomap, ispartial, istimeout, remap_cnt;
|
||||
WIN *wp;
|
||||
|
||||
gp = sp->gp;
|
||||
wp = sp->wp;
|
||||
|
||||
/* If simply checking for interrupts, argp may be NULL. */
|
||||
if (argp == NULL)
|
||||
argp = &ev;
|
||||
|
||||
retry: istimeout = remap_cnt = 0;
|
||||
|
||||
/*
|
||||
* If the queue isn't empty and we're timing out for characters,
|
||||
* return immediately.
|
||||
*/
|
||||
if (wp->i_cnt != 0 && LF_ISSET(EC_TIMEOUT))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If the queue is empty, we're checking for interrupts, or we're
|
||||
* timing out for characters, get more events.
|
||||
*/
|
||||
if (wp->i_cnt == 0 || LF_ISSET(EC_INTERRUPT | EC_TIMEOUT)) {
|
||||
/*
|
||||
* If we're reading new characters, check any scripting
|
||||
* windows for input.
|
||||
*/
|
||||
if (F_ISSET(gp, G_SCRWIN) && sscr_input(sp))
|
||||
return (1);
|
||||
loop: if (gp->scr_event(sp, argp,
|
||||
LF_ISSET(EC_INTERRUPT | EC_QUOTED | EC_RAW), timeout))
|
||||
return (1);
|
||||
switch (argp->e_event) {
|
||||
case E_ERR:
|
||||
case E_SIGHUP:
|
||||
case E_SIGTERM:
|
||||
/*
|
||||
* Fatal conditions cause the file to be synced to
|
||||
* disk immediately.
|
||||
*/
|
||||
v_sync(sp, RCV_ENDSESSION | RCV_PRESERVE |
|
||||
(argp->e_event == E_SIGTERM ? 0: RCV_EMAIL));
|
||||
return (1);
|
||||
case E_TIMEOUT:
|
||||
istimeout = 1;
|
||||
break;
|
||||
case E_INTERRUPT:
|
||||
/* Set the global interrupt flag. */
|
||||
F_SET(sp->gp, G_INTERRUPTED);
|
||||
|
||||
/*
|
||||
* If the caller was interested in interrupts, return
|
||||
* immediately.
|
||||
*/
|
||||
if (LF_ISSET(EC_INTERRUPT))
|
||||
return (0);
|
||||
goto append;
|
||||
default:
|
||||
append: if (v_event_append(sp, argp))
|
||||
return (1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the caller was only interested in interrupts or timeouts, return
|
||||
* immediately. (We may have gotten characters, and that's okay, they
|
||||
* were queued up for later use.)
|
||||
*/
|
||||
if (LF_ISSET(EC_INTERRUPT | EC_TIMEOUT))
|
||||
return (0);
|
||||
|
||||
newmap: evp = &wp->i_event[wp->i_next];
|
||||
|
||||
/*
|
||||
* If the next event in the queue isn't a character event, return
|
||||
* it, we're done.
|
||||
*/
|
||||
if (evp->e_event != E_CHARACTER) {
|
||||
*argp = *evp;
|
||||
QREM(1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the key isn't mappable because:
|
||||
*
|
||||
* + ... the timeout has expired
|
||||
* + ... it's not a mappable key
|
||||
* + ... neither the command or input map flags are set
|
||||
* + ... there are no maps that can apply to it
|
||||
*
|
||||
* return it forthwith.
|
||||
*/
|
||||
if (istimeout || FL_ISSET(evp->e_flags, CH_NOMAP) ||
|
||||
!LF_ISSET(EC_MAPCOMMAND | EC_MAPINPUT) ||
|
||||
((evp->e_c & ~MAX_BIT_SEQ) == 0 &&
|
||||
!bit_test(gp->seqb, evp->e_c)))
|
||||
goto nomap;
|
||||
|
||||
/* Search the map. */
|
||||
qp = seq_find(sp, NULL, evp, NULL, wp->i_cnt,
|
||||
LF_ISSET(EC_MAPCOMMAND) ? SEQ_COMMAND : SEQ_INPUT, &ispartial);
|
||||
|
||||
/*
|
||||
* If get a partial match, get more characters and retry the map.
|
||||
* If time out without further characters, return the characters
|
||||
* unmapped.
|
||||
*
|
||||
* !!!
|
||||
* <escape> characters are a problem. Cursor keys start with <escape>
|
||||
* characters, so there's almost always a map in place that begins with
|
||||
* an <escape> character. If we timeout <escape> keys in the same way
|
||||
* that we timeout other keys, the user will get a noticeable pause as
|
||||
* they enter <escape> to terminate input mode. If key timeout is set
|
||||
* for a slow link, users will get an even longer pause. Nvi used to
|
||||
* simply timeout <escape> characters at 1/10th of a second, but this
|
||||
* loses over PPP links where the latency is greater than 100Ms.
|
||||
*/
|
||||
if (ispartial) {
|
||||
if (O_ISSET(sp, O_TIMEOUT))
|
||||
timeout = (evp->e_value == K_ESCAPE ?
|
||||
O_VAL(sp, O_ESCAPETIME) :
|
||||
O_VAL(sp, O_KEYTIME)) * 100;
|
||||
else
|
||||
timeout = 0;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/* If no map, return the character. */
|
||||
if (qp == NULL) {
|
||||
nomap: if (!ISDIGIT(evp->e_c) && LF_ISSET(EC_MAPNODIGIT))
|
||||
goto not_digit;
|
||||
*argp = *evp;
|
||||
QREM(1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If looking for the end of a digit string, and the first character
|
||||
* of the map is it, pretend we haven't seen the character.
|
||||
*/
|
||||
if (LF_ISSET(EC_MAPNODIGIT) &&
|
||||
qp->output != NULL && !ISDIGIT(qp->output[0])) {
|
||||
not_digit: argp->e_c = CH_NOT_DIGIT;
|
||||
argp->e_value = K_NOTUSED;
|
||||
argp->e_event = E_CHARACTER;
|
||||
FL_INIT(argp->e_flags, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Find out if the initial segments are identical. */
|
||||
init_nomap = !e_memcmp(qp->output, &wp->i_event[wp->i_next], qp->ilen);
|
||||
|
||||
/* Delete the mapped characters from the queue. */
|
||||
QREM(qp->ilen);
|
||||
|
||||
/* If keys mapped to nothing, go get more. */
|
||||
if (qp->output == NULL)
|
||||
goto retry;
|
||||
|
||||
/* If remapping characters... */
|
||||
if (O_ISSET(sp, O_REMAP)) {
|
||||
/*
|
||||
* Periodically check for interrupts. Always check the first
|
||||
* time through, because it's possible to set up a map that
|
||||
* will return a character every time, but will expand to more,
|
||||
* e.g. "map! a aaaa" will always return a 'a', but we'll never
|
||||
* get anywhere useful.
|
||||
*/
|
||||
if ((++remap_cnt == 1 || remap_cnt % 10 == 0) &&
|
||||
(gp->scr_event(sp, &ev,
|
||||
EC_INTERRUPT, 0) || ev.e_event == E_INTERRUPT)) {
|
||||
F_SET(sp->gp, G_INTERRUPTED);
|
||||
argp->e_event = E_INTERRUPT;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If an initial part of the characters mapped, they are not
|
||||
* further remapped -- return the first one. Push the rest
|
||||
* of the characters, or all of the characters if no initial
|
||||
* part mapped, back on the queue.
|
||||
*/
|
||||
if (init_nomap) {
|
||||
if (v_event_push(sp, NULL, qp->output + qp->ilen,
|
||||
qp->olen - qp->ilen, CH_MAPPED))
|
||||
return (1);
|
||||
if (v_event_push(sp, NULL,
|
||||
qp->output, qp->ilen, CH_NOMAP | CH_MAPPED))
|
||||
return (1);
|
||||
evp = &wp->i_event[wp->i_next];
|
||||
goto nomap;
|
||||
}
|
||||
if (v_event_push(sp, NULL, qp->output, qp->olen, CH_MAPPED))
|
||||
return (1);
|
||||
goto newmap;
|
||||
}
|
||||
|
||||
/* Else, push the characters on the queue and return one. */
|
||||
if (v_event_push(sp, NULL, qp->output, qp->olen, CH_MAPPED | CH_NOMAP))
|
||||
return (1);
|
||||
|
||||
goto nomap;
|
||||
}
|
||||
|
||||
/*
|
||||
* v_sync --
|
||||
* Walk the screen lists, sync'ing files to their backup copies.
|
||||
*/
|
||||
static void
|
||||
v_sync(SCR *sp, int flags)
|
||||
{
|
||||
GS *gp;
|
||||
WIN *wp;
|
||||
|
||||
gp = sp->gp;
|
||||
for (wp = gp->dq.cqh_first; wp != (void *)&gp->dq;
|
||||
wp = wp->q.cqe_next)
|
||||
for (sp = wp->scrq.cqh_first; sp != (void *)&wp->scrq;
|
||||
sp = sp->q.cqe_next)
|
||||
rcv_sync(sp, flags);
|
||||
for (sp = gp->hq.cqh_first; sp != (void *)&gp->hq; sp = sp->q.cqe_next)
|
||||
rcv_sync(sp, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_event_err --
|
||||
* Unexpected event.
|
||||
*
|
||||
* PUBLIC: void v_event_err __P((SCR *, EVENT *));
|
||||
*/
|
||||
void
|
||||
v_event_err(SCR *sp, EVENT *evp)
|
||||
{
|
||||
switch (evp->e_event) {
|
||||
case E_CHARACTER:
|
||||
msgq(sp, M_ERR, "276|Unexpected character event");
|
||||
break;
|
||||
case E_EOF:
|
||||
msgq(sp, M_ERR, "277|Unexpected end-of-file event");
|
||||
break;
|
||||
case E_INTERRUPT:
|
||||
msgq(sp, M_ERR, "279|Unexpected interrupt event");
|
||||
break;
|
||||
case E_IPCOMMAND:
|
||||
msgq(sp, M_ERR, "318|Unexpected command or input");
|
||||
break;
|
||||
case E_REPAINT:
|
||||
msgq(sp, M_ERR, "281|Unexpected repaint event");
|
||||
break;
|
||||
case E_STRING:
|
||||
msgq(sp, M_ERR, "285|Unexpected string event");
|
||||
break;
|
||||
case E_TIMEOUT:
|
||||
msgq(sp, M_ERR, "286|Unexpected timeout event");
|
||||
break;
|
||||
case E_WRESIZE:
|
||||
msgq(sp, M_ERR, "316|Unexpected resize event");
|
||||
break;
|
||||
|
||||
/*
|
||||
* Theoretically, none of these can occur, as they're handled at the
|
||||
* top editor level.
|
||||
*/
|
||||
case E_ERR:
|
||||
case E_SIGHUP:
|
||||
case E_SIGTERM:
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* v_event_flush --
|
||||
* Flush any flagged keys, returning if any keys were flushed.
|
||||
*
|
||||
* PUBLIC: int v_event_flush __P((SCR *, u_int));
|
||||
*/
|
||||
int
|
||||
v_event_flush(SCR *sp, u_int flags)
|
||||
{
|
||||
WIN *wp;
|
||||
int rval;
|
||||
|
||||
for (rval = 0, wp = sp->wp; wp->i_cnt != 0 &&
|
||||
FL_ISSET(wp->i_event[wp->i_next].e_flags, flags); rval = 1)
|
||||
QREM(1);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_event_grow --
|
||||
* Grow the terminal queue.
|
||||
*/
|
||||
static int
|
||||
v_event_grow(SCR *sp, int add)
|
||||
{
|
||||
WIN *wp;
|
||||
size_t new_nelem, olen;
|
||||
|
||||
wp = sp->wp;
|
||||
new_nelem = wp->i_nelem + add;
|
||||
olen = wp->i_nelem * sizeof(wp->i_event[0]);
|
||||
BINC_RET(sp, EVENT, wp->i_event, olen, new_nelem * sizeof(EVENT));
|
||||
wp->i_nelem = olen / sizeof(wp->i_event[0]);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_key_cmp --
|
||||
* Compare two keys for sorting.
|
||||
*/
|
||||
static int
|
||||
v_key_cmp(const void *ap, const void *bp)
|
||||
{
|
||||
return (((const KEYLIST *)ap)->ch - ((const KEYLIST *)bp)->ch);
|
||||
}
|
||||
229
dist/nvi/common/key.h
vendored
Normal file
229
dist/nvi/common/key.h
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/* $NetBSD: key.h,v 1.3 2011/11/14 13:29:07 tnozaki 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: key.h,v 10.50 2001/06/28 17:53:58 skimo Exp (Berkeley) Date: 2001/06/28 17:53:58
|
||||
*/
|
||||
|
||||
#include "multibyte.h"
|
||||
|
||||
#ifdef USE_WIDECHAR
|
||||
#define FILE2INT5(sp,buf,n,nlen,w,wlen) \
|
||||
sp->conv.file2int(sp, n, nlen, &buf, &wlen, &w)
|
||||
#define INT2FILE(sp,w,wlen,n,nlen) \
|
||||
sp->conv.int2file(sp, w, wlen, &sp->wp->cw, &nlen, &n)
|
||||
#define CHAR2INT5(sp,buf,n,nlen,w,wlen) \
|
||||
sp->conv.sys2int(sp, n, nlen, &buf, &wlen, &w)
|
||||
#define INT2CHAR(sp,w,wlen,n,nlen) \
|
||||
sp->conv.int2sys(sp, w, wlen, &sp->wp->cw, &nlen, &n)
|
||||
#define INT2SYS(sp,w,wlen,n,nlen) \
|
||||
sp->conv.int2sys(sp, w, wlen, &sp->wp->cw, &nlen, &n)
|
||||
#define INPUT2INT5(sp,cw,n,nlen,w,wlen) \
|
||||
sp->conv.input2int(sp, n, nlen, &(cw), &wlen, &w)
|
||||
#define CONST
|
||||
#define CHAR_WIDTH(sp, ch) wcwidth(ch)
|
||||
#define INTISWIDE(c) (wctob(c) == EOF) /* XXX wrong name */
|
||||
#else
|
||||
#define FILE2INT5(sp,buf,n,nlen,w,wlen) \
|
||||
(w = n, wlen = nlen, 0)
|
||||
#define INT2FILE(sp,w,wlen,n,nlen) \
|
||||
(n = w, nlen = wlen, 0)
|
||||
#define CHAR2INT5(sp,buf,n,nlen,w,wlen) \
|
||||
(w = n, wlen = nlen, 0)
|
||||
#define INT2CHAR(sp,w,wlen,n,nlen) \
|
||||
(n = w, nlen = wlen, 0)
|
||||
#define INT2SYS(sp,w,wlen,n,nlen) \
|
||||
(n = w, nlen = wlen, 0)
|
||||
#define INPUT2INT5(sp,buf,n,nlen,w,wlen) \
|
||||
(w = n, wlen = nlen, 0)
|
||||
#define CONST const
|
||||
#define INTISWIDE(c) 0
|
||||
#define CHAR_WIDTH(sp, ch) 1
|
||||
#endif
|
||||
#define FILE2INT(sp,n,nlen,w,wlen) \
|
||||
FILE2INT5(sp,sp->wp->cw,n,nlen,w,wlen)
|
||||
#define CHAR2INT(sp,n,nlen,w,wlen) \
|
||||
CHAR2INT5(sp,sp->wp->cw,n,nlen,w,wlen)
|
||||
|
||||
#define MEMCPYW(to, from, n) \
|
||||
memcpy(to, from, (n) * sizeof(CHAR_T))
|
||||
#define MEMMOVEW(to, from, n) \
|
||||
memmove(to, from, (n) * sizeof(CHAR_T))
|
||||
|
||||
/* The maximum number of columns any character can take up on a screen. */
|
||||
#define MAX_CHARACTER_COLUMNS 4
|
||||
|
||||
/*
|
||||
* Event types.
|
||||
*
|
||||
* The program structure depends on the event loop being able to return
|
||||
* E_EOF/E_ERR multiple times -- eventually enough things will end due
|
||||
* to the events that vi will reach the command level for the screen, at
|
||||
* which point the exit flags will be set and vi will exit.
|
||||
*/
|
||||
typedef enum {
|
||||
E_NOTUSED = 0, /* Not set. */
|
||||
E_CHARACTER, /* Input character: e_c set. */
|
||||
E_EOF, /* End of input (NOT ^D). */
|
||||
E_ERR, /* Input error. */
|
||||
E_INTERRUPT, /* Interrupt. */
|
||||
E_IPCOMMAND, /* IP command: e_ipcom set. */
|
||||
E_REPAINT, /* Repaint: e_flno, e_tlno set. */
|
||||
E_SIGHUP, /* SIGHUP. */
|
||||
E_SIGTERM, /* SIGTERM. */
|
||||
E_STRING, /* Input string: e_csp, e_len set. */
|
||||
E_TIMEOUT, /* Timeout. */
|
||||
E_WRESIZE, /* Window resize. */
|
||||
E_FLAGS /* Flags */
|
||||
} e_event_t;
|
||||
|
||||
/*
|
||||
* Character values.
|
||||
*/
|
||||
typedef enum {
|
||||
K_NOTUSED = 0, /* Not set. */
|
||||
K_BACKSLASH, /* \ */
|
||||
K_CARAT, /* ^ */
|
||||
K_CNTRLD, /* ^D */
|
||||
K_CNTRLR, /* ^R */
|
||||
K_CNTRLT, /* ^T */
|
||||
K_CNTRLZ, /* ^Z */
|
||||
K_COLON, /* : */
|
||||
K_CR, /* \r */
|
||||
K_ESCAPE, /* ^[ */
|
||||
K_FORMFEED, /* \f */
|
||||
K_HEXCHAR, /* ^X */
|
||||
K_NL, /* \n */
|
||||
K_RIGHTBRACE, /* } */
|
||||
K_RIGHTPAREN, /* ) */
|
||||
K_TAB, /* \t */
|
||||
K_VERASE, /* set from tty: default ^H */
|
||||
K_VKILL, /* set from tty: default ^U */
|
||||
K_VLNEXT, /* set from tty: default ^V */
|
||||
K_VWERASE, /* set from tty: default ^W */
|
||||
K_ZERO /* 0 */
|
||||
} e_key_t;
|
||||
|
||||
struct _event {
|
||||
TAILQ_ENTRY(_event) q; /* Linked list of events. */
|
||||
e_event_t e_event; /* Event type. */
|
||||
int e_ipcom; /* IP command. */
|
||||
|
||||
#define CH_ABBREVIATED 0x01 /* Character is from an abbreviation. */
|
||||
#define CH_MAPPED 0x02 /* Character is from a map. */
|
||||
#define CH_NOMAP 0x04 /* Do not map the character. */
|
||||
#define CH_QUOTED 0x08 /* Character is already quoted. */
|
||||
ARG_CHAR_T e_c; /* Character. */
|
||||
e_key_t e_value; /* Key type. */
|
||||
|
||||
#define e_flags e_val1 /* Flags. */
|
||||
#define e_lno e_val1 /* Single location. */
|
||||
#define e_cno e_val2
|
||||
#define e_flno e_val1 /* Text region. */
|
||||
#define e_fcno e_val2
|
||||
#define e_tlno e_val3
|
||||
#define e_tcno e_val4
|
||||
size_t e_val1; /* Value #1. */
|
||||
size_t e_val2; /* Value #2. */
|
||||
size_t e_val3; /* Value #3. */
|
||||
size_t e_val4; /* Value #4. */
|
||||
|
||||
#define e_csp e_str1
|
||||
#define e_len e_len1
|
||||
CHAR_T *e_str1; /* String #1. */
|
||||
size_t e_len1; /* String #1 length. */
|
||||
CHAR_T *e_str2; /* String #2. */
|
||||
size_t e_len2; /* String #2 length. */
|
||||
};
|
||||
|
||||
typedef struct _keylist {
|
||||
e_key_t value; /* Special value. */
|
||||
int ch; /* Key. */
|
||||
} KEYLIST;
|
||||
extern KEYLIST keylist[];
|
||||
|
||||
/* Return if more keys in queue. */
|
||||
#define KEYS_WAITING(sp) ((sp)->wp->i_cnt != 0)
|
||||
#define MAPPED_KEYS_WAITING(sp) \
|
||||
(KEYS_WAITING(sp) && \
|
||||
FL_ISSET((sp)->wp->i_event[(sp)->wp->i_next].e_flags, CH_MAPPED))
|
||||
|
||||
/* The "standard" tab width, for displaying things to users. */
|
||||
#define STANDARD_TAB 6
|
||||
|
||||
/* Various special characters, messages. */
|
||||
#define CH_BSEARCH '?' /* Backward search prompt. */
|
||||
#define CH_CURSOR ' ' /* Cursor character. */
|
||||
#define CH_ENDMARK '$' /* End of a range. */
|
||||
#define CH_EXPROMPT ':' /* Ex prompt. */
|
||||
#define CH_FSEARCH '/' /* Forward search prompt. */
|
||||
#define CH_HEX '\030' /* Leading hex character. */
|
||||
#define CH_LITERAL '\026' /* ASCII ^V. */
|
||||
#define CH_NO 'n' /* No. */
|
||||
#define CH_NOT_DIGIT 'a' /* A non-isdigit() character. */
|
||||
#define CH_QUIT 'q' /* Quit. */
|
||||
#define CH_YES 'y' /* Yes. */
|
||||
|
||||
/*
|
||||
* Checking for interrupts means that we look at the bit that gets set if the
|
||||
* screen code supports asynchronous events, and call back into the event code
|
||||
* so that non-asynchronous screens get a chance to post the interrupt.
|
||||
*
|
||||
* INTERRUPT_CHECK is the number of lines "operated" on before checking for
|
||||
* interrupts.
|
||||
*/
|
||||
#define INTERRUPT_CHECK 100
|
||||
#define INTERRUPTED(sp) \
|
||||
(F_ISSET((sp)->gp, G_INTERRUPTED) || \
|
||||
(!v_event_get(sp, NULL, 0, EC_INTERRUPT) && \
|
||||
F_ISSET((sp)->gp, G_INTERRUPTED)))
|
||||
#define CLR_INTERRUPT(sp) \
|
||||
F_CLR((sp)->gp, G_INTERRUPTED)
|
||||
|
||||
/* Flags describing types of characters being requested. */
|
||||
#define EC_INTERRUPT 0x001 /* Checking for interrupts. */
|
||||
#define EC_MAPCOMMAND 0x002 /* Apply the command map. */
|
||||
#define EC_MAPINPUT 0x004 /* Apply the input map. */
|
||||
#define EC_MAPNODIGIT 0x008 /* Return to a digit. */
|
||||
#define EC_QUOTED 0x010 /* Try to quote next character */
|
||||
#define EC_RAW 0x020 /* Any next character. XXX: not used. */
|
||||
#define EC_TIMEOUT 0x040 /* Timeout to next character. */
|
||||
|
||||
/* Flags describing text input special cases. */
|
||||
#define TXT_ADDNEWLINE 0x00000001 /* Replay starts on a new line. */
|
||||
#define TXT_AICHARS 0x00000002 /* Leading autoindent chars. */
|
||||
#define TXT_ALTWERASE 0x00000004 /* Option: altwerase. */
|
||||
#define TXT_APPENDEOL 0x00000008 /* Appending after EOL. */
|
||||
#define TXT_AUTOINDENT 0x00000010 /* Autoindent set this line. */
|
||||
#define TXT_BACKSLASH 0x00000020 /* Backslashes escape characters. */
|
||||
#define TXT_BEAUTIFY 0x00000040 /* Only printable characters. */
|
||||
#define TXT_BS 0x00000080 /* Backspace returns the buffer. */
|
||||
#define TXT_CEDIT 0x00000100 /* Can return TERM_CEDIT. */
|
||||
#define TXT_CNTRLD 0x00000200 /* Control-D is a command. */
|
||||
#define TXT_CNTRLT 0x00000400 /* Control-T is an indent special. */
|
||||
#define TXT_CR 0x00000800 /* CR returns the buffer. */
|
||||
#define TXT_DOTTERM 0x00001000 /* Leading '.' terminates the input. */
|
||||
#define TXT_EMARK 0x00002000 /* End of replacement mark. */
|
||||
#define TXT_EOFCHAR 0x00004000 /* ICANON set, return EOF character. */
|
||||
#define TXT_ESCAPE 0x00008000 /* Escape returns the buffer. */
|
||||
#define TXT_FILEC 0x00010000 /* Option: filec. */
|
||||
#define TXT_INFOLINE 0x00020000 /* Editing the info line. */
|
||||
#define TXT_MAPINPUT 0x00040000 /* Apply the input map. */
|
||||
#define TXT_NLECHO 0x00080000 /* Echo the newline. */
|
||||
#define TXT_NUMBER 0x00100000 /* Number the line. */
|
||||
#define TXT_OVERWRITE 0x00200000 /* Overwrite characters. */
|
||||
#define TXT_PROMPT 0x00400000 /* Display a prompt. */
|
||||
#define TXT_RECORD 0x00800000 /* Record for replay. */
|
||||
#define TXT_REPLACE 0x01000000 /* Replace; don't delete overwrite. */
|
||||
#define TXT_REPLAY 0x02000000 /* Replay the last input. */
|
||||
#define TXT_RESOLVE 0x04000000 /* Resolve the text into the file. */
|
||||
#define TXT_SEARCHINCR 0x08000000 /* Incremental search. */
|
||||
#define TXT_SHOWMATCH 0x10000000 /* Option: showmatch. */
|
||||
#define TXT_TTYWERASE 0x20000000 /* Option: ttywerase. */
|
||||
#define TXT_WRAPMARGIN 0x40000000 /* Option: wrapmargin. */
|
||||
806
dist/nvi/common/log.c
vendored
Normal file
806
dist/nvi/common/log.c
vendored
Normal file
@@ -0,0 +1,806 @@
|
||||
/* $NetBSD: log.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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: log.c,v 10.26 2002/03/02 23:12:13 skimo Exp (Berkeley) Date: 2002/03/02 23:12:13";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "dbinternal.h"
|
||||
|
||||
/*
|
||||
* The log consists of records, each containing a type byte and a variable
|
||||
* length byte string, as follows:
|
||||
*
|
||||
* LOG_CURSOR_INIT MARK
|
||||
* LOG_CURSOR_END MARK
|
||||
* LOG_LINE_APPEND_F db_recno_t char *
|
||||
* LOG_LINE_APPEND_B db_recno_t char *
|
||||
* LOG_LINE_DELETE_F db_recno_t char *
|
||||
* LOG_LINE_DELETE_B db_recno_t char *
|
||||
* LOG_LINE_RESET_F db_recno_t char *
|
||||
* LOG_LINE_RESET_B db_recno_t char *
|
||||
* LOG_MARK LMARK
|
||||
*
|
||||
* We do before image physical logging. This means that the editor layer
|
||||
* MAY NOT modify records in place, even if simply deleting or overwriting
|
||||
* characters. Since the smallest unit of logging is a line, we're using
|
||||
* up lots of space. This may eventually have to be reduced, probably by
|
||||
* doing logical logging, which is a much cooler database phrase.
|
||||
*
|
||||
* The implementation of the historic vi 'u' command, using roll-forward and
|
||||
* roll-back, is simple. Each set of changes has a LOG_CURSOR_INIT record,
|
||||
* followed by a number of other records, followed by a LOG_CURSOR_END record.
|
||||
* LOG_LINE_RESET records come in pairs. The first is a LOG_LINE_RESET_B
|
||||
* record, and is the line before the change. The second is LOG_LINE_RESET_F,
|
||||
* and is the line after the change. Roll-back is done by backing up to the
|
||||
* first LOG_CURSOR_INIT record before a change. Roll-forward is done in a
|
||||
* similar fashion.
|
||||
*
|
||||
* The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
|
||||
* record for a line different from the current one. It should be noted that
|
||||
* this means that a subsequent 'u' command will make a change based on the
|
||||
* new position of the log's cursor. This is okay, and, in fact, historic vi
|
||||
* behaved that way.
|
||||
*/
|
||||
|
||||
static int vi_log_get __P((SCR *sp, db_recno_t *lnop, size_t *size));
|
||||
static int log_cursor1 __P((SCR *, int));
|
||||
static void log_err __P((SCR *, const char *, int));
|
||||
#if defined(DEBUG) && 0
|
||||
static void log_trace __P((SCR *, const char *, db_recno_t, u_char *));
|
||||
#endif
|
||||
|
||||
/* Try and restart the log on failure, i.e. if we run out of memory. */
|
||||
#define LOG_ERR { \
|
||||
log_err(sp, __FILE__, __LINE__); \
|
||||
return (1); \
|
||||
}
|
||||
|
||||
/* offset of CHAR_T string in log needs to be aligned on some systems
|
||||
* because it is passed to db_set as a string
|
||||
*/
|
||||
typedef struct {
|
||||
char data[sizeof(u_char) /* type */ + sizeof(db_recno_t)];
|
||||
CHAR_T str[1];
|
||||
} log_t;
|
||||
#define CHAR_T_OFFSET ((char *)(((log_t*)0)->str) - (char *)0)
|
||||
|
||||
/*
|
||||
* log_init --
|
||||
* Initialize the logging subsystem.
|
||||
*
|
||||
* PUBLIC: int log_init __P((SCR *, EXF *));
|
||||
*/
|
||||
int
|
||||
log_init(SCR *sp, EXF *ep)
|
||||
{
|
||||
/*
|
||||
* !!!
|
||||
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
|
||||
*
|
||||
* Initialize the buffer. The logging subsystem has its own
|
||||
* buffers because the global ones are almost by definition
|
||||
* going to be in use when the log runs.
|
||||
*/
|
||||
sp->wp->l_lp = NULL;
|
||||
sp->wp->l_len = 0;
|
||||
ep->l_cursor.lno = 1; /* XXX Any valid recno. */
|
||||
ep->l_cursor.cno = 0;
|
||||
ep->l_high = ep->l_cur = 1;
|
||||
|
||||
if (db_create(&ep->log, 0, 0) != 0 ||
|
||||
db_open(ep->log, NULL, DB_RECNO,
|
||||
DB_CREATE | VI_DB_THREAD, S_IRUSR | S_IWUSR) != 0) {
|
||||
msgq(sp, M_SYSERR, "009|Log file");
|
||||
F_SET(ep, F_NOLOG);
|
||||
return (1);
|
||||
}
|
||||
|
||||
ep->l_win = NULL;
|
||||
/*LOCK_INIT(sp->wp, ep);*/
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_end --
|
||||
* Close the logging subsystem.
|
||||
*
|
||||
* PUBLIC: int log_end __P((SCR *, EXF *));
|
||||
*/
|
||||
int
|
||||
log_end(SCR *sp, EXF *ep)
|
||||
{
|
||||
/*
|
||||
* !!!
|
||||
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
|
||||
*/
|
||||
/*LOCK_END(sp->wp, ep);*/
|
||||
if (ep->log != NULL) {
|
||||
(void)(ep->log->close)(ep->log,DB_NOSYNC);
|
||||
ep->log = NULL;
|
||||
}
|
||||
if (sp->wp->l_lp != NULL) {
|
||||
free(sp->wp->l_lp);
|
||||
sp->wp->l_lp = NULL;
|
||||
}
|
||||
sp->wp->l_len = 0;
|
||||
ep->l_cursor.lno = 1; /* XXX Any valid recno. */
|
||||
ep->l_cursor.cno = 0;
|
||||
ep->l_high = ep->l_cur = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_cursor --
|
||||
* Log the current cursor position, starting an event.
|
||||
*
|
||||
* PUBLIC: int log_cursor __P((SCR *));
|
||||
*/
|
||||
int
|
||||
log_cursor(SCR *sp)
|
||||
{
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If any changes were made since the last cursor init,
|
||||
* put out the ending cursor record.
|
||||
*/
|
||||
if (ep->l_cursor.lno == OOBLNO) {
|
||||
if (ep->l_win && ep->l_win != sp->wp)
|
||||
return 0;
|
||||
ep->l_cursor.lno = sp->lno;
|
||||
ep->l_cursor.cno = sp->cno;
|
||||
ep->l_win = NULL;
|
||||
return (log_cursor1(sp, LOG_CURSOR_END));
|
||||
}
|
||||
ep->l_cursor.lno = sp->lno;
|
||||
ep->l_cursor.cno = sp->cno;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_cursor1 --
|
||||
* Actually push a cursor record out.
|
||||
*/
|
||||
static int
|
||||
log_cursor1(SCR *sp, int type)
|
||||
{
|
||||
DBT data, key;
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
|
||||
/*
|
||||
if (type == LOG_CURSOR_INIT &&
|
||||
LOCK_TRY(sp->wp, ep))
|
||||
return 1;
|
||||
*/
|
||||
|
||||
BINC_RETC(sp, sp->wp->l_lp, sp->wp->l_len, sizeof(u_char) + sizeof(MARK));
|
||||
sp->wp->l_lp[0] = type;
|
||||
memmove(sp->wp->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK));
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &ep->l_cur;
|
||||
key.size = sizeof(db_recno_t);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = sp->wp->l_lp;
|
||||
data.size = sizeof(u_char) + sizeof(MARK);
|
||||
if (ep->log->put(ep->log, NULL, &key, &data, 0) == -1)
|
||||
LOG_ERR;
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "%lu: %s: %u/%u\n", ep->l_cur,
|
||||
type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
|
||||
sp->lno, sp->cno);
|
||||
#endif
|
||||
/* Reset high water mark. */
|
||||
ep->l_high = ++ep->l_cur;
|
||||
|
||||
/*
|
||||
if (type == LOG_CURSOR_END)
|
||||
LOCK_UNLOCK(sp->wp, ep);
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_line --
|
||||
* Log a line change.
|
||||
*
|
||||
* PUBLIC: int log_line __P((SCR *, db_recno_t, u_int));
|
||||
*/
|
||||
int
|
||||
log_line(SCR *sp, db_recno_t lno, u_int action)
|
||||
{
|
||||
DBT data, key;
|
||||
EXF *ep;
|
||||
size_t len;
|
||||
CHAR_T *lp;
|
||||
db_recno_t lcur;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
*
|
||||
* Kluge for vi. Clear the EXF undo flag so that the
|
||||
* next 'u' command does a roll-back, regardless.
|
||||
*/
|
||||
F_CLR(ep, F_UNDO);
|
||||
|
||||
/* Put out one initial cursor record per set of changes. */
|
||||
if (ep->l_cursor.lno != OOBLNO) {
|
||||
if (log_cursor1(sp, LOG_CURSOR_INIT))
|
||||
return (1);
|
||||
ep->l_cursor.lno = OOBLNO;
|
||||
ep->l_win = sp->wp;
|
||||
} /*else if (ep->l_win != sp->wp) {
|
||||
printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp);
|
||||
return 1;
|
||||
}*/
|
||||
|
||||
switch (action) {
|
||||
/* newly added for DB4 logging */
|
||||
case LOG_LINE_APPEND_B:
|
||||
case LOG_LINE_DELETE_F:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put out the changes. If it's a LOG_LINE_RESET_B call, it's a
|
||||
* special case, avoid the caches. Also, if it fails and it's
|
||||
* line 1, it just means that the user started with an empty file,
|
||||
* so fake an empty length line.
|
||||
*/
|
||||
if (action == LOG_LINE_RESET_B) {
|
||||
if (db_get(sp, lno, DBG_NOCACHE, &lp, &len)) {
|
||||
static CHAR_T nul = 0;
|
||||
if (lno != 1) {
|
||||
db_err(sp, lno);
|
||||
return (1);
|
||||
}
|
||||
len = 0;
|
||||
lp = &nul;
|
||||
}
|
||||
} else
|
||||
if (db_get(sp, lno, DBG_FATAL, &lp, &len))
|
||||
return (1);
|
||||
BINC_RETC(sp,
|
||||
sp->wp->l_lp, sp->wp->l_len,
|
||||
len * sizeof(CHAR_T) + CHAR_T_OFFSET);
|
||||
sp->wp->l_lp[0] = action;
|
||||
memmove(sp->wp->l_lp + sizeof(u_char), &lno, sizeof(db_recno_t));
|
||||
MEMMOVEW(sp->wp->l_lp + CHAR_T_OFFSET, lp, len);
|
||||
|
||||
lcur = ep->l_cur;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &lcur;
|
||||
key.size = sizeof(db_recno_t);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = sp->wp->l_lp;
|
||||
data.size = len * sizeof(CHAR_T) + CHAR_T_OFFSET;
|
||||
if (ep->log->put(ep->log, NULL, &key, &data, 0) == -1)
|
||||
LOG_ERR;
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
switch (action) {
|
||||
case LOG_LINE_APPEND_F:
|
||||
vtrace(sp, "%u: log_line: append_f: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_APPEND_B:
|
||||
vtrace(sp, "%u: log_line: append_b: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_DELETE_F:
|
||||
vtrace(sp, "%lu: log_line: delete_f: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_DELETE_B:
|
||||
vtrace(sp, "%lu: log_line: delete_b: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_RESET_F:
|
||||
vtrace(sp, "%lu: log_line: reset_f: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_RESET_B:
|
||||
vtrace(sp, "%lu: log_line: reset_b: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* Reset high water mark. */
|
||||
ep->l_high = ++ep->l_cur;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_mark --
|
||||
* Log a mark position. For the log to work, we assume that there
|
||||
* aren't any operations that just put out a log record -- this
|
||||
* would mean that undo operations would only reset marks, and not
|
||||
* cause any other change.
|
||||
*
|
||||
* PUBLIC: int log_mark __P((SCR *, LMARK *));
|
||||
*/
|
||||
int
|
||||
log_mark(SCR *sp, LMARK *lmp)
|
||||
{
|
||||
DBT data, key;
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG))
|
||||
return (0);
|
||||
|
||||
/* Put out one initial cursor record per set of changes. */
|
||||
if (ep->l_cursor.lno != OOBLNO) {
|
||||
if (log_cursor1(sp, LOG_CURSOR_INIT))
|
||||
return (1);
|
||||
ep->l_cursor.lno = OOBLNO;
|
||||
ep->l_win = sp->wp;
|
||||
}
|
||||
|
||||
BINC_RETC(sp, sp->wp->l_lp,
|
||||
sp->wp->l_len, sizeof(u_char) + sizeof(LMARK));
|
||||
sp->wp->l_lp[0] = LOG_MARK;
|
||||
memmove(sp->wp->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &ep->l_cur;
|
||||
key.size = sizeof(db_recno_t);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = sp->wp->l_lp;
|
||||
data.size = sizeof(u_char) + sizeof(LMARK);
|
||||
if (ep->log->put(ep->log, NULL, &key, &data, 0) == -1)
|
||||
LOG_ERR;
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "%lu: mark %c: %lu/%u\n",
|
||||
ep->l_cur, lmp->name, lmp->lno, lmp->cno);
|
||||
#endif
|
||||
/* Reset high water mark. */
|
||||
ep->l_high = ++ep->l_cur;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vi_log_get --
|
||||
* Get a line from the log in log buffer.
|
||||
*/
|
||||
static int
|
||||
vi_log_get(SCR *sp, db_recno_t *lnop, size_t *size)
|
||||
{
|
||||
DBT key, data;
|
||||
size_t nlen;
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
|
||||
nlen = 1024;
|
||||
retry:
|
||||
BINC_RETC(sp, sp->wp->l_lp, sp->wp->l_len, nlen);
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = lnop; /* Initialize db request. */
|
||||
key.size = sizeof(db_recno_t);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = sp->wp->l_lp;
|
||||
data.ulen = sp->wp->l_len;
|
||||
data.flags = DB_DBT_USERMEM;
|
||||
switch (ep->log->get(ep->log, NULL, &key, &data, 0)) {
|
||||
case ENOMEM:
|
||||
nlen = data.size;
|
||||
goto retry;
|
||||
case 0:
|
||||
*size = data.size;
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Log_backward --
|
||||
* Roll the log backward one operation.
|
||||
*
|
||||
* PUBLIC: int log_backward __P((SCR *, MARK *));
|
||||
*/
|
||||
int
|
||||
log_backward(SCR *sp, MARK *rp)
|
||||
{
|
||||
EXF *ep;
|
||||
LMARK lm;
|
||||
MARK m;
|
||||
db_recno_t lno;
|
||||
int didop;
|
||||
u_char *p;
|
||||
size_t size;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG)) {
|
||||
msgq(sp, M_ERR,
|
||||
"010|Logging not being performed, undo not possible");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (ep->l_cur == 1) {
|
||||
msgq(sp, M_BERR, "011|No changes to undo");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (ep->l_win && ep->l_win != sp->wp) {
|
||||
ex_emsg(sp, NULL, EXM_LOCKED);
|
||||
return 1;
|
||||
}
|
||||
ep->l_win = sp->wp;
|
||||
|
||||
|
||||
F_SET(ep, F_NOLOG); /* Turn off logging. */
|
||||
|
||||
for (didop = 0;;) {
|
||||
--ep->l_cur;
|
||||
if (vi_log_get(sp, &ep->l_cur, &size))
|
||||
LOG_ERR;
|
||||
#if defined(DEBUG) && 0
|
||||
log_trace(sp, "log_backward", ep->l_cur, data.data);
|
||||
#endif
|
||||
switch (*(p = (u_char *)sp->wp->l_lp)) {
|
||||
case LOG_CURSOR_INIT:
|
||||
if (didop) {
|
||||
memmove(rp, p + sizeof(u_char), sizeof(MARK));
|
||||
F_CLR(ep, F_NOLOG);
|
||||
ep->l_win = NULL;
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case LOG_CURSOR_END:
|
||||
break;
|
||||
case LOG_LINE_APPEND_F:
|
||||
didop = 1;
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
if (db_delete(sp, lno))
|
||||
goto err;
|
||||
++sp->rptlines[L_DELETED];
|
||||
break;
|
||||
case LOG_LINE_DELETE_B:
|
||||
didop = 1;
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
if (db_insert(sp, lno,
|
||||
(CHAR_T *)(p + CHAR_T_OFFSET),
|
||||
(size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
|
||||
goto err;
|
||||
++sp->rptlines[L_ADDED];
|
||||
break;
|
||||
case LOG_LINE_RESET_F:
|
||||
break;
|
||||
case LOG_LINE_RESET_B:
|
||||
didop = 1;
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
if (db_set(sp, lno,
|
||||
(CHAR_T *)(p + CHAR_T_OFFSET),
|
||||
(size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
|
||||
goto err;
|
||||
if (sp->rptlchange != lno) {
|
||||
sp->rptlchange = lno;
|
||||
++sp->rptlines[L_CHANGED];
|
||||
}
|
||||
break;
|
||||
case LOG_MARK:
|
||||
didop = 1;
|
||||
memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
|
||||
m.lno = lm.lno;
|
||||
m.cno = lm.cno;
|
||||
if (mark_set(sp, lm.name, &m, 0))
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
err: F_CLR(ep, F_NOLOG);
|
||||
ep->l_win = NULL;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log_setline --
|
||||
* Reset the line to its original appearance.
|
||||
*
|
||||
* XXX
|
||||
* There's a bug in this code due to our not logging cursor movements
|
||||
* unless a change was made. If you do a change, move off the line,
|
||||
* then move back on and do a 'U', the line will be restored to the way
|
||||
* it was before the original change.
|
||||
*
|
||||
* PUBLIC: int log_setline __P((SCR *));
|
||||
*/
|
||||
int
|
||||
log_setline(SCR *sp)
|
||||
{
|
||||
EXF *ep;
|
||||
LMARK lm;
|
||||
MARK m;
|
||||
db_recno_t lno;
|
||||
u_char *p;
|
||||
size_t size;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG)) {
|
||||
msgq(sp, M_ERR,
|
||||
"012|Logging not being performed, undo not possible");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (ep->l_cur == 1)
|
||||
return (1);
|
||||
|
||||
if (ep->l_win && ep->l_win != sp->wp) {
|
||||
ex_emsg(sp, NULL, EXM_LOCKED);
|
||||
return 1;
|
||||
}
|
||||
ep->l_win = sp->wp;
|
||||
|
||||
F_SET(ep, F_NOLOG); /* Turn off logging. */
|
||||
|
||||
for (;;) {
|
||||
--ep->l_cur;
|
||||
if (vi_log_get(sp, &ep->l_cur, &size))
|
||||
LOG_ERR;
|
||||
#if defined(DEBUG) && 0
|
||||
log_trace(sp, "log_setline", ep->l_cur, data.data);
|
||||
#endif
|
||||
switch (*(p = (u_char *)sp->wp->l_lp)) {
|
||||
case LOG_CURSOR_INIT:
|
||||
memmove(&m, p + sizeof(u_char), sizeof(MARK));
|
||||
if (m.lno != sp->lno || ep->l_cur == 1) {
|
||||
F_CLR(ep, F_NOLOG);
|
||||
ep->l_win = NULL;
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case LOG_CURSOR_END:
|
||||
memmove(&m, p + sizeof(u_char), sizeof(MARK));
|
||||
if (m.lno != sp->lno) {
|
||||
++ep->l_cur;
|
||||
F_CLR(ep, F_NOLOG);
|
||||
ep->l_win = NULL;
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case LOG_LINE_APPEND_F:
|
||||
case LOG_LINE_DELETE_B:
|
||||
case LOG_LINE_RESET_F:
|
||||
break;
|
||||
case LOG_LINE_RESET_B:
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
if (lno == sp->lno &&
|
||||
db_set(sp, lno, (CHAR_T *)(p + CHAR_T_OFFSET),
|
||||
(size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
|
||||
goto err;
|
||||
if (sp->rptlchange != lno) {
|
||||
sp->rptlchange = lno;
|
||||
++sp->rptlines[L_CHANGED];
|
||||
}
|
||||
case LOG_MARK:
|
||||
memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
|
||||
m.lno = lm.lno;
|
||||
m.cno = lm.cno;
|
||||
if (mark_set(sp, lm.name, &m, 0))
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
err: F_CLR(ep, F_NOLOG);
|
||||
ep->l_win = NULL;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log_forward --
|
||||
* Roll the log forward one operation.
|
||||
*
|
||||
* PUBLIC: int log_forward __P((SCR *, MARK *));
|
||||
*/
|
||||
int
|
||||
log_forward(SCR *sp, MARK *rp)
|
||||
{
|
||||
EXF *ep;
|
||||
LMARK lm;
|
||||
MARK m;
|
||||
db_recno_t lno;
|
||||
int didop;
|
||||
u_char *p;
|
||||
size_t size;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG)) {
|
||||
msgq(sp, M_ERR,
|
||||
"013|Logging not being performed, roll-forward not possible");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (ep->l_cur == ep->l_high) {
|
||||
msgq(sp, M_BERR, "014|No changes to re-do");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (ep->l_win && ep->l_win != sp->wp) {
|
||||
ex_emsg(sp, NULL, EXM_LOCKED);
|
||||
return 1;
|
||||
}
|
||||
ep->l_win = sp->wp;
|
||||
|
||||
F_SET(ep, F_NOLOG); /* Turn off logging. */
|
||||
|
||||
for (didop = 0;;) {
|
||||
++ep->l_cur;
|
||||
if (vi_log_get(sp, &ep->l_cur, &size))
|
||||
LOG_ERR;
|
||||
#if defined(DEBUG) && 0
|
||||
log_trace(sp, "log_forward", ep->l_cur, data.data);
|
||||
#endif
|
||||
switch (*(p = (u_char *)sp->wp->l_lp)) {
|
||||
case LOG_CURSOR_END:
|
||||
if (didop) {
|
||||
++ep->l_cur;
|
||||
memmove(rp, p + sizeof(u_char), sizeof(MARK));
|
||||
F_CLR(ep, F_NOLOG);
|
||||
ep->l_win = NULL;
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case LOG_CURSOR_INIT:
|
||||
break;
|
||||
case LOG_LINE_APPEND_F:
|
||||
didop = 1;
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
if (db_insert(sp, lno,
|
||||
(CHAR_T *)(p + CHAR_T_OFFSET),
|
||||
(size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
|
||||
goto err;
|
||||
++sp->rptlines[L_ADDED];
|
||||
break;
|
||||
case LOG_LINE_DELETE_B:
|
||||
didop = 1;
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
if (db_delete(sp, lno))
|
||||
goto err;
|
||||
++sp->rptlines[L_DELETED];
|
||||
break;
|
||||
case LOG_LINE_RESET_B:
|
||||
break;
|
||||
case LOG_LINE_RESET_F:
|
||||
didop = 1;
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
if (db_set(sp, lno,
|
||||
(CHAR_T *)(p + CHAR_T_OFFSET),
|
||||
(size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
|
||||
goto err;
|
||||
if (sp->rptlchange != lno) {
|
||||
sp->rptlchange = lno;
|
||||
++sp->rptlines[L_CHANGED];
|
||||
}
|
||||
break;
|
||||
case LOG_MARK:
|
||||
didop = 1;
|
||||
memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
|
||||
m.lno = lm.lno;
|
||||
m.cno = lm.cno;
|
||||
if (mark_set(sp, lm.name, &m, 0))
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
err: F_CLR(ep, F_NOLOG);
|
||||
ep->l_win = NULL;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_err --
|
||||
* Try and restart the log on failure, i.e. if we run out of memory.
|
||||
*/
|
||||
static void
|
||||
log_err(SCR *sp, const char *file, int line)
|
||||
{
|
||||
EXF *ep;
|
||||
|
||||
msgq(sp, M_SYSERR, "015|%s/%d: log put error", tail(file), line);
|
||||
ep = sp->ep;
|
||||
(void)ep->log->close(ep->log, DB_NOSYNC);
|
||||
if (!log_init(sp, ep))
|
||||
msgq(sp, M_ERR, "267|Log restarted");
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
static void
|
||||
log_trace(SCR *sp, const char *msg, db_recno_t rno, u_char *p)
|
||||
{
|
||||
LMARK lm;
|
||||
MARK m;
|
||||
db_recno_t lno;
|
||||
|
||||
switch (*p) {
|
||||
case LOG_CURSOR_INIT:
|
||||
memmove(&m, p + sizeof(u_char), sizeof(MARK));
|
||||
vtrace(sp, "%lu: %s: C_INIT: %u/%u\n", rno, msg, m.lno, m.cno);
|
||||
break;
|
||||
case LOG_CURSOR_END:
|
||||
memmove(&m, p + sizeof(u_char), sizeof(MARK));
|
||||
vtrace(sp, "%lu: %s: C_END: %u/%u\n", rno, msg, m.lno, m.cno);
|
||||
break;
|
||||
case LOG_LINE_APPEND_F:
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
vtrace(sp, "%lu: %s: APPEND_F: %lu\n", rno, msg, lno);
|
||||
break;
|
||||
case LOG_LINE_APPEND_B:
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
vtrace(sp, "%lu: %s: APPEND_B: %lu\n", rno, msg, lno);
|
||||
break;
|
||||
case LOG_LINE_DELETE_F:
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
vtrace(sp, "%lu: %s: DELETE_F: %lu\n", rno, msg, lno);
|
||||
break;
|
||||
case LOG_LINE_DELETE_B:
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
vtrace(sp, "%lu: %s: DELETE_B: %lu\n", rno, msg, lno);
|
||||
break;
|
||||
case LOG_LINE_RESET_F:
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
vtrace(sp, "%lu: %s: RESET_F: %lu\n", rno, msg, lno);
|
||||
break;
|
||||
case LOG_LINE_RESET_B:
|
||||
memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
|
||||
vtrace(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno);
|
||||
break;
|
||||
case LOG_MARK:
|
||||
memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
|
||||
vtrace(sp,
|
||||
"%lu: %s: MARK: %u/%u\n", rno, msg, lm.lno, lm.cno);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
31
dist/nvi/common/log.h
vendored
Normal file
31
dist/nvi/common/log.h
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/* $NetBSD: log.h,v 1.1.1.2 2008/05/18 14:29:46 aymeric 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*
|
||||
* Id: log.h,v 10.4 2002/06/08 21:00:33 skimo Exp (Berkeley) Date: 2002/06/08 21:00:33
|
||||
*/
|
||||
|
||||
#define LOG_NOTYPE 0
|
||||
#define LOG_CURSOR_INIT 2
|
||||
#define LOG_CURSOR_END 3
|
||||
#define LOG_LINE_APPEND_B 4
|
||||
#define LOG_LINE_APPEND_F 5
|
||||
#define LOG_LINE_DELETE_B 6
|
||||
#define LOG_LINE_DELETE_F 7
|
||||
#define LOG_LINE_RESET_B 8
|
||||
#define LOG_LINE_RESET_F 9
|
||||
#define LOG_MARK 10
|
||||
|
||||
typedef enum { UNDO_FORWARD, UNDO_BACKWARD, UNDO_SETLINE } undo_t;
|
||||
|
||||
struct _log_state {
|
||||
int didop;
|
||||
MARK pos;
|
||||
undo_t undo;
|
||||
};
|
||||
458
dist/nvi/common/log4.c
vendored
Normal file
458
dist/nvi/common/log4.c
vendored
Normal file
@@ -0,0 +1,458 @@
|
||||
/* $NetBSD: log4.c,v 1.1.1.2 2008/05/18 14:29:47 aymeric 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: log4.c,v 10.3 2002/06/08 21:00:33 skimo Exp";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* The log consists of records, each containing a type byte and a variable
|
||||
* length byte string, as follows:
|
||||
*
|
||||
* LOG_CURSOR_INIT MARK
|
||||
* LOG_CURSOR_END MARK
|
||||
* LOG_LINE_APPEND_F db_recno_t char *
|
||||
* LOG_LINE_APPEND_B db_recno_t char *
|
||||
* LOG_LINE_DELETE_F db_recno_t char *
|
||||
* LOG_LINE_DELETE_B db_recno_t char *
|
||||
* LOG_LINE_RESET_F db_recno_t char *
|
||||
* LOG_LINE_RESET_B db_recno_t char *
|
||||
* LOG_MARK LMARK
|
||||
*
|
||||
* We do before image physical logging. This means that the editor layer
|
||||
* MAY NOT modify records in place, even if simply deleting or overwriting
|
||||
* characters. Since the smallest unit of logging is a line, we're using
|
||||
* up lots of space. This may eventually have to be reduced, probably by
|
||||
* doing logical logging, which is a much cooler database phrase.
|
||||
*
|
||||
* The implementation of the historic vi 'u' command, using roll-forward and
|
||||
* roll-back, is simple. Each set of changes has a LOG_CURSOR_INIT record,
|
||||
* followed by a number of other records, followed by a LOG_CURSOR_END record.
|
||||
* LOG_LINE_RESET records come in pairs. The first is a LOG_LINE_RESET_B
|
||||
* record, and is the line before the change. The second is LOG_LINE_RESET_F,
|
||||
* and is the line after the change. Roll-back is done by backing up to the
|
||||
* first LOG_CURSOR_INIT record before a change. Roll-forward is done in a
|
||||
* similar fashion.
|
||||
*
|
||||
* The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
|
||||
* record for a line different from the current one. It should be noted that
|
||||
* this means that a subsequent 'u' command will make a change based on the
|
||||
* new position of the log's cursor. This is okay, and, in fact, historic vi
|
||||
* behaved that way.
|
||||
*/
|
||||
|
||||
static int log_cursor1 __P((SCR *, int));
|
||||
|
||||
/*
|
||||
* log_init --
|
||||
* Initialize the logging subsystem.
|
||||
*
|
||||
* PUBLIC: int log_init __P((SCR *, EXF *));
|
||||
*/
|
||||
int
|
||||
log_init(SCR *sp, EXF *ep)
|
||||
{
|
||||
DB_LOGC *logc;
|
||||
DBT data;
|
||||
size_t nlen;
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
|
||||
*
|
||||
* Initialize the buffer. The logging subsystem has its own
|
||||
* buffers because the global ones are almost by definition
|
||||
* going to be in use when the log runs.
|
||||
*/
|
||||
sp->wp->l_lp = NULL;
|
||||
sp->wp->l_len = 0;
|
||||
ep->l_cursor.lno = 1; /* XXX Any valid recno. */
|
||||
ep->l_cursor.cno = 0;
|
||||
ep->l_high = ep->l_cur = 1;
|
||||
|
||||
if ((sp->db_error = ep->env->log_cursor(ep->env, &logc, 0))
|
||||
!= 0) {
|
||||
msgq(sp, M_DBERR, "env->log_cursor");
|
||||
F_SET(ep, F_NOLOG);
|
||||
return (1);
|
||||
}
|
||||
nlen = 1024;
|
||||
retry:
|
||||
BINC_GOTO(sp, sp->wp->l_lp, sp->wp->l_len, nlen);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = sp->wp->l_lp;
|
||||
data.ulen = sp->wp->l_len;
|
||||
data.flags = DB_DBT_USERMEM;
|
||||
switch ((sp->db_error =
|
||||
logc->get(logc, &ep->lsn_first, &data, DB_LAST))) {
|
||||
case ENOMEM:
|
||||
nlen = data.size;
|
||||
goto retry;
|
||||
default:
|
||||
alloc_err:
|
||||
msgq(sp, M_DBERR, "logc->get");
|
||||
F_SET(ep, F_NOLOG);
|
||||
return (1);
|
||||
case 0:
|
||||
;
|
||||
}
|
||||
MEMCPY(&ep->lsn_cur, &ep->lsn_first, 1);
|
||||
MEMCPY(&ep->lsn_high, &ep->lsn_first, 1);
|
||||
logc->close(logc, 0);
|
||||
|
||||
ep->l_win = NULL;
|
||||
/*LOCK_INIT(sp->wp, ep);*/
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_end --
|
||||
* Close the logging subsystem.
|
||||
*
|
||||
* PUBLIC: int log_end __P((SCR *, EXF *));
|
||||
*/
|
||||
int
|
||||
log_end(SCR *sp, EXF *ep)
|
||||
{
|
||||
/*
|
||||
* !!!
|
||||
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
|
||||
*/
|
||||
/*LOCK_END(sp->wp, ep);*/
|
||||
if (sp->wp->l_lp != NULL) {
|
||||
free(sp->wp->l_lp);
|
||||
sp->wp->l_lp = NULL;
|
||||
}
|
||||
sp->wp->l_len = 0;
|
||||
ep->l_cursor.lno = 1; /* XXX Any valid recno. */
|
||||
ep->l_cursor.cno = 0;
|
||||
ep->l_high = ep->l_cur = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_cursor --
|
||||
* Log the current cursor position, starting an event.
|
||||
*
|
||||
* PUBLIC: int log_cursor __P((SCR *));
|
||||
*/
|
||||
int
|
||||
log_cursor(SCR *sp)
|
||||
{
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If any changes were made since the last cursor init,
|
||||
* put out the ending cursor record.
|
||||
*/
|
||||
if (ep->l_cursor.lno == OOBLNO) {
|
||||
if (ep->l_win && ep->l_win != sp->wp)
|
||||
return 0;
|
||||
ep->l_cursor.lno = sp->lno;
|
||||
ep->l_cursor.cno = sp->cno;
|
||||
ep->l_win = NULL;
|
||||
return (log_cursor1(sp, LOG_CURSOR_END));
|
||||
}
|
||||
ep->l_cursor.lno = sp->lno;
|
||||
ep->l_cursor.cno = sp->cno;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_cursor1 --
|
||||
* Actually push a cursor record out.
|
||||
*/
|
||||
static int
|
||||
log_cursor1(SCR *sp, int type)
|
||||
{
|
||||
DBT data, key;
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
|
||||
/*
|
||||
if (type == LOG_CURSOR_INIT &&
|
||||
LOCK_TRY(sp->wp, ep))
|
||||
return 1;
|
||||
*/
|
||||
|
||||
if (type == LOG_CURSOR_INIT &&
|
||||
(sp->db_error = __vi_log_truncate(ep)) != 0) {
|
||||
msgq(sp, M_DBERR, "truncate");
|
||||
return 1;
|
||||
}
|
||||
if ((sp->db_error =
|
||||
__vi_cursor_log(ep->env, NULL, &ep->lsn_cur, 0, type,
|
||||
ep->l_cursor.lno, ep->l_cursor.cno)) != 0) {
|
||||
msgq(sp, M_DBERR, "cursor_log");
|
||||
return 1;
|
||||
}
|
||||
if (type == LOG_CURSOR_END) {
|
||||
MEMCPY(&ep->lsn_high, &ep->lsn_cur, 1);
|
||||
/* XXXX should not be needed */
|
||||
ep->env->log_flush(ep->env, NULL);
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "%lu: %s: %u/%u\n", ep->l_cur,
|
||||
type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
|
||||
sp->lno, sp->cno);
|
||||
#endif
|
||||
/* Reset high water mark. */
|
||||
ep->l_high = ++ep->l_cur;
|
||||
|
||||
/*
|
||||
if (type == LOG_CURSOR_END)
|
||||
LOCK_UNLOCK(sp->wp, ep);
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_line --
|
||||
* Log a line change.
|
||||
*
|
||||
* PUBLIC: int log_line __P((SCR *, db_recno_t, u_int));
|
||||
*/
|
||||
int
|
||||
log_line(SCR *sp, db_recno_t lno, u_int action)
|
||||
{
|
||||
DBT data, key;
|
||||
EXF *ep;
|
||||
size_t len;
|
||||
CHAR_T *lp;
|
||||
db_recno_t lcur;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
*
|
||||
* Kluge for vi. Clear the EXF undo flag so that the
|
||||
* next 'u' command does a roll-back, regardless.
|
||||
*/
|
||||
F_CLR(ep, F_UNDO);
|
||||
|
||||
/* Put out one initial cursor record per set of changes. */
|
||||
if (ep->l_cursor.lno != OOBLNO) {
|
||||
if (log_cursor1(sp, LOG_CURSOR_INIT))
|
||||
return (1);
|
||||
ep->l_cursor.lno = OOBLNO;
|
||||
ep->l_win = sp->wp;
|
||||
} /*else if (ep->l_win != sp->wp) {
|
||||
printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp);
|
||||
return 1;
|
||||
}*/
|
||||
|
||||
if ((sp->db_error =
|
||||
__vi_change_log(ep->env, NULL, &ep->lsn_cur, 0, action,
|
||||
lno)) != 0) {
|
||||
msgq(sp, M_DBERR, "change_log");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
switch (action) {
|
||||
case LOG_LINE_APPEND_F:
|
||||
vtrace(sp, "%u: log_line: append_f: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_APPEND_B:
|
||||
vtrace(sp, "%u: log_line: append_b: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_DELETE_F:
|
||||
vtrace(sp, "%lu: log_line: delete_f: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_DELETE_B:
|
||||
vtrace(sp, "%lu: log_line: delete_b: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_RESET_F:
|
||||
vtrace(sp, "%lu: log_line: reset_f: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
case LOG_LINE_RESET_B:
|
||||
vtrace(sp, "%lu: log_line: reset_b: %lu {%u}\n",
|
||||
ep->l_cur, lno, len);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* Reset high water mark. */
|
||||
ep->l_high = ++ep->l_cur;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* log_mark --
|
||||
* Log a mark position. For the log to work, we assume that there
|
||||
* aren't any operations that just put out a log record -- this
|
||||
* would mean that undo operations would only reset marks, and not
|
||||
* cause any other change.
|
||||
*
|
||||
* PUBLIC: int log_mark __P((SCR *, LMARK *));
|
||||
*/
|
||||
int
|
||||
log_mark(SCR *sp, LMARK *lmp)
|
||||
{
|
||||
DBT data, key;
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG))
|
||||
return (0);
|
||||
|
||||
/* Put out one initial cursor record per set of changes. */
|
||||
if (ep->l_cursor.lno != OOBLNO) {
|
||||
if (log_cursor1(sp, LOG_CURSOR_INIT))
|
||||
return (1);
|
||||
ep->l_cursor.lno = OOBLNO;
|
||||
ep->l_win = sp->wp;
|
||||
}
|
||||
|
||||
if ((sp->db_error =
|
||||
__vi_mark_log(ep->env, NULL, &ep->lsn_cur, 0,
|
||||
lmp)) != 0) {
|
||||
msgq(sp, M_DBERR, "cursor_log");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "%lu: mark %c: %lu/%u\n",
|
||||
ep->l_cur, lmp->name, lmp->lno, lmp->cno);
|
||||
#endif
|
||||
/* Reset high water mark. */
|
||||
ep->l_high = ++ep->l_cur;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log_backward --
|
||||
* Roll the log backward one operation.
|
||||
*
|
||||
* PUBLIC: int log_backward __P((SCR *, MARK *));
|
||||
*/
|
||||
int
|
||||
log_backward(SCR *sp, MARK *rp)
|
||||
{
|
||||
EXF *ep;
|
||||
LMARK lm;
|
||||
MARK m;
|
||||
db_recno_t lno;
|
||||
int didop;
|
||||
u_char *p;
|
||||
size_t size;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG)) {
|
||||
msgq(sp, M_ERR,
|
||||
"010|Logging not being performed, undo not possible");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
|
||||
msgq(sp, M_BERR, "011|No changes to undo");
|
||||
return (1);
|
||||
}
|
||||
return __vi_log_traverse(sp, UNDO_BACKWARD, rp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log_setline --
|
||||
* Reset the line to its original appearance.
|
||||
*
|
||||
* XXX
|
||||
* There's a bug in this code due to our not logging cursor movements
|
||||
* unless a change was made. If you do a change, move off the line,
|
||||
* then move back on and do a 'U', the line will be restored to the way
|
||||
* it was before the original change.
|
||||
*
|
||||
* PUBLIC: int log_setline __P((SCR *));
|
||||
*/
|
||||
int
|
||||
log_setline(SCR *sp)
|
||||
{
|
||||
EXF *ep;
|
||||
LMARK lm;
|
||||
MARK m;
|
||||
db_recno_t lno;
|
||||
u_char *p;
|
||||
size_t size;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG)) {
|
||||
msgq(sp, M_ERR,
|
||||
"012|Logging not being performed, undo not possible");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
|
||||
msgq(sp, M_BERR, "011|No changes to undo");
|
||||
return (1);
|
||||
}
|
||||
return __vi_log_traverse(sp, UNDO_SETLINE, &m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log_forward --
|
||||
* Roll the log forward one operation.
|
||||
*
|
||||
* PUBLIC: int log_forward __P((SCR *, MARK *));
|
||||
*/
|
||||
int
|
||||
log_forward(SCR *sp, MARK *rp)
|
||||
{
|
||||
EXF *ep;
|
||||
LMARK lm;
|
||||
MARK m;
|
||||
db_recno_t lno;
|
||||
int didop;
|
||||
u_char *p;
|
||||
size_t size;
|
||||
|
||||
ep = sp->ep;
|
||||
if (F_ISSET(ep, F_NOLOG)) {
|
||||
msgq(sp, M_ERR,
|
||||
"013|Logging not being performed, roll-forward not possible");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (log_compare(&ep->lsn_cur, &ep->lsn_high) >= 0) {
|
||||
msgq(sp, M_BERR, "014|No changes to re-do");
|
||||
return (1);
|
||||
}
|
||||
return __vi_log_traverse(sp, UNDO_FORWARD, rp);
|
||||
}
|
||||
529
dist/nvi/common/main.c
vendored
Normal file
529
dist/nvi/common/main.c
vendored
Normal file
@@ -0,0 +1,529 @@
|
||||
/* $NetBSD: main.c,v 1.3 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char copyright[] =
|
||||
"%Z% Copyright (c) 1992, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n\
|
||||
%Z% Copyright (c) 1992, 1993, 1994, 1995, 1996\n\
|
||||
Keith Bostic. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: main.c,v 10.63 2001/11/01 15:24:43 skimo Exp (Berkeley) Date: 2001/11/01 15:24:43";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "../vi/vi.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
static void v_estr __P((const char *, int, const char *));
|
||||
static int v_obsolete __P((char *, char *[]));
|
||||
|
||||
/*
|
||||
* editor --
|
||||
* Main editor routine.
|
||||
*
|
||||
* PUBLIC: int editor __P((WIN *, int, char *[]));
|
||||
*/
|
||||
int
|
||||
editor(WIN *wp, int argc, char **argv)
|
||||
{
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
const char *p;
|
||||
EVENT ev;
|
||||
FREF *frp;
|
||||
SCR *sp;
|
||||
GS *gp;
|
||||
size_t len;
|
||||
u_int flags;
|
||||
int ch, flagchk, lflag, secure, startup, readonly, rval, silent;
|
||||
#ifdef GTAGS
|
||||
int gtags = 0;
|
||||
#endif
|
||||
char *tag_f, *wsizearg, path[256];
|
||||
const CHAR_T *w;
|
||||
size_t wlen;
|
||||
|
||||
gp = wp->gp;
|
||||
|
||||
/* Initialize the busy routine, if not defined by the screen. */
|
||||
if (gp->scr_busy == NULL)
|
||||
gp->scr_busy = vs_busy;
|
||||
/* Initialize the message routine, if not defined by the screen. */
|
||||
if (wp->scr_msg == NULL)
|
||||
wp->scr_msg = vs_msg;
|
||||
|
||||
/* Set initial screen type and mode based on the program name. */
|
||||
readonly = 0;
|
||||
if (!strcmp(gp->progname, "ex") || !strcmp(gp->progname, "nex"))
|
||||
LF_INIT(SC_EX);
|
||||
else {
|
||||
/* Nview, view are readonly. */
|
||||
if (!strcmp(gp->progname, "nview") ||
|
||||
!strcmp(gp->progname, "view"))
|
||||
readonly = 1;
|
||||
|
||||
/* Vi is the default. */
|
||||
LF_INIT(SC_VI);
|
||||
}
|
||||
|
||||
/* Convert old-style arguments into new-style ones. */
|
||||
if (v_obsolete(gp->progname, argv))
|
||||
return (1);
|
||||
|
||||
/* Parse the arguments. */
|
||||
flagchk = '\0';
|
||||
tag_f = wsizearg = NULL;
|
||||
lflag = secure = silent = 0;
|
||||
startup = 1;
|
||||
|
||||
/* Set the file snapshot flag. */
|
||||
F_SET(gp, G_SNAPSHOT);
|
||||
|
||||
while ((ch = getopt(argc, argv, "c:"
|
||||
#ifdef DEBUG
|
||||
"D:"
|
||||
#endif
|
||||
"eF"
|
||||
#ifdef GTAGS
|
||||
"G"
|
||||
#endif
|
||||
"lRrSsT:t:vw:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'c': /* Run the command. */
|
||||
/*
|
||||
* XXX
|
||||
* We should support multiple -c options.
|
||||
*/
|
||||
if (gp->c_option != NULL) {
|
||||
v_estr(gp->progname, 0,
|
||||
"only one -c command may be specified.");
|
||||
return (1);
|
||||
}
|
||||
gp->c_option = optarg;
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case 'D':
|
||||
switch (optarg[0]) {
|
||||
case 's':
|
||||
startup = 0;
|
||||
break;
|
||||
case 'w':
|
||||
attach(gp);
|
||||
break;
|
||||
default:
|
||||
v_estr(gp->progname, 0,
|
||||
"usage: -D requires s or w argument.");
|
||||
return (1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 'e': /* Ex mode. */
|
||||
LF_CLR(SC_VI);
|
||||
LF_SET(SC_EX);
|
||||
break;
|
||||
case 'F': /* No snapshot. */
|
||||
v_estr(gp->progname, 0,
|
||||
"-F option no longer supported.");
|
||||
break;
|
||||
case 'l': /* Set lisp, showmatch options. */
|
||||
lflag = 1;
|
||||
break;
|
||||
#ifdef GTAGS
|
||||
case 'G': /* gtags mode. */
|
||||
gtags = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'R': /* Readonly. */
|
||||
readonly = 1;
|
||||
break;
|
||||
case 'r': /* Recover. */
|
||||
if (flagchk == 't') {
|
||||
v_estr(gp->progname, 0,
|
||||
"only one of -r and -t may be specified.");
|
||||
return (1);
|
||||
}
|
||||
flagchk = 'r';
|
||||
break;
|
||||
case 'S':
|
||||
secure = 1;
|
||||
break;
|
||||
case 's':
|
||||
silent = 1;
|
||||
break;
|
||||
#ifdef TRACE
|
||||
case 'T': /* Trace. */
|
||||
(void)vtrace_init(optarg);
|
||||
break;
|
||||
#endif
|
||||
case 't': /* Tag. */
|
||||
if (flagchk == 'r') {
|
||||
v_estr(gp->progname, 0,
|
||||
"only one of -r and -t may be specified.");
|
||||
return (1);
|
||||
}
|
||||
if (flagchk == 't') {
|
||||
v_estr(gp->progname, 0,
|
||||
"only one tag file may be specified.");
|
||||
return (1);
|
||||
}
|
||||
flagchk = 't';
|
||||
tag_f = optarg;
|
||||
break;
|
||||
case 'v': /* Vi mode. */
|
||||
LF_CLR(SC_EX);
|
||||
LF_SET(SC_VI);
|
||||
break;
|
||||
case 'w':
|
||||
wsizearg = optarg;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
(void)gp->scr_usage();
|
||||
return (1);
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/*
|
||||
* -s option is only meaningful to ex.
|
||||
*
|
||||
* If not reading from a terminal, it's like -s was specified.
|
||||
*/
|
||||
if (silent && !LF_ISSET(SC_EX)) {
|
||||
v_estr(gp->progname, 0, "-s option is only applicable to ex.");
|
||||
goto err;
|
||||
}
|
||||
if (LF_ISSET(SC_EX) && F_ISSET(gp, G_SCRIPTED))
|
||||
silent = 1;
|
||||
|
||||
/*
|
||||
* Build and initialize the first/current screen. This is a bit
|
||||
* tricky. If an error is returned, we may or may not have a
|
||||
* screen structure. If we have a screen structure, put it on a
|
||||
* display queue so that the error messages get displayed.
|
||||
*
|
||||
* !!!
|
||||
* Everything we do until we go interactive is done in ex mode.
|
||||
*/
|
||||
if (screen_init(gp, NULL, &sp)) {
|
||||
if (sp != NULL) {
|
||||
CIRCLEQ_INSERT_HEAD(&wp->scrq, sp, q);
|
||||
sp->wp = wp;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
F_SET(sp, SC_EX);
|
||||
CIRCLEQ_INSERT_HEAD(&wp->scrq, sp, q);
|
||||
sp->wp = wp;
|
||||
|
||||
if (v_key_init(sp)) /* Special key initialization. */
|
||||
goto err;
|
||||
|
||||
{ int oargs[5], *oargp = oargs;
|
||||
if (lflag) { /* Command-line options. */
|
||||
*oargp++ = O_LISP;
|
||||
*oargp++ = O_SHOWMATCH;
|
||||
}
|
||||
if (readonly)
|
||||
*oargp++ = O_READONLY;
|
||||
#ifdef GTAGS
|
||||
if (gtags)
|
||||
*oargp++ = O_GTAGSMODE;
|
||||
#endif
|
||||
if (secure)
|
||||
*oargp++ = O_SECURE;
|
||||
*oargp = -1; /* Options initialization. */
|
||||
if (opts_init(sp, oargs))
|
||||
goto err;
|
||||
}
|
||||
if (wsizearg != NULL) {
|
||||
ARGS *av[2], a, b;
|
||||
(void)snprintf(path, sizeof(path), "window=%s", wsizearg);
|
||||
a.bp = (CHAR_T *)path;
|
||||
a.len = strlen(path);
|
||||
b.bp = NULL;
|
||||
b.len = 0;
|
||||
av[0] = &a;
|
||||
av[1] = &b;
|
||||
(void)opts_set(sp, av, NULL);
|
||||
}
|
||||
if (silent) { /* Ex batch mode option values. */
|
||||
O_CLR(sp, O_AUTOPRINT);
|
||||
O_CLR(sp, O_PROMPT);
|
||||
O_CLR(sp, O_VERBOSE);
|
||||
O_CLR(sp, O_WARN);
|
||||
F_SET(sp, SC_EX_SILENT);
|
||||
}
|
||||
|
||||
sp->rows = O_VAL(sp, O_LINES); /* Make ex formatting work. */
|
||||
sp->cols = O_VAL(sp, O_COLUMNS);
|
||||
|
||||
if (!silent && startup) { /* Read EXINIT, exrc files. */
|
||||
if (ex_exrc(sp))
|
||||
goto err;
|
||||
if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
|
||||
if (screen_end(sp))
|
||||
goto err;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* List recovery files if -r specified without file arguments.
|
||||
* Note, options must be initialized and startup information
|
||||
* read before doing this.
|
||||
*/
|
||||
if (flagchk == 'r' && argv[0] == NULL) {
|
||||
if (rcv_list(sp))
|
||||
goto err;
|
||||
if (screen_end(sp))
|
||||
goto err;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Initialize the default ^D, ^U scrolling value here, after the
|
||||
* user has had every opportunity to set the window option.
|
||||
*
|
||||
* It's historic practice that changing the value of the window
|
||||
* option did not alter the default scrolling value, only giving
|
||||
* a count to ^D/^U did that.
|
||||
*/
|
||||
sp->defscroll = (O_VAL(sp, O_WINDOW) + 1) / 2;
|
||||
|
||||
/*
|
||||
* If we don't have a command-line option, switch into the right
|
||||
* editor now, so that we position default files correctly, and
|
||||
* so that any tags file file-already-locked messages are in the
|
||||
* vi screen, not the ex screen.
|
||||
*
|
||||
* XXX
|
||||
* If we have a command-line option, the error message can end
|
||||
* up in the wrong place, but I think that the combination is
|
||||
* unlikely.
|
||||
*/
|
||||
if (gp->c_option == NULL) {
|
||||
F_CLR(sp, SC_EX | SC_VI);
|
||||
F_SET(sp, LF_ISSET(SC_EX | SC_VI));
|
||||
}
|
||||
|
||||
/* Open a tag file if specified. */
|
||||
if (tag_f != NULL) {
|
||||
CHAR2INT(sp, tag_f, strlen(tag_f) + 1, w, wlen);
|
||||
if (ex_tag_first(sp, w))
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append any remaining arguments as file names. Files are recovery
|
||||
* files if -r specified. If the tag option or ex startup commands
|
||||
* loaded a file, then any file arguments are going to come after it.
|
||||
*/
|
||||
if (*argv != NULL) {
|
||||
if (sp->frp != NULL) {
|
||||
/* Cheat -- we know we have an extra argv slot. */
|
||||
MALLOC_NOMSG(sp,
|
||||
*--argv, char *, strlen(sp->frp->name) + 1);
|
||||
if (*argv == NULL) {
|
||||
v_estr(gp->progname, errno, NULL);
|
||||
goto err;
|
||||
}
|
||||
(void)strcpy(*argv, sp->frp->name);
|
||||
}
|
||||
sp->argv = sp->cargv = argv;
|
||||
F_SET(sp, SC_ARGNOFREE);
|
||||
if (flagchk == 'r')
|
||||
F_SET(sp, SC_ARGRECOVER);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the ex startup commands and or/the tag option haven't already
|
||||
* created a file, create one. If no command-line files were given,
|
||||
* use a temporary file.
|
||||
*/
|
||||
if (sp->frp == NULL) {
|
||||
if (sp->argv == NULL) {
|
||||
if ((frp = file_add(sp, NULL)) == NULL)
|
||||
goto err;
|
||||
} else {
|
||||
if ((frp = file_add(sp, sp->argv[0])) == NULL)
|
||||
goto err;
|
||||
if (F_ISSET(sp, SC_ARGRECOVER))
|
||||
F_SET(frp, FR_RECOVER);
|
||||
}
|
||||
|
||||
if (file_init(sp, frp, NULL, 0))
|
||||
goto err;
|
||||
if (EXCMD_RUNNING(wp)) {
|
||||
(void)ex_cmd(sp);
|
||||
if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
|
||||
if (screen_end(sp))
|
||||
goto err;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if we need to wait for ex. If SC_SCR_EX is set, ex
|
||||
* was forced to initialize the screen during startup. We'd like to
|
||||
* wait for a single character from the user, but we can't because
|
||||
* we're not in raw mode. We can't switch to raw mode because the
|
||||
* vi initialization will switch to xterm's alternate screen, causing
|
||||
* us to lose the messages we're pausing to make sure the user read.
|
||||
* So, wait for a complete line.
|
||||
*/
|
||||
if (F_ISSET(sp, SC_SCR_EX)) {
|
||||
p = msg_cmsg(sp, CMSG_CONT_R, &len);
|
||||
(void)write(STDOUT_FILENO, p, len);
|
||||
for (;;) {
|
||||
if (v_event_get(sp, &ev, 0, 0))
|
||||
goto err;
|
||||
if (ev.e_event == E_INTERRUPT ||
|
||||
(ev.e_event == E_CHARACTER &&
|
||||
(ev.e_value == K_CR || ev.e_value == K_NL)))
|
||||
break;
|
||||
(void)gp->scr_bell(sp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch into the right editor, regardless. */
|
||||
F_CLR(sp, SC_EX | SC_VI);
|
||||
F_SET(sp, LF_ISSET(SC_EX | SC_VI) | SC_STATUS_CNT);
|
||||
|
||||
/*
|
||||
* Main edit loop. Vi handles split screens itself, we only return
|
||||
* here when switching editor modes or restarting the screen.
|
||||
*/
|
||||
while (sp != NULL)
|
||||
if (F_ISSET(sp, SC_EX) ? ex(&sp) : vi(&sp))
|
||||
goto err;
|
||||
|
||||
done: rval = 0;
|
||||
if (0)
|
||||
err: rval = 1;
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_obsolete --
|
||||
* Convert historic arguments into something getopt(3) will like.
|
||||
*/
|
||||
static int
|
||||
v_obsolete(char *name, char **argv)
|
||||
{
|
||||
size_t len;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* Translate old style arguments into something getopt will like.
|
||||
* Make sure it's not text space memory, because ex modifies the
|
||||
* strings.
|
||||
* Change "+" into "-c$".
|
||||
* Change "+<anything else>" into "-c<anything else>".
|
||||
* Change "-" into "-s"
|
||||
* The c, T, t and w options take arguments so they can't be
|
||||
* special arguments.
|
||||
*
|
||||
* Stop if we find "--" as an argument, the user may want to edit
|
||||
* a file named "+foo".
|
||||
*/
|
||||
while (*++argv && strcmp(argv[0], "--"))
|
||||
if (argv[0][0] == '+') {
|
||||
if (argv[0][1] == '\0') {
|
||||
MALLOC_NOMSG(NULL, argv[0], char *, 4);
|
||||
if (argv[0] == NULL)
|
||||
goto nomem;
|
||||
(void)strcpy(argv[0], "-c$");
|
||||
} else {
|
||||
p = argv[0];
|
||||
len = strlen(argv[0]);
|
||||
MALLOC_NOMSG(NULL, argv[0], char *, len + 2);
|
||||
if (argv[0] == NULL)
|
||||
goto nomem;
|
||||
argv[0][0] = '-';
|
||||
argv[0][1] = 'c';
|
||||
(void)strcpy(argv[0] + 2, p + 1);
|
||||
}
|
||||
} else if (argv[0][0] == '-') {
|
||||
if (argv[0][1] == '\0') {
|
||||
MALLOC_NOMSG(NULL, argv[0], char *, 3);
|
||||
if (argv[0] == NULL) {
|
||||
nomem: v_estr(name, errno, NULL);
|
||||
return (1);
|
||||
}
|
||||
(void)strcpy(argv[0], "-s");
|
||||
} else
|
||||
if ((argv[0][1] == 'c' || argv[0][1] == 'T' ||
|
||||
argv[0][1] == 't' || argv[0][1] == 'w') &&
|
||||
argv[0][2] == '\0')
|
||||
++argv;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
attach(GS *gp)
|
||||
{
|
||||
int fd;
|
||||
char ch;
|
||||
|
||||
if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) {
|
||||
v_estr(gp->progname, errno, _PATH_TTY);
|
||||
return;
|
||||
}
|
||||
|
||||
(void)printf("process %lu waiting, enter <CR> to continue: ",
|
||||
(u_long)getpid());
|
||||
(void)fflush(stdout);
|
||||
|
||||
do {
|
||||
if (read(fd, &ch, 1) != 1) {
|
||||
(void)close(fd);
|
||||
return;
|
||||
}
|
||||
} while (ch != '\n' && ch != '\r');
|
||||
(void)close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
v_estr(const char *name, int eno, const char *msg)
|
||||
{
|
||||
(void)fprintf(stderr, "%s", name);
|
||||
if (msg != NULL)
|
||||
(void)fprintf(stderr, ": %s", msg);
|
||||
if (eno)
|
||||
(void)fprintf(stderr, ": %s", strerror(errno));
|
||||
(void)fprintf(stderr, "\n");
|
||||
}
|
||||
263
dist/nvi/common/mark.c
vendored
Normal file
263
dist/nvi/common/mark.c
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
/* $NetBSD: mark.c,v 1.3 2009/01/18 03:45:50 lukem 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: mark.c,v 10.15 2001/06/25 15:19:11 skimo Exp (Berkeley) Date: 2001/06/25 15:19:11";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static LMARK *mark_find __P((SCR *, ARG_CHAR_T));
|
||||
|
||||
/*
|
||||
* Marks are maintained in a key sorted doubly linked list. We can't
|
||||
* use arrays because we have no idea how big an index key could be.
|
||||
* The underlying assumption is that users don't have more than, say,
|
||||
* 10 marks at any one time, so this will be is fast enough.
|
||||
*
|
||||
* Marks are fixed, and modifications to the line don't update the mark's
|
||||
* position in the line. This can be hard. If you add text to the line,
|
||||
* place a mark in that text, undo the addition and use ` to move to the
|
||||
* mark, the location will have disappeared. It's tempting to try to adjust
|
||||
* the mark with the changes in the line, but this is hard to do, especially
|
||||
* if we've given the line to v_ntext.c:v_ntext() for editing. Historic vi
|
||||
* would move to the first non-blank on the line when the mark location was
|
||||
* past the end of the line. This can be complicated by deleting to a mark
|
||||
* that has disappeared using the ` command. Historic vi treated this as
|
||||
* a line-mode motion and deleted the line. This implementation complains to
|
||||
* the user.
|
||||
*
|
||||
* In historic vi, marks returned if the operation was undone, unless the
|
||||
* mark had been subsequently reset. Tricky. This is hard to start with,
|
||||
* but in the presence of repeated undo it gets nasty. When a line is
|
||||
* deleted, we delete (and log) any marks on that line. An undo will create
|
||||
* the mark. Any mark creations are noted as to whether the user created
|
||||
* it or if it was created by an undo. The former cannot be reset by another
|
||||
* undo, but the latter may.
|
||||
*
|
||||
* All of these routines translate ABSMARK2 to ABSMARK1. Setting either of
|
||||
* the absolute mark locations sets both, so that "m'" and "m`" work like
|
||||
* they, ah, for lack of a better word, "should".
|
||||
*/
|
||||
|
||||
/*
|
||||
* mark_init --
|
||||
* Set up the marks.
|
||||
*
|
||||
* PUBLIC: int mark_init __P((SCR *, EXF *));
|
||||
*/
|
||||
int
|
||||
mark_init(SCR *sp, EXF *ep)
|
||||
{
|
||||
/*
|
||||
* !!!
|
||||
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
|
||||
*
|
||||
* Set up the marks.
|
||||
*/
|
||||
LIST_INIT(&ep->marks);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* mark_end --
|
||||
* Free up the marks.
|
||||
*
|
||||
* PUBLIC: int mark_end __P((SCR *, EXF *));
|
||||
*/
|
||||
int
|
||||
mark_end(SCR *sp, EXF *ep)
|
||||
{
|
||||
LMARK *lmp;
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
|
||||
*/
|
||||
while ((lmp = ep->marks.lh_first) != NULL) {
|
||||
LIST_REMOVE(lmp, q);
|
||||
free(lmp);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* mark_get --
|
||||
* Get the location referenced by a mark.
|
||||
*
|
||||
* PUBLIC: int mark_get __P((SCR *, ARG_CHAR_T, MARK *, mtype_t));
|
||||
*/
|
||||
int
|
||||
mark_get(SCR *sp, ARG_CHAR_T key, MARK *mp, mtype_t mtype)
|
||||
{
|
||||
LMARK *lmp;
|
||||
|
||||
if (key == ABSMARK2)
|
||||
key = ABSMARK1;
|
||||
|
||||
lmp = mark_find(sp, key);
|
||||
if (lmp == NULL || (ARG_CHAR_T)lmp->name != key) {
|
||||
msgq(sp, mtype, "017|Mark %s: not set", KEY_NAME(sp, key));
|
||||
return (1);
|
||||
}
|
||||
if (F_ISSET(lmp, MARK_DELETED)) {
|
||||
msgq(sp, mtype,
|
||||
"018|Mark %s: the line was deleted", KEY_NAME(sp, key));
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* The absolute mark is initialized to lno 1/cno 0, and historically
|
||||
* you could use it in an empty file. Make such a mark always work.
|
||||
*/
|
||||
if ((lmp->lno != 1 || lmp->cno != 0) && !db_exist(sp, lmp->lno)) {
|
||||
msgq(sp, mtype,
|
||||
"019|Mark %s: cursor position no longer exists",
|
||||
KEY_NAME(sp, key));
|
||||
return (1);
|
||||
}
|
||||
mp->lno = lmp->lno;
|
||||
mp->cno = lmp->cno;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* mark_set --
|
||||
* Set the location referenced by a mark.
|
||||
*
|
||||
* PUBLIC: int mark_set __P((SCR *, ARG_CHAR_T, MARK *, int));
|
||||
*/
|
||||
int
|
||||
mark_set(SCR *sp, ARG_CHAR_T key, MARK *value, int userset)
|
||||
{
|
||||
LMARK *lmp, *lmt;
|
||||
|
||||
if (key == ABSMARK2)
|
||||
key = ABSMARK1;
|
||||
|
||||
/*
|
||||
* The rules are simple. If the user is setting a mark (if it's a
|
||||
* new mark this is always true), it always happens. If not, it's
|
||||
* an undo, and we set it if it's not already set or if it was set
|
||||
* by a previous undo.
|
||||
*/
|
||||
lmp = mark_find(sp, key);
|
||||
if (lmp == NULL || (ARG_CHAR_T)lmp->name != key) {
|
||||
MALLOC_RET(sp, lmt, LMARK *, sizeof(LMARK));
|
||||
if (lmp == NULL) {
|
||||
LIST_INSERT_HEAD(&sp->ep->marks, lmt, q);
|
||||
} else
|
||||
LIST_INSERT_AFTER(lmp, lmt, q);
|
||||
lmp = lmt;
|
||||
} else if (!userset &&
|
||||
!F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET))
|
||||
return (0);
|
||||
|
||||
lmp->lno = value->lno;
|
||||
lmp->cno = value->cno;
|
||||
lmp->name = key;
|
||||
lmp->flags = userset ? MARK_USERSET : 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* mark_find --
|
||||
* Find the requested mark, or, the slot immediately before
|
||||
* where it would go.
|
||||
*/
|
||||
static LMARK *
|
||||
mark_find(SCR *sp, ARG_CHAR_T key)
|
||||
{
|
||||
LMARK *lmp, *lastlmp;
|
||||
|
||||
/*
|
||||
* Return the requested mark or the slot immediately before
|
||||
* where it should go.
|
||||
*/
|
||||
for (lastlmp = NULL, lmp = sp->ep->marks.lh_first;
|
||||
lmp != NULL; lastlmp = lmp, lmp = lmp->q.le_next)
|
||||
if ((ARG_CHAR_T)lmp->name >= key)
|
||||
return ((ARG_CHAR_T)lmp->name == key ? lmp : lastlmp);
|
||||
return (lastlmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* mark_insdel --
|
||||
* Update the marks based on an insertion or deletion.
|
||||
*
|
||||
* PUBLIC: int mark_insdel __P((SCR *, lnop_t, db_recno_t));
|
||||
*/
|
||||
int
|
||||
mark_insdel(SCR *sp, lnop_t op, db_recno_t lno)
|
||||
{
|
||||
LMARK *lmp;
|
||||
db_recno_t lline;
|
||||
|
||||
switch (op) {
|
||||
case LINE_APPEND:
|
||||
/* All insert/append operations are done as inserts. */
|
||||
abort();
|
||||
case LINE_DELETE:
|
||||
for (lmp = sp->ep->marks.lh_first;
|
||||
lmp != NULL; lmp = lmp->q.le_next)
|
||||
if (lmp->lno >= lno) {
|
||||
if (lmp->lno == lno) {
|
||||
F_SET(lmp, MARK_DELETED);
|
||||
(void)log_mark(sp, lmp);
|
||||
} else
|
||||
--lmp->lno;
|
||||
}
|
||||
break;
|
||||
case LINE_INSERT:
|
||||
/*
|
||||
* XXX
|
||||
* Very nasty special case. If the file was empty, then we're
|
||||
* adding the first line, which is a replacement. So, we don't
|
||||
* modify the marks. This is a hack to make:
|
||||
*
|
||||
* mz:r!echo foo<carriage-return>'z
|
||||
*
|
||||
* work, i.e. historically you could mark the "line" in an empty
|
||||
* file and replace it, and continue to use the mark. Insane,
|
||||
* well, yes, I know, but someone complained.
|
||||
*
|
||||
* Check for line #2 before going to the end of the file.
|
||||
*/
|
||||
if (!db_exist(sp, 2)) {
|
||||
if (db_last(sp, &lline))
|
||||
return (1);
|
||||
if (lline == 1)
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (lmp = sp->ep->marks.lh_first;
|
||||
lmp != NULL; lmp = lmp->q.le_next)
|
||||
if (lmp->lno >= lno)
|
||||
++lmp->lno;
|
||||
break;
|
||||
case LINE_RESET:
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
45
dist/nvi/common/mark.h
vendored
Normal file
45
dist/nvi/common/mark.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/* $NetBSD: mark.h,v 1.1.1.2 2008/05/18 14:29:47 aymeric 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*
|
||||
* Id: mark.h,v 10.5 2000/07/14 14:29:16 skimo Exp (Berkeley) Date: 2000/07/14 14:29:16
|
||||
*/
|
||||
|
||||
/*
|
||||
* The MARK and LMARK structures define positions in the file. There are
|
||||
* two structures because the mark subroutines are the only places where
|
||||
* anything cares about something other than line and column.
|
||||
*
|
||||
* Because of the different interfaces used by the db(3) package, curses,
|
||||
* and users, the line number is 1 based and the column number is 0 based.
|
||||
* Additionally, it is known that the out-of-band line number is less than
|
||||
* any legal line number. The line number is of type db_recno_t, as that's
|
||||
* the underlying type of the database. The column number is of type size_t,
|
||||
* guaranteeing that we can malloc a line.
|
||||
*/
|
||||
struct _mark {
|
||||
#define OOBLNO 0 /* Out-of-band line number. */
|
||||
db_recno_t lno; /* Line number. */
|
||||
size_t cno; /* Column number. */
|
||||
};
|
||||
|
||||
struct _lmark {
|
||||
LIST_ENTRY(_lmark) q; /* Linked list of marks. */
|
||||
db_recno_t lno; /* Line number. */
|
||||
size_t cno; /* Column number. */
|
||||
/* XXXX Needed ? Can non ascii-chars be mark names ? */
|
||||
CHAR_T name; /* Mark name. */
|
||||
|
||||
#define MARK_DELETED 0x01 /* Mark was deleted. */
|
||||
#define MARK_USERSET 0x02 /* User set this mark. */
|
||||
u_int8_t flags;
|
||||
};
|
||||
|
||||
#define ABSMARK1 '\'' /* Absolute mark name. */
|
||||
#define ABSMARK2 '`' /* Absolute mark name. */
|
||||
207
dist/nvi/common/mem.h
vendored
Normal file
207
dist/nvi/common/mem.h
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/* $NetBSD: mem.h,v 1.3 2009/01/18 03:43:45 lukem 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: mem.h,v 10.13 2002/01/05 23:13:37 skimo Exp (Berkeley) Date: 2002/01/05 23:13:37
|
||||
*/
|
||||
|
||||
#if defined(HAVE_GCC) && !defined(__NetBSD__)
|
||||
#define CHECK_TYPE(type, var) \
|
||||
do { type L__lp __attribute__((__unused__)) = var; } while (/*CONSTCOND*/0);
|
||||
#else
|
||||
#define CHECK_TYPE(type, var)
|
||||
#endif
|
||||
|
||||
/* Increase the size of a malloc'd buffer. Two versions, one that
|
||||
* returns, one that jumps to an error label.
|
||||
*/
|
||||
#define BINC_GOTO(sp, type, lp, llen, nlen) { \
|
||||
CHECK_TYPE(type *, lp) \
|
||||
void *L__bincp; \
|
||||
if ((nlen) > llen) { \
|
||||
if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL) \
|
||||
goto alloc_err; \
|
||||
/* \
|
||||
* !!! \
|
||||
* Possible pointer conversion. \
|
||||
*/ \
|
||||
lp = L__bincp; \
|
||||
} \
|
||||
}
|
||||
#define BINC_GOTOC(sp, lp, llen, nlen) \
|
||||
BINC_GOTO(sp, char, lp, llen, nlen)
|
||||
#define BINC_GOTOW(sp, lp, llen, nlen) \
|
||||
BINC_GOTO(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T))
|
||||
#define BINC_RET(sp, type, lp, llen, nlen) { \
|
||||
CHECK_TYPE(type *, lp) \
|
||||
void *L__bincp; \
|
||||
if ((size_t)(nlen) > llen) { \
|
||||
if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL) \
|
||||
return (1); \
|
||||
/* \
|
||||
* !!! \
|
||||
* Possible pointer conversion. \
|
||||
*/ \
|
||||
lp = L__bincp; \
|
||||
} \
|
||||
}
|
||||
#define BINC_RETC(sp, lp, llen, nlen) \
|
||||
BINC_RET(sp, char, lp, llen, nlen)
|
||||
#define BINC_RETW(sp, lp, llen, nlen) \
|
||||
BINC_RET(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T))
|
||||
|
||||
/*
|
||||
* Get some temporary space, preferably from the global temporary buffer,
|
||||
* from a malloc'd buffer otherwise. Two versions, one that returns, one
|
||||
* that jumps to an error label.
|
||||
*/
|
||||
#define GET_SPACE_GOTO(sp, type, bp, blen, nlen) { \
|
||||
CHECK_TYPE(type *, bp) \
|
||||
WIN *L__wp = (sp) == NULL ? NULL : (sp)->wp; \
|
||||
if (L__wp == NULL || F_ISSET(L__wp, W_TMP_INUSE)) { \
|
||||
bp = NULL; \
|
||||
blen = 0; \
|
||||
BINC_GOTO(sp, type, bp, blen, nlen); \
|
||||
} else { \
|
||||
BINC_GOTOC(sp, L__wp->tmp_bp, L__wp->tmp_blen, nlen); \
|
||||
bp = (type *) L__wp->tmp_bp; \
|
||||
blen = L__wp->tmp_blen; \
|
||||
F_SET(L__wp, W_TMP_INUSE); \
|
||||
} \
|
||||
}
|
||||
#define GET_SPACE_GOTOC(sp, bp, blen, nlen) \
|
||||
GET_SPACE_GOTO(sp, char, bp, blen, nlen)
|
||||
#define GET_SPACE_GOTOW(sp, bp, blen, nlen) \
|
||||
GET_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
|
||||
#define GET_SPACE_RET(sp, type, bp, blen, nlen) { \
|
||||
CHECK_TYPE(type *, bp) \
|
||||
WIN *L__wp = (sp) == NULL ? NULL : (sp)->wp; \
|
||||
if (L__wp == NULL || F_ISSET(L__wp, W_TMP_INUSE)) { \
|
||||
bp = NULL; \
|
||||
blen = 0; \
|
||||
BINC_RET(sp, type, bp, blen, nlen); \
|
||||
} else { \
|
||||
BINC_RETC(sp, L__wp->tmp_bp, L__wp->tmp_blen, nlen); \
|
||||
bp = (type *) L__wp->tmp_bp; \
|
||||
blen = L__wp->tmp_blen; \
|
||||
F_SET(L__wp, W_TMP_INUSE); \
|
||||
} \
|
||||
}
|
||||
#define GET_SPACE_RETC(sp, bp, blen, nlen) \
|
||||
GET_SPACE_RET(sp, char, bp, blen, nlen)
|
||||
#define GET_SPACE_RETW(sp, bp, blen, nlen) \
|
||||
GET_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
|
||||
|
||||
/*
|
||||
* Add space to a GET_SPACE returned buffer. Two versions, one that
|
||||
* returns, one that jumps to an error label.
|
||||
*/
|
||||
#define ADD_SPACE_GOTO(sp, type, bp, blen, nlen) { \
|
||||
WIN *L__wp = (sp) == NULL ? NULL : (sp)->wp; \
|
||||
CHECK_TYPE(type *, bp) \
|
||||
if (L__wp == NULL || bp == (type *)L__wp->tmp_bp) { \
|
||||
F_CLR(L__wp, W_TMP_INUSE); \
|
||||
BINC_GOTOC(sp, L__wp->tmp_bp, L__wp->tmp_blen, nlen); \
|
||||
bp = (type *) L__wp->tmp_bp; \
|
||||
blen = L__wp->tmp_blen; \
|
||||
F_SET(L__wp, W_TMP_INUSE); \
|
||||
} else \
|
||||
BINC_GOTO(sp, type, bp, blen, nlen); \
|
||||
}
|
||||
#define ADD_SPACE_GOTOW(sp, bp, blen, nlen) \
|
||||
ADD_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
|
||||
#define ADD_SPACE_RET(sp, type, bp, blen, nlen) { \
|
||||
CHECK_TYPE(type *, bp) \
|
||||
WIN *L__wp = (sp) == NULL ? NULL : (sp)->wp; \
|
||||
if (L__wp == NULL || bp == (type *)L__wp->tmp_bp) { \
|
||||
F_CLR(L__wp, W_TMP_INUSE); \
|
||||
BINC_RETC(sp, L__wp->tmp_bp, L__wp->tmp_blen, nlen); \
|
||||
bp = (type *) L__wp->tmp_bp; \
|
||||
blen = L__wp->tmp_blen; \
|
||||
F_SET(L__wp, W_TMP_INUSE); \
|
||||
} else \
|
||||
BINC_RET(sp, type, bp, blen, nlen); \
|
||||
}
|
||||
#define ADD_SPACE_RETW(sp, bp, blen, nlen) \
|
||||
ADD_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
|
||||
|
||||
/* Free a GET_SPACE returned buffer. */
|
||||
#define FREE_SPACE(sp, bp, blen) { \
|
||||
WIN *L__wp = (sp) == NULL ? NULL : (sp)->wp; \
|
||||
if (L__wp != NULL && bp == L__wp->tmp_bp) \
|
||||
F_CLR(L__wp, W_TMP_INUSE); \
|
||||
else \
|
||||
free(bp); \
|
||||
}
|
||||
#define FREE_SPACEW(sp, bp, blen) { \
|
||||
CHECK_TYPE(CHAR_T *, bp) \
|
||||
FREE_SPACE(sp, (char *)bp, blen); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Malloc a buffer, casting the return pointer. Various versions.
|
||||
*
|
||||
* !!!
|
||||
* The cast should be unnecessary, malloc(3) and friends return void *'s,
|
||||
* which is all we need. However, some systems that nvi needs to run on
|
||||
* don't do it right yet, resulting in the compiler printing out roughly
|
||||
* a million warnings. After awhile, it seemed easier to put the casts
|
||||
* in instead of explaining it all the time.
|
||||
*/
|
||||
#define CALLOC(sp, p, cast, nmemb, size) { \
|
||||
if ((p = (cast)calloc(nmemb, size)) == NULL) \
|
||||
msgq(sp, M_SYSERR, NULL); \
|
||||
}
|
||||
#define CALLOC_GOTO(sp, p, cast, nmemb, size) { \
|
||||
if ((p = (cast)calloc(nmemb, size)) == NULL) \
|
||||
goto alloc_err; \
|
||||
}
|
||||
#define CALLOC_NOMSG(sp, p, cast, nmemb, size) { \
|
||||
p = (cast)calloc(nmemb, size); \
|
||||
}
|
||||
#define CALLOC_RET(sp, p, cast, nmemb, size) { \
|
||||
if ((p = (cast)calloc(nmemb, size)) == NULL) { \
|
||||
msgq(sp, M_SYSERR, NULL); \
|
||||
return (1); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MALLOC(sp, p, cast, size) { \
|
||||
if ((p = (cast)malloc(size)) == NULL) \
|
||||
msgq(sp, M_SYSERR, NULL); \
|
||||
}
|
||||
#define MALLOC_GOTO(sp, p, cast, size) { \
|
||||
if ((p = (cast)malloc(size)) == NULL) \
|
||||
goto alloc_err; \
|
||||
}
|
||||
#define MALLOC_NOMSG(sp, p, cast, size) { \
|
||||
p = (cast)malloc(size); \
|
||||
}
|
||||
#define MALLOC_RET(sp, p, cast, size) { \
|
||||
if ((p = (cast)malloc(size)) == NULL) { \
|
||||
msgq(sp, M_SYSERR, NULL); \
|
||||
return (1); \
|
||||
} \
|
||||
}
|
||||
/*
|
||||
* XXX
|
||||
* Don't depend on realloc(NULL, size) working.
|
||||
*/
|
||||
#define REALLOC(sp, p, cast, size) { \
|
||||
if ((p = (cast)(p == NULL ? \
|
||||
malloc(size) : realloc(p, size))) == NULL) \
|
||||
msgq(sp, M_SYSERR, NULL); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Versions of memmove(3) and memset(3) that use the size of the
|
||||
* initial pointer to figure out how much memory to manipulate.
|
||||
*/
|
||||
#define MEMMOVE(p, t, len) memmove(p, t, (len) * sizeof(*(p)))
|
||||
#define MEMSET(p, value, len) memset(p, value, (len) * sizeof(*(p)))
|
||||
929
dist/nvi/common/msg.c
vendored
Normal file
929
dist/nvi/common/msg.c
vendored
Normal file
@@ -0,0 +1,929 @@
|
||||
/* $NetBSD: msg.c,v 1.5 2011/08/17 12:56:55 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: msg.c,v 10.61 2003/07/18 23:17:30 skimo Exp (Berkeley) Date: 2003/07/18 23:17:30";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h> /* XXX: param.h may not have included types.h */
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "dbinternal.h"
|
||||
#include "../vi/vi.h"
|
||||
|
||||
/*
|
||||
* msgq --
|
||||
* Display a message.
|
||||
*
|
||||
* PUBLIC: void msgq __P((SCR *, mtype_t, const char *, ...));
|
||||
*/
|
||||
void
|
||||
#ifdef __STDC__
|
||||
msgq(SCR *sp, mtype_t mt, const char *fmt, ...)
|
||||
#else
|
||||
msgq(sp, mt, fmt, va_alist)
|
||||
SCR *sp;
|
||||
mtype_t mt;
|
||||
const char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
#ifndef NL_ARGMAX
|
||||
#define __NL_ARGMAX 20 /* Set to 9 by System V. */
|
||||
struct {
|
||||
const char *str; /* String pointer. */
|
||||
size_t arg; /* Argument number. */
|
||||
size_t prefix; /* Prefix string length. */
|
||||
size_t skip; /* Skipped string length. */
|
||||
size_t suffix; /* Suffix string length. */
|
||||
} str[__NL_ARGMAX];
|
||||
#endif
|
||||
static int reenter; /* STATIC: Re-entrancy check. */
|
||||
GS *gp;
|
||||
WIN *wp = NULL;
|
||||
size_t blen, len, mlen, nlen;
|
||||
const char *p;
|
||||
char *bp, *mp;
|
||||
va_list ap;
|
||||
#ifndef NL_ARGMAX
|
||||
int ch;
|
||||
char *rbp, *s_rbp;
|
||||
const char *t, *u;
|
||||
size_t cnt1, cnt2, soff;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* It's possible to enter msg when there's no screen to hold the
|
||||
* message. If sp is NULL, ignore the special cases and put the
|
||||
* message out to stderr.
|
||||
*/
|
||||
if (sp == NULL) {
|
||||
gp = NULL;
|
||||
if (mt == M_BERR)
|
||||
mt = M_ERR;
|
||||
else if (mt == M_VINFO)
|
||||
mt = M_INFO;
|
||||
} else {
|
||||
gp = sp->gp;
|
||||
wp = sp->wp;
|
||||
switch (mt) {
|
||||
case M_BERR:
|
||||
if (F_ISSET(sp, SC_VI) && !O_ISSET(sp, O_VERBOSE)) {
|
||||
F_SET(gp, G_BELLSCHED);
|
||||
return;
|
||||
}
|
||||
mt = M_ERR;
|
||||
break;
|
||||
case M_VINFO:
|
||||
if (!O_ISSET(sp, O_VERBOSE))
|
||||
return;
|
||||
mt = M_INFO;
|
||||
/* FALLTHROUGH */
|
||||
case M_INFO:
|
||||
if (F_ISSET(sp, SC_EX_SILENT))
|
||||
return;
|
||||
break;
|
||||
case M_ERR:
|
||||
case M_SYSERR:
|
||||
case M_DBERR:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It's possible to reenter msg when it allocates space. We're
|
||||
* probably dead anyway, but there's no reason to drop core.
|
||||
*
|
||||
* XXX
|
||||
* Yes, there's a race, but it should only be two instructions.
|
||||
*/
|
||||
if (reenter++)
|
||||
return;
|
||||
|
||||
/* Get space for the message. */
|
||||
nlen = 1024;
|
||||
if (0) {
|
||||
retry: FREE_SPACE(sp, bp, blen);
|
||||
nlen *= 2;
|
||||
}
|
||||
bp = NULL;
|
||||
blen = 0;
|
||||
GET_SPACE_GOTOC(sp, bp, blen, nlen);
|
||||
|
||||
/*
|
||||
* Error prefix.
|
||||
*
|
||||
* mp: pointer to the current next character to be written
|
||||
* mlen: length of the already written characters
|
||||
* blen: total length of the buffer
|
||||
*/
|
||||
#define REM (blen - mlen)
|
||||
mp = bp;
|
||||
mlen = 0;
|
||||
if (mt == M_SYSERR || mt == M_DBERR) {
|
||||
p = msg_cat(sp, "020|Error: ", &len);
|
||||
if (REM < len)
|
||||
goto retry;
|
||||
memcpy(mp, p, len);
|
||||
mp += len;
|
||||
mlen += len;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're running an ex command that the user didn't enter, display
|
||||
* the file name and line number prefix.
|
||||
*/
|
||||
if ((mt == M_ERR || mt == M_SYSERR) &&
|
||||
sp != NULL && wp != NULL && wp->if_name != NULL) {
|
||||
for (p = wp->if_name; *p != '\0'; ++p) {
|
||||
len = snprintf(mp, REM, "%s", KEY_NAME(sp, *p));
|
||||
mp += len;
|
||||
if ((mlen += len) > blen)
|
||||
goto retry;
|
||||
}
|
||||
len = snprintf(mp, REM, ", %d: ", wp->if_lno);
|
||||
mp += len;
|
||||
if ((mlen += len) > blen)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* If nothing to format, we're done. */
|
||||
if (fmt == NULL)
|
||||
goto nofmt;
|
||||
fmt = msg_cat(sp, fmt, NULL);
|
||||
|
||||
#ifndef NL_ARGMAX
|
||||
/*
|
||||
* Nvi should run on machines that don't support the numbered argument
|
||||
* specifications (%[digit]*$). We do this by reformatting the string
|
||||
* so that we can hand it to vsprintf(3) and it will use the arguments
|
||||
* in the right order. When vsprintf returns, we put the string back
|
||||
* into the right order. It's undefined, according to SVID III, to mix
|
||||
* numbered argument specifications with the standard style arguments,
|
||||
* so this should be safe.
|
||||
*
|
||||
* In addition, we also need a character that is known to not occur in
|
||||
* any vi message, for separating the parts of the string. As callers
|
||||
* of msgq are responsible for making sure that all the non-printable
|
||||
* characters are formatted for printing before calling msgq, we use a
|
||||
* random non-printable character selected at terminal initialization
|
||||
* time. This code isn't fast by any means, but as messages should be
|
||||
* relatively short and normally have only a few arguments, it won't be
|
||||
* too bad. Regardless, nobody has come up with any other solution.
|
||||
*
|
||||
* The result of this loop is an array of pointers into the message
|
||||
* string, with associated lengths and argument numbers. The array
|
||||
* is in the "correct" order, and the arg field contains the argument
|
||||
* order.
|
||||
*/
|
||||
for (p = fmt, soff = 0; soff < __NL_ARGMAX;) {
|
||||
for (t = p; *p != '\0' && *p != '%'; ++p);
|
||||
if (*p == '\0')
|
||||
break;
|
||||
++p;
|
||||
if (!isdigit((unsigned char)*p)) {
|
||||
if (*p == '%')
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
for (u = p; *++p != '\0' && isdigit((unsigned char)*p););
|
||||
if (*p != '$')
|
||||
continue;
|
||||
|
||||
/* Up to, and including the % character. */
|
||||
str[soff].str = t;
|
||||
str[soff].prefix = u - t;
|
||||
|
||||
/* Up to, and including the $ character. */
|
||||
str[soff].arg = atoi(u);
|
||||
str[soff].skip = (p - u) + 1;
|
||||
if (str[soff].arg >= __NL_ARGMAX)
|
||||
goto ret;
|
||||
|
||||
/* Up to, and including the conversion character. */
|
||||
for (u = p; (ch = (unsigned char)*++p) != '\0';)
|
||||
if (isalpha(ch) &&
|
||||
strchr("diouxXfeEgGcspn", ch) != NULL)
|
||||
break;
|
||||
str[soff].suffix = p - u;
|
||||
if (ch != '\0')
|
||||
++p;
|
||||
++soff;
|
||||
}
|
||||
|
||||
/* If no magic strings, we're done. */
|
||||
if (soff == 0)
|
||||
goto format;
|
||||
|
||||
/* Get space for the reordered strings. */
|
||||
if ((rbp = malloc(nlen)) == NULL)
|
||||
goto ret;
|
||||
s_rbp = rbp;
|
||||
|
||||
/*
|
||||
* Reorder the strings into the message string based on argument
|
||||
* order.
|
||||
*
|
||||
* !!!
|
||||
* We ignore arguments that are out of order, i.e. if we don't find
|
||||
* an argument, we continue. Assume (almost certainly incorrectly)
|
||||
* that whoever created the string knew what they were doing.
|
||||
*
|
||||
* !!!
|
||||
* Brute force "sort", but since we don't expect more than one or two
|
||||
* arguments in a string, the setup cost of a fast sort will be more
|
||||
* expensive than the loop.
|
||||
*/
|
||||
for (cnt1 = 1; cnt1 <= soff; ++cnt1)
|
||||
for (cnt2 = 0; cnt2 < soff; ++cnt2)
|
||||
if (cnt1 == str[cnt2].arg) {
|
||||
memmove(s_rbp, str[cnt2].str, str[cnt2].prefix);
|
||||
memmove(s_rbp + str[cnt2].prefix,
|
||||
str[cnt2].str + str[cnt2].prefix +
|
||||
str[cnt2].skip, str[cnt2].suffix);
|
||||
s_rbp += str[cnt2].prefix + str[cnt2].suffix;
|
||||
*s_rbp++ =
|
||||
gp == NULL ? DEFAULT_NOPRINT : gp->noprint;
|
||||
break;
|
||||
}
|
||||
*s_rbp = '\0';
|
||||
fmt = rbp;
|
||||
#endif
|
||||
|
||||
#ifndef NL_ARGMAX
|
||||
format: /* Format the arguments into the string. */
|
||||
#endif
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
len = vsnprintf(mp, REM, fmt, ap);
|
||||
va_end(ap);
|
||||
if (len >= nlen)
|
||||
goto retry;
|
||||
|
||||
#ifndef NL_ARGMAX
|
||||
if (soff == 0)
|
||||
goto nofmt;
|
||||
|
||||
/*
|
||||
* Go through the resulting string, and, for each separator character
|
||||
* separated string, enter its new starting position and length in the
|
||||
* array.
|
||||
*/
|
||||
for (p = t = mp, cnt1 = 1,
|
||||
ch = gp == NULL ? DEFAULT_NOPRINT : gp->noprint; *p != '\0'; ++p)
|
||||
if (*p == ch) {
|
||||
for (cnt2 = 0; cnt2 < soff; ++cnt2)
|
||||
if (str[cnt2].arg == cnt1)
|
||||
break;
|
||||
str[cnt2].str = t;
|
||||
str[cnt2].prefix = p - t;
|
||||
t = p + 1;
|
||||
++cnt1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reorder the strings once again, putting them back into the
|
||||
* message buffer.
|
||||
*
|
||||
* !!!
|
||||
* Note, the length of the message gets decremented once for
|
||||
* each substring, when we discard the separator character.
|
||||
*/
|
||||
for (s_rbp = rbp, cnt1 = 0; cnt1 < soff; ++cnt1) {
|
||||
memmove(rbp, str[cnt1].str, str[cnt1].prefix);
|
||||
rbp += str[cnt1].prefix;
|
||||
--len;
|
||||
}
|
||||
memmove(mp, s_rbp, rbp - s_rbp);
|
||||
|
||||
/* Free the reordered string memory. */
|
||||
free(s_rbp);
|
||||
#endif
|
||||
|
||||
nofmt: mp += len;
|
||||
if ((mlen += len) > blen)
|
||||
goto retry;
|
||||
if (mt == M_SYSERR) {
|
||||
len = snprintf(mp, REM, ": %s", strerror(errno));
|
||||
mp += len;
|
||||
if ((mlen += len) > blen)
|
||||
goto retry;
|
||||
mt = M_ERR;
|
||||
}
|
||||
if (mt == M_DBERR) {
|
||||
len = snprintf(mp, REM, ": %s", db_strerror(sp->db_error));
|
||||
mp += len;
|
||||
if ((mlen += len) > blen)
|
||||
goto retry;
|
||||
mt = M_ERR;
|
||||
}
|
||||
|
||||
/* Add trailing newline. */
|
||||
if ((mlen += 1) > blen)
|
||||
goto retry;
|
||||
*mp = '\n';
|
||||
|
||||
if (sp != NULL && sp->ep != NULL)
|
||||
(void)ex_fflush(sp);
|
||||
if (wp != NULL)
|
||||
wp->scr_msg(sp, mt, bp, mlen);
|
||||
else
|
||||
(void)fprintf(stderr, "%.*s", (int)mlen, bp);
|
||||
|
||||
/* Cleanup. */
|
||||
#ifndef NL_ARGMAX
|
||||
ret:
|
||||
#endif
|
||||
FREE_SPACE(sp, bp, blen);
|
||||
alloc_err:
|
||||
reenter = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* msgq_str --
|
||||
* Display a message with an embedded string.
|
||||
*
|
||||
* PUBLIC: void msgq_wstr __P((SCR *, mtype_t, const CHAR_T *, const char *));
|
||||
*/
|
||||
void
|
||||
msgq_wstr(SCR *sp, mtype_t mtype, const CHAR_T *str, const char *fmt)
|
||||
{
|
||||
size_t nlen;
|
||||
const char *nstr;
|
||||
|
||||
if (str == NULL) {
|
||||
msgq(sp, mtype, "%s", fmt);
|
||||
return;
|
||||
}
|
||||
INT2CHAR(sp, str, STRLEN(str) + 1, nstr, nlen);
|
||||
msgq_str(sp, mtype, nstr, fmt);
|
||||
}
|
||||
|
||||
/*
|
||||
* msgq_str --
|
||||
* Display a message with an embedded string.
|
||||
*
|
||||
* PUBLIC: void msgq_str __P((SCR *, mtype_t, char *, char *));
|
||||
*/
|
||||
void
|
||||
msgq_str(SCR *sp, mtype_t mtype, const char *str, const char *fmt)
|
||||
{
|
||||
int nf, sv_errno;
|
||||
char *p;
|
||||
|
||||
if (str == NULL) {
|
||||
msgq(sp, mtype, "%s", fmt);
|
||||
return;
|
||||
}
|
||||
|
||||
sv_errno = errno;
|
||||
p = msg_print(sp, str, &nf);
|
||||
errno = sv_errno;
|
||||
msgq(sp, mtype, fmt, p);
|
||||
if (nf)
|
||||
FREE_SPACE(sp, p, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_rpt --
|
||||
* Report on the lines that changed.
|
||||
*
|
||||
* !!!
|
||||
* Historic vi documentation (USD:15-8) claimed that "The editor will also
|
||||
* always tell you when a change you make affects text which you cannot see."
|
||||
* This wasn't true -- edit a large file and do "100d|1". We don't implement
|
||||
* this semantic since it requires tracking each line that changes during a
|
||||
* command instead of just keeping count.
|
||||
*
|
||||
* Line counts weren't right in historic vi, either. For example, given the
|
||||
* file:
|
||||
* abc
|
||||
* def
|
||||
* the command 2d}, from the 'b' would report that two lines were deleted,
|
||||
* not one.
|
||||
*
|
||||
* PUBLIC: void mod_rpt __P((SCR *));
|
||||
*/
|
||||
void
|
||||
mod_rpt(SCR *sp)
|
||||
{
|
||||
static const char * const action[] = {
|
||||
"293|added",
|
||||
"294|changed",
|
||||
"295|deleted",
|
||||
"296|joined",
|
||||
"297|moved",
|
||||
"298|shifted",
|
||||
"299|yanked",
|
||||
};
|
||||
static const char * const lines[] = {
|
||||
"300|line",
|
||||
"301|lines",
|
||||
};
|
||||
db_recno_t total;
|
||||
u_long rptval;
|
||||
int first;
|
||||
size_t cnt, blen, len, tlen;
|
||||
const char *t;
|
||||
const char * const *ap;
|
||||
char *bp, *p;
|
||||
|
||||
/* Change reports are turned off in batch mode. */
|
||||
if (F_ISSET(sp, SC_EX_SILENT))
|
||||
return;
|
||||
|
||||
/* Reset changing line number. */
|
||||
sp->rptlchange = OOBLNO;
|
||||
|
||||
/*
|
||||
* Don't build a message if not enough changed.
|
||||
*
|
||||
* !!!
|
||||
* And now, a vi clone test. Historically, vi reported if the number
|
||||
* of changed lines was > than the value, not >=, unless it was a yank
|
||||
* command, which used >=. No lie. Furthermore, an action was never
|
||||
* reported for a single line action. This is consistent for actions
|
||||
* other than yank, but yank didn't report single line actions even if
|
||||
* the report edit option was set to 1. In addition, setting report to
|
||||
* 0 in the 4BSD historic vi was equivalent to setting it to 1, for an
|
||||
* unknown reason (this bug was fixed in System III/V at some point).
|
||||
* I got complaints, so nvi conforms to System III/V historic practice
|
||||
* except that we report a yank of 1 line if report is set to 1.
|
||||
*/
|
||||
#define ARSIZE(a) sizeof(a) / sizeof (*a)
|
||||
#define MAXNUM 25
|
||||
rptval = O_VAL(sp, O_REPORT);
|
||||
for (cnt = 0, total = 0; cnt < ARSIZE(action); ++cnt)
|
||||
total += sp->rptlines[cnt];
|
||||
if (total == 0)
|
||||
return;
|
||||
if (total <= rptval && sp->rptlines[L_YANKED] < rptval) {
|
||||
for (cnt = 0; cnt < ARSIZE(action); ++cnt)
|
||||
sp->rptlines[cnt] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Build and display the message. */
|
||||
GET_SPACE_GOTOC(sp, bp, blen, sizeof(action) * MAXNUM + 1);
|
||||
for (p = bp, first = 1, tlen = 0,
|
||||
ap = action, cnt = 0; cnt < ARSIZE(action); ++ap, ++cnt)
|
||||
if (sp->rptlines[cnt] != 0) {
|
||||
if (first)
|
||||
first = 0;
|
||||
else {
|
||||
*p++ = ';';
|
||||
*p++ = ' ';
|
||||
tlen += 2;
|
||||
}
|
||||
len = snprintf(p, MAXNUM, "%lu ",
|
||||
(unsigned long) sp->rptlines[cnt]);
|
||||
p += len;
|
||||
tlen += len;
|
||||
t = msg_cat(sp,
|
||||
lines[sp->rptlines[cnt] == 1 ? 0 : 1], &len);
|
||||
memcpy(p, t, len);
|
||||
p += len;
|
||||
tlen += len;
|
||||
*p++ = ' ';
|
||||
++tlen;
|
||||
t = msg_cat(sp, *ap, &len);
|
||||
memcpy(p, t, len);
|
||||
p += len;
|
||||
tlen += len;
|
||||
sp->rptlines[cnt] = 0;
|
||||
}
|
||||
|
||||
/* Add trailing newline. */
|
||||
*p = '\n';
|
||||
++tlen;
|
||||
|
||||
(void)ex_fflush(sp);
|
||||
sp->wp->scr_msg(sp, M_INFO, bp, tlen);
|
||||
|
||||
FREE_SPACE(sp, bp, blen);
|
||||
alloc_err:
|
||||
return;
|
||||
|
||||
#undef ARSIZE
|
||||
#undef MAXNUM
|
||||
}
|
||||
|
||||
/*
|
||||
* msgq_status --
|
||||
* Report on the file's status.
|
||||
*
|
||||
* PUBLIC: void msgq_status __P((SCR *, db_recno_t, u_int));
|
||||
*/
|
||||
void
|
||||
msgq_status(SCR *sp, db_recno_t lno, u_int flags)
|
||||
{
|
||||
db_recno_t last;
|
||||
size_t blen, len;
|
||||
int cnt, needsep;
|
||||
const char *t;
|
||||
char **ap, *bp, *np, *p, *s;
|
||||
|
||||
/* Get sufficient memory. */
|
||||
len = strlen(sp->frp->name);
|
||||
GET_SPACE_GOTOC(sp, bp, blen, len * MAX_CHARACTER_COLUMNS + 128);
|
||||
p = bp;
|
||||
|
||||
/* Copy in the filename. */
|
||||
for (p = bp, t = sp->frp->name; *t != '\0'; ++t) {
|
||||
len = KEY_LEN(sp, *t);
|
||||
memcpy(p, KEY_NAME(sp, *t), len);
|
||||
p += len;
|
||||
}
|
||||
np = p;
|
||||
*p++ = ':';
|
||||
*p++ = ' ';
|
||||
|
||||
/* Copy in the argument count. */
|
||||
if (F_ISSET(sp, SC_STATUS_CNT) && sp->argv != NULL) {
|
||||
for (cnt = 0, ap = sp->argv; *ap != NULL; ++ap, ++cnt);
|
||||
if (cnt > 1) {
|
||||
(void)sprintf(p,
|
||||
msg_cat(sp, "317|%d files to edit", NULL), cnt);
|
||||
p += strlen(p);
|
||||
*p++ = ':';
|
||||
*p++ = ' ';
|
||||
}
|
||||
F_CLR(sp, SC_STATUS_CNT);
|
||||
}
|
||||
|
||||
/*
|
||||
* See nvi/exf.c:file_init() for a description of how and when the
|
||||
* read-only bit is set.
|
||||
*
|
||||
* !!!
|
||||
* The historic display for "name changed" was "[Not edited]".
|
||||
*/
|
||||
needsep = 0;
|
||||
if (F_ISSET(sp->frp, FR_NEWFILE)) {
|
||||
F_CLR(sp->frp, FR_NEWFILE);
|
||||
t = msg_cat(sp, "021|new file", &len);
|
||||
memcpy(p, t, len);
|
||||
p += len;
|
||||
needsep = 1;
|
||||
} else {
|
||||
if (F_ISSET(sp->frp, FR_NAMECHANGE)) {
|
||||
t = msg_cat(sp, "022|name changed", &len);
|
||||
memcpy(p, t, len);
|
||||
p += len;
|
||||
needsep = 1;
|
||||
}
|
||||
if (needsep) {
|
||||
*p++ = ',';
|
||||
*p++ = ' ';
|
||||
}
|
||||
if (F_ISSET(sp->ep, F_MODIFIED))
|
||||
t = msg_cat(sp, "023|modified", &len);
|
||||
else
|
||||
t = msg_cat(sp, "024|unmodified", &len);
|
||||
memcpy(p, t, len);
|
||||
p += len;
|
||||
needsep = 1;
|
||||
}
|
||||
if (F_ISSET(sp->frp, FR_UNLOCKED)) {
|
||||
if (needsep) {
|
||||
*p++ = ',';
|
||||
*p++ = ' ';
|
||||
}
|
||||
t = msg_cat(sp, "025|UNLOCKED", &len);
|
||||
memcpy(p, t, len);
|
||||
p += len;
|
||||
needsep = 1;
|
||||
}
|
||||
if (O_ISSET(sp, O_READONLY)) {
|
||||
if (needsep) {
|
||||
*p++ = ',';
|
||||
*p++ = ' ';
|
||||
}
|
||||
t = msg_cat(sp, "026|readonly", &len);
|
||||
memcpy(p, t, len);
|
||||
p += len;
|
||||
needsep = 1;
|
||||
}
|
||||
if (needsep) {
|
||||
*p++ = ':';
|
||||
*p++ = ' ';
|
||||
}
|
||||
if (LF_ISSET(MSTAT_SHOWLAST)) {
|
||||
if (db_last(sp, &last))
|
||||
return;
|
||||
if (last == 0) {
|
||||
t = msg_cat(sp, "028|empty file", &len);
|
||||
memcpy(p, t, len);
|
||||
p += len;
|
||||
} else {
|
||||
t = msg_cat(sp, "027|line %lu of %lu [%ld%%]", &len);
|
||||
(void)sprintf(p, t, lno, last, (lno * 100) / last);
|
||||
p += strlen(p);
|
||||
}
|
||||
} else {
|
||||
t = msg_cat(sp, "029|line %lu", &len);
|
||||
(void)sprintf(p, t, lno);
|
||||
p += strlen(p);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
(void)sprintf(p, " (pid %lu)", (u_long)getpid());
|
||||
p += strlen(p);
|
||||
#endif
|
||||
*p++ = '\n';
|
||||
len = p - bp;
|
||||
|
||||
/*
|
||||
* There's a nasty problem with long path names. Cscope and tags files
|
||||
* can result in long paths and vi will request a continuation key from
|
||||
* the user as soon as it starts the screen. Unfortunately, the user
|
||||
* has already typed ahead, and chaos results. If we assume that the
|
||||
* characters in the filenames and informational messages only take a
|
||||
* single screen column each, we can trim the filename.
|
||||
*
|
||||
* XXX
|
||||
* Status lines get put up at fairly awkward times. For example, when
|
||||
* you do a filter read (e.g., :read ! echo foo) in the top screen of a
|
||||
* split screen, we have to repaint the status lines for all the screens
|
||||
* below the top screen. We don't want users having to enter continue
|
||||
* characters for those screens. Make it really hard to screw this up.
|
||||
*/
|
||||
s = bp;
|
||||
if (LF_ISSET(MSTAT_TRUNCATE) && len > sp->cols) {
|
||||
for (; s < np && (*s != '/' || (size_t)(p - s) > sp->cols - 3); ++s);
|
||||
if (s == np) {
|
||||
s = p - (sp->cols - 5);
|
||||
*--s = ' ';
|
||||
}
|
||||
*--s = '.';
|
||||
*--s = '.';
|
||||
*--s = '.';
|
||||
len = p - s;
|
||||
}
|
||||
|
||||
/* Flush any waiting ex messages. */
|
||||
(void)ex_fflush(sp);
|
||||
|
||||
sp->wp->scr_msg(sp, M_INFO, s, len);
|
||||
|
||||
FREE_SPACE(sp, bp, blen);
|
||||
alloc_err:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_open --
|
||||
* Open the message catalogs.
|
||||
*
|
||||
* PUBLIC: int msg_open __P((SCR *, const char *));
|
||||
*/
|
||||
int
|
||||
msg_open(SCR *sp, const char *file)
|
||||
{
|
||||
/*
|
||||
* !!!
|
||||
* Assume that the first file opened is the system default, and that
|
||||
* all subsequent ones user defined. Only display error messages
|
||||
* if we can't open the user defined ones -- it's useful to know if
|
||||
* the system one wasn't there, but if nvi is being shipped with an
|
||||
* installed system, the file will be there, if it's not, then the
|
||||
* message will be repeated every time nvi is started up.
|
||||
*/
|
||||
static int first = 1;
|
||||
DB *db;
|
||||
DBT data, key;
|
||||
db_recno_t msgno;
|
||||
char buf[MAXPATHLEN];
|
||||
const char *p, *t;
|
||||
|
||||
if ((p = strrchr(file, '/')) != NULL && p[1] == '\0' &&
|
||||
(((t = getenv("LC_MESSAGES")) != NULL && t[0] != '\0') ||
|
||||
((t = getenv("LANG")) != NULL && t[0] != '\0'))) {
|
||||
(void)snprintf(buf, sizeof(buf), "%s%s", file, t);
|
||||
p = buf;
|
||||
} else
|
||||
p = file;
|
||||
if ((sp->db_error = db_create(&db, 0, 0)) != 0 ||
|
||||
(sp->db_error = db->set_re_source(db, p)) != 0 ||
|
||||
(sp->db_error = db_open(db, NULL, DB_RECNO, 0, 0)) != 0) {
|
||||
if (first) {
|
||||
first = 0;
|
||||
return (1);
|
||||
}
|
||||
msgq_str(sp, M_DBERR, p, "%s");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test record 1 for the magic string. The msgq call is here so
|
||||
* the message catalog build finds it.
|
||||
*/
|
||||
#define VMC "VI_MESSAGE_CATALOG"
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &msgno;
|
||||
key.size = sizeof(db_recno_t);
|
||||
memset(&data, 0, sizeof(data));
|
||||
msgno = 1;
|
||||
if ((sp->db_error = db->get(db, NULL, &key, &data, 0)) != 0 ||
|
||||
data.size != sizeof(VMC) - 1 ||
|
||||
memcmp(data.data, VMC, sizeof(VMC) - 1)) {
|
||||
(void)db->close(db, DB_NOSYNC);
|
||||
if (first) {
|
||||
first = 0;
|
||||
return (1);
|
||||
}
|
||||
msgq_str(sp, M_DBERR, p,
|
||||
"030|The file %s is not a message catalog");
|
||||
return (1);
|
||||
}
|
||||
first = 0;
|
||||
|
||||
if (sp->gp->msg != NULL)
|
||||
(void)sp->gp->msg->close(sp->gp->msg, DB_NOSYNC);
|
||||
sp->gp->msg = db;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_close --
|
||||
* Close the message catalogs.
|
||||
*
|
||||
* PUBLIC: void msg_close __P((GS *));
|
||||
*/
|
||||
void
|
||||
msg_close(GS *gp)
|
||||
{
|
||||
if (gp->msg != NULL) {
|
||||
(void)gp->msg->close(gp->msg, 0);
|
||||
gp->msg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_cont --
|
||||
* Return common continuation messages.
|
||||
*
|
||||
* PUBLIC: const char *msg_cmsg __P((SCR *, cmsg_t, size_t *));
|
||||
*/
|
||||
const char *
|
||||
msg_cmsg(SCR *sp, cmsg_t which, size_t *lenp)
|
||||
{
|
||||
switch (which) {
|
||||
case CMSG_CONF:
|
||||
return (msg_cat(sp, "268|confirm? [ynq]", lenp));
|
||||
case CMSG_CONT:
|
||||
return (msg_cat(sp, "269|Press any key to continue: ", lenp));
|
||||
case CMSG_CONT_EX:
|
||||
return (msg_cat(sp,
|
||||
"270|Press any key to continue [: to enter more ex commands]: ",
|
||||
lenp));
|
||||
case CMSG_CONT_R:
|
||||
return (msg_cat(sp, "161|Press Enter to continue: ", lenp));
|
||||
case CMSG_CONT_S:
|
||||
return (msg_cat(sp, "275| cont?", lenp));
|
||||
case CMSG_CONT_Q:
|
||||
return (msg_cat(sp,
|
||||
"271|Press any key to continue [q to quit]: ", lenp));
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_cat --
|
||||
* Return a single message from the catalog, plus its length.
|
||||
*
|
||||
* !!!
|
||||
* Only a single catalog message can be accessed at a time, if multiple
|
||||
* ones are needed, they must be copied into local memory.
|
||||
*
|
||||
* PUBLIC: const char *msg_cat __P((SCR *, const char *, size_t *));
|
||||
*/
|
||||
const char *
|
||||
msg_cat(SCR *sp, const char *str, size_t *lenp)
|
||||
{
|
||||
GS *gp;
|
||||
DBT data, key;
|
||||
db_recno_t msgno;
|
||||
|
||||
/*
|
||||
* If it's not a catalog message, i.e. has doesn't have a leading
|
||||
* number and '|' symbol, we're done.
|
||||
*/
|
||||
if (isdigit((unsigned char)str[0]) &&
|
||||
isdigit((unsigned char)str[1]) && isdigit((unsigned char)str[2]) &&
|
||||
str[3] == '|') {
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &msgno;
|
||||
key.size = sizeof(db_recno_t);
|
||||
memset(&data, 0, sizeof(data));
|
||||
msgno = atoi(str);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Really sleazy hack -- we put an extra character on the
|
||||
* end of the format string, and then we change it to be
|
||||
* the nul termination of the string. There ought to be
|
||||
* a better way. Once we can allocate multiple temporary
|
||||
* memory buffers, maybe we can use one of them instead.
|
||||
*/
|
||||
gp = sp == NULL ? NULL : sp->gp;
|
||||
if (gp != NULL && gp->msg != NULL &&
|
||||
gp->msg->get(gp->msg, NULL, &key, &data, 0) == 0 &&
|
||||
data.size != 0) {
|
||||
if (lenp != NULL)
|
||||
*lenp = data.size - 1;
|
||||
((char *)data.data)[data.size - 1] = '\0';
|
||||
return (data.data);
|
||||
}
|
||||
str = &str[4];
|
||||
}
|
||||
if (lenp != NULL)
|
||||
*lenp = strlen(str);
|
||||
return (str);
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_print --
|
||||
* Return a printable version of a string, in allocated memory.
|
||||
*
|
||||
* PUBLIC: char *msg_print __P((SCR *, const char *, int *));
|
||||
*/
|
||||
char *
|
||||
msg_print(SCR *sp, const char *s, int *needfree)
|
||||
{
|
||||
size_t blen, nlen;
|
||||
const char *cp;
|
||||
char *bp, *ep, *p;
|
||||
unsigned char *t;
|
||||
|
||||
*needfree = 0;
|
||||
|
||||
for (cp = s; *cp != '\0'; ++cp)
|
||||
if (!isprint((unsigned char)*cp))
|
||||
break;
|
||||
if (*cp == '\0')
|
||||
return ((char *)__UNCONST(s)); /* SAFE: needfree set to 0. */
|
||||
|
||||
nlen = 0;
|
||||
if (0) {
|
||||
retry: if (sp == NULL)
|
||||
free(bp);
|
||||
else
|
||||
FREE_SPACE(sp, bp, blen);
|
||||
*needfree = 0;
|
||||
}
|
||||
nlen += 256;
|
||||
if (sp == NULL) {
|
||||
if ((bp = malloc(nlen)) == NULL)
|
||||
goto alloc_err;
|
||||
} else
|
||||
GET_SPACE_GOTOC(sp, bp, blen, nlen);
|
||||
if (0) {
|
||||
alloc_err: return __UNCONST("");
|
||||
}
|
||||
*needfree = 1;
|
||||
|
||||
for (p = bp, ep = (bp + blen) - 1, cp = s; *cp != '\0' && p < ep; ++cp)
|
||||
for (t = KEY_NAME(sp, *cp); *t != '\0' && p < ep; *p++ = *t++);
|
||||
if (p == ep)
|
||||
goto retry;
|
||||
*p = '\0';
|
||||
return (bp);
|
||||
}
|
||||
67
dist/nvi/common/msg.h
vendored
Normal file
67
dist/nvi/common/msg.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/* $NetBSD: msg.h,v 1.1.1.2 2008/05/18 14:29:48 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: msg.h,v 10.11 2000/04/21 21:26:19 skimo Exp (Berkeley) Date: 2000/04/21 21:26:19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common messages (continuation or confirmation).
|
||||
*/
|
||||
typedef enum {
|
||||
CMSG_CONF, CMSG_CONT, CMSG_CONT_EX,
|
||||
CMSG_CONT_R, CMSG_CONT_S, CMSG_CONT_Q } cmsg_t;
|
||||
|
||||
/*
|
||||
* Message types.
|
||||
*
|
||||
* !!!
|
||||
* In historical vi, O_VERBOSE didn't exist, and O_TERSE made the error
|
||||
* messages shorter. In this implementation, O_TERSE has no effect and
|
||||
* O_VERBOSE results in informational displays about common errors, for
|
||||
* naive users.
|
||||
*
|
||||
* M_NONE Display to the user, no reformatting, no nothing.
|
||||
*
|
||||
* M_BERR Error: M_ERR if O_VERBOSE, else bell.
|
||||
* M_ERR Error: Display in inverse video.
|
||||
* M_INFO Info: Display in normal video.
|
||||
* M_SYSERR Error: M_ERR, using strerror(3) message.
|
||||
* M_VINFO Info: M_INFO if O_VERBOSE, else ignore.
|
||||
*
|
||||
* The underlying message display routines only need to know about M_NONE,
|
||||
* M_ERR and M_INFO -- all the other message types are converted into one
|
||||
* of them by the message routines.
|
||||
*/
|
||||
typedef enum {
|
||||
M_NONE = 1, M_BERR, M_ERR, M_INFO, M_SYSERR, M_VINFO, M_DBERR } mtype_t;
|
||||
|
||||
/*
|
||||
* There are major problems with error messages being generated by routines
|
||||
* preparing the screen to display error messages. It's possible for the
|
||||
* editor to generate messages before we have a screen in which to display
|
||||
* them, or during the transition between ex (and vi startup) and a true vi.
|
||||
* There's a queue in the global area to hold them.
|
||||
*
|
||||
* If SC_EX/SC_VI is set, that's the mode that the editor is in. If the flag
|
||||
* S_SCREEN_READY is set, that means that the screen is prepared to display
|
||||
* messages.
|
||||
*/
|
||||
typedef struct _msgh MSGH; /* MSGS list head structure. */
|
||||
LIST_HEAD(_msgh, _msg);
|
||||
struct _msg {
|
||||
LIST_ENTRY(_msg) q; /* Linked list of messages. */
|
||||
mtype_t mtype; /* Message type: M_NONE, M_ERR, M_INFO. */
|
||||
char *buf; /* Message buffer. */
|
||||
size_t len; /* Message length. */
|
||||
};
|
||||
|
||||
/* Flags to msgq_status(). */
|
||||
#define MSTAT_SHOWLAST 0x01 /* Show the line number of the last line. */
|
||||
#define MSTAT_TRUNCATE 0x02 /* Truncate the file name if it's too long. */
|
||||
108
dist/nvi/common/multibyte.h
vendored
Normal file
108
dist/nvi/common/multibyte.h
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/* $NetBSD: multibyte.h,v 1.7 2011/11/23 15:43:39 tnozaki Exp $ */
|
||||
|
||||
#ifndef MULTIBYTE_H
|
||||
#define MULTIBYTE_H
|
||||
|
||||
/*
|
||||
* Ex/vi commands are generally separated by whitespace characters. We
|
||||
* can't use the standard isspace(3) macro because it returns true for
|
||||
* characters like ^K in the ASCII character set. The 4.4BSD isblank(3)
|
||||
* macro does exactly what we want, but it's not portable yet.
|
||||
*
|
||||
* XXX
|
||||
* Note side effect, ch is evaluated multiple times.
|
||||
*/
|
||||
#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
|
||||
|
||||
#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
|
||||
#define ISXDIGIT(c) (ISDIGIT(c) || \
|
||||
((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
|
||||
#define ISALPHA(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
|
||||
#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c))
|
||||
|
||||
/*
|
||||
* Fundamental character types.
|
||||
*
|
||||
* CHAR_T An integral type that can hold any character.
|
||||
* ARG_CHAR_T The type of a CHAR_T when passed as an argument using
|
||||
* traditional promotion rules. It should also be able
|
||||
* to be compared against any CHAR_T for equality without
|
||||
* problems.
|
||||
*
|
||||
* If no integral type can hold a character, don't even try the port.
|
||||
*/
|
||||
|
||||
#ifdef USE_WIDECHAR
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
|
||||
typedef wchar_t RCHAR_T;
|
||||
#define REOF WEOF
|
||||
typedef wchar_t CHAR_T;
|
||||
typedef wint_t ARG_CHAR_T;
|
||||
typedef wint_t UCHAR_T;
|
||||
|
||||
#define STRLEN wcslen
|
||||
#define STRTOL wcstol
|
||||
#define STRTOUL wcstoul
|
||||
#define SPRINTF swprintf
|
||||
#define STRCMP wcscmp
|
||||
#define STRPBRK wcspbrk
|
||||
#define ISBLANK2 iswblank
|
||||
#define ISCNTRL iswcntrl
|
||||
#define ISGRAPH iswgraph
|
||||
#define ISLOWER iswlower
|
||||
#define ISPUNCT iswpunct
|
||||
#define ISSPACE iswspace
|
||||
#define ISUPPER iswupper
|
||||
#define TOLOWER towlower
|
||||
#define TOUPPER towupper
|
||||
#define STRSET wmemset
|
||||
#define STRCHR wcschr
|
||||
|
||||
#define L(ch) L ## ch
|
||||
#define WS "%ls"
|
||||
#define WVS "%*ls"
|
||||
#define WC "%lc"
|
||||
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
typedef char RCHAR_T;
|
||||
#define REOF EOF
|
||||
typedef char CHAR_T;
|
||||
typedef int ARG_CHAR_T;
|
||||
typedef unsigned char UCHAR_T;
|
||||
|
||||
#define STRLEN strlen
|
||||
#define STRTOL strtol
|
||||
#define STRTOUL strtoul
|
||||
#define SPRINTF snprintf
|
||||
#define STRCMP strcmp
|
||||
#define STRPBRK strpbrk
|
||||
#define ISBLANK2 isblank
|
||||
#define ISCNTRL iscntrl
|
||||
#define ISGRAPH isgraph
|
||||
#define ISLOWER islower
|
||||
#define ISPUNCT ispunct
|
||||
#define ISSPACE isspace
|
||||
#define ISUPPER isupper
|
||||
#define TOLOWER tolower
|
||||
#define TOUPPER toupper
|
||||
#define STRSET memset
|
||||
#define STRCHR strchr
|
||||
|
||||
#define L(ch) ch
|
||||
#define WS "%s"
|
||||
#define WVS "%*s"
|
||||
#define WC "%c"
|
||||
|
||||
#endif
|
||||
|
||||
#define MEMCMP(to, from, n) \
|
||||
memcmp(to, from, (n) * sizeof(*(to)))
|
||||
#define MEMMOVE(p, t, len) memmove(p, t, (len) * sizeof(*(p)))
|
||||
#define MEMCPY(p, t, len) memcpy(p, t, (len) * sizeof(*(p)))
|
||||
#define SIZE(w) (sizeof(w)/sizeof(*w))
|
||||
|
||||
#endif
|
||||
58
dist/nvi/common/nothread.c
vendored
Normal file
58
dist/nvi/common/nothread.c
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/* $NetBSD: nothread.c,v 1.1.1.2 2008/05/18 14:29:48 aymeric Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000
|
||||
* Sven Verdoolaege. All rights reserved.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: nothread.c,v 1.4 2000/07/22 14:52:37 skimo Exp (Berkeley) Date: 2000/07/22 14:52:37";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../common/common.h"
|
||||
|
||||
static int vi_nothread_run __P((WIN *wp, void *(*fun)(void*), void *data));
|
||||
static int vi_nothread_lock __P((WIN *, void **));
|
||||
|
||||
/*
|
||||
* thread_init
|
||||
*
|
||||
* PUBLIC: void thread_init __P((GS *gp));
|
||||
*/
|
||||
void
|
||||
thread_init(GS *gp)
|
||||
{
|
||||
gp->run = vi_nothread_run;
|
||||
gp->lock_init = vi_nothread_lock;
|
||||
gp->lock_end = vi_nothread_lock;
|
||||
gp->lock_try = vi_nothread_lock;
|
||||
gp->lock_unlock = vi_nothread_lock;
|
||||
}
|
||||
|
||||
static int
|
||||
vi_nothread_run(WIN *wp, void *(*fun)(void*), void *data)
|
||||
{
|
||||
fun(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vi_nothread_lock (WIN * wp, void **lp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
21
dist/nvi/common/options.awk
vendored
Normal file
21
dist/nvi/common/options.awk
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Id: options.awk,v 10.1 1995/06/08 19:00:01 bostic Exp (Berkeley) Date: 1995/06/08 19:00:01
|
||||
|
||||
/^\/\* O_[0-9A-Z_]*/ {
|
||||
opt = $2
|
||||
printf("#define %s %d\n", opt, cnt++)
|
||||
ofs = FS
|
||||
FS="\""
|
||||
do getline
|
||||
while ($1 != " {L(")
|
||||
FS=ofs
|
||||
opt_name = $2
|
||||
if (opt_name < prev_name) {
|
||||
printf "missorted %s: \"%s\" < \"%s\"\n", opt, opt_name, prev_name >"/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
prev_name = opt_name
|
||||
next
|
||||
}
|
||||
END {
|
||||
printf("#define O_OPTIONCOUNT %d\n", cnt);
|
||||
}
|
||||
1190
dist/nvi/common/options.c
vendored
Normal file
1190
dist/nvi/common/options.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
104
dist/nvi/common/options.h
vendored
Normal file
104
dist/nvi/common/options.h
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/* $NetBSD: options.h,v 1.3 2008/12/05 22:51:42 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: options.h,v 10.20 2001/06/09 18:26:28 skimo Exp (Berkeley) Date: 2001/06/09 18:26:28
|
||||
*/
|
||||
|
||||
/*
|
||||
* Edit option information. Historically, if you set a boolean or numeric
|
||||
* edit option value to its "default" value, it didn't show up in the :set
|
||||
* display, i.e. it wasn't considered "changed". String edit options would
|
||||
* show up as changed, regardless. We maintain a parallel set of values
|
||||
* which are the default values and never consider an edit option changed
|
||||
* if it was reset to the default value.
|
||||
*
|
||||
* Macros to retrieve boolean, integral and string option values, and to
|
||||
* set, clear and test boolean option values. Some options (secure, lines,
|
||||
* columns, terminal type) are global in scope, and are therefore stored
|
||||
* in the global area. The offset in the global options array is stored
|
||||
* in the screen's value field. This is set up when the options are first
|
||||
* initialized.
|
||||
*/
|
||||
#define O_V(sp, o, fld) \
|
||||
(F_ISSET(&(sp)->opts[(o)], OPT_GLOBAL) ? \
|
||||
(sp)->gp->opts[(sp)->opts[(o)].o_cur.val].fld : \
|
||||
(sp)->opts[(o)].fld)
|
||||
|
||||
/* Global option macros. */
|
||||
#define OG_CLR(gp, o) ((gp)->opts[(o)].o_cur.val) = 0
|
||||
#define OG_SET(gp, o) ((gp)->opts[(o)].o_cur.val) = 1
|
||||
#define OG_STR(gp, o) ((gp)->opts[(o)].o_cur.str)
|
||||
#define OG_VAL(gp, o) ((gp)->opts[(o)].o_cur.val)
|
||||
#define OG_ISSET(gp, o) OG_VAL(gp, o)
|
||||
|
||||
#define OG_D_STR(gp, o) ((gp)->opts[(o)].o_def.str)
|
||||
#define OG_D_VAL(gp, o) ((gp)->opts[(o)].o_def.val)
|
||||
|
||||
/*
|
||||
* Flags to o_set(); need explicit OS_STR as can be setting the value to
|
||||
* NULL.
|
||||
*/
|
||||
#define OS_DEF 0x01 /* Set the default value. */
|
||||
#define OS_NOFREE 0x02 /* Don't free the old string. */
|
||||
#define OS_STR 0x04 /* Set to string argument. */
|
||||
#define OS_STRDUP 0x08 /* Copy then set to string argument. */
|
||||
|
||||
struct _option {
|
||||
union {
|
||||
u_long val; /* Value or boolean. */
|
||||
const char *str; /* String. */
|
||||
} o_cur;
|
||||
#define O_CLR(sp, o) o_set(sp, o, 0, NULL, 0)
|
||||
#define O_SET(sp, o) o_set(sp, o, 0, NULL, 1)
|
||||
#define O_STR(sp, o) O_V(sp, o, o_cur.str)
|
||||
#define O_VAL(sp, o) O_V(sp, o, o_cur.val)
|
||||
#define O_ISSET(sp, o) O_VAL(sp, o)
|
||||
|
||||
union {
|
||||
u_long val; /* Value or boolean. */
|
||||
const char *str; /* String. */
|
||||
} o_def;
|
||||
#define O_D_CLR(sp, o) o_set(sp, o, OS_DEF, NULL, 0)
|
||||
#define O_D_SET(sp, o) o_set(sp, o, OS_DEF, NULL, 1)
|
||||
#define O_D_STR(sp, o) O_V(sp, o, o_def.str)
|
||||
#define O_D_VAL(sp, o) O_V(sp, o, o_def.val)
|
||||
#define O_D_ISSET(sp, o) O_D_VAL(sp, o)
|
||||
|
||||
#define OPT_GLOBAL 0x01 /* Option is global. */
|
||||
#define OPT_SELECTED 0x02 /* Selected for display. */
|
||||
u_int8_t flags;
|
||||
};
|
||||
|
||||
/* List of option names, associated update functions and information. */
|
||||
struct _optlist {
|
||||
const CHAR_T *name; /* Name. */
|
||||
/* Change function. */
|
||||
int (*func) __P((SCR *, OPTION *, const char *, u_long *));
|
||||
/* Type of object. */
|
||||
enum { OPT_0BOOL, OPT_1BOOL, OPT_NUM, OPT_STR } type;
|
||||
|
||||
#define OPT_ADISP 0x001 /* Always display the option. */
|
||||
#define OPT_ALWAYS 0x002 /* Always call the support function. */
|
||||
#define OPT_NDISP 0x004 /* Never display the option. */
|
||||
#define OPT_NOSAVE 0x008 /* Mkexrc command doesn't save. */
|
||||
#define OPT_NOSET 0x010 /* Option may not be set. */
|
||||
#define OPT_NOUNSET 0x020 /* Option may not be unset. */
|
||||
#define OPT_NOZERO 0x040 /* Option may not be set to 0. */
|
||||
#define OPT_PAIRS 0x080 /* String with even length */
|
||||
u_int8_t flags;
|
||||
};
|
||||
|
||||
/* Option argument to opts_dump(). */
|
||||
enum optdisp { NO_DISPLAY, ALL_DISPLAY, CHANGED_DISPLAY, SELECT_DISPLAY };
|
||||
|
||||
/* Options array. */
|
||||
extern OPTLIST const optlist[];
|
||||
|
||||
#include "options_def.h"
|
||||
299
dist/nvi/common/options_f.c
vendored
Normal file
299
dist/nvi/common/options_f.c
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
/* $NetBSD: options_f.c,v 1.3 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: options_f.c,v 10.33 2001/06/25 15:19:11 skimo Exp (Berkeley) Date: 2001/06/25 15:19:11";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_altwerase __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_altwerase(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
if (*valp)
|
||||
O_CLR(sp, O_TTYWERASE);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_columns __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_columns(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
/* Validate the number. */
|
||||
if (*valp < MINIMUM_SCREEN_COLS) {
|
||||
msgq(sp, M_ERR, "040|Screen columns too small, less than %d",
|
||||
MINIMUM_SCREEN_COLS);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* It's not uncommon for allocation of huge chunks of memory to cause
|
||||
* core dumps on various systems. So, we prune out numbers that are
|
||||
* "obviously" wrong. Vi will not work correctly if it has the wrong
|
||||
* number of lines/columns for the screen, but at least we don't drop
|
||||
* core.
|
||||
*/
|
||||
#define MAXIMUM_SCREEN_COLS 4000
|
||||
if (*valp > MAXIMUM_SCREEN_COLS) {
|
||||
msgq(sp, M_ERR, "041|Screen columns too large, greater than %d",
|
||||
MAXIMUM_SCREEN_COLS);
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_lines __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_lines(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
/* Validate the number. */
|
||||
if (*valp < MINIMUM_SCREEN_ROWS) {
|
||||
msgq(sp, M_ERR, "042|Screen lines too small, less than %d",
|
||||
MINIMUM_SCREEN_ROWS);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* It's not uncommon for allocation of huge chunks of memory to cause
|
||||
* core dumps on various systems. So, we prune out numbers that are
|
||||
* "obviously" wrong. Vi will not work correctly if it has the wrong
|
||||
* number of lines/columns for the screen, but at least we don't drop
|
||||
* core.
|
||||
*/
|
||||
#define MAXIMUM_SCREEN_ROWS 4000
|
||||
if (*valp > MAXIMUM_SCREEN_ROWS) {
|
||||
msgq(sp, M_ERR, "043|Screen lines too large, greater than %d",
|
||||
MAXIMUM_SCREEN_ROWS);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the value, and the related scroll value. If no window
|
||||
* value set, set a new default window.
|
||||
*/
|
||||
o_set(sp, O_LINES, 0, NULL, *valp);
|
||||
if (*valp == 1) {
|
||||
sp->defscroll = 1;
|
||||
|
||||
if (O_VAL(sp, O_WINDOW) == O_D_VAL(sp, O_WINDOW) ||
|
||||
O_VAL(sp, O_WINDOW) > *valp) {
|
||||
o_set(sp, O_WINDOW, 0, NULL, 1);
|
||||
o_set(sp, O_WINDOW, OS_DEF, NULL, 1);
|
||||
}
|
||||
} else {
|
||||
sp->defscroll = (*valp - 1) / 2;
|
||||
|
||||
if (O_VAL(sp, O_WINDOW) == O_D_VAL(sp, O_WINDOW) ||
|
||||
O_VAL(sp, O_WINDOW) > *valp) {
|
||||
o_set(sp, O_WINDOW, 0, NULL, *valp - 1);
|
||||
o_set(sp, O_WINDOW, OS_DEF, NULL, *valp - 1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_lisp __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_lisp(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
msgq(sp, M_ERR, "044|The lisp option is not implemented");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_msgcat __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_msgcat(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
(void)msg_open(sp, str);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_print __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_print(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
int offset = op - sp->opts;
|
||||
|
||||
/* Preset the value, needed for reinitialization of lookup table. */
|
||||
if (offset == O_OCTAL) {
|
||||
if (*valp)
|
||||
O_SET(sp, offset);
|
||||
else
|
||||
O_CLR(sp, offset);
|
||||
} else if (o_set(sp, offset, OS_STRDUP, str, 0))
|
||||
return(1);
|
||||
|
||||
/* Reinitialize the key fast lookup table. */
|
||||
v_key_ilookup(sp);
|
||||
|
||||
/* Reformat the screen. */
|
||||
F_SET(sp, SC_SCR_REFORMAT);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_readonly __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_readonly(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
/*
|
||||
* !!!
|
||||
* See the comment in exf.c.
|
||||
*/
|
||||
if (*valp)
|
||||
F_SET(sp, SC_READONLY);
|
||||
else
|
||||
F_CLR(sp, SC_READONLY);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_recompile __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_recompile(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
if (F_ISSET(sp, SC_RE_SEARCH)) {
|
||||
regfree(&sp->re_c);
|
||||
F_CLR(sp, SC_RE_SEARCH);
|
||||
}
|
||||
if (F_ISSET(sp, SC_RE_SUBST)) {
|
||||
regfree(&sp->subre_c);
|
||||
F_CLR(sp, SC_RE_SUBST);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_reformat __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_reformat(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
F_SET(sp, SC_SCR_REFORMAT);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_ttywerase __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_ttywerase(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
if (*valp)
|
||||
O_CLR(sp, O_ALTWERASE);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_w300 __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_w300(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
u_long v;
|
||||
|
||||
/* Historical behavior for w300 was < 1200. */
|
||||
if (sp->gp->scr_baud(sp, &v))
|
||||
return (1);
|
||||
if (v >= 1200)
|
||||
return (0);
|
||||
|
||||
return (f_window(sp, op, str, valp));
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_w1200 __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_w1200(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
u_long v;
|
||||
|
||||
/* Historical behavior for w1200 was == 1200. */
|
||||
if (sp->gp->scr_baud(sp, &v))
|
||||
return (1);
|
||||
if (v < 1200 || v > 4800)
|
||||
return (0);
|
||||
|
||||
return (f_window(sp, op, str, valp));
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_w9600 __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_w9600(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
u_long v;
|
||||
|
||||
/* Historical behavior for w9600 was > 1200. */
|
||||
if (sp->gp->scr_baud(sp, &v))
|
||||
return (1);
|
||||
if (v <= 4800)
|
||||
return (0);
|
||||
|
||||
return (f_window(sp, op, str, valp));
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_window __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_window(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
if (*valp >= O_VAL(sp, O_LINES) - 1 &&
|
||||
(*valp = O_VAL(sp, O_LINES) - 1) == 0)
|
||||
*valp = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int f_encoding __P((SCR *, OPTION *, const char *, u_long *));
|
||||
*/
|
||||
int
|
||||
f_encoding(SCR *sp, OPTION *op, const char *str, u_long *valp)
|
||||
{
|
||||
int offset = op - sp->opts;
|
||||
|
||||
return conv_enc(sp, offset, str);
|
||||
}
|
||||
107
dist/nvi/common/pthread.c
vendored
Normal file
107
dist/nvi/common/pthread.c
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/* $NetBSD: pthread.c,v 1.1.1.2 2008/05/18 14:29:50 aymeric Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000
|
||||
* Sven Verdoolaege. All rights reserved.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: pthread.c,v 1.4 2000/07/22 14:52:37 skimo Exp (Berkeley) Date: 2000/07/22 14:52:37";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "../common/common.h"
|
||||
|
||||
static int vi_pthread_run __P((WIN *wp, void *(*fun)(void*), void *data));
|
||||
static int vi_pthread_lock_init __P((WIN *, void **));
|
||||
static int vi_pthread_lock_end __P((WIN *, void **));
|
||||
static int vi_pthread_lock_try __P((WIN *, void **));
|
||||
static int vi_pthread_lock_unlock __P((WIN *, void **));
|
||||
|
||||
/*
|
||||
* thread_init
|
||||
*
|
||||
* PUBLIC: void thread_init __P((GS *gp));
|
||||
*/
|
||||
void
|
||||
thread_init(GS *gp)
|
||||
{
|
||||
gp->run = vi_pthread_run;
|
||||
gp->lock_init = vi_pthread_lock_init;
|
||||
gp->lock_end = vi_pthread_lock_end;
|
||||
gp->lock_try = vi_pthread_lock_try;
|
||||
gp->lock_unlock = vi_pthread_lock_unlock;
|
||||
}
|
||||
|
||||
static int
|
||||
vi_pthread_run(WIN *wp, void *(*fun)(void*), void *data)
|
||||
{
|
||||
pthread_t *t = malloc(sizeof(pthread_t));
|
||||
pthread_create(t, NULL, fun, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vi_pthread_lock_init (WIN * wp, void **p)
|
||||
{
|
||||
pthread_mutex_t *mutex;
|
||||
int rc;
|
||||
|
||||
MALLOC_RET(NULL, mutex, pthread_mutex_t *, sizeof(*mutex));
|
||||
|
||||
if (rc = pthread_mutex_init(mutex, NULL)) {
|
||||
free(mutex);
|
||||
*p = NULL;
|
||||
return rc;
|
||||
}
|
||||
*p = mutex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vi_pthread_lock_end (WIN * wp, void **p)
|
||||
{
|
||||
int rc;
|
||||
pthread_mutex_t *mutex = (pthread_mutex_t *)*p;
|
||||
|
||||
if (rc = pthread_mutex_destroy(mutex))
|
||||
return rc;
|
||||
|
||||
free(mutex);
|
||||
*p = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vi_pthread_lock_try (WIN * wp, void **p)
|
||||
{
|
||||
printf("try %p\n", *p);
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
return pthread_mutex_trylock((pthread_mutex_t *)*p);
|
||||
}
|
||||
|
||||
static int
|
||||
vi_pthread_lock_unlock (WIN * wp, void **p)
|
||||
{
|
||||
printf("unlock %p\n", *p);
|
||||
return 0;
|
||||
return pthread_mutex_unlock((pthread_mutex_t *)*p);
|
||||
}
|
||||
|
||||
230
dist/nvi/common/put.c
vendored
Normal file
230
dist/nvi/common/put.c
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
/* $NetBSD: put.c,v 1.3 2011/11/23 19:25:28 tnozaki 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: put.c,v 10.18 2001/06/25 15:19:11 skimo Exp (Berkeley) Date: 2001/06/25 15:19:11";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* put --
|
||||
* Put text buffer contents into the file.
|
||||
*
|
||||
* PUBLIC: int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int));
|
||||
*/
|
||||
int
|
||||
put(SCR *sp, CB *cbp, ARG_CHAR_T *namep, MARK *cp, MARK *rp, int append)
|
||||
{
|
||||
ARG_CHAR_T name;
|
||||
TEXT *ltp, *tp;
|
||||
db_recno_t lno;
|
||||
size_t blen, clen, len;
|
||||
int rval;
|
||||
CHAR_T *bp, *t;
|
||||
CHAR_T *p;
|
||||
|
||||
if (cbp == NULL) {
|
||||
if (namep == NULL) {
|
||||
cbp = sp->wp->dcbp;
|
||||
if (cbp == NULL) {
|
||||
msgq(sp, M_ERR,
|
||||
"053|The default buffer is empty");
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
name = *namep;
|
||||
CBNAME(sp, cbp, name);
|
||||
if (cbp == NULL) {
|
||||
msgq(sp, M_ERR, "054|Buffer %s is empty",
|
||||
KEY_NAME(sp, name));
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
tp = cbp->textq.cqh_first;
|
||||
|
||||
/*
|
||||
* It's possible to do a put into an empty file, meaning that the cut
|
||||
* buffer simply becomes the file. It's a special case so that we can
|
||||
* ignore it in general.
|
||||
*
|
||||
* !!!
|
||||
* Historically, pasting into a file with no lines in vi would preserve
|
||||
* the single blank line. This is surely a result of the fact that the
|
||||
* historic vi couldn't deal with a file that had no lines in it. This
|
||||
* implementation treats that as a bug, and does not retain the blank
|
||||
* line.
|
||||
*
|
||||
* Historical practice is that the cursor ends at the first character
|
||||
* in the file.
|
||||
*/
|
||||
if (cp->lno == 1) {
|
||||
if (db_last(sp, &lno))
|
||||
return (1);
|
||||
if (lno == 0) {
|
||||
for (; tp != (void *)&cbp->textq;
|
||||
++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next)
|
||||
if (db_append(sp, 1, lno, tp->lb, tp->len))
|
||||
return (1);
|
||||
rp->lno = 1;
|
||||
rp->cno = 0;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* If a line mode buffer, append each new line into the file. */
|
||||
if (F_ISSET(cbp, CB_LMODE)) {
|
||||
lno = append ? cp->lno : cp->lno - 1;
|
||||
rp->lno = lno + 1;
|
||||
for (; tp != (void *)&cbp->textq;
|
||||
++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next)
|
||||
if (db_append(sp, 1, lno, tp->lb, tp->len))
|
||||
return (1);
|
||||
rp->cno = 0;
|
||||
(void)nonblank(sp, rp->lno, &rp->cno);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If buffer was cut in character mode, replace the current line with
|
||||
* one built from the portion of the first line to the left of the
|
||||
* split plus the first line in the CB. Append each intermediate line
|
||||
* in the CB. Append a line built from the portion of the first line
|
||||
* to the right of the split plus the last line in the CB.
|
||||
*
|
||||
* Get the first line.
|
||||
*/
|
||||
lno = cp->lno;
|
||||
if (db_get(sp, lno, DBG_FATAL, &p, &len))
|
||||
return (1);
|
||||
|
||||
GET_SPACE_RETW(sp, bp, blen, tp->len + len + 1);
|
||||
t = bp;
|
||||
|
||||
/* Original line, left of the split. */
|
||||
if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) {
|
||||
MEMCPYW(bp, p, clen);
|
||||
p += clen;
|
||||
t += clen;
|
||||
}
|
||||
|
||||
/* First line from the CB. */
|
||||
if (tp->len != 0) {
|
||||
MEMCPYW(t, tp->lb, tp->len);
|
||||
t += tp->len;
|
||||
}
|
||||
|
||||
/* Calculate length left in the original line. */
|
||||
clen = len == 0 ? 0 : len - (cp->cno + (append ? 1 : 0));
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* In the historical 4BSD version of vi, character mode puts within
|
||||
* a single line have two cursor behaviors: if the put is from the
|
||||
* unnamed buffer, the cursor moves to the character inserted which
|
||||
* appears last in the file. If the put is from a named buffer,
|
||||
* the cursor moves to the character inserted which appears first
|
||||
* in the file. In System III/V, it was changed at some point and
|
||||
* the cursor always moves to the first character. In both versions
|
||||
* of vi, character mode puts that cross line boundaries leave the
|
||||
* cursor on the first character. Nvi implements the System III/V
|
||||
* behavior, and expect POSIX.2 to do so as well.
|
||||
*/
|
||||
rp->lno = lno;
|
||||
rp->cno = len == 0 ? 0 : sp->cno + (append && tp->len ? 1 : 0);
|
||||
|
||||
/*
|
||||
* If no more lines in the CB, append the rest of the original
|
||||
* line and quit. Otherwise, build the last line before doing
|
||||
* the intermediate lines, because the line changes will lose
|
||||
* the cached line.
|
||||
*/
|
||||
if (tp->q.cqe_next == (void *)&cbp->textq) {
|
||||
if (clen > 0) {
|
||||
MEMCPYW(t, p, clen);
|
||||
t += clen;
|
||||
}
|
||||
if (db_set(sp, lno, bp, t - bp))
|
||||
goto err;
|
||||
if (sp->rptlchange != lno) {
|
||||
sp->rptlchange = lno;
|
||||
++sp->rptlines[L_CHANGED];
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Have to build both the first and last lines of the
|
||||
* put before doing any sets or we'll lose the cached
|
||||
* line. Build both the first and last lines in the
|
||||
* same buffer, so we don't have to have another buffer
|
||||
* floating around.
|
||||
*
|
||||
* Last part of original line; check for space, reset
|
||||
* the pointer into the buffer.
|
||||
*/
|
||||
ltp = cbp->textq.cqh_last;
|
||||
len = t - bp;
|
||||
ADD_SPACE_RETW(sp, bp, blen, ltp->len + clen);
|
||||
t = bp + len;
|
||||
|
||||
/* Add in last part of the CB. */
|
||||
MEMCPYW(t, ltp->lb, ltp->len);
|
||||
if (clen)
|
||||
MEMCPYW(t + ltp->len, p, clen);
|
||||
clen += ltp->len;
|
||||
|
||||
/*
|
||||
* Now: bp points to the first character of the first
|
||||
* line, t points to the last character of the last
|
||||
* line, t - bp is the length of the first line, and
|
||||
* clen is the length of the last. Just figured you'd
|
||||
* want to know.
|
||||
*
|
||||
* Output the line replacing the original line.
|
||||
*/
|
||||
if (db_set(sp, lno, bp, t - bp))
|
||||
goto err;
|
||||
if (sp->rptlchange != lno) {
|
||||
sp->rptlchange = lno;
|
||||
++sp->rptlines[L_CHANGED];
|
||||
}
|
||||
|
||||
/* Output any intermediate lines in the CB. */
|
||||
for (tp = tp->q.cqe_next;
|
||||
tp->q.cqe_next != (void *)&cbp->textq;
|
||||
++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next)
|
||||
if (db_append(sp, 1, lno, tp->lb, tp->len))
|
||||
goto err;
|
||||
|
||||
if (db_append(sp, 1, lno, t, clen))
|
||||
goto err;
|
||||
++sp->rptlines[L_ADDED];
|
||||
}
|
||||
rval = 0;
|
||||
|
||||
if (0)
|
||||
err: rval = 1;
|
||||
|
||||
FREE_SPACEW(sp, bp, blen);
|
||||
return (rval);
|
||||
}
|
||||
859
dist/nvi/common/recover.c
vendored
Normal file
859
dist/nvi/common/recover.c
vendored
Normal file
@@ -0,0 +1,859 @@
|
||||
/* $NetBSD: recover.c,v 1.3 2009/01/18 03:45:50 lukem 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: recover.c,v 10.31 2001/11/01 15:24:44 skimo Exp (Berkeley) Date: 2001/11/01 15:24:44";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h> /* XXX: param.h may not have included types.h */
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*
|
||||
* We include <sys/file.h>, because the open #defines were found there
|
||||
* on historical systems. We also include <fcntl.h> because the open(2)
|
||||
* #defines are found there on newer systems.
|
||||
*/
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
/*
|
||||
* Recovery code.
|
||||
*
|
||||
* The basic scheme is as follows. In the EXF structure, we maintain full
|
||||
* paths of a b+tree file and a mail recovery file. The former is the file
|
||||
* used as backing store by the DB package. The latter is the file that
|
||||
* contains an email message to be sent to the user if we crash. The two
|
||||
* simple states of recovery are:
|
||||
*
|
||||
* + first starting the edit session:
|
||||
* the b+tree file exists and is mode 700, the mail recovery
|
||||
* file doesn't exist.
|
||||
* + after the file has been modified:
|
||||
* the b+tree file exists and is mode 600, the mail recovery
|
||||
* file exists, and is exclusively locked.
|
||||
*
|
||||
* In the EXF structure we maintain a file descriptor that is the locked
|
||||
* file descriptor for the mail recovery file. NOTE: we sometimes have to
|
||||
* do locking with fcntl(2). This is a problem because if you close(2) any
|
||||
* file descriptor associated with the file, ALL of the locks go away. Be
|
||||
* sure to remember that if you have to modify the recovery code. (It has
|
||||
* been rhetorically asked of what the designers could have been thinking
|
||||
* when they did that interface. The answer is simple: they weren't.)
|
||||
*
|
||||
* To find out if a recovery file/backing file pair are in use, try to get
|
||||
* a lock on the recovery file.
|
||||
*
|
||||
* To find out if a backing file can be deleted at boot time, check for an
|
||||
* owner execute bit. (Yes, I know it's ugly, but it's either that or put
|
||||
* special stuff into the backing file itself, or correlate the files at
|
||||
* boot time, neither of which looks like fun.) Note also that there's a
|
||||
* window between when the file is created and the X bit is set. It's small,
|
||||
* but it's there. To fix the window, check for 0 length files as well.
|
||||
*
|
||||
* To find out if a file can be recovered, check the F_RCV_ON bit. Note,
|
||||
* this DOES NOT mean that any initialization has been done, only that we
|
||||
* haven't yet failed at setting up or doing recovery.
|
||||
*
|
||||
* To preserve a recovery file/backing file pair, set the F_RCV_NORM bit.
|
||||
* If that bit is not set when ending a file session:
|
||||
* If the EXF structure paths (rcv_path and rcv_mpath) are not NULL,
|
||||
* they are unlink(2)'d, and free(3)'d.
|
||||
* If the EXF file descriptor (rcv_fd) is not -1, it is closed.
|
||||
*
|
||||
* The backing b+tree file is set up when a file is first edited, so that
|
||||
* the DB package can use it for on-disk caching and/or to snapshot the
|
||||
* file. When the file is first modified, the mail recovery file is created,
|
||||
* the backing file permissions are updated, the file is sync(2)'d to disk,
|
||||
* and the timer is started. Then, at RCV_PERIOD second intervals, the
|
||||
* b+tree file is synced to disk. RCV_PERIOD is measured using SIGALRM, which
|
||||
* means that the data structures (SCR, EXF, the underlying tree structures)
|
||||
* must be consistent when the signal arrives.
|
||||
*
|
||||
* The recovery mail file contains normal mail headers, with two additions,
|
||||
* which occur in THIS order, as the FIRST TWO headers:
|
||||
*
|
||||
* X-vi-recover-file: file_name
|
||||
* X-vi-recover-path: recover_path
|
||||
*
|
||||
* Since newlines delimit the headers, this means that file names cannot have
|
||||
* newlines in them, but that's probably okay. As these files aren't intended
|
||||
* to be long-lived, changing their format won't be too painful.
|
||||
*
|
||||
* Btree files are named "vi.XXXX" and recovery files are named "recover.XXXX".
|
||||
*/
|
||||
|
||||
#define VI_FHEADER "X-vi-recover-file: "
|
||||
#define VI_PHEADER "X-vi-recover-path: "
|
||||
|
||||
static int rcv_copy __P((SCR *, int, char *));
|
||||
static void rcv_email __P((SCR *, char *));
|
||||
static char *rcv_gets __P((char *, size_t, int));
|
||||
static int rcv_mailfile __P((SCR *, int, char *));
|
||||
static int rcv_mktemp __P((SCR *, char *, const char *, int));
|
||||
|
||||
/*
|
||||
* rcv_tmp --
|
||||
* Build a file name that will be used as the recovery file.
|
||||
*
|
||||
* PUBLIC: int rcv_tmp __P((SCR *, EXF *, char *));
|
||||
*/
|
||||
int
|
||||
rcv_tmp(SCR *sp, EXF *ep, char *name)
|
||||
{
|
||||
struct stat sb;
|
||||
int fd;
|
||||
char path[MAXPATHLEN];
|
||||
const char *dp;
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
|
||||
*
|
||||
*
|
||||
* If the recovery directory doesn't exist, try and create it. As
|
||||
* the recovery files are themselves protected from reading/writing
|
||||
* by other than the owner, the worst that can happen is that a user
|
||||
* would have permission to remove other user's recovery files. If
|
||||
* the sticky bit has the BSD semantics, that too will be impossible.
|
||||
*/
|
||||
if (opts_empty(sp, O_RECDIR, 0))
|
||||
goto err;
|
||||
dp = O_STR(sp, O_RECDIR);
|
||||
if (stat(dp, &sb)) {
|
||||
if (errno != ENOENT || mkdir(dp, 0)) {
|
||||
msgq(sp, M_SYSERR, "%s", dp);
|
||||
goto err;
|
||||
}
|
||||
(void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
|
||||
}
|
||||
|
||||
/* Newlines delimit the mail messages. */
|
||||
if (strchr(name, '\n')) {
|
||||
msgq(sp, M_ERR,
|
||||
"055|Files with newlines in the name are unrecoverable");
|
||||
goto err;
|
||||
}
|
||||
|
||||
(void)snprintf(path, sizeof(path), "%s/vi.XXXXXX", dp);
|
||||
if ((fd = rcv_mktemp(sp, path, dp, S_IRWXU)) == -1)
|
||||
goto err;
|
||||
(void)close(fd);
|
||||
|
||||
if ((ep->rcv_path = strdup(path)) == NULL) {
|
||||
msgq(sp, M_SYSERR, NULL);
|
||||
(void)unlink(path);
|
||||
err: msgq(sp, M_ERR,
|
||||
"056|Modifications not recoverable if the session fails");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* We believe the file is recoverable. */
|
||||
F_SET(ep, F_RCV_ON);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcv_init --
|
||||
* Force the file to be snapshotted for recovery.
|
||||
*
|
||||
* PUBLIC: int rcv_init __P((SCR *));
|
||||
*/
|
||||
int
|
||||
rcv_init(SCR *sp)
|
||||
{
|
||||
EXF *ep;
|
||||
db_recno_t lno;
|
||||
|
||||
ep = sp->ep;
|
||||
|
||||
/* Only do this once. */
|
||||
F_CLR(ep, F_FIRSTMODIFY);
|
||||
|
||||
/* If we already know the file isn't recoverable, we're done. */
|
||||
if (!F_ISSET(ep, F_RCV_ON))
|
||||
return (0);
|
||||
|
||||
/* Turn off recoverability until we figure out if this will work. */
|
||||
F_CLR(ep, F_RCV_ON);
|
||||
|
||||
/* Test if we're recovering a file, not editing one. */
|
||||
if (ep->rcv_mpath == NULL) {
|
||||
/* Build a file to mail to the user. */
|
||||
if (rcv_mailfile(sp, 0, NULL))
|
||||
goto err;
|
||||
|
||||
/* Force a read of the entire file. */
|
||||
if (db_last(sp, &lno))
|
||||
goto err;
|
||||
|
||||
/* Turn on a busy message, and sync it to backing store. */
|
||||
sp->gp->scr_busy(sp,
|
||||
"057|Copying file for recovery...", BUSY_ON);
|
||||
if (ep->db->sync(ep->db, 0)) {
|
||||
msgq_str(sp, M_SYSERR, ep->rcv_path,
|
||||
"058|Preservation failed: %s");
|
||||
sp->gp->scr_busy(sp, NULL, BUSY_OFF);
|
||||
goto err;
|
||||
}
|
||||
sp->gp->scr_busy(sp, NULL, BUSY_OFF);
|
||||
}
|
||||
|
||||
/* Turn off the owner execute bit. */
|
||||
(void)chmod(ep->rcv_path, S_IRUSR | S_IWUSR);
|
||||
|
||||
/* We believe the file is recoverable. */
|
||||
F_SET(ep, F_RCV_ON);
|
||||
return (0);
|
||||
|
||||
err: msgq(sp, M_ERR,
|
||||
"059|Modifications not recoverable if the session fails");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcv_sync --
|
||||
* Sync the file, optionally:
|
||||
* flagging the backup file to be preserved
|
||||
* snapshotting the backup file and send email to the user
|
||||
* sending email to the user if the file was modified
|
||||
* ending the file session
|
||||
*
|
||||
* PUBLIC: int rcv_sync __P((SCR *, u_int));
|
||||
*/
|
||||
int
|
||||
rcv_sync(SCR *sp, u_int flags)
|
||||
{
|
||||
EXF *ep;
|
||||
int fd, rval;
|
||||
char buf[1024];
|
||||
const char *dp;
|
||||
|
||||
/* Make sure that there's something to recover/sync. */
|
||||
ep = sp->ep;
|
||||
if (ep == NULL || !F_ISSET(ep, F_RCV_ON))
|
||||
return (0);
|
||||
|
||||
/* Sync the file if it's been modified. */
|
||||
if (F_ISSET(ep, F_MODIFIED)) {
|
||||
if (ep->db->sync(ep->db, 0)) {
|
||||
F_CLR(ep, F_RCV_ON | F_RCV_NORM);
|
||||
msgq_str(sp, M_SYSERR,
|
||||
ep->rcv_path, "060|File backup failed: %s");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* REQUEST: don't remove backing file on exit. */
|
||||
if (LF_ISSET(RCV_PRESERVE))
|
||||
F_SET(ep, F_RCV_NORM);
|
||||
|
||||
/* REQUEST: send email. */
|
||||
if (LF_ISSET(RCV_EMAIL))
|
||||
rcv_email(sp, ep->rcv_mpath);
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Each time the user exec's :preserve, we have to snapshot all of
|
||||
* the recovery information, i.e. it's like the user re-edited the
|
||||
* file. We copy the DB(3) backing file, and then create a new mail
|
||||
* recovery file, it's simpler than exiting and reopening all of the
|
||||
* underlying files.
|
||||
*
|
||||
* REQUEST: snapshot the file.
|
||||
*/
|
||||
rval = 0;
|
||||
if (LF_ISSET(RCV_SNAPSHOT)) {
|
||||
if (opts_empty(sp, O_RECDIR, 0))
|
||||
goto err;
|
||||
dp = O_STR(sp, O_RECDIR);
|
||||
(void)snprintf(buf, sizeof(buf), "%s/vi.XXXXXX", dp);
|
||||
if ((fd = rcv_mktemp(sp, buf, dp, S_IRUSR | S_IWUSR)) == -1)
|
||||
goto err;
|
||||
sp->gp->scr_busy(sp,
|
||||
"061|Copying file for recovery...", BUSY_ON);
|
||||
if (rcv_copy(sp, fd, ep->rcv_path) ||
|
||||
close(fd) || rcv_mailfile(sp, 1, buf)) {
|
||||
(void)unlink(buf);
|
||||
(void)close(fd);
|
||||
rval = 1;
|
||||
}
|
||||
sp->gp->scr_busy(sp, NULL, BUSY_OFF);
|
||||
}
|
||||
if (0) {
|
||||
err: rval = 1;
|
||||
}
|
||||
|
||||
/* REQUEST: end the file session. */
|
||||
if (LF_ISSET(RCV_ENDSESSION) && file_end(sp, NULL, 1))
|
||||
rval = 1;
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcv_mailfile --
|
||||
* Build the file to mail to the user.
|
||||
*/
|
||||
static int
|
||||
rcv_mailfile(SCR *sp, int issync, char *cp_path)
|
||||
{
|
||||
EXF *ep;
|
||||
GS *gp;
|
||||
struct passwd *pw;
|
||||
size_t len;
|
||||
time_t now;
|
||||
uid_t uid;
|
||||
int fd;
|
||||
char *p, *t, buf[4096], mpath[MAXPATHLEN];
|
||||
const char *dp;
|
||||
char *t1, *t2, *t3;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* MAXHOSTNAMELEN is in various places on various systems, including
|
||||
* <netdb.h> and <sys/socket.h>. If not found, use a large default.
|
||||
*/
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 1024
|
||||
#endif
|
||||
char host[MAXHOSTNAMELEN];
|
||||
|
||||
gp = sp->gp;
|
||||
if ((pw = getpwuid(uid = getuid())) == NULL) {
|
||||
msgq(sp, M_ERR,
|
||||
"062|Information on user id %u not found", uid);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (opts_empty(sp, O_RECDIR, 0))
|
||||
return (1);
|
||||
dp = O_STR(sp, O_RECDIR);
|
||||
(void)snprintf(mpath, sizeof(mpath), "%s/recover.XXXXXX", dp);
|
||||
if ((fd = rcv_mktemp(sp, mpath, dp, S_IRUSR | S_IWUSR)) == -1)
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* We keep an open lock on the file so that the recover option can
|
||||
* distinguish between files that are live and those that need to
|
||||
* be recovered. There's an obvious window between the mkstemp call
|
||||
* and the lock, but it's pretty small.
|
||||
*/
|
||||
ep = sp->ep;
|
||||
if (file_lock(sp, NULL, NULL, fd, 1) != LOCK_SUCCESS)
|
||||
msgq(sp, M_SYSERR, "063|Unable to lock recovery file");
|
||||
if (!issync) {
|
||||
/* Save the recover file descriptor, and mail path. */
|
||||
ep->rcv_fd = fd;
|
||||
if ((ep->rcv_mpath = strdup(mpath)) == NULL) {
|
||||
msgq(sp, M_SYSERR, NULL);
|
||||
goto err;
|
||||
}
|
||||
cp_path = ep->rcv_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* We can't use stdio(3) here. The problem is that we may be using
|
||||
* fcntl(2), so if ANY file descriptor into the file is closed, the
|
||||
* lock is lost. So, we could never close the FILE *, even if we
|
||||
* dup'd the fd first.
|
||||
*/
|
||||
t = sp->frp->name;
|
||||
if ((p = strrchr(t, '/')) == NULL)
|
||||
p = t;
|
||||
else
|
||||
++p;
|
||||
(void)time(&now);
|
||||
(void)gethostname(host, sizeof(host));
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"%s%s\n%s%s\n%s\n%s\n%s%s\n%s%s\n%s\n\n",
|
||||
VI_FHEADER, t, /* Non-standard. */
|
||||
VI_PHEADER, cp_path, /* Non-standard. */
|
||||
"Reply-To: root",
|
||||
"From: root (Nvi recovery program)",
|
||||
"To: ", pw->pw_name,
|
||||
"Subject: Nvi saved the file ", p,
|
||||
"Precedence: bulk"); /* For vacation(1). */
|
||||
if (len > sizeof(buf) - 1)
|
||||
goto lerr;
|
||||
if ((size_t)write(fd, buf, len) != len)
|
||||
goto werr;
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"%s%.24s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n\n",
|
||||
"On ", ctime(&now), ", the user ", pw->pw_name,
|
||||
" was editing a file named ", t, " on the machine ",
|
||||
host, ", when it was saved for recovery. ",
|
||||
"You can recover most, if not all, of the changes ",
|
||||
"to this file using the -r option to ", gp->progname, ":\n\n\t",
|
||||
gp->progname, " -r ", t);
|
||||
if (len > sizeof(buf) - 1) {
|
||||
lerr: msgq(sp, M_ERR, "064|Recovery file buffer overrun");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Format the message. (Yes, I know it's silly.)
|
||||
* Requires that the message end in a <newline>.
|
||||
*/
|
||||
#define FMTCOLS 60
|
||||
for (t1 = buf; len > 0; len -= t2 - t1, t1 = t2) {
|
||||
/* Check for a short length. */
|
||||
if (len <= FMTCOLS) {
|
||||
t2 = t1 + (len - 1);
|
||||
goto wout;
|
||||
}
|
||||
|
||||
/* Check for a required <newline>. */
|
||||
t2 = strchr(t1, '\n');
|
||||
if (t2 - t1 <= FMTCOLS)
|
||||
goto wout;
|
||||
|
||||
/* Find the closest space, if any. */
|
||||
for (t3 = t2; t2 > t1; --t2)
|
||||
if (*t2 == ' ') {
|
||||
if (t2 - t1 <= FMTCOLS)
|
||||
goto wout;
|
||||
t3 = t2;
|
||||
}
|
||||
t2 = t3;
|
||||
|
||||
/* t2 points to the last character to display. */
|
||||
wout: *t2++ = '\n';
|
||||
|
||||
/* t2 points one after the last character to display. */
|
||||
if (write(fd, t1, t2 - t1) != t2 - t1)
|
||||
goto werr;
|
||||
}
|
||||
|
||||
if (issync) {
|
||||
rcv_email(sp, mpath);
|
||||
if (close(fd)) {
|
||||
werr: msgq(sp, M_SYSERR, "065|Recovery file");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
|
||||
err: if (!issync)
|
||||
ep->rcv_fd = -1;
|
||||
if (fd != -1)
|
||||
(void)close(fd);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* people making love
|
||||
* never exactly the same
|
||||
* just like a snowflake
|
||||
*
|
||||
* rcv_list --
|
||||
* List the files that can be recovered by this user.
|
||||
*
|
||||
* PUBLIC: int rcv_list __P((SCR *));
|
||||
*/
|
||||
int
|
||||
rcv_list(SCR *sp)
|
||||
{
|
||||
struct dirent *dp;
|
||||
struct stat sb;
|
||||
DIR *dirp;
|
||||
FILE *fp;
|
||||
int found;
|
||||
char *p, *t;
|
||||
const char *d;
|
||||
char file[MAXPATHLEN], path[MAXPATHLEN];
|
||||
|
||||
/* Open the recovery directory for reading. */
|
||||
if (opts_empty(sp, O_RECDIR, 0))
|
||||
return (1);
|
||||
d = O_STR(sp, O_RECDIR);
|
||||
if (chdir(d) || (dirp = opendir(".")) == NULL) {
|
||||
msgq_str(sp, M_SYSERR, d, "recdir: %s");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Read the directory. */
|
||||
for (found = 0; (dp = readdir(dirp)) != NULL;) {
|
||||
if (strncmp(dp->d_name, "recover.", 8))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If it's readable, it's recoverable.
|
||||
*
|
||||
* XXX
|
||||
* Should be "r", we don't want to write the file. However,
|
||||
* if we're using fcntl(2), there's no way to lock a file
|
||||
* descriptor that's not open for writing.
|
||||
*/
|
||||
if ((fp = fopen(dp->d_name, "r+")) == NULL)
|
||||
continue;
|
||||
|
||||
switch (file_lock(sp, NULL, NULL, fileno(fp), 1)) {
|
||||
case LOCK_FAILED:
|
||||
/*
|
||||
* XXX
|
||||
* Assume that a lock can't be acquired, but that we
|
||||
* should permit recovery anyway. If this is wrong,
|
||||
* and someone else is using the file, we're going to
|
||||
* die horribly.
|
||||
*/
|
||||
break;
|
||||
case LOCK_SUCCESS:
|
||||
break;
|
||||
case LOCK_UNAVAIL:
|
||||
/* If it's locked, it's live. */
|
||||
(void)fclose(fp);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check the headers. */
|
||||
if (fgets(file, sizeof(file), fp) == NULL ||
|
||||
strncmp(file, VI_FHEADER, sizeof(VI_FHEADER) - 1) ||
|
||||
(p = strchr(file, '\n')) == NULL ||
|
||||
fgets(path, sizeof(path), fp) == NULL ||
|
||||
strncmp(path, VI_PHEADER, sizeof(VI_PHEADER) - 1) ||
|
||||
(t = strchr(path, '\n')) == NULL) {
|
||||
msgq_str(sp, M_ERR, dp->d_name,
|
||||
"066|%s: malformed recovery file");
|
||||
goto next;
|
||||
}
|
||||
*p = *t = '\0';
|
||||
|
||||
/*
|
||||
* If the file doesn't exist, it's an orphaned recovery file,
|
||||
* toss it.
|
||||
*
|
||||
* XXX
|
||||
* This can occur if the backup file was deleted and we crashed
|
||||
* before deleting the email file.
|
||||
*/
|
||||
errno = 0;
|
||||
if (stat(path + sizeof(VI_PHEADER) - 1, &sb) &&
|
||||
errno == ENOENT) {
|
||||
(void)unlink(dp->d_name);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Get the last modification time and display. */
|
||||
(void)fstat(fileno(fp), &sb);
|
||||
(void)printf("%.24s: %s\n",
|
||||
ctime(&sb.st_mtime), file + sizeof(VI_FHEADER) - 1);
|
||||
found = 1;
|
||||
|
||||
/* Close, discarding lock. */
|
||||
next: (void)fclose(fp);
|
||||
}
|
||||
if (found == 0)
|
||||
(void)printf("vi: no files to recover.\n");
|
||||
(void)closedir(dirp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcv_read --
|
||||
* Start a recovered file as the file to edit.
|
||||
*
|
||||
* PUBLIC: int rcv_read __P((SCR *, FREF *));
|
||||
*/
|
||||
int
|
||||
rcv_read(SCR *sp, FREF *frp)
|
||||
{
|
||||
struct dirent *dp;
|
||||
struct stat sb;
|
||||
DIR *dirp;
|
||||
EXF *ep;
|
||||
time_t rec_mtime;
|
||||
int fd, found, locked = 0, requested, sv_fd;
|
||||
char *name, *p, *t, *recp, *pathp;
|
||||
const char *rp;
|
||||
char file[MAXPATHLEN], path[MAXPATHLEN], recpath[MAXPATHLEN];
|
||||
|
||||
if (opts_empty(sp, O_RECDIR, 0))
|
||||
return (1);
|
||||
rp = O_STR(sp, O_RECDIR);
|
||||
if ((dirp = opendir(rp)) == NULL) {
|
||||
msgq_str(sp, M_ERR, rp, "%s");
|
||||
return (1);
|
||||
}
|
||||
|
||||
name = frp->name;
|
||||
sv_fd = -1;
|
||||
rec_mtime = 0;
|
||||
recp = pathp = NULL;
|
||||
for (found = requested = 0; (dp = readdir(dirp)) != NULL;) {
|
||||
if (strncmp(dp->d_name, "recover.", 8))
|
||||
continue;
|
||||
(void)snprintf(recpath,
|
||||
sizeof(recpath), "%s/%s", rp, dp->d_name);
|
||||
|
||||
/*
|
||||
* If it's readable, it's recoverable. It would be very
|
||||
* nice to use stdio(3), but, we can't because that would
|
||||
* require closing and then reopening the file so that we
|
||||
* could have a lock and still close the FP. Another tip
|
||||
* of the hat to fcntl(2).
|
||||
*
|
||||
* XXX
|
||||
* Should be O_RDONLY, we don't want to write it. However,
|
||||
* if we're using fcntl(2), there's no way to lock a file
|
||||
* descriptor that's not open for writing.
|
||||
*/
|
||||
if ((fd = open(recpath, O_RDWR, 0)) == -1)
|
||||
continue;
|
||||
|
||||
switch (file_lock(sp, NULL, NULL, fd, 1)) {
|
||||
case LOCK_FAILED:
|
||||
/*
|
||||
* XXX
|
||||
* Assume that a lock can't be acquired, but that we
|
||||
* should permit recovery anyway. If this is wrong,
|
||||
* and someone else is using the file, we're going to
|
||||
* die horribly.
|
||||
*/
|
||||
locked = 0;
|
||||
break;
|
||||
case LOCK_SUCCESS:
|
||||
locked = 1;
|
||||
break;
|
||||
case LOCK_UNAVAIL:
|
||||
/* If it's locked, it's live. */
|
||||
(void)close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check the headers. */
|
||||
if (rcv_gets(file, sizeof(file), fd) == NULL ||
|
||||
strncmp(file, VI_FHEADER, sizeof(VI_FHEADER) - 1) ||
|
||||
(p = strchr(file, '\n')) == NULL ||
|
||||
rcv_gets(path, sizeof(path), fd) == NULL ||
|
||||
strncmp(path, VI_PHEADER, sizeof(VI_PHEADER) - 1) ||
|
||||
(t = strchr(path, '\n')) == NULL) {
|
||||
msgq_str(sp, M_ERR, recpath,
|
||||
"067|%s: malformed recovery file");
|
||||
goto next;
|
||||
}
|
||||
*p = *t = '\0';
|
||||
++found;
|
||||
|
||||
/*
|
||||
* If the file doesn't exist, it's an orphaned recovery file,
|
||||
* toss it.
|
||||
*
|
||||
* XXX
|
||||
* This can occur if the backup file was deleted and we crashed
|
||||
* before deleting the email file.
|
||||
*/
|
||||
errno = 0;
|
||||
if (stat(path + sizeof(VI_PHEADER) - 1, &sb) &&
|
||||
errno == ENOENT) {
|
||||
(void)unlink(dp->d_name);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Check the file name. */
|
||||
if (strcmp(file + sizeof(VI_FHEADER) - 1, name))
|
||||
goto next;
|
||||
|
||||
++requested;
|
||||
|
||||
/*
|
||||
* If we've found more than one, take the most recent.
|
||||
*
|
||||
* XXX
|
||||
* Since we're using st_mtime, for portability reasons,
|
||||
* we only get a single second granularity, instead of
|
||||
* getting it right.
|
||||
*/
|
||||
(void)fstat(fd, &sb);
|
||||
if (recp == NULL || rec_mtime < sb.st_mtime) {
|
||||
p = recp;
|
||||
t = pathp;
|
||||
if ((recp = strdup(recpath)) == NULL) {
|
||||
msgq(sp, M_SYSERR, NULL);
|
||||
recp = p;
|
||||
goto next;
|
||||
}
|
||||
if ((pathp = strdup(path)) == NULL) {
|
||||
msgq(sp, M_SYSERR, NULL);
|
||||
free(recp);
|
||||
recp = p;
|
||||
pathp = t;
|
||||
goto next;
|
||||
}
|
||||
if (p != NULL) {
|
||||
free(p);
|
||||
free(t);
|
||||
}
|
||||
rec_mtime = sb.st_mtime;
|
||||
if (sv_fd != -1)
|
||||
(void)close(sv_fd);
|
||||
sv_fd = fd;
|
||||
} else
|
||||
next: (void)close(fd);
|
||||
}
|
||||
(void)closedir(dirp);
|
||||
|
||||
if (recp == NULL) {
|
||||
msgq_str(sp, M_INFO, name,
|
||||
"068|No files named %s, readable by you, to recover");
|
||||
return (1);
|
||||
}
|
||||
if (found) {
|
||||
if (requested > 1)
|
||||
msgq(sp, M_INFO,
|
||||
"069|There are older versions of this file for you to recover");
|
||||
if (found > requested)
|
||||
msgq(sp, M_INFO,
|
||||
"070|There are other files for you to recover");
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the FREF structure, start the btree file.
|
||||
*
|
||||
* XXX
|
||||
* file_init() is going to set ep->rcv_path.
|
||||
*/
|
||||
if (file_init(sp, frp, pathp + sizeof(VI_PHEADER) - 1, 0)) {
|
||||
free(recp);
|
||||
free(pathp);
|
||||
(void)close(sv_fd);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We keep an open lock on the file so that the recover option can
|
||||
* distinguish between files that are live and those that need to
|
||||
* be recovered. The lock is already acquired, just copy it.
|
||||
*/
|
||||
ep = sp->ep;
|
||||
ep->rcv_mpath = recp;
|
||||
ep->rcv_fd = sv_fd;
|
||||
if (!locked)
|
||||
F_SET(frp, FR_UNLOCKED);
|
||||
|
||||
/* We believe the file is recoverable. */
|
||||
F_SET(ep, F_RCV_ON);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcv_copy --
|
||||
* Copy a recovery file.
|
||||
*/
|
||||
static int
|
||||
rcv_copy(SCR *sp, int wfd, char *fname)
|
||||
{
|
||||
int nr, nw, off, rfd;
|
||||
char buf[8 * 1024];
|
||||
|
||||
if ((rfd = open(fname, O_RDONLY, 0)) == -1)
|
||||
goto err;
|
||||
while ((nr = read(rfd, buf, sizeof(buf))) > 0)
|
||||
for (off = 0; nr; nr -= nw, off += nw)
|
||||
if ((nw = write(wfd, buf + off, nr)) < 0)
|
||||
goto err;
|
||||
if (nr == 0)
|
||||
return (0);
|
||||
|
||||
err: msgq_str(sp, M_SYSERR, fname, "%s");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcv_gets --
|
||||
* Fgets(3) for a file descriptor.
|
||||
*/
|
||||
static char *
|
||||
rcv_gets(char *buf, size_t len, int fd)
|
||||
{
|
||||
int nr;
|
||||
char *p;
|
||||
|
||||
if ((nr = read(fd, buf, len - 1)) == -1)
|
||||
return (NULL);
|
||||
if ((p = strchr(buf, '\n')) == NULL)
|
||||
return (NULL);
|
||||
(void)lseek(fd, (off_t)((p - buf) + 1), SEEK_SET);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcv_mktemp --
|
||||
* Paranoid make temporary file routine.
|
||||
*/
|
||||
static int
|
||||
rcv_mktemp(SCR *sp, char *path, const char *dname, int perms)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* We expect mkstemp(3) to set the permissions correctly. On
|
||||
* historic System V systems, mkstemp didn't. Do it here, on
|
||||
* GP's.
|
||||
*
|
||||
* XXX
|
||||
* The variable perms should really be a mode_t, and it would
|
||||
* be nice to use fchmod(2) instead of chmod(2), here.
|
||||
*/
|
||||
if ((fd = mkstemp(path)) == -1)
|
||||
msgq_str(sp, M_SYSERR, dname, "%s");
|
||||
else
|
||||
(void)chmod(path, perms);
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcv_email --
|
||||
* Send email.
|
||||
*/
|
||||
static void
|
||||
rcv_email(SCR *sp, char *fname)
|
||||
{
|
||||
struct stat sb;
|
||||
char buf[MAXPATHLEN * 2 + 20];
|
||||
|
||||
if (_PATH_SENDMAIL[0] != '/' || stat(_PATH_SENDMAIL, &sb))
|
||||
msgq_str(sp, M_SYSERR,
|
||||
_PATH_SENDMAIL, "071|not sending email: %s");
|
||||
else {
|
||||
/*
|
||||
* !!!
|
||||
* If you need to port this to a system that doesn't have
|
||||
* sendmail, the -t flag causes sendmail to read the message
|
||||
* for the recipients instead of specifying them some other
|
||||
* way.
|
||||
*/
|
||||
(void)snprintf(buf, sizeof(buf),
|
||||
"%s -t < %s", _PATH_SENDMAIL, fname);
|
||||
(void)system(buf);
|
||||
}
|
||||
}
|
||||
238
dist/nvi/common/screen.c
vendored
Normal file
238
dist/nvi/common/screen.c
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
/* $NetBSD: screen.c,v 1.1.1.2 2008/05/18 14:29:51 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: screen.c,v 10.22 2001/06/25 15:19:12 skimo Exp (Berkeley) Date: 2001/06/25 15:19:12";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "../vi/vi.h"
|
||||
|
||||
/*
|
||||
* screen_init --
|
||||
* Do the default initialization of an SCR structure.
|
||||
*
|
||||
* PUBLIC: int screen_init __P((GS *, SCR *, SCR **));
|
||||
*/
|
||||
int
|
||||
screen_init(GS *gp, SCR *orig, SCR **spp)
|
||||
{
|
||||
SCR *sp;
|
||||
size_t len;
|
||||
|
||||
*spp = NULL;
|
||||
CALLOC_RET(orig, sp, SCR *, 1, sizeof(SCR));
|
||||
*spp = sp;
|
||||
|
||||
/* INITIALIZED AT SCREEN CREATE. */
|
||||
sp->id = ++gp->id;
|
||||
sp->refcnt = 1;
|
||||
|
||||
sp->gp = gp; /* All ref the GS structure. */
|
||||
|
||||
sp->ccnt = 2; /* Anything > 1 */
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* sp->defscroll is initialized by the opts_init() code because
|
||||
* we don't have the option information yet.
|
||||
*/
|
||||
|
||||
CIRCLEQ_INIT(&sp->tiq);
|
||||
|
||||
/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
|
||||
if (orig == NULL) {
|
||||
sp->searchdir = NOTSET;
|
||||
} else {
|
||||
sp->wp = orig->wp;
|
||||
|
||||
/* Alternate file name. */
|
||||
if (orig->alt_name != NULL &&
|
||||
(sp->alt_name = strdup(orig->alt_name)) == NULL)
|
||||
goto mem;
|
||||
|
||||
/* Last executed at buffer. */
|
||||
if (F_ISSET(orig, SC_AT_SET)) {
|
||||
F_SET(sp, SC_AT_SET);
|
||||
sp->at_lbuf = orig->at_lbuf;
|
||||
}
|
||||
|
||||
/* Retain searching/substitution information. */
|
||||
sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD;
|
||||
if (orig->re != NULL && (sp->re =
|
||||
v_wstrdup(sp, orig->re, orig->re_len)) == NULL)
|
||||
goto mem;
|
||||
sp->re_len = orig->re_len;
|
||||
if (orig->subre != NULL && (sp->subre =
|
||||
v_wstrdup(sp, orig->subre, orig->subre_len)) == NULL)
|
||||
goto mem;
|
||||
sp->subre_len = orig->subre_len;
|
||||
if (orig->repl != NULL && (sp->repl =
|
||||
v_wstrdup(sp, orig->repl, orig->repl_len)) == NULL)
|
||||
goto mem;
|
||||
sp->repl_len = orig->repl_len;
|
||||
if (orig->newl_len) {
|
||||
len = orig->newl_len * sizeof(size_t);
|
||||
MALLOC(sp, sp->newl, size_t *, len);
|
||||
if (sp->newl == NULL) {
|
||||
mem: msgq(orig, M_SYSERR, NULL);
|
||||
goto err;
|
||||
}
|
||||
sp->newl_len = orig->newl_len;
|
||||
sp->newl_cnt = orig->newl_cnt;
|
||||
memcpy(sp->newl, orig->newl, len);
|
||||
}
|
||||
|
||||
if (opts_copy(orig, sp))
|
||||
goto err;
|
||||
|
||||
F_SET(sp, F_ISSET(orig, SC_EX | SC_VI));
|
||||
}
|
||||
|
||||
if (ex_screen_copy(orig, sp)) /* Ex. */
|
||||
goto err;
|
||||
if (v_screen_copy(orig, sp)) /* Vi. */
|
||||
goto err;
|
||||
sp->cl_private = 0; /* XXX */
|
||||
conv_init(orig, sp); /* XXX */
|
||||
|
||||
*spp = sp;
|
||||
return (0);
|
||||
|
||||
err: screen_end(sp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* screen_end --
|
||||
* Release a screen, no matter what had (and had not) been
|
||||
* initialized.
|
||||
*
|
||||
* PUBLIC: int screen_end __P((SCR *));
|
||||
*/
|
||||
int
|
||||
screen_end(SCR *sp)
|
||||
{
|
||||
int rval;
|
||||
|
||||
/* If multiply referenced, just decrement the count and return. */
|
||||
if (--sp->refcnt != 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Remove the screen from the displayed queue.
|
||||
*
|
||||
* If a created screen failed during initialization, it may not
|
||||
* be linked into the chain.
|
||||
*/
|
||||
if (sp->q.cqe_next != NULL)
|
||||
CIRCLEQ_REMOVE(&sp->wp->scrq, sp, q);
|
||||
|
||||
/* The screen is no longer real. */
|
||||
F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
|
||||
|
||||
rval = 0;
|
||||
#ifdef HAVE_PERL_INTERP
|
||||
if (perl_screen_end(sp)) /* End perl. */
|
||||
rval = 1;
|
||||
#endif
|
||||
if (v_screen_end(sp)) /* End vi. */
|
||||
rval = 1;
|
||||
if (ex_screen_end(sp)) /* End ex. */
|
||||
rval = 1;
|
||||
|
||||
/* Free file names. */
|
||||
{ char **ap;
|
||||
if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) {
|
||||
for (ap = sp->argv; *ap != NULL; ++ap)
|
||||
free(*ap);
|
||||
free(sp->argv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free any text input. */
|
||||
if (sp->tiq.cqh_first != NULL)
|
||||
text_lfree(&sp->tiq);
|
||||
|
||||
/* Free alternate file name. */
|
||||
if (sp->alt_name != NULL)
|
||||
free(sp->alt_name);
|
||||
|
||||
/* Free up search information. */
|
||||
if (sp->re != NULL)
|
||||
free(sp->re);
|
||||
if (F_ISSET(sp, SC_RE_SEARCH))
|
||||
regfree(&sp->re_c);
|
||||
if (sp->subre != NULL)
|
||||
free(sp->subre);
|
||||
if (F_ISSET(sp, SC_RE_SUBST))
|
||||
regfree(&sp->subre_c);
|
||||
if (sp->repl != NULL)
|
||||
free(sp->repl);
|
||||
if (sp->newl != NULL)
|
||||
free(sp->newl);
|
||||
|
||||
/* Free all the options */
|
||||
opts_free(sp);
|
||||
|
||||
/* Free the screen itself. */
|
||||
free(sp);
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* screen_next --
|
||||
* Return the next screen in the queue.
|
||||
*
|
||||
* PUBLIC: SCR *screen_next __P((SCR *));
|
||||
*/
|
||||
SCR *
|
||||
screen_next(SCR *sp)
|
||||
{
|
||||
GS *gp;
|
||||
WIN *wp;
|
||||
SCR *next;
|
||||
|
||||
/* Try the display queue, without returning the current screen. */
|
||||
gp = sp->gp;
|
||||
wp = sp->wp;
|
||||
for (next = wp->scrq.cqh_first;
|
||||
next != (void *)&wp->scrq; next = next->q.cqe_next)
|
||||
if (next != sp)
|
||||
break;
|
||||
if (next != (void *)&wp->scrq)
|
||||
return (next);
|
||||
|
||||
/* Try the hidden queue; if found, move screen to the display queue. */
|
||||
if (gp->hq.cqh_first != (void *)&gp->hq) {
|
||||
next = gp->hq.cqh_first;
|
||||
CIRCLEQ_REMOVE(&gp->hq, next, q);
|
||||
CIRCLEQ_INSERT_HEAD(&wp->scrq, next, q);
|
||||
next->wp = sp->wp;
|
||||
return (next);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
283
dist/nvi/common/screen.h
vendored
Normal file
283
dist/nvi/common/screen.h
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
/* $NetBSD: screen.h,v 1.2 2011/11/23 19:25:28 tnozaki 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*
|
||||
* Id: screen.h,v 10.49 2002/03/02 23:47:02 skimo Exp (Berkeley) Date: 2002/03/02 23:47:02
|
||||
*/
|
||||
|
||||
/*
|
||||
* There are minimum values that vi has to have to display a screen. The row
|
||||
* minimum is fixed at 1 (the svi code can share a line between the text line
|
||||
* and the colon command/message line). Column calculation is a lot trickier.
|
||||
* For example, you have to have enough columns to display the line number,
|
||||
* not to mention guaranteeing that tabstop and shiftwidth values are smaller
|
||||
* than the current column value. It's simpler to have a fixed value and not
|
||||
* worry about it.
|
||||
*
|
||||
* XXX
|
||||
* MINIMUM_SCREEN_COLS is almost certainly wrong.
|
||||
*/
|
||||
#define MINIMUM_SCREEN_ROWS 1
|
||||
#define MINIMUM_SCREEN_COLS 20
|
||||
|
||||
/*
|
||||
* WIN --
|
||||
* A list of screens that are displayed as a whole.
|
||||
*/
|
||||
struct _win {
|
||||
CIRCLEQ_ENTRY(_win) q; /* Windows. */
|
||||
|
||||
CIRCLEQ_HEAD(_scrh, _scr) scrq; /* Screens */
|
||||
|
||||
GS *gp; /* Pointer to global area. */
|
||||
|
||||
SCR *ccl_sp; /* Colon command-line screen. */
|
||||
|
||||
void *perl_private; /* Perl interpreter. */
|
||||
|
||||
void *ip_private; /* IP support private area. */
|
||||
|
||||
void *th_private; /* Threading support private area. */
|
||||
|
||||
/*
|
||||
* Ex command structures (EXCMD). Defined here because ex commands
|
||||
* exist outside of any particular screen or file.
|
||||
*/
|
||||
#define EXCMD_RUNNING(wp) ((wp)->ecq.lh_first->clen != 0)
|
||||
LIST_HEAD(_excmdh, _excmd) ecq; /* Ex command linked list. */
|
||||
EXCMD excmd; /* Default ex command structure. */
|
||||
char *if_name; /* Current associated file. */
|
||||
db_recno_t if_lno; /* Current associated line number. */
|
||||
|
||||
EVENT *i_event; /* Array of input events. */
|
||||
size_t i_nelem; /* Number of array elements. */
|
||||
size_t i_cnt; /* Count of events. */
|
||||
size_t i_next; /* Offset of next event. */
|
||||
|
||||
CB *dcbp; /* Default cut buffer pointer. */
|
||||
CB dcb_store; /* Default cut buffer storage. */
|
||||
LIST_HEAD(_cuth, _cb) cutq; /* Linked list of cut buffers. */
|
||||
|
||||
/* For now, can be either char or CHAR_T buffer */
|
||||
char *tmp_bp; /* Temporary buffer. */
|
||||
size_t tmp_blen; /* Temporary buffer size. */
|
||||
|
||||
char *l_lp; /* Log buffer. */
|
||||
size_t l_len; /* Log buffer length. */
|
||||
|
||||
CONVWIN cw;
|
||||
|
||||
/* Flags. */
|
||||
#define W_TMP_INUSE 0x0001 /* Temporary buffer in use. */
|
||||
u_int32_t flags;
|
||||
|
||||
/* Message or ex output. */
|
||||
void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
|
||||
};
|
||||
|
||||
/*
|
||||
* SCR --
|
||||
* The screen structure. To the extent possible, all screen information
|
||||
* is stored in the various private areas. The only information here
|
||||
* is used by global routines or is shared by too many screens.
|
||||
*/
|
||||
struct _scr {
|
||||
/* INITIALIZED AT SCREEN CREATE. */
|
||||
CIRCLEQ_ENTRY(_scr) q; /* Screens. */
|
||||
CIRCLEQ_ENTRY(_scr) eq; /* Screens. */
|
||||
|
||||
int id; /* Screen id #. */
|
||||
int refcnt; /* Reference count. */
|
||||
|
||||
WIN *wp; /* Pointer to window. */
|
||||
GS *gp; /* Pointer to global area. */
|
||||
SCR *nextdisp; /* Next display screen. */
|
||||
SCR *ccl_parent; /* Colon command-line parent screen. */
|
||||
EXF *ep; /* Screen's current EXF structure. */
|
||||
|
||||
CHAR_T *c_lp; /* Cached line. */
|
||||
size_t c_len; /* Cached line length. */
|
||||
/* May move out again once we use DB
|
||||
* to cache internal representation
|
||||
*/
|
||||
size_t c_blen; /* Cached line buffer length. */
|
||||
db_recno_t c_lno; /* Cached line number. */
|
||||
|
||||
FREF *frp; /* FREF being edited. */
|
||||
char **argv; /* NULL terminated file name array. */
|
||||
char **cargv; /* Current file name. */
|
||||
|
||||
u_long ccnt; /* Command count. */
|
||||
u_long q_ccnt; /* Quit or ZZ command count. */
|
||||
|
||||
/* Screen's: */
|
||||
size_t rows; /* 1-N: number of rows. */
|
||||
size_t cols; /* 1-N: number of columns. */
|
||||
size_t t_rows; /* 1-N: cur number of text rows. */
|
||||
size_t t_maxrows; /* 1-N: max number of text rows. */
|
||||
size_t t_minrows; /* 1-N: min number of text rows. */
|
||||
size_t coff; /* 0-N: screen col offset in display. */
|
||||
size_t roff; /* 0-N: screen row offset in display. */
|
||||
|
||||
/* Cursor's: */
|
||||
db_recno_t lno; /* 1-N: file line. */
|
||||
size_t cno; /* 0-N: file character in line. */
|
||||
|
||||
size_t rcm; /* Vi: 0-N: Most attractive column. */
|
||||
|
||||
#define L_ADDED 0 /* Added lines. */
|
||||
#define L_CHANGED 1 /* Changed lines. */
|
||||
#define L_DELETED 2 /* Deleted lines. */
|
||||
#define L_JOINED 3 /* Joined lines. */
|
||||
#define L_MOVED 4 /* Moved lines. */
|
||||
#define L_SHIFT 5 /* Shift lines. */
|
||||
#define L_YANKED 6 /* Yanked lines. */
|
||||
db_recno_t rptlchange; /* Ex/vi: last L_CHANGED lno. */
|
||||
db_recno_t rptlines[L_YANKED + 1];/* Ex/vi: lines changed by last op. */
|
||||
|
||||
TEXTH tiq; /* Ex/vi: text input queue. */
|
||||
|
||||
SCRIPT *script; /* Vi: script mode information .*/
|
||||
|
||||
db_recno_t defscroll; /* Vi: ^D, ^U scroll information. */
|
||||
|
||||
/* Display character. */
|
||||
u_char cname[MAX_CHARACTER_COLUMNS + 1];
|
||||
size_t clen; /* Length of display character. */
|
||||
|
||||
enum { /* Vi editor mode. */
|
||||
SM_APPEND = 0, SM_CHANGE, SM_COMMAND, SM_INSERT,
|
||||
SM_REPLACE } showmode;
|
||||
|
||||
void *ex_private; /* Ex private area. */
|
||||
void *vi_private; /* Vi private area. */
|
||||
void *perl_private; /* Perl private area. */
|
||||
void *cl_private; /* Curses private area. */
|
||||
|
||||
CONV conv;
|
||||
|
||||
struct _log_state state; /* State during log traversal. */
|
||||
|
||||
/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
|
||||
char *alt_name; /* Ex/vi: alternate file name. */
|
||||
|
||||
ARG_CHAR_T at_lbuf; /* Ex/vi: Last executed at buffer. */
|
||||
|
||||
/* Ex/vi: re_compile flags. */
|
||||
#define RE_WSTART L("[[:<:]]") /* Ex/vi: not-in-word search pattern. */
|
||||
#define RE_WSTOP L("[[:>:]]")
|
||||
#define RE_WSTART_LEN (sizeof(RE_WSTART)/sizeof(CHAR_T)-1)
|
||||
#define RE_WSTOP_LEN (sizeof(RE_WSTOP)/sizeof(CHAR_T)-1)
|
||||
/* Ex/vi: flags to search routines. */
|
||||
#define SEARCH_CSCOPE 0x000001 /* Search for a cscope pattern. */
|
||||
#define SEARCH_CSEARCH 0x000002 /* Compile search replacement. */
|
||||
#define SEARCH_CSUBST 0x000004 /* Compile substitute replacement. */
|
||||
#define SEARCH_EOL 0x000008 /* Offset past EOL is okay. */
|
||||
#define SEARCH_EXTEND 0x000010 /* Extended RE. */
|
||||
#define SEARCH_FIRST 0x000020 /* Search from the first line. */
|
||||
#define SEARCH_IC 0x000040 /* Ignore case. */
|
||||
#define SEARCH_ICL 0x000080 /* Ignore case. */
|
||||
#define SEARCH_INCR 0x000100 /* Search incrementally. */
|
||||
#define SEARCH_LITERAL 0x000200 /* Literal string. */
|
||||
#define SEARCH_MSG 0x000400 /* Display search messages. */
|
||||
#define SEARCH_NOOPT 0x000800 /* Ignore edit options. */
|
||||
#define SEARCH_PARSE 0x001000 /* Parse the search pattern. */
|
||||
#define SEARCH_SET 0x002000 /* Set search direction. */
|
||||
#define SEARCH_TAG 0x004000 /* Search for a tag pattern. */
|
||||
#define SEARCH_WMSG 0x008000 /* Display search-wrapped messages. */
|
||||
#define SEARCH_WRAP 0x010000 /* Wrap past sof/eof. */
|
||||
|
||||
/* Ex/vi: RE information. */
|
||||
dir_t searchdir; /* Last file search direction. */
|
||||
regex_t re_c; /* Search RE: compiled form. */
|
||||
CHAR_T *re; /* Search RE: uncompiled form. */
|
||||
size_t re_len; /* Search RE: uncompiled length. */
|
||||
regex_t subre_c; /* Substitute RE: compiled form. */
|
||||
CHAR_T *subre; /* Substitute RE: uncompiled form. */
|
||||
size_t subre_len; /* Substitute RE: uncompiled length). */
|
||||
CHAR_T *repl; /* Substitute replacement. */
|
||||
size_t repl_len; /* Substitute replacement length.*/
|
||||
size_t *newl; /* Newline offset array. */
|
||||
size_t newl_len; /* Newline array size. */
|
||||
size_t newl_cnt; /* Newlines in replacement. */
|
||||
u_int8_t c_suffix; /* Edcompatible 'c' suffix value. */
|
||||
u_int8_t g_suffix; /* Edcompatible 'g' suffix value. */
|
||||
|
||||
OPTION opts[O_OPTIONCOUNT]; /* Ex/vi: Options. */
|
||||
|
||||
/*
|
||||
* Screen flags.
|
||||
*
|
||||
* Editor screens.
|
||||
*/
|
||||
#define SC_EX 0x00000001 /* Ex editor. */
|
||||
#define SC_VI 0x00000002 /* Vi editor. */
|
||||
|
||||
/*
|
||||
* Screen formatting flags, first major, then minor.
|
||||
*
|
||||
* SC_SCR_EX
|
||||
* Ex screen, i.e. cooked mode.
|
||||
* SC_SCR_VI
|
||||
* Vi screen, i.e. raw mode.
|
||||
* SC_SCR_EXWROTE
|
||||
* The editor had to write on the screen behind curses' back, and we can't
|
||||
* let curses change anything until the user agrees, e.g. entering the
|
||||
* commands :!utility followed by :set. We have to switch back into the
|
||||
* vi "editor" to read the user's command input, but we can't touch the
|
||||
* rest of the screen because it's known to be wrong.
|
||||
* SC_SCR_REFORMAT
|
||||
* The expected presentation of the lines on the screen have changed,
|
||||
* requiring that the intended screen lines be recalculated. Implies
|
||||
* SC_SCR_REDRAW.
|
||||
* SC_SCR_REDRAW
|
||||
* The screen doesn't correctly represent the file; repaint it. Note,
|
||||
* setting SC_SCR_REDRAW in the current window causes *all* windows to
|
||||
* be repainted.
|
||||
* SC_SCR_CENTER
|
||||
* If the current line isn't already on the screen, center it.
|
||||
* SC_SCR_TOP
|
||||
* If the current line isn't already on the screen, put it at the to@.
|
||||
*/
|
||||
#define SC_SCR_EX 0x00000004 /* Screen is in ex mode. */
|
||||
#define SC_SCR_VI 0x00000008 /* Screen is in vi mode. */
|
||||
#define SC_SCR_EXWROTE 0x00000010 /* Ex overwrite: see comment above. */
|
||||
#define SC_SCR_REFORMAT 0x00000020 /* Reformat (refresh). */
|
||||
#define SC_SCR_REDRAW 0x00000040 /* Refresh. */
|
||||
|
||||
#define SC_SCR_CENTER 0x00000080 /* Center the line if not visible. */
|
||||
#define SC_SCR_TOP 0x00000100 /* Top the line if not visible. */
|
||||
|
||||
/* Screen/file changes. */
|
||||
#define SC_EXIT 0x00000200 /* Exiting (not forced). */
|
||||
#define SC_EXIT_FORCE 0x00000400 /* Exiting (forced). */
|
||||
#define SC_FSWITCH 0x00000800 /* Switch underlying files. */
|
||||
#define SC_SSWITCH 0x00001000 /* Switch screens. */
|
||||
|
||||
#define SC_ARGNOFREE 0x00002000 /* Argument list wasn't allocated. */
|
||||
#define SC_ARGRECOVER 0x00004000 /* Argument list is recovery files. */
|
||||
#define SC_AT_SET 0x00008000 /* Last at buffer set. */
|
||||
#define SC_COMEDIT 0x00010000 /* Colon command-line edit window. */
|
||||
#define SC_EX_GLOBAL 0x00020000 /* Ex: executing a global command. */
|
||||
#define SC_EX_SILENT 0x00040000 /* Ex: batch script. */
|
||||
#define SC_EX_WAIT_NO 0x00080000 /* Ex: don't wait for the user. */
|
||||
#define SC_EX_WAIT_YES 0x00100000 /* Ex: do wait for the user. */
|
||||
#define SC_READONLY 0x00200000 /* Persistent readonly state. */
|
||||
#define SC_RE_SEARCH 0x00400000 /* Search RE has been compiled. */
|
||||
#define SC_RE_SUBST 0x00800000 /* Substitute RE has been compiled. */
|
||||
#define SC_SCRIPT 0x01000000 /* Shell script window. */
|
||||
#define SC_STATUS 0x02000000 /* Welcome message. */
|
||||
#define SC_STATUS_CNT 0x04000000 /* Welcome message plus file count. */
|
||||
#define SC_TINPUT 0x08000000 /* Doing text input. */
|
||||
#define SC_TINPUT_INFO 0x10000000 /* Doing text input on info line. */
|
||||
#define SC_CONV_ERROR 0x20000000 /* Met with a conversion error. */
|
||||
u_int32_t flags;
|
||||
|
||||
int db_error; /* Return code from db function. */
|
||||
};
|
||||
482
dist/nvi/common/search.c
vendored
Normal file
482
dist/nvi/common/search.c
vendored
Normal file
@@ -0,0 +1,482 @@
|
||||
/* $NetBSD: search.c,v 1.3 2009/01/22 10:33:58 lukem 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: search.c,v 10.31 2001/06/25 15:19:12 skimo Exp (Berkeley) Date: 2001/06/25 15:19:12";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef enum { S_EMPTY, S_EOF, S_NOPREV, S_NOTFOUND, S_SOF, S_WRAP } smsg_t;
|
||||
|
||||
static void search_msg __P((SCR *, smsg_t));
|
||||
static int search_init __P((SCR *, dir_t, CHAR_T *, size_t, CHAR_T **, u_int));
|
||||
|
||||
/*
|
||||
* search_init --
|
||||
* Set up a search.
|
||||
*/
|
||||
static int
|
||||
search_init(SCR *sp, dir_t dir, CHAR_T *ptrn, size_t plen, CHAR_T **epp, u_int flags)
|
||||
{
|
||||
db_recno_t lno;
|
||||
int delim;
|
||||
CHAR_T *p, *t;
|
||||
|
||||
/* If the file is empty, it's a fast search. */
|
||||
if (sp->lno <= 1) {
|
||||
if (db_last(sp, &lno))
|
||||
return (1);
|
||||
if (lno == 0) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_msg(sp, S_EMPTY);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (LF_ISSET(SEARCH_PARSE)) { /* Parse the string. */
|
||||
/*
|
||||
* Use the saved pattern if no pattern specified, or if only
|
||||
* one or two delimiter characters specified.
|
||||
*
|
||||
* !!!
|
||||
* Historically, only the pattern itself was saved, vi didn't
|
||||
* preserve addressing or delta information.
|
||||
*/
|
||||
if (ptrn == NULL)
|
||||
goto prev;
|
||||
if (plen == 1) {
|
||||
if (epp != NULL)
|
||||
*epp = ptrn + 1;
|
||||
goto prev;
|
||||
}
|
||||
if (ptrn[0] == ptrn[1]) {
|
||||
if (epp != NULL)
|
||||
*epp = ptrn + 2;
|
||||
|
||||
/* Complain if we don't have a previous pattern. */
|
||||
prev: if (sp->re == NULL) {
|
||||
search_msg(sp, S_NOPREV);
|
||||
return (1);
|
||||
}
|
||||
/* Re-compile the search pattern if necessary. */
|
||||
if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp,
|
||||
sp->re, sp->re_len, NULL, NULL, &sp->re_c,
|
||||
SEARCH_CSEARCH | SEARCH_MSG))
|
||||
return (1);
|
||||
|
||||
/* Set the search direction. */
|
||||
if (LF_ISSET(SEARCH_SET))
|
||||
sp->searchdir = dir;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the delimiter, and move forward to the terminating
|
||||
* delimiter, handling escaped delimiters.
|
||||
*
|
||||
* QUOTING NOTE:
|
||||
* Only discard an escape character if it escapes a delimiter.
|
||||
*/
|
||||
for (delim = *ptrn, p = t = ++ptrn;; *t++ = *p++) {
|
||||
if (--plen == 0 || p[0] == delim) {
|
||||
if (plen != 0)
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
if (plen > 1 && p[0] == '\\' && p[1] == delim) {
|
||||
++p;
|
||||
--plen;
|
||||
}
|
||||
}
|
||||
if (epp != NULL)
|
||||
*epp = p;
|
||||
|
||||
plen = t - ptrn;
|
||||
}
|
||||
|
||||
/* Compile the RE. */
|
||||
if (re_compile(sp, ptrn, plen, &sp->re, &sp->re_len, &sp->re_c,
|
||||
SEARCH_CSEARCH | LF_ISSET(SEARCH_CSCOPE | SEARCH_IC |
|
||||
SEARCH_LITERAL | SEARCH_MSG | SEARCH_TAG)))
|
||||
return (1);
|
||||
|
||||
/* Set the search direction. */
|
||||
if (LF_ISSET(SEARCH_SET))
|
||||
sp->searchdir = dir;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* f_search --
|
||||
* Do a forward search.
|
||||
*
|
||||
* PUBLIC: int f_search __P((SCR *,
|
||||
* PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
|
||||
*/
|
||||
int
|
||||
f_search(SCR *sp, MARK *fm, MARK *rm, CHAR_T *ptrn, size_t plen, CHAR_T **eptrn, u_int flags)
|
||||
{
|
||||
busy_t btype;
|
||||
db_recno_t lno;
|
||||
regmatch_t match[1];
|
||||
size_t coff, len;
|
||||
int cnt, eval, rval, wrapped;
|
||||
CHAR_T *l;
|
||||
|
||||
if (search_init(sp, FORWARD, ptrn, plen, eptrn, flags))
|
||||
return (1);
|
||||
|
||||
/* Figure out if we're going to wrap. */
|
||||
if (!LF_ISSET(SEARCH_NOOPT) && O_ISSET(sp, O_WRAPSCAN))
|
||||
LF_SET(SEARCH_WRAP);
|
||||
|
||||
if (LF_ISSET(SEARCH_FIRST)) {
|
||||
lno = 1;
|
||||
coff = 0;
|
||||
} else {
|
||||
if (db_get(sp, fm->lno, DBG_FATAL, &l, &len))
|
||||
return (1);
|
||||
lno = fm->lno;
|
||||
|
||||
/*
|
||||
* If doing incremental search, start searching at the previous
|
||||
* column, so that we search a minimal distance and still match
|
||||
* special patterns, e.g., \< for beginning of a word.
|
||||
*
|
||||
* Otherwise, start searching immediately after the cursor. If
|
||||
* at the end of the line, start searching on the next line.
|
||||
* This is incompatible (read bug fix) with the historic vi --
|
||||
* searches for the '$' pattern never moved forward, and the
|
||||
* "-t foo" didn't work if the 'f' was the first character in
|
||||
* the file.
|
||||
*/
|
||||
if (LF_ISSET(SEARCH_INCR)) {
|
||||
if ((coff = fm->cno) != 0)
|
||||
--coff;
|
||||
} else if (fm->cno + 1 >= len) {
|
||||
coff = 0;
|
||||
lno = fm->lno + 1;
|
||||
if (db_get(sp, lno, 0, &l, &len)) {
|
||||
if (!LF_ISSET(SEARCH_WRAP)) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_msg(sp, S_EOF);
|
||||
return (1);
|
||||
}
|
||||
lno = 1;
|
||||
}
|
||||
} else
|
||||
coff = fm->cno + 1;
|
||||
}
|
||||
|
||||
btype = BUSY_ON;
|
||||
for (cnt = INTERRUPT_CHECK, rval = 1, wrapped = 0;; ++lno, coff = 0) {
|
||||
if (cnt-- == 0) {
|
||||
if (INTERRUPTED(sp))
|
||||
break;
|
||||
if (LF_ISSET(SEARCH_MSG)) {
|
||||
search_busy(sp, btype);
|
||||
btype = BUSY_UPDATE;
|
||||
}
|
||||
cnt = INTERRUPT_CHECK;
|
||||
}
|
||||
if ((wrapped && lno > fm->lno) ||
|
||||
db_get(sp, lno, 0, &l, &len)) {
|
||||
if (wrapped) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_msg(sp, S_NOTFOUND);
|
||||
break;
|
||||
}
|
||||
if (!LF_ISSET(SEARCH_WRAP)) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_msg(sp, S_EOF);
|
||||
break;
|
||||
}
|
||||
lno = 0;
|
||||
wrapped = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If already at EOL, just keep going. */
|
||||
if (len != 0 && coff == len)
|
||||
continue;
|
||||
|
||||
/* Set the termination. */
|
||||
match[0].rm_so = coff;
|
||||
match[0].rm_eo = len;
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "F search: %lu from %u to %u\n",
|
||||
lno, coff, len != 0 ? len - 1 : len);
|
||||
#endif
|
||||
/* Search the line. */
|
||||
eval = regexec(&sp->re_c, l, 1, match,
|
||||
(match[0].rm_so == 0 ? 0 : REG_NOTBOL) | REG_STARTEND);
|
||||
if (eval == REG_NOMATCH)
|
||||
continue;
|
||||
if (eval != 0) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
re_error(sp, eval, &sp->re_c);
|
||||
else
|
||||
(void)sp->gp->scr_bell(sp);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Warn if the search wrapped. */
|
||||
if (wrapped && LF_ISSET(SEARCH_WMSG))
|
||||
search_msg(sp, S_WRAP);
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "F search: %qu to %qu\n",
|
||||
match[0].rm_so, match[0].rm_eo);
|
||||
#endif
|
||||
rm->lno = lno;
|
||||
rm->cno = match[0].rm_so;
|
||||
|
||||
/*
|
||||
* If a change command, it's possible to move beyond the end
|
||||
* of a line. Historic vi generally got this wrong (e.g. try
|
||||
* "c?$<cr>"). Not all that sure this gets it right, there
|
||||
* are lots of strange cases.
|
||||
*/
|
||||
if (!LF_ISSET(SEARCH_EOL) && rm->cno >= len)
|
||||
rm->cno = len != 0 ? len - 1 : 0;
|
||||
|
||||
rval = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_busy(sp, BUSY_OFF);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* b_search --
|
||||
* Do a backward search.
|
||||
*
|
||||
* PUBLIC: int b_search __P((SCR *,
|
||||
* PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
|
||||
*/
|
||||
int
|
||||
b_search(SCR *sp, MARK *fm, MARK *rm, CHAR_T *ptrn, size_t plen, CHAR_T **eptrn, u_int flags)
|
||||
{
|
||||
busy_t btype;
|
||||
db_recno_t lno;
|
||||
regmatch_t match[1];
|
||||
size_t coff, last, len;
|
||||
int cnt, eval, rval, wrapped;
|
||||
CHAR_T *l;
|
||||
|
||||
if (search_init(sp, BACKWARD, ptrn, plen, eptrn, flags))
|
||||
return (1);
|
||||
|
||||
/* Figure out if we're going to wrap. */
|
||||
if (!LF_ISSET(SEARCH_NOOPT) && O_ISSET(sp, O_WRAPSCAN))
|
||||
LF_SET(SEARCH_WRAP);
|
||||
|
||||
/*
|
||||
* If doing incremental search, set the "starting" position past the
|
||||
* current column, so that we search a minimal distance and still
|
||||
* match special patterns, e.g., \> for the end of a word. This is
|
||||
* safe when the cursor is at the end of a line because we only use
|
||||
* it for comparison with the location of the match.
|
||||
*
|
||||
* Otherwise, start searching immediately before the cursor. If in
|
||||
* the first column, start search on the previous line.
|
||||
*/
|
||||
if (LF_ISSET(SEARCH_INCR)) {
|
||||
lno = fm->lno;
|
||||
coff = fm->cno + 1;
|
||||
} else {
|
||||
if (fm->cno == 0) {
|
||||
if (fm->lno == 1 && !LF_ISSET(SEARCH_WRAP)) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_msg(sp, S_SOF);
|
||||
return (1);
|
||||
}
|
||||
lno = fm->lno - 1;
|
||||
} else
|
||||
lno = fm->lno;
|
||||
coff = fm->cno;
|
||||
}
|
||||
|
||||
btype = BUSY_ON;
|
||||
for (cnt = INTERRUPT_CHECK, rval = 1, wrapped = 0;; --lno, coff = 0) {
|
||||
if (cnt-- == 0) {
|
||||
if (INTERRUPTED(sp))
|
||||
break;
|
||||
if (LF_ISSET(SEARCH_MSG)) {
|
||||
search_busy(sp, btype);
|
||||
btype = BUSY_UPDATE;
|
||||
}
|
||||
cnt = INTERRUPT_CHECK;
|
||||
}
|
||||
if ((wrapped && lno < fm->lno) || lno == 0) {
|
||||
if (wrapped) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_msg(sp, S_NOTFOUND);
|
||||
break;
|
||||
}
|
||||
if (!LF_ISSET(SEARCH_WRAP)) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_msg(sp, S_SOF);
|
||||
break;
|
||||
}
|
||||
if (db_last(sp, &lno))
|
||||
break;
|
||||
if (lno == 0) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
search_msg(sp, S_EMPTY);
|
||||
break;
|
||||
}
|
||||
++lno;
|
||||
wrapped = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (db_get(sp, lno, 0, &l, &len))
|
||||
break;
|
||||
|
||||
/* Set the termination. */
|
||||
match[0].rm_so = 0;
|
||||
match[0].rm_eo = len;
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp,
|
||||
"B search: %lu from 0 to %qu\n", lno, match[0].rm_eo);
|
||||
#endif
|
||||
/* Search the line. */
|
||||
eval = regexec(&sp->re_c, l, 1, match,
|
||||
((size_t)match[0].rm_eo == len ? 0 : REG_NOTEOL) | REG_STARTEND);
|
||||
if (eval == REG_NOMATCH)
|
||||
continue;
|
||||
if (eval != 0) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
re_error(sp, eval, &sp->re_c);
|
||||
else
|
||||
(void)sp->gp->scr_bell(sp);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for a match starting past the cursor. */
|
||||
if (coff != 0 && (size_t)match[0].rm_so >= coff)
|
||||
continue;
|
||||
|
||||
/* Warn if the search wrapped. */
|
||||
if (wrapped && LF_ISSET(SEARCH_WMSG))
|
||||
search_msg(sp, S_WRAP);
|
||||
|
||||
#if defined(DEBUG) && 0
|
||||
vtrace(sp, "B found: %qu to %qu\n",
|
||||
match[0].rm_so, match[0].rm_eo);
|
||||
#endif
|
||||
/*
|
||||
* We now have the first match on the line. Step through the
|
||||
* line character by character until find the last acceptable
|
||||
* match. This is painful, we need a better interface to regex
|
||||
* to make this work.
|
||||
*/
|
||||
for (;;) {
|
||||
last = match[0].rm_so++;
|
||||
if ((size_t)match[0].rm_so >= len)
|
||||
break;
|
||||
match[0].rm_eo = len;
|
||||
eval = regexec(&sp->re_c, l, 1, match,
|
||||
(match[0].rm_so == 0 ? 0 : REG_NOTBOL) |
|
||||
REG_STARTEND);
|
||||
if (eval == REG_NOMATCH)
|
||||
break;
|
||||
if (eval != 0) {
|
||||
if (LF_ISSET(SEARCH_MSG))
|
||||
re_error(sp, eval, &sp->re_c);
|
||||
else
|
||||
(void)sp->gp->scr_bell(sp);
|
||||
goto err;
|
||||
}
|
||||
if (coff && (size_t)match[0].rm_so >= coff)
|
||||
break;
|
||||
}
|
||||
rm->lno = lno;
|
||||
|
||||
/* See comment in f_search(). */
|
||||
if (!LF_ISSET(SEARCH_EOL) && last >= len)
|
||||
rm->cno = len != 0 ? len - 1 : 0;
|
||||
else
|
||||
rm->cno = last;
|
||||
rval = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
err: if (LF_ISSET(SEARCH_MSG))
|
||||
search_busy(sp, BUSY_OFF);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* search_msg --
|
||||
* Display one of the search messages.
|
||||
*/
|
||||
static void
|
||||
search_msg(SCR *sp, smsg_t msg)
|
||||
{
|
||||
switch (msg) {
|
||||
case S_EMPTY:
|
||||
msgq(sp, M_ERR, "072|File empty; nothing to search");
|
||||
break;
|
||||
case S_EOF:
|
||||
msgq(sp, M_ERR,
|
||||
"073|Reached end-of-file without finding the pattern");
|
||||
break;
|
||||
case S_NOPREV:
|
||||
msgq(sp, M_ERR, "074|No previous search pattern");
|
||||
break;
|
||||
case S_NOTFOUND:
|
||||
msgq(sp, M_ERR, "075|Pattern not found");
|
||||
break;
|
||||
case S_SOF:
|
||||
msgq(sp, M_ERR,
|
||||
"076|Reached top-of-file without finding the pattern");
|
||||
break;
|
||||
case S_WRAP:
|
||||
msgq(sp, M_ERR, "077|Search wrapped");
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* search_busy --
|
||||
* Put up the busy searching message.
|
||||
*
|
||||
* PUBLIC: void search_busy __P((SCR *, busy_t));
|
||||
*/
|
||||
void
|
||||
search_busy(SCR *sp, busy_t btype)
|
||||
{
|
||||
sp->gp->scr_busy(sp, "078|Searching...", btype);
|
||||
}
|
||||
369
dist/nvi/common/seq.c
vendored
Normal file
369
dist/nvi/common/seq.c
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
/* $NetBSD: seq.c,v 1.3 2011/03/21 14:53:02 tnozaki 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: seq.c,v 10.15 2001/06/25 15:19:12 skimo Exp (Berkeley) Date: 2001/06/25 15:19:12";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* seq_set --
|
||||
* Internal version to enter a sequence.
|
||||
*
|
||||
* PUBLIC: int seq_set __P((SCR *, CHAR_T *,
|
||||
* PUBLIC: size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int));
|
||||
*/
|
||||
int
|
||||
seq_set(SCR *sp, CHAR_T *name, size_t nlen, CHAR_T *input, size_t ilen, CHAR_T *output, size_t olen, seq_t stype, int flags)
|
||||
{
|
||||
CHAR_T *p;
|
||||
SEQ *lastqp, *qp;
|
||||
int sv_errno;
|
||||
|
||||
/*
|
||||
* An input string must always be present. The output string
|
||||
* can be NULL, when set internally, that's how we throw away
|
||||
* input.
|
||||
*
|
||||
* Just replace the output field if the string already set.
|
||||
*/
|
||||
if ((qp =
|
||||
seq_find(sp, &lastqp, NULL, input, ilen, stype, NULL)) != NULL) {
|
||||
if (LF_ISSET(SEQ_NOOVERWRITE))
|
||||
return (0);
|
||||
if (output == NULL || olen == 0) {
|
||||
p = NULL;
|
||||
olen = 0;
|
||||
} else if ((p = v_wstrdup(sp, output, olen)) == NULL) {
|
||||
sv_errno = errno;
|
||||
goto mem1;
|
||||
}
|
||||
if (qp->output != NULL)
|
||||
free(qp->output);
|
||||
qp->olen = olen;
|
||||
qp->output = p;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Allocate and initialize SEQ structure. */
|
||||
CALLOC(sp, qp, SEQ *, 1, sizeof(SEQ));
|
||||
if (qp == NULL) {
|
||||
sv_errno = errno;
|
||||
goto mem1;
|
||||
}
|
||||
|
||||
/* Name. */
|
||||
if (name == NULL || nlen == 0)
|
||||
qp->name = NULL;
|
||||
else if ((qp->name = v_wstrdup(sp, name, nlen)) == NULL) {
|
||||
sv_errno = errno;
|
||||
goto mem2;
|
||||
}
|
||||
qp->nlen = nlen;
|
||||
|
||||
/* Input. */
|
||||
if ((qp->input = v_wstrdup(sp, input, ilen)) == NULL) {
|
||||
sv_errno = errno;
|
||||
goto mem3;
|
||||
}
|
||||
qp->ilen = ilen;
|
||||
|
||||
/* Output. */
|
||||
if (output == NULL) {
|
||||
qp->output = NULL;
|
||||
olen = 0;
|
||||
} else if ((qp->output = v_wstrdup(sp, output, olen)) == NULL) {
|
||||
sv_errno = errno;
|
||||
free(qp->input);
|
||||
mem3: if (qp->name != NULL)
|
||||
free(qp->name);
|
||||
mem2: free(qp);
|
||||
mem1: errno = sv_errno;
|
||||
msgq(sp, M_SYSERR, NULL);
|
||||
return (1);
|
||||
}
|
||||
qp->olen = olen;
|
||||
|
||||
/* Type, flags. */
|
||||
qp->stype = stype;
|
||||
qp->flags = flags;
|
||||
|
||||
/* Link into the chain. */
|
||||
if (lastqp == NULL) {
|
||||
LIST_INSERT_HEAD(&sp->gp->seqq, qp, q);
|
||||
} else {
|
||||
LIST_INSERT_AFTER(lastqp, qp, q);
|
||||
}
|
||||
|
||||
/* Set the fast lookup bit. */
|
||||
if ((qp->input[0] & ~MAX_BIT_SEQ) == 0)
|
||||
bit_set(sp->gp->seqb, qp->input[0]);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_delete --
|
||||
* Delete a sequence.
|
||||
*
|
||||
* PUBLIC: int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t));
|
||||
*/
|
||||
int
|
||||
seq_delete(SCR *sp, CHAR_T *input, size_t ilen, seq_t stype)
|
||||
{
|
||||
SEQ *qp;
|
||||
|
||||
if ((qp = seq_find(sp, NULL, NULL, input, ilen, stype, NULL)) == NULL)
|
||||
return (1);
|
||||
return (seq_mdel(qp));
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_mdel --
|
||||
* Delete a map entry, without lookup.
|
||||
*
|
||||
* PUBLIC: int seq_mdel __P((SEQ *));
|
||||
*/
|
||||
int
|
||||
seq_mdel(SEQ *qp)
|
||||
{
|
||||
LIST_REMOVE(qp, q);
|
||||
if (qp->name != NULL)
|
||||
free(qp->name);
|
||||
free(qp->input);
|
||||
if (qp->output != NULL)
|
||||
free(qp->output);
|
||||
free(qp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_find --
|
||||
* Search the sequence list for a match to a buffer, if ispartial
|
||||
* isn't NULL, partial matches count.
|
||||
*
|
||||
* PUBLIC: SEQ *seq_find
|
||||
* PUBLIC: __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *));
|
||||
*/
|
||||
SEQ *
|
||||
seq_find(SCR *sp, SEQ **lastqp, EVENT *e_input, CHAR_T *c_input, size_t ilen, seq_t stype, int *ispartialp)
|
||||
{
|
||||
SEQ *lqp, *qp;
|
||||
int diff;
|
||||
|
||||
/*
|
||||
* Ispartialp is a location where we return if there was a
|
||||
* partial match, i.e. if the string were extended it might
|
||||
* match something.
|
||||
*
|
||||
* XXX
|
||||
* Overload the meaning of ispartialp; only the terminal key
|
||||
* search doesn't want the search limited to complete matches,
|
||||
* i.e. ilen may be longer than the match.
|
||||
*/
|
||||
if (ispartialp != NULL)
|
||||
*ispartialp = 0;
|
||||
for (lqp = NULL, qp = sp->gp->seqq.lh_first;
|
||||
qp != NULL; lqp = qp, qp = qp->q.le_next) {
|
||||
/*
|
||||
* Fast checks on the first character and type, and then
|
||||
* a real comparison.
|
||||
*/
|
||||
if (e_input == NULL) {
|
||||
if (qp->input[0] > c_input[0])
|
||||
break;
|
||||
if (qp->input[0] < c_input[0] ||
|
||||
qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
|
||||
continue;
|
||||
diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen));
|
||||
} else {
|
||||
if (qp->input[0] > e_input->e_c)
|
||||
break;
|
||||
if (qp->input[0] < e_input->e_c ||
|
||||
qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
|
||||
continue;
|
||||
diff =
|
||||
e_memcmp(qp->input, e_input, MIN(qp->ilen, ilen));
|
||||
}
|
||||
if (diff > 0)
|
||||
break;
|
||||
if (diff < 0)
|
||||
continue;
|
||||
/*
|
||||
* If the entry is the same length as the string, return a
|
||||
* match. If the entry is shorter than the string, return a
|
||||
* match if called from the terminal key routine. Otherwise,
|
||||
* keep searching for a complete match.
|
||||
*/
|
||||
if (qp->ilen <= ilen) {
|
||||
if (qp->ilen == ilen || ispartialp != NULL) {
|
||||
if (lastqp != NULL)
|
||||
*lastqp = lqp;
|
||||
return (qp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* If the entry longer than the string, return partial match
|
||||
* if called from the terminal key routine. Otherwise, no
|
||||
* match.
|
||||
*/
|
||||
if (ispartialp != NULL)
|
||||
*ispartialp = 1;
|
||||
break;
|
||||
}
|
||||
if (lastqp != NULL)
|
||||
*lastqp = lqp;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_close --
|
||||
* Discard all sequences.
|
||||
*
|
||||
* PUBLIC: void seq_close __P((GS *));
|
||||
*/
|
||||
void
|
||||
seq_close(GS *gp)
|
||||
{
|
||||
SEQ *qp;
|
||||
|
||||
while ((qp = gp->seqq.lh_first) != NULL) {
|
||||
if (qp->name != NULL)
|
||||
free(qp->name);
|
||||
if (qp->input != NULL)
|
||||
free(qp->input);
|
||||
if (qp->output != NULL)
|
||||
free(qp->output);
|
||||
LIST_REMOVE(qp, q);
|
||||
free(qp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_dump --
|
||||
* Display the sequence entries of a specified type.
|
||||
*
|
||||
* PUBLIC: int seq_dump __P((SCR *, seq_t, int));
|
||||
*/
|
||||
int
|
||||
seq_dump(SCR *sp, seq_t stype, int isname)
|
||||
{
|
||||
CHAR_T *p;
|
||||
GS *gp;
|
||||
SEQ *qp;
|
||||
int cnt, len, olen;
|
||||
|
||||
cnt = 0;
|
||||
gp = sp->gp;
|
||||
for (qp = gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
|
||||
if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP))
|
||||
continue;
|
||||
++cnt;
|
||||
for (p = qp->input,
|
||||
olen = qp->ilen, len = 0; olen > 0; --olen, ++p)
|
||||
len += ex_puts(sp, (char *)KEY_NAME(sp, *p));
|
||||
for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
|
||||
len -= ex_puts(sp, " ");
|
||||
|
||||
if (qp->output != NULL)
|
||||
for (p = qp->output,
|
||||
olen = qp->olen, len = 0; olen > 0; --olen, ++p)
|
||||
len += ex_puts(sp, (char *)KEY_NAME(sp, *p));
|
||||
else
|
||||
len = 0;
|
||||
|
||||
if (isname && qp->name != NULL) {
|
||||
for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
|
||||
len -= ex_puts(sp, " ");
|
||||
for (p = qp->name,
|
||||
olen = qp->nlen; olen > 0; --olen, ++p)
|
||||
(void)ex_puts(sp, (char *)KEY_NAME(sp, *p));
|
||||
}
|
||||
(void)ex_puts(sp, "\n");
|
||||
}
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_save --
|
||||
* Save the sequence entries to a file.
|
||||
*
|
||||
* PUBLIC: int seq_save __P((SCR *, FILE *, char *, seq_t));
|
||||
*/
|
||||
int
|
||||
seq_save(SCR *sp, FILE *fp, const char *prefix, seq_t stype)
|
||||
{
|
||||
CHAR_T *p;
|
||||
SEQ *qp;
|
||||
size_t olen;
|
||||
ARG_CHAR_T ch;
|
||||
|
||||
/* Write a sequence command for all keys the user defined. */
|
||||
for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
|
||||
if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF))
|
||||
continue;
|
||||
if (prefix)
|
||||
(void)fprintf(fp, "%s", prefix);
|
||||
for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
|
||||
ch = (UCHAR_T)*p++;
|
||||
if (ch == CH_LITERAL || ch == '|' ||
|
||||
ISBLANK(ch) || KEY_VAL(sp, ch) == K_NL)
|
||||
(void)putc(CH_LITERAL, fp);
|
||||
(void)fprintf(fp, WC, ch);
|
||||
}
|
||||
(void)putc(' ', fp);
|
||||
if (qp->output != NULL)
|
||||
for (p = qp->output,
|
||||
olen = qp->olen; olen > 0; --olen) {
|
||||
ch = (UCHAR_T)*p++;
|
||||
if (ch == CH_LITERAL || ch == '|' ||
|
||||
KEY_VAL(sp, ch) == K_NL)
|
||||
(void)putc(CH_LITERAL, fp);
|
||||
(void)fprintf(fp, WC, ch);
|
||||
}
|
||||
(void)putc('\n', fp);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* e_memcmp --
|
||||
* Compare a string of EVENT's to a string of CHAR_T's.
|
||||
*
|
||||
* PUBLIC: int e_memcmp __P((CHAR_T *, EVENT *, size_t));
|
||||
*/
|
||||
int
|
||||
e_memcmp(CHAR_T *p1, EVENT *ep, size_t n)
|
||||
{
|
||||
if (n != 0) {
|
||||
do {
|
||||
if (*p1++ != ep->e_c)
|
||||
return (*--p1 - ep->e_c);
|
||||
++ep;
|
||||
} while (--n != 0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
46
dist/nvi/common/seq.h
vendored
Normal file
46
dist/nvi/common/seq.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/* $NetBSD: seq.h,v 1.1.1.2 2008/05/18 14:29:52 aymeric 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.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*
|
||||
* Id: seq.h,v 10.3 1996/03/06 19:51:03 bostic Exp (Berkeley) Date: 1996/03/06 19:51:03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Map and abbreviation structures.
|
||||
*
|
||||
* The map structure is doubly linked list, sorted by input string and by
|
||||
* input length within the string. (The latter is necessary so that short
|
||||
* matches will happen before long matches when the list is searched.)
|
||||
* Additionally, there is a bitmap which has bits set if there are entries
|
||||
* starting with the corresponding character. This keeps us from walking
|
||||
* the list unless it's necessary.
|
||||
*
|
||||
* The name and the output fields of a SEQ can be empty, i.e. NULL.
|
||||
* Only the input field is required.
|
||||
*
|
||||
* XXX
|
||||
* The fast-lookup bits are never turned off -- users don't usually unmap
|
||||
* things, though, so it's probably not a big deal.
|
||||
*/
|
||||
struct _seq {
|
||||
LIST_ENTRY(_seq) q; /* Linked list of all sequences. */
|
||||
seq_t stype; /* Sequence type. */
|
||||
CHAR_T *name; /* Sequence name (if any). */
|
||||
size_t nlen; /* Name length. */
|
||||
CHAR_T *input; /* Sequence input keys. */
|
||||
size_t ilen; /* Input keys length. */
|
||||
CHAR_T *output; /* Sequence output keys. */
|
||||
size_t olen; /* Output keys length. */
|
||||
|
||||
#define SEQ_FUNCMAP 0x01 /* If unresolved function key.*/
|
||||
#define SEQ_NOOVERWRITE 0x02 /* Don't replace existing entry. */
|
||||
#define SEQ_SCREEN 0x04 /* If screen specific. */
|
||||
#define SEQ_USERDEF 0x08 /* If user defined. */
|
||||
u_int8_t flags;
|
||||
};
|
||||
93
dist/nvi/common/trace.c
vendored
Normal file
93
dist/nvi/common/trace.c
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/* $NetBSD: trace.c,v 1.1.1.2 2008/05/18 14:29:52 aymeric Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996
|
||||
* Rob Zimmermann. All rights reserved.
|
||||
* Copyright (c) 1996
|
||||
* Keith Bostic. All rights reserved.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: trace.c,v 8.4 1997/08/03 15:04:23 bostic Exp (Berkeley) Date: 1997/08/03 15:04:23";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef TRACE
|
||||
|
||||
static FILE *tfp;
|
||||
|
||||
/*
|
||||
* vtrace_end --
|
||||
* End tracing.
|
||||
*
|
||||
* PUBLIC: void vtrace_end __P((void));
|
||||
*/
|
||||
void
|
||||
vtrace_end()
|
||||
{
|
||||
if (tfp != NULL && tfp != stderr)
|
||||
(void)fclose(tfp);
|
||||
}
|
||||
|
||||
/*
|
||||
* vtrace_init --
|
||||
* Initialize tracing.
|
||||
*
|
||||
* PUBLIC: void vtrace_init __P((char *));
|
||||
*/
|
||||
void
|
||||
vtrace_init(name)
|
||||
char *name;
|
||||
{
|
||||
if (name == NULL || (tfp = fopen(name, "w")) == NULL)
|
||||
tfp = stderr;
|
||||
vtrace("\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\nTRACE\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* vtrace --
|
||||
* Debugging trace routine.
|
||||
*
|
||||
* PUBLIC: void vtrace __P((const char *, ...));
|
||||
*/
|
||||
void
|
||||
#ifdef __STDC__
|
||||
vtrace(const char *fmt, ...)
|
||||
#else
|
||||
vtrace(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (tfp == NULL)
|
||||
vtrace_init(NULL);
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void)vfprintf(tfp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
(void)fflush(tfp);
|
||||
}
|
||||
#endif
|
||||
196
dist/nvi/common/util.c
vendored
Normal file
196
dist/nvi/common/util.c
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
/* $NetBSD: util.c,v 1.4 2011/03/21 14:53:02 tnozaki 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "Id: util.c,v 10.22 2001/06/25 15:19:12 skimo Exp (Berkeley) Date: 2001/06/25 15:19:12";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* binc --
|
||||
* Increase the size of a buffer.
|
||||
*
|
||||
* PUBLIC: void *binc __P((SCR *, void *, size_t *, size_t));
|
||||
*/
|
||||
void *
|
||||
binc(SCR *sp, void *bp, size_t *bsizep, size_t min)
|
||||
/* sp MAY BE NULL!!! */
|
||||
|
||||
|
||||
{
|
||||
size_t csize;
|
||||
|
||||
/* If already larger than the minimum, just return. */
|
||||
if (min && *bsizep >= min)
|
||||
return (bp);
|
||||
|
||||
csize = *bsizep + MAX(min, 256);
|
||||
REALLOC(sp, bp, void *, csize);
|
||||
|
||||
if (bp == NULL) {
|
||||
/*
|
||||
* Theoretically, realloc is supposed to leave any already
|
||||
* held memory alone if it can't get more. Don't trust it.
|
||||
*/
|
||||
*bsizep = 0;
|
||||
return (NULL);
|
||||
}
|
||||
/*
|
||||
* Memory is guaranteed to be zero-filled, various parts of
|
||||
* nvi depend on this.
|
||||
*/
|
||||
memset((char *)bp + *bsizep, 0, csize - *bsizep);
|
||||
*bsizep = csize;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
/*
|
||||
* nonblank --
|
||||
* Set the column number of the first non-blank character
|
||||
* including or after the starting column. On error, set
|
||||
* the column to 0, it's safest.
|
||||
*
|
||||
* PUBLIC: int nonblank __P((SCR *, db_recno_t, size_t *));
|
||||
*/
|
||||
int
|
||||
nonblank(SCR *sp, db_recno_t lno, size_t *cnop)
|
||||
{
|
||||
CHAR_T *p;
|
||||
size_t cnt, len, off;
|
||||
int isempty;
|
||||
|
||||
/* Default. */
|
||||
off = *cnop;
|
||||
*cnop = 0;
|
||||
|
||||
/* Get the line, succeeding in an empty file. */
|
||||
if (db_eget(sp, lno, &p, &len, &isempty))
|
||||
return (!isempty);
|
||||
|
||||
/* Set the offset. */
|
||||
if (len == 0 || off >= len)
|
||||
return (0);
|
||||
|
||||
for (cnt = off, p = &p[off],
|
||||
len -= off; len && ISBLANK((UCHAR_T)*p); ++cnt, ++p, --len);
|
||||
|
||||
/* Set the return. */
|
||||
*cnop = len ? cnt : cnt - 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* tail --
|
||||
* Return tail of a path.
|
||||
*
|
||||
* PUBLIC: char *tail __P((char *));
|
||||
*/
|
||||
const char *
|
||||
tail(const char *path)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if ((p = strrchr(path, '/')) == NULL)
|
||||
return (path);
|
||||
return (p + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_strdup --
|
||||
* Strdup for wide character strings with an associated length.
|
||||
*
|
||||
* PUBLIC: char *v_strdup __P((SCR *, const char *, size_t));
|
||||
*/
|
||||
char *
|
||||
v_strdup(SCR *sp, const char *str, size_t len)
|
||||
{
|
||||
char *copy;
|
||||
|
||||
MALLOC(sp, copy, char *, (len + 1));
|
||||
if (copy == NULL)
|
||||
return (NULL);
|
||||
memcpy(copy, str, len);
|
||||
copy[len] = '\0';
|
||||
return (copy);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_strdup --
|
||||
* Strdup for wide character strings with an associated length.
|
||||
*
|
||||
* PUBLIC: CHAR_T *v_wstrdup __P((SCR *, const CHAR_T *, size_t));
|
||||
*/
|
||||
CHAR_T *
|
||||
v_wstrdup(SCR *sp, const CHAR_T *str, size_t len)
|
||||
{
|
||||
CHAR_T *copy;
|
||||
|
||||
MALLOC(sp, copy, CHAR_T *, (len + 1) * sizeof(CHAR_T));
|
||||
if (copy == NULL)
|
||||
return (NULL);
|
||||
MEMCPYW(copy, str, len);
|
||||
copy[len] = '\0';
|
||||
return (copy);
|
||||
}
|
||||
|
||||
/*
|
||||
* nget_uslong --
|
||||
* Get an unsigned long, checking for overflow.
|
||||
*
|
||||
* PUBLIC: enum nresult nget_uslong __P((SCR *, u_long *, const CHAR_T *, CHAR_T **, int));
|
||||
*/
|
||||
enum nresult
|
||||
nget_uslong(SCR *sp, u_long *valp, const CHAR_T *p, CHAR_T **endp, int base)
|
||||
{
|
||||
errno = 0;
|
||||
*valp = STRTOUL(p, (RCHAR_T **)endp, base);
|
||||
if (errno == 0)
|
||||
return (NUM_OK);
|
||||
if (errno == ERANGE && *valp == ULONG_MAX)
|
||||
return (NUM_OVER);
|
||||
return (NUM_ERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* nget_slong --
|
||||
* Convert a signed long, checking for overflow and underflow.
|
||||
*
|
||||
* PUBLIC: enum nresult nget_slong __P((SCR *, long *, const CHAR_T *, CHAR_T **, int));
|
||||
*/
|
||||
enum nresult
|
||||
nget_slong(SCR *sp, long int *valp, const CHAR_T *p, CHAR_T **endp, int base)
|
||||
{
|
||||
errno = 0;
|
||||
*valp = STRTOL(p, (RCHAR_T **)endp, base);
|
||||
if (errno == 0)
|
||||
return (NUM_OK);
|
||||
if (errno == ERANGE) {
|
||||
if (*valp == LONG_MAX)
|
||||
return (NUM_OVER);
|
||||
if (*valp == LONG_MIN)
|
||||
return (NUM_UNDER);
|
||||
}
|
||||
return (NUM_ERR);
|
||||
}
|
||||
59
dist/nvi/common/util.h
vendored
Normal file
59
dist/nvi/common/util.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/* $NetBSD: util.h,v 1.2 2009/01/18 03:43:45 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 1994, 1995, 1996
|
||||
* Keith Bostic. All rights reserved.
|
||||
*
|
||||
* See the LICENSE file for redistribution information.
|
||||
*
|
||||
* Id: util.h,v 10.5 1996/03/16 14:42:47 bostic Exp (Berkeley) Date: 1996/03/16 14:42:47
|
||||
*/
|
||||
|
||||
/* Macros to init/set/clear/test flags. */
|
||||
#define FL_INIT(l, f) (l) = (f) /* Specific flags location. */
|
||||
#define FL_SET(l, f) ((l) |= (f))
|
||||
#define FL_CLR(l, f) ((l) &= ~(f))
|
||||
#define FL_ISSET(l, f) ((l) & (f))
|
||||
|
||||
#define LF_INIT(f) FL_INIT(flags, f) /* Local variable flags. */
|
||||
#define LF_SET(f) FL_SET(flags, f)
|
||||
#define LF_CLR(f) FL_CLR(flags, f)
|
||||
#define LF_ISSET(f) FL_ISSET(flags, f)
|
||||
|
||||
#define F_INIT(p, f) FL_INIT((p)->flags, f) /* Structure element flags. */
|
||||
#define F_SET(p, f) FL_SET((p)->flags, f)
|
||||
#define F_CLR(p, f) FL_CLR((p)->flags, f)
|
||||
#define F_ISSET(p, f) FL_ISSET((p)->flags, f)
|
||||
|
||||
/* Offset to next column of stop size, e.g. tab offsets. */
|
||||
#define COL_OFF(c, stop) ((stop) - ((c) % (stop)))
|
||||
|
||||
/* Busy message types. */
|
||||
typedef enum { B_NONE, B_OFF, B_READ, B_RECOVER, B_SEARCH, B_WRITE } bmsg_t;
|
||||
|
||||
/*
|
||||
* Number handling defines and protoypes.
|
||||
*
|
||||
* NNFITS: test for addition of two negative numbers under a limit
|
||||
* NPFITS: test for addition of two positive numbers under a limit
|
||||
* NADD_SLONG: test for addition of two signed longs
|
||||
* NADD_USLONG: test for addition of two unsigned longs
|
||||
*/
|
||||
enum nresult { NUM_ERR, NUM_OK, NUM_OVER, NUM_UNDER };
|
||||
#define NNFITS(min, cur, add) \
|
||||
(((long)(min)) - (cur) <= (add))
|
||||
#define NPFITS(max, cur, add) \
|
||||
(((unsigned long)(max)) - (cur) >= (add))
|
||||
#define NADD_SLONG(sp, v1, v2) \
|
||||
((v1) < 0 ? \
|
||||
((v2) < 0 && \
|
||||
NNFITS(LONG_MIN, (v1), (v2))) ? NUM_UNDER : NUM_OK : \
|
||||
(v1) > 0 ? \
|
||||
(v2) > 0 && \
|
||||
NPFITS(LONG_MAX, (unsigned long)(v1), (unsigned long)(v2)) ? \
|
||||
NUM_OK : NUM_OVER : \
|
||||
NUM_OK)
|
||||
#define NADD_USLONG(sp, v1, v2) \
|
||||
(NPFITS(ULONG_MAX, (v1), (v2)) ? NUM_OK : NUM_OVER)
|
||||
38
dist/nvi/common/util2.c
vendored
Normal file
38
dist/nvi/common/util2.c
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/* $NetBSD: util2.c,v 1.1.1.2 2008/05/18 14:29:52 aymeric Exp $ */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "multibyte.h"
|
||||
|
||||
int
|
||||
ucs2utf8(const CHAR_T *src, size_t len, char *dst)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0, j = 0; i < len; ++i) {
|
||||
if (src[i] < 0x80)
|
||||
dst[j++] = src[i];
|
||||
else if (src[i] < 0x800) {
|
||||
dst[j++] = (src[i] >> 6) | 0xc0;
|
||||
dst[j++] = (src[i] & 0x3f) | 0x80;
|
||||
} else {
|
||||
dst[j++] = (src[i] >> 12) | 0xe0;
|
||||
dst[j++] = ((src[i] >> 6) & 0x3f) | 0x80;
|
||||
dst[j++] = (src[i] & 0x3f) | 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
37
dist/nvi/common/vi.src
vendored
Normal file
37
dist/nvi/common/vi.src
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
PREFIX vi
|
||||
|
||||
INCLUDE #include <sys/types.h>
|
||||
INCLUDE #include <sys/queue.h>
|
||||
INCLUDE #include <sys/stat.h>
|
||||
INCLUDE #include <bitstring.h>
|
||||
INCLUDE #include <errno.h>
|
||||
INCLUDE #include <fcntl.h>
|
||||
INCLUDE #include <limits.h>
|
||||
INCLUDE #include <stdio.h>
|
||||
INCLUDE #include <stdlib.h>
|
||||
INCLUDE #include <string.h>
|
||||
INCLUDE #include "common.h"
|
||||
INCLUDE #include <db_int.h>
|
||||
INCLUDE #include "db_page.h"
|
||||
INCLUDE #include "db_am.h"
|
||||
INCLUDE #include "rep.h"
|
||||
INCLUDE #include "txn.h"
|
||||
|
||||
BEGIN marker 200
|
||||
ARG opcode u_int32_t lu
|
||||
END
|
||||
|
||||
BEGIN cursor 201
|
||||
ARG opcode u_int32_t lu
|
||||
ARG lno db_recno_t lu
|
||||
ARG cno size_t d
|
||||
END
|
||||
|
||||
BEGIN mark 202
|
||||
POINTER lmp LMARK * %
|
||||
END
|
||||
|
||||
BEGIN change 203
|
||||
ARG opcode u_int32_t lu
|
||||
ARG lno db_recno_t lu
|
||||
END
|
||||
810
dist/nvi/common/vi_auto.c
vendored
Normal file
810
dist/nvi/common/vi_auto.c
vendored
Normal file
@@ -0,0 +1,810 @@
|
||||
/* $NetBSD: vi_auto.c,v 1.1.1.2 2008/05/18 14:29:53 aymeric Exp $ */
|
||||
|
||||
/* Do not edit: automatically built by gen_rec.awk. */
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
#include <bitstring.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include <db_int.h>
|
||||
#include "db_page.h"
|
||||
#include "db_am.h"
|
||||
#include "rep.h"
|
||||
#include "txn.h"
|
||||
/*
|
||||
* PUBLIC: #ifdef USE_DB4_LOGGING
|
||||
*/
|
||||
/*
|
||||
* PUBLIC: int __vi_marker_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
* PUBLIC: u_int32_t));
|
||||
*/
|
||||
int
|
||||
__vi_marker_log(dbenv, txnid, ret_lsnp, flags,
|
||||
opcode)
|
||||
DB_ENV *dbenv;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN *ret_lsnp;
|
||||
u_int32_t flags;
|
||||
u_int32_t opcode;
|
||||
{
|
||||
DBT logrec;
|
||||
DB_LSN *lsnp, null_lsn;
|
||||
u_int32_t uinttmp;
|
||||
u_int32_t rectype, txn_num;
|
||||
int ret;
|
||||
u_int8_t *bp;
|
||||
|
||||
rectype = DB_vi_marker;
|
||||
if (txnid != NULL &&
|
||||
TAILQ_FIRST(&txnid->kids) != NULL &&
|
||||
(ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
|
||||
return (ret);
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
|
||||
+ sizeof(u_int32_t);
|
||||
if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
bp += sizeof(rectype);
|
||||
|
||||
memcpy(bp, &txn_num, sizeof(txn_num));
|
||||
bp += sizeof(txn_num);
|
||||
|
||||
memcpy(bp, lsnp, sizeof(DB_LSN));
|
||||
bp += sizeof(DB_LSN);
|
||||
|
||||
uinttmp = (u_int32_t)opcode;
|
||||
memcpy(bp, &uinttmp, sizeof(uinttmp));
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
|
||||
ret = dbenv->log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL && ret == 0)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
#ifdef LOG_DIAGNOSTIC
|
||||
if (ret != 0)
|
||||
(void)__vi_marker_print(dbenv,
|
||||
(DBT *)&logrec, ret_lsnp, NULL, NULL);
|
||||
#endif
|
||||
__os_free(dbenv, logrec.data, logrec.size);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_marker_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
* PUBLIC: void *));
|
||||
*/
|
||||
int
|
||||
__vi_marker_getpgnos(dbenv, rec, lsnp, notused1, summary)
|
||||
DB_ENV *dbenv;
|
||||
DBT *rec;
|
||||
DB_LSN *lsnp;
|
||||
db_recops notused1;
|
||||
void *summary;
|
||||
{
|
||||
TXN_RECS *t;
|
||||
int ret;
|
||||
COMPQUIET(rec, NULL);
|
||||
COMPQUIET(notused1, DB_TXN_ABORT);
|
||||
|
||||
t = (TXN_RECS *)summary;
|
||||
|
||||
if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
t->array[t->npages].flags = LSN_PAGE_NOLOCK;
|
||||
t->array[t->npages].lsn = *lsnp;
|
||||
t->array[t->npages].fid = DB_LOGFILEID_INVALID;
|
||||
memset(&t->array[t->npages].pgdesc, 0,
|
||||
sizeof(t->array[t->npages].pgdesc));
|
||||
|
||||
t->npages++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_marker_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
* PUBLIC: void *));
|
||||
*/
|
||||
int
|
||||
__vi_marker_print(dbenv, dbtp, lsnp, notused2, notused3)
|
||||
DB_ENV *dbenv;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
db_recops notused2;
|
||||
void *notused3;
|
||||
{
|
||||
__vi_marker_args *argp;
|
||||
int ret;
|
||||
|
||||
notused2 = DB_TXN_ABORT;
|
||||
notused3 = NULL;
|
||||
|
||||
if ((ret = __vi_marker_read(dbenv, dbtp->data, &argp)) != 0)
|
||||
return (ret);
|
||||
(void)printf(
|
||||
"[%lu][%lu]vi_marker: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
|
||||
(u_long)lsnp->file,
|
||||
(u_long)lsnp->offset,
|
||||
(u_long)argp->type,
|
||||
(u_long)argp->txnid->txnid,
|
||||
(u_long)argp->prev_lsn.file,
|
||||
(u_long)argp->prev_lsn.offset);
|
||||
(void)printf("\topcode: %lu\n", (u_long)argp->opcode);
|
||||
(void)printf("\n");
|
||||
__os_free(dbenv, argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_marker_read __P((DB_ENV *, void *, __vi_marker_args **));
|
||||
*/
|
||||
int
|
||||
__vi_marker_read(dbenv, recbuf, argpp)
|
||||
DB_ENV *dbenv;
|
||||
void *recbuf;
|
||||
__vi_marker_args **argpp;
|
||||
{
|
||||
__vi_marker_args *argp;
|
||||
int ret;
|
||||
u_int32_t uinttmp;
|
||||
u_int8_t *bp;
|
||||
|
||||
ret = __os_malloc(dbenv, sizeof(__vi_marker_args) +
|
||||
sizeof(DB_TXN), &argp);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
argp->txnid = (DB_TXN *)&argp[1];
|
||||
|
||||
bp = recbuf;
|
||||
memcpy(&argp->type, bp, sizeof(argp->type));
|
||||
bp += sizeof(argp->type);
|
||||
|
||||
memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
|
||||
bp += sizeof(argp->txnid->txnid);
|
||||
|
||||
memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
|
||||
bp += sizeof(DB_LSN);
|
||||
|
||||
memcpy(&uinttmp, bp, sizeof(uinttmp));
|
||||
argp->opcode = (u_int32_t)uinttmp;
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
*argpp = argp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_cursor_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
* PUBLIC: u_int32_t, db_recno_t, size_t));
|
||||
*/
|
||||
int
|
||||
__vi_cursor_log(dbenv, txnid, ret_lsnp, flags,
|
||||
opcode, lno, cno)
|
||||
DB_ENV *dbenv;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN *ret_lsnp;
|
||||
u_int32_t flags;
|
||||
u_int32_t opcode;
|
||||
db_recno_t lno;
|
||||
size_t cno;
|
||||
{
|
||||
DBT logrec;
|
||||
DB_LSN *lsnp, null_lsn;
|
||||
u_int32_t uinttmp;
|
||||
u_int32_t rectype, txn_num;
|
||||
int ret;
|
||||
u_int8_t *bp;
|
||||
|
||||
rectype = DB_vi_cursor;
|
||||
if (txnid != NULL &&
|
||||
TAILQ_FIRST(&txnid->kids) != NULL &&
|
||||
(ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
|
||||
return (ret);
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
|
||||
+ sizeof(u_int32_t)
|
||||
+ sizeof(u_int32_t)
|
||||
+ sizeof(u_int32_t);
|
||||
if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
bp += sizeof(rectype);
|
||||
|
||||
memcpy(bp, &txn_num, sizeof(txn_num));
|
||||
bp += sizeof(txn_num);
|
||||
|
||||
memcpy(bp, lsnp, sizeof(DB_LSN));
|
||||
bp += sizeof(DB_LSN);
|
||||
|
||||
uinttmp = (u_int32_t)opcode;
|
||||
memcpy(bp, &uinttmp, sizeof(uinttmp));
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
uinttmp = (u_int32_t)lno;
|
||||
memcpy(bp, &uinttmp, sizeof(uinttmp));
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
uinttmp = (u_int32_t)cno;
|
||||
memcpy(bp, &uinttmp, sizeof(uinttmp));
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
|
||||
ret = dbenv->log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL && ret == 0)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
#ifdef LOG_DIAGNOSTIC
|
||||
if (ret != 0)
|
||||
(void)__vi_cursor_print(dbenv,
|
||||
(DBT *)&logrec, ret_lsnp, NULL, NULL);
|
||||
#endif
|
||||
__os_free(dbenv, logrec.data, logrec.size);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_cursor_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
* PUBLIC: void *));
|
||||
*/
|
||||
int
|
||||
__vi_cursor_getpgnos(dbenv, rec, lsnp, notused1, summary)
|
||||
DB_ENV *dbenv;
|
||||
DBT *rec;
|
||||
DB_LSN *lsnp;
|
||||
db_recops notused1;
|
||||
void *summary;
|
||||
{
|
||||
TXN_RECS *t;
|
||||
int ret;
|
||||
COMPQUIET(rec, NULL);
|
||||
COMPQUIET(notused1, DB_TXN_ABORT);
|
||||
|
||||
t = (TXN_RECS *)summary;
|
||||
|
||||
if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
t->array[t->npages].flags = LSN_PAGE_NOLOCK;
|
||||
t->array[t->npages].lsn = *lsnp;
|
||||
t->array[t->npages].fid = DB_LOGFILEID_INVALID;
|
||||
memset(&t->array[t->npages].pgdesc, 0,
|
||||
sizeof(t->array[t->npages].pgdesc));
|
||||
|
||||
t->npages++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_cursor_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
* PUBLIC: void *));
|
||||
*/
|
||||
int
|
||||
__vi_cursor_print(dbenv, dbtp, lsnp, notused2, notused3)
|
||||
DB_ENV *dbenv;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
db_recops notused2;
|
||||
void *notused3;
|
||||
{
|
||||
__vi_cursor_args *argp;
|
||||
int ret;
|
||||
|
||||
notused2 = DB_TXN_ABORT;
|
||||
notused3 = NULL;
|
||||
|
||||
if ((ret = __vi_cursor_read(dbenv, dbtp->data, &argp)) != 0)
|
||||
return (ret);
|
||||
(void)printf(
|
||||
"[%lu][%lu]vi_cursor: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
|
||||
(u_long)lsnp->file,
|
||||
(u_long)lsnp->offset,
|
||||
(u_long)argp->type,
|
||||
(u_long)argp->txnid->txnid,
|
||||
(u_long)argp->prev_lsn.file,
|
||||
(u_long)argp->prev_lsn.offset);
|
||||
(void)printf("\topcode: %lu\n", (u_long)argp->opcode);
|
||||
(void)printf("\tlno: %lu\n", (u_long)argp->lno);
|
||||
(void)printf("\tcno: %d\n", argp->cno);
|
||||
(void)printf("\n");
|
||||
__os_free(dbenv, argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_cursor_read __P((DB_ENV *, void *, __vi_cursor_args **));
|
||||
*/
|
||||
int
|
||||
__vi_cursor_read(dbenv, recbuf, argpp)
|
||||
DB_ENV *dbenv;
|
||||
void *recbuf;
|
||||
__vi_cursor_args **argpp;
|
||||
{
|
||||
__vi_cursor_args *argp;
|
||||
int ret;
|
||||
u_int32_t uinttmp;
|
||||
u_int8_t *bp;
|
||||
|
||||
ret = __os_malloc(dbenv, sizeof(__vi_cursor_args) +
|
||||
sizeof(DB_TXN), &argp);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
argp->txnid = (DB_TXN *)&argp[1];
|
||||
|
||||
bp = recbuf;
|
||||
memcpy(&argp->type, bp, sizeof(argp->type));
|
||||
bp += sizeof(argp->type);
|
||||
|
||||
memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
|
||||
bp += sizeof(argp->txnid->txnid);
|
||||
|
||||
memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
|
||||
bp += sizeof(DB_LSN);
|
||||
|
||||
memcpy(&uinttmp, bp, sizeof(uinttmp));
|
||||
argp->opcode = (u_int32_t)uinttmp;
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
memcpy(&uinttmp, bp, sizeof(uinttmp));
|
||||
argp->lno = (db_recno_t)uinttmp;
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
memcpy(&uinttmp, bp, sizeof(uinttmp));
|
||||
argp->cno = (size_t)uinttmp;
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
*argpp = argp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_mark_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
* PUBLIC: LMARK *));
|
||||
*/
|
||||
int
|
||||
__vi_mark_log(dbenv, txnid, ret_lsnp, flags,
|
||||
lmp)
|
||||
DB_ENV *dbenv;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN *ret_lsnp;
|
||||
u_int32_t flags;
|
||||
LMARK * lmp;
|
||||
{
|
||||
DBT logrec;
|
||||
DB_LSN *lsnp, null_lsn;
|
||||
u_int32_t rectype, txn_num;
|
||||
int ret;
|
||||
u_int8_t *bp;
|
||||
|
||||
rectype = DB_vi_mark;
|
||||
if (txnid != NULL &&
|
||||
TAILQ_FIRST(&txnid->kids) != NULL &&
|
||||
(ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
|
||||
return (ret);
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
|
||||
+ sizeof(*lmp);
|
||||
if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
bp += sizeof(rectype);
|
||||
|
||||
memcpy(bp, &txn_num, sizeof(txn_num));
|
||||
bp += sizeof(txn_num);
|
||||
|
||||
memcpy(bp, lsnp, sizeof(DB_LSN));
|
||||
bp += sizeof(DB_LSN);
|
||||
|
||||
if (lmp != NULL)
|
||||
memcpy(bp, lmp, sizeof(*lmp));
|
||||
else
|
||||
memset(bp, 0, sizeof(*lmp));
|
||||
bp += sizeof(*lmp);
|
||||
|
||||
DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
|
||||
ret = dbenv->log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL && ret == 0)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
#ifdef LOG_DIAGNOSTIC
|
||||
if (ret != 0)
|
||||
(void)__vi_mark_print(dbenv,
|
||||
(DBT *)&logrec, ret_lsnp, NULL, NULL);
|
||||
#endif
|
||||
__os_free(dbenv, logrec.data, logrec.size);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_mark_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
* PUBLIC: void *));
|
||||
*/
|
||||
int
|
||||
__vi_mark_getpgnos(dbenv, rec, lsnp, notused1, summary)
|
||||
DB_ENV *dbenv;
|
||||
DBT *rec;
|
||||
DB_LSN *lsnp;
|
||||
db_recops notused1;
|
||||
void *summary;
|
||||
{
|
||||
TXN_RECS *t;
|
||||
int ret;
|
||||
COMPQUIET(rec, NULL);
|
||||
COMPQUIET(notused1, DB_TXN_ABORT);
|
||||
|
||||
t = (TXN_RECS *)summary;
|
||||
|
||||
if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
t->array[t->npages].flags = LSN_PAGE_NOLOCK;
|
||||
t->array[t->npages].lsn = *lsnp;
|
||||
t->array[t->npages].fid = DB_LOGFILEID_INVALID;
|
||||
memset(&t->array[t->npages].pgdesc, 0,
|
||||
sizeof(t->array[t->npages].pgdesc));
|
||||
|
||||
t->npages++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_mark_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
* PUBLIC: void *));
|
||||
*/
|
||||
int
|
||||
__vi_mark_print(dbenv, dbtp, lsnp, notused2, notused3)
|
||||
DB_ENV *dbenv;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
db_recops notused2;
|
||||
void *notused3;
|
||||
{
|
||||
__vi_mark_args *argp;
|
||||
int ret;
|
||||
|
||||
notused2 = DB_TXN_ABORT;
|
||||
notused3 = NULL;
|
||||
|
||||
if ((ret = __vi_mark_read(dbenv, dbtp->data, &argp)) != 0)
|
||||
return (ret);
|
||||
(void)printf(
|
||||
"[%lu][%lu]vi_mark: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
|
||||
(u_long)lsnp->file,
|
||||
(u_long)lsnp->offset,
|
||||
(u_long)argp->type,
|
||||
(u_long)argp->txnid->txnid,
|
||||
(u_long)argp->prev_lsn.file,
|
||||
(u_long)argp->prev_lsn.offset);
|
||||
(void)printf("\tlmp: %%\n", argp->lmp);
|
||||
(void)printf("\n");
|
||||
__os_free(dbenv, argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_mark_read __P((DB_ENV *, void *, __vi_mark_args **));
|
||||
*/
|
||||
int
|
||||
__vi_mark_read(dbenv, recbuf, argpp)
|
||||
DB_ENV *dbenv;
|
||||
void *recbuf;
|
||||
__vi_mark_args **argpp;
|
||||
{
|
||||
__vi_mark_args *argp;
|
||||
int ret;
|
||||
u_int8_t *bp;
|
||||
|
||||
ret = __os_malloc(dbenv, sizeof(__vi_mark_args) +
|
||||
sizeof(DB_TXN), &argp);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
argp->txnid = (DB_TXN *)&argp[1];
|
||||
|
||||
bp = recbuf;
|
||||
memcpy(&argp->type, bp, sizeof(argp->type));
|
||||
bp += sizeof(argp->type);
|
||||
|
||||
memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
|
||||
bp += sizeof(argp->txnid->txnid);
|
||||
|
||||
memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
|
||||
bp += sizeof(DB_LSN);
|
||||
|
||||
memcpy(&argp->lmp, bp, sizeof(argp->lmp));
|
||||
bp += sizeof(argp->lmp);
|
||||
|
||||
*argpp = argp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_change_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
* PUBLIC: u_int32_t, db_recno_t));
|
||||
*/
|
||||
int
|
||||
__vi_change_log(dbenv, txnid, ret_lsnp, flags,
|
||||
opcode, lno)
|
||||
DB_ENV *dbenv;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN *ret_lsnp;
|
||||
u_int32_t flags;
|
||||
u_int32_t opcode;
|
||||
db_recno_t lno;
|
||||
{
|
||||
DBT logrec;
|
||||
DB_LSN *lsnp, null_lsn;
|
||||
u_int32_t uinttmp;
|
||||
u_int32_t rectype, txn_num;
|
||||
int ret;
|
||||
u_int8_t *bp;
|
||||
|
||||
rectype = DB_vi_change;
|
||||
if (txnid != NULL &&
|
||||
TAILQ_FIRST(&txnid->kids) != NULL &&
|
||||
(ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
|
||||
return (ret);
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
|
||||
+ sizeof(u_int32_t)
|
||||
+ sizeof(u_int32_t);
|
||||
if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
bp += sizeof(rectype);
|
||||
|
||||
memcpy(bp, &txn_num, sizeof(txn_num));
|
||||
bp += sizeof(txn_num);
|
||||
|
||||
memcpy(bp, lsnp, sizeof(DB_LSN));
|
||||
bp += sizeof(DB_LSN);
|
||||
|
||||
uinttmp = (u_int32_t)opcode;
|
||||
memcpy(bp, &uinttmp, sizeof(uinttmp));
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
uinttmp = (u_int32_t)lno;
|
||||
memcpy(bp, &uinttmp, sizeof(uinttmp));
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
|
||||
ret = dbenv->log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL && ret == 0)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
#ifdef LOG_DIAGNOSTIC
|
||||
if (ret != 0)
|
||||
(void)__vi_change_print(dbenv,
|
||||
(DBT *)&logrec, ret_lsnp, NULL, NULL);
|
||||
#endif
|
||||
__os_free(dbenv, logrec.data, logrec.size);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_change_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
* PUBLIC: void *));
|
||||
*/
|
||||
int
|
||||
__vi_change_getpgnos(dbenv, rec, lsnp, notused1, summary)
|
||||
DB_ENV *dbenv;
|
||||
DBT *rec;
|
||||
DB_LSN *lsnp;
|
||||
db_recops notused1;
|
||||
void *summary;
|
||||
{
|
||||
TXN_RECS *t;
|
||||
int ret;
|
||||
COMPQUIET(rec, NULL);
|
||||
COMPQUIET(notused1, DB_TXN_ABORT);
|
||||
|
||||
t = (TXN_RECS *)summary;
|
||||
|
||||
if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
t->array[t->npages].flags = LSN_PAGE_NOLOCK;
|
||||
t->array[t->npages].lsn = *lsnp;
|
||||
t->array[t->npages].fid = DB_LOGFILEID_INVALID;
|
||||
memset(&t->array[t->npages].pgdesc, 0,
|
||||
sizeof(t->array[t->npages].pgdesc));
|
||||
|
||||
t->npages++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_change_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops,
|
||||
* PUBLIC: void *));
|
||||
*/
|
||||
int
|
||||
__vi_change_print(dbenv, dbtp, lsnp, notused2, notused3)
|
||||
DB_ENV *dbenv;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
db_recops notused2;
|
||||
void *notused3;
|
||||
{
|
||||
__vi_change_args *argp;
|
||||
int ret;
|
||||
|
||||
notused2 = DB_TXN_ABORT;
|
||||
notused3 = NULL;
|
||||
|
||||
if ((ret = __vi_change_read(dbenv, dbtp->data, &argp)) != 0)
|
||||
return (ret);
|
||||
(void)printf(
|
||||
"[%lu][%lu]vi_change: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
|
||||
(u_long)lsnp->file,
|
||||
(u_long)lsnp->offset,
|
||||
(u_long)argp->type,
|
||||
(u_long)argp->txnid->txnid,
|
||||
(u_long)argp->prev_lsn.file,
|
||||
(u_long)argp->prev_lsn.offset);
|
||||
(void)printf("\topcode: %lu\n", (u_long)argp->opcode);
|
||||
(void)printf("\tlno: %lu\n", (u_long)argp->lno);
|
||||
(void)printf("\n");
|
||||
__os_free(dbenv, argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_change_read __P((DB_ENV *, void *, __vi_change_args **));
|
||||
*/
|
||||
int
|
||||
__vi_change_read(dbenv, recbuf, argpp)
|
||||
DB_ENV *dbenv;
|
||||
void *recbuf;
|
||||
__vi_change_args **argpp;
|
||||
{
|
||||
__vi_change_args *argp;
|
||||
int ret;
|
||||
u_int32_t uinttmp;
|
||||
u_int8_t *bp;
|
||||
|
||||
ret = __os_malloc(dbenv, sizeof(__vi_change_args) +
|
||||
sizeof(DB_TXN), &argp);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
argp->txnid = (DB_TXN *)&argp[1];
|
||||
|
||||
bp = recbuf;
|
||||
memcpy(&argp->type, bp, sizeof(argp->type));
|
||||
bp += sizeof(argp->type);
|
||||
|
||||
memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
|
||||
bp += sizeof(argp->txnid->txnid);
|
||||
|
||||
memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
|
||||
bp += sizeof(DB_LSN);
|
||||
|
||||
memcpy(&uinttmp, bp, sizeof(uinttmp));
|
||||
argp->opcode = (u_int32_t)uinttmp;
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
memcpy(&uinttmp, bp, sizeof(uinttmp));
|
||||
argp->lno = (db_recno_t)uinttmp;
|
||||
bp += sizeof(uinttmp);
|
||||
|
||||
*argpp = argp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *,
|
||||
* PUBLIC: DB_LSN *, db_recops, void *), size_t *));
|
||||
*/
|
||||
int
|
||||
__vi_init_print(dbenv, dtabp, dtabsizep)
|
||||
DB_ENV *dbenv;
|
||||
int (***dtabp)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
size_t *dtabsizep;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep,
|
||||
__vi_marker_print, DB_vi_marker)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep,
|
||||
__vi_cursor_print, DB_vi_cursor)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep,
|
||||
__vi_mark_print, DB_vi_mark)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep,
|
||||
__vi_change_print, DB_vi_change)) != 0)
|
||||
return (ret);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_init_getpgnos __P((DB_ENV *, int (***)(DB_ENV *, DBT *,
|
||||
* PUBLIC: DB_LSN *, db_recops, void *), size_t *));
|
||||
*/
|
||||
int
|
||||
__vi_init_getpgnos(dbenv, dtabp, dtabsizep)
|
||||
DB_ENV *dbenv;
|
||||
int (***dtabp)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
size_t *dtabsizep;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep,
|
||||
__vi_marker_getpgnos, DB_vi_marker)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep,
|
||||
__vi_cursor_getpgnos, DB_vi_cursor)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep,
|
||||
__vi_mark_getpgnos, DB_vi_mark)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep,
|
||||
__vi_change_getpgnos, DB_vi_change)) != 0)
|
||||
return (ret);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __vi_init_recover __P((DB_ENV *));
|
||||
*/
|
||||
int
|
||||
__vi_init_recover(dbenv)
|
||||
DB_ENV *dbenv;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = __db_add_recovery(dbenv, &dbenv->dtab, &dbenv->dtab_size,
|
||||
__vi_marker_recover, DB_vi_marker)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, &dbenv->dtab, &dbenv->dtab_size,
|
||||
__vi_cursor_recover, DB_vi_cursor)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, &dbenv->dtab, &dbenv->dtab_size,
|
||||
__vi_mark_recover, DB_vi_mark)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv, &dbenv->dtab, &dbenv->dtab_size,
|
||||
__vi_change_recover, DB_vi_change)) != 0)
|
||||
return (ret);
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* PUBLIC: #endif
|
||||
*/
|
||||
42
dist/nvi/common/vi_auto.h
vendored
Normal file
42
dist/nvi/common/vi_auto.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/* $NetBSD: vi_auto.h,v 1.1.1.2 2008/05/18 14:29:53 aymeric Exp $ */
|
||||
|
||||
/* Do not edit: automatically built by gen_rec.awk. */
|
||||
|
||||
#ifndef vi_AUTO_H
|
||||
#define vi_AUTO_H
|
||||
#define DB_vi_marker 200
|
||||
typedef struct _vi_marker_args {
|
||||
u_int32_t type;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN prev_lsn;
|
||||
u_int32_t opcode;
|
||||
} __vi_marker_args;
|
||||
|
||||
#define DB_vi_cursor 201
|
||||
typedef struct _vi_cursor_args {
|
||||
u_int32_t type;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN prev_lsn;
|
||||
u_int32_t opcode;
|
||||
db_recno_t lno;
|
||||
size_t cno;
|
||||
} __vi_cursor_args;
|
||||
|
||||
#define DB_vi_mark 202
|
||||
typedef struct _vi_mark_args {
|
||||
u_int32_t type;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN prev_lsn;
|
||||
LMARK lmp;
|
||||
} __vi_mark_args;
|
||||
|
||||
#define DB_vi_change 203
|
||||
typedef struct _vi_change_args {
|
||||
u_int32_t type;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN prev_lsn;
|
||||
u_int32_t opcode;
|
||||
db_recno_t lno;
|
||||
} __vi_change_args;
|
||||
|
||||
#endif
|
||||
323
dist/nvi/common/vi_rec.c
vendored
Normal file
323
dist/nvi/common/vi_rec.c
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
/* $NetBSD: vi_rec.c,v 1.1.1.2 2008/05/18 14:29:53 aymeric Exp $ */
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include <log.h>
|
||||
#include "hash.h"
|
||||
#include "btree.h"
|
||||
|
||||
#define LOG_CURSOR_HIT -1000
|
||||
|
||||
/*
|
||||
* PUBLIC: #ifdef USE_DB4_LOGGING
|
||||
*/
|
||||
/*
|
||||
* __vi_marker_recover --
|
||||
* Recovery function for marker.
|
||||
*
|
||||
* PUBLIC: int __vi_marker_recover
|
||||
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
*/
|
||||
int
|
||||
__vi_marker_recover(dbenv, dbtp, lsnp, op, info)
|
||||
DB_ENV *dbenv;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
db_recops op;
|
||||
void *info;
|
||||
{
|
||||
__vi_marker_args *argp;
|
||||
int ret;
|
||||
|
||||
REC_PRINT(__vi_marker_print);
|
||||
REC_NOOP_INTRO(__vi_marker_read);
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
REC_NOOP_CLOSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* __vi_cursor_recover --
|
||||
* Recovery function for cursor.
|
||||
*
|
||||
* PUBLIC: int __vi_cursor_recover
|
||||
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
*/
|
||||
int
|
||||
__vi_cursor_recover(dbenv, dbtp, lsnp, op, info)
|
||||
DB_ENV *dbenv;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
db_recops op;
|
||||
void *info;
|
||||
{
|
||||
__vi_cursor_args *argp;
|
||||
int ret;
|
||||
SCR *sp;
|
||||
|
||||
REC_PRINT(__vi_cursor_print);
|
||||
REC_NOOP_INTRO(__vi_cursor_read);
|
||||
|
||||
sp = (SCR *)dbenv->app_private;
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
if (sp->state.undo == UNDO_SETLINE) {
|
||||
/* Why the check for ep->l_cur ? (copied from log.c)
|
||||
*/
|
||||
ret = (argp->lno != sp->lno ||
|
||||
(argp->opcode == LOG_CURSOR_INIT && sp->ep->l_cur == 1))
|
||||
? LOG_CURSOR_HIT : 0;
|
||||
}
|
||||
else {
|
||||
ret = argp->opcode ==
|
||||
(DB_UNDO(op) ? LOG_CURSOR_INIT : LOG_CURSOR_END)
|
||||
? LOG_CURSOR_HIT : 0;
|
||||
if (ret) {
|
||||
sp->state.pos.lno = argp->lno;
|
||||
sp->state.pos.cno = argp->cno;
|
||||
}
|
||||
}
|
||||
|
||||
REC_NOOP_CLOSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* __vi_mark_recover --
|
||||
* Recovery function for mark.
|
||||
*
|
||||
* PUBLIC: int __vi_mark_recover
|
||||
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
*/
|
||||
int
|
||||
__vi_mark_recover(dbenv, dbtp, lsnp, op, info)
|
||||
DB_ENV *dbenv;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
db_recops op;
|
||||
void *info;
|
||||
{
|
||||
__vi_mark_args *argp;
|
||||
int ret;
|
||||
MARK m;
|
||||
SCR *sp;
|
||||
|
||||
REC_PRINT(__vi_mark_print);
|
||||
REC_NOOP_INTRO(__vi_mark_read);
|
||||
|
||||
sp = (SCR *)dbenv->app_private;
|
||||
*lsnp = argp->prev_lsn;
|
||||
m.lno = argp->lmp.lno;
|
||||
m.cno = argp->lmp.cno;
|
||||
ret = mark_set(sp, argp->lmp.name, &m, 0);
|
||||
|
||||
REC_NOOP_CLOSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* __vi_change_recover --
|
||||
* Recovery function for change.
|
||||
*
|
||||
* PUBLIC: int __vi_change_recover
|
||||
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
|
||||
*/
|
||||
int
|
||||
__vi_change_recover(dbenv, dbtp, lsnp, op, info)
|
||||
DB_ENV *dbenv;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
db_recops op;
|
||||
void *info;
|
||||
{
|
||||
__vi_change_args *argp;
|
||||
int ret;
|
||||
SCR *sp;
|
||||
|
||||
REC_PRINT(__vi_change_print);
|
||||
REC_NOOP_INTRO(__vi_change_read);
|
||||
|
||||
ret = 0;
|
||||
|
||||
sp = (SCR *)dbenv->app_private;
|
||||
if (DB_UNDO(op) != (argp->opcode & 1))
|
||||
switch (argp->opcode) {
|
||||
case LOG_LINE_RESET_B:
|
||||
case LOG_LINE_RESET_F:
|
||||
ret = line_insdel(sp, LINE_RESET, argp->lno);
|
||||
update_cache(sp, LINE_RESET, argp->lno);
|
||||
ret = scr_update(sp, argp->lno, LINE_RESET, 1) || ret;
|
||||
break;
|
||||
case LOG_LINE_APPEND_B:
|
||||
case LOG_LINE_DELETE_F:
|
||||
ret = line_insdel(sp, LINE_DELETE, argp->lno);
|
||||
update_cache(sp, LINE_DELETE, argp->lno);
|
||||
ret = scr_update(sp, argp->lno, LINE_DELETE, 1) || ret;
|
||||
break;
|
||||
case LOG_LINE_DELETE_B:
|
||||
case LOG_LINE_APPEND_F:
|
||||
ret = line_insdel(sp, LINE_INSERT, argp->lno);
|
||||
update_cache(sp, LINE_INSERT, argp->lno);
|
||||
ret = scr_update(sp, argp->lno, LINE_INSERT, 1) || ret;
|
||||
break;
|
||||
}
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
|
||||
REC_NOOP_CLOSE;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* PUBLIC: int __vi_log_truncate __P((EXF *ep));
|
||||
*/
|
||||
int
|
||||
__vi_log_truncate(EXF *ep)
|
||||
{
|
||||
DB_LSN ckplsn;
|
||||
|
||||
ZERO_LSN(ckplsn);
|
||||
return __log_vtruncate(ep->env, &ep->lsn_cur, &ckplsn);
|
||||
/*return __log_vtruncate(ep->env, &ep->lsn_cur, &ep->lsn_first);*/
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* PUBLIC: int __vi_log_dispatch __P((DB_ENV *dbenv, DBT *data, DB_LSN *lsn, db_recops ops));
|
||||
*/
|
||||
int
|
||||
__vi_log_dispatch(DB_ENV *dbenv, DBT *data, DB_LSN *lsn, db_recops ops)
|
||||
{
|
||||
u_int32_t rectype;
|
||||
char s[100];
|
||||
|
||||
memcpy(&rectype, data->data, sizeof(rectype));
|
||||
snprintf(s,100,"%d\n", rectype);
|
||||
return dbenv->dtab[rectype](dbenv, data, lsn, ops, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
vi_log_get(SCR *sp, DB_LOGC *logc, DBT *data, u_int32_t which)
|
||||
{
|
||||
size_t nlen;
|
||||
EXF *ep;
|
||||
|
||||
ep = sp->ep;
|
||||
|
||||
nlen = 1024;
|
||||
retry:
|
||||
BINC_GOTO(sp, sp->wp->l_lp, sp->wp->l_len, nlen);
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->data = sp->wp->l_lp;
|
||||
data->ulen = sp->wp->l_len;
|
||||
data->flags = DB_DBT_USERMEM;
|
||||
switch ((sp->db_error = logc->get(logc, &ep->lsn_cur, data, which))) {
|
||||
case ENOMEM:
|
||||
nlen = data->size;
|
||||
goto retry;
|
||||
default:
|
||||
alloc_err:
|
||||
msgq(sp, M_DBERR, "logc->get");
|
||||
F_SET(ep, F_NOLOG);
|
||||
return (1);
|
||||
case 0:
|
||||
;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* PUBLIC: int __vi_log_traverse __P((SCR *sp, undo_t undo, MARK *));
|
||||
*/
|
||||
int
|
||||
__vi_log_traverse(SCR *sp, undo_t undo, MARK *rp)
|
||||
{
|
||||
DB_LOGC *logc;
|
||||
DBT data;
|
||||
EXF *ep;
|
||||
int ret;
|
||||
DB_LSN lsn;
|
||||
u_int32_t which;
|
||||
db_recops ops;
|
||||
|
||||
ep = sp->ep;
|
||||
|
||||
F_SET(ep, F_NOLOG); /* Turn off logging. */
|
||||
|
||||
sp->state.undo = undo;
|
||||
ep->env->app_private = sp;
|
||||
if ((sp->db_error = ep->env->log_cursor(ep->env, &logc, 0))
|
||||
!= 0) {
|
||||
msgq(sp, M_DBERR, "env->log_cursor");
|
||||
return (1);
|
||||
}
|
||||
if (vi_log_get(sp, logc, &data, DB_SET))
|
||||
return 1;
|
||||
if (undo == UNDO_FORWARD) {
|
||||
ops = DB_TXN_FORWARD_ROLL;
|
||||
which = DB_NEXT;
|
||||
if (vi_log_get(sp, logc, &data, DB_NEXT))
|
||||
return 1;
|
||||
} else {
|
||||
ops = DB_TXN_BACKWARD_ROLL;
|
||||
which = DB_PREV;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
MEMCPY(&lsn, &ep->lsn_cur, 1);
|
||||
ret = __vi_log_dispatch(ep->env, &data, &lsn, ops);
|
||||
if (ret != 0) {
|
||||
if (ret == LOG_CURSOR_HIT)
|
||||
break;
|
||||
}
|
||||
|
||||
if (vi_log_get(sp, logc, &data, which))
|
||||
return 1;
|
||||
if (undo == UNDO_SETLINE &&
|
||||
log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
|
||||
/* Move to previous record without dispatching. */
|
||||
undo = UNDO_BACKWARD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (undo == UNDO_BACKWARD)
|
||||
if (vi_log_get(sp, logc, &data, DB_PREV))
|
||||
return 1;
|
||||
|
||||
logc->close(logc, 0);
|
||||
|
||||
ep->env->app_private = NULL;
|
||||
|
||||
MEMMOVE(rp, &sp->state.pos, 1);
|
||||
|
||||
F_CLR(ep, F_NOLOG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
vi_db_init_recover(DB_ENV *dbenv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = __db_init_recover(dbenv)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __bam_init_recover(dbenv)) != 0)
|
||||
return (ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* PUBLIC: #endif
|
||||
*/
|
||||
473
dist/nvi/dist/ExtUtils/Embed.pm
vendored
Normal file
473
dist/nvi/dist/ExtUtils/Embed.pm
vendored
Normal file
@@ -0,0 +1,473 @@
|
||||
# Id: Embed.pm,v 10.2 1996/09/19 09:12:51 bostic Exp
|
||||
require 5.002;
|
||||
|
||||
package ExtUtils::Embed;
|
||||
require Exporter;
|
||||
require FileHandle;
|
||||
use Config;
|
||||
use Getopt::Std;
|
||||
|
||||
#Only when we need them
|
||||
#require ExtUtils::MakeMaker;
|
||||
#require ExtUtils::Liblist;
|
||||
|
||||
use vars qw(@ISA @EXPORT $VERSION
|
||||
@Extensions $Verbose $lib_ext
|
||||
$opt_o $opt_s
|
||||
);
|
||||
use strict;
|
||||
|
||||
$VERSION = sprintf("%d.%02d", qRevision: 10.2 =~ /(\d+)\.(\d+)/);
|
||||
#for the namespace change
|
||||
$Devel::embed::VERSION = "99.99";
|
||||
|
||||
sub Version { $VERSION; }
|
||||
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT = qw(&xsinit &ldopts
|
||||
&ccopts &ccflags &ccdlflags &perl_inc
|
||||
&xsi_header &xsi_protos &xsi_body);
|
||||
|
||||
#let's have Miniperl borrow from us instead
|
||||
#require ExtUtils::Miniperl;
|
||||
#*canon = \&ExtUtils::Miniperl::canon;
|
||||
|
||||
$Verbose = 0;
|
||||
$lib_ext = $Config{lib_ext} || '.a';
|
||||
|
||||
sub xsinit {
|
||||
my($file, $std, $mods) = @_;
|
||||
my($fh,@mods,%seen);
|
||||
$file ||= "perlxsi.c";
|
||||
|
||||
if (@_) {
|
||||
@mods = @$mods if $mods;
|
||||
}
|
||||
else {
|
||||
getopts('o:s:');
|
||||
$file = $opt_o if defined $opt_o;
|
||||
$std = $opt_s if defined $opt_s;
|
||||
@mods = @ARGV;
|
||||
}
|
||||
$std = 1 unless scalar @mods;
|
||||
|
||||
if ($file eq "STDOUT") {
|
||||
$fh = \*STDOUT;
|
||||
}
|
||||
else {
|
||||
$fh = new FileHandle "> $file";
|
||||
}
|
||||
|
||||
push(@mods, static_ext()) if defined $std;
|
||||
@mods = grep(!$seen{$_}++, @mods);
|
||||
|
||||
print $fh &xsi_header();
|
||||
print $fh "EXTERN_C void xs_init _((void));\n\n";
|
||||
print $fh &xsi_protos(@mods);
|
||||
|
||||
print $fh "\nEXTERN_C void\nxs_init()\n{\n";
|
||||
print $fh &xsi_body(@mods);
|
||||
print $fh "}\n";
|
||||
|
||||
}
|
||||
|
||||
sub xsi_header {
|
||||
return <<EOF;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
# ifndef EXTERN_C
|
||||
# define EXTERN_C extern "C"
|
||||
# endif
|
||||
#else
|
||||
# ifndef EXTERN_C
|
||||
# define EXTERN_C extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
sub xsi_protos {
|
||||
my(@exts) = @_;
|
||||
my(@retval,%seen);
|
||||
|
||||
foreach $_ (@exts){
|
||||
my($pname) = canon('/', $_);
|
||||
my($mname, $cname);
|
||||
($mname = $pname) =~ s!/!::!g;
|
||||
($cname = $pname) =~ s!/!__!g;
|
||||
my($ccode) = "EXTERN_C void boot_${cname} _((CV* cv));\n";
|
||||
next if $seen{$ccode}++;
|
||||
push(@retval, $ccode);
|
||||
}
|
||||
return join '', @retval;
|
||||
}
|
||||
|
||||
sub xsi_body {
|
||||
my(@exts) = @_;
|
||||
my($pname,@retval,%seen);
|
||||
my($dl) = canon('/','DynaLoader');
|
||||
push(@retval, "\tdXSUB_SYS;\n") if $] > 5.002;
|
||||
push(@retval, "\tchar *file = __FILE__;\n\n");
|
||||
|
||||
foreach $_ (@exts){
|
||||
my($pname) = canon('/', $_);
|
||||
my($mname, $cname, $ccode);
|
||||
($mname = $pname) =~ s!/!::!g;
|
||||
($cname = $pname) =~ s!/!__!g;
|
||||
if ($pname eq $dl){
|
||||
# Must NOT install 'DynaLoader::boot_DynaLoader' as 'bootstrap'!
|
||||
# boot_DynaLoader is called directly in DynaLoader.pm
|
||||
$ccode = "\t/* DynaLoader is a special case */\n\tnewXS(\"${mname}::boot_${cname}\", boot_${cname}, file);\n";
|
||||
push(@retval, $ccode) unless $seen{$ccode}++;
|
||||
} else {
|
||||
$ccode = "\tnewXS(\"${mname}::bootstrap\", boot_${cname}, file);\n";
|
||||
push(@retval, $ccode) unless $seen{$ccode}++;
|
||||
}
|
||||
}
|
||||
return join '', @retval;
|
||||
}
|
||||
|
||||
sub static_ext {
|
||||
unless (scalar @Extensions) {
|
||||
@Extensions = sort split /\s+/, $Config{static_ext};
|
||||
unshift @Extensions, qw(DynaLoader);
|
||||
}
|
||||
@Extensions;
|
||||
}
|
||||
|
||||
sub ldopts {
|
||||
require ExtUtils::MakeMaker;
|
||||
require ExtUtils::Liblist;
|
||||
my($std,$mods,$link_args,$path) = @_;
|
||||
my(@mods,@link_args,@argv);
|
||||
my($dllib,$config_libs,@potential_libs,@path);
|
||||
local($") = ' ' unless $" eq ' ';
|
||||
my $MM = bless {} => 'MY';
|
||||
if (scalar @_) {
|
||||
@link_args = @$link_args if $link_args;
|
||||
@mods = @$mods if $mods;
|
||||
}
|
||||
else {
|
||||
@argv = @ARGV;
|
||||
#hmm
|
||||
while($_ = shift @argv) {
|
||||
/^-std$/ && do { $std = 1; next; };
|
||||
/^--$/ && do { @link_args = @argv; last; };
|
||||
/^-I(.*)/ && do { $path = $1 || shift @argv; next; };
|
||||
push(@mods, $_);
|
||||
}
|
||||
}
|
||||
$std = 1 unless scalar @link_args;
|
||||
@path = $path ? split(/:/, $path) : @INC;
|
||||
|
||||
push(@potential_libs, @link_args) if scalar @link_args;
|
||||
push(@potential_libs, $Config{libs}) if defined $std;
|
||||
|
||||
push(@mods, static_ext()) if $std;
|
||||
|
||||
my($mod,@ns,$root,$sub,$extra,$archive,@archives);
|
||||
print STDERR "Searching (@path) for archives\n" if $Verbose;
|
||||
foreach $mod (@mods) {
|
||||
@ns = split('::', $mod);
|
||||
$sub = $ns[-1];
|
||||
$root = $MM->catdir(@ns);
|
||||
|
||||
print STDERR "searching for '$sub${lib_ext}'\n" if $Verbose;
|
||||
foreach (@path) {
|
||||
next unless -e ($archive = $MM->catdir($_,"auto",$root,"$sub$lib_ext"));
|
||||
push @archives, $archive;
|
||||
if(-e ($extra = $MM->catdir($_,"auto",$root,"extralibs.ld"))) {
|
||||
local(*FH);
|
||||
if(open(FH, $extra)) {
|
||||
my($libs) = <FH>; chomp $libs;
|
||||
push @potential_libs, split /\s+/, $libs;
|
||||
}
|
||||
else {
|
||||
warn "Couldn't open '$extra'";
|
||||
}
|
||||
}
|
||||
last;
|
||||
}
|
||||
}
|
||||
#print STDERR "\@potential_libs = @potential_libs\n";
|
||||
|
||||
my($extralibs, $bsloadlibs, $ldloadlibs, $ld_run_path) =
|
||||
$MM->ext(join ' ',
|
||||
$MM->catdir("-L$Config{archlib}", "CORE"), " -lperl",
|
||||
@potential_libs);
|
||||
|
||||
my $ld_or_bs = $bsloadlibs || $ldloadlibs;
|
||||
print STDERR "bs: $bsloadlibs ** ld: $ldloadlibs" if $Verbose;
|
||||
my $linkage = "$Config{ldflags} @archives $ld_or_bs";
|
||||
print STDERR "ldopts: '$linkage'\n" if $Verbose;
|
||||
|
||||
return $linkage if scalar @_;
|
||||
print "$linkage\n";
|
||||
}
|
||||
|
||||
sub ccflags {
|
||||
print " $Config{ccflags} ";
|
||||
}
|
||||
|
||||
sub ccdlflags {
|
||||
print " $Config{ccdlflags} ";
|
||||
}
|
||||
|
||||
sub perl_inc {
|
||||
print " -I$Config{archlib}/CORE ";
|
||||
}
|
||||
|
||||
sub ccopts {
|
||||
ccflags;
|
||||
ccdlflags;
|
||||
perl_inc;
|
||||
}
|
||||
|
||||
sub canon {
|
||||
my($as, @ext) = @_;
|
||||
foreach(@ext) {
|
||||
# might be X::Y or lib/auto/X/Y/Y.a
|
||||
next if s!::!/!g;
|
||||
s:^(lib|ext)/(auto/)?::;
|
||||
s:/\w+\.\w+$::;
|
||||
}
|
||||
grep(s:/:$as:, @ext) if ($as ne '/');
|
||||
@ext;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ExtUtils::Embed - Utilities for embedding Perl in C/C++ applications
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
|
||||
perl -MExtUtils::Embed -e xsinit
|
||||
perl -MExtUtils::Embed -e ldopts
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
ExtUtils::Embed provides utility functions for embedding a Perl interpreter
|
||||
and extensions in your C/C++ applications.
|
||||
Typically, an application B<Makefile> will invoke ExtUtils::Embed
|
||||
functions while building your application.
|
||||
|
||||
=head1 @EXPORT
|
||||
|
||||
ExtUtils::Embed exports the following functions:
|
||||
|
||||
L<xsinit()>, L<ldopts()>, L<ccopts()>, L<perl_inc()>, L<ccflags()>,
|
||||
L<ccdlflags()>, L<xsi_header()>, L<xsi_protos()>, L<xsi_body()>
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=item xsinit()
|
||||
|
||||
Generate C/C++ code for the XS intializer function.
|
||||
|
||||
When invoked as C<`perl -MExtUtils::Embed -e xsinit --`>
|
||||
the following options are recognized:
|
||||
|
||||
B<-o> <output filename> (Defaults to B<perlxsi.c>)
|
||||
|
||||
B<-o STDOUT> will print to STDOUT.
|
||||
|
||||
B<-std> (Write code for extensions that are linked with the current Perl.)
|
||||
|
||||
Any additional arguments are expected to be names of modules
|
||||
to generate code for.
|
||||
|
||||
When invoked with parameters the following are accepted and optional:
|
||||
|
||||
C<xsinit($filename,$std,[@modules])>
|
||||
|
||||
Where,
|
||||
|
||||
B<$filename> is equivalent to the B<-o> option.
|
||||
|
||||
B<$std> is boolean, equivalent to the B<-std> option.
|
||||
|
||||
B<[@modules]> is an array ref, same as additional arguments mentioned above.
|
||||
|
||||
=item Examples
|
||||
|
||||
|
||||
perl -MExtUtils::Embed -e xsinit -- -o xsinit.c Socket
|
||||
|
||||
|
||||
This will generate code with an B<xs_init> function that glues the perl B<Socket::bootstrap> function
|
||||
to the C B<boot_Socket> function and writes it to a file named "xsinit.c".
|
||||
|
||||
Note that B<DynaLoader> is a special case where it must call B<boot_DynaLoader> directly.
|
||||
|
||||
perl -MExtUtils::Embed -e xsinit
|
||||
|
||||
|
||||
This will generate code for linking with B<DynaLoader> and
|
||||
each static extension found in B<$Config{static_ext}>.
|
||||
The code is written to the default file name B<perlxsi.c>.
|
||||
|
||||
|
||||
perl -MExtUtils::Embed -e xsinit -- -o xsinit.c -std DBI DBD::Oracle
|
||||
|
||||
|
||||
Here, code is written for all the currently linked extensions along with code
|
||||
for B<DBI> and B<DBD::Oracle>.
|
||||
|
||||
If you have a working B<DynaLoader> then there is rarely any need to statically link in any
|
||||
other extensions.
|
||||
|
||||
=item ldopts()
|
||||
|
||||
Output arguments for linking the Perl library and extensions to your
|
||||
application.
|
||||
|
||||
When invoked as C<`perl -MExtUtils::Embed -e ldopts --`>
|
||||
the following options are recognized:
|
||||
|
||||
B<-std>
|
||||
|
||||
Output arguments for linking the Perl library and any extensions linked
|
||||
with the current Perl.
|
||||
|
||||
B<-I> <path1:path2>
|
||||
|
||||
Search path for ModuleName.a archives.
|
||||
Default path is B<@INC>.
|
||||
Library archives are expected to be found as
|
||||
B</some/path/auto/ModuleName/ModuleName.a>
|
||||
For example, when looking for B<Socket.a> relative to a search path,
|
||||
we should find B<auto/Socket/Socket.a>
|
||||
|
||||
When looking for B<DBD::Oracle> relative to a search path,
|
||||
we should find B<auto/DBD/Oracle/Oracle.a>
|
||||
|
||||
Keep in mind, you can always supply B</my/own/path/ModuleName.a>
|
||||
as an additional linker argument.
|
||||
|
||||
B<--> <list of linker args>
|
||||
|
||||
Additional linker arguments to be considered.
|
||||
|
||||
Any additional arguments found before the B<--> token
|
||||
are expected to be names of modules to generate code for.
|
||||
|
||||
When invoked with parameters the following are accepted and optional:
|
||||
|
||||
C<ldopts($std,[@modules],[@link_args],$path)>
|
||||
|
||||
Where,
|
||||
|
||||
B<$std> is boolean, equivalent to the B<-std> option.
|
||||
|
||||
B<[@modules]> is equivalent to additional arguments found before the B<--> token.
|
||||
|
||||
B<[@link_args]> is equivalent to arguments found after the B<--> token.
|
||||
|
||||
B<$path> is equivalent to the B<-I> option.
|
||||
|
||||
In addition, when ldopts is called with parameters, it will return the argument string
|
||||
rather than print it to STDOUT.
|
||||
|
||||
=item Examples
|
||||
|
||||
|
||||
perl -MExtUtils::Embed -e ldopts
|
||||
|
||||
|
||||
This will print arguments for linking with B<libperl.a>, B<DynaLoader> and
|
||||
extensions found in B<$Config{static_ext}>. This includes libraries
|
||||
found in B<$Config{libs}> and the first ModuleName.a library
|
||||
for each extension that is found by searching B<@INC> or the path
|
||||
specifed by the B<-I> option.
|
||||
In addition, when ModuleName.a is found, additional linker arguments
|
||||
are picked up from the B<extralibs.ld> file in the same directory.
|
||||
|
||||
|
||||
perl -MExtUtils::Embed -e ldopts -- -std Socket
|
||||
|
||||
|
||||
This will do the same as the above example, along with printing additional arguments for linking with the B<Socket> extension.
|
||||
|
||||
|
||||
perl -MExtUtils::Embed -e ldopts -- DynaLoader
|
||||
|
||||
|
||||
This will print arguments for linking with just the B<DynaLoader> extension
|
||||
and B<libperl.a>.
|
||||
|
||||
|
||||
perl -MExtUtils::Embed -e ldopts -- -std Msql -- -L/usr/msql/lib -lmsql
|
||||
|
||||
|
||||
Any arguments after the second '--' token are additional linker
|
||||
arguments that will be examined for potential conflict. If there is no
|
||||
conflict, the additional arguments will be part of the output.
|
||||
|
||||
|
||||
=item perl_inc()
|
||||
|
||||
For including perl header files this function simply prints:
|
||||
|
||||
-I $Config{archlib}/CORE
|
||||
|
||||
So, rather than having to say:
|
||||
|
||||
perl -MConfig -e 'print "-I $Config{archlib}/CORE"'
|
||||
|
||||
Just say:
|
||||
|
||||
perl -MExtUtils::Embed -e perl_inc
|
||||
|
||||
=item ccflags(), ccdlflags()
|
||||
|
||||
These functions simply print $Config{ccflags} and $Config{ccdlflags}
|
||||
|
||||
=item ccopts()
|
||||
|
||||
This function combines perl_inc(), ccflags() and ccdlflags() into one.
|
||||
|
||||
=item xsi_header()
|
||||
|
||||
This function simply returns a string defining the same B<EXTERN_C> macro as
|
||||
B<perlmain.c> along with #including B<perl.h> and B<EXTERN.h>.
|
||||
|
||||
=item xsi_protos(@modules)
|
||||
|
||||
This function returns a string of B<boot_$ModuleName> prototypes for each @modules.
|
||||
|
||||
=item xsi_body(@modules)
|
||||
|
||||
This function returns a string of calls to B<newXS()> that glue the module B<bootstrap>
|
||||
function to B<boot_ModuleName> for each @modules.
|
||||
|
||||
B<xsinit()> uses the xsi_* functions to generate most of it's code.
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
For examples on how to use B<ExtUtils::Embed> for building C/C++ applications
|
||||
with embedded perl, see the eg/ directory and the I<perlembed> man page.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
the I<perlembed> man page
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Doug MacEachern <dougm@osf.org>
|
||||
|
||||
Based on ideas from Tim Bunce <Tim.Bunce@ig.co.uk> and
|
||||
B<minimod.pl> by Andreas Koenig <k@anna.in-berlin.de> and Tim Bunce.
|
||||
|
||||
=cut
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user